-
-
-
+
-
-
-
-
+
+
+
+
{{course.startdate * 1000 | coreFormatDate:"strftimedatefullshort" }}
- {{course.enddate * 1000 | coreFormatDate:"strftimedatefullshort" }}
+
+
+
+
+
+ {{'core.summary' | translate}}
+
-
-
+
+
{{ 'core.teachers' | translate }}
-
@@ -62,7 +67,7 @@
-
+
@@ -83,7 +88,8 @@
-
+
+
{{ instance.name }}
@@ -92,23 +98,24 @@
-
-
-
- {{ 'core.courses.paypalaccepted' | translate }}
- {{ 'core.paymentinstant' | translate }}
-
- {{ 'core.courses.sendpaymentbutton' | translate }}
-
-
-
-
-
- {{ 'core.courses.notenrollable' | translate }}
-
-
-
+
+
+ {{ 'core.courses.paypalaccepted' | translate }}
+ {{ 'core.paymentinstant' | translate }}
+
+ {{ 'core.courses.sendpaymentbutton' | translate }}
+
+
+
+
+
+ {{ 'core.courses.notenrollable' | translate }}
+
+
+
+
+
@@ -116,23 +123,24 @@
[name]="prefetchCourseData.icon" color="success" aria-hidden="true" role="status">
-
- {{ 'core.course.downloadcourse' | translate }}
- {{ 'core.course.refreshcourse' | translate }}
-
-
-
+ {{ 'core.course.downloadcourse' | translate }}
+ {{ 'core.course.refreshcourse' | translate }}
+
+
+
- {{ 'core.course' | translate }}
+ {{ 'core.course' | translate }}
-
-
+
+
+
- {{ 'core.openinbrowser' | translate }}
+ {{ 'core.openinbrowser' | translate }}
-
+
+
diff --git a/src/core/features/course/pages/preview/preview.page.ts b/src/core/features/course/pages/preview/preview.page.ts
index 923eb7109..8c1f9b9ce 100644
--- a/src/core/features/course/pages/preview/preview.page.ts
+++ b/src/core/features/course/pages/preview/preview.page.ts
@@ -20,8 +20,8 @@ import { CoreSites } from '@services/sites';
import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import {
+ CoreCourseCustomField,
CoreCourseEnrolmentMethod,
- CoreCourseGetCoursesData,
CoreCourses,
CoreCourseSearchedData,
CoreCoursesProvider,
@@ -34,6 +34,8 @@ import { Translate } from '@singletons';
import { CoreConstants } from '@/core/constants';
import { CoreCoursesSelfEnrolPasswordComponent } from '../../../courses/components/self-enrol-password/self-enrol-password';
import { CoreNavigator } from '@services/navigator';
+import { CoreUtils } from '@services/utils/utils';
+import { CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper';
/**
* Page that allows "previewing" a course and enrolling in it if enabled and not enrolled.
@@ -45,12 +47,13 @@ import { CoreNavigator } from '@services/navigator';
})
export class CoreCoursePreviewPage implements OnInit, OnDestroy {
- course?: CoreCourseSearchedData;
+ course?: CoreCourseSummaryData;
isEnrolled = false;
canAccessCourse = true;
selfEnrolInstances: CoreCourseEnrolmentMethod[] = [];
paypalEnabled = false;
dataLoaded = false;
+ avoidOpenCourse = false;
prefetchCourseData: CorePrefetchStatusInfo = {
icon: '',
statusTranslatable: 'core.loading',
@@ -64,6 +67,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
courseUrl = '';
courseImageUrl?: string;
isMobile: boolean;
+ progress?: number;
protected isGuestEnabled = false;
protected useGuestAccess = false;
@@ -74,6 +78,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
protected paypalReturnUrl = '';
protected pageDestroyed = false;
protected courseStatusObserver?: CoreEventObserver;
+ protected courseId!: number;
constructor(
protected zone: NgZone,
@@ -84,7 +89,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
if (this.downloadCourseEnabled) {
// Listen for status change in course.
this.courseStatusObserver = CoreEvents.on(CoreEvents.COURSE_STATUS_CHANGED, (data) => {
- if (data.courseId == this.course!.id || data.courseId == CoreCourseProvider.ALL_COURSES_CLEARED) {
+ if (data.courseId == this.courseId || data.courseId == CoreCourseProvider.ALL_COURSES_CLEARED) {
this.updateCourseStatus(data.status);
}
}, CoreSites.getCurrentSiteId());
@@ -92,27 +97,25 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
}
/**
- * View loaded.
+ * @inheritdoc
*/
async ngOnInit(): Promise
{
- this.course = CoreNavigator.getRouteParam('course');
-
- if (!this.course) {
+ try {
+ this.courseId = CoreNavigator.getRequiredRouteNumberParam('courseId');
+ } catch (error) {
+ CoreDomUtils.showErrorModal(error);
CoreNavigator.back();
return;
}
- const currentSite = CoreSites.getCurrentSite();
- const currentSiteUrl = currentSite && currentSite.getURL();
+ this.avoidOpenCourse = !!CoreNavigator.getRouteBooleanParam('avoidOpenCourse');
+ this.course = CoreNavigator.getRouteParam('course');
- this.paypalEnabled = this.course!.enrollmentmethods?.indexOf('paypal') > -1;
- this.enrolUrl = CoreTextUtils.concatenatePaths(currentSiteUrl!, 'enrol/index.php?id=' + this.course!.id);
- this.courseUrl = CoreTextUtils.concatenatePaths(currentSiteUrl!, 'course/view.php?id=' + this.course!.id);
- this.paypalReturnUrl = CoreTextUtils.concatenatePaths(currentSiteUrl!, 'enrol/paypal/return.php');
- if (this.course.overviewfiles.length > 0) {
- this.courseImageUrl = this.course.overviewfiles[0].fileurl;
- }
+ const currentSiteUrl = CoreSites.getRequiredCurrentSite().getURL();
+ this.enrolUrl = CoreTextUtils.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.courseId);
+ this.courseUrl = CoreTextUtils.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.courseId);
+ this.paypalReturnUrl = CoreTextUtils.concatenatePaths(currentSiteUrl, 'enrol/paypal/return.php');
try {
await this.getCourse();
@@ -120,11 +123,11 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
if (this.downloadCourseEnabled) {
// Determine course prefetch icon.
- this.prefetchCourseData = await CoreCourseHelper.getCourseStatusIconAndTitle(this.course!.id);
+ this.prefetchCourseData = await CoreCourseHelper.getCourseStatusIconAndTitle(this.courseId);
if (this.prefetchCourseData.loading) {
// Course is being downloaded. Get the download promise.
- const promise = CoreCourseHelper.getCourseDownloadPromise(this.course!.id);
+ const promise = CoreCourseHelper.getCourseDownloadPromise(this.courseId);
if (promise) {
// There is a download promise. If it fails, show an error.
promise.catch((error) => {
@@ -134,7 +137,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
});
} else {
// No download, this probably means that the app was closed while downloading. Set previous status.
- CoreCourse.setCoursePreviousStatus(this.course!.id);
+ CoreCourse.setCoursePreviousStatus(this.courseId);
}
}
}
@@ -177,13 +180,15 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
this.selfEnrolInstances = [];
try {
- this.enrolmentMethods = await CoreCourses.getCourseEnrolmentMethods(this.course!.id);
+ this.enrolmentMethods = await CoreCourses.getCourseEnrolmentMethods(this.courseId);
this.enrolmentMethods.forEach((method) => {
if (method.type === 'self') {
this.selfEnrolInstances.push(method);
} else if (method.type === 'guest') {
this.isGuestEnabled = true;
+ } else if (method.type === 'paypal') {
+ this.paypalEnabled = true;
}
});
} catch (error) {
@@ -191,22 +196,17 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
}
try {
- let course: CoreEnrolledCourseData | CoreCourseGetCoursesData;
-
// Check if user is enrolled in the course.
try {
- course = await CoreCourses.getUserCourse(this.course!.id);
+ this.course = await CoreCourses.getUserCourse(this.courseId);
this.isEnrolled = true;
} catch {
// The user is not enrolled in the course. Use getCourses to see if it's an admin/manager and can see the course.
this.isEnrolled = false;
-
- course = await CoreCourses.getCourse(this.course!.id);
+ this.course = await CoreCourses.getCourse(this.courseId);
}
// Success retrieving the course, we can assume the user has permissions to view it.
- this.course!.fullname = course.fullname || this.course!.fullname;
- this.course!.summary = course.summary || this.course!.summary;
this.canAccessCourse = true;
this.useGuestAccess = false;
} catch {
@@ -219,14 +219,37 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
}
}
- if (!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) {
- try {
- const course = await CoreCourses.getCourseByField('id', this.course!.id);
+ if (this.course && 'overviewfiles' in this.course && this.course.overviewfiles?.length) {
+ this.courseImageUrl = this.course.overviewfiles[0].fileurl;
+ }
- this.course!.customfields = course.customfields;
- } catch {
- // Ignore errors.
+ try {
+ const courseByField = await CoreCourses.getCourseByField('id', this.courseId);
+ if (this.course) {
+ this.course.customfields = courseByField.customfields;
+ this.course.contacts = courseByField.contacts;
+ this.course.displayname = courseByField.displayname;
+ this.course.categoryname = courseByField.categoryname;
+ this.course.overviewfiles = courseByField.overviewfiles;
+ } else {
+ this.course = courseByField;
}
+
+ this.paypalEnabled = !this.isEnrolled && courseByField.enrollmentmethods?.indexOf('paypal') > -1;
+
+ } catch {
+ // Ignore errors.
+ }
+
+ if (!this.course ||
+ !('progress' in this.course) ||
+ typeof this.course.progress !== 'number' ||
+ this.course.progress < 0 ||
+ this.course.completionusertracked === false
+ ) {
+ this.progress = undefined;
+ } else {
+ this.progress = this.course.progress;
}
this.dataLoaded = true;
@@ -234,13 +257,15 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
/**
* Open the course.
+ *
+ * @param replaceCurrentPage If current place should be replaced in the navigation stack.
*/
- openCourse(): void {
- if (!this.canAccessCourse) {
+ openCourse(replaceCurrentPage = false): void {
+ if (!this.canAccessCourse || !this.course || this.avoidOpenCourse) {
return;
}
- CoreCourseHelper.openCourse(this.course!, { isGuest: this.useGuestAccess });
+ CoreCourseHelper.openCourse(this.course, { params: { isGuest: this.useGuestAccess }, replace: replaceCurrentPage });
}
/**
@@ -279,7 +304,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
};
// Open the enrolment page in InAppBrowser.
- const window = await CoreSites.getCurrentSite()!.openInAppWithAutoLogin(this.enrolUrl);
+ const window = await CoreSites.getRequiredCurrentSite().openInAppWithAutoLogin(this.enrolUrl);
// Observe loaded pages in the InAppBrowser to check if the enrol process has ended.
const inAppLoadSubscription = window.on('loadstart').subscribe((event) => {
@@ -319,7 +344,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
const modal = await CoreDomUtils.showModalLoading('core.loading', true);
try {
- await CoreCourses.selfEnrol(this.course!.id, password, instanceId);
+ await CoreCourses.selfEnrol(this.courseId, password, instanceId);
// Close modal and refresh data.
this.isEnrolled = true;
@@ -331,13 +356,13 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
await this.refreshData().finally(() => {
// My courses have been updated, trigger event.
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
- courseId: this.course!.id,
+ courseId: this.courseId,
course: this.course,
action: CoreCoursesProvider.ACTION_ENROL,
}, CoreSites.getCurrentSiteId());
});
- this.openCourse();
+ this.openCourse(true);
modal?.dismiss();
} catch (error) {
@@ -378,12 +403,10 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
const promises: Promise[] = [];
promises.push(CoreCourses.invalidateUserCourses());
- promises.push(CoreCourses.invalidateCourse(this.course!.id));
- promises.push(CoreCourses.invalidateCourseEnrolmentMethods(this.course!.id));
- promises.push(CoreCourseOptionsDelegate.clearAndInvalidateCoursesOptions(this.course!.id));
- if (CoreSites.getCurrentSite() && !CoreSites.getCurrentSite()!.isVersionGreaterEqualThan('3.7')) {
- promises.push(CoreCourses.invalidateCoursesByField('id', this.course!.id));
- }
+ promises.push(CoreCourses.invalidateCourse(this.courseId));
+ promises.push(CoreCourses.invalidateCourseEnrolmentMethods(this.courseId));
+ promises.push(CoreCourseOptionsDelegate.clearAndInvalidateCoursesOptions(this.courseId));
+ promises.push(CoreCourses.invalidateCoursesByField('id', this.courseId));
if (this.guestInstanceId) {
promises.push(CoreCourses.invalidateCourseGuestEnrolmentInfo(this.guestInstanceId));
}
@@ -419,14 +442,10 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
}
// Check if user is enrolled in the course.
- try {
- CoreCourses.invalidateUserCourses();
- } catch {
- // Ignore errors.
- }
+ await CoreUtils.ignoreErrors(CoreCourses.invalidateUserCourses());
try {
- await CoreCourses.getUserCourse(this.course!.id);
+ await CoreCourses.getUserCourse(this.courseId);
} catch {
// Not enrolled, wait a bit and try again.
if (this.pageDestroyed || (Date.now() - this.waitStart > 60000)) {
@@ -451,7 +470,7 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
*/
async prefetchCourse(): Promise {
try {
- await CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course!, {
+ await CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course as CoreEnrolledCourseData, {
isGuest: this.useGuestAccess,
});
} catch (error) {
@@ -462,14 +481,20 @@ export class CoreCoursePreviewPage implements OnInit, OnDestroy {
}
/**
- * Page destroyed.
+ * @inheritdoc
*/
ngOnDestroy(): void {
this.pageDestroyed = true;
-
- if (this.courseStatusObserver) {
- this.courseStatusObserver.off();
- }
+ this.courseStatusObserver?.off();
}
}
+
+type CoreCourseSummaryData = CoreCourseWithImageAndColor & (CoreEnrolledCourseData | CoreCourseSearchedData) & {
+ contacts?: { // Contact users.
+ id: number; // Contact user id.
+ fullname: string; // Contact user fullname.
+ }[];
+ customfields?: CoreCourseCustomField[]; // Custom fields and associated values.
+ categoryname?: string; // Category name.
+};
diff --git a/src/core/features/course/pages/preview/preview.scss b/src/core/features/course/pages/preview/preview.scss
index 161f3647a..8f159c333 100644
--- a/src/core/features/course/pages/preview/preview.scss
+++ b/src/core/features/course/pages/preview/preview.scss
@@ -1,41 +1,43 @@
:host {
- --scroll-factor: 0.5;
- --translate-z: calc(-2 * var(--scroll-factor))px;
- --scale: calc(1 + var(--scroll-factor) * 2);
+ ion-content:not(.animating) {
+ &::part(scroll) {
+ perspective: 1px;
+ perspective-origin: center top;
+ transform-style: preserve-3d;
+ }
- perspective: 1px;
- perspective-origin: center top;
- transform-style: preserve-3d;
+ .core-course-thumb {
+ transform-origin: center top;
- // @todo This parallax effect caused the image to be scaled during page transitions,
- // and in some devices it seems like the problem persisted even after the transition.
- // We should decide whether we want to keep this parallax or not, and if we do fix
- // the problem or find an alternative implementation. For now, it's disabled.
+ --scroll-factor: 0.5;
+ --translate-z: calc(-2 * var(--scroll-factor))px;
+ --scale: calc(1 + var(--scroll-factor) * 2);
+
+ /**
+ * Calculated with scroll-factor: 0.5;
+ * translate-z: -2 * $scroll-factor px;
+ * scale: 1 + $scroll-factor * 2;
+ */
+ transform: translateZ(-1px) scale(2);
+ }
+ }
+
+ .core-course-thumb-parallax-content {
+ transform: translateZ(0);
+ -webkit-filter: drop-shadow(0px -3px 3px rgba(var(--drop-shadow)));
+ filter: drop-shadow(0px -3px 3px rgba(var(--drop-shadow)));
+ }
+
+ .core-course-thumb-parallax {
+ height: 40vw;
+ max-height: 35vh;
+ z-index: -1;
+ overflow: hidden;
+ }
- // .core-course-thumb-parallax-content {
- // transform: translateZ(0);
- // -webkit-filter: drop-shadow(0px -3px 3px rgba(var(--drop-shadow)));
- // filter: drop-shadow(0px -3px 3px rgba(var(--drop-shadow)));
- // }
- // .core-course-thumb-parallax {
- // height: 40vw;
- // max-height: 35vh;
- // z-index: -1;
- // overflow: hidden;
- // }
.core-course-thumb {
overflow: hidden;
text-align: center;
- cursor: pointer;
- pointer-events: auto;
- transform-origin: center top;
-
- /**
- * Calculated with scroll-factor: 0.5;
- * translate-z: -2 * $scroll-factor px;
- * scale: 1 + $scroll-factor * 2;
- */
- // transform: translateZ(-1px) scale(2);
}
diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts
index 737a405ae..56dee5790 100644
--- a/src/core/features/course/services/course-helper.ts
+++ b/src/core/features/course/services/course-helper.ts
@@ -68,7 +68,7 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events';
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
import { CoreNetworkError } from '@classes/errors/network-error';
import { CoreSiteHome } from '@features/sitehome/services/sitehome';
-import { CoreNavigator } from '@services/navigator';
+import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { CoreSiteHomeHomeHandlerService } from '@features/sitehome/services/handlers/sitehome-home';
import { CoreStatusWithWarningsWSResponse } from '@services/ws';
@@ -1178,7 +1178,7 @@ export class CoreCourseHelperProvider {
modal?.dismiss();
- return this.openCourse(course, params, siteId);
+ return this.openCourse(course, { params , siteId });
}
/**
@@ -2020,20 +2020,25 @@ export class CoreCourseHelperProvider {
* they will see the result immediately.
*
* @param course Course to open
- * @param params Params to pass to the course page.
- * @param siteId Site ID. If not defined, current site.
+ * @param navOptions Navigation options that includes params to pass to the page.
* @return Promise resolved when done.
*/
- async openCourse(course: CoreCourseAnyCourseData | { id: number }, params?: Params, siteId?: string): Promise {
+ async openCourse(
+ course: CoreCourseAnyCourseData | { id: number },
+ navOptions?: CoreNavigationOptions & { siteId?: string },
+ ): Promise {
+ const siteId = navOptions?.siteId;
if (!siteId || siteId == CoreSites.getCurrentSiteId()) {
// Current site, we can open the course.
- return CoreCourse.openCourse(course, params);
+ return CoreCourse.openCourse(course, navOptions);
} else {
// We need to load the site first.
- params = params || {};
- Object.assign(params, { course: course });
+ navOptions = navOptions || {};
- await CoreNavigator.navigateToSitePath(`course/${course.id}`, { siteId, params });
+ navOptions.params = navOptions.params || {};
+ Object.assign(navOptions.params, { course: course });
+
+ await CoreNavigator.navigateToSitePath(`course/${course.id}`, navOptions);
}
}
diff --git a/src/core/features/course/services/course.ts b/src/core/features/course/services/course.ts
index 001452497..fa30f2991 100644
--- a/src/core/features/course/services/course.ts
+++ b/src/core/features/course/services/course.ts
@@ -43,7 +43,7 @@ import { CoreCourseLogCronHandler } from './handlers/log-cron';
import { CoreSitePlugins } from '@features/siteplugins/services/siteplugins';
import { CoreCourseAutoSyncData, CoreCourseSyncProvider } from './sync';
import { CoreTagItem } from '@features/tag/services/tag';
-import { CoreNavigator } from '@services/navigator';
+import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { CoreCourseModuleDelegate } from './module-delegate';
const ROOT_CACHE_KEY = 'mmCourse:';
@@ -1177,10 +1177,13 @@ export class CoreCourseProvider {
* This function must be in here instead of course helper to prevent circular dependencies.
*
* @param course Course to open
- * @param params Other params to pass to the course page.
+ * @param navOptions Navigation options that includes params to pass to the page.
* @return Promise resolved when done.
*/
- async openCourse(course: CoreCourseAnyCourseData | { id: number }, params?: Params): Promise {
+ async openCourse(
+ course: CoreCourseAnyCourseData | { id: number },
+ navOptions?: CoreNavigationOptions,
+ ): Promise {
const loading = await CoreDomUtils.showModalLoading();
// Wait for site plugins to be fetched.
@@ -1197,7 +1200,7 @@ export class CoreCourseProvider {
if (!format || !CoreSitePlugins.sitePluginPromiseExists(`format_${format}`)) {
// No custom format plugin. We don't need to wait for anything.
loading.dismiss();
- await CoreCourseFormatDelegate.openCourse( course, params);
+ await CoreCourseFormatDelegate.openCourse( course, navOptions);
return;
}
@@ -1208,7 +1211,7 @@ export class CoreCourseProvider {
// The format loaded successfully, but the handlers wont be registered until all site plugins have loaded.
if (CoreSitePlugins.sitePluginsFinishedLoading) {
- return CoreCourseFormatDelegate.openCourse( course, params);
+ return CoreCourseFormatDelegate.openCourse( course, navOptions);
}
// Wait for plugins to be loaded.
@@ -1217,7 +1220,7 @@ export class CoreCourseProvider {
const observer = CoreEvents.on(CoreEvents.SITE_PLUGINS_LOADED, () => {
observer?.off();
- CoreCourseFormatDelegate.openCourse( course, params)
+ CoreCourseFormatDelegate.openCourse( course, navOptions)
.then(deferred.resolve).catch(deferred.reject);
});
diff --git a/src/core/features/course/services/format-delegate.ts b/src/core/features/course/services/format-delegate.ts
index 967903d58..4bfb14bc7 100644
--- a/src/core/features/course/services/format-delegate.ts
+++ b/src/core/features/course/services/format-delegate.ts
@@ -13,10 +13,10 @@
// limitations under the License.
import { Injectable, Type } from '@angular/core';
-import { Params } from '@angular/router';
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
import { CoreCourseAnyCourseData } from '@features/courses/services/courses';
+import { CoreNavigationOptions } from '@services/navigator';
import { makeSingleton } from '@singletons';
import { CoreCourseWSSection } from './course';
import { CoreCourseSection } from './course-helper';
@@ -100,10 +100,10 @@ export interface CoreCourseFormatHandler extends CoreDelegateHandler {
* Your page should include the course handlers using CoreCoursesDelegate.
*
* @param course The course to open. It should contain a "format" attribute.
- * @param params Params to pass to the course page.
+ * @param navOptions Navigation options that includes params to pass to the page.
* @return Promise resolved when done.
*/
- openCourse?(course: CoreCourseAnyCourseData, params?: Params): Promise;
+ openCourse?(course: CoreCourseAnyCourseData, navOptions?: CoreNavigationOptions): Promise;
/**
* Return the Component to use to display the course format instead of using the default one.
@@ -323,11 +323,11 @@ export class CoreCourseFormatDelegateService extends CoreDelegate {
- await this.executeFunctionOnEnabled(course.format || '', 'openCourse', [course, params]);
+ async openCourse(course: CoreCourseAnyCourseData, navOptions?: CoreNavigationOptions): Promise {
+ await this.executeFunctionOnEnabled(course.format || '', 'openCourse', [course, navOptions]);
}
/**
diff --git a/src/core/features/course/services/handlers/default-format.ts b/src/core/features/course/services/handlers/default-format.ts
index 4ef53ca4b..d7254f194 100644
--- a/src/core/features/course/services/handlers/default-format.ts
+++ b/src/core/features/course/services/handlers/default-format.ts
@@ -13,12 +13,9 @@
// limitations under the License.
import { Injectable } from '@angular/core';
-import { Params } from '@angular/router';
-
import { CoreCourseAnyCourseData, CoreCourses } from '@features/courses/services/courses';
-import { CoreNavigator } from '@services/navigator';
+import { CoreNavigationOptions, CoreNavigator } from '@services/navigator';
import { CoreUtils } from '@services/utils/utils';
-import { CoreCourseWSSection } from '../course';
import { CoreCourseSection } from '../course-helper';
import { CoreCourseFormatHandler } from '../format-delegate';
@@ -32,19 +29,14 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
format = 'default';
/**
- * Whether or not the handler is enabled on a site level.
- *
- * @return Promise resolved with true if enabled.
+ * @inheritdoc
*/
async isEnabled(): Promise {
return true;
}
/**
- * Get the title to use in course page.
- *
- * @param course The course.
- * @return Title.
+ * @inheritdoc
*/
getCourseTitle(course: CoreCourseAnyCourseData): string {
if (course.displayname) {
@@ -57,57 +49,35 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
}
/**
- * Whether it allows seeing all sections at the same time. Defaults to true.
- *
- * @param course The course to check.
- * @return Whether it can view all sections.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- canViewAllSections(course: CoreCourseAnyCourseData): boolean {
+ canViewAllSections(): boolean {
return true;
}
/**
- * Whether the option blocks should be displayed. Defaults to true.
- *
- * @param course The course to check.
- * @return Whether it can display blocks.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- displayBlocks(course: CoreCourseAnyCourseData): boolean {
+ displayBlocks(): boolean {
return true;
}
/**
- * Whether the default section selector should be displayed. Defaults to true.
- *
- * @param course The course to check.
- * @return Whether the default section selector should be displayed.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- displaySectionSelector(course: CoreCourseAnyCourseData): boolean {
+ displaySectionSelector(): boolean {
return true;
}
/**
- * Whether the course refresher should be displayed. If it returns false, a refresher must be included in the course format,
- * and the doRefresh method of CoreCourseSectionPage must be called on refresh. Defaults to true.
- *
- * @param course The course to check.
- * @param sections List of course sections.
- * @return Whether the refresher should be displayed.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- displayRefresher(course: CoreCourseAnyCourseData, sections: CoreCourseWSSection[]): boolean {
+ displayRefresher(): boolean {
return true;
}
/**
- * Given a list of sections, get the "current" section that should be displayed first.
- *
- * @param course The course to get the title.
- * @param sections List of sections.
- * @return Current section (or promise resolved with current section).
+ * @inheritdoc
*/
async getCurrentSection(course: CoreCourseAnyCourseData, sections: CoreCourseSection[]): Promise {
let marker: number | undefined;
@@ -137,48 +107,33 @@ export class CoreCourseFormatDefaultHandler implements CoreCourseFormatHandler {
}
/**
- * Invalidate the data required to load the course format.
- *
- * @param course The course to get the title.
- * @param sections List of sections.
- * @return Promise resolved when the data is invalidated.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- async invalidateData(course: CoreCourseAnyCourseData, sections: CoreCourseWSSection[]): Promise {
+ async invalidateData(course: CoreCourseAnyCourseData): Promise {
await CoreCourses.invalidateCoursesByField('id', course.id);
}
/**
- * Open the page to display a course. If not defined, the page CoreCourseSectionPage will be opened.
- * Implement it only if you want to create your own page to display the course. In general it's better to use the method
- * getCourseFormatComponent because it will display the course handlers at the top.
- * Your page should include the course handlers using CoreCoursesDelegate.
- *
- * @param course The course to open. It should contain a "format" attribute.
- * @param params Params to pass to the course page.
- * @return Promise resolved when done.
+ * @inheritdoc
*/
- async openCourse(course: CoreCourseAnyCourseData, params?: Params): Promise {
- params = params || {};
- Object.assign(params, { course: course });
+ async openCourse(course: CoreCourseAnyCourseData, navOptions?: CoreNavigationOptions): Promise {
+ navOptions = navOptions || {};
+
+ navOptions.params = navOptions.params || {};
+ Object.assign(navOptions.params, { course: course });
// Don't return the .push promise, we don't want to display a loading modal during the page transition.
const currentTab = CoreNavigator.getCurrentMainMenuTab();
const routeDepth = CoreNavigator.getRouteDepth(`/main/${currentTab}/course/${course.id}`);
const deepPath = '/deep'.repeat(routeDepth);
- CoreNavigator.navigateToSitePath(`course${deepPath}/${course.id}`, { params });
+ CoreNavigator.navigateToSitePath(`course${deepPath}/${course.id}`, navOptions);
}
/**
- * Whether the view should be refreshed when completion changes. If your course format doesn't display
- * activity completion then you should return false.
- *
- * @param course The course.
- * @return Whether course view should be refreshed when an activity completion changes.
+ * @inheritdoc
*/
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- async shouldRefreshWhenCompletionChanges(course: CoreCourseAnyCourseData): Promise {
+ async shouldRefreshWhenCompletionChanges(): Promise {
return true;
}
diff --git a/src/core/features/courses/components/course-list-item/course-list-item.ts b/src/core/features/courses/components/course-list-item/course-list-item.ts
index bf9d4419f..5a5f5fa24 100644
--- a/src/core/features/courses/components/course-list-item/course-list-item.ts
+++ b/src/core/features/courses/components/course-list-item/course-list-item.ts
@@ -171,7 +171,7 @@ export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, On
CoreCourseHelper.openCourse(this.course);
} else {
CoreNavigator.navigateToSitePath(
- '/course/' + this.course.id + '/preview',
+ `/course/${this.course.id}/preview`,
{ params: { course: this.course } },
);
}
diff --git a/src/core/features/courses/services/handlers/course-link.ts b/src/core/features/courses/services/handlers/course-link.ts
index 5e1800ddb..5c7347844 100644
--- a/src/core/features/courses/services/handlers/course-link.ts
+++ b/src/core/features/courses/services/handlers/course-link.ts
@@ -156,7 +156,7 @@ export class CoreCoursesCourseLinkHandlerService extends CoreContentLinksHandler
modal.dismiss();
// Now open the course.
- CoreCourseHelper.openCourse(course, pageParams);
+ CoreCourseHelper.openCourse(course, { params: pageParams });
}
/**
diff --git a/src/core/lang.json b/src/core/lang.json
index 6690dc4bb..624038e0b 100644
--- a/src/core/lang.json
+++ b/src/core/lang.json
@@ -301,6 +301,7 @@
"strftimetime24": "%H:%M",
"submit": "Submit",
"success": "Success",
+ "summary": "Summary",
"tablet": "Tablet",
"teachers": "Teachers",
"thereisdatatosync": "There are offline {{$a}} to be synchronised.",
diff --git a/upgrade.txt b/upgrade.txt
index 79ccced1d..e55234e0d 100644
--- a/upgrade.txt
+++ b/upgrade.txt
@@ -15,6 +15,7 @@ information provided here is intended especially for developers.
The function CoreUserDelegate.getProfileHandlersFor must now receive a context + contextId instead of a courseId.
The user handler function isEnabledForCourse is now called isEnabledForContext and receives a context + contextId instead of a courseId.
Some user handler's functions have also changed to accept context + contextId instead of a courseId: isEnabledForUser, getDisplayData, action.
+- CoreCourseHelperProvider.openCourse parameters changed, now it admits CoreNavigationOptions + siteId on the same object that includes Params passed to page.
=== 3.9.5 ===