Skip to content

Commit

Permalink
Merge pull request #3876 from dpalou/MOBILE-4479
Browse files Browse the repository at this point in the history
Mobile 4479
  • Loading branch information
crazyserver authored Dec 4, 2023
2 parents ef26d6d + fec29ec commit 76beb12
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 25 deletions.
22 changes: 9 additions & 13 deletions src/core/directives/collapsible-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,19 +428,15 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
return;
}

// Wait loadings to finish.
await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-loading', CoreLoadingComponent);

// Wait tabs to be ready.
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 CoreDirectivesRegistry.waitDirectivesReady(
this.page,
'core-tab core-loading, ion-router-outlet core-loading',
CoreLoadingComponent,
);
// Make sure elements have been added to the DOM.
await CoreUtils.nextTick();

// Wait all loadings and tabs to finish loading.
await CoreDirectivesRegistry.waitMultipleDirectivesReady(this.page, [
{ selector: 'core-loading', class: CoreLoadingComponent },
{ selector: 'core-tabs', class: CoreTabsComponent },
{ selector: 'core-tabs-outlet', class: CoreTabsOutletComponent },
]);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
</core-navbar-buttons>

<!-- Activity info. -->
<core-course-module-info [module]="module" [courseId]="courseId" [component]="component" [componentId]="module.id" />
<core-course-module-info *ngIf="addDefaultModuleInfo" [module]="module" [courseId]="courseId" [component]="component"
[componentId]="module.id" />

<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args"
[initResult]="initResult" [data]="jsData" [pageTitle]="pageTitle" [preSets]="preSets" (onContentLoaded)="contentLoaded($event)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
description?: string;

collapsibleFooterAppearOnBottom = true;
addDefaultModuleInfo = false;

displayOpenInBrowser = true;
displayDescription = true;
Expand Down Expand Up @@ -133,6 +134,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
* Function called when the data of the site plugin content is loaded.
*/
contentLoaded(data: CoreSitePluginsPluginContentLoadedData): void {
this.addDefaultModuleInfo = !data.content.includes('<core-course-module-info');
if (data.success) {
CoreCourse.storeModuleViewed(this.courseId, this.module.id, {
sectionId: this.module.section,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,11 +142,11 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck {
this.updateModuleCourseContent(cmId, alreadyFetched);
this.jsData.updateCachedContent = () => this.updateCachedContent();

this.onContentLoaded.emit({ refresh: !!refresh, success: true });
this.onContentLoaded.emit({ refresh: !!refresh, success: true, content: this.content });
} catch (error) {
// Make it think it's loaded - otherwise it sticks on 'loading' and stops navigation working.
this.content = '<div></div>';
this.onContentLoaded.emit({ refresh: !!refresh, success: false });
this.onContentLoaded.emit({ refresh: !!refresh, success: false, content: this.content });

CoreDomUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
} finally {
Expand Down Expand Up @@ -282,4 +282,5 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck {
export type CoreSitePluginsPluginContentLoadedData = {
refresh: boolean;
success: boolean;
content: string;
};
84 changes: 75 additions & 9 deletions src/core/singletons/directives-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,16 @@ export class CoreDirectivesRegistry {
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));
}

const findElements = (): Element[] => {
if (!selector || element.matches(selector)) {
// Element to wait is myself.
return [element];
} else {
return Array.from(element.querySelectorAll(selector));
}
};

const elements = findElements();
if (!elements.length) {
return;
}
Expand All @@ -135,6 +136,63 @@ export class CoreDirectivesRegistry {

// Wait for next tick to ensure directives are completely rendered.
await CoreUtils.nextTick();

// Check if there are new elements now that the found elements are ready (there could be nested elements).
if (elements.length !== findElements().length) {
await this.waitDirectivesReady(element, selector, directiveClass);
}
}

/**
* Get all directive instances (with multiple types) and wait for them to be ready.
*
* @param element Root element.
* @param directives Directives to wait.
* @returns Promise resolved when done.
*/
static async waitMultipleDirectivesReady(
element: Element,
directives: DirectiveData<AsyncDirective>[],
): Promise<void> {
const findElements = (selector?: string): Element[] => {
if (!selector || element.matches(selector)) {
// Element to wait is myself.
return [element];
} else {
return Array.from(element.querySelectorAll(selector));
}
};

let allElements: Element[] = [];

await Promise.all(directives.map(async directive => {
const elements = findElements(directive.selector);
if (!elements.length) {
return;
}

allElements = allElements.concat(elements);

await Promise.all(elements.map(async element => {
const instances = this.resolveAll<AsyncDirective>(element, directive.class);

await Promise.all(instances.map(instance => instance.ready()));
}));
}));

// Wait for next tick to ensure directives are completely rendered.
await CoreUtils.nextTick();

// Check if there are new elements now that the found elements are ready (there could be nested elements).
const elementsAfterReady = directives.reduce((elements, directive) => {
elements = elements.concat(findElements(directive.selector));

return elements;
}, <Element[]> []);

if (allElements.length !== elementsAfterReady.length) {
await this.waitMultipleDirectivesReady(element, directives);
}
}

}
Expand All @@ -144,3 +202,11 @@ export class CoreDirectivesRegistry {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type DirectiveConstructor<T = Directive> = { new(...args: any[]): T };

/**
* Data to identify a directive when waiting for ready.
*/
type DirectiveData<T extends AsyncDirective> = {
selector?: string; // If defined, CSS Selector to wait for.
class?: DirectiveConstructor<T>; // Directive class.
};

0 comments on commit 76beb12

Please sign in to comment.