mmhglobal-dynamicform 2.41.5 → 2.43.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.
@@ -2357,37 +2357,27 @@ class ZComponentService {
2357
2357
  }
2358
2358
  return obsList;
2359
2359
  }
2360
- localizeDateTimeByIgnoringTimeZone(value, data) {
2361
- if (this.timePickerDateType.includes(data.Type)) {
2362
- const userTimeZoneOffSet = this.convertOffsetMinToHour((new Date(value).getTimezoneOffset()));
2363
- const datetimeWithoutTimeZone = this.removeTimeZoneAndConvertToISOString(value);
2364
- //return new Date(`${datetimeWithoutTimeZone.split('.000Z')[0]}${userTimeZoneOffSet}`);
2365
- return new Date(`${datetimeWithoutTimeZone.split('Z')[0]}${userTimeZoneOffSet}`);
2366
- }
2367
- else if (data.Type === 'zshortdate') {
2368
- const dateOnly = value.includes('T') ? value.split('T')[0] : value; // Extract date portion
2369
- const date = new Date(dateOnly); // Create a date object from the extracted date
2370
- date.setUTCDate(1); // Set day to the first of the month
2371
- // Convert to UTC, accounting for the timezone offset
2372
- const timezoneOffset = date.getTimezoneOffset(); // Get timezone offset in minutes
2373
- date.setMinutes(date.getMinutes() + timezoneOffset); // Adjust for timezone offset
2374
- // Return the final date object
2375
- return date;
2376
- }
2377
- else {
2378
- const dateOnly = value.includes('T') ? value.split('T')[0] : value;
2379
- return new Date(dateOnly + " " + new Date(dateOnly).toLocaleTimeString());
2380
- }
2381
- }
2382
- removeTimeZoneAndConvertToISOString(value) {
2383
- const result = value.split('+')[0];
2384
- return new Date(result.endsWith('Z') ? result : `${result}Z`).toISOString();
2385
- }
2386
- convertOffsetMinToHour(num) {
2387
- num = -num;
2388
- const prefix = num.toString().startsWith('-') ? '-' : '+';
2389
- const result = `${(Math.abs(num) / 60).toString().padStart(2, '0')}:00`;
2390
- return `${prefix}${result}`;
2360
+ localizeDateTimeByIgnoringTimeZone(value, field) {
2361
+ // Support both string and Date inputs
2362
+ const originalDate = value instanceof Date ? new Date(value.getTime()) : new Date(value);
2363
+ // Case 1: time / datetime fields → keep wall-clock time stable
2364
+ if (this.timePickerDateType.includes(field.Type)) {
2365
+ const adjusted = new Date(originalDate);
2366
+ const offsetMinutes = originalDate.getTimezoneOffset();
2367
+ adjusted.setMinutes(originalDate.getMinutes() - offsetMinutes);
2368
+ return adjusted;
2369
+ }
2370
+ // Case 2: month-only (zshortdate) → year+month, day fixed to 1
2371
+ if (field.Type === 'zshortdate') {
2372
+ return new Date(originalDate.getFullYear(), originalDate.getMonth(), 1, // day
2373
+ 0, 0, 0, 0);
2374
+ }
2375
+ // Case 3: normal date-only → keep calendar date stable, ignore time
2376
+ const dateOnly = new Date(originalDate.getFullYear(), originalDate.getMonth(), originalDate.getDate(), 0, 0, 0, 0);
2377
+ const normalizedDate = new Date(dateOnly);
2378
+ const localOffsetMinutes = dateOnly.getTimezoneOffset();
2379
+ normalizedDate.setMinutes(dateOnly.getMinutes() - localOffsetMinutes);
2380
+ return normalizedDate;
2391
2381
  }
2392
2382
  //#endregion
2393
2383
  decrementComponentCounterForField(field) {
@@ -3598,21 +3588,21 @@ class DateParserFilter {
3598
3588
  constructor(componentService) {
3599
3589
  this.componentService = componentService;
3600
3590
  }
3601
- transform(value, data) {
3602
- // debugger;
3603
- if (!value) {
3604
- return value;
3591
+ transform(rawValue, field) {
3592
+ if (!rawValue) {
3593
+ return null;
3605
3594
  }
3606
- // filter items array, items which match and return true will be
3607
- // kept, false will be filtered out
3608
3595
  try {
3609
- if (data.IsIgnoreTimeZone) {
3610
- return this.componentService.localizeDateTimeByIgnoringTimeZone(value, data);
3596
+ // For "ignore timezone" fields, normalize via service
3597
+ if (field.IsIgnoreTimeZone) {
3598
+ return this.componentService.localizeDateTimeByIgnoringTimeZone(rawValue, field);
3611
3599
  }
3612
- return new Date(value);
3600
+ // Otherwise, just convert to Date
3601
+ const inputDate = new Date(rawValue);
3602
+ return inputDate;
3613
3603
  }
3614
3604
  catch (error) {
3615
- console.log("DateParserFilter error: ", error);
3605
+ console.log('DateParserFilter error:', error);
3616
3606
  return null;
3617
3607
  }
3618
3608
  }
@@ -7214,12 +7204,13 @@ class ZdatetimeComponent extends InputFieldBase {
7214
7204
  }
7215
7205
  onChange(value) {
7216
7206
  const formControl = this.form.controls[this.data.Value];
7217
- const val = this.convertDateTimeValueToString(value);
7207
+ const dateValue = this.convertDateTimeValueToString(value);
7218
7208
  if (formControl) {
7219
- formControl.setValue(val);
7209
+ formControl.setValue(dateValue);
7220
7210
  formControl.markAsTouched();
7221
7211
  }
7222
- super.onChange(null, val);
7212
+ // Important: pass Date to base, not ISO string
7213
+ super.onChange(null, dateValue);
7223
7214
  }
7224
7215
  setMinAndMaxDateRange() {
7225
7216
  const minDateGroupValue = ZComponentHelper.getGroupValue(this.data.MinDate, this.group);
@@ -7239,24 +7230,39 @@ class ZdatetimeComponent extends InputFieldBase {
7239
7230
  }
7240
7231
  }
7241
7232
  convertDateTimeValueToString(value) {
7242
- if (value == undefined) {
7233
+ if (value === undefined || value === null) {
7243
7234
  return undefined;
7244
7235
  }
7245
- const valueDate = value;
7236
+ const inputDate = new Date(value);
7237
+ // zshortdate → normalize to first day of month
7246
7238
  if (this.data.Type === 'zshortdate') {
7247
- valueDate.setDate(1);
7239
+ const monthStart = new Date(inputDate);
7240
+ monthStart.setDate(1);
7241
+ return monthStart;
7248
7242
  }
7243
+ // Ignore timezone: keep same local wall-clock time regardless of browser TZ
7249
7244
  if (this.data.IsIgnoreTimeZone) {
7250
- const timezoneOffSet = new Date(value).getTimezoneOffset();
7251
- valueDate.setMinutes(valueDate.getMinutes() + (-timezoneOffSet));
7252
- return valueDate.toISOString();
7245
+ return this.adjustForIgnoreTimeZone(inputDate);
7253
7246
  }
7247
+ // For non-time types -> date-only
7254
7248
  if (!['zuidatetime', 'ztime', 'zuitime'].includes(this.data.Type)) {
7255
- return this.parseAnyValueToDateOnly(value).toISOString();
7256
- }
7257
- else {
7258
- return this.parseAnyValueToDate(value).toISOString();
7249
+ // Assuming these helpers already return Date
7250
+ const dateOnly = this.parseAnyValueToDateOnly(inputDate);
7251
+ return dateOnly;
7259
7252
  }
7253
+ // For datetime/time types -> full datetime
7254
+ const dateTime = this.parseAnyValueToDate(inputDate);
7255
+ return dateTime;
7256
+ }
7257
+ /**
7258
+ * Adjusts a Date so that its wall-clock time stays the same
7259
+ * when ignoring the browser timezone.
7260
+ */
7261
+ adjustForIgnoreTimeZone(date) {
7262
+ const adjustedDate = new Date(date);
7263
+ const timezoneOffsetMinutes = adjustedDate.getTimezoneOffset();
7264
+ adjustedDate.setMinutes(adjustedDate.getMinutes() - timezoneOffsetMinutes);
7265
+ return adjustedDate;
7260
7266
  }
7261
7267
  parseAnyValueToDate(value) {
7262
7268
  return new Date(value instanceof Date ? value : new Date(value));
@@ -7302,13 +7308,22 @@ class ZgaugeComponent extends FieldBase {
7302
7308
  super(componentService);
7303
7309
  this.componentService = componentService;
7304
7310
  this.isLoading = true;
7311
+ this.value = 0;
7312
+ this.title = "";
7313
+ this.color = [{ color: "#0175c7" }];
7314
+ this.majorTicks = { visible: true, color: '#0000ff' };
7315
+ this.minorTicks = { visible: true, color: '#0000ff' };
7316
+ this.startAngle = 0;
7317
+ this.endAngle = 180;
7318
+ this.minValue = 0;
7319
+ this.maxValue = 200;
7305
7320
  this.options = {
7306
- value: 0,
7307
- title: '',
7321
+ value: this.value,
7322
+ title: this.title,
7308
7323
  chartInnerText1: '',
7309
7324
  chartInnerText2: '',
7310
7325
  scaleMax: 50,
7311
- colors: [],
7326
+ colors: this.color,
7312
7327
  transitions: false,
7313
7328
  majorTicks: { visible: true, color: '#0000ff' },
7314
7329
  minorTicks: { visible: true, color: '#0000ff' },
@@ -7319,12 +7334,12 @@ class ZgaugeComponent extends FieldBase {
7319
7334
  endAngle: 180,
7320
7335
  rangePlaceholderColor: '#e6e5e5',
7321
7336
  labelsColor: '#0000ff',
7322
- rangeFrom: 0,
7323
- rangeTo: 100,
7324
7337
  rangeColor: '#ff6358',
7325
7338
  rangeLineCap: 'round',
7326
7339
  showLabels: true,
7327
7340
  rangeSize: 10,
7341
+ labelStyle: "text-align: center; font-size: 18px;",
7342
+ arcgaugeStyle: "margin-top:50px;width:90% ;height:100%; min-width: 330px;",
7328
7343
  };
7329
7344
  }
7330
7345
  ngOnInit() {
@@ -7353,25 +7368,24 @@ class ZgaugeComponent extends FieldBase {
7353
7368
  }
7354
7369
  getFieldDeclarationForSetup(field, options) {
7355
7370
  if (field.Value.startsWith('group.')) {
7356
- options.value = ZComponentHelper.getGroupEvalValue.call(this, field.Value) || options.value;
7371
+ options.value = ZComponentHelper.getGroupEvalValue.call(this, field.Value) ?? options.value;
7357
7372
  }
7358
7373
  else {
7359
- options.value = this.group.zModel[field.Value] || options.value;
7374
+ options.value = this.group.zModel[field.Value] ?? options.value;
7360
7375
  options.value = parseInt(options.value);
7361
7376
  }
7362
7377
  options.title = ZComponentHelper.getGroupEvalValue.call(this, field.Title) || options.title;
7363
- options.scaleMax = field.Max || options.scaleMax; // not using
7364
7378
  options.minValue = ZComponentHelper.getGroupEvalValue.call(this, field.MinValue) || options.minValue || 0;
7365
7379
  options.maxValue = ZComponentHelper.getGroupEvalValue.call(this, field.MaxValue) || options.maxValue || 100;
7366
- options.colors = ZComponentHelper.getGroupEvalValue.call(this, field.Color) || options.colors || { color: "#0175c7" };
7380
+ options.colors = ZComponentHelper.getGroupEvalValue.call(this, field.Color) || options.colors;
7367
7381
  options.transitions = field.Transitions || options.transitions;
7368
- options.majorTicks = ZComponentHelper.getGroupEvalValue.call(this, field.MajorTicks) || options.majorTicks || { visible: true, color: '#0000ff' };
7369
- options.minorTicks = ZComponentHelper.getGroupEvalValue.call(this, field.MinorTicks) || options.minorTicks || { visible: true, color: '#0000ff' };
7382
+ options.majorTicks = ZComponentHelper.getGroupEvalValue.call(this, field.MajorTicks) || options.majorTicks;
7383
+ options.minorTicks = ZComponentHelper.getGroupEvalValue.call(this, field.MinorTicks) || options.minorTicks;
7370
7384
  options.showLabels = field.ShowLabels != undefined ? field.ShowLabels : options.showLabels;
7371
7385
  options.style = field.Style || options.style;
7372
7386
  options.reverse = field.Reverse || options.reverse;
7373
- options.startAngle = ZComponentHelper.getGroupEvalValue.call(this, field.StartAngle) || options.startAngle || 0;
7374
- options.endAngle = ZComponentHelper.getGroupEvalValue.call(this, field.EndAngle) || options.endAngle || 180;
7387
+ options.startAngle = field.StartAngle || options.startAngle || 0;
7388
+ options.endAngle = field.EndAngle || options.endAngle || 180;
7375
7389
  options.rangePlaceholderColor = field.RangePlaceholderColor || options.rangePlaceholderColor;
7376
7390
  options.rangeFrom = ZComponentHelper.getGroupEvalValue.call(this, field['RangeFrom']) || options.rangeFrom;
7377
7391
  options.rangeTo = ZComponentHelper.getGroupEvalValue.call(this, field['RangeTo']) || options.rangeTo;
@@ -7392,10 +7406,10 @@ class ZgaugeComponent extends FieldBase {
7392
7406
  }
7393
7407
  }
7394
7408
  ZgaugeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: ZgaugeComponent, deps: [{ token: ZComponentService }], target: i0.ɵɵFactoryTarget.Component });
7395
- ZgaugeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.3", type: ZgaugeComponent, selector: "app-zgauge", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\" style=\"text-align: center;\">\r\n <div id=\"marketShareContainer\" class=\"ion-row\" class=\"col-xs-12 stats-graph\" *ngIf=\"options.title\">\r\n <h6 style=\"color: gray;\">{{ options.title }}</h6>\r\n </div>\r\n <div [ngStyle]='alignment()'>\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\" style=\"margin-top:50px;width:90% ;height:100%; min-width: 330px;\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <span [style.color]=\"color\">{{ value }}</span>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>\r\n\r\n<!--<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\"\r\n [style]=\"componentProperties.style.style\" class=\"e1tag-style\">\r\n <div class=\"chart-top-title e1tag-style1\" [style]=\"componentProperties.style.style1\" *ngIf=\"options.title\">\r\n {{options.title}}\r\n </div>\r\n <div [style]=\"componentProperties.style.style2\" class=\"e1tag-style2\">\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\"\r\n [style]=\"getGaugeStyle()\" class=\"e1tag-style3\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <div *ngIf=\"options.chartInnerText1\" [style]=\"componentProperties.style.style4\" class=\"e1tag-style4\">{{ options.chartInnerText1 }}</div>\r\n <div *ngIf=\"options.chartInnerText2\" [style]=\"componentProperties.style.style5\" class=\"e1tag-style5\">{{ options.chartInnerText2 }}</div>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>-->\r\n\r\n", styles: [""], components: [{ type: i2$8.ArcGaugeComponent, selector: "kendo-arcgauge", inputs: ["value", "color", "colors", "opacity", "scale"], exportAs: ["kendoArcGauge"] }, { type: i2$8.ArcScaleComponent, selector: "kendo-arcgauge-scale", inputs: ["labels", "rangeDistance", "rangeLineCap", "startAngle", "endAngle"] }, { type: i2$8.ArcLabelsComponent, selector: "kendo-arcgauge-scale-labels" }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i7.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i2$8.ArcCenterTemplateDirective, selector: "[kendoArcGaugeCenterTemplate]" }] });
7409
+ ZgaugeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.3", type: ZgaugeComponent, selector: "app-zgauge", usesInheritance: true, ngImport: i0, template: "<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\" [style]=\"componentProperties.style.style\">\r\n <div id=\"marketShareContainer\" class=\"ion-row\" class=\"col-xs-12 stats-graph\" *ngIf=\"options.title\">\r\n <h6 style=\"color: gray;\">{{ options.title }}</h6>\r\n </div>\r\n <div [ngStyle]='alignment()'>\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\" [style]=\"componentProperties.style.style1\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <span [style.color]=\"color\" [style]=\"componentProperties.style.style2\">{{ value }}</span>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>\r\n\r\n<!--<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\"\r\n [style]=\"componentProperties.style.style\" class=\"e1tag-style\">\r\n <div class=\"chart-top-title e1tag-style1\" [style]=\"componentProperties.style.style1\" *ngIf=\"options.title\">\r\n {{options.title}}\r\n </div>\r\n <div [style]=\"componentProperties.style.style2\" class=\"e1tag-style2\">\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\"\r\n [style]=\"getGaugeStyle()\" class=\"e1tag-style3\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <div *ngIf=\"options.chartInnerText1\" [style]=\"componentProperties.style.style4\" class=\"e1tag-style4\">{{ options.chartInnerText1 }}</div>\r\n <div *ngIf=\"options.chartInnerText2\" [style]=\"componentProperties.style.style5\" class=\"e1tag-style5\">{{ options.chartInnerText2 }}</div>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>-->\r\n\r\n", styles: [""], components: [{ type: i2$8.ArcGaugeComponent, selector: "kendo-arcgauge", inputs: ["value", "color", "colors", "opacity", "scale"], exportAs: ["kendoArcGauge"] }, { type: i2$8.ArcScaleComponent, selector: "kendo-arcgauge-scale", inputs: ["labels", "rangeDistance", "rangeLineCap", "startAngle", "endAngle"] }, { type: i2$8.ArcLabelsComponent, selector: "kendo-arcgauge-scale-labels" }], directives: [{ type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i7.DefaultStyleDirective, selector: " [ngStyle], [ngStyle.xs], [ngStyle.sm], [ngStyle.md], [ngStyle.lg], [ngStyle.xl], [ngStyle.lt-sm], [ngStyle.lt-md], [ngStyle.lt-lg], [ngStyle.lt-xl], [ngStyle.gt-xs], [ngStyle.gt-sm], [ngStyle.gt-md], [ngStyle.gt-lg]", inputs: ["ngStyle", "ngStyle.xs", "ngStyle.sm", "ngStyle.md", "ngStyle.lg", "ngStyle.xl", "ngStyle.lt-sm", "ngStyle.lt-md", "ngStyle.lt-lg", "ngStyle.lt-xl", "ngStyle.gt-xs", "ngStyle.gt-sm", "ngStyle.gt-md", "ngStyle.gt-lg"] }, { type: i2$8.ArcCenterTemplateDirective, selector: "[kendoArcGaugeCenterTemplate]" }] });
7396
7410
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: ZgaugeComponent, decorators: [{
7397
7411
  type: Component,
7398
- args: [{ selector: 'app-zgauge', template: "<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\" style=\"text-align: center;\">\r\n <div id=\"marketShareContainer\" class=\"ion-row\" class=\"col-xs-12 stats-graph\" *ngIf=\"options.title\">\r\n <h6 style=\"color: gray;\">{{ options.title }}</h6>\r\n </div>\r\n <div [ngStyle]='alignment()'>\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\" style=\"margin-top:50px;width:90% ;height:100%; min-width: 330px;\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <span [style.color]=\"color\">{{ value }}</span>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>\r\n\r\n<!--<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\"\r\n [style]=\"componentProperties.style.style\" class=\"e1tag-style\">\r\n <div class=\"chart-top-title e1tag-style1\" [style]=\"componentProperties.style.style1\" *ngIf=\"options.title\">\r\n {{options.title}}\r\n </div>\r\n <div [style]=\"componentProperties.style.style2\" class=\"e1tag-style2\">\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\"\r\n [style]=\"getGaugeStyle()\" class=\"e1tag-style3\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <div *ngIf=\"options.chartInnerText1\" [style]=\"componentProperties.style.style4\" class=\"e1tag-style4\">{{ options.chartInnerText1 }}</div>\r\n <div *ngIf=\"options.chartInnerText2\" [style]=\"componentProperties.style.style5\" class=\"e1tag-style5\">{{ options.chartInnerText2 }}</div>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>-->\r\n\r\n", styles: [""] }]
7412
+ args: [{ selector: 'app-zgauge', template: "<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\" [style]=\"componentProperties.style.style\">\r\n <div id=\"marketShareContainer\" class=\"ion-row\" class=\"col-xs-12 stats-graph\" *ngIf=\"options.title\">\r\n <h6 style=\"color: gray;\">{{ options.title }}</h6>\r\n </div>\r\n <div [ngStyle]='alignment()'>\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\" [style]=\"componentProperties.style.style1\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <span [style.color]=\"color\" [style]=\"componentProperties.style.style2\">{{ value }}</span>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>\r\n\r\n<!--<div *ngIf=\"!isLoading && (!!componentProperties.isVisibleField ? group[componentProperties.isVisibleField] : componentProperties.isVisible)\"\r\n [style]=\"componentProperties.style.style\" class=\"e1tag-style\">\r\n <div class=\"chart-top-title e1tag-style1\" [style]=\"componentProperties.style.style1\" *ngIf=\"options.title\">\r\n {{options.title}}\r\n </div>\r\n <div [style]=\"componentProperties.style.style2\" class=\"e1tag-style2\">\r\n <kendo-arcgauge [value]=\"options.value\" [transitions]=\"options.transitions\" [colors]=\"options.colors\"\r\n [style]=\"getGaugeStyle()\" class=\"e1tag-style3\">\r\n <kendo-arcgauge-scale [majorTicks]=\"options.majorTicks\"\r\n [minorTicks]=\"options.minorTicks\"\r\n [reverse]=\"options.reverse\"\r\n [startAngle]=\"options.startAngle\"\r\n [endAngle]=\"options.endAngle\"\r\n [min]=\"options.minValue\"\r\n [max]=\"options.maxValue\"\r\n [rangePlaceholderColor]=\"options.rangePlaceholderColor\"\r\n [rangeSize]=\"options.rangeSize\"\r\n [rangeLineCap]=\"options.rangeLineCap\">\r\n <kendo-arcgauge-scale-labels format=\"l\" [color]=\"options.labelsColor\" [visible]=\"options.showLabels\">\r\n </kendo-arcgauge-scale-labels>\r\n </kendo-arcgauge-scale>\r\n <ng-template kendoArcGaugeCenterTemplate let-value=\"value\" let-color=\"color\">\r\n <div *ngIf=\"options.chartInnerText1\" [style]=\"componentProperties.style.style4\" class=\"e1tag-style4\">{{ options.chartInnerText1 }}</div>\r\n <div *ngIf=\"options.chartInnerText2\" [style]=\"componentProperties.style.style5\" class=\"e1tag-style5\">{{ options.chartInnerText2 }}</div>\r\n </ng-template>\r\n </kendo-arcgauge>\r\n </div>\r\n</div>-->\r\n\r\n", styles: [""] }]
7399
7413
  }], ctorParameters: function () { return [{ type: ZComponentService }]; } });
7400
7414
 
7401
7415
  const hideAndShowVerticalAnimation = trigger('hideAndShowAnimation', [
@@ -9041,24 +9055,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImpor
9041
9055
  class MyFileInfo {
9042
9056
  }
9043
9057
  class ZuploadComponent extends InputFieldBase {
9044
- // zModelValue = [{
9045
- // name: "RXJS 01.png",
9046
- // size: 128753,
9047
- // uid: "c96e234d-af61-4587-adcc-3b400ddef884"
9048
- // }];
9049
- // fieldElement = [{
9050
- // Name: 'FileUploadList',
9051
- // Type: 'zupload',
9052
- // Value: 'FileUploadList',
9053
- // SelectionOptions: ['jpg', 'jpeg', 'png', 'bmp', 'pdf'],
9054
- // UploadMetaData: 'group.UploadMetaData',
9055
- // AutoUpload: false,
9056
- // AllowRemove: true,
9057
- // Multiple: false,
9058
- // OnSuccess: 'group.onSuccess()',
9059
- // DivClass: "col-md-12 col-md-6",
9060
- // Visible: true
9061
- // }];
9062
9058
  constructor(componentService, authService, compressImage, zcoreService, ngZone, sharePointService, alertService) {
9063
9059
  super(componentService);
9064
9060
  this.componentService = componentService;
@@ -9068,6 +9064,7 @@ class ZuploadComponent extends InputFieldBase {
9068
9064
  this.ngZone = ngZone;
9069
9065
  this.sharePointService = sharePointService;
9070
9066
  this.alertService = alertService;
9067
+ // NOTE: Naming: `uid` array actually stores preview UIDs. Consider renaming to `previewUids` in future (not changed to preserve API).
9071
9068
  this.uploadAttachmentUrl = null;
9072
9069
  this.uploadSaveUrl = "/Attachment/Chunk_Upload_Save"; // should represent an actual API endpoint
9073
9070
  this.uploadRemoveUrl = "/Attachment/Chunk_Upload_Remove"; // should represent an actual API endpoint
@@ -9075,9 +9072,9 @@ class ZuploadComponent extends InputFieldBase {
9075
9072
  this.getImageUrl = "/Attachment/getImage"; // GET method
9076
9073
  this.isAutoUpload = false;
9077
9074
  this.isMultiple = false;
9075
+ this.showFileList = true;
9078
9076
  this.imagePreviews = [];
9079
9077
  this.uid = [];
9080
- this.showFileList = true;
9081
9078
  this.fileList = [];
9082
9079
  this.restrictions = {
9083
9080
  minFileSize: 1,
@@ -9102,74 +9099,132 @@ class ZuploadComponent extends InputFieldBase {
9102
9099
  size: 102400,
9103
9100
  maxAutoRetries: 3,
9104
9101
  };
9105
- this.uploadAttachmentUrl = this.zcoreService.normalizeUrl(this.zcoreService.getEnvironment().uploadAttachmentUrl);
9106
- this.uploadSaveUrl = this.uploadAttachmentUrl + this.uploadSaveUrl;
9107
- this.uploadRemoveUrl = this.uploadAttachmentUrl + this.uploadRemoveUrl;
9102
+ const env = this.zcoreService.getEnvironment();
9103
+ const normalized = this.zcoreService.normalizeUrl(env?.uploadAttachmentUrl);
9104
+ this.uploadAttachmentUrl = normalized ?? null;
9105
+ if (this.uploadAttachmentUrl) {
9106
+ this.uploadSaveUrl = this.uploadAttachmentUrl + this.uploadSaveUrl;
9107
+ this.uploadRemoveUrl = this.uploadAttachmentUrl + this.uploadRemoveUrl;
9108
+ }
9109
+ else {
9110
+ // Safer logging: avoid silent null URLs that break uploads
9111
+ // NOTE: This indicates a configuration issue.
9112
+ console.warn(`[ZuploadComponent] uploadAttachmentUrl is empty. Upload endpoints may be invalid.`, { uploadAttachmentUrl: env?.uploadAttachmentUrl });
9113
+ }
9114
+ this.defaultUploadSaveUrl = this.uploadSaveUrl;
9115
+ this.defaultUploadRemoveUrl = this.uploadRemoveUrl;
9108
9116
  }
9117
+ /**
9118
+ * Angular lifecycle hook - initializes restrictions and upload behavior from field config.
9119
+ */
9109
9120
  ngOnInit() {
9110
9121
  super.setupInnerField();
9111
- // this.group['UploadMetaData'] = new UploadMetaData(null, '15', 'SO-No-1234', 'SaleOrder');
9112
- // this.uploadSaveUrl = uploadAttachmentUrl + this.uploadSaveUrl;
9113
- // this.uploadRemoveUrl = uploadAttachmentUrl + this.uploadRemoveUrl;
9114
- if (this.data.SelectOptions && !this.data.AllowedFileExtension) {
9122
+ // Allowed extensions:
9123
+ // - If SelectOptions present and AllowedFileExtension not present, override
9124
+ // - Else if AllowedFileExtension present and SelectOptions absent, append
9125
+ // NOTE: Keep original behavior; it may allow duplicates, but prevents unexpected restriction loss.
9126
+ if (this.data?.SelectOptions && !this.data?.AllowedFileExtension) {
9115
9127
  this.restrictions.allowedExtensions = this.data.SelectOptions;
9116
9128
  }
9117
- else if (!this.data.SelectOptions && this.data.AllowedFileExtension) {
9129
+ else if (!this.data?.SelectOptions && this.data?.AllowedFileExtension) {
9118
9130
  this.restrictions.allowedExtensions = this.restrictions.allowedExtensions.concat(this.data.AllowedFileExtension);
9119
9131
  }
9120
- if (this.data.MinFileSize) {
9132
+ if (typeof this.data?.MinFileSize === "number" && this.data.MinFileSize >= 0) {
9121
9133
  this.restrictions.minFileSize = this.data.MinFileSize;
9122
9134
  }
9123
- if (this.data.MaxFileSize) {
9135
+ if (typeof this.data?.MaxFileSize === "number" && this.data.MaxFileSize >= 0) {
9124
9136
  this.restrictions.maxFileSize = this.data.MaxFileSize;
9125
9137
  }
9126
- this.isAutoUpload = this.data.AutoUpload || false;
9127
- if (!this.data.AllowRemove) {
9138
+ this.isAutoUpload = Boolean(this.data?.AutoUpload);
9139
+ // If remove is not allowed, Kendo upload expects empty URL to hide remove request.
9140
+ if (this.data && this.data.AllowRemove === false) {
9128
9141
  this.uploadRemoveUrl = "";
9129
9142
  }
9130
- if (this.data.Multiple) {
9131
- this.isMultiple = this.data.Multiple;
9132
- }
9133
- this.componentProperties.style.style6 = this.componentProperties.style.style6 || "margin: 5px; border: 1px solid gray;";
9143
+ this.isMultiple = Boolean(this.data?.Multiple);
9144
+ // Ensure style6 exists (legacy styling hook).
9145
+ this.componentProperties.style.style6 =
9146
+ this.componentProperties.style.style6 || "margin: 5px; border: 1px solid gray;";
9134
9147
  }
9148
+ /**
9149
+ * Kendo Upload success callback for both upload and remove.
9150
+ * Keeps zModel in sync and emits ZComponent output events.
9151
+ */
9135
9152
  onSuccess(e) {
9136
- // angular kendo upload didn't filter away Sent event for remove, so we have to handle it here
9137
- // upload progress not required for removal, thus it's also removed
9138
- // @ts-ignore
9139
- if (e.operation === "remove" && (e.response.type === HttpEventType.Sent || e.response.type === HttpEventType.UploadProgress)) {
9153
+ // Angular Kendo Upload emits "Sent" and "UploadProgress" for remove; ignore them to avoid double-handling.
9154
+ // @ts-ignore - Kendo types for response differ by runtime usage
9155
+ const responseType = e?.response?.type;
9156
+ if (e?.operation === "remove" &&
9157
+ (responseType === HttpEventType.Sent || responseType === HttpEventType.UploadProgress)) {
9158
+ return;
9159
+ }
9160
+ const modelKey = this.data?.Value;
9161
+ if (!modelKey) {
9162
+ console.warn(`[ZuploadComponent] onSuccess skipped: missing data.Value.`, { event: e });
9163
+ return;
9164
+ }
9165
+ if (!this.group?.zModel) {
9166
+ console.warn(`[ZuploadComponent] onSuccess skipped: missing group.zModel.`, { event: e });
9140
9167
  return;
9141
9168
  }
9142
- if (!Array.isArray(this.group.zModel[this.data.Value])) {
9143
- this.group.zModel[this.data.Value] = [];
9169
+ if (!Array.isArray(this.group.zModel[modelKey])) {
9170
+ this.group.zModel[modelKey] = [];
9171
+ }
9172
+ const file = e?.files?.[0] ?? undefined;
9173
+ if (!file) {
9174
+ console.warn(`[ZuploadComponent] onSuccess: no file found in event.`, { event: e });
9175
+ return;
9144
9176
  }
9145
- const file = e.files[0];
9146
- const existingFileIndex = this.group.zModel[this.data.Value].findIndex(f => f.name === file.name && f.uid === file.uid);
9177
+ const existingFileIndex = this.group.zModel[modelKey].findIndex((f) => f?.name === file.name && f?.uid === file.uid);
9147
9178
  if (e.operation === "upload") {
9148
- // console.log('upload Success: ', e);
9149
- //sharepoint required to read data from fileUid and attachment able to get data from fileUid too.
9150
- file.myUid = e.response?.body?.fileUid ?? file.uid;
9151
- delete file['httpSubscription'];
9179
+ // SharePoint and Attachment use fileUid (server) for later operations.
9180
+ // Prefer fileUid if provided; fallback to file.uid
9181
+ // @ts-ignore - body shape is runtime-dependent
9182
+ file.myUid = e?.response?.body?.fileUid ?? file.uid;
9183
+ // Clean up internal subscription data to avoid circular structures
9184
+ // NOTE: This relies on Kendo attaching internal fields; safe delete.
9185
+ delete file["httpSubscription"];
9152
9186
  if (existingFileIndex !== -1) {
9153
- this.group.zModel[this.data.Value][existingFileIndex] = file;
9187
+ this.group.zModel[modelKey][existingFileIndex] = file;
9154
9188
  }
9155
9189
  else {
9156
- this.group.zModel[this.data.Value].push(file);
9190
+ this.group.zModel[modelKey].push(file);
9157
9191
  }
9192
+ console.info(`[ZuploadComponent] Upload succeeded.`, {
9193
+ name: file.name,
9194
+ uid: file.uid,
9195
+ myUid: file.myUid,
9196
+ });
9158
9197
  }
9159
9198
  else if (e.operation === "remove") {
9160
9199
  if (existingFileIndex !== -1) {
9161
- this.group.zModel[this.data.Value].splice(existingFileIndex, 1);
9200
+ this.group.zModel[modelKey].splice(existingFileIndex, 1);
9162
9201
  }
9202
+ console.info(`[ZuploadComponent] Remove succeeded.`, {
9203
+ name: file.name,
9204
+ uid: file.uid,
9205
+ myUid: file.myUid,
9206
+ });
9163
9207
  }
9164
- ZComponentHelper.setComponentModelValue(this.data, this.group.zModel[this.data.Value], this.group);
9165
- this.group.subject.next({
9208
+ else {
9209
+ // Unknown operation, preserve behavior but log for diagnostics.
9210
+ console.debug(`[ZuploadComponent] onSuccess received unsupported operation.`, { operation: e.operation, event: e });
9211
+ }
9212
+ ZComponentHelper.setComponentModelValue(this.data, this.group.zModel[modelKey], this.group);
9213
+ this.group.subject?.next({
9166
9214
  type: "zupload-onSuccess",
9167
- target: this.data.OnSuccess,
9215
+ target: this.data?.OnSuccess,
9168
9216
  event: e,
9169
- data: { value: e.files[0], field: this.data },
9217
+ data: { value: file, field: this.data },
9170
9218
  });
9171
9219
  }
9220
+ /**
9221
+ * Normalize and enrich image compression config with byte-based thresholds.
9222
+ */
9172
9223
  compressionConfigHandler(imgConfig) {
9224
+ if (!imgConfig) {
9225
+ // NOTE: keep function safe for unexpected null; returns as-is
9226
+ return imgConfig;
9227
+ }
9173
9228
  if (imgConfig.FileSizeMaxSize) {
9174
9229
  imgConfig.FileSizeMaxSizeByte = this.convertSizeToByte(imgConfig.FileSizeMaxSize);
9175
9230
  }
@@ -9181,79 +9236,114 @@ class ZuploadComponent extends InputFieldBase {
9181
9236
  }
9182
9237
  return imgConfig;
9183
9238
  }
9239
+ /**
9240
+ * Convert string size values like "10KB", "2 MB", "1gb", "1024" into bytes.
9241
+ * If unit is omitted, bytes are assumed.
9242
+ *
9243
+ * @param sizeString Human readable size string.
9244
+ * @returns Size in bytes. Returns 0 if parsing fails.
9245
+ */
9184
9246
  convertSizeToByte(sizeString) {
9185
- let _tempFileSizeMaxSize = 0;
9247
+ if (!sizeString || typeof sizeString !== "string") {
9248
+ return 0;
9249
+ }
9250
+ // Remove all spaces
9251
+ const raw = sizeString.replace(/ /g, "").trim();
9252
+ if (!raw) {
9253
+ return 0;
9254
+ }
9255
+ let parsedValue = 0;
9186
9256
  let sizeByByte = 0;
9187
- let sizeType = 'b';
9188
- // remove all space
9189
- const _tempFileSize = sizeString.replace(/ /g, '');
9190
- // check last char is alphabetic
9191
- const lastChar = _tempFileSize.substr(_tempFileSize.length - 1);
9192
- if (isNaN(parseFloat(lastChar))) {
9193
- const secLastChar = _tempFileSize.substr(_tempFileSize.length - 2).slice(0, -1);
9194
- if (isNaN(parseFloat(secLastChar))) {
9195
- // check last 2nd char is alphabetic
9196
- sizeType = secLastChar + sizeType;
9197
- _tempFileSizeMaxSize = parseFloat(_tempFileSize.slice(0, -2));
9257
+ let sizeType = "b";
9258
+ // Check last char is alphabetic
9259
+ const lastChar = raw.substring(raw.length - 1);
9260
+ const lastCharIsNumber = !Number.isNaN(Number.parseFloat(lastChar));
9261
+ if (!lastCharIsNumber) {
9262
+ const secondLastChar = raw.substring(raw.length - 2).slice(0, -1);
9263
+ const secondLastIsNumber = !Number.isNaN(Number.parseFloat(secondLastChar));
9264
+ if (!secondLastIsNumber) {
9265
+ // Last 2nd char is also alphabetic (e.g. "MB", "GB")
9266
+ sizeType = `${secondLastChar}${sizeType}`;
9267
+ parsedValue = Number.parseFloat(raw.slice(0, -2));
9198
9268
  }
9199
9269
  else {
9200
- _tempFileSizeMaxSize = parseFloat(_tempFileSize.slice(0, -1));
9270
+ parsedValue = Number.parseFloat(raw.slice(0, -1));
9271
+ }
9272
+ // If parsing failed, return 0 (SonarQube safe behavior)
9273
+ if (Number.isNaN(parsedValue) || parsedValue < 0) {
9274
+ console.warn(`[ZuploadComponent] convertSizeToByte: invalid size value.`, { sizeString });
9275
+ return 0;
9201
9276
  }
9202
9277
  switch (sizeType.toLowerCase()) {
9203
9278
  case "b":
9204
- sizeByByte = _tempFileSizeMaxSize;
9279
+ sizeByByte = parsedValue;
9205
9280
  break;
9206
9281
  case "kb":
9207
- sizeByByte = _tempFileSizeMaxSize * 1024;
9282
+ sizeByByte = parsedValue * 1024;
9208
9283
  break;
9209
9284
  case "mb":
9210
- sizeByByte = _tempFileSizeMaxSize * 1048576;
9285
+ sizeByByte = parsedValue * 1048576;
9211
9286
  break;
9212
9287
  case "gb":
9213
- sizeByByte = _tempFileSizeMaxSize * 1073741824;
9288
+ sizeByByte = parsedValue * 1073741824;
9289
+ break;
9290
+ default:
9291
+ // Unknown unit => treat as bytes for backward compatibility
9292
+ console.warn(`[ZuploadComponent] convertSizeToByte: unknown unit, defaulting to bytes.`, {
9293
+ sizeString,
9294
+ unit: sizeType,
9295
+ });
9296
+ sizeByByte = parsedValue;
9214
9297
  break;
9215
9298
  }
9216
9299
  }
9217
9300
  else {
9218
- // default using bytes if no size type
9219
- sizeByByte = parseFloat(_tempFileSize);
9301
+ // Default using bytes if no size type
9302
+ const n = Number.parseFloat(raw);
9303
+ if (Number.isNaN(n) || n < 0) {
9304
+ console.warn(`[ZuploadComponent] convertSizeToByte: invalid numeric bytes value.`, { sizeString });
9305
+ return 0;
9306
+ }
9307
+ sizeByByte = n;
9220
9308
  }
9221
9309
  return sizeByByte;
9222
9310
  }
9311
+ /**
9312
+ * Kendo Upload upload event: validates files, builds image previews, injects metadata and auth header.
9313
+ */
9223
9314
  uploadEventHandler(e) {
9315
+ if (!e?.files?.length) {
9316
+ console.warn(`[ZuploadComponent] uploadEventHandler: no files in UploadEvent.`);
9317
+ return;
9318
+ }
9224
9319
  // Image Preview
9225
- const me = this;
9226
9320
  e.files.forEach((file) => {
9227
- if (!me.isValidUploadedFile(me, file)) {
9321
+ if (!this.isValidUploadedFile(file)) {
9228
9322
  e.preventDefault();
9229
9323
  return;
9230
9324
  }
9231
- else {
9232
- if (file.rawFile && file.rawFile.type.includes("image")) {
9233
- if (!file.validationErrors) {
9234
- const reader = new FileReader();
9235
- reader.onload = function (ev) {
9236
- if (me.data.EnableImagePreview) {
9237
- if (!me.uid.includes(file.uid)) {
9238
- me.uid.push(file.uid);
9239
- me.imagePreviews.push({ ...file, src: reader.result });
9240
- }
9241
- }
9242
- };
9243
- reader.readAsDataURL(file.rawFile);
9325
+ if (file?.rawFile?.type?.includes("image") && !file.validationErrors) {
9326
+ const reader = new FileReader();
9327
+ reader.onload = () => {
9328
+ if (this.data?.EnableImagePreview) {
9329
+ if (!this.uid.includes(file.uid)) {
9330
+ this.uid.push(file.uid);
9331
+ this.imagePreviews.push({ ...file, src: reader.result });
9332
+ }
9244
9333
  }
9245
- }
9334
+ };
9335
+ reader.readAsDataURL(file.rawFile);
9246
9336
  }
9247
9337
  });
9248
9338
  // Add metadata to the upload event
9249
- let additional = ZComponentHelper.getGroupEvalValue.call(this, this.data.UploadMetaData);
9339
+ let additional = ZComponentHelper.getGroupEvalValue.call(this, this.data?.UploadMetaData);
9250
9340
  if (!(additional instanceof UploadMetaData)) {
9251
- console.error("UploadMetaData defined at " + this.data.UploadMetaData + " is invalid: ", additional);
9341
+ console.warn(`[ZuploadComponent] Invalid UploadMetaData at "${this.data?.UploadMetaData}". Fallback to default metadata.`, additional);
9252
9342
  additional = new UploadMetaData(null, "0");
9253
9343
  }
9254
9344
  //#region sharepoint
9255
- let attachmentInfo = this.sharePointService.getAttachmentInfo(this.data["DownloadFileConfig"]);
9256
- //add tagging into metadata
9345
+ const attachmentInfo = this.sharePointService.getAttachmentInfo(this.data?.["DownloadFileConfig"]);
9346
+ // Add tagging into metadata
9257
9347
  if (attachmentInfo) {
9258
9348
  if (attachmentInfo.tag) {
9259
9349
  const tag = this.sharePointService.generateTagging(this.group, attachmentInfo.tag);
@@ -9264,155 +9354,270 @@ class ZuploadComponent extends InputFieldBase {
9264
9354
  additional[AttachmentConfig.isSaveToSharePoint] = attachmentInfo.isSaveToSharePoint;
9265
9355
  }
9266
9356
  //#endregion
9267
- const str = JSON.stringify(additional);
9268
- e.data = { additional: str, };
9269
- e.headers = e.headers.append("Authorization", "Bearer " + this.authService.e1AccessToken);
9357
+ additional[AttachmentConfig.projectCode] = this.data?.ProjectCode;
9358
+ additional[AttachmentConfig.moduleCode] = this.data?.ModuleCode;
9359
+ const payload = JSON.stringify(additional);
9360
+ e.data = { additional: payload };
9361
+ // NOTE: Potentially unsafe: assumes token is always present. Keep behavior but add clearer logging.
9362
+ const token = this.authService?.e1AccessToken;
9363
+ if (!token) {
9364
+ console.warn(`[ZuploadComponent] Missing e1AccessToken. Upload may fail due to authorization.`);
9365
+ }
9366
+ e.headers = e.headers.append("Authorization", `Bearer ${token ?? ""}`);
9270
9367
  }
9368
+ /**
9369
+ * Kendo Upload remove event: updates component memory, fires project event if defined,
9370
+ * otherwise attaches required payload and authorization headers.
9371
+ */
9271
9372
  onRemove(e) {
9272
- // remove file from component memory
9273
- const index = this.fileList.findIndex((item) => item.uid === e.files[0].uid);
9373
+ const file = e?.files?.[0];
9374
+ if (!file) {
9375
+ console.warn(`[ZuploadComponent] onRemove: no file found in RemoveEvent.`, { event: e });
9376
+ return;
9377
+ }
9378
+ // Remove file from component memory (for SelectFileOnly flow)
9379
+ const index = this.fileList.findIndex((item) => item.uid === file.uid);
9274
9380
  if (index >= 0) {
9275
9381
  this.fileList.splice(index, 1);
9276
- this.group['zupload_' + this.data.Value] = this.fileList;
9382
+ this.group[`zupload_${this.data?.Value}`] = this.fileList;
9277
9383
  }
9278
- if (this.data['FileRemovedEvent']) {
9279
- this.group.subject.next({
9384
+ const removedEvent = this.data?.["FileRemovedEvent"];
9385
+ if (removedEvent) {
9386
+ this.group.subject?.next({
9280
9387
  type: "zupload-fileRemovedEvent",
9281
- target: this.data['FileRemovedEvent'],
9282
- data: e
9388
+ target: removedEvent,
9389
+ data: e,
9283
9390
  });
9391
+ return;
9284
9392
  }
9285
- else {
9286
- const myFile = e.files[0];
9287
- // console.log('remove done: ', e);
9288
- e.data = {
9289
- id: myFile.myUid,
9290
- };
9291
- e.headers = e.headers.append("Authorization", "Bearer " + this.authService.e1AccessToken);
9292
- if (this.data.EnableImagePreview) {
9293
- e.files.forEach((file) => {
9294
- this.imagePreviews = this.imagePreviews.filter(f => f.uid !== file.uid);
9295
- });
9296
- }
9393
+ const myFile = file;
9394
+ // Attach remove payload
9395
+ e.data = { id: myFile.myUid };
9396
+ const token = this.authService?.e1AccessToken;
9397
+ if (!token) {
9398
+ console.warn(`[ZuploadComponent] Missing e1AccessToken. Remove may fail due to authorization.`);
9399
+ }
9400
+ e.headers = e.headers.append("Authorization", `Bearer ${token ?? ""}`);
9401
+ // Remove preview if enabled
9402
+ if (this.data?.EnableImagePreview) {
9403
+ e.files.forEach((f) => {
9404
+ this.imagePreviews = this.imagePreviews.filter((p) => p?.["uid"] !== f.uid);
9405
+ });
9297
9406
  }
9407
+ console.info(`[ZuploadComponent] Remove requested.`, { name: myFile.name, uid: myFile.uid, myUid: myFile.myUid });
9298
9408
  }
9299
- onChange(file) {
9300
- if (this.data['FileChangedEvent']) {
9301
- this.group.subject.next({
9302
- type: "zupload-fileChangedEvent",
9303
- target: this.data['FileChangedEvent'],
9304
- data: file
9305
- });
9409
+ /**
9410
+ * Kendo Upload change event handler. Emits project event if configured.
9411
+ */
9412
+ onChange(files) {
9413
+ const changedEvent = this.data?.["FileChangedEvent"];
9414
+ if (!changedEvent) {
9415
+ return;
9306
9416
  }
9417
+ this.group.subject?.next({
9418
+ type: "zupload-fileChangedEvent",
9419
+ target: changedEvent,
9420
+ data: files,
9421
+ });
9307
9422
  }
9308
- isValidUploadedFile(me, file) {
9309
- const fileSize = file.rawFile.size;
9310
- const fileExtension = file.rawFile.name.split('.').pop().toLowerCase();
9311
- // Check if file size and extension are valid
9312
- if (fileSize > me.restrictions.maxFileSize || !me.restrictions.allowedExtensions.includes(fileExtension)) {
9313
- let errorMessage = 'Error: ';
9314
- if (!me.restrictions.allowedExtensions.includes(fileExtension)) {
9315
- errorMessage = `Invalid file type. Allowed types are: ${me.restrictions.allowedExtensions.join(', ')}.`;
9316
- }
9317
- else if (fileSize > me.restrictions.maxFileSize) {
9318
- errorMessage = `File size cannot exceeds ${me.formatFileSize(me.restrictions.maxFileSize)}.`;
9319
- }
9320
- me.alertService.showOkay('Failed to upload', errorMessage, ['col-4']);
9423
+ /**
9424
+ * Validate a selected/uploaded file against configured restrictions (size + extension).
9425
+ *
9426
+ * @param file Kendo FileInfo
9427
+ * @returns true if file passes restrictions, otherwise false (and shows alert).
9428
+ */
9429
+ isValidUploadedFile(file) {
9430
+ const rawFile = file?.rawFile;
9431
+ if (!rawFile) {
9432
+ // NOTE: Kendo can provide FileInfo without rawFile in some events. Preserve behavior: treat as invalid.
9433
+ console.warn(`[ZuploadComponent] File validation failed: rawFile is missing.`, { file });
9434
+ this.alertService.showOkay("Failed to upload", "File is not available for upload.", ["col-4"]);
9435
+ return false;
9436
+ }
9437
+ const fileSize = rawFile.size ?? 0;
9438
+ // Keep original behavior: uses last segment after dot.
9439
+ // NOTE: Potentially unsafe for files without extension; will result in empty extension.
9440
+ const fileExtension = (rawFile.name?.split(".").pop() ?? "").toLowerCase();
9441
+ const max = this.restrictions?.maxFileSize ?? 0;
9442
+ const allowed = this.restrictions?.allowedExtensions ?? [];
9443
+ const isExtensionAllowed = allowed.includes(fileExtension);
9444
+ const isSizeAllowed = fileSize <= max;
9445
+ if (!isExtensionAllowed || !isSizeAllowed) {
9446
+ let errorMessage = "Error:";
9447
+ if (!isExtensionAllowed) {
9448
+ errorMessage = `Invalid file type "${fileExtension || "unknown"}". Allowed types: ${allowed.join(", ")}.`;
9449
+ }
9450
+ else if (!isSizeAllowed) {
9451
+ errorMessage = `File size cannot exceed ${this.formatFileSize(max)}.`;
9452
+ }
9453
+ console.warn(`[ZuploadComponent] File rejected by restrictions.`, {
9454
+ name: rawFile.name,
9455
+ size: fileSize,
9456
+ extension: fileExtension,
9457
+ maxAllowedBytes: max,
9458
+ allowedExtensions: allowed,
9459
+ });
9460
+ this.alertService.showOkay("Failed to upload", errorMessage, ["col-4"]);
9321
9461
  return false;
9322
9462
  }
9323
9463
  return true;
9324
9464
  }
9465
+ /**
9466
+ * Kendo Upload select event handler:
9467
+ * - Handles SharePoint endpoint switching
9468
+ * - Supports SelectFileOnly mode (read file content into memory and emit event)
9469
+ * - Supports image compression when AutoUpload is false
9470
+ */
9325
9471
  selectEventHandler(e) {
9326
- const me = this;
9472
+ if (!e?.files?.length) {
9473
+ console.warn(`[ZuploadComponent] selectEventHandler: no files in SelectEvent.`);
9474
+ return;
9475
+ }
9476
+ // Reset to default every selection to avoid SharePoint URL "sticking" permanently.
9477
+ this.uploadSaveUrl = this.defaultUploadSaveUrl;
9478
+ this.uploadRemoveUrl = this.defaultUploadRemoveUrl;
9327
9479
  //#region sharepoint
9328
- const attachmentInfo = this.sharePointService.getAttachmentInfo(this.data["DownloadFileConfig"]);
9480
+ const attachmentInfo = this.sharePointService.getAttachmentInfo(this.data?.["DownloadFileConfig"]);
9329
9481
  // Change uploadSaveUrl if saving to SharePoint
9330
- if (attachmentInfo && attachmentInfo.isSaveToSharePoint && attachmentInfo.siteName) {
9331
- const attachmentSourceUrl = this.zcoreService.getEnvironment().attachmentSourceUrl;
9332
- this.uploadSaveUrl = attachmentSourceUrl + '/Chunk_Upload_Save';
9482
+ if (attachmentInfo?.isSaveToSharePoint && attachmentInfo.siteName) {
9483
+ const attachmentSourceUrl = this.zcoreService.getEnvironment()?.attachmentSourceUrl;
9484
+ if (attachmentSourceUrl) {
9485
+ this.uploadSaveUrl = `${attachmentSourceUrl}/Chunk_Upload_Save`;
9486
+ console.info(`[ZuploadComponent] Upload endpoint switched to SharePoint mode.`, { uploadSaveUrl: this.uploadSaveUrl });
9487
+ }
9488
+ else {
9489
+ console.warn(`[ZuploadComponent] attachmentSourceUrl is missing. Cannot switch to SharePoint upload endpoint.`);
9490
+ }
9333
9491
  }
9334
9492
  //#endregion
9335
- if (this.data['SelectFileOnly']) {
9493
+ if (this.data?.["SelectFileOnly"]) {
9336
9494
  // Append all files to component memory
9337
- e.files.forEach(async (file) => {
9338
- if (me.isValidUploadedFile(me, file)) {
9339
- if (file.rawFile) {
9340
- const reader = new FileReader();
9341
- reader.onload = function (ev) {
9342
- // Clone the data and also add the read file to the object
9343
- const fileData = Object.assign({}, file);
9344
- fileData['file'] = ev.target["result"];
9345
- // Push to component fileList
9346
- me.fileList.push(fileData);
9347
- me.group['zupload_' + me.data.Value] = me.fileList;
9348
- if (me.data['FileSelectedEvent']) {
9349
- // Call the project event
9350
- me.group.subject.next({
9351
- type: "zupload-fileSelectedEvent",
9352
- target: me.data['FileSelectedEvent'],
9353
- data: me.fileList
9354
- });
9355
- }
9356
- };
9357
- await reader.readAsDataURL(file.rawFile);
9358
- }
9495
+ e.files.forEach((file) => {
9496
+ if (!this.isValidUploadedFile(file)) {
9497
+ e.preventDefault();
9498
+ return;
9359
9499
  }
9360
- else {
9500
+ if (!file.rawFile) {
9361
9501
  e.preventDefault();
9502
+ return;
9362
9503
  }
9504
+ const reader = new FileReader();
9505
+ reader.onload = (ev) => {
9506
+ // Clone the data and also add the read file to the object
9507
+ const fileData = {
9508
+ ...file,
9509
+ file: ev?.target?.result ?? null,
9510
+ };
9511
+ fileData["file"] = ev?.target?.result;
9512
+ // Push to component fileList
9513
+ this.fileList.push(fileData);
9514
+ this.group[`zupload_${this.data?.Value}`] = this.fileList;
9515
+ const selectedEvent = this.data?.["FileSelectedEvent"];
9516
+ if (selectedEvent) {
9517
+ this.group.subject?.next({
9518
+ type: "zupload-fileSelectedEvent",
9519
+ target: selectedEvent,
9520
+ data: this.fileList,
9521
+ });
9522
+ }
9523
+ };
9524
+ reader.onerror = () => {
9525
+ console.warn(`[ZuploadComponent] Failed to read file as base64.`, {
9526
+ name: file.rawFile?.name,
9527
+ uid: file.uid,
9528
+ error: reader.error,
9529
+ });
9530
+ };
9531
+ reader.readAsDataURL(file.rawFile);
9363
9532
  });
9533
+ return;
9364
9534
  }
9365
- else {
9366
- // Only workable for Auto Upload = false
9367
- if (!this.data.AutoUpload) {
9368
- // Compression for image file
9369
- const imageCompressionEnabled = this.data.Compression ? true : false;
9370
- //Check if Image Compression is enabled.
9371
- if (imageCompressionEnabled === true) {
9372
- e.files.forEach((file) => {
9373
- if (me.isValidUploadedFile(me, file)) {
9374
- // Compress only if it is an image file
9375
- if (file.rawFile && file.rawFile.type.includes("image")) {
9376
- if (!file.validationErrors) {
9377
- const imgConfig = this.compressionConfigHandler(this.data.Compression);
9378
- if (file.size > imgConfig.FileSizeMinSizeByte) {
9379
- me.compressImage.compress(file.rawFile, imgConfig) //Pass in parameter to set the Compression Options
9380
- .pipe(take(1))
9381
- .subscribe(compressFile => {
9382
- this.ngZone.run(() => {
9383
- file.rawFile = compressFile;
9384
- file.size = compressFile.size;
9385
- // Push to component fileList
9386
- me.fileList.push(Object.assign({}, file));
9387
- const reader = new FileReader();
9388
- reader.readAsDataURL(file.rawFile);
9389
- });
9390
- console.log(`Compressed file size: ${(file.rawFile.size / 1024).toFixed(2)}KB`);
9391
- });
9392
- } // file size check
9393
- } // validationErrors check
9394
- } // file type check
9395
- }
9396
- else {
9397
- e.preventDefault();
9398
- }
9399
- }); // loop each file
9400
- } // imagecompression check
9401
- // add to group scope
9402
- me.group['zupload_' + me.data.Value] = e.files;
9403
- }
9535
+ // Only workable for Auto Upload = false
9536
+ if (this.data?.AutoUpload) {
9537
+ return;
9538
+ }
9539
+ // Compression for image file
9540
+ const imageCompressionEnabled = Boolean(this.data?.Compression);
9541
+ // Check if Image Compression is enabled.
9542
+ if (imageCompressionEnabled) {
9543
+ e.files.forEach((file) => {
9544
+ if (!this.isValidUploadedFile(file)) {
9545
+ e.preventDefault();
9546
+ return;
9547
+ }
9548
+ // Compress only if it is an image file
9549
+ if (!file?.rawFile?.type?.includes("image") || file.validationErrors) {
9550
+ return;
9551
+ }
9552
+ const imgConfig = this.compressionConfigHandler(this.data.Compression);
9553
+ const minBytes = imgConfig?.FileSizeMinSizeByte ?? 0;
9554
+ // Original behavior: only compress if file size > minBytes
9555
+ if (file.size <= minBytes) {
9556
+ return;
9557
+ }
9558
+ this.compressImage
9559
+ .compress(file.rawFile, imgConfig) // Pass in parameter to set the Compression Options
9560
+ .pipe(take(1))
9561
+ .subscribe({
9562
+ next: (compressFile) => {
9563
+ this.ngZone.run(() => {
9564
+ file.rawFile = compressFile;
9565
+ file.size = compressFile.size;
9566
+ // Push to component fileList (kept as original intent)
9567
+ const fileData = { ...file };
9568
+ this.fileList.push(fileData);
9569
+ // Keep original: read to data URL (side effect)
9570
+ const reader = new FileReader();
9571
+ reader.readAsDataURL(file.rawFile);
9572
+ });
9573
+ console.info(`[ZuploadComponent] Image compressed successfully.`, {
9574
+ name: file?.rawFile?.name,
9575
+ newSizeKB: Number((file.rawFile.size / 1024).toFixed(2)),
9576
+ });
9577
+ },
9578
+ error: (err) => {
9579
+ // Preserve flow (do not block selection), but provide clearer diagnostic
9580
+ console.error(`[ZuploadComponent] Image compression failed. Upload will continue with original file.`, {
9581
+ name: file?.rawFile?.name,
9582
+ error: err,
9583
+ });
9584
+ },
9585
+ });
9586
+ });
9404
9587
  }
9588
+ // Add to group scope (original behavior: store selected files)
9589
+ this.group[`zupload_${this.data?.Value}`] = e.files;
9405
9590
  }
9591
+ /**
9592
+ * Clears UI-selected files and syncs group state.
9593
+ * NOTE: Original behavior sets group value to fileList (not empty); preserved.
9594
+ */
9406
9595
  clearFiles() {
9596
+ if (!this.uploadComponent) {
9597
+ console.warn(`[ZuploadComponent] clearFiles: uploadComponent is not ready.`);
9598
+ return;
9599
+ }
9407
9600
  this.uploadComponent.clearFiles();
9408
- this.group['zupload_' + this.data.Value] = this.fileList;
9601
+ this.group[`zupload_${this.data?.Value}`] = this.fileList;
9602
+ console.info(`[ZuploadComponent] Files cleared from UI.`, {
9603
+ storedFileListCount: this.fileList.length,
9604
+ });
9409
9605
  }
9606
+ /**
9607
+ * Format bytes into human-readable string.
9608
+ *
9609
+ * @param bytes Raw byte size
9610
+ * @returns Formatted file size string (e.g. "12.5MB")
9611
+ */
9410
9612
  formatFileSize(bytes) {
9411
- const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
9412
- if (bytes === 0)
9413
- return '0 Byte';
9613
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB"];
9614
+ if (!Number.isFinite(bytes) || bytes <= 0) {
9615
+ return "0 Byte";
9616
+ }
9414
9617
  const i = Math.floor(Math.log(bytes) / Math.log(1024));
9415
- return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + sizes[i];
9618
+ const value = bytes / Math.pow(1024, i);
9619
+ // NOTE: Original output had no space between number and unit; preserved.
9620
+ return `${Number.parseFloat(value.toFixed(2))}${sizes[i]}`;
9416
9621
  }
9417
9622
  }
9418
9623
  ZuploadComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: ZuploadComponent, deps: [{ token: ZComponentService }, { token: i2.AuthService }, { token: i2.CompressImageService }, { token: i2.ZCoreService }, { token: i0.NgZone }, { token: i2.SharePointService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component });
@@ -9422,7 +9627,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImpor
9422
9627
  args: [{ selector: "app-zupload", template: "<div [formGroup]=\"form\" class=\"zupload-container e1tag-style\" [style]=\"componentProperties.style.style\">\r\n <kendo-upload\r\n *ngIf=\"!data.SelectFileOnly\"\r\n #uploadComponent\r\n [id]=\"data.Value\"\r\n [autoUpload]=\"isAutoUpload\"\r\n [saveUrl]=\"uploadSaveUrl\"\r\n [removeUrl]=\"uploadRemoveUrl\"\r\n [restrictions]=\"restrictions\"\r\n [multiple]=\"isMultiple\"\r\n [chunkable]=\"chunkSettings\"\r\n [showFileList]=\"showFileList\"\r\n (select)=\"selectEventHandler($event)\"\r\n (remove)=\"onRemove($event)\"\r\n (success)=\"onSuccess($event)\"\r\n (upload)=\"uploadEventHandler($event)\"\r\n [style]=\"componentProperties.style.style1\"\r\n class=\"e1tag-style1\">\r\n </kendo-upload>\r\n\r\n <kendo-fileselect\r\n *ngIf=\"data.SelectFileOnly\"\r\n #uploadComponent\r\n [id]=\"data.Value\"\r\n (select)=\"selectEventHandler($event)\"\r\n (remove)=\"onRemove($event)\"\r\n [formControlName]=\"data.Value\"\r\n (valueChange)=\"onChange($event)\" \r\n [restrictions]=\"restrictions\"\r\n [style]=\"componentProperties.style.style1\"\r\n class=\"e1tag-style1\">\r\n </kendo-fileselect>\r\n\r\n <div\r\n *ngIf=\"imagePreviews.length\"\r\n class=\"image-preview-container e1tag-style2\"\r\n [style]=\"componentProperties.style.style2\">\r\n <div\r\n class=\"label-container e1tag-style3\"\r\n [style]=\"componentProperties.style.style3\">\r\n Image Preview:\r\n </div>\r\n <div\r\n class=\"image-container e1tag-style4\"\r\n [style]=\"componentProperties.style.style4\">\r\n <img\r\n *ngFor=\"let image of imagePreviews\"\r\n [src]=\"image.src\"\r\n alt=\"image preview\"\r\n height=\"100\"\r\n class=\"e1tag-style5\"\r\n [style]=\"componentProperties.style.style5\" />\r\n </div>\r\n </div>\r\n</div>\r\n", styles: [".image-preview-container{border:1px solid rgba(0,0,0,.08)}.image-preview-container>.label-container{margin:5px}\n"] }]
9423
9628
  }], ctorParameters: function () { return [{ type: ZComponentService }, { type: i2.AuthService }, { type: i2.CompressImageService }, { type: i2.ZCoreService }, { type: i0.NgZone }, { type: i2.SharePointService }, { type: i2.AlertService }]; }, propDecorators: { uploadComponent: [{
9424
9629
  type: ViewChild,
9425
- args: ["uploadComponent"]
9630
+ args: ["uploadComponent", { static: false }]
9426
9631
  }] } });
9427
9632
 
9428
9633
  /********** Angular **********/
@@ -9494,73 +9699,174 @@ class ZtexteditorComponent extends InputFieldBase {
9494
9699
  };
9495
9700
  this.isCompressModeOn = false;
9496
9701
  this.CloseEnlargeBtn = false;
9497
- this.style = "";
9498
- this.CompressionEnableIcon = 'k-i-zoom-best-fit';
9499
- this.CompressionDisabledIcon = 'k-i-zoom-actual-size';
9702
+ this.originalInlineStyle = '';
9703
+ this.compressionEnableIcon = 'k-i-zoom-best-fit';
9704
+ this.compressionDisabledIcon = 'k-i-zoom-actual-size';
9500
9705
  }
9706
+ /** Initialize component state and editor configuration. */
9501
9707
  ngOnInit() {
9502
9708
  super.setupInnerField();
9503
- this.data.ToolBarUploadImageMethod = this.data.ToolBarUploadImageMethod || 'explorer'; // || 'default';
9709
+ // Backward-compatible default: when not provided, use explorer.
9710
+ this.data.ToolBarUploadImageMethod = this.data.ToolBarUploadImageMethod || 'explorer';
9504
9711
  this.setupPasteCleanupSettings();
9505
9712
  super.setupComponentSettings(this.componentSettings);
9506
9713
  super.focusOnDefault(this.focus.bind(this));
9507
- this.isCompressModeOn = !!this.data.Compression;
9714
+ // Safe cast to boolean.
9715
+ this.isCompressModeOn = !!this.data?.Compression;
9508
9716
  }
9717
+ /** Notify component service once view is ready. */
9509
9718
  ngAfterViewInit() {
9510
9719
  this.componentService.decrementComponentCounterForField(this.data);
9511
9720
  }
9721
+ /** Sync editor content to zModel and trigger configured change handler. */
9512
9722
  onChange(value) {
9513
9723
  ZComponentHelper.setToZModel(this.data.Value, value, this.group, this.data);
9514
- this.triggerEvent("inputfield-onChange", this.data.OnChange, value);
9515
- }
9516
- async onPaste($event) {
9517
- const imageCompressionEnabled = !!this.data.Compression;
9518
- if (imageCompressionEnabled && this.isCompressModeOn) {
9519
- let beforeSize = 0;
9520
- let afterSize = 0;
9521
- const parser = new DOMParser();
9522
- const doc = parser.parseFromString($event.cleanedHtml, 'text/html');
9523
- const imgElements = Array.from(doc.querySelectorAll('img')).filter(dom => dom.src.startsWith('data:image/'));
9524
- await Promise.all(imgElements.map(async (imgTags, index) => {
9525
- const file = await this.base64ToFile(imgTags.src, "image" + index.toString());
9526
- beforeSize += file.size;
9527
- const compress = await this.ImageCompression(file);
9528
- if (compress != null) {
9529
- const base64 = await this.readFileAsDataURL(compress);
9530
- afterSize += compress.size;
9531
- imgTags.src = base64;
9532
- }
9533
- else {
9534
- console.log('Image compress failed');
9535
- }
9536
- }));
9537
- console.log(`Before Image compress size: ${(beforeSize / 1024).toFixed(2)}KB`);
9538
- console.log(`After Image compress size: ${(afterSize / 1024).toFixed(2)}KB`);
9539
- this.editor.value = doc.body.innerHTML;
9724
+ this.triggerEvent('inputfield-onChange', this.data.OnChange, value);
9725
+ }
9726
+ /** Handle paste: normalize plain-text special entities, then optionally compress pasted base64 images. */
9727
+ async onPaste(e) {
9728
+ if (!e) {
9729
+ console.warn('[Ztexteditor] Paste event is undefined. Paste ignored.');
9730
+ return;
9540
9731
  }
9732
+ // Common Excel/plain-text issue: "&amp;" gets inserted literally causing "&amp;amp;" in HTML.
9733
+ this.handleCommonSymbolTags(e);
9734
+ // Compress only if enabled and base64 images exist.
9735
+ await this.handleImageCompression(e);
9541
9736
  }
9542
- OnOffCompressMode($event) {
9543
- debugger;
9544
- const alertHeader = `Confirmation`;
9545
- const alertMessage = `Do you want to <b>${this.isCompressModeOn ? 'disable' : 'enable'}</b> image compression when input content? <br/> Note: Click "Yes" the content will be reset to blank.`;
9546
- const buttonConfig = {
9737
+ /**
9738
+ * If the paste is plain text (no HTML tags and no images), normalize common entities and insert as real text.
9739
+ * Returns true when the event is handled and default paste is prevented.
9740
+ */
9741
+ handleCommonSymbolTags(e) {
9742
+ const editor = this.editor;
9743
+ if (!editor) {
9744
+ console.warn('[Ztexteditor] Editor is not ready. Cannot handle plain-text normalization.');
9745
+ return false;
9746
+ }
9747
+ const clipboard = e.originalEvent?.clipboardData;
9748
+ const plainText = clipboard?.getData('text/plain') ?? '';
9749
+ const htmlText = clipboard?.getData('text/html') ?? '';
9750
+ const cleanedHtml = e.cleanedHtml ?? '';
9751
+ const htmlHasImg = /<img\b/i.test(htmlText);
9752
+ const cleanedHasTags = /<[^>]+>/.test(cleanedHtml);
9753
+ // If paste has HTML tags or images, do NOT interfere (let Kendo handle it).
9754
+ if (htmlHasImg || cleanedHasTags) {
9755
+ return false;
9756
+ }
9757
+ // Plain-text paste: prevent Kendo from inserting encoded entities as literal text.
9758
+ e.preventDefault();
9759
+ // Decode common entities once so user sees correct characters.
9760
+ // This is intentionally limited to common entities to avoid unexpected transformations.
9761
+ const normalized = (plainText || cleanedHtml)
9762
+ .replaceAll('&amp;', '&')
9763
+ .replaceAll('&lt;', '<')
9764
+ .replaceAll('&gt;', '>')
9765
+ .replaceAll('&quot;', '"')
9766
+ .replaceAll('&#39;', "'");
9767
+ editor.exec('insertText', { text: normalized });
9768
+ return true;
9769
+ }
9770
+ /**
9771
+ * If compression is enabled and compress mode is ON, compress any pasted base64 images (data:image/*).
9772
+ * IMPORTANT: modifies e.cleanedHtml (what gets pasted), not editor.value.
9773
+ */
9774
+ async handleImageCompression(e) {
9775
+ const compressionConfig = this.data?.Compression;
9776
+ const isCompressionEnabled = !!compressionConfig;
9777
+ if (!isCompressionEnabled || !this.isCompressModeOn) {
9778
+ return;
9779
+ }
9780
+ const cleaned = e.cleanedHtml ?? '';
9781
+ if (!cleaned) {
9782
+ return;
9783
+ }
9784
+ let doc;
9785
+ try {
9786
+ doc = new DOMParser().parseFromString(cleaned, 'text/html');
9787
+ }
9788
+ catch (err) {
9789
+ console.warn('[Ztexteditor] Failed to parse pasted HTML for image compression. Paste will continue.', err);
9790
+ return;
9791
+ }
9792
+ const imgElements = Array.from(doc.querySelectorAll('img'))
9793
+ .map(img => img)
9794
+ .filter(img => typeof img?.src === 'string' && img.src.startsWith('data:image/'));
9795
+ if (imgElements.length === 0) {
9796
+ return;
9797
+ }
9798
+ let beforeSizeBytes = 0;
9799
+ let afterSizeBytes = 0;
9800
+ let failedCount = 0;
9801
+ await Promise.all(imgElements.map(async (img, index) => {
9802
+ const src = img.src;
9803
+ try {
9804
+ const file = await this.base64ToFile(src, `pasted-image-${index}`);
9805
+ beforeSizeBytes += file.size;
9806
+ const compressed = await this.imageCompression(file);
9807
+ if (!compressed) {
9808
+ failedCount++;
9809
+ console.warn(`[Ztexteditor] Image compression skipped/failed for pasted image #${index + 1}.`);
9810
+ return;
9811
+ }
9812
+ const base64 = await this.readFileAsDataURL(compressed);
9813
+ afterSizeBytes += compressed.size;
9814
+ img.src = base64;
9815
+ }
9816
+ catch (err) {
9817
+ failedCount++;
9818
+ console.warn(`[Ztexteditor] Error compressing pasted image #${index + 1}.`, err);
9819
+ }
9820
+ }));
9821
+ // Helpful console logs for troubleshooting.
9822
+ const beforeKb = (beforeSizeBytes / 1024).toFixed(2);
9823
+ const afterKb = (afterSizeBytes / 1024).toFixed(2);
9824
+ console.log(`[Ztexteditor] Pasted image compression completed. Images=${imgElements.length}, Failed=${failedCount}, Before=${beforeKb}KB, After=${afterKb}KB`);
9825
+ // Modify what gets pasted, not editor.value.
9826
+ e.cleanedHtml = doc.body.innerHTML;
9827
+ }
9828
+ /**
9829
+ * Toggle compress mode via confirmation dialog.
9830
+ */
9831
+ onOffCompressMode(event) {
9832
+ const header = 'Confirmation';
9833
+ const actionText = this.isCompressModeOn ? 'disable' : 'enable';
9834
+ // Keep existing behavior: toggling resets content.
9835
+ const message = `Do you want to <b>${actionText}</b> image compression when input content?` +
9836
+ `<br/>Note: Click "Yes" the content will be reset to blank.`;
9837
+ const buttons = {
9547
9838
  yes: { text: 'Yes', cssClass: 'primary' },
9548
- no: { text: 'No', cssClass: 'secondary' }
9839
+ no: { text: 'No', cssClass: 'secondary' },
9549
9840
  };
9550
- this.alertService.show(alertHeader, alertMessage, [buttonConfig.yes, buttonConfig.no], ['col-4'])
9841
+ this.alertService
9842
+ .show(header, message, [buttons.yes, buttons.no], ['col-4'])
9551
9843
  .subscribe(reply => {
9552
- if (reply === 'Yes') {
9553
- this.editor.value = "";
9554
- this.isCompressModeOn = !this.isCompressModeOn;
9555
- let button = $event.target;
9556
- button.classList.remove(this.CompressionEnableIcon);
9557
- button.classList.remove(this.CompressionDisabledIcon);
9558
- button.classList.add(this.isCompressModeOn ? this.CompressionDisabledIcon : this.CompressionEnableIcon);
9844
+ if (reply !== 'Yes') {
9845
+ return;
9846
+ }
9847
+ const editor = this.editor;
9848
+ if (!editor) {
9849
+ console.warn('[Ztexteditor] Editor is not ready. Cannot toggle compression mode.');
9850
+ return;
9851
+ }
9852
+ editor.value = '';
9853
+ this.isCompressModeOn = !this.isCompressModeOn;
9854
+ // Update toolbar icon classes safely.
9855
+ const buttonEl = this.getEventTargetElement(event);
9856
+ if (!buttonEl) {
9857
+ console.warn('[Ztexteditor] Unable to resolve toolbar button element from event.');
9858
+ }
9859
+ else {
9860
+ buttonEl.classList.remove(this.compressionEnableIcon, this.compressionDisabledIcon);
9861
+ buttonEl.classList.add(this.isCompressModeOn ? this.compressionDisabledIcon : this.compressionEnableIcon);
9862
+ }
9863
+ if (this.compress_btn) {
9559
9864
  this.compress_btn.title = `${this.isCompressModeOn ? 'Disable' : 'Enable'} image compression`;
9560
- this.toastService.show(`${this.isCompressModeOn ? 'Enable' : 'Disable'} image compression successfully.`, 'top', false, 2500, "success");
9561
9865
  }
9866
+ this.toastService.show(`${this.isCompressModeOn ? 'Enable' : 'Disable'} image compression successfully.`, 'top', false, 2500, 'success');
9562
9867
  });
9563
9868
  }
9869
+ /** Focus editor if available. Returns true if focus succeeded. */
9564
9870
  focus() {
9565
9871
  if (this.editor) {
9566
9872
  this.editor.focus();
@@ -9575,96 +9881,182 @@ class ZtexteditorComponent extends InputFieldBase {
9575
9881
  }
9576
9882
  return iconName;
9577
9883
  }
9884
+ /** Merge paste cleanup options from data.Options (string expression or object) into pasteCleanupSettings. */
9578
9885
  setupPasteCleanupSettings() {
9579
- if (this.data.Options) {
9580
- if (typeof this.data.Options == 'string') {
9581
- const option = ZComponentHelper.getGroupValue(this.data.Options, this.group);
9582
- Object.assign(this.pasteCleanupSettings, option);
9886
+ const options = this.data?.Options;
9887
+ if (!options) {
9888
+ return;
9889
+ }
9890
+ if (typeof options === 'string') {
9891
+ const resolved = ZComponentHelper.getGroupValue(options, this.group);
9892
+ if (resolved && typeof resolved === 'object') {
9893
+ Object.assign(this.pasteCleanupSettings, resolved);
9583
9894
  }
9584
- else if (typeof this.data.Options == 'object') {
9585
- Object.assign(this.pasteCleanupSettings, this.data.Options);
9895
+ else {
9896
+ console.warn('[Ztexteditor] data.Options resolved value is not an object. Paste cleanup settings unchanged.', {
9897
+ resolved,
9898
+ });
9586
9899
  }
9900
+ return;
9901
+ }
9902
+ if (typeof options === 'object') {
9903
+ Object.assign(this.pasteCleanupSettings, options);
9904
+ return;
9587
9905
  }
9906
+ console.warn('[Ztexteditor] Unsupported data.Options type. Paste cleanup settings unchanged.', {
9907
+ type: typeof options,
9908
+ });
9588
9909
  }
9589
- // #region Custom Image Upload
9910
+ // #region Custom Image Upload / Enlarge
9911
+ /** Trigger hidden file input click for image upload. */
9590
9912
  openFileExplorer() {
9591
- const input = document.getElementById(`${this.data.Value}-upload-file`);
9592
- if (input) {
9593
- input.click();
9913
+ const id = `${this.data.Value}-upload-file`;
9914
+ const input = document.getElementById(id);
9915
+ if (!input) {
9916
+ console.warn(`[Ztexteditor] Upload input element not found (id="${id}").`);
9917
+ return;
9594
9918
  }
9919
+ input.click();
9595
9920
  }
9921
+ /** Open an enlarged popup editor. */
9596
9922
  openPopup() {
9597
- if (this.editor) {
9598
- // Open the popup
9599
- this.dialogRef = this.dialogService.open({
9600
- content: ZtexteditorComponent,
9601
- width: '98%',
9602
- height: '97%'
9603
- });
9604
- const texteditor = this.dialogRef.content.instance;
9605
- texteditor.data = this.data;
9606
- texteditor.data.AllowEnlarge = false;
9607
- texteditor.dialogRef = this.dialogRef;
9608
- texteditor.CloseEnlargeBtn = true;
9609
- texteditor.componentProperties = this.componentProperties;
9610
- this.style = this.componentProperties.style.style1;
9611
- texteditor.componentProperties.style.style1 += "height:" + (window.innerHeight * 0.8).toString() + "px";
9612
- texteditor.group = this.group;
9613
- texteditor.componentSettings = this.componentSettings;
9614
- texteditor.form = this.form;
9615
- //To set the html back into the target ztext editor.
9616
- this.dialogRef.result.subscribe(() => {
9617
- this.data.AllowEnlarge = true;
9618
- this.componentProperties.style.style1 = this.style;
9619
- this.editor.value = this.group.zModel[this.data.Value];
9620
- this.onChange(this.group.zModel[this.data.Value]);
9621
- this.focus();
9622
- });
9923
+ const editor = this.editor;
9924
+ if (!editor) {
9925
+ console.warn('[Ztexteditor] Editor is not ready. Cannot open popup.');
9926
+ return;
9623
9927
  }
9928
+ // Open dialog
9929
+ this.dialogRef = this.dialogService.open({
9930
+ content: ZtexteditorComponent,
9931
+ width: '98%',
9932
+ height: '97%',
9933
+ });
9934
+ const popupComponent = this.dialogRef.content.instance;
9935
+ popupComponent.data = this.data;
9936
+ popupComponent.data.AllowEnlarge = false;
9937
+ popupComponent.dialogRef = this.dialogRef;
9938
+ popupComponent.CloseEnlargeBtn = true;
9939
+ popupComponent.componentProperties = this.componentProperties;
9940
+ // Preserve style so we can restore it on close.
9941
+ this.originalInlineStyle = this.componentProperties?.style?.style1 ?? '';
9942
+ if (popupComponent.componentProperties?.style) {
9943
+ popupComponent.componentProperties.style.style1 =
9944
+ (popupComponent.componentProperties.style.style1 ?? '') +
9945
+ `height:${(window.innerHeight * 0.8).toString()}px`;
9946
+ }
9947
+ popupComponent.group = this.group;
9948
+ popupComponent.componentSettings = this.componentSettings;
9949
+ popupComponent.form = this.form;
9950
+ // Restore state and push value back into editor on close.
9951
+ this.dialogRef.result.subscribe(() => {
9952
+ this.data.AllowEnlarge = true;
9953
+ if (this.componentProperties?.style) {
9954
+ this.componentProperties.style.style1 = this.originalInlineStyle;
9955
+ }
9956
+ // Pull current zModel into editor and trigger onChange (existing behavior).
9957
+ const newValue = this.group?.zModel?.[this.data.Value];
9958
+ editor.value = newValue;
9959
+ this.onChange(newValue);
9960
+ this.focus();
9961
+ });
9624
9962
  }
9963
+ /** Close the popup editor if open. */
9625
9964
  onPopupClose() {
9965
+ if (!this.dialogRef) {
9966
+ return;
9967
+ }
9626
9968
  this.dialogRef.close();
9627
9969
  }
9970
+ /**
9971
+ * Handle <input type="file"> change and insert selected image into editor.
9972
+ * NOTE: Prefer typing fileInput as Event for better safety.
9973
+ */
9628
9974
  uploadImage(fileInput) {
9629
- const uploadedImage = fileInput.target.files[0];
9630
- if (uploadedImage) {
9631
- this.insertImageIntoEditor(uploadedImage);
9975
+ const input = fileInput?.target;
9976
+ const file = input?.files?.[0];
9977
+ if (!file) {
9978
+ console.warn('[Ztexteditor] No image selected for upload.');
9979
+ return;
9632
9980
  }
9981
+ void this.insertImageIntoEditor(file);
9633
9982
  }
9983
+ /** Insert image into editor, optionally compressing first. */
9634
9984
  async insertImageIntoEditor(file) {
9635
- const imageCompressionEnabled = !!this.data.Compression;
9636
- if (imageCompressionEnabled) {
9637
- console.log(`Before Image compress size: ${(file.size / 1024).toFixed(2)}KB`);
9638
- file = await this.ImageCompression(file);
9639
- console.log(`After Image compress size: ${(file.size / 1024).toFixed(2)}KB`);
9985
+ const editor = this.editor;
9986
+ if (!editor) {
9987
+ console.warn('[Ztexteditor] Editor is not ready. Cannot insert image.');
9988
+ return;
9989
+ }
9990
+ let workingFile = file;
9991
+ const compressionConfig = this.data?.Compression;
9992
+ const compressionEnabled = !!compressionConfig;
9993
+ if (compressionEnabled) {
9994
+ console.log(`[Ztexteditor] Upload image before compression: ${(workingFile.size / 1024).toFixed(2)}KB`);
9995
+ workingFile = await this.imageCompression(workingFile);
9996
+ if (!workingFile) {
9997
+ console.warn('[Ztexteditor] Image compression failed. Upload image insertion aborted.');
9998
+ return;
9999
+ }
10000
+ console.log(`[Ztexteditor] Upload image after compression: ${(workingFile.size / 1024).toFixed(2)}KB`);
10001
+ }
10002
+ try {
10003
+ const base64 = await this.readFileAsDataURL(workingFile);
10004
+ editor.exec('insertImage', { src: base64 });
10005
+ }
10006
+ catch (err) {
10007
+ console.warn('[Ztexteditor] Failed to read uploaded image as base64.', err);
9640
10008
  }
9641
- var base64str = await this.readFileAsDataURL(file);
9642
- this.editor.exec("insertImage", { src: base64str });
9643
10009
  }
10010
+ /** Convert base64 (data URL) to File. */
9644
10011
  async base64ToFile(base64String, fileName) {
10012
+ // Using fetch on data URL is supported by modern browsers; keep existing logic.
9645
10013
  const response = await fetch(base64String);
9646
10014
  const blob = await response.blob();
9647
- const file = new File([blob], fileName, {
10015
+ return new File([blob], fileName, {
9648
10016
  type: blob.type,
9649
10017
  lastModified: Date.now(),
9650
10018
  });
9651
- return file;
9652
- }
9653
- async ImageCompression(file) {
9654
- //Check if Image Compression is enabled.
9655
- if (file && file.type.includes("image")) {
9656
- const imgConfig = this.compressionConfigHandler(this.data.Compression);
9657
- if (file.size > imgConfig.FileSizeMinSizeByte) {
9658
- const compressed$ = this.compressImage.compress(file, imgConfig);
9659
- const compressFile = await firstValueFrom(compressed$);
9660
- return compressFile;
9661
- } // file size check
10019
+ }
10020
+ /**
10021
+ * Compress an image file if it is an image and above min threshold.
10022
+ * Returns the compressed file, or null if not compressible / compression skipped.
10023
+ */
10024
+ async imageCompression(file) {
10025
+ if (!file) {
10026
+ console.warn('[Ztexteditor] imageCompression called with empty file.');
10027
+ return null;
9662
10028
  }
9663
- else {
10029
+ if (!file.type || !file.type.includes('image')) {
10030
+ console.warn('[Ztexteditor] Skipping compression: file is not an image.', { type: file.type });
10031
+ return null;
10032
+ }
10033
+ const config = this.data?.Compression;
10034
+ if (!config) {
10035
+ // Compression not configured.
10036
+ return null;
10037
+ }
10038
+ const imgConfig = this.compressionConfigHandler(config);
10039
+ // If file is below threshold, keep existing behavior: skip compression (return null).
10040
+ if (file.size <= imgConfig.FileSizeMinSizeByte) {
10041
+ console.log(`[Ztexteditor] Skipping compression: file size ${(file.size / 1024).toFixed(2)}KB is below threshold ${(imgConfig.FileSizeMinSizeByte / 1024).toFixed(2)}KB.`);
10042
+ return null;
10043
+ }
10044
+ try {
10045
+ const compressed$ = this.compressImage.compress(file, imgConfig);
10046
+ const compressedFile = await firstValueFrom(compressed$);
10047
+ return compressedFile ?? null;
10048
+ }
10049
+ catch (err) {
10050
+ console.warn('[Ztexteditor] Compression service threw an error.', err);
9664
10051
  return null;
9665
10052
  }
9666
10053
  }
10054
+ /** Normalize image compression config into byte-based thresholds. */
9667
10055
  compressionConfigHandler(imgConfig) {
10056
+ if (!imgConfig) {
10057
+ // Defensive: should never happen because caller checks.
10058
+ return imgConfig;
10059
+ }
9668
10060
  if (imgConfig.FileSizeMaxSize) {
9669
10061
  imgConfig.FileSizeMaxSizeByte = this.convertSizeToByte(imgConfig.FileSizeMaxSize);
9670
10062
  }
@@ -9676,63 +10068,74 @@ class ZtexteditorComponent extends InputFieldBase {
9676
10068
  }
9677
10069
  return imgConfig;
9678
10070
  }
10071
+ /**
10072
+ * Convert size string like "100kb", "1 MB", "2gb" to bytes.
10073
+ * If no unit is provided, bytes are assumed.
10074
+ */
9679
10075
  convertSizeToByte(sizeString) {
9680
- let _tempFileSizeMaxSize = 0;
9681
- let sizeByByte = 0;
9682
- let sizeType = 'b';
9683
- // remove all space
9684
- const _tempFileSize = sizeString.replace(/ /g, '');
9685
- // check last char is alphabetic
9686
- const lastChar = _tempFileSize.substr(_tempFileSize.length - 1);
9687
- if (isNaN(parseFloat(lastChar))) {
9688
- const secLastChar = _tempFileSize.substr(_tempFileSize.length - 2).slice(0, -1);
9689
- if (isNaN(parseFloat(secLastChar))) {
9690
- // check last 2nd char is alphabetic
9691
- sizeType = secLastChar + sizeType;
9692
- _tempFileSizeMaxSize = parseFloat(_tempFileSize.slice(0, -2));
9693
- }
9694
- else {
9695
- _tempFileSizeMaxSize = parseFloat(_tempFileSize.slice(0, -1));
9696
- }
9697
- switch (sizeType.toLowerCase()) {
9698
- case "b":
9699
- sizeByByte = _tempFileSizeMaxSize;
9700
- break;
9701
- case "kb":
9702
- sizeByByte = _tempFileSizeMaxSize * 1024;
9703
- break;
9704
- case "mb":
9705
- sizeByByte = _tempFileSizeMaxSize * 1048576;
9706
- break;
9707
- case "gb":
9708
- sizeByByte = _tempFileSizeMaxSize * 1073741824;
9709
- break;
9710
- }
10076
+ if (!sizeString || typeof sizeString !== 'string') {
10077
+ console.warn('[Ztexteditor] convertSizeToByte received invalid sizeString. Defaulting to 0.', { sizeString });
10078
+ return 0;
9711
10079
  }
9712
- else {
9713
- // default using bytes if no size type
9714
- sizeByByte = parseFloat(_tempFileSize);
10080
+ // Remove all spaces, e.g. "1 MB" -> "1MB"
10081
+ const trimmed = sizeString.replace(/ /g, '').trim();
10082
+ if (!trimmed) {
10083
+ return 0;
10084
+ }
10085
+ // Extract numeric part and unit part (letters).
10086
+ // Example: "1.5MB" => number=1.5, unit="mb"
10087
+ const match = /^([0-9]*\.?[0-9]+)([a-zA-Z]*)$/.exec(trimmed);
10088
+ if (!match) {
10089
+ console.warn('[Ztexteditor] Unable to parse sizeString. Defaulting to 0.', { sizeString });
10090
+ return 0;
10091
+ }
10092
+ const numeric = Number(match[1]);
10093
+ const unit = (match[2] || 'b').toLowerCase();
10094
+ if (Number.isNaN(numeric) || numeric < 0) {
10095
+ console.warn('[Ztexteditor] Invalid numeric size in sizeString. Defaulting to 0.', { sizeString });
10096
+ return 0;
10097
+ }
10098
+ switch (unit) {
10099
+ case 'b':
10100
+ case '':
10101
+ return numeric;
10102
+ case 'kb':
10103
+ return numeric * 1024;
10104
+ case 'mb':
10105
+ return numeric * 1024 * 1024;
10106
+ case 'gb':
10107
+ return numeric * 1024 * 1024 * 1024;
10108
+ default:
10109
+ console.warn('[Ztexteditor] Unknown unit in sizeString. Defaulting to bytes.', { sizeString, unit });
10110
+ return numeric;
9715
10111
  }
9716
- return sizeByByte;
9717
10112
  }
10113
+ /** Read a File as base64 data URL. */
9718
10114
  readFileAsDataURL(file) {
9719
10115
  return new Promise((resolve, reject) => {
10116
+ if (!file) {
10117
+ reject(new Error('File is required.'));
10118
+ return;
10119
+ }
9720
10120
  const reader = new FileReader();
9721
10121
  reader.readAsDataURL(file);
9722
- reader.onload = () => {
9723
- resolve(reader.result);
9724
- };
9725
- reader.onerror = (error) => {
9726
- reject(error);
9727
- };
10122
+ reader.onload = () => resolve(reader.result);
10123
+ reader.onerror = (error) => reject(error);
9728
10124
  });
9729
10125
  }
10126
+ // #endregion
10127
+ // #region Small helpers
10128
+ /** Extract event target as HTMLElement safely. */
10129
+ getEventTargetElement(event) {
10130
+ const target = event?.target;
10131
+ return target instanceof HTMLElement ? target : null;
10132
+ }
9730
10133
  }
9731
10134
  ZtexteditorComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: ZtexteditorComponent, deps: [{ token: ZComponentService }, { token: i2.FontAweSomeService }, { token: i6.DialogService }, { token: i2.AlertService }, { token: i2.CompressImageService }, { token: i2.ToastService }], target: i0.ɵɵFactoryTarget.Component });
9732
- ZtexteditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.3", type: ZtexteditorComponent, selector: "app-ztexteditor", viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true }, { propertyName: "compress_btn", first: true, predicate: ["compressButton"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\r\n\r\n<div [formGroup]=\"form\" class=\"ztexteditor-container e1tag-style\" [style]=\"componentProperties.style.style\" [ngClass]=\"data.Class\">\r\n <div class=\"col-lg-12 expand-btn-container\">\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"data.AllowEnlarge\" (click)=\"openPopup()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faExpandAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"CloseEnlargeBtn\" (click)=\"onPopupClose()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faCompressAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n</div>\r\n <kendo-editor #editor\r\n [id]=\"data.Value\"\r\n [formControlName]=\"data.Value\"\r\n class=\"e1tag-style1\"\r\n [style]=\"componentProperties.style.style1\"\r\n [readonly]=\"(!!componentProperties.isReadOnlyField ? group[componentProperties.isReadOnlyField] : componentProperties.isReadOnly)\"\r\n (valueChange)=\"onChange($event)\"\r\n [resizable]=\"data.Resizable || false\"\r\n [pasteCleanupSettings]=\"pasteCleanupSettings\"\r\n (paste)=\"onPaste($event)\"\r\n [iframe]=\"componentSettings.iframe\">\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'basic' ? 'inherit' : 'none'\" class=\"e1tag-style2\"\r\n [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFormat></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-zoom-actual-size\" (click)=\"OnOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'full' ? 'inherit' : 'none'\" class=\"e1tag-style2\" [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-file-image\" (click)=\"OnOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorMergeCellsButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSplitCellButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n </kendo-toolbar>\r\n </kendo-editor>\r\n <input style=\"display:none;\" type=\"file\" [id]=\"data.Value +'-upload-file'\" [name]=\"data.Value +'-upload-file'\" accept=\"image/*\" ngf-max-size=\"5MB\" (change)=\"uploadImage($event)\">\r\n</div>\r\n", styles: [".title{margin:20px 10px 5px;font-size:18px;font-weight:700}.expand-btn-container{text-align:right}.expand-btn-container ion-button{--background: rgba(var(--ion-color-primary-rgb),10%);--color:black;font-size:12px}\n"], components: [{ type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { type: i4.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "spin", "pulse", "mask", "styles", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "classes", "transform", "a11yRole"] }, { type: i6$2.EditorComponent, selector: "kendo-editor", inputs: ["value", "disabled", "readonly", "iframe", "applyToWord", "schema", "plugins", "placeholder", "preserveWhitespace", "pasteCleanupSettings", "resizable"], outputs: ["valueChange", "focus", "paste", "blur"] }, { type: i7$3.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "tabindex", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { type: i7$3.ToolBarButtonGroupComponent, selector: "kendo-toolbar-buttongroup", inputs: ["disabled", "selection", "width", "look"], exportAs: ["kendoToolBarButtonGroup"] }, { type: i7$3.ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "themeColor", "icon", "iconClass", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { type: i6$2.EditorFormatComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFormat]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorFontSizeComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFontSize]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorFontFamilyComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFontFamily]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorColorPickerComponent, selector: "kendo-toolbar-colorpicker", inputs: ["value", "icon", "paletteSettings", "editorCommand", "disabled", "views", "view"] }, { type: i6$2.EditorInsertTableButtonComponent, selector: "kendo-editor-insert-table-button" }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i7.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i6$2.EditorUndoButtonDirective, selector: "kendo-toolbar-button[kendoEditorUndoButton]" }, { type: i6$2.EditorRedoButtonDirective, selector: "kendo-toolbar-button[kendoEditorRedoButton]" }, { type: i6$2.EditorBoldButtonDirective, selector: "kendo-toolbar-button[kendoEditorBoldButton]" }, { type: i6$2.EditorItalicButtonDirective, selector: "kendo-toolbar-button[kendoEditorItalicButton]" }, { type: i6$2.EditorUnderlineButtonDirective, selector: "kendo-toolbar-button[kendoEditorUnderlineButton]" }, { type: i6$2.EditorStrikethroughButtonDirective, selector: "kendo-toolbar-button[kendoEditorStrikethroughButton]" }, { type: i6$2.EditorSubscriptButtonDirective, selector: "kendo-toolbar-button[kendoEditorSubscriptButton]" }, { type: i6$2.EditorSuperscriptButtonDirective, selector: "kendo-toolbar-button[kendoEditorSuperscriptButton]" }, { type: i6$2.EditorAlignLeftButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignLeftButton]" }, { type: i6$2.EditorAlignCenterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignCenterButton]" }, { type: i6$2.EditorAlignRightButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignRightButton]" }, { type: i6$2.EditorAlignJustifyButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignJustifyButton]" }, { type: i6$2.EditorForeColorDirective, selector: "[kendoEditorForeColor]" }, { type: i6$2.EditorBackColorDirective, selector: "[kendoEditorBackColor]" }, { type: i6$2.EditorInsertUnorderedListButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertUnorderedListButton]" }, { type: i6$2.EditorInsertOrderedListButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertOrderedListButton]" }, { type: i6$2.EditorIndentButtonDirective, selector: "kendo-toolbar-button[kendoEditorIndentButton]" }, { type: i6$2.EditorOutdentButtonDirective, selector: "kendo-toolbar-button[kendoEditorOutdentButton]" }, { type: i6$2.EditorCreateLinkButtonDirective, selector: "kendo-toolbar-button[kendoEditorCreateLinkButton]" }, { type: i6$2.EditorUnlinkButtonDirective, selector: "kendo-toolbar-button[kendoEditorUnlinkButton]" }, { type: i6$2.EditorAddColumnBeforeButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddColumnBeforeButton]" }, { type: i6$2.EditorAddColumnAfterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddColumnAfterButton]" }, { type: i6$2.EditorAddRowBeforeButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddRowBeforeButton]" }, { type: i6$2.EditorAddRowAfterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddRowAfterButton]" }, { type: i6$2.EditorDeleteColumnButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteColumnButton]" }, { type: i6$2.EditorDeleteRowButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteRowButton]" }, { type: i6$2.EditorDeleteTableButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteTableButton]" }, { type: i6$2.EditorInsertFileButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertFileButton]" }, { type: i6$2.EditorInsertImageButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertImageButton]" }, { type: i6$2.EditorViewSourceButtonDirective, selector: "kendo-toolbar-button[kendoEditorViewSourceButton]" }, { type: i6$2.EditorMergeCellsButtonDirective, selector: "kendo-toolbar-button[kendoEditorMergeCellsButton]" }, { type: i6$2.EditorSplitCellButtonDirective, selector: "kendo-toolbar-button[kendoEditorSplitCellButton]" }] });
10135
+ ZtexteditorComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.3.3", type: ZtexteditorComponent, selector: "app-ztexteditor", viewQueries: [{ propertyName: "editor", first: true, predicate: ["editor"], descendants: true }, { propertyName: "compress_btn", first: true, predicate: ["compressButton"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\r\n\r\n<div [formGroup]=\"form\" class=\"ztexteditor-container e1tag-style\" [style]=\"componentProperties.style.style\" [ngClass]=\"data.Class\">\r\n <div class=\"col-lg-12 expand-btn-container\">\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"data.AllowEnlarge\" (click)=\"openPopup()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faExpandAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"CloseEnlargeBtn\" (click)=\"onPopupClose()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faCompressAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n</div>\r\n <kendo-editor #editor\r\n [id]=\"data.Value\"\r\n [formControlName]=\"data.Value\"\r\n class=\"e1tag-style1\"\r\n [style]=\"componentProperties.style.style1\"\r\n [readonly]=\"(!!componentProperties.isReadOnlyField ? group[componentProperties.isReadOnlyField] : componentProperties.isReadOnly)\"\r\n (valueChange)=\"onChange($event)\"\r\n [resizable]=\"data.Resizable || false\"\r\n [pasteCleanupSettings]=\"pasteCleanupSettings\"\r\n (paste)=\"onPaste($event)\"\r\n [iframe]=\"componentSettings.iframe\">\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'basic' ? 'inherit' : 'none'\" class=\"e1tag-style2\"\r\n [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFormat></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-zoom-actual-size\" (click)=\"onOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'full' ? 'inherit' : 'none'\" class=\"e1tag-style2\" [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-file-image\" (click)=\"onOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorMergeCellsButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSplitCellButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n </kendo-toolbar>\r\n </kendo-editor>\r\n <input style=\"display:none;\" type=\"file\" [id]=\"data.Value +'-upload-file'\" [name]=\"data.Value +'-upload-file'\" accept=\"image/*\" ngf-max-size=\"5MB\" (change)=\"uploadImage($event)\">\r\n</div>\r\n", styles: [".title{margin:20px 10px 5px;font-size:18px;font-weight:700}.expand-btn-container{text-align:right}.expand-btn-container ion-button{--background: rgba(var(--ion-color-primary-rgb),10%);--color:black;font-size:12px}\n"], components: [{ type: i2$1.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { type: i4.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "spin", "pulse", "mask", "styles", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "classes", "transform", "a11yRole"] }, { type: i6$2.EditorComponent, selector: "kendo-editor", inputs: ["value", "disabled", "readonly", "iframe", "applyToWord", "schema", "plugins", "placeholder", "preserveWhitespace", "pasteCleanupSettings", "resizable"], outputs: ["valueChange", "focus", "paste", "blur"] }, { type: i7$3.ToolBarComponent, selector: "kendo-toolbar", inputs: ["overflow", "resizable", "popupSettings", "tabindex", "tabIndex"], outputs: ["open", "close"], exportAs: ["kendoToolBar"] }, { type: i7$3.ToolBarButtonGroupComponent, selector: "kendo-toolbar-buttongroup", inputs: ["disabled", "selection", "width", "look"], exportAs: ["kendoToolBarButtonGroup"] }, { type: i7$3.ToolBarButtonComponent, selector: "kendo-toolbar-button", inputs: ["showText", "showIcon", "text", "style", "className", "title", "disabled", "toggleable", "look", "togglable", "selected", "fillMode", "themeColor", "icon", "iconClass", "imageUrl"], outputs: ["click", "pointerdown", "selectedChange"], exportAs: ["kendoToolBarButton"] }, { type: i6$2.EditorFormatComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFormat]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorFontSizeComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFontSize]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorFontFamilyComponent, selector: "kendo-toolbar-dropdownlist[kendoEditorFontFamily]", inputs: ["data"], outputs: ["valueChange"] }, { type: i6$2.EditorColorPickerComponent, selector: "kendo-toolbar-colorpicker", inputs: ["value", "icon", "paletteSettings", "editorCommand", "disabled", "views", "view"] }, { type: i6$2.EditorInsertTableButtonComponent, selector: "kendo-editor-insert-table-button" }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i7.DefaultClassDirective, selector: " [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]", inputs: ["ngClass", "ngClass.xs", "ngClass.sm", "ngClass.md", "ngClass.lg", "ngClass.xl", "ngClass.lt-sm", "ngClass.lt-md", "ngClass.lt-lg", "ngClass.lt-xl", "ngClass.gt-xs", "ngClass.gt-sm", "ngClass.gt-md", "ngClass.gt-lg"] }, { type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i6$2.EditorUndoButtonDirective, selector: "kendo-toolbar-button[kendoEditorUndoButton]" }, { type: i6$2.EditorRedoButtonDirective, selector: "kendo-toolbar-button[kendoEditorRedoButton]" }, { type: i6$2.EditorBoldButtonDirective, selector: "kendo-toolbar-button[kendoEditorBoldButton]" }, { type: i6$2.EditorItalicButtonDirective, selector: "kendo-toolbar-button[kendoEditorItalicButton]" }, { type: i6$2.EditorUnderlineButtonDirective, selector: "kendo-toolbar-button[kendoEditorUnderlineButton]" }, { type: i6$2.EditorStrikethroughButtonDirective, selector: "kendo-toolbar-button[kendoEditorStrikethroughButton]" }, { type: i6$2.EditorSubscriptButtonDirective, selector: "kendo-toolbar-button[kendoEditorSubscriptButton]" }, { type: i6$2.EditorSuperscriptButtonDirective, selector: "kendo-toolbar-button[kendoEditorSuperscriptButton]" }, { type: i6$2.EditorAlignLeftButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignLeftButton]" }, { type: i6$2.EditorAlignCenterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignCenterButton]" }, { type: i6$2.EditorAlignRightButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignRightButton]" }, { type: i6$2.EditorAlignJustifyButtonDirective, selector: "kendo-toolbar-button[kendoEditorAlignJustifyButton]" }, { type: i6$2.EditorForeColorDirective, selector: "[kendoEditorForeColor]" }, { type: i6$2.EditorBackColorDirective, selector: "[kendoEditorBackColor]" }, { type: i6$2.EditorInsertUnorderedListButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertUnorderedListButton]" }, { type: i6$2.EditorInsertOrderedListButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertOrderedListButton]" }, { type: i6$2.EditorIndentButtonDirective, selector: "kendo-toolbar-button[kendoEditorIndentButton]" }, { type: i6$2.EditorOutdentButtonDirective, selector: "kendo-toolbar-button[kendoEditorOutdentButton]" }, { type: i6$2.EditorCreateLinkButtonDirective, selector: "kendo-toolbar-button[kendoEditorCreateLinkButton]" }, { type: i6$2.EditorUnlinkButtonDirective, selector: "kendo-toolbar-button[kendoEditorUnlinkButton]" }, { type: i6$2.EditorAddColumnBeforeButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddColumnBeforeButton]" }, { type: i6$2.EditorAddColumnAfterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddColumnAfterButton]" }, { type: i6$2.EditorAddRowBeforeButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddRowBeforeButton]" }, { type: i6$2.EditorAddRowAfterButtonDirective, selector: "kendo-toolbar-button[kendoEditorAddRowAfterButton]" }, { type: i6$2.EditorDeleteColumnButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteColumnButton]" }, { type: i6$2.EditorDeleteRowButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteRowButton]" }, { type: i6$2.EditorDeleteTableButtonDirective, selector: "kendo-toolbar-button[kendoEditorDeleteTableButton]" }, { type: i6$2.EditorInsertFileButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertFileButton]" }, { type: i6$2.EditorInsertImageButtonDirective, selector: "kendo-toolbar-button[kendoEditorInsertImageButton]" }, { type: i6$2.EditorViewSourceButtonDirective, selector: "kendo-toolbar-button[kendoEditorViewSourceButton]" }, { type: i6$2.EditorMergeCellsButtonDirective, selector: "kendo-toolbar-button[kendoEditorMergeCellsButton]" }, { type: i6$2.EditorSplitCellButtonDirective, selector: "kendo-toolbar-button[kendoEditorSplitCellButton]" }] });
9733
10136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.3", ngImport: i0, type: ZtexteditorComponent, decorators: [{
9734
10137
  type: Component,
9735
- args: [{ selector: 'app-ztexteditor', template: "\r\n\r\n<div [formGroup]=\"form\" class=\"ztexteditor-container e1tag-style\" [style]=\"componentProperties.style.style\" [ngClass]=\"data.Class\">\r\n <div class=\"col-lg-12 expand-btn-container\">\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"data.AllowEnlarge\" (click)=\"openPopup()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faExpandAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"CloseEnlargeBtn\" (click)=\"onPopupClose()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faCompressAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n</div>\r\n <kendo-editor #editor\r\n [id]=\"data.Value\"\r\n [formControlName]=\"data.Value\"\r\n class=\"e1tag-style1\"\r\n [style]=\"componentProperties.style.style1\"\r\n [readonly]=\"(!!componentProperties.isReadOnlyField ? group[componentProperties.isReadOnlyField] : componentProperties.isReadOnly)\"\r\n (valueChange)=\"onChange($event)\"\r\n [resizable]=\"data.Resizable || false\"\r\n [pasteCleanupSettings]=\"pasteCleanupSettings\"\r\n (paste)=\"onPaste($event)\"\r\n [iframe]=\"componentSettings.iframe\">\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'basic' ? 'inherit' : 'none'\" class=\"e1tag-style2\"\r\n [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFormat></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-zoom-actual-size\" (click)=\"OnOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'full' ? 'inherit' : 'none'\" class=\"e1tag-style2\" [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-file-image\" (click)=\"OnOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorMergeCellsButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSplitCellButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n </kendo-toolbar>\r\n </kendo-editor>\r\n <input style=\"display:none;\" type=\"file\" [id]=\"data.Value +'-upload-file'\" [name]=\"data.Value +'-upload-file'\" accept=\"image/*\" ngf-max-size=\"5MB\" (change)=\"uploadImage($event)\">\r\n</div>\r\n", styles: [".title{margin:20px 10px 5px;font-size:18px;font-weight:700}.expand-btn-container{text-align:right}.expand-btn-container ion-button{--background: rgba(var(--ion-color-primary-rgb),10%);--color:black;font-size:12px}\n"] }]
10138
+ args: [{ selector: 'app-ztexteditor', template: "\r\n\r\n<div [formGroup]=\"form\" class=\"ztexteditor-container e1tag-style\" [style]=\"componentProperties.style.style\" [ngClass]=\"data.Class\">\r\n <div class=\"col-lg-12 expand-btn-container\">\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"data.AllowEnlarge\" (click)=\"openPopup()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faExpandAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n <ion-button class=\"ion-activatable ripple-parent\" [style]=\"componentProperties.style.style4\" *ngIf=\"CloseEnlargeBtn\" (click)=\"onPopupClose()\" [id]=\"data.Value +'-popup-button'\">\r\n <fa-icon class=\"btn-icon\" [icon]=\"getFontAwesome('faCompressAlt', fontAweSomeService)\"></fa-icon>\r\n </ion-button>\r\n</div>\r\n <kendo-editor #editor\r\n [id]=\"data.Value\"\r\n [formControlName]=\"data.Value\"\r\n class=\"e1tag-style1\"\r\n [style]=\"componentProperties.style.style1\"\r\n [readonly]=\"(!!componentProperties.isReadOnlyField ? group[componentProperties.isReadOnlyField] : componentProperties.isReadOnly)\"\r\n (valueChange)=\"onChange($event)\"\r\n [resizable]=\"data.Resizable || false\"\r\n [pasteCleanupSettings]=\"pasteCleanupSettings\"\r\n (paste)=\"onPaste($event)\"\r\n [iframe]=\"componentSettings.iframe\">\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'basic' ? 'inherit' : 'none'\" class=\"e1tag-style2\"\r\n [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFormat></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertFileButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-zoom-actual-size\" (click)=\"onOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n </kendo-toolbar>\r\n <kendo-toolbar [style.display]=\"data.ToolBarStyle === 'full' ? 'inherit' : 'none'\" class=\"e1tag-style2\" [style]=\"componentProperties.style.style2\">\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorUndoButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorRedoButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorBoldButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorItalicButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnderlineButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorStrikethroughButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorSubscriptButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSuperscriptButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAlignLeftButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignCenterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignRightButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAlignJustifyButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-dropdownlist kendoEditorFontSize></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-dropdownlist kendoEditorFontFamily></kendo-toolbar-dropdownlist>\r\n <kendo-toolbar-colorpicker kendoEditorForeColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-colorpicker kendoEditorBackColor view=\"gradient\"></kendo-toolbar-colorpicker>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorInsertUnorderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorInsertOrderedListButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorIndentButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorOutdentButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorCreateLinkButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorUnlinkButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'default'\" kendoEditorInsertImageButton></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"data.ToolBarUploadImageMethod == 'explorer'\" icon=\"k-i-image k-i-photo\" (click)=\"openFileExplorer()\"></kendo-toolbar-button>\r\n <kendo-toolbar-button *ngIf=\"!!data.Compression\" icon=\"k-i-image k-i-file-image\" (click)=\"onOffCompressMode($event)\" #compressButton title=\"Disable Image Compression\"></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorViewSourceButton></kendo-toolbar-button>\r\n <kendo-editor-insert-table-button></kendo-editor-insert-table-button>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorAddColumnBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddColumnAfterButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowBeforeButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorAddRowAfterButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorDeleteColumnButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteRowButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorDeleteTableButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n <kendo-toolbar-buttongroup>\r\n <kendo-toolbar-button kendoEditorMergeCellsButton></kendo-toolbar-button>\r\n <kendo-toolbar-button kendoEditorSplitCellButton></kendo-toolbar-button>\r\n </kendo-toolbar-buttongroup>\r\n </kendo-toolbar>\r\n </kendo-editor>\r\n <input style=\"display:none;\" type=\"file\" [id]=\"data.Value +'-upload-file'\" [name]=\"data.Value +'-upload-file'\" accept=\"image/*\" ngf-max-size=\"5MB\" (change)=\"uploadImage($event)\">\r\n</div>\r\n", styles: [".title{margin:20px 10px 5px;font-size:18px;font-weight:700}.expand-btn-container{text-align:right}.expand-btn-container ion-button{--background: rgba(var(--ion-color-primary-rgb),10%);--color:black;font-size:12px}\n"] }]
9736
10139
  }], ctorParameters: function () { return [{ type: ZComponentService }, { type: i2.FontAweSomeService }, { type: i6.DialogService }, { type: i2.AlertService }, { type: i2.CompressImageService }, { type: i2.ToastService }]; }, propDecorators: { editor: [{
9737
10140
  type: ViewChild,
9738
10141
  args: ['editor']
@@ -12064,6 +12467,13 @@ class ZschedulerComponent {
12064
12467
  }
12065
12468
  //Set session values
12066
12469
  this.group["selectedDate"] = args.selectedDate;
12470
+ if (this.data.OnDateChange) {
12471
+ const func = ZComponentHelper.getGroupEvalValue.call(this, this.data.OnDateChange);
12472
+ if (typeof func === 'function') {
12473
+ const callFunc = func.bind(this.group.ctrlScope);
12474
+ callFunc(args);
12475
+ }
12476
+ }
12067
12477
  console.log("zschedule component date-change selection: ", args.dateRange);
12068
12478
  // this.local.selectedDate = args.dateRange.start;
12069
12479
  this.group.subject.next({
@@ -14664,8 +15074,8 @@ class ZprogressbarComponent extends FieldBase {
14664
15074
  ngOnInit() {
14665
15075
  super.initComponent().subscribe(() => {
14666
15076
  this.value = this.group.zModel[this.data.Value];
14667
- this.minValue = this.data.MinValue || this.minValue;
14668
- this.maxValue = this.data.MaxValue || this.maxValue;
15077
+ this.minValue = ZComponentHelper.getGroupEvalValue.call(this, this.data.MinValue) || this.minValue;
15078
+ this.maxValue = ZComponentHelper.getGroupEvalValue.call(this, this.data.MaxValue) || this.maxValue;
14669
15079
  if (this.data.Options) {
14670
15080
  const optionType = typeof (this.data.Options);
14671
15081
  if (optionType === 'object') {