MOBILE-3063 reading-mode: Find header in splitview if needed

main
Pau Ferrer Ocaña 2024-12-17 11:10:44 +01:00
parent e6733bbd65
commit 170817ed7c
4 changed files with 65 additions and 52 deletions

View File

@ -89,7 +89,7 @@ export class CoreNavBarButtonsComponent implements OnInit, OnDestroy {
*/
async ngOnInit(): Promise<void> {
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<HTMLIonHeaderElement> {
await CoreDom.waitToBeInDOM(this.element);
let parentPage: HTMLElement | null = this.element;
while (parentPage && parentPage.parentElement) {
const content = parentPage.closest<HTMLIonContentElement>('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<HTMLIonHeaderElement>(':scope > ion-header');
if (header && getComputedStyle(header).display !== 'none') {
return header;
}
// Find using content if any.
header = content?.parentElement?.querySelector<HTMLIonHeaderElement>(':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.
*/

View File

@ -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<void> {
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<void> {
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<HTMLIonButtonsElement>('ion-header ion-toolbar ion-buttons[slot="end"]');
if (!buttonsContainer) {
const header = await CoreDom.findIonHeaderFromElement(this.element);
const buttonsContainer = header?.querySelector<HTMLIonButtonsElement>('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();
}
}

View File

@ -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<HTMLElement | null> {
await CoreDom.waitToBeInDOM(element);
let parentPage: HTMLElement | null = element;
while (parentPage && parentPage.parentElement) {
const content = parentPage.closest<HTMLIonContentElement>('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<HTMLIonHeaderElement>(':scope > ion-header');
if (header && getComputedStyle(header).display !== 'none') {
return header;
}
// Find using content if any.
header = content?.parentElement?.querySelector<HTMLIonHeaderElement>(':scope > ion-header');
if (header && getComputedStyle(header).display !== 'none') {
return header;
}
}
// Header not found, reject.
throw Error('Header not found.');
}
}
/**

View File

@ -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);