mirror of
https://github.com/johannesjo/super-productivity.git
synced 2026-01-23 02:36:05 +00:00
refactor: improve typing
This commit is contained in:
parent
a00bb80ff3
commit
f649734de4
9 changed files with 162 additions and 91 deletions
|
|
@ -38,7 +38,7 @@ import {
|
|||
*/
|
||||
export class PluginAPI implements PluginAPIInterface {
|
||||
readonly Hooks = PluginHooks;
|
||||
private _hookHandlers = new Map<string, Map<Hooks, Array<PluginHookHandler<any>>>>();
|
||||
private _hookHandlers = new Map<string, Map<Hooks, Array<PluginHookHandler<Hooks>>>>();
|
||||
private _headerButtons: Array<PluginHeaderBtnCfg> = [];
|
||||
private _menuEntries: Array<PluginMenuEntryCfg> = [];
|
||||
private _shortcuts: Array<PluginShortcutCfg> = [];
|
||||
|
|
@ -89,11 +89,11 @@ export class PluginAPI implements PluginAPIInterface {
|
|||
pluginHooks.set(hook, []);
|
||||
}
|
||||
|
||||
pluginHooks.get(hook)!.push(fn as PluginHookHandler<any>);
|
||||
pluginHooks.get(hook)!.push(fn as PluginHookHandler<Hooks>);
|
||||
PluginLog.log(`Plugin ${this._pluginId} registered hook: ${hook}`);
|
||||
|
||||
// Register hook with bridge
|
||||
this._pluginBridge.registerHook(this._pluginId, hook, fn as PluginHookHandler<any>);
|
||||
this._pluginBridge.registerHook(this._pluginId, hook, fn as PluginHookHandler<Hooks>);
|
||||
}
|
||||
|
||||
registerHeaderButton(headerBtnCfg: PluginHeaderBtnCfg): void {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { ActionReducerMap } from '@ngrx/store';
|
||||
import { RootState } from './root-state';
|
||||
|
||||
export const reducers: ActionReducerMap<any> = {
|
||||
export const reducers: Partial<ActionReducerMap<RootState>> = {
|
||||
// test: (state, action) => {
|
||||
// Log.log(state, action);
|
||||
// return state;
|
||||
|
|
|
|||
|
|
@ -51,11 +51,21 @@ const properties = [
|
|||
const isBrowser = typeof window !== 'undefined';
|
||||
const isFirefox = isBrowser && window['mozInnerScreenX'] != null;
|
||||
|
||||
interface CaretCoordinatesOptions {
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
interface CaretCoordinates {
|
||||
top: number;
|
||||
left: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export const getCaretCoordinates = (
|
||||
element: any,
|
||||
element: HTMLTextAreaElement | HTMLInputElement,
|
||||
position: number,
|
||||
options: any,
|
||||
): any => {
|
||||
options?: CaretCoordinatesOptions,
|
||||
): CaretCoordinates => {
|
||||
if (!isBrowser) {
|
||||
throw new Error(
|
||||
'textarea-caret-position#getCaretCoordinates should only be called in a browser',
|
||||
|
|
@ -76,7 +86,7 @@ export const getCaretCoordinates = (
|
|||
const style = div.style;
|
||||
const computed = window.getComputedStyle
|
||||
? window.getComputedStyle(element)
|
||||
: element.currentStyle; // currentStyle for IE < 9
|
||||
: (element as any).currentStyle; // currentStyle for IE < 9
|
||||
const isInput = element.nodeName === 'INPUT';
|
||||
|
||||
// Default textarea styles
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
// configuration structure, backwards compatible with earlier versions
|
||||
|
||||
export interface MentionConfig extends Mentions {
|
||||
export interface MentionItem {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface MentionConfig<T = MentionItem> extends Mentions<T> {
|
||||
// nested config
|
||||
mentions?: Mentions[];
|
||||
mentions?: Mentions<T>[];
|
||||
|
||||
// option to disable encapsulated styles so global styles can be used instead
|
||||
disableStyle?: boolean;
|
||||
}
|
||||
|
||||
export interface Mentions {
|
||||
export interface Mentions<T = MentionItem> {
|
||||
// an array of strings or objects to suggest
|
||||
items?: any[];
|
||||
items?: T[] | string[];
|
||||
|
||||
// the character that will trigger the menu behavior
|
||||
triggerChar?: string;
|
||||
|
|
@ -38,8 +42,8 @@ export interface Mentions {
|
|||
returnTrigger?: boolean;
|
||||
|
||||
// optional function to format the selected item before inserting the text
|
||||
mentionSelect?: (item: any, triggerChar?: string) => string;
|
||||
mentionSelect?: (item: T | string, triggerChar?: string) => string;
|
||||
|
||||
// optional function to customize the search implementation
|
||||
mentionFilter?: (searchString: string, items?: any) => any[];
|
||||
mentionFilter?: (searchString: string, items?: T[] | string[]) => T[] | string[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { CommonModule } from '@angular/common';
|
|||
|
||||
import { isInputOrTextAreaElement, getContentEditableCaretCoords } from './mention-utils';
|
||||
import { getCaretCoordinates } from './caret-coords';
|
||||
import { MentionItem } from './mention-config';
|
||||
import { Log } from '../../core/log';
|
||||
|
||||
/**
|
||||
|
|
@ -61,12 +62,12 @@ import { Log } from '../../core/log';
|
|||
})
|
||||
export class MentionListComponent implements AfterContentChecked {
|
||||
@Input() labelKey: string = 'label';
|
||||
@Input() itemTemplate?: TemplateRef<any>;
|
||||
@Input() itemTemplate?: TemplateRef<{ $implicit: MentionItem; index: number }>;
|
||||
@Output() itemClick = new EventEmitter();
|
||||
@ViewChild('list', { static: true }) list!: ElementRef;
|
||||
@ViewChild('defaultItemTemplate', { static: true })
|
||||
defaultItemTemplate!: TemplateRef<any>;
|
||||
items = [];
|
||||
defaultItemTemplate!: TemplateRef<{ $implicit: MentionItem; index: number }>;
|
||||
items: MentionItem[] | string[] = [];
|
||||
activeIndex: number = 0;
|
||||
hidden: boolean = false;
|
||||
dropUp: boolean = false;
|
||||
|
|
@ -91,7 +92,7 @@ export class MentionListComponent implements AfterContentChecked {
|
|||
this.coords = getCaretCoordinates(
|
||||
nativeParentElement,
|
||||
nativeParentElement.selectionStart || 0,
|
||||
null,
|
||||
undefined,
|
||||
);
|
||||
this.coords.top =
|
||||
nativeParentElement.offsetTop + this.coords.top - nativeParentElement.scrollTop;
|
||||
|
|
@ -133,7 +134,7 @@ export class MentionListComponent implements AfterContentChecked {
|
|||
this.positionElement();
|
||||
}
|
||||
|
||||
get activeItem(): any {
|
||||
get activeItem(): MentionItem | string | null {
|
||||
// Add bounds checking to prevent accessing undefined array elements
|
||||
if (!this.items || !Array.isArray(this.items) || this.items.length === 0) {
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// DOM element manipulation functions...
|
||||
//
|
||||
|
||||
const setValue = (el: HTMLInputElement, value: any): void => {
|
||||
const setValue = (el: HTMLInputElement, value: string): void => {
|
||||
//console.log("setValue", el.nodeName, "["+value+"]");
|
||||
if (isInputOrTextAreaElement(el)) {
|
||||
el.value = value;
|
||||
|
|
|
|||
|
|
@ -20,10 +20,20 @@ import {
|
|||
isInputOrTextAreaElement,
|
||||
} from './mention-utils';
|
||||
|
||||
import { MentionConfig } from './mention-config';
|
||||
import { MentionConfig, MentionItem } from './mention-config';
|
||||
import { MentionListComponent } from './mention-list.component';
|
||||
import { Log } from '../../core/log';
|
||||
|
||||
// Custom types for mention events
|
||||
interface CustomEvent extends Event {
|
||||
wasClick?: boolean;
|
||||
}
|
||||
|
||||
interface CustomKeyboardEvent extends KeyboardEvent {
|
||||
inputEvent?: boolean;
|
||||
wasClick?: boolean;
|
||||
}
|
||||
|
||||
const KEY_BACKSPACE = 8;
|
||||
const KEY_TAB = 9;
|
||||
const KEY_ENTER = 13;
|
||||
|
|
@ -55,9 +65,9 @@ const KEY_BUFFERED = 229;
|
|||
})
|
||||
export class MentionDirective implements OnChanges {
|
||||
// stores the items passed to the mentions directive and used to populate the root items in mentionConfig
|
||||
private mentionItems: any[] = [];
|
||||
private mentionItems: MentionItem[] | string[] = [];
|
||||
|
||||
@Input('mention') set mention(items: any[]) {
|
||||
@Input('mention') set mention(items: MentionItem[] | string[]) {
|
||||
this.mentionItems = items;
|
||||
}
|
||||
|
||||
|
|
@ -73,13 +83,19 @@ export class MentionDirective implements OnChanges {
|
|||
maxItems: -1,
|
||||
allowSpace: false,
|
||||
returnTrigger: false,
|
||||
mentionSelect: (item: any, triggerChar?: string) => {
|
||||
mentionSelect: (item: MentionItem | string, triggerChar?: string) => {
|
||||
// Add defensive null/undefined checks to prevent TypeError
|
||||
if (!item) {
|
||||
Log.warn('MentionDirective: mentionSelect called with undefined/null item');
|
||||
return this.activeConfig?.triggerChar || '';
|
||||
}
|
||||
|
||||
// Handle string items directly
|
||||
if (typeof item === 'string') {
|
||||
return (this.activeConfig?.triggerChar || '') + item;
|
||||
}
|
||||
|
||||
// Handle MentionItem objects
|
||||
const labelKey = this.activeConfig?.labelKey || 'label';
|
||||
const itemValue = item[labelKey];
|
||||
|
||||
|
|
@ -90,7 +106,7 @@ export class MentionDirective implements OnChanges {
|
|||
|
||||
return (this.activeConfig?.triggerChar || '') + itemValue;
|
||||
},
|
||||
mentionFilter: (searchString: string, items: any[]) => {
|
||||
mentionFilter: (searchString: string, items?: MentionItem[] | string[]) => {
|
||||
if (!items || !Array.isArray(items)) {
|
||||
Log.warn('MentionDirective: mentionFilter called with invalid items array');
|
||||
return [];
|
||||
|
|
@ -99,34 +115,46 @@ export class MentionDirective implements OnChanges {
|
|||
const searchStringLowerCase = searchString.toLowerCase();
|
||||
const labelKey = this.activeConfig?.labelKey || 'label';
|
||||
|
||||
return items.filter((e) => {
|
||||
const filteredItems = items.filter((e: MentionItem | string) => {
|
||||
// Add defensive checks to prevent errors during filtering
|
||||
if (!e || typeof e !== 'object') {
|
||||
if (!e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const itemValue = e[labelKey];
|
||||
if (
|
||||
itemValue === undefined ||
|
||||
itemValue === null ||
|
||||
typeof itemValue !== 'string'
|
||||
) {
|
||||
return false;
|
||||
// Handle string items directly
|
||||
if (typeof e === 'string') {
|
||||
return e.toLowerCase().startsWith(searchStringLowerCase);
|
||||
}
|
||||
|
||||
return itemValue.toLowerCase().startsWith(searchStringLowerCase);
|
||||
// Handle MentionItem objects
|
||||
if (typeof e === 'object') {
|
||||
const itemValue = e[labelKey];
|
||||
if (
|
||||
itemValue === undefined ||
|
||||
itemValue === null ||
|
||||
typeof itemValue !== 'string'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return itemValue.toLowerCase().startsWith(searchStringLowerCase);
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
// Return the same type as the input array
|
||||
return filteredItems as typeof items;
|
||||
},
|
||||
};
|
||||
|
||||
// template to use for rendering list items
|
||||
@Input() mentionListTemplate?: TemplateRef<any>;
|
||||
@Input() mentionListTemplate?: TemplateRef<{ $implicit: MentionItem; index: number }>;
|
||||
|
||||
// event emitted whenever the search term changes
|
||||
@Output() searchTerm = new EventEmitter<string>();
|
||||
|
||||
// event emitted when an item is selected
|
||||
@Output() itemSelected = new EventEmitter<any>();
|
||||
@Output() itemSelected = new EventEmitter<MentionItem | string>();
|
||||
|
||||
// event emitted whenever the mention list is opened or closed
|
||||
@Output() opened = new EventEmitter();
|
||||
|
|
@ -137,10 +165,10 @@ export class MentionDirective implements OnChanges {
|
|||
|
||||
private searchString: string | null = null;
|
||||
private startPos: number = -1;
|
||||
private startNode: any;
|
||||
private startNode: Node | null = null;
|
||||
private searchList?: MentionListComponent;
|
||||
private searching: boolean = false;
|
||||
private iframe: any; // optional
|
||||
private iframe: HTMLIFrameElement | null = null; // optional
|
||||
private lastKeyCode: number = 0;
|
||||
|
||||
private readonly _element = inject(ElementRef);
|
||||
|
|
@ -178,17 +206,19 @@ export class MentionDirective implements OnChanges {
|
|||
if (items && items.length > 0) {
|
||||
// convert strings to objects
|
||||
if (typeof items[0] == 'string') {
|
||||
items = items.map((label) => {
|
||||
const object: any = {};
|
||||
items = (items as string[]).map((label) => {
|
||||
const object: Record<string, unknown> = {};
|
||||
object[config.labelKey || 'label'] = label;
|
||||
return object;
|
||||
});
|
||||
}
|
||||
if (config.labelKey) {
|
||||
// remove items without an labelKey (as it's required to filter the list)
|
||||
items = items.filter((e) => e[config.labelKey!]);
|
||||
items = (items as MentionItem[]).filter((e) => e[config.labelKey!]);
|
||||
if (!config.disableSort) {
|
||||
items.sort((a, b) => a[config.labelKey!].localeCompare(b[config.labelKey!]));
|
||||
(items as MentionItem[]).sort((a, b) =>
|
||||
String(a[config.labelKey!]).localeCompare(String(b[config.labelKey!])),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +238,7 @@ export class MentionDirective implements OnChanges {
|
|||
this.iframe = iframe;
|
||||
}
|
||||
|
||||
stopEvent(event: any): void {
|
||||
stopEvent(event: CustomEvent): void {
|
||||
//if (event instanceof KeyboardEvent) { // does not work for iframe
|
||||
if (!event.wasClick) {
|
||||
event.preventDefault();
|
||||
|
|
@ -217,24 +247,27 @@ export class MentionDirective implements OnChanges {
|
|||
}
|
||||
}
|
||||
|
||||
blurHandler(event: any): void {
|
||||
blurHandler(event: FocusEvent): void {
|
||||
this.stopEvent(event);
|
||||
this.stopSearch();
|
||||
}
|
||||
|
||||
inputHandler(
|
||||
event: any,
|
||||
event: InputEvent,
|
||||
nativeElement: HTMLInputElement = this._element.nativeElement,
|
||||
): void {
|
||||
if (this.lastKeyCode === KEY_BUFFERED && event.data) {
|
||||
const keyCode = event.data.charCodeAt(0);
|
||||
this.keyHandler({ keyCode, inputEvent: true }, nativeElement);
|
||||
this.keyHandler(
|
||||
{ keyCode, inputEvent: true } as CustomKeyboardEvent,
|
||||
nativeElement,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// @param nativeElement is the alternative text element in an iframe scenario
|
||||
keyHandler(
|
||||
event: any,
|
||||
event: CustomKeyboardEvent,
|
||||
nativeElement: HTMLInputElement = this._element.nativeElement,
|
||||
): boolean | undefined {
|
||||
this.lastKeyCode = event.keyCode;
|
||||
|
|
@ -270,7 +303,9 @@ export class MentionDirective implements OnChanges {
|
|||
const typedLen = 1 + (this.searchString ? this.searchString.length : 0); // trigger + search
|
||||
pos = this.startPos + typedLen;
|
||||
setCaretPosition(
|
||||
isInputOrTextAreaElement(nativeElement) ? nativeElement : (this.startNode as any),
|
||||
isInputOrTextAreaElement(nativeElement)
|
||||
? nativeElement
|
||||
: (this.startNode as HTMLInputElement),
|
||||
pos,
|
||||
this.iframe,
|
||||
);
|
||||
|
|
@ -281,9 +316,9 @@ export class MentionDirective implements OnChanges {
|
|||
if (config) {
|
||||
this.activeConfig = config;
|
||||
this.startPos = event.inputEvent ? pos - 1 : pos;
|
||||
this.startNode = (
|
||||
this.iframe ? this.iframe.contentWindow.getSelection() : window.getSelection()
|
||||
).anchorNode;
|
||||
this.startNode =
|
||||
(this.iframe ? this.iframe.contentWindow?.getSelection() : window.getSelection())
|
||||
?.anchorNode || null;
|
||||
this.searching = true;
|
||||
this.searchString = null;
|
||||
this.showSearchList(nativeElement);
|
||||
|
|
@ -329,31 +364,34 @@ export class MentionDirective implements OnChanges {
|
|||
}
|
||||
|
||||
// emit the selected list item
|
||||
this.itemSelected.emit(this.searchList.activeItem);
|
||||
// optional function to format the selected item before inserting the text
|
||||
const text = this.activeConfig!.mentionSelect!(
|
||||
this.searchList.activeItem,
|
||||
this.activeConfig!.triggerChar,
|
||||
);
|
||||
// value is inserted without a trailing space for consistency
|
||||
// between element types (div and iframe do not preserve the space)
|
||||
insertValue(nativeElement, this.startPos, pos, text, this.iframe);
|
||||
// fire input event so angular bindings are updated
|
||||
if ('createEvent' in document) {
|
||||
const evt = document.createEvent('HTMLEvents');
|
||||
if (this.iframe) {
|
||||
// a 'change' event is required to trigger tinymce updates
|
||||
evt.initEvent('change', true, false);
|
||||
} else {
|
||||
evt.initEvent('input', true, false);
|
||||
const activeItem = this.searchList.activeItem;
|
||||
if (activeItem) {
|
||||
this.itemSelected.emit(activeItem);
|
||||
// optional function to format the selected item before inserting the text
|
||||
const text = this.activeConfig!.mentionSelect!(
|
||||
activeItem,
|
||||
this.activeConfig!.triggerChar,
|
||||
);
|
||||
// value is inserted without a trailing space for consistency
|
||||
// between element types (div and iframe do not preserve the space)
|
||||
insertValue(nativeElement, this.startPos, pos, text, this.iframe);
|
||||
// fire input event so angular bindings are updated
|
||||
if ('createEvent' in document) {
|
||||
const evt = document.createEvent('HTMLEvents');
|
||||
if (this.iframe) {
|
||||
// a 'change' event is required to trigger tinymce updates
|
||||
evt.initEvent('change', true, false);
|
||||
} else {
|
||||
evt.initEvent('input', true, false);
|
||||
}
|
||||
// this seems backwards, but fire the event from this elements nativeElement (not the
|
||||
// one provided that may be in an iframe, as it won't be propogate)
|
||||
this._element.nativeElement.dispatchEvent(evt);
|
||||
}
|
||||
// this seems backwards, but fire the event from this elements nativeElement (not the
|
||||
// one provided that may be in an iframe, as it won't be propogate)
|
||||
this._element.nativeElement.dispatchEvent(evt);
|
||||
this.startPos = -1;
|
||||
this.stopSearch();
|
||||
return false;
|
||||
}
|
||||
this.startPos = -1;
|
||||
this.stopSearch();
|
||||
return false;
|
||||
} else if (event.keyCode === KEY_ESCAPE) {
|
||||
this.stopEvent(event);
|
||||
this.stopSearch();
|
||||
|
|
@ -406,7 +444,10 @@ export class MentionDirective implements OnChanges {
|
|||
'@';
|
||||
const pos = getCaretPosition(nativeElement, this.iframe);
|
||||
insertValue(nativeElement, pos, pos, triggerChar, this.iframe);
|
||||
this.keyHandler({ key: triggerChar, inputEvent: true }, nativeElement);
|
||||
this.keyHandler(
|
||||
{ key: triggerChar, inputEvent: true } as CustomKeyboardEvent,
|
||||
nativeElement,
|
||||
);
|
||||
}
|
||||
|
||||
stopSearch(): void {
|
||||
|
|
@ -420,7 +461,7 @@ export class MentionDirective implements OnChanges {
|
|||
}
|
||||
|
||||
updateSearchList(): void {
|
||||
let matches: any[] = [];
|
||||
let matches: MentionItem[] | string[] = [];
|
||||
if (this.activeConfig && this.activeConfig.items) {
|
||||
let objects = this.activeConfig.items;
|
||||
// disabling the search relies on the async operation to do the filtering
|
||||
|
|
@ -444,7 +485,7 @@ export class MentionDirective implements OnChanges {
|
|||
}
|
||||
// update the search list
|
||||
if (this.searchList) {
|
||||
this.searchList.items = matches as any;
|
||||
this.searchList.items = matches;
|
||||
this.searchList.hidden = matches.length == 0;
|
||||
this.listShownChange.emit(matches.length > 0);
|
||||
}
|
||||
|
|
@ -462,7 +503,11 @@ export class MentionDirective implements OnChanges {
|
|||
this.searchList.itemTemplate = this.mentionListTemplate;
|
||||
componentRef.instance['itemClick'].subscribe(() => {
|
||||
nativeElement.focus();
|
||||
const fakeKeydown = { key: 'Enter', keyCode: KEY_ENTER, wasClick: true };
|
||||
const fakeKeydown = {
|
||||
key: 'Enter',
|
||||
keyCode: KEY_ENTER,
|
||||
wasClick: true,
|
||||
} as CustomKeyboardEvent;
|
||||
this.keyHandler(fakeKeydown, nativeElement);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import {
|
|||
} from '@angular/router';
|
||||
import { APP_ROUTES } from './app/app.routes';
|
||||
import { StoreModule } from '@ngrx/store';
|
||||
import { reducers } from './app/root-store';
|
||||
import { undoTaskDeleteMetaReducer } from './app/root-store/meta/undo-task-delete.meta-reducer';
|
||||
import { actionLoggerReducer } from './app/root-store/meta/action-logger.reducer';
|
||||
import {
|
||||
|
|
@ -52,10 +51,10 @@ import { EffectsModule } from '@ngrx/effects';
|
|||
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { ServiceWorkerModule } from '@angular/service-worker';
|
||||
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import {
|
||||
TranslateHttpLoader,
|
||||
TRANSLATE_HTTP_LOADER_CONFIG,
|
||||
TranslateHttpLoader,
|
||||
} from '@ngx-translate/http-loader';
|
||||
import { CdkDropListGroup } from '@angular/cdk/drag-drop';
|
||||
import { AppComponent } from './app/app.component';
|
||||
|
|
@ -102,7 +101,7 @@ bootstrapApplication(AppComponent, {
|
|||
// External
|
||||
BrowserModule,
|
||||
// NOTE: both need to be present to use forFeature stores
|
||||
StoreModule.forRoot(reducers, {
|
||||
StoreModule.forRoot(undefined, {
|
||||
metaReducers: [
|
||||
undoTaskDeleteMetaReducer,
|
||||
taskSharedCrudMetaReducer,
|
||||
|
|
@ -192,7 +191,7 @@ bootstrapApplication(AppComponent, {
|
|||
!IS_ANDROID_WEB_VIEW
|
||||
) {
|
||||
Log.log('Registering Service worker');
|
||||
return navigator.serviceWorker.register('ngsw-worker.js').catch((err: any) => {
|
||||
return navigator.serviceWorker.register('ngsw-worker.js').catch((err: unknown) => {
|
||||
Log.log('Service Worker Registration Error');
|
||||
Log.err(err);
|
||||
});
|
||||
|
|
|
|||
25
src/typings/ical.d.ts
vendored
25
src/typings/ical.d.ts
vendored
|
|
@ -1,6 +1,7 @@
|
|||
// Type override for ical.js to fix TypeScript v5.8+ compatibility issue
|
||||
declare module 'ical.js' {
|
||||
export = ICAL;
|
||||
|
||||
namespace ICAL {
|
||||
class Time {
|
||||
static now(): Time;
|
||||
|
|
@ -13,18 +14,23 @@ declare module 'ical.js' {
|
|||
icaltype: string;
|
||||
}
|
||||
|
||||
class Property {
|
||||
getValues(): string[];
|
||||
// Add other property methods as needed
|
||||
}
|
||||
|
||||
class Component {
|
||||
constructor(jCal: any);
|
||||
constructor(jCal: ICalJCal | ICalJCal[]);
|
||||
getAllSubcomponents(name?: string): Component[];
|
||||
getFirstSubcomponent(name: string): Component | null;
|
||||
getFirstPropertyValue(name: string): any;
|
||||
getAllProperties(name: string): any[];
|
||||
updatePropertyWithValue(name: string, value: any): void;
|
||||
getFirstPropertyValue(name: string): ICalPropertyValue;
|
||||
getAllProperties(name: string): Property[];
|
||||
updatePropertyWithValue(name: string, value: ICalPropertyValue): void;
|
||||
removeProperty(name: string): void;
|
||||
}
|
||||
|
||||
class Timezone {
|
||||
constructor(options: any);
|
||||
constructor(options: ICalTimezoneOptions);
|
||||
tzid: string;
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +44,12 @@ declare module 'ical.js' {
|
|||
updateTimezones(comp: Component): Component;
|
||||
};
|
||||
|
||||
function parse(icalData: string): any;
|
||||
function stringify(jCal: any): string;
|
||||
function parse(icalData: string): ICalJCal[];
|
||||
function stringify(jCal: ICalJCal | ICalJCal[]): string;
|
||||
|
||||
// Base types for ical.js
|
||||
type ICalJCal = [string, Record<string, unknown>[], unknown[]];
|
||||
type ICalPropertyValue = string | number | Date | boolean | unknown[] | Time;
|
||||
type ICalTimezoneOptions = Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue