diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html index 79ddc5e48..35576e9ee 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.html @@ -240,7 +240,6 @@ alt="Sample document page" i18n-alt class="d-block w-100" - [style.visibility]="imageLoaded ? 'visible' : 'hidden'" crossorigin="use-credentials" /> @if (imageLoaded) { @@ -267,7 +266,7 @@ [attr.width]="rect.w" [attr.height]="rect.h" [attr.stroke]="zoneColor(i)" - [attr.fill]="zoneFill(i)" + [attr.fill]="zoneColor(i) + '33'" > { expect(component.template.zones[0].x).toBe(200) }) + it('keeps the language selection reference stable until its value changes', () => { + const selected = zone() + selected.ocr_language = 'deu+eng' + const languages = component.ocrLanguageArray(selected) + + expect(languages).toEqual(['deu', 'eng']) + expect(component.ocrLanguageArray(selected)).toBe(languages) + + component.setOcrLanguages(selected, ['fra']) + expect(selected.ocr_language).toBe('fra') + const updated = component.ocrLanguageArray(selected) + expect(updated).toEqual(['fra']) + expect(updated).not.toBe(languages) + expect(component.ocrLanguageArray(selected)).toBe(updated) + + component.setOcrLanguages(selected, null) + expect(selected.ocr_language).toBe('') + const empty = component.ocrLanguageArray(selected) + expect(empty).toEqual([]) + expect(component.ocrLanguageArray(selected)).toBe(empty) + }) + it('hides results when extraction settings or geometry change', () => { const selected = zone() component.template.zones = [selected] diff --git a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts index a1f62c0ca..479f5cf81 100644 --- a/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts +++ b/src-ui/src/app/components/manage/ocr-templates/ocr-template-editor/ocr-template-editor.component.ts @@ -191,7 +191,6 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { } private _customFields: CustomField[] = [] - /** Items for the zone field select: built-in targets, then custom fields OCR can write to. */ readonly fieldItems = signal<{ id: ZoneFieldSelection; name: string }[]>([ ...OCR_BUILTIN_TARGETS, ]) @@ -211,11 +210,8 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { } documentTypes: DocumentType[] = [] transformOptions = TRANSFORM_OPTIONS - builtinTargets = OCR_BUILTIN_TARGETS - dateFormatOptions = DATE_FORMAT_OPTIONS ocrLanguageOptions = OCR_LANGUAGE_OPTIONS dateTransform = OCR_ZONE_TRANSFORM.Date - customDateFormatChoice = CUSTOM_DATE_FORMAT_CHOICE noSampleDocumentTitle = $localize`Select a sample document to test this zone` dateFormatItems = [ ...DATE_FORMAT_OPTIONS, @@ -592,7 +588,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { if (this.selectedZoneIndex !== null) { const handle = this.findHandleAt(point, this.selectedZoneIndex) if (handle) { - this.overlayCursor = RESIZE_CURSOR[handle] || 'crosshair' + this.overlayCursor = RESIZE_CURSOR[handle] return } } @@ -703,13 +699,7 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { return `0 0 ${imageSize.width} ${imageSize.height}` } - zoneColor(index: number): string { - return getZoneColor(index) - } - - zoneFill(index: number): string { - return `${this.zoneColor(index)}33` - } + readonly zoneColor = getZoneColor zoneLabel(zone: OcrTemplateZone, index: number): string { return zone.name || `Zone ${index + 1}` @@ -890,29 +880,24 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { }) } - private ocrLangCache = new WeakMap< + private readonly ocrLanguageCache = new WeakMap< OcrTemplateZone, - { src: string; arr: string[] } + { language: string; languages: string[] } >() ocrLanguageArray(zone: OcrTemplateZone): string[] { - const src = zone.ocr_language || '' - const cached = this.ocrLangCache.get(zone) - if (cached && cached.src === src) return cached.arr - const arr = src ? src.split('+').filter(Boolean) : [] - this.ocrLangCache.set(zone, { src, arr }) - return arr + const language = zone.ocr_language || '' + const cached = this.ocrLanguageCache.get(zone) + if (cached?.language === language) return cached.languages + const languages = language.split('+').filter(Boolean) + this.ocrLanguageCache.set(zone, { language, languages }) + return languages } setOcrLanguages(zone: OcrTemplateZone, langs: string[]) { - zone.ocr_language = (langs || []).join('+') - this.ocrLangCache.set(zone, { - src: zone.ocr_language, - arr: langs ? [...langs] : [], - }) + zone.ocr_language = (langs ?? []).join('+') } - /** Value bound to the field select: a built-in id string or a custom-field id. */ zoneFieldValue(zone: OcrTemplateZone): ZoneFieldSelection { const target = zone.target || DEFAULT_OCR_ZONE_TARGET return target === OCR_ZONE_TARGET.CustomField ? zone.custom_field : target @@ -1008,17 +993,10 @@ export class OcrTemplateEditorComponent implements OnInit, OnDestroy { return ( this.customDateFormatZones.has(zone) || (!!zone.date_format && - !this.dateFormatOptions.some( - (option) => option.id === zone.date_format - )) + !DATE_FORMAT_OPTIONS.some((option) => option.id === zone.date_format)) ) } - getDocumentTypeName(id: number): string { - const dt = this.documentTypes.find((d) => d.id === id) - return dt ? dt.name : `Type #${id}` - } - createField(name?: string) { const zone = this.selectedZone const modal = this.modalService.open(CustomFieldEditDialogComponent)