@sumaris-net/ngx-components 1.20.10 → 1.20.13

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.
@@ -3371,15 +3371,15 @@
3371
3371
  }
3372
3372
  SharedValidators.getDoubleRegexp = function (maxDecimals) {
3373
3373
  if (isNil(maxDecimals))
3374
- return this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS.NO_LIMIT;
3374
+ return this._DOUBLE_REGEXP_CACHE.NO_LIMIT;
3375
3375
  if (maxDecimals < 0)
3376
3376
  throw new Error("Invalid maxDecimals value: " + maxDecimals);
3377
- var regexp = this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS[maxDecimals];
3377
+ var regexp = this._DOUBLE_REGEXP_CACHE[maxDecimals];
3378
3378
  if (regexp)
3379
3379
  return regexp;
3380
- // New regexp: add it to cache
3381
- this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS[maxDecimals] = new RegExp("^[-]?[0-9]+([.,][0-9]{1," + maxDecimals + "})?$");
3382
- return this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS[maxDecimals];
3380
+ // New: add to cache
3381
+ this._DOUBLE_REGEXP_CACHE[maxDecimals] = new RegExp("^-?\\d+([.,]\\d{1," + maxDecimals + "})?$");
3382
+ return this._DOUBLE_REGEXP_CACHE[maxDecimals];
3383
3383
  };
3384
3384
  SharedValidators.latitude = function (control) {
3385
3385
  var value = control.value;
@@ -3551,13 +3551,11 @@
3551
3551
  };
3552
3552
  return SharedValidators;
3553
3553
  }());
3554
- SharedValidators._REGEXP_CACHE = {
3555
- DOUBLE_BY_MAX_DECIMALS: {
3556
- NO_LIMIT: /^[-]?[0-9]+([.,][0-9]*)?$/,
3557
- 1: /^[-]?[0-9]+([.,][0-9])?$/,
3558
- 2: /^[-]?[0-9]+([.,][0-9]{1,2})?$/,
3559
- 3: /^[-]?[0-9]+([.,][0-9]{1,2})?$/,
3560
- }
3554
+ SharedValidators._DOUBLE_REGEXP_CACHE = {
3555
+ NO_LIMIT: /^-?\d+([.,]\d*)?$/,
3556
+ 1: /^-?\d+([.,]\d)?$/,
3557
+ 2: /^-?\d+([.,]\d{1,2})?$/,
3558
+ 3: /^-?\d+([.,]\d{1,3})?$/ // 3 decimals max
3561
3559
  };
3562
3560
  SharedValidators.I18N_ERROR_KEYS = {
3563
3561
  required: 'ERROR.FIELD_REQUIRED',
@@ -5366,16 +5364,15 @@
5366
5364
  };
5367
5365
  var ɵ0$2 = noop$1;
5368
5366
  var MatLatLongField = /** @class */ (function () {
5369
- function MatLatLongField(translate, formBuilder, cd, formGroupDir) {
5370
- this.translate = translate;
5367
+ function MatLatLongField(formBuilder, cd, formGroupDir) {
5371
5368
  this.formBuilder = formBuilder;
5372
5369
  this.cd = cd;
5373
5370
  this.formGroupDir = formGroupDir;
5374
5371
  this._onChangeCallback = noop$1;
5375
5372
  this._onTouchedCallback = noop$1;
5376
5373
  this._subscription = new rxjs.Subscription();
5377
- this.disabling = false;
5378
- this.writing = false;
5374
+ this._disabling = false;
5375
+ this._writing = false;
5379
5376
  this._readonly = false;
5380
5377
  this.required = false;
5381
5378
  this.floatLabel = 'auto';
@@ -5457,7 +5454,7 @@
5457
5454
  .subscribe(function (_) { return _this.onFormChange(_this.textFormControl.value); }));
5458
5455
  // Listen status changes (when done outside the component - e.g. when setErrors() is calling on the formControl)
5459
5456
  this._subscription.add(this.formControl.statusChanges
5460
- .pipe(operators.filter(function (_) { return !_this.readonly && !_this.writing && !_this.disabling; }) // Skip
5457
+ .pipe(operators.filter(function (_) { return !_this.readonly && !_this._writing && !_this._disabling; }) // Skip
5461
5458
  )
5462
5459
  .subscribe(function (_) { return _this.markForCheck(); }));
5463
5460
  };
@@ -5465,12 +5462,12 @@
5465
5462
  this._subscription.unsubscribe();
5466
5463
  };
5467
5464
  MatLatLongField.prototype.writeValue = function (obj) {
5468
- if (this.writing)
5465
+ if (this._writing)
5469
5466
  return;
5470
- this.value = (typeof obj === 'string') ? parseFloat(obj.replace(/,/g, '.')) : obj;
5471
- this.writing = true;
5467
+ var value = (typeof obj === 'string') ? parseFloat(obj.replace(/,/g, '.')) : obj;
5468
+ this._writing = true;
5472
5469
  var strValue = this._formatFn(this.value, Object.assign(Object.assign({}, this._formatOptions), { placeholderChar: this.placeholderChar }));
5473
- var sign = isNotNil(this.value) ? (this.value < 0 ? -1 : 1) :
5470
+ var sign = isNotNil(this.value) ? (value < 0 ? -1 : 1) :
5474
5471
  // Use default sign, if any
5475
5472
  (this.defaultSign ? (this.defaultSign === '-' ? -1 : 1) : null);
5476
5473
  // DEBUG
@@ -5478,7 +5475,7 @@
5478
5475
  // console.debug("sign: " + sign)
5479
5476
  this.textFormControl.patchValue(strValue, { emitEvent: false });
5480
5477
  this.signFormControl.patchValue(sign, { emitEvent: false });
5481
- this.writing = false;
5478
+ this._writing = false;
5482
5479
  this.markForCheck();
5483
5480
  };
5484
5481
  MatLatLongField.prototype.registerOnChange = function (fn) {
@@ -5488,9 +5485,9 @@
5488
5485
  this._onTouchedCallback = fn;
5489
5486
  };
5490
5487
  MatLatLongField.prototype.setDisabledState = function (isDisabled) {
5491
- if (this.disabling)
5488
+ if (this._disabling)
5492
5489
  return;
5493
- this.disabling = true;
5490
+ this._disabling = true;
5494
5491
  if (isDisabled) {
5495
5492
  this.textFormControl.disable({ onlySelf: true, emitEvent: false });
5496
5493
  this.signFormControl.disable({ onlySelf: true, emitEvent: false });
@@ -5499,7 +5496,7 @@
5499
5496
  this.textFormControl.enable({ onlySelf: true, emitEvent: false });
5500
5497
  this.signFormControl.enable({ onlySelf: true, emitEvent: false });
5501
5498
  }
5502
- this.disabling = false;
5499
+ this._disabling = false;
5503
5500
  this.markForCheck();
5504
5501
  };
5505
5502
  /**
@@ -5621,13 +5618,13 @@
5621
5618
  }
5622
5619
  };
5623
5620
  MatLatLongField.prototype.onFormChange = function (strValue) {
5624
- if (this.writing)
5621
+ if (this._writing)
5625
5622
  return; // Skip if call by self
5626
- this.writing = true;
5623
+ this._writing = true;
5627
5624
  if (this.textFormControl.invalid || this.signFormControl.invalid) {
5628
5625
  this.formControl.markAsPending();
5629
5626
  this.formControl.setErrors(Object.assign(Object.assign(Object.assign({}, this.formControl.errors), this.textFormControl.errors), this.signFormControl.errors));
5630
- this.writing = false;
5627
+ this._writing = false;
5631
5628
  return;
5632
5629
  }
5633
5630
  var parsedValue = isNotNilOrBlank(strValue) ? parseLatitudeOrLongitude(strValue, this.pattern, 7 /*=precision of the converted double value */, this.placeholderChar) : null;
@@ -5636,15 +5633,15 @@
5636
5633
  if (isNaN(parsedValue)) {
5637
5634
  this.formControl.markAsPending();
5638
5635
  this.formControl.setErrors(this.type === 'latitude' ? { latitude: true } : { longitude: true });
5639
- this.writing = false;
5636
+ this._writing = false;
5640
5637
  return;
5641
5638
  }
5642
5639
  var sign = (this.pattern === 'DD') ? 1 /*ignore sign*/ : (this.signFormControl.value || 1);
5643
- this.value = isNotNil(parsedValue) ? sign * parsedValue : null;
5640
+ var value = isNotNil(parsedValue) ? sign * parsedValue : null;
5644
5641
  // Get the model value
5645
- //console.debug("[mat-latlon] Setting value {" + this.value + "} parsed from {" + strValue + "}");
5646
- this.formControl.patchValue(this.value, { emitEvent: false });
5647
- this.writing = false;
5642
+ //console.debug("[mat-latlon] Setting value {" + value + "} parsed from {" + strValue + "}");
5643
+ this.formControl.patchValue(value, { emitEvent: false });
5644
+ this._writing = false;
5648
5645
  this.markForCheck();
5649
5646
  this._onChangeCallback(this.value);
5650
5647
  };
@@ -5664,7 +5661,7 @@
5664
5661
  MatLatLongField.decorators = [
5665
5662
  { type: i0.Component, args: [{
5666
5663
  selector: 'mat-latlong-field',
5667
- template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{_format(value) }}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n</mat-form-field>\n\n<!-- writable -->\n<ng-template #writable>\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding no-wrap\">\n <ion-col class=\"text ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"formControl.disabled\"\n [class.mat-form-field-invalid]=\"formControl.touched && formControl.invalid\">\n\n <mat-label *ngIf=\"placeholder\">{{placeholder}}</mat-label>\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput #inputElement\n type=\"text\"\n autocomplete=\"off\"\n [textMask]=\"textMaskConfig\"\n [formControl]=\"textFormControl\"\n [placeholder]=\"inputPlaceholder|translate\"\n (keypress)=\"onKeypress($event)\"\n (keydown.tab)=\"moveCaretToSeparator($event, true)\"\n (keydown.shift.tab)=\"moveCaretToSeparator($event, false)\"\n (focus)=\"_onFocus($event)\"\n (blur)=\"_onBlur($event)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\">\n\n <div matSuffix *ngIf=\"!showSignControl\">\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <div class=\"mat-form-field-subscript mat-form-field-subscript-wrapper\">\n\n <!-- errors -->\n <ng-container *ngIf=\"formControl.touched && formControl.errors|mapKeys|arrayFirst; let errorKey\" [ngSwitch]=\"errorKey\">\n <mat-error *ngSwitchCase=\"'required'\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngSwitchCase=\"'latitude'\" translate>ERROR.FIELD_NOT_VALID_LATITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'longitude'\" translate>ERROR.FIELD_NOT_VALID_LONGITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'min'\">{{'ERROR.FIELD_MIN_COMPACT'|translate: {min: _format(formControl.errors.min.min) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'max'\">{{'ERROR.FIELD_MAX_COMPACT'|translate: {max: _format(formControl.errors.max.max) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'msg'\">{{(formControl.errors.msg?.key || formControl.errors.msg) | translate: formControl.errors.msg?.params}}</mat-error>\n </ng-container>\n <ng-content select=\"mat-error\"></ng-content>\n\n <!-- mat hint -->\n <div class=\"mat-form-field-hint-wrapper\" [class.cdk-visually-hidden]=\"formControl.invalid\">\n <div class=\"mat-form-field-hint-spacer\"></div>\n <ng-content select=\"mat-hint\"></ng-content>\n </div>\n </div>\n </mat-form-field>\n </ion-col>\n\n <!-- sign -->\n <ion-col class=\"sign ion-no-padding\" [ngSwitch]=\"type\" *ngIf=\"showSignControl\">\n\n <!-- sign on latitude -->\n <mat-form-field *ngSwitchCase=\"'latitude'\"\n floatLabel=\"never\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LAT_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+1\">\n <mat-option [value]=\"1\">{{'COMMON.LAT_LONG.LAT_SIGN_N'|translate}}</mat-option>\n <mat-option [value]=\"-1\" >{{'COMMON.LAT_LONG.LAT_SIGN_S'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n\n <!-- sign on longitude -->\n <mat-form-field floatLabel=\"never\"\n *ngSwitchCase=\"'longitude'\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LONG_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+2\">\n <mat-option [value]=\"1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_E'|translate}}</mat-option>\n <mat-option [value]=\"-1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_W'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n</ng-template>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
5664
+ template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{_format(formControl.value) }}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n</mat-form-field>\n\n<!-- writable -->\n<ng-template #writable>\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding no-wrap\">\n <ion-col class=\"text ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"formControl.disabled\"\n [class.mat-form-field-invalid]=\"formControl.touched && formControl.invalid\">\n\n <mat-label *ngIf=\"placeholder\">{{placeholder}}</mat-label>\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput #inputElement\n type=\"text\"\n autocomplete=\"off\"\n [textMask]=\"textMaskConfig\"\n [formControl]=\"textFormControl\"\n [placeholder]=\"inputPlaceholder|translate\"\n (keypress)=\"onKeypress($event)\"\n (keydown.tab)=\"moveCaretToSeparator($event, true)\"\n (keydown.shift.tab)=\"moveCaretToSeparator($event, false)\"\n (focus)=\"_onFocus($event)\"\n (blur)=\"_onBlur($event)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\">\n\n <div matSuffix *ngIf=\"!showSignControl\">\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <div class=\"mat-form-field-subscript mat-form-field-subscript-wrapper\">\n\n <!-- errors -->\n <ng-container *ngIf=\"formControl.touched && formControl.errors|mapKeys|arrayFirst; let errorKey\" [ngSwitch]=\"errorKey\">\n <mat-error *ngSwitchCase=\"'required'\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngSwitchCase=\"'latitude'\" translate>ERROR.FIELD_NOT_VALID_LATITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'longitude'\" translate>ERROR.FIELD_NOT_VALID_LONGITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'min'\">{{'ERROR.FIELD_MIN_COMPACT'|translate: {min: _format(formControl.errors.min.min) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'max'\">{{'ERROR.FIELD_MAX_COMPACT'|translate: {max: _format(formControl.errors.max.max) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'msg'\">{{(formControl.errors.msg?.key || formControl.errors.msg) | translate: formControl.errors.msg?.params}}</mat-error>\n </ng-container>\n <ng-content select=\"mat-error\"></ng-content>\n\n <!-- mat hint -->\n <div class=\"mat-form-field-hint-wrapper\" [class.cdk-visually-hidden]=\"formControl.invalid\">\n <div class=\"mat-form-field-hint-spacer\"></div>\n <ng-content select=\"mat-hint\"></ng-content>\n </div>\n </div>\n </mat-form-field>\n </ion-col>\n\n <!-- sign -->\n <ion-col class=\"sign ion-no-padding\" [ngSwitch]=\"type\" *ngIf=\"showSignControl\">\n\n <!-- sign on latitude -->\n <mat-form-field *ngSwitchCase=\"'latitude'\"\n floatLabel=\"never\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LAT_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+1\">\n <mat-option [value]=\"1\">{{'COMMON.LAT_LONG.LAT_SIGN_N'|translate}}</mat-option>\n <mat-option [value]=\"-1\" >{{'COMMON.LAT_LONG.LAT_SIGN_S'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n\n <!-- sign on longitude -->\n <mat-form-field floatLabel=\"never\"\n *ngSwitchCase=\"'longitude'\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LONG_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+2\">\n <mat-option [value]=\"1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_E'|translate}}</mat-option>\n <mat-option [value]=\"-1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_W'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n</ng-template>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
5668
5665
  providers: [
5669
5666
  {
5670
5667
  provide: i1.NG_VALUE_ACCESSOR,
@@ -5672,12 +5669,10 @@
5672
5669
  useExisting: i0.forwardRef(function () { return MatLatLongField; }),
5673
5670
  }
5674
5671
  ],
5675
- changeDetection: i0.ChangeDetectionStrategy.OnPush,
5676
- styles: [":host{display:inline-block;width:100%;min-width:140px;position:relative;--ion-grid-column-padding:0}mat-form-field .datetime-md{padding:0!important}ion-row{flex-wrap:nowrap}ion-row ion-col.text{min-width:80px}ion-row ion-col.sign{min-width:40px;max-width:55px}mat-form-field{width:100%}mat-form-field .mat-form-field-subscript-wrapper{overflow:visible;white-space:nowrap;top:100%}mat-form-field .mat-form-field-subscript-wrapper .mat-form-field-hint-wrapper{display:flex}mat-form-field .mat-form-field-subscript-wrapper .mat-form-field-hint-wrapper .mat-form-field-hint-spacer{flex:1 0 1em}mat-error{text-align:right;width:100%}"]
5672
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
5677
5673
  },] }
5678
5674
  ];
5679
5675
  MatLatLongField.ctorParameters = function () { return [
5680
- { type: i1$2.TranslateService },
5681
5676
  { type: i1.FormBuilder },
5682
5677
  { type: i0.ChangeDetectorRef },
5683
5678
  { type: i1.FormGroupDirective, decorators: [{ type: i0.Optional }] }
@@ -18382,6 +18377,30 @@
18382
18377
  }
18383
18378
  }
18384
18379
  };
18380
+ FilesUtils.downloadUri = function (uri, filename) {
18381
+ if (navigator.msLaunchUri) { // IE 10+
18382
+ navigator.msLaunchUri(uri);
18383
+ }
18384
+ else {
18385
+ filename = filename || this.getFilenameFromUri(uri);
18386
+ var link = document.createElement('a');
18387
+ if (link.download !== undefined) {
18388
+ // Browsers that support HTML5 download attribute
18389
+ link.setAttribute('href', uri);
18390
+ link.setAttribute('download', filename);
18391
+ link.style.visibility = 'hidden';
18392
+ document.body.appendChild(link);
18393
+ link.click();
18394
+ document.body.removeChild(link);
18395
+ }
18396
+ }
18397
+ };
18398
+ FilesUtils.getFilenameFromUri = function (uri) {
18399
+ var lastSlashIndex = uri === null || uri === void 0 ? void 0 : uri.lastIndexOf('/');
18400
+ if (lastSlashIndex === -1 || lastSlashIndex === uri.length - 1)
18401
+ throw new Error('Invalid URI format. No slash found');
18402
+ return uri.substring(lastSlashIndex + 1);
18403
+ };
18385
18404
  return FilesUtils;
18386
18405
  }());
18387
18406
  FilesUtils.UTF8_BOM_CHAR = new Uint8Array([0xEF, 0xBB, 0xBF]); // UTF-8 BOM