diff --git a/src/core/components/navbar-buttons/navbar-buttons.ts b/src/core/components/navbar-buttons/navbar-buttons.ts index e06a88435..6fc5179f0 100644 --- a/src/core/components/navbar-buttons/navbar-buttons.ts +++ b/src/core/components/navbar-buttons/navbar-buttons.ts @@ -89,7 +89,7 @@ export class CoreNavBarButtonsComponent implements OnInit, OnDestroy { */ async ngOnInit(): Promise { try { - const header = await this.searchHeader(); + const header = await CoreDom.findIonHeaderFromElement(this.element); if (header) { // Search the right buttons container (start, end or any). let selector = 'ion-buttons'; @@ -192,43 +192,6 @@ export class CoreNavBarButtonsComponent implements OnInit, OnDestroy { return componentRef.instance; } - /** - * Search the ion-header where the buttons should be added. - * - * @returns Promise resolved with the header element. - */ - protected async searchHeader(): Promise { - await CoreDom.waitToBeInDOM(this.element); - let parentPage: HTMLElement | null = this.element; - - while (parentPage && parentPage.parentElement) { - const content = parentPage.closest('ion-content'); - if (content) { - // Sometimes ion-page class is not yet added by the ViewController, wait for content to render. - await content.componentOnReady(); - } - - parentPage = parentPage.parentElement.closest('.ion-page, .ion-page-hidden, .ion-page-invisible'); - - // Check if the page has a header. If it doesn't, search the next parent page. - let header = parentPage?.querySelector(':scope > ion-header'); - - if (header && getComputedStyle(header).display !== 'none') { - return header; - } - - // Find using content if any. - header = content?.parentElement?.querySelector(':scope > ion-header'); - - if (header && getComputedStyle(header).display !== 'none') { - return header; - } - } - - // Header not found, reject. - throw Error('Header not found.'); - } - /** * Show or hide all the elements. */ diff --git a/src/core/directives/reading-mode.ts b/src/core/directives/reading-mode.ts index 7949eea64..f46a5f124 100644 --- a/src/core/directives/reading-mode.ts +++ b/src/core/directives/reading-mode.ts @@ -47,7 +47,6 @@ export class CoreReadingModeDirective implements AfterViewInit, OnDestroy { protected hiddenElements: HTMLElement[] = []; protected renamedStyles: HTMLElement[] = []; protected enabled = false; - protected contentEl?: HTMLIonContentElement; protected header?: CoreCollapsibleHeaderDirective; protected logger = CoreLogger.getInstance('CoreReadingModeDirective'); @@ -64,7 +63,12 @@ export class CoreReadingModeDirective implements AfterViewInit, OnDestroy { async ngAfterViewInit(): Promise { await this.viewportPromise; await CoreWait.nextTick(); - this.addTextViewerButton(); + await this.addTextViewerButton(); + + this.enabled = document.body.classList.contains('core-reading-mode-enabled'); + if (this.enabled) { + await this.enterReadingMode(); + } } /** @@ -72,24 +76,26 @@ export class CoreReadingModeDirective implements AfterViewInit, OnDestroy { */ protected async addTextViewerButton(): Promise { const page = CoreDom.closest(this.element, '.ion-page'); - this.contentEl = page?.querySelector('ion-content') ?? undefined; + const contentEl = page?.querySelector('ion-content') ?? undefined; - const buttonsContainer = page?.querySelector('ion-header ion-toolbar ion-buttons[slot="end"]'); - - if (!buttonsContainer) { + const header = await CoreDom.findIonHeaderFromElement(this.element); + const buttonsContainer = header?.querySelector('ion-toolbar ion-buttons[slot="end"]'); + if (!buttonsContainer || !contentEl) { this.logger.warn('The header was not found, or it didn\'t have any ion-buttons on slot end.'); return; } + + contentEl.classList.add('core-reading-mode-content'); + if (buttonsContainer.querySelector('.core-text-viewer-button')) { + return; } - this.contentEl?.classList.add('core-reading-mode-content'); - - const header = CoreDirectivesRegistry.resolve(page?.querySelector('ion-header'), CoreCollapsibleHeaderDirective); - if (header) { - this.header = header; + const collapsibleHeader = CoreDirectivesRegistry.resolve(header, CoreCollapsibleHeaderDirective); + if (collapsibleHeader) { + this.header = collapsibleHeader; } const label = Translate.instant('core.viewer.enterreadingmode'); @@ -118,7 +124,6 @@ export class CoreReadingModeDirective implements AfterViewInit, OnDestroy { } else { this.showReadingSettings(); } - }); } @@ -214,8 +219,14 @@ export class CoreReadingModeDirective implements AfterViewInit, OnDestroy { * @inheritdoc */ ngOnDestroy(): void { - this.disableReadingMode(); this.viewportPromise?.cancel(); + + if (this.enabled && document.body.querySelectorAll('[core-reading-mode]')) { + // Do not disable if there are more instances of the directive in the DOM. + + return; + } + this.disableReadingMode(); } } diff --git a/src/core/singletons/dom.ts b/src/core/singletons/dom.ts index 0a2ddea57..f7cad2467 100644 --- a/src/core/singletons/dom.ts +++ b/src/core/singletons/dom.ts @@ -781,6 +781,44 @@ export class CoreDom { return !!units && units.length > 1; } + /** + * Search the ion-header of the page. + * This function is usually used to find the header of a page to add buttons. + * + * @returns The header element if found. + */ + static async findIonHeaderFromElement(element: HTMLElement): Promise { + await CoreDom.waitToBeInDOM(element); + let parentPage: HTMLElement | null = element; + + while (parentPage && parentPage.parentElement) { + const content = parentPage.closest('ion-content'); + if (content) { + // Sometimes ion-page class is not yet added by the ViewController, wait for content to render. + await content.componentOnReady(); + } + + parentPage = parentPage.parentElement.closest('.ion-page, .ion-page-hidden, .ion-page-invisible'); + + // Check if the page has a header. If it doesn't, search the next parent page. + let header = parentPage?.querySelector(':scope > ion-header'); + + if (header && getComputedStyle(header).display !== 'none') { + return header; + } + + // Find using content if any. + header = content?.parentElement?.querySelector(':scope > ion-header'); + + if (header && getComputedStyle(header).display !== 'none') { + return header; + } + } + + // Header not found, reject. + throw Error('Header not found.'); + } + } /** diff --git a/src/theme/components/reading-mode.scss b/src/theme/components/reading-mode.scss index 97aa4b5ef..2fec7a7b6 100644 --- a/src/theme/components/reading-mode.scss +++ b/src/theme/components/reading-mode.scss @@ -37,7 +37,8 @@ body.core-reading-mode-enabled { } } - ion-content.core-reading-mode-content { + ion-content.core-reading-mode-content, + ion-content.core-reading-mode-content core-split-view ion-content { --background: var(--reading-mode-background, --ion-background-color); background: var(--background);