MOBILE-3814 chore: Add a disconnect method on waitToBeInDOM
This commit is contained in:
		
							parent
							
								
									30d24f99e3
								
							
						
					
					
						commit
						23cfb29de0
					
				@ -19,7 +19,7 @@ import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreMath } from '@singletons/math';
 | 
			
		||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
 | 
			
		||||
import { CoreFormatTextDirective } from './format-text';
 | 
			
		||||
import { CoreEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreEventObserver, CoreSingleTimeEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreLoadingComponent } from '@components/loading/loading';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
 | 
			
		||||
@ -48,6 +48,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
 | 
			
		||||
    protected contentScrollListener?: EventListener;
 | 
			
		||||
    protected endContentScrollListener?: EventListener;
 | 
			
		||||
    protected resizeListener?: CoreEventObserver;
 | 
			
		||||
    protected domListener?: CoreSingleTimeEventObserver;
 | 
			
		||||
 | 
			
		||||
    constructor(el: ElementRef, protected ionContent: IonContent) {
 | 
			
		||||
        this.element = el.nativeElement;
 | 
			
		||||
@ -61,7 +62,9 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
 | 
			
		||||
        // Only if not present or explicitly falsy it will be false.
 | 
			
		||||
        this.appearOnBottom = !CoreUtils.isFalseOrZero(this.appearOnBottom);
 | 
			
		||||
 | 
			
		||||
        await CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        this.domListener = CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        await this.domListener.promise;
 | 
			
		||||
 | 
			
		||||
        await this.waitLoadingsDone();
 | 
			
		||||
        await this.waitFormatTextsRendered(this.element);
 | 
			
		||||
 | 
			
		||||
@ -231,6 +234,7 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.resizeListener?.off();
 | 
			
		||||
        this.domListener?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,7 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { Translate } from '@singletons';
 | 
			
		||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
 | 
			
		||||
import { CoreEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreEventObserver, CoreSingleTimeEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreFormatTextDirective } from './format-text';
 | 
			
		||||
 | 
			
		||||
const defaultMaxHeight = 80;
 | 
			
		||||
@ -49,6 +49,7 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
 | 
			
		||||
    protected maxHeight = defaultMaxHeight;
 | 
			
		||||
    protected expandedHeight = 0;
 | 
			
		||||
    protected resizeListener?: CoreEventObserver;
 | 
			
		||||
    protected domListener?: CoreSingleTimeEventObserver;
 | 
			
		||||
 | 
			
		||||
    constructor(el: ElementRef<HTMLElement>) {
 | 
			
		||||
        this.element = el.nativeElement;
 | 
			
		||||
@ -95,7 +96,8 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
 | 
			
		||||
     * @return Promise resolved when loadings are done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async waitLoadingsDone(): Promise<void> {
 | 
			
		||||
        await CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        this.domListener = CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        await this.domListener.promise;
 | 
			
		||||
 | 
			
		||||
        const page = this.element.closest('.ion-page');
 | 
			
		||||
 | 
			
		||||
@ -240,6 +242,7 @@ export class CoreCollapsibleItemDirective implements OnInit, OnDestroy {
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.resizeListener?.off();
 | 
			
		||||
        this.domListener?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,6 +23,7 @@ import {
 | 
			
		||||
    Optional,
 | 
			
		||||
    ViewContainerRef,
 | 
			
		||||
    ViewChild,
 | 
			
		||||
    OnDestroy,
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { IonContent } from '@ionic/angular';
 | 
			
		||||
 | 
			
		||||
@ -41,6 +42,7 @@ import { CoreFilterHelper } from '@features/filter/services/filter-helper';
 | 
			
		||||
import { CoreSubscriptions } from '@singletons/subscriptions';
 | 
			
		||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
 | 
			
		||||
import { CoreCollapsibleItemDirective } from './collapsible-item';
 | 
			
		||||
import { CoreSingleTimeEventObserver } from '@singletons/events';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective
 | 
			
		||||
@ -54,7 +56,7 @@ import { CoreCollapsibleItemDirective } from './collapsible-item';
 | 
			
		||||
@Directive({
 | 
			
		||||
    selector: 'core-format-text',
 | 
			
		||||
})
 | 
			
		||||
export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
export class CoreFormatTextDirective implements OnChanges, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    @ViewChild(CoreCollapsibleItemDirective) collapsible?: CoreCollapsibleItemDirective;
 | 
			
		||||
 | 
			
		||||
@ -88,6 +90,7 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
    protected element: HTMLElement;
 | 
			
		||||
    protected emptyText = '';
 | 
			
		||||
    protected contentSpan: HTMLElement;
 | 
			
		||||
    protected domListener?: CoreSingleTimeEventObserver;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        element: ElementRef,
 | 
			
		||||
@ -126,6 +129,13 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.domListener?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Wait until the text is fully rendered.
 | 
			
		||||
     */
 | 
			
		||||
@ -546,7 +556,8 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
     * @return The width of the element in pixels.
 | 
			
		||||
     */
 | 
			
		||||
    protected async getElementWidth(): Promise<number> {
 | 
			
		||||
        await CoreUtils.ignoreErrors(CoreDomUtils.waitToBeInDOM(this.element));
 | 
			
		||||
        this.domListener = CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        await this.domListener.promise;
 | 
			
		||||
 | 
			
		||||
        let width = this.element.getBoundingClientRect().width;
 | 
			
		||||
        if (!width) {
 | 
			
		||||
@ -700,7 +711,7 @@ export class CoreFormatTextDirective implements OnChanges {
 | 
			
		||||
                let width: string | number;
 | 
			
		||||
                let height: string | number;
 | 
			
		||||
 | 
			
		||||
                await CoreDomUtils.waitToBeInDOM(iframe);
 | 
			
		||||
                await CoreDomUtils.waitToBeInDOM(iframe, 5000).promise;
 | 
			
		||||
 | 
			
		||||
                if (iframe.width) {
 | 
			
		||||
                    width = iframe.width;
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,7 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreUrlUtils } from '@services/utils/url';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { Platform, Translate } from '@singletons';
 | 
			
		||||
import { CoreEventFormActionData, CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreEventFormActionData, CoreEventObserver, CoreEvents, CoreSingleTimeEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreEditorOffline } from '../../services/editor-offline';
 | 
			
		||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
 | 
			
		||||
import { CoreLoadingComponent } from '@components/loading/loading';
 | 
			
		||||
@ -104,6 +104,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
    protected selectionChangeFunction?: () => void;
 | 
			
		||||
    protected languageChangedSubscription?: Subscription;
 | 
			
		||||
    protected resizeListener?: CoreEventObserver;
 | 
			
		||||
    protected domListener?: CoreSingleTimeEventObserver;
 | 
			
		||||
 | 
			
		||||
    rteEnabled = false;
 | 
			
		||||
    isPhone = false;
 | 
			
		||||
@ -249,9 +250,6 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
            this.windowResized();
 | 
			
		||||
        }, 50);
 | 
			
		||||
 | 
			
		||||
        // Start observing the target node for configured mutations
 | 
			
		||||
        this.resizeObserver?.observe(this.element);
 | 
			
		||||
 | 
			
		||||
        document.addEventListener('selectionchange', this.selectionChangeFunction = this.updateToolbarStyles.bind(this));
 | 
			
		||||
 | 
			
		||||
        this.keyboardObserver = CoreEvents.on(CoreEvents.KEYBOARD_CHANGE, () => {
 | 
			
		||||
@ -289,7 +287,8 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
     * @return Promise resolved when loadings are done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async waitLoadingsDone(): Promise<void> {
 | 
			
		||||
        await CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        this.domListener = CoreDomUtils.waitToBeInDOM(this.element);
 | 
			
		||||
        await this.domListener.promise;
 | 
			
		||||
 | 
			
		||||
        const page = this.element.closest('.ion-page');
 | 
			
		||||
 | 
			
		||||
@ -829,7 +828,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
 | 
			
		||||
        const length = await this.toolbarSlides.length();
 | 
			
		||||
 | 
			
		||||
        await CoreDomUtils.waitToBeInDOM(this.toolbar.nativeElement);
 | 
			
		||||
        await CoreDomUtils.waitToBeInDOM(this.toolbar.nativeElement, 5000).promise;
 | 
			
		||||
 | 
			
		||||
        const width = this.toolbar.nativeElement.getBoundingClientRect().width;
 | 
			
		||||
 | 
			
		||||
@ -1075,7 +1074,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being destroyed.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    ngOnDestroy(): void {
 | 
			
		||||
        this.valueChangeSubscription?.unsubscribe();
 | 
			
		||||
@ -1088,6 +1087,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterContentIn
 | 
			
		||||
        this.keyboardObserver?.off();
 | 
			
		||||
        this.labelObserver?.disconnect();
 | 
			
		||||
        this.resizeListener?.off();
 | 
			
		||||
        this.domListener?.off();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,7 @@ import { NavigationStart } from '@angular/router';
 | 
			
		||||
import { filter } from 'rxjs/operators';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
 | 
			
		||||
import { CoreEventObserver } from '@singletons/events';
 | 
			
		||||
import { CoreEventObserver, CoreSingleTimeEventObserver } from '@singletons/events';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * "Utils" service with helper functions for UI, DOM elements and HTML code.
 | 
			
		||||
@ -96,36 +96,52 @@ export class CoreDomUtilsProvider {
 | 
			
		||||
     * Wait an element to be in dom of another element.
 | 
			
		||||
     *
 | 
			
		||||
     * @param element Element to wait.
 | 
			
		||||
     * @return Promise resolved when added. It will be rejected after a timeout of 5s.
 | 
			
		||||
     * @param timeout If defined, timeout to wait before rejecting the promise.
 | 
			
		||||
     * @return Promise CoreSingleTimeEventObserver with a promise.
 | 
			
		||||
     */
 | 
			
		||||
    async waitToBeInDOM(
 | 
			
		||||
    waitToBeInDOM(
 | 
			
		||||
        element: Element,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        timeout?: number,
 | 
			
		||||
    ): CoreSingleTimeEventObserver {
 | 
			
		||||
        let root = element.getRootNode({ composed: true });
 | 
			
		||||
 | 
			
		||||
        if (root === document) {
 | 
			
		||||
            // Already in DOM.
 | 
			
		||||
            return;
 | 
			
		||||
            return {
 | 
			
		||||
                off: (): void => {
 | 
			
		||||
                    // Nothing to do here.
 | 
			
		||||
                },
 | 
			
		||||
                promise: Promise.resolve(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new Promise((resolve, reject) => {
 | 
			
		||||
            // Disconnect observer for performance reasons.
 | 
			
		||||
            const timeout = window.setTimeout(() => {
 | 
			
		||||
                observer.disconnect();
 | 
			
		||||
                reject(new Error('Waiting for DOM timeout reached'));
 | 
			
		||||
            }, 5000);
 | 
			
		||||
        let observer: MutationObserver | undefined;
 | 
			
		||||
        let observerTimeout: number | undefined;
 | 
			
		||||
        if (timeout) {
 | 
			
		||||
            observerTimeout = window.setTimeout(() => {
 | 
			
		||||
                observer?.disconnect();
 | 
			
		||||
                throw new Error('Waiting for DOM timeout reached');
 | 
			
		||||
            }, timeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
            const observer = new MutationObserver(() => {
 | 
			
		||||
                root = element.getRootNode({ composed: true });
 | 
			
		||||
                if (root === document) {
 | 
			
		||||
                    observer.disconnect();
 | 
			
		||||
                    clearTimeout(timeout);
 | 
			
		||||
                    resolve();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        return {
 | 
			
		||||
            off: (): void => {
 | 
			
		||||
                observer?.disconnect();
 | 
			
		||||
                clearTimeout(observerTimeout);
 | 
			
		||||
            },
 | 
			
		||||
            promise: new Promise((resolve) => {
 | 
			
		||||
                observer = new MutationObserver(() => {
 | 
			
		||||
                    root = element.getRootNode({ composed: true });
 | 
			
		||||
                    if (root === document) {
 | 
			
		||||
                        observer?.disconnect();
 | 
			
		||||
                        clearTimeout(observerTimeout);
 | 
			
		||||
                        resolve();
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
            observer.observe(document.body, { subtree: true, childList: true });
 | 
			
		||||
        });
 | 
			
		||||
                observer.observe(document.body, { subtree: true, childList: true });
 | 
			
		||||
            }),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,21 @@ export interface CoreEventObserver {
 | 
			
		||||
    off: () => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Observer instance to stop listening to an observer.
 | 
			
		||||
 */
 | 
			
		||||
export interface CoreSingleTimeEventObserver {
 | 
			
		||||
    /**
 | 
			
		||||
     * Stop the observer.
 | 
			
		||||
     */
 | 
			
		||||
    off: () => void;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Promise Resolved when event is done (first time).
 | 
			
		||||
     */
 | 
			
		||||
    promise: Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Event payloads.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user