mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-07-18 00:46:45 +00:00
refactor: migrate to signals for querries
This commit is contained in:
parent
8663819185
commit
150e582936
37 changed files with 293 additions and 266 deletions
|
|
@ -4,8 +4,8 @@ import {
|
|||
HostBinding,
|
||||
HostListener,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ChromeExtensionInterfaceService } from './core/chrome-extension-interface/chrome-extension-interface.service';
|
||||
import { ShortcutService } from './core-ui/shortcut/shortcut.service';
|
||||
|
|
@ -65,8 +65,8 @@ export class AppComponent implements OnDestroy {
|
|||
|
||||
@HostBinding('@.disabled') isDisableAnimations = false;
|
||||
|
||||
@ViewChild('notesElRef', { read: ViewContainerRef }) notesElRef?: ViewContainerRef;
|
||||
@ViewChild('sideNavElRef', { read: ViewContainerRef }) sideNavElRef?: ViewContainerRef;
|
||||
readonly notesElRef = viewChild('notesElRef', { read: ViewContainerRef });
|
||||
readonly sideNavElRef = viewChild('sideNavElRef', { read: ViewContainerRef });
|
||||
|
||||
isRTL: boolean = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
OnDestroy,
|
||||
OnInit,
|
||||
Renderer2,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ProjectService } from '../../features/project/project.service';
|
||||
import { LayoutService } from '../layout/layout.service';
|
||||
|
|
@ -44,7 +44,7 @@ export class MainHeaderComponent implements OnInit, OnDestroy {
|
|||
circumference: number = this.progressCircleRadius * Math.PI * 2;
|
||||
isShowSimpleCounterBtnsMobile: boolean = false;
|
||||
|
||||
@ViewChild('circleSvg', { static: true }) circleSvg?: ElementRef;
|
||||
readonly circleSvg = viewChild<ElementRef>('circleSvg');
|
||||
|
||||
currentTaskContext$: Observable<Project | Tag | null> =
|
||||
this.taskService.currentTaskParentOrCurrent$.pipe(
|
||||
|
|
@ -104,17 +104,14 @@ export class MainHeaderComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.taskService.currentTaskProgress$.subscribe((progressIN) => {
|
||||
if (this.circleSvg) {
|
||||
const circleSvg = this.circleSvg();
|
||||
if (circleSvg) {
|
||||
let progress = progressIN || 1;
|
||||
if (progress > 1) {
|
||||
progress = 1;
|
||||
}
|
||||
const dashOffset = this.circumference * -1 * progress;
|
||||
this._renderer.setStyle(
|
||||
this.circleSvg.nativeElement,
|
||||
'stroke-dashoffset',
|
||||
dashOffset,
|
||||
);
|
||||
this._renderer.setStyle(circleSvg.nativeElement, 'stroke-dashoffset', dashOffset);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ElementRef,
|
||||
HostBinding,
|
||||
input,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { RouterLink, RouterModule } from '@angular/router';
|
||||
import { UiModule } from '../../../ui/ui.module';
|
||||
|
|
@ -41,8 +41,7 @@ export class SideNavItemComponent {
|
|||
|
||||
contextMenuPosition: { x: string; y: string } = { x: '0px', y: '0px' };
|
||||
|
||||
@ViewChild('routeBtn', { static: true, read: ElementRef })
|
||||
routeBtn!: ElementRef;
|
||||
readonly routeBtn = viewChild.required('routeBtn', { read: ElementRef });
|
||||
|
||||
@HostBinding('class.hasTasks')
|
||||
get workContextHasTasks(): boolean {
|
||||
|
|
@ -60,6 +59,6 @@ export class SideNavItemComponent {
|
|||
}
|
||||
|
||||
focus(): void {
|
||||
this.routeBtn.nativeElement.focus();
|
||||
this.routeBtn().nativeElement.focus();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ import {
|
|||
HostBinding,
|
||||
HostListener,
|
||||
OnDestroy,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
viewChildren,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ProjectService } from '../../features/project/project.service';
|
||||
import { T } from '../../t.const';
|
||||
|
|
@ -53,13 +52,13 @@ import { updateProject } from '../../features/project/store/project.actions';
|
|||
standalone: false,
|
||||
})
|
||||
export class SideNavComponent implements OnDestroy {
|
||||
@ViewChildren('menuEntry') navEntries?: QueryList<MatMenuItem>;
|
||||
readonly navEntries = viewChildren<MatMenuItem>('menuEntry');
|
||||
IS_MOUSE_PRIMARY = IS_MOUSE_PRIMARY;
|
||||
IS_TOUCH_PRIMARY = IS_TOUCH_PRIMARY;
|
||||
DRAG_DELAY_FOR_TOUCH_LONGER = DRAG_DELAY_FOR_TOUCH_LONGER;
|
||||
|
||||
keyboardFocusTimeout?: number;
|
||||
@ViewChild('projectExpandBtn', { read: ElementRef }) projectExpandBtn?: ElementRef;
|
||||
readonly projectExpandBtn = viewChild('projectExpandBtn', { read: ElementRef });
|
||||
isProjectsExpanded: boolean = this.fetchProjectListState();
|
||||
isProjectsExpanded$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(
|
||||
this.isProjectsExpanded,
|
||||
|
|
@ -77,7 +76,7 @@ export class SideNavComponent implements OnDestroy {
|
|||
),
|
||||
);
|
||||
|
||||
@ViewChild('tagExpandBtn', { read: ElementRef }) tagExpandBtn?: ElementRef;
|
||||
readonly tagExpandBtn = viewChild('tagExpandBtn', { read: ElementRef });
|
||||
isTagsExpanded: boolean = this.fetchTagListState();
|
||||
isTagsExpanded$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(
|
||||
this.isTagsExpanded,
|
||||
|
|
@ -123,9 +122,10 @@ export class SideNavComponent implements OnDestroy {
|
|||
|
||||
this._subs.add(
|
||||
this._layoutService.isShowSideNav$.subscribe((isShow) => {
|
||||
if (this.navEntries && isShow) {
|
||||
const navEntries = this.navEntries();
|
||||
if (navEntries && isShow) {
|
||||
this.keyManager = new FocusKeyManager<MatMenuItem>(
|
||||
this.navEntries,
|
||||
navEntries,
|
||||
).withVerticalOrientation(true);
|
||||
window.clearTimeout(this.keyboardFocusTimeout);
|
||||
this.keyboardFocusTimeout = window.setTimeout(() => {
|
||||
|
|
@ -190,9 +190,9 @@ export class SideNavComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
checkFocusProject(ev: KeyboardEvent): void {
|
||||
if (ev.key === 'ArrowLeft' && this.projectExpandBtn?.nativeElement) {
|
||||
const targetIndex = this.navEntries?.toArray().findIndex((value) => {
|
||||
return value._getHostElement() === this.projectExpandBtn?.nativeElement;
|
||||
if (ev.key === 'ArrowLeft' && this.projectExpandBtn()?.nativeElement) {
|
||||
const targetIndex = this.navEntries().findIndex((value) => {
|
||||
return value._getHostElement() === this.projectExpandBtn()?.nativeElement;
|
||||
});
|
||||
if (targetIndex) {
|
||||
this.keyManager?.setActiveItem(targetIndex);
|
||||
|
|
@ -217,9 +217,9 @@ export class SideNavComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
checkFocusTag(ev: KeyboardEvent): void {
|
||||
if (ev.key === 'ArrowLeft' && this.tagExpandBtn?.nativeElement) {
|
||||
const targetIndex = this.navEntries?.toArray().findIndex((value) => {
|
||||
return value._getHostElement() === this.tagExpandBtn?.nativeElement;
|
||||
if (ev.key === 'ArrowLeft' && this.tagExpandBtn()?.nativeElement) {
|
||||
const targetIndex = this.navEntries().findIndex((value) => {
|
||||
return value._getHostElement() === this.tagExpandBtn()?.nativeElement;
|
||||
});
|
||||
if (targetIndex) {
|
||||
this.keyManager?.setActiveItem(targetIndex);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ export class BookmarkBarComponent {
|
|||
private readonly _matDialog: MatDialog,
|
||||
) {}
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// Accessor queries cannot be migrated as they are too complex.
|
||||
@ViewChild('bookmarkBar', { read: ElementRef }) set bookmarkBarEl(content: ElementRef) {
|
||||
if (content && content.nativeElement) {
|
||||
this.bookmarkBarHeight = content.nativeElement.offsetHeight;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import {
|
|||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
ViewContainerRef,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { expandAnimation } from '../../../ui/animations/expand.ani';
|
||||
import {
|
||||
|
|
@ -40,8 +40,7 @@ export class ConfigSectionComponent implements OnInit, OnDestroy {
|
|||
sectionKey: GlobalConfigSectionKey | ProjectCfgFormKey | TagCfgFormKey;
|
||||
config: any;
|
||||
}> = new EventEmitter();
|
||||
@ViewChild('customForm', { read: ViewContainerRef, static: true })
|
||||
customFormRef?: ViewContainerRef;
|
||||
readonly customFormRef = viewChild('customForm', { read: ViewContainerRef });
|
||||
isExpanded: boolean = false;
|
||||
private _subs: Subscription = new Subscription();
|
||||
private _instance?: Component;
|
||||
|
|
@ -84,13 +83,14 @@ export class ConfigSectionComponent implements OnInit, OnDestroy {
|
|||
this._workContextService.onWorkContextChange$.subscribe(() => {
|
||||
this._cd.markForCheck();
|
||||
|
||||
const customFormRef = this.customFormRef();
|
||||
if (
|
||||
this.section &&
|
||||
this.section.customSection &&
|
||||
this.customFormRef &&
|
||||
customFormRef &&
|
||||
this.section.customSection
|
||||
) {
|
||||
this.customFormRef.clear();
|
||||
customFormRef.clear();
|
||||
// dirty trick to make sure data is actually there
|
||||
this._viewDestroyTimeout = window.setTimeout(() => {
|
||||
this._loadCustomSection((this.section as any).customSection);
|
||||
|
|
@ -126,7 +126,7 @@ export class ConfigSectionComponent implements OnInit, OnDestroy {
|
|||
if (componentToRender) {
|
||||
const factory: ComponentFactory<any> =
|
||||
this._componentFactoryResolver.resolveComponentFactory(componentToRender as any);
|
||||
const ref = exists<any>(this.customFormRef).createComponent(factory);
|
||||
const ref = exists<any>(this.customFormRef()).createComponent(factory);
|
||||
|
||||
// NOTE: important that this is set only if we actually have a value
|
||||
// otherwise the default fallback will be overwritten
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
input,
|
||||
OnInit,
|
||||
signal,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ErrorCardComponent } from '../../../ui/error-card/error-card.component';
|
||||
import { IssuePreviewItemComponent } from '../issue-preview-item/issue-preview-item.component';
|
||||
|
|
@ -39,7 +39,7 @@ export class IssuePanelCalendarAgendaComponent implements OnInit {
|
|||
error = signal<string | undefined>(undefined);
|
||||
isLoading = signal(false);
|
||||
|
||||
@ViewChild(CdkDropList) dropList?: CdkDropList;
|
||||
readonly dropList = viewChild(CdkDropList);
|
||||
|
||||
agendaItems = signal<
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
input,
|
||||
OnDestroy,
|
||||
signal,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { IssuePreviewItemComponent } from '../issue-preview-item/issue-preview-item.component';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
|
|
@ -173,8 +173,8 @@ export class IssueProviderTabComponent implements OnDestroy, AfterViewInit {
|
|||
);
|
||||
issueItems = toSignal(this.issueItems$.pipe(map((v) => v.notAdded)));
|
||||
|
||||
@ViewChild(CdkDropList) dropList?: CdkDropList;
|
||||
@ViewChild('searchTextEl') searchTextEl!: ElementRef;
|
||||
readonly dropList = viewChild(CdkDropList);
|
||||
readonly searchTextEl = viewChild.required<ElementRef>('searchTextEl');
|
||||
|
||||
private _focusTimeout?: number;
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ export class IssueProviderTabComponent implements OnDestroy, AfterViewInit {
|
|||
// this.dropListService.registerDropList(this.dropList!);
|
||||
if (this.searchText().length <= 1 && IS_MOUSE_PRIMARY) {
|
||||
this._focusTimeout = window.setTimeout(() => {
|
||||
this.searchTextEl?.nativeElement.focus();
|
||||
this.searchTextEl()?.nativeElement.focus();
|
||||
}, 500);
|
||||
}
|
||||
this.searchText.set(this.issueProvider().pinnedSearch || '');
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
Input,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { Note } from '../note.model';
|
||||
import { NoteService } from '../note.service';
|
||||
|
|
@ -37,7 +37,7 @@ export class NoteComponent implements OnChanges {
|
|||
|
||||
@Input() isFocus?: boolean;
|
||||
|
||||
@ViewChild('markdownEl') markdownEl?: HTMLElement;
|
||||
readonly markdownEl = viewChild<HTMLElement>('markdownEl');
|
||||
|
||||
isLongNote?: boolean;
|
||||
shortenedNote?: string;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import {
|
|||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
HostListener,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { NoteService } from '../note.service';
|
||||
import { MatButton } from '@angular/material/button';
|
||||
|
|
@ -30,7 +30,7 @@ export class NotesComponent {
|
|||
isDragOver: boolean = false;
|
||||
dragEnterTarget?: HTMLElement;
|
||||
|
||||
@ViewChild('buttonEl', { static: true }) buttonEl?: MatButton;
|
||||
readonly buttonEl = viewChild<MatButton>('buttonEl');
|
||||
|
||||
constructor(
|
||||
public noteService: NoteService,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ChangeDetectorRef,
|
||||
Component,
|
||||
Inject,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { UiModule } from '../../../ui/ui.module';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
|
|
@ -52,7 +52,7 @@ import { WorkContextService } from '../../work-context/work-context.service';
|
|||
export class DialogScheduleTaskComponent implements AfterViewInit {
|
||||
T: typeof T = T;
|
||||
minDate = new Date();
|
||||
@ViewChild(MatCalendar, { static: true }) calendar!: MatCalendar<Date>;
|
||||
readonly calendar = viewChild.required(MatCalendar);
|
||||
|
||||
remindAvailableOptions: TaskReminderOption[] = TASK_REMINDER_OPTIONS;
|
||||
task: TaskCopy = this.data.task;
|
||||
|
|
@ -124,7 +124,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
|
|||
this.selectedDate = dateStrToUtcDate(this.data.targetDay);
|
||||
}
|
||||
|
||||
this.calendar.activeDate = new Date(this.selectedDate || new Date());
|
||||
this.calendar().activeDate = new Date(this.selectedDate || new Date());
|
||||
this._cd.detectChanges();
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
@ -168,7 +168,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
|
|||
if (
|
||||
this.selectedDate &&
|
||||
new Date(this.selectedDate).getTime() ===
|
||||
new Date(this.calendar.activeDate).getTime()
|
||||
new Date(this.calendar().activeDate).getTime()
|
||||
) {
|
||||
this.submit();
|
||||
}
|
||||
|
|
@ -211,7 +211,7 @@ export class DialogScheduleTaskComponent implements AfterViewInit {
|
|||
// we do the timeout is there to make sure this happens after our click handler
|
||||
setTimeout(() => {
|
||||
this.selectedDate = new Date(newDate);
|
||||
this.calendar.activeDate = this.selectedDate;
|
||||
this.calendar().activeDate = this.selectedDate;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
Input,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { TaskCopy } from '../../tasks/task.model';
|
||||
import { EMPTY, Observable } from 'rxjs';
|
||||
|
|
@ -41,8 +41,9 @@ export class PlannerTaskComponent extends BaseComponent implements OnInit, OnDes
|
|||
|
||||
moveToProjectList$!: Observable<Project[]>;
|
||||
|
||||
@ViewChild('taskContextMenu', { static: true, read: TaskContextMenuComponent })
|
||||
taskContextMenu?: TaskContextMenuComponent;
|
||||
readonly taskContextMenu = viewChild('taskContextMenu', {
|
||||
read: TaskContextMenuComponent,
|
||||
});
|
||||
|
||||
@HostBinding('class.isDone')
|
||||
get isDone(): boolean {
|
||||
|
|
@ -114,7 +115,7 @@ export class PlannerTaskComponent extends BaseComponent implements OnInit, OnDes
|
|||
}
|
||||
|
||||
openContextMenu(event: TouchEvent | MouseEvent): void {
|
||||
this.taskContextMenu?.open(event);
|
||||
this.taskContextMenu()?.open(event);
|
||||
}
|
||||
|
||||
estimateTimeClick(ev: MouseEvent): void {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
output,
|
||||
signal,
|
||||
Signal,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { TaskService } from '../../tasks/task.service';
|
||||
|
|
@ -46,8 +46,7 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
|
|||
// time = computed(() => {})
|
||||
editEnd = output<void>();
|
||||
|
||||
@ViewChild('textAreaElement', { static: true, read: ElementRef })
|
||||
textAreaElement?: ElementRef<HTMLTextAreaElement>;
|
||||
readonly textAreaElement = viewChild('textAreaElement', { read: ElementRef });
|
||||
|
||||
private _editEndTimeout: number | undefined;
|
||||
|
||||
|
|
@ -59,7 +58,7 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
|
|||
@HostListener('click', ['$event'])
|
||||
onClick(event: MouseEvent): void {
|
||||
event.stopPropagation();
|
||||
this.textAreaElement?.nativeElement.focus();
|
||||
this.textAreaElement()?.nativeElement.focus();
|
||||
// cancel blur
|
||||
window.clearTimeout(this._editEndTimeout);
|
||||
}
|
||||
|
|
@ -70,7 +69,7 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
|
|||
) {
|
||||
effect(() => {
|
||||
if (this.isEditMode()) {
|
||||
this.textAreaElement?.nativeElement.focus();
|
||||
this.textAreaElement()?.nativeElement.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -87,15 +86,16 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
async onKeyDown(event: KeyboardEvent): Promise<void> {
|
||||
const textAreaElement = this.textAreaElement();
|
||||
if (
|
||||
event.key === 'Enter' &&
|
||||
typeof this.plannedAt() === 'number' &&
|
||||
this.textAreaElement?.nativeElement.value
|
||||
textAreaElement?.nativeElement.value
|
||||
) {
|
||||
this.editEnd.emit();
|
||||
if (this.isForDayMode()) {
|
||||
const id = this._taskService.add(
|
||||
this.textAreaElement?.nativeElement.value || '',
|
||||
textAreaElement?.nativeElement.value || '',
|
||||
false,
|
||||
{
|
||||
timeEstimate: 30 * 60 * 1000,
|
||||
|
|
@ -110,7 +110,7 @@ export class CreateTaskPlaceholderComponent implements OnDestroy {
|
|||
);
|
||||
} else {
|
||||
this._taskService.addAndSchedule(
|
||||
this.textAreaElement?.nativeElement.value || '',
|
||||
textAreaElement?.nativeElement.value || '',
|
||||
{
|
||||
timeEstimate: 30 * 60 * 1000,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
Input,
|
||||
LOCALE_ID,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ScheduleEvent, ScheduleFromCalendarEvent } from '../schedule.model';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
|
|
@ -77,8 +77,9 @@ export class ScheduleEventComponent implements OnInit {
|
|||
|
||||
contextMenuPosition: { x: string; y: string } = { x: '0px', y: '0px' };
|
||||
|
||||
@ViewChild('taskContextMenu', { static: false, read: TaskContextMenuComponent })
|
||||
taskContextMenu?: TaskContextMenuComponent;
|
||||
readonly taskContextMenu = viewChild('taskContextMenu', {
|
||||
read: TaskContextMenuComponent,
|
||||
});
|
||||
|
||||
protected readonly SVEType = SVEType;
|
||||
destroyRef = inject(DestroyRef);
|
||||
|
|
@ -264,7 +265,7 @@ export class ScheduleEventComponent implements OnInit {
|
|||
}
|
||||
|
||||
openContextMenu(event: TouchEvent | MouseEvent): void {
|
||||
this.taskContextMenu?.open(event);
|
||||
this.taskContextMenu()?.open(event);
|
||||
}
|
||||
|
||||
deleteTask(): void {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
Inject,
|
||||
LOCALE_ID,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { UiModule } from '../../../ui/ui.module';
|
||||
import { BehaviorSubject, combineLatest, fromEvent, Observable } from 'rxjs';
|
||||
|
|
@ -258,7 +258,7 @@ export class ScheduleComponent implements AfterViewInit, OnDestroy {
|
|||
dragCloneEl: HTMLElement | null = null;
|
||||
destroyRef = inject(DestroyRef);
|
||||
|
||||
@ViewChild('gridContainer') gridContainer!: ElementRef;
|
||||
readonly gridContainer = viewChild.required<ElementRef>('gridContainer');
|
||||
|
||||
private _currentAniTimeout: number | undefined;
|
||||
|
||||
|
|
@ -332,7 +332,7 @@ export class ScheduleComponent implements AfterViewInit, OnDestroy {
|
|||
|
||||
// console.log(ev);
|
||||
if (ev.target instanceof HTMLElement && ev.target.classList.contains('col')) {
|
||||
const gridContainer = this.gridContainer.nativeElement;
|
||||
const gridContainer = this.gridContainer().nativeElement;
|
||||
const gridStyles = window.getComputedStyle(gridContainer);
|
||||
|
||||
const rowSizes = gridStyles.gridTemplateRows
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
EventEmitter,
|
||||
OnDestroy,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { T } from '../../t.const';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
|
|
@ -46,9 +46,9 @@ const MAX_RESULTS = 100;
|
|||
export class SearchBarComponent implements AfterViewInit, OnDestroy {
|
||||
@Output() blurred: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@ViewChild('inputEl') inputEl!: ElementRef;
|
||||
@ViewChild('searchForm') searchForm!: ElementRef;
|
||||
@ViewChild(MatAutocompleteTrigger) autocomplete!: MatAutocompleteTrigger;
|
||||
readonly inputEl = viewChild.required<ElementRef>('inputEl');
|
||||
readonly searchForm = viewChild.required<ElementRef>('searchForm');
|
||||
readonly autocomplete = viewChild.required(MatAutocompleteTrigger);
|
||||
|
||||
T: typeof T = T;
|
||||
isLoading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||
|
|
@ -143,7 +143,7 @@ export class SearchBarComponent implements AfterViewInit, OnDestroy {
|
|||
);
|
||||
|
||||
this._attachKeyDownHandlerTimeout = window.setTimeout(() => {
|
||||
this.inputEl.nativeElement.addEventListener('keydown', (ev: KeyboardEvent) => {
|
||||
this.inputEl().nativeElement.addEventListener('keydown', (ev: KeyboardEvent) => {
|
||||
if (ev.key === 'Escape') {
|
||||
this.blurred.emit();
|
||||
} else if (
|
||||
|
|
@ -176,15 +176,15 @@ export class SearchBarComponent implements AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
private _shakeSearchForm(): void {
|
||||
this.searchForm.nativeElement.classList.toggle('shake-form');
|
||||
this.searchForm.nativeElement.onanimationend = () => {
|
||||
this.searchForm.nativeElement.classList.toggle('shake-form');
|
||||
this.searchForm().nativeElement.classList.toggle('shake-form');
|
||||
this.searchForm().nativeElement.onanimationend = () => {
|
||||
this.searchForm().nativeElement.classList.toggle('shake-form');
|
||||
};
|
||||
}
|
||||
|
||||
onAnimationEvent(event: AnimationEvent): void {
|
||||
if (event.fromState) {
|
||||
this.inputEl.nativeElement.focus();
|
||||
this.inputEl().nativeElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
inject,
|
||||
input,
|
||||
output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
MatAutocomplete,
|
||||
|
|
@ -70,8 +70,8 @@ export class TagEditComponent {
|
|||
inputCtrl: UntypedFormControl = new UntypedFormControl();
|
||||
separatorKeysCodes: number[] = DEFAULT_SEPARATOR_KEY_CODES;
|
||||
|
||||
@ViewChild('inputElRef', { static: true }) inputEl?: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('autoElRef', { static: true }) matAutocomplete?: MatAutocomplete;
|
||||
readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputElRef');
|
||||
readonly matAutocomplete = viewChild<MatAutocomplete>('autoElRef');
|
||||
|
||||
inputVal = toSignal<string>(this.inputCtrl.valueChanges);
|
||||
tagSuggestions = toSignal(this._tagService.tagsNoMyDayAndNoList$, { initialValue: [] });
|
||||
|
|
@ -99,11 +99,12 @@ export class TagEditComponent {
|
|||
});
|
||||
|
||||
add(event: MatChipInputEvent): void {
|
||||
if (!this.matAutocomplete) {
|
||||
const matAutocomplete = this.matAutocomplete();
|
||||
if (!matAutocomplete) {
|
||||
throw new Error('Auto complete undefined');
|
||||
}
|
||||
|
||||
if (!this.matAutocomplete.isOpen) {
|
||||
if (!matAutocomplete.isOpen) {
|
||||
const inp = event.input;
|
||||
const value = event.value;
|
||||
|
||||
|
|
@ -125,8 +126,9 @@ export class TagEditComponent {
|
|||
}
|
||||
|
||||
focusInput(): void {
|
||||
if (this.inputEl) {
|
||||
this.inputEl.nativeElement.focus();
|
||||
const inputEl = this.inputEl();
|
||||
if (inputEl) {
|
||||
inputEl.nativeElement.focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,8 +138,9 @@ export class TagEditComponent {
|
|||
|
||||
selected(event: MatAutocompleteSelectedEvent): void {
|
||||
this._add(event.option.value);
|
||||
if (this.inputEl) {
|
||||
this.inputEl.nativeElement.value = '';
|
||||
const inputEl = this.inputEl();
|
||||
if (inputEl) {
|
||||
inputEl.nativeElement.value = '';
|
||||
}
|
||||
this.inputCtrl.setValue(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
OnDestroy,
|
||||
output,
|
||||
signal,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { TaskService } from '../task.service';
|
||||
|
|
@ -56,7 +56,7 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
|
|||
isSearchIssueProviders = signal(false);
|
||||
isSearchIssueProviders$ = toObservable(this.isSearchIssueProviders);
|
||||
|
||||
@ViewChild('inputEl', { static: true }) inputEl?: ElementRef;
|
||||
readonly inputEl = viewChild<ElementRef>('inputEl');
|
||||
|
||||
T: typeof T = T;
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
this._attachKeyDownHandlerTimeout = window.setTimeout(() => {
|
||||
(this.inputEl as ElementRef).nativeElement.addEventListener(
|
||||
(this.inputEl() as ElementRef).nativeElement.addEventListener(
|
||||
'keydown',
|
||||
(ev: KeyboardEvent) => {
|
||||
if (ev.key === 'Escape') {
|
||||
|
|
@ -133,8 +133,8 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
|
|||
sessionStorage.setItem(SS.TODO_TMP, '');
|
||||
this.taskSuggestionsCtrl.setValue(savedTodo);
|
||||
this._saveTmpTodoTimeout = window.setTimeout(() => {
|
||||
(this.inputEl as ElementRef).nativeElement.value = savedTodo;
|
||||
(this.inputEl as ElementRef).nativeElement.select();
|
||||
(this.inputEl() as ElementRef).nativeElement.value = savedTodo;
|
||||
(this.inputEl() as ElementRef).nativeElement.select();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -175,15 +175,13 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
|
|||
className.includes('shepherd-enabled');
|
||||
}
|
||||
|
||||
const inputEl = this.inputEl();
|
||||
if (!relatedTarget || (relatedTarget && !isUIelement)) {
|
||||
sessionStorage.setItem(
|
||||
SS.TODO_TMP,
|
||||
(this.inputEl as ElementRef).nativeElement.value,
|
||||
);
|
||||
sessionStorage.setItem(SS.TODO_TMP, (inputEl as ElementRef).nativeElement.value);
|
||||
}
|
||||
|
||||
if (relatedTarget && isUIelement) {
|
||||
(this.inputEl as ElementRef).nativeElement.focus();
|
||||
(inputEl as ElementRef).nativeElement.focus();
|
||||
} else {
|
||||
// we need to wait since otherwise addTask is not working
|
||||
window.clearTimeout(this._delayBlurTimeout);
|
||||
|
|
@ -270,14 +268,14 @@ export class AddTaskBarComponent implements AfterViewInit, OnDestroy {
|
|||
private _focusInput(): void {
|
||||
if (IS_ANDROID_WEB_VIEW) {
|
||||
document.body.focus();
|
||||
(this.inputEl as ElementRef).nativeElement.focus();
|
||||
(this.inputEl() as ElementRef).nativeElement.focus();
|
||||
this._autofocusTimeout = window.setTimeout(() => {
|
||||
document.body.focus();
|
||||
(this.inputEl as ElementRef).nativeElement.focus();
|
||||
(this.inputEl() as ElementRef).nativeElement.focus();
|
||||
}, 1000);
|
||||
} else {
|
||||
this._autofocusTimeout = window.setTimeout(() => {
|
||||
(this.inputEl as ElementRef).nativeElement.focus();
|
||||
(this.inputEl() as ElementRef).nativeElement.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import {
|
|||
input,
|
||||
Input,
|
||||
output,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { AsyncPipe, DatePipe } from '@angular/common';
|
||||
import { IssueModule } from '../../../issue/issue.module';
|
||||
|
|
@ -95,10 +95,11 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
|
|||
|
||||
contextMenuPosition: { x: string; y: string } = { x: '100px', y: '100px' };
|
||||
|
||||
@ViewChild('contextMenuTriggerEl', { static: true, read: MatMenuTrigger })
|
||||
contextMenuTrigger?: MatMenuTrigger;
|
||||
readonly contextMenuTrigger = viewChild('contextMenuTriggerEl', {
|
||||
read: MatMenuTrigger,
|
||||
});
|
||||
|
||||
@ViewChild('contextMenu', { static: true, read: MatMenu }) contextMenu?: MatMenu;
|
||||
readonly contextMenu = viewChild('contextMenu', { read: MatMenu });
|
||||
|
||||
task!: TaskWithSubTasks | Task;
|
||||
|
||||
|
|
@ -186,7 +187,7 @@ export class TaskContextMenuInnerComponent implements AfterViewInit {
|
|||
}
|
||||
|
||||
this._isOpenedFromKeyboard = isOpenedFromKeyBoard;
|
||||
this.contextMenuTrigger?.openMenu();
|
||||
this.contextMenuTrigger()?.openMenu();
|
||||
}
|
||||
|
||||
focusRelatedTaskOrNext(): void {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
ChangeDetectorRef,
|
||||
Component,
|
||||
input,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { IssueModule } from '../../issue/issue.module';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
|
@ -23,17 +23,15 @@ export class TaskContextMenuComponent {
|
|||
|
||||
isShowInner: boolean = false;
|
||||
|
||||
@ViewChild('taskContextMenuInner', {
|
||||
static: false,
|
||||
readonly taskContextMenuInner = viewChild('taskContextMenuInner', {
|
||||
read: TaskContextMenuInnerComponent,
|
||||
})
|
||||
taskContextMenuInner?: TaskContextMenuInnerComponent;
|
||||
});
|
||||
|
||||
constructor(private _cd: ChangeDetectorRef) {}
|
||||
|
||||
open(ev: MouseEvent | KeyboardEvent | TouchEvent, isOpenedFromKeyBoard = false): void {
|
||||
this.isShowInner = true;
|
||||
this._cd.detectChanges();
|
||||
this.taskContextMenuInner?.open(ev, isOpenedFromKeyBoard);
|
||||
this.taskContextMenuInner()?.open(ev, isOpenedFromKeyBoard);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,8 @@ import {
|
|||
Input,
|
||||
LOCALE_ID,
|
||||
OnDestroy,
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
viewChildren,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { ShowSubTasksMode, TaskDetailTargetPanel, TaskWithSubTasks } from '../task.model';
|
||||
import { IssueService } from '../../issue/issue.service';
|
||||
|
|
@ -94,10 +93,9 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
|
|||
@Input() isOver: boolean = false;
|
||||
@Input() isDialogMode: boolean = false;
|
||||
|
||||
@ViewChildren(TaskDetailItemComponent)
|
||||
itemEls?: QueryList<TaskDetailItemComponent>;
|
||||
@ViewChild('attachmentPanelElRef')
|
||||
attachmentPanelElRef?: TaskDetailItemComponent;
|
||||
readonly itemEls = viewChildren(TaskDetailItemComponent);
|
||||
readonly attachmentPanelElRef =
|
||||
viewChild<TaskDetailItemComponent>('attachmentPanelElRef');
|
||||
IS_TOUCH_PRIMARY = IS_TOUCH_PRIMARY;
|
||||
|
||||
_onDestroy$ = new Subject<void>();
|
||||
|
|
@ -377,11 +375,12 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
|
|||
)
|
||||
.subscribe(([v]) => {
|
||||
if (v === TaskDetailTargetPanel.Attachments) {
|
||||
if (!this.attachmentPanelElRef) {
|
||||
const attachmentPanelElRef = this.attachmentPanelElRef();
|
||||
if (!attachmentPanelElRef) {
|
||||
devError('this.attachmentPanelElRef not ready');
|
||||
this._focusFirst();
|
||||
} else {
|
||||
this.focusItem(this.attachmentPanelElRef);
|
||||
this.focusItem(attachmentPanelElRef);
|
||||
}
|
||||
} else {
|
||||
this._focusFirst();
|
||||
|
|
@ -458,30 +457,29 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
|
|||
}
|
||||
|
||||
onItemKeyPress(ev: KeyboardEvent): void {
|
||||
if (!this.itemEls) {
|
||||
const itemEls = this.itemEls();
|
||||
if (!itemEls) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
if (ev.key === 'ArrowUp' && this.selectedItemIndex > 0) {
|
||||
this.selectedItemIndex--;
|
||||
this.itemEls.toArray()[this.selectedItemIndex].focusEl();
|
||||
} else if (
|
||||
ev.key === 'ArrowDown' &&
|
||||
this.itemEls.toArray().length > this.selectedItemIndex + 1
|
||||
) {
|
||||
itemEls[this.selectedItemIndex].focusEl();
|
||||
} else if (ev.key === 'ArrowDown' && itemEls.length > this.selectedItemIndex + 1) {
|
||||
this.selectedItemIndex++;
|
||||
this.itemEls.toArray()[this.selectedItemIndex].focusEl();
|
||||
itemEls[this.selectedItemIndex].focusEl();
|
||||
}
|
||||
}
|
||||
|
||||
focusItem(cmpInstance: TaskDetailItemComponent, timeoutDuration: number = 150): void {
|
||||
window.clearTimeout(this._focusTimeout);
|
||||
this._focusTimeout = window.setTimeout(() => {
|
||||
if (!this.itemEls) {
|
||||
const itemEls = this.itemEls();
|
||||
if (!itemEls) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
const i = this.itemEls.toArray().findIndex((el) => el === cmpInstance);
|
||||
const i = itemEls.findIndex((el) => el === cmpInstance);
|
||||
if (i === -1) {
|
||||
this.focusItem(cmpInstance);
|
||||
} else {
|
||||
|
|
@ -503,10 +501,11 @@ export class TaskDetailPanelComponent implements AfterViewInit, OnDestroy {
|
|||
|
||||
private _focusFirst(): void {
|
||||
this._focusTimeout = window.setTimeout(() => {
|
||||
if (!this.itemEls) {
|
||||
const itemEls = this.itemEls();
|
||||
if (!itemEls) {
|
||||
throw new Error();
|
||||
}
|
||||
this.focusItem(this.itemEls.first, 0);
|
||||
this.focusItem(itemEls.at(0)!, 0);
|
||||
}, 150);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
computed,
|
||||
input,
|
||||
OnDestroy,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { DropListModelSource, Task, TaskCopy, TaskWithSubTasks } from '../task.model';
|
||||
import { TaskService } from '../task.service';
|
||||
|
|
@ -86,7 +86,7 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
|
|||
});
|
||||
allTasksLength = computed(() => this.tasks()?.length ?? 0);
|
||||
|
||||
@ViewChild(CdkDropList) dropList?: CdkDropList;
|
||||
readonly dropList = viewChild(CdkDropList);
|
||||
|
||||
T: typeof T = T;
|
||||
|
||||
|
|
@ -99,11 +99,11 @@ export class TaskListComponent implements OnDestroy, AfterViewInit {
|
|||
) {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.dropListService.registerDropList(this.dropList!, this.listId() === 'SUB');
|
||||
this.dropListService.registerDropList(this.dropList()!, this.listId() === 'SUB');
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.dropListService.unregisterDropList(this.dropList!);
|
||||
this.dropListService.unregisterDropList(this.dropList()!);
|
||||
}
|
||||
|
||||
trackByFn(i: number, task: Task): string {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
input,
|
||||
OnDestroy,
|
||||
Renderer2,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { TaskService } from '../task.service';
|
||||
import { EMPTY, forkJoin, of } from 'rxjs';
|
||||
|
|
@ -112,14 +112,16 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
ShowSubTasksMode: typeof ShowSubTasksMode = ShowSubTasksMode;
|
||||
isFirstLineHover: boolean = false;
|
||||
|
||||
@ViewChild('taskTitleEditEl', { static: true }) taskTitleEditEl?: ElementRef;
|
||||
@ViewChild('blockLeftEl') blockLeftElRef?: ElementRef;
|
||||
@ViewChild('blockRightEl') blockRightElRef?: ElementRef;
|
||||
@ViewChild('innerWrapperEl', { static: true }) innerWrapperElRef?: ElementRef;
|
||||
@ViewChild('projectMenuTriggerEl', { static: false, read: MatMenuTrigger })
|
||||
projectMenuTrigger?: MatMenuTrigger;
|
||||
@ViewChild('taskContextMenu', { static: true, read: TaskContextMenuComponent })
|
||||
taskContextMenu?: TaskContextMenuComponent;
|
||||
readonly taskTitleEditEl = viewChild<ElementRef>('taskTitleEditEl');
|
||||
readonly blockLeftElRef = viewChild<ElementRef>('blockLeftEl');
|
||||
readonly blockRightElRef = viewChild<ElementRef>('blockRightEl');
|
||||
readonly innerWrapperElRef = viewChild<ElementRef>('innerWrapperEl');
|
||||
readonly projectMenuTrigger = viewChild('projectMenuTriggerEl', {
|
||||
read: MatMenuTrigger,
|
||||
});
|
||||
readonly taskContextMenu = viewChild('taskContextMenu', {
|
||||
read: TaskContextMenuComponent,
|
||||
});
|
||||
|
||||
private _task$ = toObservable(this.task);
|
||||
|
||||
|
|
@ -468,17 +470,18 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
}
|
||||
|
||||
focusTitleForEdit(): void {
|
||||
if (!this.taskTitleEditEl || !(this.taskTitleEditEl as any).textarea.nativeElement) {
|
||||
console.log(this.taskTitleEditEl);
|
||||
const taskTitleEditEl = this.taskTitleEditEl();
|
||||
if (!taskTitleEditEl || !(taskTitleEditEl as any).textarea.nativeElement) {
|
||||
console.log(taskTitleEditEl);
|
||||
throw new Error('No el');
|
||||
}
|
||||
(this.taskTitleEditEl as any).textarea.nativeElement.focus();
|
||||
(taskTitleEditEl as any).textarea.nativeElement.focus();
|
||||
// (this.taskTitleEditEl as any).textarea.nativeElement.focus();
|
||||
}
|
||||
|
||||
openContextMenu(event: TouchEvent | MouseEvent): void {
|
||||
(this.taskTitleEditEl as any).textarea.nativeElement?.blur();
|
||||
this.taskContextMenu?.open(event);
|
||||
(this.taskTitleEditEl() as any).textarea.nativeElement?.blur();
|
||||
this.taskContextMenu()?.open(event);
|
||||
}
|
||||
|
||||
onTagsUpdated(tagIds: string[]): void {
|
||||
|
|
@ -489,7 +492,8 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
if (!IS_TOUCH_PRIMARY) {
|
||||
return;
|
||||
}
|
||||
if (!this.taskTitleEditEl) {
|
||||
const taskTitleEditEl = this.taskTitleEditEl();
|
||||
if (!taskTitleEditEl) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
|
||||
|
|
@ -498,7 +502,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
if (
|
||||
(targetEl.className.indexOf && targetEl.className.indexOf('drag-handle') > -1) ||
|
||||
Math.abs(ev.deltaY) > Math.abs(ev.deltaX) ||
|
||||
document.activeElement === (this.taskTitleEditEl as any).textarea.nativeElement ||
|
||||
document.activeElement === (taskTitleEditEl as any).textarea.nativeElement ||
|
||||
ev.isFinal
|
||||
) {
|
||||
return;
|
||||
|
|
@ -514,13 +518,15 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
if (!IS_TOUCH_PRIMARY || (!this.isLockPanLeft && !this.isLockPanRight)) {
|
||||
return;
|
||||
}
|
||||
if (!this.blockLeftElRef || !this.blockRightElRef) {
|
||||
const blockLeftElRef = this.blockLeftElRef();
|
||||
const blockRightElRef = this.blockRightElRef();
|
||||
if (!blockLeftElRef || !blockRightElRef) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
|
||||
this.isPreventPointerEventsWhilePanning = false;
|
||||
this._renderer.removeStyle(this.blockLeftElRef.nativeElement, 'transition');
|
||||
this._renderer.removeStyle(this.blockRightElRef.nativeElement, 'transition');
|
||||
this._renderer.removeStyle(blockLeftElRef.nativeElement, 'transition');
|
||||
this._renderer.removeStyle(blockRightElRef.nativeElement, 'transition');
|
||||
|
||||
if (this._currentPanTimeout) {
|
||||
window.clearTimeout(this._currentPanTimeout);
|
||||
|
|
@ -528,11 +534,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
|
||||
if (this.isActionTriggered) {
|
||||
if (this.isLockPanLeft) {
|
||||
this._renderer.setStyle(
|
||||
this.blockRightElRef.nativeElement,
|
||||
'transform',
|
||||
`scaleX(1)`,
|
||||
);
|
||||
this._renderer.setStyle(blockRightElRef.nativeElement, 'transform', `scaleX(1)`);
|
||||
this._currentPanTimeout = window.setTimeout(() => {
|
||||
if (this.workContextService.isToday) {
|
||||
if (this.task().repeatCfgId) {
|
||||
|
|
@ -554,11 +556,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
this._resetAfterPan();
|
||||
}, 100);
|
||||
} else if (this.isLockPanRight) {
|
||||
this._renderer.setStyle(
|
||||
this.blockLeftElRef.nativeElement,
|
||||
'transform',
|
||||
`scaleX(1)`,
|
||||
);
|
||||
this._renderer.setStyle(blockLeftElRef.nativeElement, 'transform', `scaleX(1)`);
|
||||
this._currentPanTimeout = window.setTimeout(() => {
|
||||
this.toggleTaskDone();
|
||||
this._resetAfterPan();
|
||||
|
|
@ -696,11 +694,14 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
) {
|
||||
return;
|
||||
}
|
||||
if (!this.innerWrapperElRef) {
|
||||
const innerWrapperElRef = this.innerWrapperElRef();
|
||||
if (!innerWrapperElRef) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
|
||||
const targetRef = this.isLockPanRight ? this.blockLeftElRef : this.blockRightElRef;
|
||||
const targetRef = this.isLockPanRight
|
||||
? this.blockLeftElRef()
|
||||
: this.blockRightElRef();
|
||||
|
||||
const MAGIC_FACTOR = 2;
|
||||
this.isPreventPointerEventsWhilePanning = true;
|
||||
|
|
@ -720,7 +721,7 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
this._renderer.setStyle(targetRef.nativeElement, 'width', `${moveBy}px`);
|
||||
this._renderer.setStyle(targetRef.nativeElement, 'transition', `none`);
|
||||
this._renderer.setStyle(
|
||||
this.innerWrapperElRef.nativeElement,
|
||||
innerWrapperElRef.nativeElement,
|
||||
'transform',
|
||||
`translateX(${ev.deltaX}px`,
|
||||
);
|
||||
|
|
@ -728,11 +729,14 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
}
|
||||
|
||||
private _resetAfterPan(): void {
|
||||
const blockLeftElRef = this.blockLeftElRef();
|
||||
const blockRightElRef = this.blockRightElRef();
|
||||
const innerWrapperElRef = this.innerWrapperElRef();
|
||||
if (
|
||||
!this.taskTitleEditEl ||
|
||||
!this.blockLeftElRef ||
|
||||
!this.blockRightElRef ||
|
||||
!this.innerWrapperElRef
|
||||
!this.taskTitleEditEl() ||
|
||||
!blockLeftElRef ||
|
||||
!blockRightElRef ||
|
||||
!innerWrapperElRef
|
||||
) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
|
|
@ -744,9 +748,9 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
// const scale = 0;
|
||||
// this._renderer.setStyle(this.blockLeftEl.nativeElement, 'transform', `scaleX(${scale})`);
|
||||
// this._renderer.setStyle(this.blockRightEl.nativeElement, 'transform', `scaleX(${scale})`);
|
||||
this._renderer.removeClass(this.blockLeftElRef.nativeElement, 'isActive');
|
||||
this._renderer.removeClass(this.blockRightElRef.nativeElement, 'isActive');
|
||||
this._renderer.setStyle(this.innerWrapperElRef.nativeElement, 'transform', ``);
|
||||
this._renderer.removeClass(blockLeftElRef.nativeElement, 'isActive');
|
||||
this._renderer.removeClass(blockRightElRef.nativeElement, 'isActive');
|
||||
this._renderer.setStyle(innerWrapperElRef.nativeElement, 'transform', ``);
|
||||
}
|
||||
|
||||
get kb(): KeyboardConfig {
|
||||
|
|
@ -793,16 +797,18 @@ export class TaskComponent implements OnDestroy, AfterViewInit {
|
|||
this.addAttachment();
|
||||
}
|
||||
if (!t.parentId && checkKeyCombo(ev, keys.taskMoveToProject)) {
|
||||
if (!this.projectMenuTrigger) {
|
||||
const projectMenuTrigger = this.projectMenuTrigger();
|
||||
if (!projectMenuTrigger) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
this.projectMenuTrigger.openMenu();
|
||||
projectMenuTrigger.openMenu();
|
||||
}
|
||||
if (checkKeyCombo(ev, keys.taskOpenContextMenu)) {
|
||||
if (!this.taskContextMenu) {
|
||||
const taskContextMenu = this.taskContextMenu();
|
||||
if (!taskContextMenu) {
|
||||
throw new Error('No el');
|
||||
}
|
||||
this.taskContextMenu.open(ev, true);
|
||||
taskContextMenu.open(ev, true);
|
||||
}
|
||||
|
||||
if (checkKeyCombo(ev, keys.togglePlay)) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
Input,
|
||||
Output,
|
||||
Renderer2,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { fromEvent, Subscription } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
|
@ -32,7 +32,7 @@ export class SplitComponent implements AfterViewInit {
|
|||
|
||||
pos: number = 100;
|
||||
eventSubs?: Subscription;
|
||||
@ViewChild('buttonEl', { static: true }) buttonEl?: ElementRef;
|
||||
readonly buttonEl = viewChild<ElementRef>('buttonEl');
|
||||
private _isDrag: boolean = false;
|
||||
private _isViewInitialized: boolean = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ export class WorkViewComponent implements OnInit, OnDestroy, AfterContentInit {
|
|||
private _addTasksForTomorrowService: AddTasksForTomorrowService,
|
||||
) {}
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// Accessor queries cannot be migrated as they are too complex.
|
||||
@ViewChild('splitTopEl', { read: ElementRef }) set splitTopElRef(ref: ElementRef) {
|
||||
if (ref) {
|
||||
this.splitTopEl$.next(ref.nativeElement);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, viewChild } from '@angular/core';
|
||||
import { DataImportService } from '../sync/data-import.service';
|
||||
import { SnackService } from '../../core/snack/snack.service';
|
||||
import { AppDataComplete } from '../sync/sync.model';
|
||||
|
|
@ -16,7 +16,7 @@ import { privacyExport } from './privacy-export';
|
|||
standalone: false,
|
||||
})
|
||||
export class FileImexComponent {
|
||||
@ViewChild('fileInput', { static: true }) fileInputRef?: ElementRef;
|
||||
readonly fileInputRef = viewChild<ElementRef>('fileInput');
|
||||
T: typeof T = T;
|
||||
|
||||
constructor(
|
||||
|
|
@ -50,14 +50,15 @@ export class FileImexComponent {
|
|||
await this._dataImportService.importCompleteSyncData(data as AppDataComplete);
|
||||
}
|
||||
|
||||
if (!this.fileInputRef) {
|
||||
const fileInputRef = this.fileInputRef();
|
||||
if (!fileInputRef) {
|
||||
throw new Error('No file input Ref element');
|
||||
}
|
||||
|
||||
// clear input
|
||||
this.fileInputRef.nativeElement.value = '';
|
||||
this.fileInputRef.nativeElement.type = 'text';
|
||||
this.fileInputRef.nativeElement.type = 'file';
|
||||
fileInputRef.nativeElement.value = '';
|
||||
fileInputRef.nativeElement.type = 'text';
|
||||
fileInputRef.nativeElement.type = 'file';
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ export class BetterDrawerContainerComponent
|
|||
return this._isOver;
|
||||
}
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// Accessor queries cannot be migrated as they are too complex.
|
||||
@ViewChild('contentElRef', { read: ElementRef }) set setContentElRef(ref: ElementRef) {
|
||||
this.contentEl$.next(ref.nativeElement);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ export class BetterSimpleDrawerComponent implements OnInit, OnDestroy {
|
|||
return this._isOpen;
|
||||
}
|
||||
|
||||
// TODO: Skipped for migration because:
|
||||
// Accessor queries cannot be migrated as they are too complex.
|
||||
@ViewChild('contentElRef', { read: ElementRef }) set setContentElRef(ref: ElementRef) {
|
||||
this.contentEl$.next(ref.nativeElement);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
Input,
|
||||
OnDestroy,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { Observable } from 'rxjs';
|
||||
|
|
@ -56,8 +56,8 @@ export class ChipListInputComponent implements OnDestroy {
|
|||
inputCtrl: UntypedFormControl = new UntypedFormControl();
|
||||
separatorKeysCodes: number[] = DEFAULT_SEPARATOR_KEY_CODES;
|
||||
isAutoFocus = false;
|
||||
@ViewChild('inputElRef', { static: true }) inputEl?: ElementRef<HTMLInputElement>;
|
||||
@ViewChild('autoElRef', { static: true }) matAutocomplete?: MatAutocomplete;
|
||||
readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputElRef');
|
||||
readonly matAutocomplete = viewChild<MatAutocomplete>('autoElRef');
|
||||
private _modelIds: string[] = [];
|
||||
|
||||
filteredSuggestions: Observable<Suggestion[]> = this.inputCtrl.valueChanges.pipe(
|
||||
|
|
@ -77,7 +77,7 @@ export class ChipListInputComponent implements OnDestroy {
|
|||
if (typeof autoFocus === 'string') {
|
||||
this.isAutoFocus = true;
|
||||
this._autoFocusTimeout = window.setTimeout(() => {
|
||||
this.inputEl?.nativeElement.focus();
|
||||
this.inputEl()?.nativeElement.focus();
|
||||
// NOTE: we need to wait a little for the tag dialog to be there
|
||||
}, 300);
|
||||
}
|
||||
|
|
@ -100,11 +100,12 @@ export class ChipListInputComponent implements OnDestroy {
|
|||
}
|
||||
|
||||
add(event: MatChipInputEvent): void {
|
||||
if (!this.matAutocomplete) {
|
||||
const matAutocomplete = this.matAutocomplete();
|
||||
if (!matAutocomplete) {
|
||||
throw new Error('Auto complete undefined');
|
||||
}
|
||||
|
||||
if (!this.matAutocomplete.isOpen) {
|
||||
if (!matAutocomplete.isOpen) {
|
||||
const input = event.input;
|
||||
const value = event.value;
|
||||
|
||||
|
|
@ -125,8 +126,9 @@ export class ChipListInputComponent implements OnDestroy {
|
|||
|
||||
selected(event: MatAutocompleteSelectedEvent): void {
|
||||
this._add(event.option.value);
|
||||
if (this.inputEl) {
|
||||
this.inputEl.nativeElement.value = '';
|
||||
const inputEl = this.inputEl();
|
||||
if (inputEl) {
|
||||
inputEl.nativeElement.value = '';
|
||||
}
|
||||
this.inputCtrl.setValue(null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
input,
|
||||
OnInit,
|
||||
TemplateRef,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
MatMenu,
|
||||
|
|
@ -27,8 +27,9 @@ export class ContextMenuComponent implements OnInit {
|
|||
rightClickTriggerEl = input.required<HTMLElement | MatMenuItem | MatIconButton>();
|
||||
contextMenu = input.required<TemplateRef<any>>();
|
||||
|
||||
@ViewChild('contextMenuTriggerEl', { static: true, read: MatMenuTrigger })
|
||||
contextMenuTriggerEl!: MatMenuTrigger;
|
||||
readonly contextMenuTriggerEl = viewChild.required('contextMenuTriggerEl', {
|
||||
read: MatMenuTrigger,
|
||||
});
|
||||
contextMenuPosition: { x: string; y: string } = { x: '0px', y: '0px' };
|
||||
|
||||
ngOnInit(): void {
|
||||
|
|
@ -61,10 +62,11 @@ export class ContextMenuComponent implements OnInit {
|
|||
('touches' in event ? event.touches[0].clientX : event.clientX) + 'px';
|
||||
this.contextMenuPosition.y =
|
||||
('touches' in event ? event.touches[0].clientY : event.clientY) + 'px';
|
||||
this.contextMenuTriggerEl.menuData = {
|
||||
const contextMenuTriggerEl = this.contextMenuTriggerEl();
|
||||
contextMenuTriggerEl.menuData = {
|
||||
x: this.contextMenuPosition.x,
|
||||
y: this.contextMenuPosition.y,
|
||||
};
|
||||
this.contextMenuTriggerEl.openMenu();
|
||||
contextMenuTriggerEl.openMenu();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ChangeDetectionStrategy, Component, ElementRef, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, viewChild } from '@angular/core';
|
||||
import { FieldType } from '@ngx-formly/material';
|
||||
import { FormlyFieldConfig } from '@ngx-formly/core';
|
||||
import { stringToMs } from '../string-to-ms.pipe';
|
||||
|
|
@ -11,7 +11,7 @@ import { stringToMs } from '../string-to-ms.pipe';
|
|||
standalone: false,
|
||||
})
|
||||
export class InputDurationFormlyComponent extends FieldType<FormlyFieldConfig> {
|
||||
@ViewChild('inputEl', { static: true, read: ElementRef }) input!: ElementRef;
|
||||
readonly input = viewChild.required('inputEl', { read: ElementRef });
|
||||
|
||||
// @ViewChild(MatInput, {static: true}) formFieldControl?: MatInput;
|
||||
onInputValueChange(ev: Event): void {
|
||||
|
|
@ -30,10 +30,11 @@ export class InputDurationFormlyComponent extends FieldType<FormlyFieldConfig> {
|
|||
|
||||
private _updateValue(val: string): void {
|
||||
this.formControl.setValue(val ? stringToMs(val) : null);
|
||||
this.input.nativeElement.value = val;
|
||||
this.input().nativeElement.value = val;
|
||||
setTimeout(() => {
|
||||
if (this.input.nativeElement.value !== val) {
|
||||
this.input.nativeElement.value = val;
|
||||
const input = this.input();
|
||||
if (input.nativeElement.value !== val) {
|
||||
input.nativeElement.value = val;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { nanoid } from 'nanoid';
|
||||
import moment from 'moment';
|
||||
|
|
@ -34,7 +34,7 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
endHandler?: () => void;
|
||||
moveHandler?: (ev: any) => void;
|
||||
|
||||
@ViewChild('circleEl', { static: true }) circleEl?: ElementRef;
|
||||
readonly circleEl = viewChild<ElementRef>('circleEl');
|
||||
|
||||
@Input() label: string = '';
|
||||
@Output() modelChange: EventEmitter<number> = new EventEmitter();
|
||||
|
|
@ -57,7 +57,7 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
|
||||
ngOnInit(): void {
|
||||
this.startHandler = (ev) => {
|
||||
if (!this.endHandler || !this.moveHandler || !this.circleEl) {
|
||||
if (!this.endHandler || !this.moveHandler || !this.circleEl()) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +83,8 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
) {
|
||||
return;
|
||||
}
|
||||
if (!this.endHandler || !this.moveHandler || !this.circleEl) {
|
||||
const circleEl = this.circleEl();
|
||||
if (!this.endHandler || !this.moveHandler || !circleEl) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
|
|
@ -92,8 +93,8 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
|
||||
const convertThetaToCssDegrees = (thetaIN: number): number => 90 - thetaIN;
|
||||
|
||||
const centerX = this.circleEl.nativeElement.offsetWidth / 2;
|
||||
const centerY = this.circleEl.nativeElement.offsetHeight / 2;
|
||||
const centerX = circleEl.nativeElement.offsetWidth / 2;
|
||||
const centerY = circleEl.nativeElement.offsetHeight / 2;
|
||||
|
||||
let offsetX;
|
||||
|
||||
|
|
@ -117,7 +118,7 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
};
|
||||
|
||||
this.endHandler = () => {
|
||||
if (!this.endHandler || !this.moveHandler || !this.circleEl) {
|
||||
if (!this.endHandler || !this.moveHandler || !this.circleEl()) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +139,7 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!this.endHandler || !this.moveHandler || !this.startHandler || !this.circleEl) {
|
||||
if (!this.endHandler || !this.moveHandler || !this.startHandler || !this.circleEl()) {
|
||||
throw new Error();
|
||||
}
|
||||
|
||||
|
|
@ -154,10 +155,11 @@ export class InputDurationSliderComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
setCircleRotation(cssDegrees: number): void {
|
||||
if (!this.circleEl) {
|
||||
const circleEl = this.circleEl();
|
||||
if (!circleEl) {
|
||||
throw new Error();
|
||||
}
|
||||
this.circleEl.nativeElement.style.transform = 'rotate(' + cssDegrees + 'deg)';
|
||||
circleEl.nativeElement.style.transform = 'rotate(' + cssDegrees + 'deg)';
|
||||
}
|
||||
|
||||
setDots(hours: number = 0): void {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ElementRef,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { FieldType } from '@ngx-formly/core';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
|
@ -21,7 +21,7 @@ export class FormlyTranslatedTemplateComponent
|
|||
extends FieldType
|
||||
implements OnInit, OnDestroy
|
||||
{
|
||||
@ViewChild('tplWrapper', { static: true }) tplWrapper?: ElementRef;
|
||||
readonly tplWrapper = viewChild<ElementRef>('tplWrapper');
|
||||
|
||||
private _el?: HTMLElement;
|
||||
private _subs: Subscription = new Subscription();
|
||||
|
|
@ -54,11 +54,12 @@ export class FormlyTranslatedTemplateComponent
|
|||
}
|
||||
|
||||
private _createTag(): void {
|
||||
if (!this.field.templateOptions || !this.tplWrapper) {
|
||||
const tplWrapper = this.tplWrapper();
|
||||
if (!this.field.templateOptions || !tplWrapper) {
|
||||
throw new Error();
|
||||
}
|
||||
const tag = this.field.templateOptions.tag || 'div';
|
||||
const tplWrapperEl = this.tplWrapper.nativeElement;
|
||||
const tplWrapperEl = tplWrapper.nativeElement;
|
||||
|
||||
if (tplWrapperEl) {
|
||||
this._el = document.createElement(tag);
|
||||
|
|
@ -67,7 +68,7 @@ export class FormlyTranslatedTemplateComponent
|
|||
(this._el as HTMLElement).classList.add(this.field.templateOptions.class);
|
||||
}
|
||||
|
||||
this.tplWrapper.nativeElement.append(this._el);
|
||||
tplWrapper.nativeElement.append(this._el);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
HostBinding,
|
||||
Input,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
|
|
@ -24,8 +24,8 @@ export class InlineInputComponent implements AfterViewInit {
|
|||
@Input() newValue?: string | number;
|
||||
|
||||
@Output() changed: EventEmitter<string | number> = new EventEmitter();
|
||||
@ViewChild('inputEl') inputEl?: ElementRef;
|
||||
@ViewChild('inputElDuration') inputElDuration?: ElementRef;
|
||||
readonly inputEl = viewChild<ElementRef>('inputEl');
|
||||
readonly inputElDuration = viewChild<ElementRef>('inputElDuration');
|
||||
|
||||
@HostBinding('class.isFocused') isFocused: boolean = false;
|
||||
|
||||
|
|
@ -36,15 +36,15 @@ export class InlineInputComponent implements AfterViewInit {
|
|||
ngAfterViewInit(): void {
|
||||
this.activeInputEl =
|
||||
this.type === 'duration'
|
||||
? (this.inputElDuration as ElementRef).nativeElement
|
||||
: (this.inputEl as ElementRef).nativeElement;
|
||||
? (this.inputElDuration() as ElementRef).nativeElement
|
||||
: (this.inputEl() as ElementRef).nativeElement;
|
||||
}
|
||||
|
||||
focusInput(): void {
|
||||
this.activeInputEl =
|
||||
this.type === 'duration'
|
||||
? (this.inputElDuration as ElementRef).nativeElement
|
||||
: (this.inputEl as ElementRef).nativeElement;
|
||||
? (this.inputElDuration() as ElementRef).nativeElement
|
||||
: (this.inputEl() as ElementRef).nativeElement;
|
||||
|
||||
this.isFocused = true;
|
||||
(this.activeInputEl as HTMLElement).focus();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
OnDestroy,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { fadeAnimation } from '../animations/fade.ani';
|
||||
import { MarkdownComponent } from 'ngx-markdown';
|
||||
|
|
@ -40,9 +40,9 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
@Output() focused: EventEmitter<Event> = new EventEmitter();
|
||||
@Output() blurred: EventEmitter<Event> = new EventEmitter();
|
||||
@Output() keyboardUnToggle: EventEmitter<Event> = new EventEmitter();
|
||||
@ViewChild('wrapperEl', { static: true }) wrapperEl: ElementRef | undefined;
|
||||
@ViewChild('textareaEl') textareaEl: ElementRef | undefined;
|
||||
@ViewChild('previewEl') previewEl: MarkdownComponent | undefined;
|
||||
readonly wrapperEl = viewChild<ElementRef>('wrapperEl');
|
||||
readonly textareaEl = viewChild<ElementRef>('textareaEl');
|
||||
readonly previewEl = viewChild<MarkdownComponent>('previewEl');
|
||||
|
||||
isHideOverflow: boolean = false;
|
||||
isChecklistMode: boolean = false;
|
||||
|
|
@ -144,10 +144,11 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
this.resizeParsedToFit();
|
||||
this.isShowEdit = false;
|
||||
}
|
||||
if (!this.textareaEl) {
|
||||
const textareaEl = this.textareaEl();
|
||||
if (!textareaEl) {
|
||||
throw new Error('Textarea not visible');
|
||||
}
|
||||
this.modelCopy = this.textareaEl.nativeElement.value;
|
||||
this.modelCopy = textareaEl.nativeElement.value;
|
||||
|
||||
if (this.modelCopy !== this.model) {
|
||||
this.model = this.modelCopy;
|
||||
|
|
@ -157,17 +158,17 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
|
||||
resizeTextareaToFit(): void {
|
||||
this._hideOverflow();
|
||||
if (!this.textareaEl) {
|
||||
const textareaEl = this.textareaEl();
|
||||
if (!textareaEl) {
|
||||
throw new Error('Textarea not visible');
|
||||
}
|
||||
if (!this.wrapperEl) {
|
||||
const wrapperEl = this.wrapperEl();
|
||||
if (!wrapperEl) {
|
||||
throw new Error('Wrapper el not visible');
|
||||
}
|
||||
this.textareaEl.nativeElement.style.height = 'auto';
|
||||
this.textareaEl.nativeElement.style.height =
|
||||
this.textareaEl.nativeElement.scrollHeight + 'px';
|
||||
this.wrapperEl.nativeElement.style.height =
|
||||
this.textareaEl.nativeElement.offsetHeight + 'px';
|
||||
textareaEl.nativeElement.style.height = 'auto';
|
||||
textareaEl.nativeElement.style.height = textareaEl.nativeElement.scrollHeight + 'px';
|
||||
wrapperEl.nativeElement.style.height = textareaEl.nativeElement.offsetHeight + 'px';
|
||||
}
|
||||
|
||||
openFullScreen(): void {
|
||||
|
|
@ -193,20 +194,22 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
this._hideOverflow();
|
||||
|
||||
setTimeout(() => {
|
||||
if (!this.previewEl) {
|
||||
if (this.textareaEl) {
|
||||
const previewEl = this.previewEl();
|
||||
if (!previewEl) {
|
||||
if (this.textareaEl()) {
|
||||
this.resizeTextareaToFit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!this.wrapperEl) {
|
||||
const wrapperEl = this.wrapperEl();
|
||||
if (!wrapperEl) {
|
||||
throw new Error('Wrapper el not visible');
|
||||
}
|
||||
this.previewEl.element.nativeElement.style.height = 'auto';
|
||||
previewEl.element.nativeElement.style.height = 'auto';
|
||||
// NOTE: somehow this pixel seem to help
|
||||
this.wrapperEl.nativeElement.style.height =
|
||||
this.previewEl.element.nativeElement.offsetHeight + 'px';
|
||||
this.previewEl.element.nativeElement.style.height = '';
|
||||
wrapperEl.nativeElement.style.height =
|
||||
previewEl.element.nativeElement.offsetHeight + 'px';
|
||||
previewEl.element.nativeElement.style.height = '';
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -234,11 +237,12 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
this.isShowEdit = true;
|
||||
this.modelCopy = this.model || '';
|
||||
setTimeout(() => {
|
||||
if (!this.textareaEl) {
|
||||
const textareaEl = this.textareaEl();
|
||||
if (!textareaEl) {
|
||||
throw new Error('Textarea not visible');
|
||||
}
|
||||
this.textareaEl.nativeElement.value = this.modelCopy;
|
||||
this.textareaEl.nativeElement.focus();
|
||||
textareaEl.nativeElement.value = this.modelCopy;
|
||||
textareaEl.nativeElement.focus();
|
||||
this.resizeTextareaToFit();
|
||||
});
|
||||
}
|
||||
|
|
@ -256,10 +260,11 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
private _makeLinksWorkForElectron(): void {
|
||||
if (!this.wrapperEl) {
|
||||
const wrapperEl = this.wrapperEl();
|
||||
if (!wrapperEl) {
|
||||
throw new Error('Wrapper el not visible');
|
||||
}
|
||||
this.wrapperEl.nativeElement.addEventListener('click', (ev: MouseEvent) => {
|
||||
wrapperEl.nativeElement.addEventListener('click', (ev: MouseEvent) => {
|
||||
const target = ev.target as HTMLElement;
|
||||
if (target.tagName && target.tagName.toLowerCase() === 'a') {
|
||||
const href = target.getAttribute('href');
|
||||
|
|
@ -273,7 +278,7 @@ export class InlineMarkdownComponent implements OnInit, OnDestroy {
|
|||
|
||||
private _handleCheckboxClick(targetEl: HTMLElement): void {
|
||||
const allCheckboxes =
|
||||
this.previewEl?.element.nativeElement.querySelectorAll('.checkbox-wrapper');
|
||||
this.previewEl()?.element.nativeElement.querySelectorAll('.checkbox-wrapper');
|
||||
|
||||
const checkIndex = Array.from(allCheckboxes || []).findIndex((el) => el === targetEl);
|
||||
if (checkIndex !== -1 && this._model) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
HostBinding,
|
||||
Input,
|
||||
Output,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { T } from 'src/app/t.const';
|
||||
|
|
@ -47,7 +47,8 @@ export class InlineMultilineInputComponent {
|
|||
lastExternalValue?: string;
|
||||
tmpValue?: string;
|
||||
|
||||
@ViewChild('textAreaElement') textarea!: ElementRef<HTMLTextAreaElement>;
|
||||
readonly textarea =
|
||||
viewChild.required<ElementRef<HTMLTextAreaElement>>('textAreaElement');
|
||||
|
||||
@Output() valueEdited = new EventEmitter<{
|
||||
newVal: string;
|
||||
|
|
@ -78,7 +79,7 @@ export class InlineMultilineInputComponent {
|
|||
this._setTxtHeight();
|
||||
try {
|
||||
window.setTimeout(() => {
|
||||
const el = this.textarea.nativeElement;
|
||||
const el = this.textarea().nativeElement;
|
||||
el.setSelectionRange(el.value.length, el.value.length);
|
||||
el.selectionStart = el.selectionEnd = el.value.length;
|
||||
});
|
||||
|
|
@ -124,7 +125,7 @@ export class InlineMultilineInputComponent {
|
|||
}
|
||||
|
||||
private _forceBlur(): void {
|
||||
this.textarea.nativeElement.blur();
|
||||
this.textarea().nativeElement.blur();
|
||||
}
|
||||
|
||||
private _submit(): void {
|
||||
|
|
@ -153,15 +154,15 @@ export class InlineMultilineInputComponent {
|
|||
private _setTxtHeight(): void {
|
||||
try {
|
||||
// reset height
|
||||
this.textarea.nativeElement.style.height = 'auto';
|
||||
this.textarea.nativeElement.style.height =
|
||||
this.textarea.nativeElement.scrollHeight + 'px';
|
||||
const textarea = this.textarea();
|
||||
textarea.nativeElement.style.height = 'auto';
|
||||
textarea.nativeElement.style.height = textarea.nativeElement.scrollHeight + 'px';
|
||||
} catch (e) {
|
||||
setTimeout(() => {
|
||||
// reset height
|
||||
this.textarea.nativeElement.style.height = 'auto';
|
||||
this.textarea.nativeElement.style.height =
|
||||
this.textarea.nativeElement.scrollHeight + 'px';
|
||||
const textarea = this.textarea();
|
||||
textarea.nativeElement.style.height = 'auto';
|
||||
textarea.nativeElement.style.height = textarea.nativeElement.scrollHeight + 'px';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
ElementRef,
|
||||
Input,
|
||||
Renderer2,
|
||||
ViewChild,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
|
|
@ -16,21 +16,22 @@ import {
|
|||
})
|
||||
export class ProgressCircleComponent {
|
||||
@Input() set progress(progressIN: number) {
|
||||
if (this.progressCircle) {
|
||||
const progressCircle = this.progressCircle();
|
||||
if (progressCircle) {
|
||||
let progress = progressIN || 0;
|
||||
if (progress > 100) {
|
||||
progress = 100;
|
||||
}
|
||||
|
||||
this._renderer.setStyle(
|
||||
this.progressCircle.nativeElement,
|
||||
progressCircle.nativeElement,
|
||||
'stroke-dasharray',
|
||||
`${progress} ,100`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ViewChild('progressCircle', { static: true }) progressCircle?: ElementRef;
|
||||
readonly progressCircle = viewChild<ElementRef>('progressCircle');
|
||||
|
||||
constructor(private readonly _renderer: Renderer2) {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue