RED-10563: fixed key actions not prevented when input is focused.

Also updated config.json with documine stack and properties.
This commit is contained in:
Nicoleta Panaghiu 2024-11-29 13:21:47 +02:00
parent a890e4c5bc
commit 584a6b7bd0
6 changed files with 39 additions and 30 deletions

View File

@ -1,7 +1,6 @@
import { Component, computed, ElementRef, EventEmitter, Input, Output } from '@angular/core'; import { Component, computed, ElementRef, EventEmitter, Input, Output } from '@angular/core';
import { getConfig, HasScrollbarDirective } from '@iqser/common-ui'; import { getConfig, HasScrollbarDirective } from '@iqser/common-ui';
import { FilterService } from '@iqser/common-ui/lib/filtering'; import { FilterService } from '@iqser/common-ui/lib/filtering';
import { IqserEventTarget } from '@iqser/common-ui/lib/utils';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ListItem } from '@models/file/list-item'; import { ListItem } from '@models/file/list-item';
import { EarmarkGroup } from '@red/domain'; import { EarmarkGroup } from '@red/domain';
@ -15,6 +14,7 @@ import { NgForOf, NgIf } from '@angular/common';
import { HighlightsSeparatorComponent } from '../highlights-separator/highlights-separator.component'; import { HighlightsSeparatorComponent } from '../highlights-separator/highlights-separator.component';
import { AnnotationWrapperComponent } from '../annotation-wrapper/annotation-wrapper.component'; import { AnnotationWrapperComponent } from '../annotation-wrapper/annotation-wrapper.component';
import { AnnotationReferencesListComponent } from '../annotation-references-list/annotation-references-list.component'; import { AnnotationReferencesListComponent } from '../annotation-references-list/annotation-references-list.component';
import { isTargetInput } from '@utils/functions';
@Component({ @Component({
selector: 'redaction-annotations-list', selector: 'redaction-annotations-list',
@ -52,7 +52,7 @@ export class AnnotationsListComponent extends HasScrollbarDirective {
console.log('Selected Annotation:', annotation); console.log('Selected Annotation:', annotation);
} }
if (($event?.target as IqserEventTarget)?.localName === 'input') { if (isTargetInput($event)) {
return; return;
} }

View File

@ -4,7 +4,6 @@ import {
Component, Component,
computed, computed,
ElementRef, ElementRef,
HostListener,
Input, Input,
NgZone, NgZone,
OnDestroy, OnDestroy,
@ -19,7 +18,6 @@ import {
getConfig, getConfig,
HelpModeService, HelpModeService,
IqserAllowDirective, IqserAllowDirective,
IqserDialog,
IqserPermissionsService, IqserPermissionsService,
isIqserDevMode, isIqserDevMode,
LoadingService, LoadingService,
@ -51,6 +49,7 @@ import { ALL_HOTKEYS } from '../../utils/constants';
import { AnnotationDrawService } from '../../../pdf-viewer/services/annotation-draw.service'; import { AnnotationDrawService } from '../../../pdf-viewer/services/annotation-draw.service';
import { FileManagementService } from '@services/files/file-management.service'; import { FileManagementService } from '@services/files/file-management.service';
import { MatDialog } from '@angular/material/dialog'; import { MatDialog } from '@angular/material/dialog';
import { isTargetInput, isTargetTextArea } from '@utils/functions';
@Component({ @Component({
selector: 'redaction-file-header', selector: 'redaction-file-header',
@ -105,6 +104,7 @@ export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnD
ngOnInit() { ngOnInit() {
document.documentElement.addEventListener('fullscreenchange', this.fullscreenListener); document.documentElement.addEventListener('fullscreenchange', this.fullscreenListener);
this._pdf.instance.UI.iframeWindow.addEventListener('keyup', this.handleKeyEvent);
} }
ngAfterViewInit() { ngAfterViewInit() {
@ -116,10 +116,12 @@ export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnD
ngOnDetach() { ngOnDetach() {
document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener);
this._pdf.instance.UI.iframeWindow.removeEventListener('keyup', this.handleKeyEvent);
} }
ngOnDestroy() { ngOnDestroy() {
document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener); document.documentElement.removeEventListener('fullscreenchange', this.fullscreenListener);
this._pdf.instance.UI.iframeWindow.removeEventListener('keyup', this.handleKeyEvent);
} }
async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) { async downloadOriginalFile({ cacheIdentifier, dossierId, fileId, filename }: File) {
@ -177,7 +179,7 @@ export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnD
} }
} }
@HostListener('document:keyup', ['$event']) @Bind()
handleKeyEvent($event: KeyboardEvent) { handleKeyEvent($event: KeyboardEvent) {
if (this._router.url.indexOf('/file/') < 0) { if (this._router.url.indexOf('/file/') < 0) {
return; return;
@ -208,19 +210,20 @@ export class FileHeaderComponent implements OnInit, AfterViewInit, OnDetach, OnD
this._changeRef.markForCheck(); this._changeRef.markForCheck();
} }
if ($event.key === 'F5') {
window.location.reload();
}
if (isTargetInput($event) || isTargetTextArea($event)) {
return;
}
if (!$event.ctrlKey && !$event.metaKey && ['f', 'F'].includes($event.key)) { if (!$event.ctrlKey && !$event.metaKey && ['f', 'F'].includes($event.key)) {
// if you type in an input, don't toggle full-screen
if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) {
return;
}
this.toggleFullScreen(); this.toggleFullScreen();
return; return;
} }
if (['h', 'H'].includes($event.key)) { if (['h', 'H'].includes($event.key)) {
if ($event.target instanceof HTMLInputElement || $event.target instanceof HTMLTextAreaElement) {
return;
}
this._ngZone.run(() => { this._ngZone.run(() => {
window.focus(); window.focus();
this._helpModeService.activateHelpMode(false); this._helpModeService.activateHelpMode(false);

View File

@ -27,7 +27,7 @@ import {
PreventDefaultDirective, PreventDefaultDirective,
} from '@iqser/common-ui'; } from '@iqser/common-ui';
import { FilterService, INestedFilter, PopupFilterComponent } from '@iqser/common-ui/lib/filtering'; import { FilterService, INestedFilter, PopupFilterComponent } from '@iqser/common-ui/lib/filtering';
import { AutoUnsubscribe, Debounce, IqserEventTarget } from '@iqser/common-ui/lib/utils'; import { AutoUnsubscribe, Debounce } from '@iqser/common-ui/lib/utils';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ListItem } from '@models/file/list-item'; import { ListItem } from '@models/file/list-item';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
@ -57,6 +57,7 @@ import { PageExclusionComponent } from '../page-exclusion/page-exclusion.compone
import { PagesComponent } from '../pages/pages.component'; import { PagesComponent } from '../pages/pages.component';
import { ReadonlyBannerComponent } from '../readonly-banner/readonly-banner.component'; import { ReadonlyBannerComponent } from '../readonly-banner/readonly-banner.component';
import { DocumentInfoComponent } from '../document-info/document-info.component'; import { DocumentInfoComponent } from '../document-info/document-info.component';
import { isTargetInput } from '@utils/functions';
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
@ -89,10 +90,7 @@ const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
], ],
}) })
export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, OnDestroy { export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, OnDestroy {
private readonly _annotationsElement = viewChild<ElementRef>('annotationsElement');
private readonly _quickNavigationElement = viewChild<ElementRef>('quickNavigation');
readonly multiSelectTemplate = viewChild<TemplateRef<any>>('multiSelect'); readonly multiSelectTemplate = viewChild<TemplateRef<any>>('multiSelect');
readonly #isIqserDevMode = this._userPreferenceService.isIqserDevMode;
protected readonly iconButtonTypes = IconButtonTypes; protected readonly iconButtonTypes = IconButtonTypes;
protected readonly circleButtonTypes = CircleButtonTypes; protected readonly circleButtonTypes = CircleButtonTypes;
protected readonly displayedAnnotations$: Observable<Map<number, ListItem<AnnotationWrapper>[]>>; protected readonly displayedAnnotations$: Observable<Map<number, ListItem<AnnotationWrapper>[]>>;
@ -106,6 +104,9 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
protected displayedPages: number[] = []; protected displayedPages: number[] = [];
protected pagesPanelActive = true; protected pagesPanelActive = true;
protected enabledFilters = []; protected enabledFilters = [];
private readonly _annotationsElement = viewChild<ElementRef>('annotationsElement');
private readonly _quickNavigationElement = viewChild<ElementRef>('quickNavigation');
readonly #isIqserDevMode = this._userPreferenceService.isIqserDevMode;
#displayedPagesChanged = false; #displayedPagesChanged = false;
constructor( constructor(
@ -245,11 +246,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
@HostListener('window:keyup', ['$event']) @HostListener('window:keyup', ['$event'])
handleKeyEvent($event: KeyboardEvent): void { handleKeyEvent($event: KeyboardEvent): void {
if ( if (!ALL_HOTKEY_ARRAY.includes($event.key) || this._dialog.openDialogs.length || isTargetInput($event)) {
!ALL_HOTKEY_ARRAY.includes($event.key) ||
this._dialog.openDialogs.length ||
($event.target as IqserEventTarget).localName === 'input'
) {
return; return;
} }
@ -331,7 +328,7 @@ export class FileWorkloadComponent extends AutoUnsubscribe implements OnInit, On
} }
preventKeyDefault($event: KeyboardEvent): void { preventKeyDefault($event: KeyboardEvent): void {
if (COMMAND_KEY_ARRAY.includes($event.key) && !(($event.target as any).localName === 'input')) { if (COMMAND_KEY_ARRAY.includes($event.key) && !isTargetInput($event)) {
$event.preventDefault(); $event.preventDefault();
} }
} }

View File

@ -14,6 +14,7 @@ import { PdfViewer } from './pdf-viewer.service';
import Color = Core.Annotations.Color; import Color = Core.Annotations.Color;
import DocumentViewer = Core.DocumentViewer; import DocumentViewer = Core.DocumentViewer;
import Quad = Core.Math.Quad; import Quad = Core.Math.Quad;
import { isTargetInput } from '@utils/functions';
@Injectable() @Injectable()
export class REDDocumentViewer { export class REDDocumentViewer {
@ -71,12 +72,12 @@ export class REDDocumentViewer {
return fromEvent<KeyboardEvent>(this.#document, 'keyUp').pipe( return fromEvent<KeyboardEvent>(this.#document, 'keyUp').pipe(
tap(stopAndPreventIfNotAllowed), tap(stopAndPreventIfNotAllowed),
filter($event => { filter($event => {
if (($event.target as HTMLElement)?.tagName?.toLowerCase() === 'input') { if (isTargetInput($event)) {
if ($event.key === 'Escape') { if ($event.key === 'Escape') {
return true; return true;
} }
} }
return ($event.target as HTMLElement)?.tagName?.toLowerCase() !== 'input'; return isTargetInput($event);
}), }),
filter($event => $event.key.startsWith('Arrow') || ['f', 'h', 'H', 'Escape'].includes($event.key)), filter($event => $event.key.startsWith('Arrow') || ['f', 'h', 'H', 'Escape'].includes($event.key)),
tap<KeyboardEvent>(stopAndPrevent), tap<KeyboardEvent>(stopAndPrevent),

View File

@ -1,5 +1,5 @@
import { ITrackable } from '@iqser/common-ui'; import { ITrackable } from '@iqser/common-ui';
import type { List } from '@iqser/common-ui/lib/utils'; import type { IqserEventTarget, List } from '@iqser/common-ui/lib/utils';
import type { AnnotationWrapper } from '@models/file/annotation.wrapper'; import type { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { Dayjs } from 'dayjs'; import { Dayjs } from 'dayjs';
@ -143,3 +143,11 @@ export function urlFileId() {
const fileId = splitUrl[splitUrl.length - 1]; const fileId = splitUrl[splitUrl.length - 1];
return fileId.split('?')[0]; return fileId.split('?')[0];
} }
export function isTargetInput(event: Event) {
return (event?.target as IqserEventTarget)?.localName === 'input';
}
export function isTargetTextArea(event: Event) {
return (event?.target as IqserEventTarget)?.localName === 'textarea';
}

View File

@ -1,9 +1,9 @@
{ {
"ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_NAME": null,
"ADMIN_CONTACT_URL": null, "ADMIN_CONTACT_URL": null,
"API_URL": "https://dan2.iqser.cloud", "API_URL": "https://frontend2.iqser.cloud",
"APP_NAME": "RedactManager", "APP_NAME": "RedactManager",
"IS_DOCUMINE": false, "IS_DOCUMINE": true,
"RULE_EDITOR_DEV_ONLY": false, "RULE_EDITOR_DEV_ONLY": false,
"AUTO_READ_TIME": 3, "AUTO_READ_TIME": 3,
"BACKEND_APP_VERSION": "4.4.40", "BACKEND_APP_VERSION": "4.4.40",
@ -13,13 +13,13 @@
"MAX_RETRIES_ON_SERVER_ERROR": 3, "MAX_RETRIES_ON_SERVER_ERROR": 3,
"OAUTH_CLIENT_ID": "redaction", "OAUTH_CLIENT_ID": "redaction",
"OAUTH_IDP_HINT": null, "OAUTH_IDP_HINT": null,
"OAUTH_URL": "https://dan2.iqser.cloud/auth", "OAUTH_URL": "https://frontend2.iqser.cloud/auth",
"RECENT_PERIOD_IN_HOURS": 24, "RECENT_PERIOD_IN_HOURS": 24,
"SELECTION_MODE": "structural", "SELECTION_MODE": "structural",
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview",
"ANNOTATIONS_THRESHOLD": 1000, "ANNOTATIONS_THRESHOLD": 1000,
"THEME": "redact", "THEME": "scm",
"BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/redact/", "BASE_TRANSLATIONS_DIRECTORY": "/assets/i18n/scm/",
"AVAILABLE_NOTIFICATIONS_DAYS": 30, "AVAILABLE_NOTIFICATIONS_DAYS": 30,
"AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60, "AVAILABLE_OLD_NOTIFICATIONS_MINUTES": 60,
"NOTIFICATIONS_THRESHOLD": 1000, "NOTIFICATIONS_THRESHOLD": 1000,