All files / app/formly bbox.type.ts

77.5% Statements 31/40
76.31% Branches 29/38
90% Functions 9/10
78.12% Lines 25/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 9312x                                                                               12x   4x               67x       56x     4x       15x 5x 5x   15x       4x 1x       11x 11x 52x 11x 44x   11x 11x 11x 10x   1x   38x 11x 11x      
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { FieldType, FieldTypeConfig } from '@ngx-formly/core';
 
/**
 * GeoJSON bounding box: [west, south, east, north]
 * or [west, south, minZ, east, north, maxZ] (altitudes are preserved)
 */
@Component({
  selector: 'formly-field-bbox',
  host: { 'class': 'field bbox-field' },
  template: `
    <div class="form-array">
      @for (side of sides; track side.index) {
        <input type="number"
               class="grow bbox-{{ side.name }}"
               step="any"
               [min]="side.min"
               [max]="side.max"
               [placeholder]="side.label"
               [attr.aria-label]="side.label"
               [id]="side.index ? field.id + '-' + side.name : field.id"
               [value]="value(side.index)"
               [disabled]="formControl.disabled"
               (input)="set(side.index, $any($event.target).value)">
      }
    </div>
  `,
  styles: `
    .form-array {
      min-width: 0;
    }
    input {
      min-width: 0;
      width: 80px;
    }
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [ReactiveFormsModule],
})
export class FormlyFieldBbox extends FieldType<FieldTypeConfig> {
 
  sides = [
    { index: 0, name: 'west', label: $localize`West`, min: -180, max: 180 },
    { index: 1, name: 'south', label: $localize`South`, min: -90, max: 90 },
    { index: 2, name: 'east', label: $localize`East`, min: -180, max: 180 },
    { index: 3, name: 'north', label: $localize`North`, min: -90, max: 90 },
  ];
 
  get is3d() {
    return this.formControl.value?.length === 6;
  }
 
  pos(index: number) {
    return this.is3d && index >= 2 ? index + 1 : index;
  }
 
  private blank = new Set<number>();
  private saved?: (number | null)[];
 
  private blanks() {
    if (this.formControl.value !== this.saved) {
      this.blank.clear();
      this.saved = this.formControl.value;
    }
    return this.blank;
  }
 
  value(index: number) {
    if (this.blanks().has(index)) return '';
    return this.formControl.value?.[this.pos(index)] ?? '';
  }
 
  set(index: number, value: string) {
    const blank = this.blanks();
    const length = this.is3d ? 6 : 4;
    const bbox: (number | null)[] = Array.from({ length }, (_, i) => this.formControl.value?.[i] ?? null);
    for (const side of this.sides) {
      if (bbox[this.pos(side.index)] === null) blank.add(side.index);
    }
    const n = parseFloat(value);
    bbox[this.pos(index)] = isNaN(n) ? null : n;
    if (isNaN(n)) {
      blank.add(index);
    } else {
      blank.delete(index);
    }
    this.saved = blank.size === this.sides.length ? undefined : bbox.map(b => b ?? 0);
    this.formControl.setValue(this.saved);
    this.formControl.markAsDirty();
  }
}