mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
Migrate to new animations api (#12078)
This commit is contained in:
@@ -17,9 +17,8 @@
|
||||
|
||||
import { fakeAsync, TestBed, tick } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SessionTimeoutDialogComponent } from './session-timeout-dialog.component';
|
||||
import { NoopTranslateModule } from '../../testing';
|
||||
|
||||
describe('SessionTimeoutDialogComponent', () => {
|
||||
const dialogRef = { close: jasmine.createSpy('close') };
|
||||
@@ -27,7 +26,7 @@ describe('SessionTimeoutDialogComponent', () => {
|
||||
beforeEach(() => {
|
||||
dialogRef.close.calls.reset();
|
||||
TestBed.configureTestingModule({
|
||||
imports: [SessionTimeoutDialogComponent, NoopAnimationsModule, TranslateModule.forRoot()],
|
||||
imports: [SessionTimeoutDialogComponent, NoopTranslateModule],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: dialogRef },
|
||||
{ provide: MAT_DIALOG_DATA, useValue: { dialogTimeoutMs: 3000 } }
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { state, style, animate, transition, query, group, sequence, AnimationStateMetadata, AnimationTransitionMetadata } from '@angular/animations';
|
||||
|
||||
export const contextMenuAnimation: (AnimationStateMetadata | AnimationTransitionMetadata)[] = [
|
||||
state(
|
||||
'void',
|
||||
style({
|
||||
opacity: 0,
|
||||
transform: 'scale(0.01, 0.01)'
|
||||
})
|
||||
),
|
||||
transition(
|
||||
'void => *',
|
||||
sequence([
|
||||
query('.mat-mdc-menu-content', style({ opacity: 0 })),
|
||||
animate('100ms linear', style({ opacity: 1, transform: 'scale(1, 0.5)' })),
|
||||
group([
|
||||
query('.mat-mdc-menu-content', animate('400ms cubic-bezier(0.55, 0, 0.55, 0.2)', style({ opacity: 1 }))),
|
||||
animate('300ms cubic-bezier(0.25, 0.8, 0.25, 1)', style({ transform: 'scale(1, 1)' }))
|
||||
])
|
||||
])
|
||||
),
|
||||
transition('* => void', animate('150ms 50ms linear', style({ opacity: 0 })))
|
||||
];
|
||||
@@ -1,15 +1,20 @@
|
||||
<div mat-menu class="mat-mdc-menu-panel mdc-menu-surface mdc-menu-surface--open" @panelAnimation>
|
||||
<div mat-menu class="mat-mdc-menu-panel mdc-menu-surface mdc-menu-surface--open adf-context-menu-animate">
|
||||
<div id="adf-context-menu-content" class="mat-mdc-menu-content">
|
||||
<ng-container *ngFor="let link of links">
|
||||
<button *ngIf="link.model?.visible"
|
||||
@for (link of links; track link) {
|
||||
@if (link.model?.visible) {
|
||||
<button
|
||||
[attr.data-automation-id]="'context-' + (link.title || link.model?.title | translate)"
|
||||
mat-menu-item
|
||||
[disabled]="link.model?.disabled"
|
||||
[title]="link.model?.tooltip | translate"
|
||||
(click)="onMenuItemClick($event, link)">
|
||||
<mat-icon *ngIf="link.model?.icon" [adf-icon]="link.model.icon" />
|
||||
<span>{{ link.title || link.model?.title | translate }}</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
(click)="onMenuItemClick($event, link)"
|
||||
>
|
||||
@if (link.model?.icon) {
|
||||
<mat-icon [adf-icon]="link.model.icon" />
|
||||
}
|
||||
<span>{{ link.title || link.model?.title | translate }}</span>
|
||||
</button>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,48 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes menu-scale-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: scale(0.01, 0.01);
|
||||
}
|
||||
|
||||
25% {
|
||||
opacity: 1;
|
||||
transform: scale(1, 0.5);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes menu-scale-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: scale(1, 1);
|
||||
}
|
||||
|
||||
75% {
|
||||
opacity: 0;
|
||||
transform: scale(1, 0.5);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: scale(0.01, 0.01);
|
||||
}
|
||||
}
|
||||
|
||||
adf-context-menu {
|
||||
animation: delayed-elevation 0.5s ease-in-out 0.1s forwards;
|
||||
|
||||
.adf-context-menu-animate {
|
||||
animation: menu-scale-in 500ms cubic-bezier(0.25, 0.8, 0.25, 1) forwards;
|
||||
|
||||
&.adf-closing {
|
||||
animation: menu-scale-out 500ms cubic-bezier(0.25, 0.8, 0.25, 1) forwards;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { trigger } from '@angular/animations';
|
||||
import { FocusKeyManager } from '@angular/cdk/a11y';
|
||||
import { MatMenuItem, MatMenuModule } from '@angular/material/menu';
|
||||
import { ContextMenuOverlayRef } from './context-menu-overlay';
|
||||
import { contextMenuAnimation } from './animations';
|
||||
import { CONTEXT_MENU_DATA } from './context-menu.tokens';
|
||||
import { AfterViewInit, Component, HostListener, QueryList, ViewChildren, ViewEncapsulation, inject } from '@angular/core';
|
||||
import { NgForOf, NgIf } from '@angular/common';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes';
|
||||
import { IconModule } from '../icon/icon.module';
|
||||
@@ -37,16 +34,15 @@ import { ContextMenuItem } from './interfaces';
|
||||
class: 'adf-context-menu'
|
||||
},
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [IconModule, MatMenuModule, NgForOf, NgIf, TranslatePipe],
|
||||
animations: [trigger('panelAnimation', contextMenuAnimation)]
|
||||
imports: [IconModule, MatMenuModule, TranslatePipe]
|
||||
})
|
||||
export class ContextMenuListComponent implements AfterViewInit {
|
||||
private readonly contextMenuOverlayRef = inject<ContextMenuOverlayRef>(ContextMenuOverlayRef);
|
||||
private readonly data = inject(CONTEXT_MENU_DATA, { optional: true });
|
||||
private keyManager?: FocusKeyManager<MatMenuItem>;
|
||||
|
||||
private keyManager: FocusKeyManager<MatMenuItem>;
|
||||
@ViewChildren(MatMenuItem) items: QueryList<MatMenuItem>;
|
||||
links: ContextMenuItem[];
|
||||
@ViewChildren(MatMenuItem) items = new QueryList<MatMenuItem>();
|
||||
|
||||
public readonly links: ContextMenuItem[] = inject(CONTEXT_MENU_DATA, { optional: true }) || [];
|
||||
|
||||
@HostListener('document:keydown.Escape', ['$event'])
|
||||
handleKeydownEscape(event: Event) {
|
||||
@@ -60,15 +56,11 @@ export class ContextMenuListComponent implements AfterViewInit {
|
||||
if (event) {
|
||||
const keyCode = event.keyCode;
|
||||
if (keyCode === UP_ARROW || keyCode === DOWN_ARROW) {
|
||||
this.keyManager.onKeydown(event);
|
||||
this.keyManager?.onKeydown(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.links = this.data;
|
||||
}
|
||||
|
||||
onMenuItemClick(event: Event, menuItem: ContextMenuItem) {
|
||||
if (menuItem?.model?.disabled) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -14,25 +14,24 @@
|
||||
[cdkDropListSortPredicate]="filterDisabledColumns"
|
||||
data-automation-id="datatable-row-header"
|
||||
class="adf-datatable-row"
|
||||
role="row">
|
||||
|
||||
|
||||
role="row"
|
||||
>
|
||||
<!-- Drag -->
|
||||
@if (enableDragRows) {
|
||||
@if (enableDragRows) {
|
||||
<div class="adf-datatable-cell-header adf-drag-column">
|
||||
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.DRAG' | translate }}</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<!-- Actions (left) -->
|
||||
@if (actions && actionsPosition === 'left') {
|
||||
@if (actions && actionsPosition === 'left') {
|
||||
<div class="adf-actions-column adf-datatable-cell-header">
|
||||
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
<!-- Columns -->
|
||||
@if (multiselect) {
|
||||
@if (multiselect) {
|
||||
<div class="adf-datatable-cell-header adf-datatable-checkbox">
|
||||
<mat-checkbox
|
||||
[indeterminate]="isSelectAllIndeterminate"
|
||||
@@ -48,21 +47,28 @@
|
||||
{{ 'ADF-DATATABLE.ACCESSIBILITY.SELECT_ALL' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@for (col of getVisibleColumns(); track col.key; let lastColumn = $last; let columnIndex = $index) {
|
||||
@for (col of getVisibleColumns(); track col.key; let lastColumn = $last; let columnIndex = $index) {
|
||||
@if (col.title || !showProvidedActions) {
|
||||
<div
|
||||
class="adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-header adf-datatable-cell-data"
|
||||
class="adf-datatable-cell--{{ col.type || 'text' }} {{
|
||||
col.cssClass
|
||||
}} adf-datatable-cell-header adf-datatable-cell-data"
|
||||
[attr.data-automation-id]="'auto_id_' + col.key"
|
||||
[ngClass]="{
|
||||
'adf-sortable': col.sortable,
|
||||
'adf-datatable__cursor--pointer': !isResizing,
|
||||
'adf-datatable__header--sorted-asc': isColumnSorted(col, 'asc'),
|
||||
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')}"
|
||||
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
|
||||
'adf-datatable__header--sorted-desc': isColumnSorted(col, 'desc')
|
||||
}"
|
||||
[ngStyle]="col.width && !lastColumn && { flex: getFlexValue(col) }"
|
||||
role="columnheader"
|
||||
[attr.aria-label]="col.srTitle ? (col.srTitle | translate) : (col.title | translate) + (col.subtitle ? ' ' + (col.subtitle | translate) : '')"
|
||||
[attr.aria-label]="
|
||||
col.srTitle
|
||||
? (col.srTitle | translate)
|
||||
: (col.title | translate) + (col.subtitle ? ' ' + (col.subtitle | translate) : '')
|
||||
"
|
||||
[attr.aria-sort]="col.sortable ? (getAriaSort(col) | translate) : null"
|
||||
cdkDrag
|
||||
cdkDragLockAxis="x"
|
||||
@@ -71,9 +77,10 @@
|
||||
[cdkDragDisabled]="!col.draggable"
|
||||
(mouseenter)="hoveredHeaderColumnIndex = columnIndex"
|
||||
(mouseleave)="hoveredHeaderColumnIndex = -1"
|
||||
adf-drop-zone dropTarget="header"
|
||||
[dropColumn]="col">
|
||||
|
||||
adf-drop-zone
|
||||
dropTarget="header"
|
||||
[dropColumn]="col"
|
||||
>
|
||||
<div
|
||||
adf-resizable
|
||||
#resizableElement="adf-resizable"
|
||||
@@ -86,9 +93,9 @@
|
||||
col.srTitle
|
||||
? (col.srTitle | translate)
|
||||
: ('ADF-DATATABLE.ACCESSIBILITY.SORT_DEFAULT' | translate) +
|
||||
' ' +
|
||||
(col.title | translate) +
|
||||
(col.subtitle ? ' ' + (col.subtitle | translate) : '')
|
||||
' ' +
|
||||
(col.title | translate) +
|
||||
(col.subtitle ? ' ' + (col.subtitle | translate) : '')
|
||||
"
|
||||
(click)="onColumnHeaderClick(col, $event)"
|
||||
(keyup.enter)="onColumnHeaderClick(col, $event)"
|
||||
@@ -99,27 +106,24 @@
|
||||
(resizeEnd)="onResizingEnd()"
|
||||
[attr.data-automation-id]="'auto_header_content_id_' + col.key"
|
||||
class="adf-datatable-cell-header-content"
|
||||
[ngClass]="{ 'adf-datatable-cell-header-content--hovered':
|
||||
hoveredHeaderColumnIndex === columnIndex &&
|
||||
!isDraggingHeaderColumn &&
|
||||
!isResizing && col.sortable}"
|
||||
[ngClass]="{
|
||||
'adf-datatable-cell-header-content--hovered':
|
||||
hoveredHeaderColumnIndex === columnIndex && !isDraggingHeaderColumn && !isResizing && col.sortable
|
||||
}"
|
||||
>
|
||||
@if (!col.header) {
|
||||
@if (col.title) {
|
||||
<span
|
||||
title="{{col.title | translate}}"
|
||||
class="adf-datatable-cell-value"
|
||||
>
|
||||
{{col.title | translate}}
|
||||
<span title="{{ col.title | translate }}" class="adf-datatable-cell-value">
|
||||
{{ col.title | translate }}
|
||||
</span>
|
||||
}
|
||||
|
||||
@if (col.subtitle) {
|
||||
<span
|
||||
title="{{col.subtitle | translate}}"
|
||||
title="{{ col.subtitle | translate }}"
|
||||
class="adf-datatable-cell-value adf-datatable-cell-header_subtitle"
|
||||
>
|
||||
({{col.subtitle | translate}})
|
||||
({{ col.subtitle | translate }})
|
||||
</span>
|
||||
}
|
||||
|
||||
@@ -136,29 +140,27 @@
|
||||
|
||||
@if (col.header) {
|
||||
<div class="adf-datatable-cell-value">
|
||||
<ng-template [ngTemplateOutlet]="col.header" [ngTemplateOutletContext]="{$implicit: col}" />
|
||||
<ng-template [ngTemplateOutlet]="col.header" [ngTemplateOutletContext]="{ $implicit: col }" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<span
|
||||
[class.adf-datatable__header--sorted-asc]="isColumnSorted(col, 'asc')"
|
||||
[class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')">
|
||||
[class.adf-datatable__header--sorted-desc]="isColumnSorted(col, 'desc')"
|
||||
>
|
||||
</span>
|
||||
|
||||
@if (allowFiltering) {
|
||||
<ng-template [ngTemplateOutlet]="headerFilterTemplate" [ngTemplateOutletContext]="{$implicit: col}" />
|
||||
<ng-template [ngTemplateOutlet]="headerFilterTemplate" [ngTemplateOutletContext]="{ $implicit: col }" />
|
||||
}
|
||||
|
||||
@if (col.draggable) {
|
||||
<span
|
||||
cdkDragHandle
|
||||
[ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }"
|
||||
>
|
||||
<span cdkDragHandle [ngClass]="{ 'adf-datatable-cell-header-drag-icon': !isResizing }">
|
||||
@if (hoveredHeaderColumnIndex === columnIndex && !isResizing) {
|
||||
<mat-icon
|
||||
svgIcon="adf:drag_indicator"
|
||||
class="adf-datatable-cell-header-drag-icon-visible"
|
||||
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-'+col.key"
|
||||
[attr.data-automation-id]="'adf-datatable-cell-header-drag-icon-' + col.key"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
}
|
||||
@@ -167,7 +169,11 @@
|
||||
</div>
|
||||
@if (isResizingEnabled && col.resizable && !lastColumn) {
|
||||
<div
|
||||
[ngClass]="hoveredHeaderColumnIndex === columnIndex && !isResizing || resizingColumnIndex === columnIndex ? 'adf-datatable__resize-handle-visible' : 'adf-datatable__resize-handle-hidden'"
|
||||
[ngClass]="
|
||||
(hoveredHeaderColumnIndex === columnIndex && !isResizing) || resizingColumnIndex === columnIndex
|
||||
? 'adf-datatable__resize-handle-visible'
|
||||
: 'adf-datatable__resize-handle-hidden'
|
||||
"
|
||||
adf-resize-handle
|
||||
tabindex="0"
|
||||
role="slider"
|
||||
@@ -178,17 +184,18 @@
|
||||
(click)="$event.stopPropagation()"
|
||||
(keydown)="$event.stopPropagation()"
|
||||
class="adf-datatable__resize-handle"
|
||||
[resizableContainer]="resizableElement">
|
||||
[resizableContainer]="resizableElement"
|
||||
>
|
||||
<div class="adf-datatable__resize-handle--divider"></div>
|
||||
</div>
|
||||
}
|
||||
<div class="adf-drop-header-cell-placeholder" *cdkDragPlaceholder></div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<!-- Header actions (right) -->
|
||||
@if ((actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions)) {
|
||||
@if ((actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions)) {
|
||||
<div
|
||||
class="adf-actions-column adf-datatable-actions-menu adf-datatable-cell-header adf-datatable__actions-cell"
|
||||
[class.adf-datatable-actions-menu-provided]="showProvidedActions"
|
||||
@@ -200,7 +207,8 @@
|
||||
mat-icon-button
|
||||
#mainMenuTrigger="matMenuTrigger"
|
||||
(click)="onMainMenuOpen()"
|
||||
[matMenuTriggerFor]="mainMenu">
|
||||
[matMenuTriggerFor]="mainMenu"
|
||||
>
|
||||
<mat-icon adf-icon="view_week_outline" />
|
||||
</button>
|
||||
<mat-menu #mainMenu (closed)="onMainMenuClosed()">
|
||||
@@ -209,13 +217,14 @@
|
||||
[ngTemplateOutlet]="mainActionTemplate"
|
||||
[ngTemplateOutletContext]="{
|
||||
$implicit: mainMenuTrigger
|
||||
}" />
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</mat-menu>
|
||||
<span class="adf-sr-only">{{ 'ADF-DATATABLE.ACCESSIBILITY.ACTIONS' | translate }}</span>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</adf-datatable-row>
|
||||
</div>
|
||||
}
|
||||
@@ -223,12 +232,18 @@
|
||||
@if (!loading) {
|
||||
<div
|
||||
class="adf-datatable-body"
|
||||
[ngClass]="{ 'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing), 'adf-datatable-body__draggable': enableDragRows && !isDraggingRow, 'adf-datatable-body__dragging': isDraggingRow }"
|
||||
[ngClass]="{
|
||||
'adf-blur-datatable-body': blurOnResize && (isDraggingHeaderColumn || isResizing),
|
||||
'adf-datatable-body__draggable': enableDragRows && !isDraggingRow,
|
||||
'adf-datatable-body__dragging': isDraggingRow
|
||||
}"
|
||||
cdkDropList
|
||||
[cdkDropListDisabled]="!enableDragRows"
|
||||
role="rowgroup">
|
||||
role="rowgroup"
|
||||
>
|
||||
@if (!noPermission) {
|
||||
<adf-datatable-row *ngFor="let row of data.getRows(); let idx = index"
|
||||
<adf-datatable-row
|
||||
*ngFor="let row of data.getRows(); let idx = index"
|
||||
cdkDrag
|
||||
[cdkDragDisabled]="!enableDragRows"
|
||||
(cdkDragDropped)="onDragDrop($event)"
|
||||
@@ -255,29 +270,33 @@
|
||||
>
|
||||
<!-- Drag button -->
|
||||
@if (enableDragRows) {
|
||||
<div
|
||||
role="gridcell"
|
||||
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-hover-only">
|
||||
<div role="gridcell" class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-hover-only">
|
||||
<mat-icon adf-icon="drag_indicator" aria-hidden="true" />
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Actions (left) -->
|
||||
@if (actions && actionsPosition === 'left') {
|
||||
@if (actions && actionsPosition === 'left') {
|
||||
<div role="gridcell" class="adf-datatable-cell">
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
|
||||
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
|
||||
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
|
||||
[attr.id]="'action_menu_left_' + idx"
|
||||
[attr.data-automation-id]="'action_menu_' + idx">
|
||||
<button
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="menu"
|
||||
#actionsMenuTrigger="matMenuTrigger"
|
||||
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
|
||||
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
|
||||
[attr.id]="'action_menu_left_' + idx"
|
||||
[attr.data-automation-id]="'action_menu_' + idx"
|
||||
>
|
||||
<mat-icon adf-icon="more_vert" />
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
@for (action of getRowActions(row); track action.title) {
|
||||
<button mat-menu-item
|
||||
[attr.data-automation-id]="action.title"
|
||||
[disabled]="action.disabled"
|
||||
(click)="onExecuteRowAction(row, action)">
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.data-automation-id]="action.title"
|
||||
[disabled]="action.disabled"
|
||||
(click)="onExecuteRowAction(row, action)"
|
||||
>
|
||||
@if (action.icon) {
|
||||
<mat-icon [adf-icon]="action.icon" />
|
||||
}
|
||||
@@ -286,9 +305,9 @@
|
||||
}
|
||||
</mat-menu>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@if (multiselect) {
|
||||
@if (multiselect) {
|
||||
<label
|
||||
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
|
||||
(click)="onCheckboxLabelClick(row, $event)"
|
||||
@@ -316,24 +335,28 @@
|
||||
<span class="adf-sr-only" aria-live="off">
|
||||
{{ row.isSelected ? ('ADF-DATATABLE.ACCESSIBILITY.SELECTED' | translate) : '' }}
|
||||
</span>
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@for (col of getVisibleColumns(); track col.key; let lastColumn = $last;) {
|
||||
@for (col of getVisibleColumns(); track col.key; let lastColumn = $last) {
|
||||
<div
|
||||
role="gridcell"
|
||||
class="adf-datatable-cell adf-datatable-cell--{{col.type || 'text'}} {{col.cssClass}} adf-datatable-cell-data adf-datatable-cell--{{getAutomationValue(row)}}"
|
||||
class="adf-datatable-cell adf-datatable-cell--{{ col.type || 'text' }} {{
|
||||
col.cssClass
|
||||
}} adf-datatable-cell-data adf-datatable-cell--{{ getAutomationValue(row) }}"
|
||||
[attr.title]="col.title | translate"
|
||||
[attr.data-automation-id]="getAutomationValue(row)"
|
||||
[attr.aria-label]="col.title ? (col.title | translate) : null"
|
||||
[attr.aria-hidden]='isRepresentationContent(col) ? "true" : null'
|
||||
[attr.aria-hidden]="isRepresentationContent(col) ? 'true' : null"
|
||||
(click)="onRowClick(row, $event)"
|
||||
[attr.tabindex]="null"
|
||||
(keydown.enter)="onEnterKeyPressed(row, $any($event))"
|
||||
[adf-context-menu]="getContextMenuActions(row, col)"
|
||||
[adf-context-menu-enabled]="contextMenu"
|
||||
adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row"
|
||||
[ngStyle]="(col.width) && !lastColumn && {'flex': getFlexValue(col)}"
|
||||
adf-drop-zone
|
||||
dropTarget="cell"
|
||||
[dropColumn]="col"
|
||||
[dropRow]="row"
|
||||
[ngStyle]="col.width && !lastColumn && { flex: getFlexValue(col) }"
|
||||
>
|
||||
@if (!col.template) {
|
||||
<div class="adf-datatable-cell-container">
|
||||
@@ -342,7 +365,7 @@
|
||||
<div class="adf-cell-value">
|
||||
@if (isIconValue(row, col)) {
|
||||
<mat-icon
|
||||
[attr.aria-label]="col.srTitle? (col.srTitle | translate) : null"
|
||||
[attr.aria-label]="col.srTitle ? (col.srTitle | translate) : null"
|
||||
[attr.aria-hidden]="!asIconValue(row, col)"
|
||||
[adf-icon]="asIconValue(row, col)"
|
||||
/>
|
||||
@@ -350,19 +373,35 @@
|
||||
@if (row.isSelected && !multiselect) {
|
||||
<mat-icon class="adf-datatable-selected" svgIcon="selected" />
|
||||
} @else {
|
||||
<img class="adf-datatable-center-img-ie"
|
||||
[attr.aria-label]="(data.getValue(row, col) | fileType) === 'disable' ?
|
||||
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
|
||||
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
|
||||
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
|
||||
}"
|
||||
[attr.alt]="(data.getValue(row, col) | fileType) === 'disable' ?
|
||||
('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate) :
|
||||
'ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT' | translate:{
|
||||
type: 'ADF-DATATABLE.FILE_TYPE.' + (data.getValue(row, col) | fileType | uppercase) | translate
|
||||
}"
|
||||
<img
|
||||
class="adf-datatable-center-img-ie"
|
||||
[attr.aria-label]="
|
||||
(data.getValue(row, col) | fileType) === 'disable'
|
||||
? ('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate)
|
||||
: ('ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT'
|
||||
| translate
|
||||
: {
|
||||
type:
|
||||
'ADF-DATATABLE.FILE_TYPE.' +
|
||||
(data.getValue(row, col) | fileType | uppercase)
|
||||
| translate
|
||||
})
|
||||
"
|
||||
[attr.alt]="
|
||||
(data.getValue(row, col) | fileType) === 'disable'
|
||||
? ('ADF-DATATABLE.ACCESSIBILITY.ICON_DISABLED' | translate)
|
||||
: ('ADF-DATATABLE.ACCESSIBILITY.ICON_TEXT'
|
||||
| translate
|
||||
: {
|
||||
type:
|
||||
'ADF-DATATABLE.FILE_TYPE.' +
|
||||
(data.getValue(row, col) | fileType | uppercase)
|
||||
| translate
|
||||
})
|
||||
"
|
||||
src="{{ data.getValue(row, col) }}"
|
||||
(error)="onImageLoadingError($event, row)">
|
||||
(error)="onImageLoadingError($event, row)"
|
||||
/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@@ -381,59 +420,74 @@
|
||||
@case ('date') {
|
||||
<div
|
||||
class="adf-cell-value adf-cell-date"
|
||||
[attr.data-automation-id]="'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium') ">
|
||||
<adf-date-cell class="adf-datatable-center-date-column-ie"
|
||||
[attr.data-automation-id]="
|
||||
'date_' + (data.getValue(row, col, resolverFn) | adfLocalizedDate: 'medium')
|
||||
"
|
||||
>
|
||||
<adf-date-cell
|
||||
class="adf-datatable-center-date-column-ie"
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)"
|
||||
[dateConfig]="col.dateConfig" />
|
||||
[dateConfig]="col.dateConfig"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('location') {
|
||||
<div class="adf-cell-value"
|
||||
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)">
|
||||
<div
|
||||
class="adf-cell-value"
|
||||
[attr.data-automation-id]="'location' + data.getValue(row, col, resolverFn)"
|
||||
>
|
||||
<adf-location-cell
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)" />
|
||||
[tooltip]="getCellTooltip(row, col)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('fileSize') {
|
||||
<div class="adf-cell-value"
|
||||
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)">
|
||||
<adf-filesize-cell class="adf-datatable-center-size-column-ie"
|
||||
<div
|
||||
class="adf-cell-value"
|
||||
[attr.data-automation-id]="'fileSize_' + data.getValue(row, col, resolverFn)"
|
||||
>
|
||||
<adf-filesize-cell
|
||||
class="adf-datatable-center-size-column-ie"
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)" />
|
||||
[tooltip]="getCellTooltip(row, col)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('text') {
|
||||
<div class="adf-cell-value"
|
||||
[attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
|
||||
<div class="adf-cell-value" [attr.data-automation-id]="'text_' + data.getValue(row, col, resolverFn)">
|
||||
<adf-datatable-cell
|
||||
[copyContent]="col.copyContent"
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)" />
|
||||
[tooltip]="getCellTooltip(row, col)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('boolean') {
|
||||
<div class="adf-cell-value"
|
||||
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)">
|
||||
<div
|
||||
class="adf-cell-value"
|
||||
[attr.data-automation-id]="'boolean_' + data.getValue(row, col, resolverFn)"
|
||||
>
|
||||
<adf-boolean-cell
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[row]="row"
|
||||
[resolverFn]="resolverFn"
|
||||
[tooltip]="getCellTooltip(row, col)" />
|
||||
[tooltip]="getCellTooltip(row, col)"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('json') {
|
||||
@@ -443,31 +497,36 @@
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[resolverFn]="resolverFn"
|
||||
[row]="row" />
|
||||
[row]="row"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('amount') {
|
||||
<div
|
||||
class="adf-cell-value"
|
||||
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)">
|
||||
[attr.data-automation-id]="'amount_' + data.getValue(row, col, resolverFn)"
|
||||
>
|
||||
<adf-amount-cell
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[resolverFn]="resolverFn"
|
||||
[row]="row"
|
||||
[currencyConfig]="col.currencyConfig" />
|
||||
[currencyConfig]="col.currencyConfig"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@case ('number') {
|
||||
<div
|
||||
class="adf-cell-value"
|
||||
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)">
|
||||
[attr.data-automation-id]="'number_' + data.getValue(row, col, resolverFn)"
|
||||
>
|
||||
<adf-number-cell
|
||||
[data]="data"
|
||||
[column]="col"
|
||||
[resolverFn]="resolverFn"
|
||||
[row]="row"
|
||||
[decimalConfig]="col.decimalConfig" />
|
||||
[decimalConfig]="col.decimalConfig"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
@default {
|
||||
@@ -482,7 +541,11 @@
|
||||
<div class="adf-cell-value">
|
||||
<ng-container
|
||||
[ngTemplateOutlet]="col.template"
|
||||
[ngTemplateOutletContext]="{ $implicit: { data: data, row: row, col: col }, value: data.getValue(row, col, resolverFn) }" />
|
||||
[ngTemplateOutletContext]="{
|
||||
$implicit: { data: data, row: row, col: col },
|
||||
value: data.getValue(row, col, resolverFn)
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -490,28 +553,34 @@
|
||||
}
|
||||
|
||||
<!-- Row actions (right) -->
|
||||
@if (!showProvidedActions && ((actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions))) {
|
||||
@if (!showProvidedActions && ((actions && actionsPosition === 'right') || (mainActionTemplate && showMainDatatableActions))) {
|
||||
<div
|
||||
role="gridcell"
|
||||
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu">
|
||||
|
||||
class="adf-datatable-cell adf-datatable__actions-cell adf-datatable-center-actions-column-ie adf-datatable-actions-menu"
|
||||
>
|
||||
@if (actions && actionsPosition === 'right') {
|
||||
<button mat-icon-button [matMenuTriggerFor]="menu" #actionsMenuTrigger="matMenuTrigger"
|
||||
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
|
||||
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
|
||||
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
|
||||
[attr.id]="'action_menu_right_' + idx"
|
||||
[attr.data-automation-id]="'action_menu_' + idx"
|
||||
(keydown.enter)="actionsMenuTrigger.openMenu()">
|
||||
<button
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="menu"
|
||||
#actionsMenuTrigger="matMenuTrigger"
|
||||
[ngClass]="getHideActionsWithoutHoverClass(actionsMenuTrigger)"
|
||||
[attr.aria-label]="'ADF-DATATABLE.ACCESSIBILITY.ROW_OPTION_BUTTON' | translate"
|
||||
[title]="'ADF-DATATABLE.CONTENT-ACTIONS.TOOLTIP' | translate"
|
||||
[attr.id]="'action_menu_right_' + idx"
|
||||
[attr.data-automation-id]="'action_menu_' + idx"
|
||||
(keydown.enter)="actionsMenuTrigger.openMenu()"
|
||||
>
|
||||
<mat-icon adf-icon="more_vert" />
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
@for (action of getRowActions(row); track action.title) {
|
||||
<button mat-menu-item
|
||||
[attr.data-automation-id]="action.title"
|
||||
[attr.aria-label]="action.title | translate"
|
||||
[disabled]="action.disabled"
|
||||
(click)="onExecuteRowAction(row, action)">
|
||||
<button
|
||||
mat-menu-item
|
||||
[attr.data-automation-id]="action.title"
|
||||
[attr.aria-label]="action.title | translate"
|
||||
[disabled]="action.disabled"
|
||||
(click)="onExecuteRowAction(row, action)"
|
||||
>
|
||||
@if (action.icon) {
|
||||
<mat-icon [adf-icon]="action.icon" />
|
||||
}
|
||||
@@ -521,29 +590,23 @@
|
||||
</mat-menu>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</adf-datatable-row>
|
||||
@if (isEmpty()) {
|
||||
<div role="row" class="adf-datatable-row">
|
||||
<div class="adf-no-content-container adf-datatable-cell" role="gridcell">
|
||||
@if (noContentTemplate) {
|
||||
<ng-template
|
||||
ngFor [ngForOf]="[data]"
|
||||
[ngForTemplate]="noContentTemplate" />
|
||||
<ng-template ngFor [ngForOf]="[data]" [ngForTemplate]="noContentTemplate" />
|
||||
}
|
||||
<ng-content select="adf-empty-list" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
} @else {
|
||||
<div
|
||||
role="row"
|
||||
class="adf-datatable-row adf-no-permission__row">
|
||||
<div role="row" class="adf-datatable-row adf-no-permission__row">
|
||||
<div class="adf-no-permission__cell adf-no-content-container adf-datatable-cell">
|
||||
@if (noPermissionTemplate) {
|
||||
<ng-template
|
||||
ngFor [ngForOf]="[data]"
|
||||
[ngForTemplate]="noPermissionTemplate" />
|
||||
<ng-template ngFor [ngForOf]="[data]" [ngForTemplate]="noPermissionTemplate" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -553,9 +616,7 @@
|
||||
<div class="adf-datatable-row adf-datatable-data-loading">
|
||||
<div class="adf-no-content-container adf-datatable-cell">
|
||||
@if (loadingTemplate) {
|
||||
<ng-template
|
||||
ngFor [ngForOf]="[data]"
|
||||
[ngForTemplate]="loadingTemplate" />
|
||||
<ng-template ngFor [ngForOf]="[data]" [ngForTemplate]="loadingTemplate" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -59,7 +59,7 @@ import { ObjectDataTableAdapter } from '../../data/object-datatable-adapter';
|
||||
import { DataCellEvent } from '../data-cell.event';
|
||||
import { DataRowActionEvent } from '../data-row-action.event';
|
||||
import { buffer, debounceTime, filter, map, share } from 'rxjs/operators';
|
||||
import { CdkDrag, CdkDragDrop, CdkDragHandle, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { CdkDrag, CdkDragDrop, CdkDragHandle, CdkDragPlaceholder, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { MatIconRegistry } from '@angular/material/icon';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { ResizeEvent } from '../../directives/resizable/types';
|
||||
@@ -122,7 +122,8 @@ export type ShowHeaderMode = (typeof ShowHeaderMode)[keyof typeof ShowHeaderMode
|
||||
JsonCellComponent,
|
||||
AmountCellComponent,
|
||||
NumberCellComponent,
|
||||
MatTooltipModule
|
||||
MatTooltipModule,
|
||||
CdkDragPlaceholder
|
||||
],
|
||||
templateUrl: './datatable.component.html',
|
||||
styleUrls: ['./datatable.component.scss'],
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { EditJsonDialogComponent } from './edit-json.dialog';
|
||||
|
||||
/* @deprecated Use EditJsonDialogComponent directly */
|
||||
@NgModule({
|
||||
declarations: [],
|
||||
imports: [EditJsonDialogComponent],
|
||||
exports: [EditJsonDialogComponent]
|
||||
})
|
||||
export class EditJsonDialogModule {}
|
||||
@@ -16,13 +16,10 @@
|
||||
*/
|
||||
|
||||
export * from './edit-json/edit-json.dialog';
|
||||
export * from './edit-json/edit-json.dialog.module';
|
||||
|
||||
export * from './unsaved-changes-dialog/unsaved-changes-dialog.component';
|
||||
export * from './unsaved-changes-dialog/unsaved-changes-dialog.module';
|
||||
export * from './unsaved-changes-dialog/unsaved-changes.guard';
|
||||
|
||||
export * from './confirm-dialog/confirm.dialog';
|
||||
export * from './confirm-dialog/confirm.dialog.module';
|
||||
|
||||
export * from './dialog';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UnsavedChangesDialogComponent } from './unsaved-changes-dialog.component';
|
||||
|
||||
/** @deprecated import `UnsavedChangesDialogComponent` instead */
|
||||
@NgModule({
|
||||
imports: [UnsavedChangesDialogComponent],
|
||||
exports: [UnsavedChangesDialogComponent]
|
||||
})
|
||||
export class UnsavedChangesDialogModule {}
|
||||
@@ -1,4 +1,4 @@
|
||||
<div @tooltip class="adf-tooltip-card" [style.width.px]="width">
|
||||
<div class="adf-tooltip-card" [style.width.px]="width">
|
||||
<img *ngIf="image " [src]="image" [width]="width" alt="{{text}}">
|
||||
<hr *ngIf="image" />
|
||||
<p *ngIf="text">{{text}}</p>
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@keyframes tooltip-fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
animation: tooltip-fade-in 200ms ease-out;
|
||||
}
|
||||
|
||||
div.adf-tooltip-card {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
import { Component, Input, SecurityContext, inject } from '@angular/core';
|
||||
import { animate, style, transition, trigger } from '@angular/animations';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
@@ -24,13 +23,7 @@ import { CommonModule } from '@angular/common';
|
||||
selector: 'adf-tooltip-card-component',
|
||||
imports: [CommonModule],
|
||||
templateUrl: './tooltip-card.component.html',
|
||||
styleUrls: ['./tooltip-card.component.scss'],
|
||||
animations: [
|
||||
trigger('tooltip', [
|
||||
transition(':enter', [style({ opacity: 0 }), animate(200, style({ opacity: 1 }))]),
|
||||
transition(':leave', [animate(200, style({ opacity: 0 }))])
|
||||
])
|
||||
]
|
||||
styleUrls: ['./tooltip-card.component.scss']
|
||||
})
|
||||
export class TooltipCardComponent {
|
||||
private readonly sanitizer = inject(DomSanitizer);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
<div class="adf-error-container adf-error-widget-container">
|
||||
<div *ngIf="error?.isActive()" [@transitionMessages]="subscriptAnimationState" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ error.message | translate:translateParameters }}</div>
|
||||
</div>
|
||||
<div *ngIf="required" [@transitionMessages]="subscriptAnimationState" class="adf-error">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ required }}</div>
|
||||
</div>
|
||||
@if (error?.isActive()) {
|
||||
<div class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ error.message | translate: translateParameters }}</div>
|
||||
</div>
|
||||
}
|
||||
@if (required) {
|
||||
<div class="adf-error adf-error-animate">
|
||||
<mat-icon class="adf-error-icon" adf-icon="error_outline" />
|
||||
<div class="adf-error-text">{{ required }}</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
@keyframes adf-error-slide-in-down {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.adf-error {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -6,6 +18,10 @@
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&-animate {
|
||||
animation: adf-error-slide-in-down 300ms cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
}
|
||||
|
||||
&-container {
|
||||
padding-top: 0;
|
||||
color: var(--mat-sys-error);
|
||||
|
||||
@@ -50,12 +50,6 @@ describe('ErrorWidgetComponent', () => {
|
||||
expect(errorIcon).toEqual('error_outline');
|
||||
});
|
||||
|
||||
it('should set subscriptAnimationState value', () => {
|
||||
widget.ngOnChanges(errorChanges);
|
||||
|
||||
expect(widget.subscriptAnimationState).toEqual('enter');
|
||||
});
|
||||
|
||||
it('should check proper error message', async () => {
|
||||
widget.ngOnChanges(errorChanges);
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
|
||||
/* eslint-disable @angular-eslint/component-selector */
|
||||
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
import { NgIf } from '@angular/common';
|
||||
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { ErrorMessageModel } from '../core';
|
||||
@@ -29,18 +27,6 @@ import { IconModule } from '../../../../icon/icon.module';
|
||||
selector: 'error-widget',
|
||||
templateUrl: './error.component.html',
|
||||
styleUrls: ['./error.component.scss'],
|
||||
animations: [
|
||||
trigger('transitionMessages', [
|
||||
state('enter', style({ opacity: 1, transform: 'translateY(0%)' })),
|
||||
transition('void => enter', [
|
||||
style({
|
||||
opacity: 0,
|
||||
transform: 'translateY(-100%)'
|
||||
}),
|
||||
animate('300ms cubic-bezier(0.55, 0, 0.55, 0.2)')
|
||||
])
|
||||
])
|
||||
],
|
||||
host: {
|
||||
'(click)': 'event($event)',
|
||||
'(blur)': 'event($event)',
|
||||
@@ -52,7 +38,7 @@ import { IconModule } from '../../../../icon/icon.module';
|
||||
'(invalid)': 'event($event)',
|
||||
'(select)': 'event($event)'
|
||||
},
|
||||
imports: [NgIf, IconModule, TranslatePipe],
|
||||
imports: [IconModule, TranslatePipe],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
|
||||
@@ -63,18 +49,15 @@ export class ErrorWidgetComponent extends WidgetComponent implements OnChanges {
|
||||
required: string;
|
||||
|
||||
translateParameters: any = null;
|
||||
subscriptAnimationState: string = '';
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes['required']) {
|
||||
this.required = changes.required.currentValue;
|
||||
this.subscriptAnimationState = 'enter';
|
||||
}
|
||||
if (changes['error']?.currentValue) {
|
||||
if (changes.error.currentValue.isActive()) {
|
||||
this.error = changes.error.currentValue;
|
||||
this.translateParameters = this.error.getAttributesAsJsonObj();
|
||||
this.subscriptAnimationState = 'enter';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
<mat-sidenav-container class="adf-layout-container" autosize>
|
||||
<mat-sidenav
|
||||
class="adf-layout-container-sidenav"
|
||||
[ngClass]="sidenavAnimationState?.value"
|
||||
[position]="position"
|
||||
[disableClose]="!isMobileScreenSize"
|
||||
[@sidenavAnimation]="sidenavAnimationState"
|
||||
[opened]="!isMobileScreenSize && !hideSidenav"
|
||||
[mode]="isMobileScreenSize ? 'over' : 'side'">
|
||||
[mode]="isMobileScreenSize ? 'over' : 'side'"
|
||||
[style.width.px]="sidenavAnimationState?.params?.width">
|
||||
<ng-content sidenav select="[app-layout-navigation]" />
|
||||
</mat-sidenav>
|
||||
|
||||
<div>
|
||||
<div class="adf-container-full-width" [@contentAnimationLeft]="getContentAnimationState()">
|
||||
<div class="adf-container-full-width" [ngClass]="contentAnimationState?.value" [style.margin-left.px]="contentAnimationState?.params?.['margin-left']" [style.margin-right.px]="contentAnimationState?.params?.['margin-right']">
|
||||
<ng-content select="[app-layout-content]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,12 +11,16 @@ adf-layout-container {
|
||||
border-right: 1px solid var(--mat-sys-outline-variant);
|
||||
background: var(--mat-sys-surface);
|
||||
color: var(--mat-sys-on-surface);
|
||||
transition: width 400ms cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.adf-container-full-width {
|
||||
width: inherit;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
margin-left 400ms cubic-bezier(0.25, 0.8, 0.25, 1),
|
||||
margin-right 400ms cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
/* query for Microsoft IE 11 */
|
||||
|
||||
@@ -19,40 +19,13 @@ import { Component, Input, ViewChild, OnInit, OnDestroy, ViewEncapsulation, OnCh
|
||||
import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { Direction } from '@angular/cdk/bidi';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-layout-container',
|
||||
imports: [CommonModule, MatSidenavModule],
|
||||
templateUrl: './layout-container.component.html',
|
||||
styleUrls: ['./layout-container.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
animations: [
|
||||
trigger('sidenavAnimation', [
|
||||
state('expanded', style({ width: '{{ width }}px' }), { params: { width: 0 } }),
|
||||
state('compact', style({ width: '{{ width }}px' }), { params: { width: 0 } }),
|
||||
transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)'))
|
||||
]),
|
||||
trigger('contentAnimationLeft', [
|
||||
state(
|
||||
'expanded',
|
||||
style({
|
||||
'margin-left': '{{ margin-left }}px',
|
||||
'margin-right': '{{ margin-right }}px'
|
||||
}),
|
||||
{ params: { 'margin-left': 0, 'margin-right': 0 } }
|
||||
),
|
||||
state(
|
||||
'compact',
|
||||
style({
|
||||
'margin-left': '{{ margin-left }}px',
|
||||
'margin-right': '{{ margin-right }}px'
|
||||
}),
|
||||
{ params: { 'margin-left': 0, 'margin-right': 0 } }
|
||||
),
|
||||
transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
|
||||
])
|
||||
]
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges {
|
||||
@Input() sidenavMin: number;
|
||||
@@ -118,10 +91,6 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges {
|
||||
return !!this.mediaQueryList?.matches;
|
||||
}
|
||||
|
||||
getContentAnimationState(): any {
|
||||
return this.contentAnimationState;
|
||||
}
|
||||
|
||||
private get toggledSidenavAnimation(): any {
|
||||
return this.sidenavAnimationState === this.SIDENAV_STATES.EXPANDED ? this.SIDENAV_STATES.COMPACT : this.SIDENAV_STATES.EXPANDED;
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { trigger, transition, animate, style, state, AnimationTriggerMetadata } from '@angular/animations';
|
||||
|
||||
export const searchAnimation: AnimationTriggerMetadata = trigger('transitionMessages', [
|
||||
state(
|
||||
'active',
|
||||
style({
|
||||
'margin-left': '{{ margin-left }}px',
|
||||
'margin-right': '{{ margin-right }}px',
|
||||
transform: '{{ transform }}'
|
||||
}),
|
||||
{ params: { 'margin-left': 0, 'margin-right': 0, transform: 'translateX(0%)' } }
|
||||
),
|
||||
state(
|
||||
'inactive',
|
||||
style({
|
||||
'margin-left': '{{ margin-left }}px',
|
||||
'margin-right': '{{ margin-right }}px',
|
||||
transform: '{{ transform }}'
|
||||
}),
|
||||
{ params: { 'margin-left': 0, 'margin-right': 0, transform: 'translateX(0%)' } }
|
||||
),
|
||||
state('no-animation', style({ transform: 'translateX(0%)', width: '100%' })),
|
||||
transition('active <=> inactive', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
|
||||
]);
|
||||
@@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './animations';
|
||||
export * from './search-text-input.component';
|
||||
export * from './search-trigger.directive';
|
||||
export * from './search-text-input.module';
|
||||
|
||||
@@ -1,44 +1,52 @@
|
||||
<div class="adf-search-container" [attr.state]="subscriptAnimationState.value">
|
||||
<div class="adf-search-container-transition"
|
||||
[@transitionMessages]="subscriptAnimationState"
|
||||
(@transitionMessages.done)="applySearchFocus($event)">
|
||||
<button mat-icon-button
|
||||
*ngIf="expandable && !isSearchBarActive()"
|
||||
<div class="adf-search-container-transition" [class.adf-search-active]="isSearchBarActive()" [ngStyle]="subscriptAnimationState.params">
|
||||
@if (expandable && !isSearchBarActive()) {
|
||||
<button
|
||||
mat-icon-button
|
||||
id="adf-search-button"
|
||||
class="adf-search-button"
|
||||
[ngClass]="{'adf-search-button-inactive': subscriptAnimationState.value === 'inactive'}"
|
||||
[ngClass]="{ 'adf-search-button-inactive': subscriptAnimationState.value === 'inactive' }"
|
||||
[title]="'CORE.SEARCH.BUTTON.TOOLTIP' | translate"
|
||||
(click)="toggleSearchBar()"
|
||||
(keyup.enter)="toggleSearchBar()">
|
||||
<mat-icon [attr.aria-label]="'CORE.SEARCH.BUTTON.ARIA-LABEL' | translate" adf-icon="search" />
|
||||
</button>
|
||||
(keyup.enter)="toggleSearchBar()"
|
||||
>
|
||||
<mat-icon [attr.aria-label]="'CORE.SEARCH.BUTTON.ARIA-LABEL' | translate" adf-icon="search" />
|
||||
</button>
|
||||
}
|
||||
<mat-form-field class="adf-input-form-field-divider" [hintLabel]="hintLabel">
|
||||
<mat-label *ngIf='label'>{{label}}</mat-label>
|
||||
<input matInput
|
||||
#searchInput
|
||||
[attr.aria-label]="'CORE.SEARCH.INPUT.ARIA-LABEL' | translate"
|
||||
[attr.type]="inputType"
|
||||
[autocomplete]="getAutoComplete()"
|
||||
id="adf-control-input"
|
||||
[(ngModel)]="searchTerm"
|
||||
[placeholder]="placeholder"
|
||||
(focus)="activateToolbar()"
|
||||
(blur)="onBlur($event)"
|
||||
(keyup.escape)="toggleSearchBar()"
|
||||
(keyup.arrowdown)="selectFirstResult($event)"
|
||||
(ngModelChange)="inputChange($event)"
|
||||
[searchAutocomplete]="searchAutocomplete ? searchAutocomplete : null"
|
||||
(keyup.enter)="searchSubmit($event)">
|
||||
<button mat-icon-button
|
||||
*ngIf="canShowClearSearch()"
|
||||
@if (label) {
|
||||
<mat-label>{{ label }}</mat-label>
|
||||
}
|
||||
<input
|
||||
matInput
|
||||
#searchInput
|
||||
[attr.aria-label]="'CORE.SEARCH.INPUT.ARIA-LABEL' | translate"
|
||||
[attr.type]="inputType"
|
||||
[autocomplete]="getAutoComplete()"
|
||||
id="adf-control-input"
|
||||
[(ngModel)]="searchTerm"
|
||||
[placeholder]="placeholder"
|
||||
(focus)="activateToolbar()"
|
||||
(blur)="onBlur($event)"
|
||||
(keyup.escape)="toggleSearchBar()"
|
||||
(keyup.arrowdown)="selectFirstResult($event)"
|
||||
(ngModelChange)="inputChange($event)"
|
||||
[searchAutocomplete]="searchAutocomplete ? searchAutocomplete : null"
|
||||
(keyup.enter)="searchSubmit($event)"
|
||||
/>
|
||||
@if (canShowClearSearch()) {
|
||||
<button
|
||||
mat-icon-button
|
||||
matSuffix
|
||||
data-automation-id="adf-clear-search-button"
|
||||
class="adf-clear-search-button"
|
||||
[title]="'CORE.SEARCH.FILTER.BUTTONS.CLOSE' | translate"
|
||||
(click)="resetSearch()"
|
||||
(keyup.enter)="resetSearch()">
|
||||
(keyup.enter)="resetSearch()"
|
||||
>
|
||||
<mat-icon adf-icon="close" />
|
||||
</button>
|
||||
}
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
.adf-search-container-transition {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition:
|
||||
transform 400ms cubic-bezier(0.25, 0.8, 0.25, 1),
|
||||
margin-left 400ms cubic-bezier(0.25, 0.8, 0.25, 1),
|
||||
margin-right 400ms cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
}
|
||||
|
||||
.adf {
|
||||
|
||||
@@ -164,7 +164,7 @@ describe('SearchTextInputComponent', () => {
|
||||
function testMarginValue(isLtr: boolean): void {
|
||||
userPreferencesService.setWithoutStore('textOrientation', isLtr ? 'ltr' : 'rtl');
|
||||
clickSearchButton();
|
||||
const expectedResult = isLtr ? { 'margin-left': 0 } : { 'margin-right': 0 };
|
||||
const expectedResult = isLtr ? { 'margin-left': '0px' } : { 'margin-right': '0px' };
|
||||
expect(component.subscriptAnimationState.params).toEqual(expectedResult);
|
||||
discardPeriodicTasks();
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { Direction } from '@angular/cdk/bidi';
|
||||
import { NgClass, NgIf } from '@angular/common';
|
||||
import { NgClass, NgStyle } from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
DestroyRef,
|
||||
@@ -24,8 +24,8 @@ import {
|
||||
EventEmitter,
|
||||
inject,
|
||||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
Output,
|
||||
ViewChild,
|
||||
ViewEncapsulation
|
||||
@@ -35,10 +35,9 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { Observable, Subject, Subscription } from 'rxjs';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { debounceTime, filter } from 'rxjs/operators';
|
||||
import { UserPreferencesService } from '../common';
|
||||
import { searchAnimation } from './animations';
|
||||
import { SearchAnimationDirection, SearchAnimationState, SearchTextStateEnum } from './models/search-text-input.model';
|
||||
import { SearchTriggerDirective } from './search-trigger.directive';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
@@ -48,9 +47,8 @@ import { IconModule } from '../icon/icon.module';
|
||||
selector: 'adf-search-text-input',
|
||||
templateUrl: './search-text-input.component.html',
|
||||
styleUrls: ['./search-text-input.component.scss'],
|
||||
animations: [searchAnimation],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [MatButtonModule, IconModule, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, SearchTriggerDirective, NgIf, NgClass],
|
||||
imports: [MatButtonModule, IconModule, TranslatePipe, MatFormFieldModule, MatInputModule, FormsModule, SearchTriggerDirective, NgClass, NgStyle],
|
||||
host: {
|
||||
class: 'adf-search-text-input'
|
||||
}
|
||||
@@ -91,7 +89,7 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
|
||||
/** Listener for results-list events (focus, blur and focusout). */
|
||||
@Input()
|
||||
focusListener: Observable<FocusEvent>;
|
||||
focusListener: Observable<FocusEvent> | null = null;
|
||||
|
||||
/** Collapse search bar on submit. */
|
||||
@Input()
|
||||
@@ -147,44 +145,44 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
|
||||
/** Emitted when the search visibility changes. True when the search is active, false when it is inactive */
|
||||
@Output()
|
||||
searchVisibility: EventEmitter<boolean> = new EventEmitter<boolean>();
|
||||
searchVisibility = new EventEmitter<boolean>();
|
||||
|
||||
@ViewChild('searchInput', { static: true })
|
||||
searchInput: ElementRef;
|
||||
|
||||
subscriptAnimationState: any;
|
||||
searchInput!: ElementRef;
|
||||
|
||||
animationStates: SearchAnimationDirection = {
|
||||
ltr: {
|
||||
active: { value: 'active', params: { 'margin-left': 13 } },
|
||||
active: { value: 'active', params: { 'margin-left': '13px' } },
|
||||
inactive: { value: 'inactive', params: { transform: 'translateX(100%)' } }
|
||||
},
|
||||
rtl: {
|
||||
active: { value: 'active', params: { 'margin-right': 13 } },
|
||||
active: { value: 'active', params: { 'margin-right': '13px' } },
|
||||
inactive: { value: 'inactive', params: { transform: 'translateX(-100%)' } }
|
||||
}
|
||||
};
|
||||
|
||||
private dir = 'ltr';
|
||||
private toggleSearch = new Subject<any>();
|
||||
private focusSubscription: Subscription;
|
||||
subscriptAnimationState: SearchAnimationState = this.animationStates.ltr.inactive;
|
||||
|
||||
private dir: keyof SearchAnimationDirection = 'ltr';
|
||||
private readonly toggleSearch = new Subject<any>();
|
||||
private readonly valueChange = new Subject<string>();
|
||||
private readonly toggleSubscription: Subscription;
|
||||
|
||||
toggle$ = this.toggleSearch.asObservable();
|
||||
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
|
||||
constructor() {
|
||||
this.toggleSubscription = this.toggle$.pipe(debounceTime(200), takeUntilDestroyed()).subscribe(() => {
|
||||
this.toggle$.pipe(debounceTime(200), takeUntilDestroyed(this.destroyRef)).subscribe(() => {
|
||||
if (this.expandable) {
|
||||
this.subscriptAnimationState = this.toggleAnimation();
|
||||
if (this.subscriptAnimationState.value === 'inactive') {
|
||||
this.searchTerm = '';
|
||||
this.reset.emit(true);
|
||||
if (document.activeElement.id === this.searchInput.nativeElement.id) {
|
||||
if (document.activeElement?.id === this.searchInput.nativeElement.id) {
|
||||
this.searchInput.nativeElement.blur();
|
||||
}
|
||||
} else if (this.subscriptAnimationState.value === 'active' && this.isDefaultStateCollapsed()) {
|
||||
setTimeout(() => this.searchInput.nativeElement.focus(), 0);
|
||||
}
|
||||
this.emitVisibilitySearch();
|
||||
}
|
||||
@@ -205,10 +203,9 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
this.setupFocusEventHandlers();
|
||||
}
|
||||
|
||||
applySearchFocus(animationDoneEvent) {
|
||||
if (animationDoneEvent.toState === 'active' && this.isDefaultStateCollapsed()) {
|
||||
this.searchInput.nativeElement.focus();
|
||||
}
|
||||
ngOnDestroy() {
|
||||
this.toggleSearch.complete();
|
||||
this.valueChange.complete();
|
||||
}
|
||||
|
||||
getAutoComplete(): string {
|
||||
@@ -218,23 +215,23 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
private toggleAnimation() {
|
||||
if (this.dir === 'ltr') {
|
||||
return this.subscriptAnimationState.value === 'inactive'
|
||||
? { value: 'active', params: { 'margin-left': 0 } }
|
||||
? { value: 'active', params: { 'margin-left': '0px' } }
|
||||
: { value: 'inactive', params: { transform: 'translateX(100%)' } };
|
||||
} else {
|
||||
return this.subscriptAnimationState.value === 'inactive'
|
||||
? { value: 'active', params: { 'margin-right': 0 } }
|
||||
? { value: 'active', params: { 'margin-right': '0px' } }
|
||||
: { value: 'inactive', params: { transform: 'translateX(-100%)' } };
|
||||
}
|
||||
}
|
||||
|
||||
private getDefaultState(dir: string): SearchAnimationState {
|
||||
private getDefaultState(dir: keyof SearchAnimationDirection): SearchAnimationState {
|
||||
if (this.dir) {
|
||||
return this.getAnimationState(dir);
|
||||
}
|
||||
return this.animationStates.ltr.inactive;
|
||||
}
|
||||
|
||||
private getAnimationState(dir: string): SearchAnimationState {
|
||||
private getAnimationState(dir: keyof SearchAnimationDirection): SearchAnimationState {
|
||||
if (this.expandable && this.isDefaultStateExpanded()) {
|
||||
return this.animationStates[dir].active;
|
||||
} else if (this.expandable) {
|
||||
@@ -246,21 +243,21 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
|
||||
private setupFocusEventHandlers() {
|
||||
if (this.focusListener) {
|
||||
const focusEvents: Observable<FocusEvent> = this.focusListener.pipe(
|
||||
debounceTime(50),
|
||||
filter(
|
||||
($event: any) => this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout' || $event.type === 'focus')
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
);
|
||||
|
||||
this.focusSubscription = focusEvents.subscribe((event: FocusEvent) => {
|
||||
if (event.type === 'focus') {
|
||||
this.searchInput.nativeElement.focus();
|
||||
} else {
|
||||
this.toggleSearchBar();
|
||||
}
|
||||
});
|
||||
this.focusListener
|
||||
.pipe(
|
||||
debounceTime(50),
|
||||
filter(
|
||||
($event: any) => this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout' || $event.type === 'focus')
|
||||
),
|
||||
takeUntilDestroyed(this.destroyRef)
|
||||
)
|
||||
.subscribe((event: FocusEvent) => {
|
||||
if (event.type === 'focus') {
|
||||
this.searchInput.nativeElement.focus();
|
||||
} else {
|
||||
this.toggleSearchBar();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,11 +267,11 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
selectFirstResult($event) {
|
||||
selectFirstResult($event: any) {
|
||||
this.selectResult.emit($event);
|
||||
}
|
||||
|
||||
onBlur($event) {
|
||||
onBlur($event: any) {
|
||||
if (this.collapseOnBlur && !$event.relatedTarget) {
|
||||
this.resetSearch();
|
||||
}
|
||||
@@ -308,20 +305,6 @@ export class SearchTextInputComponent implements OnInit, OnDestroy {
|
||||
return this.subscriptAnimationState.value === 'active';
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.toggleSearch) {
|
||||
this.toggleSubscription.unsubscribe();
|
||||
this.toggleSearch.complete();
|
||||
this.toggleSearch = null;
|
||||
}
|
||||
|
||||
if (this.focusSubscription) {
|
||||
this.focusSubscription.unsubscribe();
|
||||
this.focusSubscription = null;
|
||||
this.focusListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
canShowClearSearch(): boolean {
|
||||
return this.showClearButton && this.isSearchBarActive();
|
||||
}
|
||||
|
||||
@@ -15,12 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
||||
import { NoopTranslateModule } from './noop-translate.module';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { BrowserTestingModule } from '@angular/platform-browser/testing';
|
||||
import { provideNoopAnimations } from '@angular/platform-browser/animations';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserDynamicTestingModule, NoopTranslateModule, NoopAnimationsModule]
|
||||
imports: [BrowserTestingModule, NoopTranslateModule],
|
||||
providers: [provideNoopAnimations()]
|
||||
})
|
||||
export class GlobalTestingModule {}
|
||||
|
||||
Reference in New Issue
Block a user