use stopPropagation & preventDefault

This commit is contained in:
Dan Percic 2023-03-18 02:11:12 +02:00
parent 655874989b
commit a2e40583e3
19 changed files with 57 additions and 73 deletions

View File

@ -1,9 +1,4 @@
<div
(click)="preventActionOnDisabled($event)"
[matTooltipClass]="tooltipClass"
[matTooltipPosition]="tooltipPosition"
[matTooltip]="tooltip"
>
<div [matTooltipClass]="tooltipClass" [matTooltipPosition]="tooltipPosition" [matTooltip]="tooltip">
<button
(click)="performAction($event)"
[class.dark-bg]="type === circleButtonTypes.dark"
@ -16,6 +11,7 @@
[id]="buttonId"
[type]="isSubmit ? 'submit' : 'button'"
mat-icon-button
stopPropagation
>
<mat-icon [svgIcon]="icon"></mat-icon>
</button>

View File

@ -5,13 +5,14 @@ import { IqserTooltipPosition, IqserTooltipPositions, randomString } from '../..
import { NgIf } from '@angular/common';
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
import { MatIconModule } from '@angular/material/icon';
import { StopPropagationDirective } from '../../directives';
@Component({
selector: 'iqser-circle-button [icon]',
templateUrl: './circle-button.component.html',
styleUrls: ['./circle-button.component.scss'],
standalone: true,
imports: [MatTooltipModule, MatIconModule, NgIf, MatButtonModule],
imports: [MatTooltipModule, MatIconModule, NgIf, MatButtonModule, StopPropagationDirective],
})
export class CircleButtonComponent implements OnInit {
readonly circleButtonTypes = CircleButtonTypes;
@ -41,7 +42,7 @@ export class CircleButtonComponent implements OnInit {
(this._elementRef.nativeElement as HTMLElement).style.setProperty('--iconSize', `${this.iconSize}px`);
}
performAction($event: MouseEvent): void {
performAction($event: MouseEvent) {
if (this.removeTooltip) {
this._matTooltip.hide();
// Timeout to allow tooltip to disappear first,
@ -51,10 +52,4 @@ export class CircleButtonComponent implements OnInit {
this.action.emit($event);
}
}
preventActionOnDisabled($event: MouseEvent): void {
if (this.disabled) {
$event.stopPropagation();
}
}
}

View File

@ -5,6 +5,7 @@
[ngClass]="classes"
[type]="submit ? 'submit' : 'button'"
mat-button
stopPropagation
>
<mat-icon *ngIf="icon" [svgIcon]="icon"></mat-icon>
<span>{{ label }}</span>

View File

@ -4,13 +4,14 @@ import { randomString } from '../../utils';
import { NgClass, NgIf } from '@angular/common';
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
import { MatIconModule } from '@angular/material/icon';
import { StopPropagationDirective } from '../../directives';
@Component({
selector: 'iqser-icon-button [label]',
templateUrl: './icon-button.component.html',
styleUrls: ['./icon-button.component.scss'],
standalone: true,
imports: [NgClass, MatButtonModule, NgIf, MatIconModule],
imports: [NgClass, MatButtonModule, NgIf, MatIconModule, StopPropagationDirective],
})
export class IconButtonComponent {
readonly iconButtonTypes = IconButtonTypes;

View File

@ -22,6 +22,7 @@ import { MatDialogModule } from '@angular/material/dialog';
import { CircleButtonComponent, IconButtonComponent } from './buttons';
import { DomSanitizer } from '@angular/platform-browser';
import { ICONS } from './utils/constants';
import { StopPropagationDirective } from './directives';
const matModules = [
MatIconModule,
@ -46,6 +47,7 @@ const components = [ConnectionStatusComponent, FullPageErrorComponent, Confirmat
TranslateModule,
IconButtonComponent,
CircleButtonComponent,
StopPropagationDirective,
],
exports: [...components, ...modules],
providers: [

View File

@ -25,8 +25,6 @@ export class ConfirmationDialogService extends DialogService<DialogType> {
openDialog(data?: { disableConfirm: boolean; [key: string]: unknown }): MatDialogRef<unknown> {
return super.openDialog(
'confirm',
// @ts-ignore
undefined,
new ConfirmationDialogInput({
title: _('confirmation-dialog.unsaved-changes.title'),
question: _('confirmation-dialog.unsaved-changes.question'),

View File

@ -1,12 +1,12 @@
<ng-container *ngIf="primaryFilterGroup$ | async as primaryGroup">
<iqser-input-with-action
(click)="$event.stopPropagation()"
*ngIf="primaryGroup.filterceptionPlaceholder"
[(value)]="searchService.searchValue"
[id]="'filterception-' + primaryGroup.slug"
[placeholder]="primaryGroup.filterceptionPlaceholder"
[width]="'full'"
></iqser-input-with-action>
<ng-container *ngTemplateOutlet="filterHeader"></ng-container>
<div *ngIf="primaryFilters$ | async as filters" class="filter-content">
@ -48,23 +48,20 @@
<div [translateParams]="{ count: primaryGroup.filters.length }" [translate]="primaryFiltersLabel" class="all-caps-label"></div>
<div class="actions">
<div
(click)="activatePrimaryFilters(); $event.stopPropagation()"
(click)="activatePrimaryFilters()"
*ngIf="!primaryGroup.singleSelect"
class="all-caps-label primary pointer"
stopPropagation
translate="actions.all"
></div>
<div
(click)="deactivateFilters(); $event.stopPropagation()"
class="all-caps-label primary pointer"
translate="actions.none"
></div>
<div (click)="deactivateFilters()" class="all-caps-label primary pointer" stopPropagation translate="actions.none"></div>
</div>
</div>
</ng-template>
<!--TODO: move to separate component-->
<ng-template #defaultFilterTemplate let-atLeastOneIsExpandable="atLeastOneIsExpandable" let-filter="filter" let-filterGroup="filterGroup">
<div (click)="toggleFilterExpanded($event, filter)" class="mat-menu-item flex">
<div (click)="toggleFilterExpanded(filter)" class="mat-menu-item flex" stopPropagation>
<div *ngIf="filter.children?.length > 0" class="arrow-wrapper">
<mat-icon *ngIf="filter.expanded" color="accent" svgIcon="iqser:arrow-down"></mat-icon>
<mat-icon *ngIf="!filter.expanded" color="accent" svgIcon="iqser:arrow-right"></mat-icon>
@ -73,11 +70,12 @@
<div *ngIf="atLeastOneIsExpandable && filter.children?.length === 0" class="arrow-wrapper spacer">&nbsp;</div>
<mat-checkbox
(click)="filterCheckboxClicked($event, filter, filterGroup)"
(click)="filterCheckboxClicked(filter, filterGroup)"
[checked]="filter.checked"
[id]="'filter-checkbox-' + (filter.id ? filter.id.replaceAll(' ', '-').replaceAll('.', '-') : 'none')"
[indeterminate]="filter.indeterminate"
class="filter-menu-checkbox"
stopPropagation
>
<ng-container
[ngTemplateOutletContext]="{ filter: filter }"
@ -89,8 +87,8 @@
</div>
<div *ngIf="filter.children?.length && filter.expanded">
<div (click)="$event.stopPropagation()" *ngFor="let child of filter.children" class="padding-left mat-menu-item">
<mat-checkbox (click)="filterCheckboxClicked($event, child, filterGroup, filter)" [checked]="child.checked">
<div *ngFor="let child of filter.children" class="padding-left mat-menu-item" stopPropagation>
<mat-checkbox (click)="filterCheckboxClicked(child, filterGroup, filter)" [checked]="child.checked" stopPropagation>
<ng-container
[ngTemplateOutletContext]="{ filter: child }"
[ngTemplateOutlet]="filterGroup.filterTemplate ?? defaultFilterLabelTemplate"

View File

@ -72,9 +72,7 @@ export class FilterCardComponent implements OnInit {
(this._elementRef.nativeElement as HTMLElement).style.setProperty('--filter-card-min-width', `${this.minWidth}px`);
}
filterCheckboxClicked($event: MouseEvent, nestedFilter: INestedFilter, filterGroup: IFilterGroup, parent?: INestedFilter): void {
$event.stopPropagation();
filterCheckboxClicked(nestedFilter: INestedFilter, filterGroup: IFilterGroup, parent?: INestedFilter): void {
if (filterGroup.singleSelect) {
this.deactivateFilters(nestedFilter.id);
}
@ -109,8 +107,7 @@ export class FilterCardComponent implements OnInit {
}
}
toggleFilterExpanded($event: MouseEvent, nestedFilter: INestedFilter): void {
$event.stopPropagation();
toggleFilterExpanded(nestedFilter: INestedFilter): void {
// eslint-disable-next-line no-param-reassign
nestedFilter.expanded = !nestedFilter.expanded;
this.filterService.refresh();

View File

@ -11,6 +11,7 @@ import { IqserHelpModeModule } from '../help-mode';
import { SingleFilterComponent } from './single-filter/single-filter.component';
import { FilterCardComponent } from './filter-card/filter-card.component';
import { MatIconModule } from '@angular/material/icon';
import { PreventDefaultDirective, StopPropagationDirective } from '../directives';
const matModules = [MatCheckboxModule, MatMenuModule];
const components = [QuickFiltersComponent, PopupFilterComponent, SingleFilterComponent, FilterCardComponent];
@ -27,6 +28,8 @@ const components = [QuickFiltersComponent, PopupFilterComponent, SingleFilterCom
IconButtonComponent,
ChevronButtonComponent,
MatIconModule,
StopPropagationDirective,
PreventDefaultDirective,
],
})
export class IqserFiltersModule {}

View File

@ -1,3 +1,3 @@
<mat-checkbox (click)="checkboxClicked($event)" [checked]="filter.checked" class="filter-menu-checkbox" color="primary">
<mat-checkbox (click)="checkboxClicked()" [checked]="filter.checked" class="filter-menu-checkbox" color="primary" preventDefault>
{{ filter.label }}
</mat-checkbox>

View File

@ -13,8 +13,7 @@ export class SingleFilterComponent {
constructor(readonly filterService: FilterService) {}
checkboxClicked($event: MouseEvent) {
$event.preventDefault();
checkboxClicked() {
this.filterService.toggleSingleFilter(this.filter.id);
}
}

View File

@ -12,14 +12,16 @@ import { MatDialog } from '@angular/material/dialog';
export class HelpModeComponent {
constructor(private readonly _dialog: MatDialog, readonly helpModeService: HelpModeService) {}
@HostListener('document:keydown.escape', ['$event']) onEscKeydownHandler(event: KeyboardEvent): void {
@HostListener('document:keydown.escape', ['$event'])
onEscKeydownHandler(event: KeyboardEvent): void {
if (!this.helpModeService.helpModeDialogIsOpened && this.helpModeService.isHelpModeActive) {
event?.stopPropagation();
this.helpModeService.deactivateHelpMode();
}
}
@HostListener('document:keydown.h', ['$event']) onHKeydownHandler(event: KeyboardEvent): void {
@HostListener('document:keydown.h', ['$event'])
onHKeydownHandler(event: KeyboardEvent): void {
const node = (event.target as IqserEventTarget).localName;
if (!this.helpModeService.isHelpModeActive && node !== 'input' && node !== 'textarea') {
if (this.helpModeService.helpButtonKey) {
@ -32,13 +34,15 @@ export class HelpModeComponent {
}
}
@HostListener('click') onClick(): void {
@HostListener('click')
onClick(): void {
if (this.helpModeService.isHelpModeActive) {
this.helpModeService.highlightHelperElements();
}
}
@HostListener('window:resize') onResize() {
@HostListener('window:resize')
onResize() {
if (this.helpModeService.isHelpModeActive) {
this.helpModeService.updateHelperElements();
}

View File

@ -1,15 +1,15 @@
<div class="iqser-input-group" [ngClass]="classList" [class.datepicker-wrapper]="isDate">
<div [class.datepicker-wrapper]="isDate" [ngClass]="classList" class="iqser-input-group">
<label *ngIf="label"> {{ label }} </label>
<ng-container *ngIf="isDate">
<input
[matDatepicker]="picker"
[placeholder]="placeholder || 'dd/mm/yy'"
[id]="id"
[name]="name"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
(click)="$event?.stopPropagation()"
[(ngModel)]="input"
[id]="id"
[matDatepicker]="picker"
[name]="name"
[placeholder]="placeholder || 'dd/mm/yy'"
stopPropagation
/>
<mat-datepicker-toggle [for]="picker" matSuffix>
<mat-icon matDatepickerToggleIcon svgIcon="red:calendar"></mat-icon>
@ -18,23 +18,15 @@
</ng-container>
<input
(ngModelChange)="onChange($event)"
*ngIf="isText"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
[id]="id"
[name]="name"
[placeholder]="placeholder || ''"
stopPropagation
type="text"
(click)="$event?.stopPropagation()"
/>
<input
*ngIf="isNumber"
[(ngModel)]="input"
(ngModelChange)="onChange($event)"
[id]="id"
[name]="name"
type="number"
(click)="$event?.stopPropagation()"
/>
<input (ngModelChange)="onChange($event)" *ngIf="isNumber" [(ngModel)]="input" [id]="id" [name]="name" stopPropagation type="number" />
</div>

View File

@ -1,9 +1,9 @@
<form (submit)="executeAction(null)" [style.max-width]="computedWidth" [style.width]="computedWidth" class="iqser-input-group">
<form (submit)="executeAction()" [style.max-width]="computedWidth" [style.width]="computedWidth" class="iqser-input-group" stopPropagation>
<input
[id]="inputId"
(ngModelChange)="valueChange.emit($event)"
[(ngModel)]="value"
[autocomplete]="autocomplete"
[id]="inputId"
[ngModelOptions]="{ standalone: true }"
[placeholder]="placeholder"
class="with-icon mt-0"
@ -15,17 +15,17 @@
<mat-icon *ngIf="isSearch && !hasContent" class="icon-right" svgIcon="iqser:search"></mat-icon>
<iqser-circle-button
[buttonId]="inputId + '-clear'"
(action)="reset()"
*ngIf="isSearch && hasContent"
[buttonId]="inputId + '-clear'"
[size]="25"
icon="iqser:close"
></iqser-circle-button>
<iqser-circle-button
[buttonId]="actionButtonId"
(action)="executeAction($event)"
(action)="executeAction()"
*ngIf="!isSearch"
[buttonId]="actionButtonId"
[disabled]="!hasContent"
[icon]="icon"
[size]="25"

View File

@ -4,6 +4,7 @@ import { FormsModule } from '@angular/forms';
import { NgIf } from '@angular/common';
import { CircleButtonComponent } from '../../buttons';
import { MatIconModule } from '@angular/material/icon';
import { StopPropagationDirective } from '../../directives';
@Component({
selector: 'iqser-input-with-action',
@ -11,7 +12,7 @@ import { MatIconModule } from '@angular/material/icon';
styleUrls: ['./input-with-action.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [FormsModule, NgIf, MatIconModule, CircleButtonComponent],
imports: [FormsModule, NgIf, MatIconModule, CircleButtonComponent, StopPropagationDirective],
})
export class InputWithActionComponent {
@Input() inputId = `${randomString() + '-search-input'}`;
@ -45,9 +46,7 @@ export class InputWithActionComponent {
this._changeDetectorRef.markForCheck();
}
executeAction($event: MouseEvent): void {
$event?.stopPropagation();
executeAction(): void {
if (this.hasContent) {
this.action.emit(this.value);
}

View File

@ -12,6 +12,7 @@ import { MatInputModule } from '@angular/material/input';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { CircleButtonComponent } from '../buttons';
import { MatIconModule } from '@angular/material/icon';
import { StopPropagationDirective } from '../directives';
const components = [RoundCheckboxComponent, EditableInputComponent, DetailsRadioComponent, DynamicInputComponent];
const deleteThisWhenAllComponentsAreStandalone = [InputWithActionComponent];
@ -29,6 +30,7 @@ const deleteThisWhenAllComponentsAreStandalone = [InputWithActionComponent];
MatInputModule,
...deleteThisWhenAllComponentsAreStandalone,
CircleButtonComponent,
StopPropagationDirective,
],
providers: [{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } }],
})

View File

@ -36,14 +36,12 @@ export abstract class DialogService<T extends string> {
openDialog(
type: T,
$event: MouseEvent,
data: unknown,
data?: unknown,
cb?: (...params: unknown[]) => Promise<unknown> | void,
finallyCb?: (...params: unknown[]) => void | Promise<unknown>,
): MatDialogRef<unknown> {
const config = this._config[type];
$event?.stopPropagation();
const ref = this._dialog.open(config.component, {
...defaultDialogConfig,
...(config.dialogConfig || {}),

View File

@ -10,7 +10,7 @@
</div>
<div *ngIf="actions?.length" class="actions-wrapper">
<a (click)="callAction($event, action.action)" *ngFor="let action of actions">
<a (click)="callAction(action.action)" *ngFor="let action of actions" stopPropagation>
{{ action.title }}
</a>
</div>

View File

@ -15,8 +15,7 @@ export class ToastComponent extends Toast {
return (this.options as ToasterOptions)?.actions || [];
}
callAction($event: MouseEvent, action: () => void): void {
$event.stopPropagation();
callAction(action: () => void): void {
if (action) {
action();
}