MOBILE-4166 core: Implement CoreDirectivesRegistry and deprecate old one
parent
7341ca28c0
commit
47e5158afe
|
@ -47,7 +47,7 @@ import { CanLeave } from '@guards/can-leave';
|
|||
import { CoreForms } from '@singletons/form';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreTime } from '@singletons/time';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
|
||||
/**
|
||||
* Page that allows attempting a quiz.
|
||||
|
@ -690,7 +690,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy, CanLeave {
|
|||
*/
|
||||
protected async scrollToQuestion(slot: number): Promise<void> {
|
||||
await CoreUtils.nextTick();
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.elementRef.nativeElement, 'core-question');
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.elementRef.nativeElement, 'core-question');
|
||||
await CoreDom.scrollToElement(
|
||||
this.elementRef.nativeElement,
|
||||
'#addon-mod_quiz-question-' + slot,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { CoreFormatTextDirective } from '@directives/format-text';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreCoordinates, CoreDom } from '@singletons/dom';
|
||||
import { CoreEventObserver } from '@singletons/events';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
|
@ -427,7 +427,7 @@ export class AddonQtypeDdwtosQuestion {
|
|||
protected async waitForReady(): Promise<void> {
|
||||
await CoreDom.waitToBeInDOM(this.container);
|
||||
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.container, 'core-format-text', CoreFormatTextDirective);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.container, 'core-format-text', CoreFormatTextDirective);
|
||||
|
||||
const drag = Array.from(this.container.querySelectorAll<HTMLElement>(this.selectors.dragHomes()))[0];
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* Component that is not rendered immediately after being mounted.
|
||||
* Directive that is not rendered immediately after being mounted.
|
||||
*/
|
||||
export interface AsyncComponent {
|
||||
export interface AsyncDirective {
|
||||
|
||||
/**
|
||||
* Wait until the component is fully rendered and ready.
|
||||
* Wait until the directive is fully rendered and ready.
|
||||
*/
|
||||
ready(): Promise<void>;
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
import { CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { AsyncComponent } from './async-component';
|
||||
import { AsyncDirective } from './async-directive';
|
||||
import { PageLoadsManager } from './page-loads-manager';
|
||||
import { CorePromisedValue } from './promised-value';
|
||||
import { WSObservable } from './site';
|
||||
|
@ -27,7 +27,7 @@ export class PageLoadWatcher {
|
|||
|
||||
protected hasChanges = false;
|
||||
protected ongoingRequests = 0;
|
||||
protected components = new Set<AsyncComponent>();
|
||||
protected components = new Set<AsyncDirective>();
|
||||
protected loadedTimeout?: number;
|
||||
protected hasChangesPromises: Promise<boolean>[] = [];
|
||||
|
||||
|
@ -66,7 +66,7 @@ export class PageLoadWatcher {
|
|||
*
|
||||
* @param component Component instance.
|
||||
*/
|
||||
async watchComponent(component: AsyncComponent): Promise<void> {
|
||||
async watchComponent(component: AsyncDirective): Promise<void> {
|
||||
this.components.add(component);
|
||||
clearTimeout(this.loadedTimeout);
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { CoreRefreshButtonModalComponent } from '@components/refresh-button-moda
|
|||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { Subject } from 'rxjs';
|
||||
import { AsyncComponent } from './async-component';
|
||||
import { AsyncDirective } from './async-directive';
|
||||
import { PageLoadWatcher } from './page-load-watcher';
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ export class PageLoadsManager {
|
|||
* @param staleWhileRevalidate Whether to use stale while revalidate strategy.
|
||||
* @returns Load watcher to use.
|
||||
*/
|
||||
startPageLoad(page: AsyncComponent, staleWhileRevalidate: boolean): PageLoadWatcher {
|
||||
startPageLoad(page: AsyncDirective, staleWhileRevalidate: boolean): PageLoadWatcher {
|
||||
this.initialPath = this.initialPath ?? CoreNavigator.getCurrentPath();
|
||||
this.currentLoadWatcher = new PageLoadWatcher(this, staleWhileRevalidate);
|
||||
this.ongoingLoadWatchers.add(this.currentLoadWatcher);
|
||||
|
@ -53,7 +53,7 @@ export class PageLoadsManager {
|
|||
* @param component Component instance.
|
||||
* @returns Load watcher to use.
|
||||
*/
|
||||
startComponentLoad(component: AsyncComponent): PageLoadWatcher {
|
||||
startComponentLoad(component: AsyncDirective): PageLoadWatcher {
|
||||
// If a component is loading data without the page loading data, probably the component is reloading/refreshing.
|
||||
// In that case, create a load watcher instance but don't store it in currentLoadWatcher because it's not a page load.
|
||||
const loadWatcher = this.currentLoadWatcher ?? new PageLoadWatcher(this, false);
|
||||
|
|
|
@ -37,8 +37,8 @@ import { CoreDom } from '@singletons/dom';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreError } from './errors/error';
|
||||
import { CorePromisedValue } from './promised-value';
|
||||
import { AsyncComponent } from './async-component';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { AsyncDirective } from './async-directive';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CorePlatform } from '@services/platform';
|
||||
|
||||
/**
|
||||
|
@ -47,7 +47,7 @@ import { CorePlatform } from '@services/platform';
|
|||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, AfterViewInit, OnChanges, OnDestroy, AsyncComponent {
|
||||
export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, AfterViewInit, OnChanges, OnDestroy, AsyncDirective {
|
||||
|
||||
// Minimum tab's width.
|
||||
protected static readonly MIN_TAB_WIDTH = 107;
|
||||
|
@ -99,7 +99,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
|||
|
||||
this.tabAction = new CoreTabsRoleTab(this);
|
||||
|
||||
CoreComponentsRegistry.register(element.nativeElement, this);
|
||||
CoreDirectivesRegistry.register(element.nativeElement, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,7 +20,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { Translate } from '@singletons';
|
||||
import { CoreContextMenuItemComponent } from './context-menu-item';
|
||||
import { CoreContextMenuPopoverComponent } from './context-menu-popover';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
|
||||
/**
|
||||
* This component adds a button (usually in the navigation bar) that displays a context menu popover.
|
||||
|
@ -61,7 +61,7 @@ export class CoreContextMenuComponent implements OnInit, OnDestroy {
|
|||
// Calculate the unique ID.
|
||||
this.uniqueId = 'core-context-menu-' + CoreUtils.getUniqueId('CoreContextMenuComponent');
|
||||
|
||||
CoreComponentsRegistry.register(elementRef.nativeElement, this);
|
||||
CoreDirectivesRegistry.register(elementRef.nativeElement, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,9 +18,9 @@ import { CoreEventLoadingChangedData, CoreEvents } from '@singletons/events';
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreAnimations } from '@components/animations';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CoreApp } from '@services/app';
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ import { CoreApp } from '@services/app';
|
|||
styleUrls: ['loading.scss'],
|
||||
animations: [CoreAnimations.SHOW_HIDE],
|
||||
})
|
||||
export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncComponent, OnDestroy {
|
||||
export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncDirective, OnDestroy {
|
||||
|
||||
@Input() hideUntil: unknown = false; // Determine when should the contents be shown.
|
||||
@Input() message?: string; // Message to show while loading.
|
||||
|
@ -65,7 +65,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
|
|||
|
||||
constructor(element: ElementRef) {
|
||||
this.element = element.nativeElement;
|
||||
CoreComponentsRegistry.register(this.element, this);
|
||||
CoreDirectivesRegistry.register(this.element, this);
|
||||
|
||||
// Calculate the unique ID.
|
||||
this.uniqueId = 'core-loading-content-' + CoreUtils.getUniqueId('CoreLoadingComponent');
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreContextMenuComponent } from '../context-menu/context-menu';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
|
||||
const BUTTON_HIDDEN_CLASS = 'core-navbar-button-hidden';
|
||||
|
@ -82,7 +82,7 @@ export class CoreNavBarButtonsComponent implements OnInit, OnDestroy {
|
|||
this.element = element.nativeElement;
|
||||
this.logger = CoreLogger.getInstance('CoreNavBarButtonsComponent');
|
||||
|
||||
CoreComponentsRegistry.register(this.element, this);
|
||||
CoreDirectivesRegistry.register(this.element, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,11 +156,11 @@ export class CoreNavBarButtonsComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
const mainContextMenu = buttonsContainer.querySelector('core-context-menu');
|
||||
const secondaryContextMenuInstance = CoreComponentsRegistry.resolve(secondaryContextMenu, CoreContextMenuComponent);
|
||||
const secondaryContextMenuInstance = CoreDirectivesRegistry.resolve(secondaryContextMenu, CoreContextMenuComponent);
|
||||
let mainContextMenuInstance: CoreContextMenuComponent | null;
|
||||
if (mainContextMenu) {
|
||||
// Both containers have a context menu. Merge them to prevent having 2 menus at the same time.
|
||||
mainContextMenuInstance = CoreComponentsRegistry.resolve(mainContextMenu, CoreContextMenuComponent);
|
||||
mainContextMenuInstance = CoreDirectivesRegistry.resolve(mainContextMenu, CoreContextMenuComponent);
|
||||
} else {
|
||||
// There is a context-menu in these buttons, but there is no main context menu in the header.
|
||||
// Create one main context menu dynamically.
|
||||
|
|
|
@ -31,7 +31,7 @@ import { CoreNavBarButtonsComponent } from '../navbar-buttons/navbar-buttons';
|
|||
import { StackEvent } from '@ionic/angular/directives/navigation/stack-utils';
|
||||
import { CoreNavigator } from '@services/navigator';
|
||||
import { CoreTabBase, CoreTabsBaseComponent } from '@classes/tabs';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
|
||||
/**
|
||||
* This component displays some top scrollable tabs that will autohide on vertical scroll.
|
||||
|
@ -207,7 +207,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
|||
protected showHideNavBarButtons(activatedPageName: string): void {
|
||||
const elements = this.ionTabs.outlet.nativeEl.querySelectorAll('core-navbar-buttons');
|
||||
elements.forEach((element) => {
|
||||
const instance = CoreComponentsRegistry.resolve(element, CoreNavBarButtonsComponent);
|
||||
const instance = CoreDirectivesRegistry.resolve(element, CoreNavBarButtonsComponent);
|
||||
|
||||
if (instance) {
|
||||
const pagetagName = element.closest('.ion-page')?.tagName;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Component, Input, Output, OnInit, OnDestroy, ElementRef, EventEmitter,
|
|||
import { CoreTabBase } from '@classes/tabs';
|
||||
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreNavBarButtonsComponent } from '../navbar-buttons/navbar-buttons';
|
||||
import { CoreTabsComponent } from './tabs';
|
||||
|
||||
|
@ -140,7 +140,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase {
|
|||
protected showHideNavBarButtons(show: boolean): void {
|
||||
const elements = this.element.querySelectorAll('core-navbar-buttons');
|
||||
elements.forEach((element) => {
|
||||
const instance = CoreComponentsRegistry.resolve(element, CoreNavBarButtonsComponent);
|
||||
const instance = CoreDirectivesRegistry.resolve(element, CoreNavBarButtonsComponent);
|
||||
|
||||
if (instance) {
|
||||
instance.forceHide(!show);
|
||||
|
|
|
@ -17,7 +17,7 @@ import { ScrollDetail } from '@ionic/core';
|
|||
import { IonContent } from '@ionic/angular';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreMath } from '@singletons/math';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreFormatTextDirective } from './format-text';
|
||||
import { CoreEventObserver } from '@singletons/events';
|
||||
import { CoreLoadingComponent } from '@components/loading/loading';
|
||||
|
@ -203,7 +203,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
|
|||
* Wait until all <core-format-text> children inside the element are done rendering.
|
||||
*/
|
||||
protected async waitFormatTextsRendered(): Promise<void> {
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.element, 'core-format-text', CoreFormatTextDirective);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.element, 'core-format-text', CoreFormatTextDirective);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,8 +249,8 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
|
|||
const scrollElement = await this.ionContent.getScrollElement();
|
||||
|
||||
await Promise.all([
|
||||
await CoreComponentsRegistry.waitComponentsReady(scrollElement, 'core-loading', CoreLoadingComponent),
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.element, 'core-loading', CoreLoadingComponent),
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(scrollElement, 'core-loading', CoreLoadingComponent),
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.element, 'core-loading', CoreLoadingComponent),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreTabsComponent } from '@components/tabs/tabs';
|
|||
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
|
||||
import { ScrollDetail } from '@ionic/core';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreMath } from '@singletons/math';
|
||||
|
@ -294,7 +294,7 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
this.listenEvents();
|
||||
|
||||
// Initialize from tabs.
|
||||
const tabs = CoreComponentsRegistry.resolve(this.page.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
|
||||
const tabs = CoreDirectivesRegistry.resolve(this.page.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
|
||||
|
||||
if (tabs) {
|
||||
const outlet = tabs.getOutlet();
|
||||
|
@ -424,14 +424,14 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
}
|
||||
|
||||
// Wait loadings to finish.
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-loading', CoreLoadingComponent);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-loading', CoreLoadingComponent);
|
||||
|
||||
// Wait tabs to be ready.
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs', CoreTabsComponent);
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs-outlet', CoreTabsOutletComponent);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-tabs', CoreTabsComponent);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-tabs-outlet', CoreTabsOutletComponent);
|
||||
|
||||
// Wait loadings to finish, inside tabs (if any).
|
||||
await CoreComponentsRegistry.waitComponentsReady(
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(
|
||||
this.page,
|
||||
'core-tab core-loading, ion-router-outlet core-loading',
|
||||
CoreLoadingComponent,
|
||||
|
@ -445,7 +445,7 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
* @returns Promise resolved when texts are rendered.
|
||||
*/
|
||||
protected async waitFormatTextsRendered(element: Element): Promise<void> {
|
||||
await CoreComponentsRegistry.waitComponentsReady(element, 'core-format-text', CoreFormatTextDirective);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(element, 'core-format-text', CoreFormatTextDirective);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,7 @@ import { CoreSettingsHelper } from '@features/settings/services/settings-helper'
|
|||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreColors } from '@singletons/colors';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreEventObserver } from '@singletons/events';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
@ -128,14 +128,14 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-loading', CoreLoadingComponent);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-loading', CoreLoadingComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until all <core-format-text> children inside the element are done rendering.
|
||||
*/
|
||||
protected async waitFormatTextsRendered(): Promise<void> {
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.element, 'core-format-text', CoreFormatTextDirective);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(this.element, 'core-format-text', CoreFormatTextDirective);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,10 +42,10 @@ import { CoreFilter, CoreFilterFilter, CoreFilterFormatTextOptions } from '@feat
|
|||
import { CoreFilterDelegate } from '@features/filter/services/filter-delegate';
|
||||
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
|
||||
import { CoreSubscriptions } from '@singletons/subscriptions';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreCollapsibleItemDirective } from './collapsible-item';
|
||||
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CorePath } from '@singletons/path';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreEvents } from '@singletons/events';
|
||||
|
@ -67,7 +67,7 @@ import { FrameElementController } from '@classes/element-controllers/FrameElemen
|
|||
@Directive({
|
||||
selector: 'core-format-text',
|
||||
})
|
||||
export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncComponent {
|
||||
export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirective {
|
||||
|
||||
@ViewChild(CoreCollapsibleItemDirective) collapsible?: CoreCollapsibleItemDirective;
|
||||
|
||||
|
@ -111,7 +111,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncCompo
|
|||
protected viewContainerRef: ViewContainerRef,
|
||||
@Optional() @Inject(CORE_REFRESH_CONTEXT) protected refreshContext?: CoreRefreshContext,
|
||||
) {
|
||||
CoreComponentsRegistry.register(element.nativeElement, this);
|
||||
CoreDirectivesRegistry.register(element.nativeElement, this);
|
||||
|
||||
this.element = element.nativeElement;
|
||||
this.element.classList.add('core-loading'); // Hide contents until they're treated.
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreCourseBlock } from '../../course/services/course';
|
|||
import { Params } from '@angular/router';
|
||||
import { ContextLevel } from '@/core/constants';
|
||||
import { CoreNavigationOptions } from '@services/navigator';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
|
||||
/**
|
||||
|
@ -30,7 +30,7 @@ import { CorePromisedValue } from '@classes/promised-value';
|
|||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export abstract class CoreBlockBaseComponent implements OnInit, ICoreBlockComponent, AsyncComponent {
|
||||
export abstract class CoreBlockBaseComponent implements OnInit, ICoreBlockComponent, AsyncDirective {
|
||||
|
||||
@Input() title!: string; // The block title.
|
||||
@Input() block!: CoreCourseBlock; // The block to render.
|
||||
|
|
|
@ -79,6 +79,7 @@ import { Md5 } from 'ts-md5/dist/md5';
|
|||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||
import { CoreArray } from '@singletons/array';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreForms } from '@singletons/form';
|
||||
import { CoreText } from '@singletons/text';
|
||||
|
@ -350,6 +351,7 @@ export class CoreCompileProvider {
|
|||
instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider;
|
||||
instance['CoreArray'] = CoreArray;
|
||||
instance['CoreComponentsRegistry'] = CoreComponentsRegistry;
|
||||
instance['CoreDirectivesRegistry'] = CoreDirectivesRegistry;
|
||||
instance['CoreNetwork'] = CoreNetwork.instance;
|
||||
instance['CorePlatform'] = CorePlatform.instance;
|
||||
instance['CoreDom'] = CoreDom;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { AddonBlockMyOverviewComponent } from '@addons/block/myoverview/components/myoverview/myoverview';
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { PageLoadsManager } from '@classes/page-loads-manager';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreBlockComponent } from '@features/block/components/block/block';
|
||||
|
@ -42,7 +42,7 @@ import { CoreCourses } from '../../services/courses';
|
|||
useClass: PageLoadsManager,
|
||||
}],
|
||||
})
|
||||
export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncComponent {
|
||||
export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncDirective {
|
||||
|
||||
@ViewChild(CoreBlockComponent) block!: CoreBlockComponent;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { Translate } from '@singletons';
|
||||
import { CoreEventFormActionData, CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreEditorOffline } from '../../services/editor-offline';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreLoadingComponent } from '@components/loading/loading';
|
||||
import { CoreScreen } from '@services/screen';
|
||||
import { CoreCancellablePromise } from '@classes/cancellable-promise';
|
||||
|
@ -304,7 +304,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit,
|
|||
return;
|
||||
}
|
||||
|
||||
await CoreComponentsRegistry.waitComponentsReady(page, 'core-loading', CoreLoadingComponent);
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(page, 'core-loading', CoreLoadingComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component, Input, Output, OnInit, EventEmitter, ChangeDetectorRef, Type, ElementRef } from '@angular/core';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate';
|
||||
import { CoreQuestionDelegate } from '@features/question/services/question-delegate';
|
||||
|
@ -22,7 +22,7 @@ import { CoreQuestionBehaviourButton, CoreQuestionHelper, CoreQuestionQuestion }
|
|||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
|
||||
/**
|
||||
|
@ -33,7 +33,7 @@ import { CoreLogger } from '@singletons/logger';
|
|||
templateUrl: 'core-question.html',
|
||||
styleUrls: ['../../question.scss'],
|
||||
})
|
||||
export class CoreQuestionComponent implements OnInit, AsyncComponent {
|
||||
export class CoreQuestionComponent implements OnInit, AsyncDirective {
|
||||
|
||||
@Input() question?: CoreQuestionQuestion; // The question to render.
|
||||
@Input() component?: string; // The component the question belongs to.
|
||||
|
@ -66,7 +66,7 @@ export class CoreQuestionComponent implements OnInit, AsyncComponent {
|
|||
constructor(protected changeDetector: ChangeDetectorRef, private element: ElementRef) {
|
||||
this.logger = CoreLogger.getInstance('CoreQuestionComponent');
|
||||
this.promisedReady = new CorePromisedValue();
|
||||
CoreComponentsRegistry.register(this.element.nativeElement, this);
|
||||
CoreDirectivesRegistry.register(this.element.nativeElement, this);
|
||||
}
|
||||
|
||||
async ready(): Promise<void> {
|
||||
|
|
|
@ -30,7 +30,7 @@ import { CoreUserToursPopoverLayout } from '@features/usertours/classes/popover-
|
|||
import { CoreUserTours, CoreUserToursAlignment, CoreUserToursSide } from '@features/usertours/services/user-tours';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { AngularFrameworkDelegate } from '@singletons';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreMainMenuProvider } from '@features/mainmenu/services/mainmenu';
|
||||
|
@ -84,7 +84,7 @@ export class CoreUserToursUserTourComponent implements AfterViewInit, OnDestroy
|
|||
constructor({ nativeElement: element }: ElementRef<HTMLElement>) {
|
||||
this.element = element;
|
||||
|
||||
CoreComponentsRegistry.register(element, this);
|
||||
CoreDirectivesRegistry.register(element, this);
|
||||
|
||||
this.element.addEventListener('click', (event) =>
|
||||
this.dismissOnBackOrBackdrop(event.target as HTMLElement));
|
||||
|
|
|
@ -21,7 +21,7 @@ import { CoreDatabaseCachingStrategy, CoreDatabaseTableProxy } from '@classes/da
|
|||
import { CoreApp } from '@services/app';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { AngularFrameworkDelegate, makeSingleton } from '@singletons';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreSubscriptions } from '@singletons/subscriptions';
|
||||
import { CoreUserToursUserTourComponent } from '../components/user-tour/user-tour';
|
||||
|
@ -120,7 +120,7 @@ export class CoreUserToursService {
|
|||
CoreUserToursUserTourComponent,
|
||||
{ ...componentOptions, container },
|
||||
);
|
||||
const tour = CoreComponentsRegistry.require(element, CoreUserToursUserTourComponent);
|
||||
const tour = CoreDirectivesRegistry.require(element, CoreUserToursUserTourComponent);
|
||||
|
||||
return this.startTour(tour, options.watch ?? (options as CoreUserToursFocusedOptions).focus);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ import { CoreSites } from '@services/sites';
|
|||
import { NavigationStart } from '@angular/router';
|
||||
import { filter } from 'rxjs/operators';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreSiteError } from '@classes/errors/siteerror';
|
||||
|
@ -665,10 +665,10 @@ export class CoreDomUtilsProvider {
|
|||
*
|
||||
* @param element The root element of the component/directive.
|
||||
* @returns The instance, undefined if not found.
|
||||
* @deprecated since 4.0.0. Use CoreComponentsRegistry instead.
|
||||
* @deprecated since 4.0.0. Use CoreDirectivesRegistry instead.
|
||||
*/
|
||||
getInstanceByElement<T = unknown>(element: Element): T | undefined {
|
||||
return CoreComponentsRegistry.resolve<T>(element) ?? undefined;
|
||||
return CoreDirectivesRegistry.resolve<T>(element) ?? undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1718,10 +1718,10 @@ export class CoreDomUtilsProvider {
|
|||
*
|
||||
* @param element The root element of the component/directive.
|
||||
* @param instance The instance to store.
|
||||
* @deprecated since 4.0.0. Use CoreComponentsRegistry instead.
|
||||
* @deprecated since 4.0.0. Use CoreDirectivesRegistry instead.
|
||||
*/
|
||||
storeInstanceByElement(element: Element, instance: unknown): void {
|
||||
CoreComponentsRegistry.register(element, instance);
|
||||
CoreDirectivesRegistry.register(element, instance);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreLogger } from './logger';
|
||||
|
||||
/**
|
||||
* Registry to keep track of component instances.
|
||||
*
|
||||
* @deprecated since 4.1.1. Use CoreDirectivesRegistry instead.
|
||||
*/
|
||||
export class CoreComponentsRegistry {
|
||||
|
||||
|
@ -74,7 +76,7 @@ export class CoreComponentsRegistry {
|
|||
* @param componentClass Component class.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
static async waitComponentReady<T extends AsyncComponent>(
|
||||
static async waitComponentReady<T extends AsyncDirective>(
|
||||
element: Element | null,
|
||||
componentClass?: ComponentConstructor<T>,
|
||||
): Promise<void> {
|
||||
|
@ -96,7 +98,7 @@ export class CoreComponentsRegistry {
|
|||
* @param componentClass Component class.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
static async waitComponentsReady<T extends AsyncComponent>(
|
||||
static async waitComponentsReady<T extends AsyncDirective>(
|
||||
element: Element,
|
||||
selector: string,
|
||||
componentClass?: ComponentConstructor<T>,
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { Directive } from '@angular/core';
|
||||
import { AsyncDirective } from '@classes/async-directive';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreLogger } from './logger';
|
||||
|
||||
/**
|
||||
* Registry to keep track of directive instances.
|
||||
*/
|
||||
export class CoreDirectivesRegistry {
|
||||
|
||||
private static instances: WeakMap<Element, unknown[]> = new WeakMap();
|
||||
protected static logger = CoreLogger.getInstance('CoreDirectivesRegistry');
|
||||
|
||||
/**
|
||||
* Register a directive instance.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param instance Directive instance.
|
||||
*/
|
||||
static register(element: Element, instance: unknown): void {
|
||||
const list = this.instances.get(element) ?? [];
|
||||
list.push(instance);
|
||||
this.instances.set(element, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a directive instance.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param directiveClass Directive class.
|
||||
* @returns Directive instance.
|
||||
*/
|
||||
static resolve<T>(element?: Element | null, directiveClass?: DirectiveConstructor<T>): T | null {
|
||||
const list = (element && this.instances.get(element) as T[]) ?? [];
|
||||
|
||||
return list.find(instance => !directiveClass || instance instanceof directiveClass) ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve all directive instances.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param directiveClass Directive class.
|
||||
* @returns Directive instances.
|
||||
*/
|
||||
static resolveAll<T>(element?: Element | null, directiveClass?: DirectiveConstructor<T>): T[] {
|
||||
const list = (element && this.instances.get(element) as T[]) ?? [];
|
||||
|
||||
return list.filter(instance => !directiveClass || instance instanceof directiveClass) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a directive instance and fail if it cannot be resolved.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param directiveClass Directive class.
|
||||
* @returns Directive instance.
|
||||
*/
|
||||
static require<T>(element: Element, directiveClass?: DirectiveConstructor<T>): T {
|
||||
const instance = this.resolve(element, directiveClass);
|
||||
|
||||
if (!instance) {
|
||||
throw new Error('Couldn\'t resolve directive instance');
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a directive instance and wait to be ready.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param directiveClass Directive class.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
static async waitDirectiveReady<T extends AsyncDirective>(
|
||||
element: Element | null,
|
||||
directiveClass?: DirectiveConstructor<T>,
|
||||
): Promise<void> {
|
||||
const instance = this.resolve(element, directiveClass);
|
||||
if (!instance) {
|
||||
this.logger.error('No instance registered for element ' + directiveClass, element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
await instance.ready();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all directive instances and wait to be ready.
|
||||
*
|
||||
* @param element Root element.
|
||||
* @param directiveClass Directive class.
|
||||
* @returns Promise resolved when done.
|
||||
*/
|
||||
static async waitDirectivesReady<T extends AsyncDirective>(
|
||||
element: Element,
|
||||
selector?: string,
|
||||
directiveClass?: DirectiveConstructor<T>,
|
||||
): Promise<void> {
|
||||
let elements: Element[] = [];
|
||||
|
||||
if (!selector || element.matches(selector)) {
|
||||
// Element to wait is myself.
|
||||
elements = [element];
|
||||
} else {
|
||||
elements = Array.from(element.querySelectorAll(selector));
|
||||
}
|
||||
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(elements.map(async element => {
|
||||
const instances = this.resolveAll<T>(element, directiveClass);
|
||||
|
||||
await Promise.all(instances.map(instance => instance.ready()));
|
||||
}));
|
||||
|
||||
// Wait for next tick to ensure directives are completely rendered.
|
||||
await CoreUtils.nextTick();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Directive constructor.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type DirectiveConstructor<T = Directive> = { new(...args: any[]): T };
|
|
@ -108,7 +108,7 @@ export class CoreEvents {
|
|||
static readonly FILE_SHARED = 'file_shared';
|
||||
static readonly KEYBOARD_CHANGE = 'keyboard_change';
|
||||
/**
|
||||
* @deprecated since app 4.0. Use CoreComponentsRegistry promises instead.
|
||||
* @deprecated since app 4.0. Use CoreDirectivesRegistry promises instead.
|
||||
*/
|
||||
static readonly CORE_LOADING_CHANGED = 'core_loading_changed';
|
||||
static readonly ORIENTATION_CHANGE = 'orientation_change';
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { wait } from '@/testing/utils';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
|
||||
const cssClassName = 'core-components-registry-test';
|
||||
const createAndRegisterInstance = () => {
|
||||
const element = document.createElement('div');
|
||||
element.classList.add(cssClassName);
|
||||
const instance = new ComponentsRegistryTestClass();
|
||||
|
||||
CoreComponentsRegistry.register(element, instance);
|
||||
|
||||
return { element, instance };
|
||||
};
|
||||
|
||||
describe('CoreComponentsRegistry singleton', () => {
|
||||
|
||||
let element: HTMLElement;
|
||||
let testClassInstance: ComponentsRegistryTestClass;
|
||||
|
||||
beforeEach(() => {
|
||||
const result = createAndRegisterInstance();
|
||||
element = result.element;
|
||||
testClassInstance = result.instance;
|
||||
});
|
||||
|
||||
it('resolves stored instances', () => {
|
||||
expect(CoreComponentsRegistry.resolve(element)).toEqual(testClassInstance);
|
||||
expect(CoreComponentsRegistry.resolve(element, ComponentsRegistryTestClass)).toEqual(testClassInstance);
|
||||
expect(CoreComponentsRegistry.resolve(element, CoreComponentsRegistry)).toEqual(null);
|
||||
expect(CoreComponentsRegistry.resolve(document.createElement('div'))).toEqual(null);
|
||||
});
|
||||
|
||||
it('requires stored instances', () => {
|
||||
expect(CoreComponentsRegistry.require(element)).toEqual(testClassInstance);
|
||||
expect(CoreComponentsRegistry.require(element, ComponentsRegistryTestClass)).toEqual(testClassInstance);
|
||||
expect(() => CoreComponentsRegistry.require(element, CoreComponentsRegistry)).toThrow();
|
||||
expect(() => CoreComponentsRegistry.require(document.createElement('div'))).toThrow();
|
||||
});
|
||||
|
||||
it('waits for component ready', async () => {
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
|
||||
await CoreComponentsRegistry.waitComponentReady(element);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
});
|
||||
|
||||
it('waits for components ready: just one', async () => {
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
|
||||
await CoreComponentsRegistry.waitComponentsReady(element, `.${cssClassName}`);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
});
|
||||
|
||||
it('waits for components ready: multiple', async () => {
|
||||
const secondResult = createAndRegisterInstance();
|
||||
const thirdResult = createAndRegisterInstance();
|
||||
thirdResult.element.classList.remove(cssClassName); // Remove the class so the element and instance aren't treated.
|
||||
|
||||
const parent = document.createElement('div');
|
||||
parent.appendChild(element);
|
||||
parent.appendChild(secondResult.element);
|
||||
parent.appendChild(thirdResult.element);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
expect(secondResult.instance.isReady).toBe(false);
|
||||
expect(thirdResult.instance.isReady).toBe(false);
|
||||
|
||||
await CoreComponentsRegistry.waitComponentsReady(parent, `.${cssClassName}`);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
expect(secondResult.instance.isReady).toBe(true);
|
||||
expect(thirdResult.instance.isReady).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
class ComponentsRegistryTestClass {
|
||||
|
||||
randomId = Math.random();
|
||||
isReady = false;
|
||||
|
||||
async ready(): Promise<void> {
|
||||
await wait(50);
|
||||
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
// (C) Copyright 2015 Moodle Pty Ltd.
|
||||
//
|
||||
// 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 { wait } from '@/testing/utils';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
|
||||
const cssClassName = 'core-directives-registry-test';
|
||||
const createAndRegisterInstance = (element?: HTMLElement) => {
|
||||
element = element ?? document.createElement('div');
|
||||
element.classList.add(cssClassName);
|
||||
const instance = new DirectivesRegistryTestClass();
|
||||
|
||||
CoreDirectivesRegistry.register(element, instance);
|
||||
|
||||
return { element, instance };
|
||||
};
|
||||
|
||||
describe('CoreDirectivesRegistry singleton', () => {
|
||||
|
||||
let element: HTMLElement;
|
||||
let testClassInstance: DirectivesRegistryTestClass;
|
||||
let testClassSecondInstance: DirectivesRegistryTestClass;
|
||||
let testAltClassInstance: DirectivesRegistryAltTestClass;
|
||||
|
||||
beforeEach(() => {
|
||||
let result = createAndRegisterInstance();
|
||||
element = result.element;
|
||||
testClassInstance = result.instance;
|
||||
|
||||
result = createAndRegisterInstance(element);
|
||||
testClassSecondInstance = result.instance;
|
||||
|
||||
testAltClassInstance = new DirectivesRegistryAltTestClass();
|
||||
CoreDirectivesRegistry.register(element, testAltClassInstance);
|
||||
});
|
||||
|
||||
it('resolves a stored instance', () => {
|
||||
expect(CoreDirectivesRegistry.resolve(element)).toEqual(testClassInstance);
|
||||
expect(CoreDirectivesRegistry.resolve(element, DirectivesRegistryTestClass)).toEqual(testClassInstance);
|
||||
expect(CoreDirectivesRegistry.resolve(element, DirectivesRegistryAltTestClass)).toEqual(testAltClassInstance);
|
||||
expect(CoreDirectivesRegistry.resolve(element, CoreDirectivesRegistry)).toEqual(null);
|
||||
expect(CoreDirectivesRegistry.resolve(document.createElement('div'))).toEqual(null);
|
||||
});
|
||||
|
||||
it('resolves all stored instances', () => {
|
||||
expect(CoreDirectivesRegistry.resolveAll(element)).toEqual(
|
||||
[testClassInstance, testClassSecondInstance, testAltClassInstance],
|
||||
);
|
||||
expect(CoreDirectivesRegistry.resolveAll(element, DirectivesRegistryTestClass)).toEqual(
|
||||
[testClassInstance, testClassSecondInstance],
|
||||
);
|
||||
expect(CoreDirectivesRegistry.resolveAll(element, DirectivesRegistryAltTestClass)).toEqual([testAltClassInstance]);
|
||||
expect(CoreDirectivesRegistry.resolveAll(element, CoreDirectivesRegistry)).toEqual([]);
|
||||
expect(CoreDirectivesRegistry.resolveAll(document.createElement('div'))).toEqual([]);
|
||||
});
|
||||
|
||||
it('requires a stored instance', () => {
|
||||
expect(CoreDirectivesRegistry.require(element)).toEqual(testClassInstance);
|
||||
expect(CoreDirectivesRegistry.require(element, DirectivesRegistryTestClass)).toEqual(testClassInstance);
|
||||
expect(CoreDirectivesRegistry.require(element, DirectivesRegistryAltTestClass)).toEqual(testAltClassInstance);
|
||||
expect(() => CoreDirectivesRegistry.require(element, CoreDirectivesRegistry)).toThrow();
|
||||
expect(() => CoreDirectivesRegistry.require(document.createElement('div'))).toThrow();
|
||||
});
|
||||
|
||||
it('waits for directive ready', async () => {
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
|
||||
await CoreDirectivesRegistry.waitDirectiveReady(element);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
});
|
||||
|
||||
it('waits for directives ready: just one element and directive', async () => {
|
||||
const result = createAndRegisterInstance();
|
||||
expect(result.instance.isReady).toBe(false);
|
||||
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(result.element, `.${cssClassName}`);
|
||||
|
||||
expect(result.instance.isReady).toBe(true);
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
});
|
||||
|
||||
it('waits for directives ready: all directives, single element', async () => {
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
expect(testClassSecondInstance.isReady).toBe(false);
|
||||
expect(testAltClassInstance.isReady).toBe(false);
|
||||
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(element);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
expect(testClassSecondInstance.isReady).toBe(true);
|
||||
expect(testAltClassInstance.isReady).toBe(true);
|
||||
});
|
||||
|
||||
it('waits for directives ready: filter by class, single element', async () => {
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
expect(testClassSecondInstance.isReady).toBe(false);
|
||||
expect(testAltClassInstance.isReady).toBe(false);
|
||||
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(element, `.${cssClassName}`, DirectivesRegistryTestClass);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
expect(testClassSecondInstance.isReady).toBe(true);
|
||||
expect(testAltClassInstance.isReady).toBe(false);
|
||||
});
|
||||
|
||||
it('waits for directives ready: multiple elements', async () => {
|
||||
const secondResult = createAndRegisterInstance();
|
||||
const thirdResult = createAndRegisterInstance();
|
||||
thirdResult.element.classList.remove(cssClassName); // Remove the class so the element and instance aren't treated.
|
||||
|
||||
const parent = document.createElement('div');
|
||||
parent.appendChild(element);
|
||||
parent.appendChild(secondResult.element);
|
||||
parent.appendChild(thirdResult.element);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(false);
|
||||
expect(testClassSecondInstance.isReady).toBe(false);
|
||||
expect(testAltClassInstance.isReady).toBe(false);
|
||||
expect(secondResult.instance.isReady).toBe(false);
|
||||
expect(thirdResult.instance.isReady).toBe(false);
|
||||
|
||||
await CoreDirectivesRegistry.waitDirectivesReady(parent, `.${cssClassName}`, DirectivesRegistryTestClass);
|
||||
|
||||
expect(testClassInstance.isReady).toBe(true);
|
||||
expect(testClassSecondInstance.isReady).toBe(true);
|
||||
expect(testAltClassInstance.isReady).toBe(false);
|
||||
expect(secondResult.instance.isReady).toBe(true);
|
||||
expect(thirdResult.instance.isReady).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
class DirectivesRegistryTestClass {
|
||||
|
||||
randomId = Math.random();
|
||||
isReady = false;
|
||||
|
||||
async ready(): Promise<void> {
|
||||
await wait(50);
|
||||
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DirectivesRegistryAltTestClass {
|
||||
|
||||
randomId = Math.random();
|
||||
isReady = false;
|
||||
|
||||
async ready(): Promise<void> {
|
||||
await wait(50);
|
||||
|
||||
this.isReady = true;
|
||||
}
|
||||
|
||||
}
|
|
@ -23,7 +23,7 @@ import { CoreNetwork, CoreNetworkService } from '@services/network';
|
|||
import { CorePushNotifications, CorePushNotificationsProvider } from '@features/pushnotifications/services/pushnotifications';
|
||||
import { CoreCronDelegate, CoreCronDelegateService } from '@services/cron';
|
||||
import { CoreLoadingComponent } from '@components/loading/loading';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
|
||||
import { CoreDom } from '@singletons/dom';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSites, CoreSitesProvider } from '@services/sites';
|
||||
|
@ -127,7 +127,7 @@ export class TestingBehatRuntimeService {
|
|||
.filter((element) => CoreDom.isElementVisible(element));
|
||||
|
||||
await Promise.all(elements.map(element =>
|
||||
CoreComponentsRegistry.waitComponentReady(element, CoreLoadingComponent)));
|
||||
CoreDirectivesRegistry.waitDirectiveReady(element, CoreLoadingComponent)));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue