From 08d7d6e1f9595cee554ea7a8b6cb6518bee857ef Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 25 Mar 2019 14:33:51 +0100 Subject: [PATCH 01/13] MOBILE-2915 split: Fix call split push too soon --- src/components/split-view/split-view.ts | 28 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/components/split-view/split-view.ts b/src/components/split-view/split-view.ts index ac9e434f5..3e26f6e86 100644 --- a/src/components/split-view/split-view.ts +++ b/src/components/split-view/split-view.ts @@ -49,7 +49,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy { @ViewChild('menu') menu: Menu; @Input() when?: string | boolean = 'md'; - protected isEnabled = false; + protected isEnabled; protected masterPageName = ''; protected masterPageIndex = 0; protected loadDetailPage: any = false; @@ -174,7 +174,7 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy { * @return {boolean} If split view is enabled. */ isOn(): boolean { - return this.isEnabled; + return !!this.isEnabled; } /** @@ -182,16 +182,24 @@ export class CoreSplitViewComponent implements OnInit, OnDestroy { * * @param {any} page The component class or deeplink name you want to push onto the navigation stack. * @param {any} params Any NavParams you want to pass along to the next view. + * @param {boolean} [retrying] Whether it's retrying. */ - push(page: any, params?: any): void { - if (this.isEnabled) { - this.detailNav.setRoot(page, params); + push(page: any, params?: any, retrying?: boolean): void { + if (typeof this.isEnabled == 'undefined' && !retrying) { + // Hasn't calculated if it's enabled yet. Wait a bit and try again. + setTimeout(() => { + this.push(page, params, true); + }, 200); } else { - this.loadDetailPage = { - component: page, - data: params - }; - this.masterNav.push(page, params); + if (this.isEnabled) { + this.detailNav.setRoot(page, params); + } else { + this.loadDetailPage = { + component: page, + data: params + }; + this.masterNav.push(page, params); + } } } From b3663e591c28d1eb6b7276f08cbc5762ec2a1648 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 26 Mar 2019 12:05:37 +0100 Subject: [PATCH 02/13] MOBILE-2915 desktop: Fix 'push' click in desktop apps --- src/core/emulator/providers/local-notifications.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/core/emulator/providers/local-notifications.ts b/src/core/emulator/providers/local-notifications.ts index bcf07ca6b..3b943aba1 100644 --- a/src/core/emulator/providers/local-notifications.ts +++ b/src/core/emulator/providers/local-notifications.ts @@ -294,10 +294,6 @@ export class LocalNotificationsMock extends LocalNotifications { notification.timeoutAfter = this.parseToInt('timeoutAfter', notification); } - if (typeof notification.data == 'object') { - notification.data = JSON.stringify(notification.data); - } - this.convertPriority(notification); this.convertTrigger(notification); this.convertActions(notification); From 63cfc0604a9ee78f03b5ab0bdb3eacdd23904409 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 26 Mar 2019 16:13:23 +0100 Subject: [PATCH 03/13] MOBILE-2915 ios: Fix shared files treated twice in iOS 12 --- src/core/sharedfiles/sharedfiles.module.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/core/sharedfiles/sharedfiles.module.ts b/src/core/sharedfiles/sharedfiles.module.ts index 82c41169a..692ace04d 100644 --- a/src/core/sharedfiles/sharedfiles.module.ts +++ b/src/core/sharedfiles/sharedfiles.module.ts @@ -44,15 +44,27 @@ export class CoreSharedFilesModule { delegate.registerHandler(handler); if (platform.is('ios')) { + let lastCheck = 0; + // Check if there are new files at app start and when the app is resumed. helper.searchIOSNewSharedFiles(); platform.resume.subscribe(() => { - helper.searchIOSNewSharedFiles(); + // Wait a bit to make sure that APP_LAUNCHED_URL is treated before this callback. + setTimeout(() => { + if (Date.now() - lastCheck < 1000) { + // Last check less than 1s ago, don't do anything. + return; + } + + lastCheck = Date.now(); + helper.searchIOSNewSharedFiles(); + }, 200); }); eventsProvider.on(CoreEventsProvider.APP_LAUNCHED_URL, (url) => { if (url && url.indexOf('file://') === 0) { // We received a file in iOS, it's probably a shared file. Treat it. + lastCheck = Date.now(); helper.searchIOSNewSharedFiles(url); } }); From ba27f753247aa3dbfbf57fd25274b18d4db1fe20 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 12:01:27 +0100 Subject: [PATCH 04/13] MOBILE-2915 login: Fix signup errors not displayed --- .../login/pages/email-signup/email-signup.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/core/login/pages/email-signup/email-signup.ts b/src/core/login/pages/email-signup/email-signup.ts index 553a33a55..b038da362 100644 --- a/src/core/login/pages/email-signup/email-signup.ts +++ b/src/core/login/pages/email-signup/email-signup.ts @@ -261,25 +261,25 @@ export class CoreLoginEmailSignupPage { (fieldsData) => { params.customprofilefields = fieldsData; - this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl }).then((result) => { - if (result.success) { - // Show alert and ho back. - const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email }); - this.domUtils.showAlert(this.translate.instant('core.success'), message); - this.navCtrl.pop(); - } else { - if (result.warnings && result.warnings.length) { - let error = result.warnings[0].message; - if (error == 'incorrect-captcha-sol') { - error = this.translate.instant('core.login.recaptchaincorrect'); - } - - this.domUtils.showErrorModal(error); - } else { - this.domUtils.showErrorModal('core.login.usernotaddederror', true); + return this.wsProvider.callAjax('auth_email_signup_user', params, { siteUrl: this.siteUrl }); + }).then((result) => { + if (result.success) { + // Show alert and ho back. + const message = this.translate.instant('core.login.emailconfirmsent', { $a: params.email }); + this.domUtils.showAlert(this.translate.instant('core.success'), message); + this.navCtrl.pop(); + } else { + if (result.warnings && result.warnings.length) { + let error = result.warnings[0].message; + if (error == 'incorrect-captcha-sol') { + error = this.translate.instant('core.login.recaptchaincorrect'); } + + this.domUtils.showErrorModal(error); + } else { + this.domUtils.showErrorModal('core.login.usernotaddederror', true); } - }); + } }).catch((error) => { this.domUtils.showErrorModalDefault(error, 'core.login.usernotaddederror', true); }).finally(() => { From 9978bd0caeeb67fb0e7e8e328c4e6944e8bb26ce Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 13:38:58 +0100 Subject: [PATCH 05/13] MOBILE-2915 file: Fix delete files with special chars --- src/components/local-file/local-file.ts | 14 +++++++------- src/providers/file.ts | 11 ++++++++++- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/local-file/local-file.ts b/src/components/local-file/local-file.ts index f507b2275..b5f3140ec 100644 --- a/src/components/local-file/local-file.ts +++ b/src/components/local-file/local-file.ts @@ -62,13 +62,6 @@ export class CoreLocalFileComponent implements OnInit { ngOnInit(): void { this.manage = this.utils.isTrueOrOne(this.manage); - // Let's calculate the relative path for the file. - this.relativePath = this.fileProvider.removeBasePath(this.file.toURL()); - if (!this.relativePath) { - // Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail. - this.relativePath = this.file.fullPath; - } - this.loadFileBasicData(); // Get the size and timemodified. @@ -88,6 +81,13 @@ export class CoreLocalFileComponent implements OnInit { this.fileName = this.file.name; this.fileIcon = this.mimeUtils.getFileIcon(this.file.name); this.fileExtension = this.mimeUtils.getFileExtension(this.file.name); + + // Let's calculate the relative path for the file. + this.relativePath = this.fileProvider.removeBasePath(this.file.toURL()); + if (!this.relativePath) { + // Didn't find basePath, use fullPath but if the user tries to manage the file it'll probably fail. + this.relativePath = this.file.fullPath; + } } /** diff --git a/src/providers/file.ts b/src/providers/file.ts index 579a7745f..a2c53ceb1 100644 --- a/src/providers/file.ts +++ b/src/providers/file.ts @@ -324,7 +324,16 @@ export class CoreFileProvider { path = this.removeStartingSlash(path.replace(this.basePath, '')); this.logger.debug('Remove file: ' + path); - return this.file.removeFile(this.basePath, path); + return this.file.removeFile(this.basePath, path).catch((error) => { + // The delete can fail if the path has encoded characters. Try again if that's the case. + const decodedPath = decodeURI(path); + + if (decodedPath != path) { + return this.file.removeFile(this.basePath, decodedPath); + } else { + return Promise.reject(error); + } + }); }); } From 3f370f97caf88c8cc37b48a847b5c9cc35409ede Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 16:35:34 +0100 Subject: [PATCH 06/13] MOBILE-2915 login: Mark recaptcha as required --- src/core/login/pages/email-signup/email-signup.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/login/pages/email-signup/email-signup.html b/src/core/login/pages/email-signup/email-signup.html index c8909aafe..e00adbfca 100644 --- a/src/core/login/pages/email-signup/email-signup.html +++ b/src/core/login/pages/email-signup/email-signup.html @@ -115,7 +115,7 @@ - {{ 'core.login.security_question' | translate }} + {{ 'core.login.security_question' | translate }} From 5c4fcaf09e48aa9d1dd32d8db66dc64c6594b3cf Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 17:06:13 +0100 Subject: [PATCH 07/13] MOBILE-2915 core: Fix multiple change password errors --- src/classes/site.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/classes/site.ts b/src/classes/site.ts index 52a919a24..b9068bd13 100644 --- a/src/classes/site.ts +++ b/src/classes/site.ts @@ -605,7 +605,7 @@ export class CoreSite { // Session expired, trigger event. this.eventsProvider.trigger(CoreEventsProvider.SESSION_EXPIRED, {}, this.id); - // Change error message. We'll try to get data from cache. + // Change error message. Try to get data from cache, the event will handle the error. error.message = this.translate.instant('core.lostconnection'); } else if (error.errorcode === 'userdeleted') { // User deleted, trigger event. @@ -614,17 +614,15 @@ export class CoreSite { return Promise.reject(error); } else if (error.errorcode === 'forcepasswordchangenotice') { - // Password Change Forced, trigger event. + // Password Change Forced, trigger event. Try to get data from cache, the event will handle the error. this.eventsProvider.trigger(CoreEventsProvider.PASSWORD_CHANGE_FORCED, {}, this.id); error.message = this.translate.instant('core.forcepasswordchangenotice'); - return Promise.reject(error); } else if (error.errorcode === 'usernotfullysetup') { - // User not fully setup, trigger event. + // User not fully setup, trigger event. Try to get data from cache, the event will handle the error. this.eventsProvider.trigger(CoreEventsProvider.USER_NOT_FULLY_SETUP, {}, this.id); error.message = this.translate.instant('core.usernotfullysetup'); - return Promise.reject(error); } else if (error.errorcode === 'sitepolicynotagreed') { // Site policy not agreed, trigger event. this.eventsProvider.trigger(CoreEventsProvider.SITE_POLICY_NOT_AGREED, {}, this.id); From 8b5b33ec82713027b354ba491091813426dcc2c2 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 18:03:36 +0100 Subject: [PATCH 08/13] MOBILE-2915 forum: Fix discussion sync --- src/addon/mod/forum/pages/discussion/discussion.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/addon/mod/forum/pages/discussion/discussion.ts b/src/addon/mod/forum/pages/discussion/discussion.ts index 7b5f6f6f1..7cf56cdf0 100644 --- a/src/addon/mod/forum/pages/discussion/discussion.ts +++ b/src/addon/mod/forum/pages/discussion/discussion.ts @@ -357,7 +357,7 @@ export class AddonModForumDiscussionPage implements OnDestroy { protected syncDiscussion(showErrors: boolean): Promise { const promises = []; - promises.push(this.forumSync.syncDiscussionReplies(this.forumId, this.discussionId).then((result) => { + promises.push(this.forumSync.syncDiscussionReplies(this.discussionId).then((result) => { if (result.warnings && result.warnings.length) { this.domUtils.showErrorModal(result.warnings[0]); } From bbc9421a5eaf97fa0a4b758e4f9221a16897c897 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 18:24:15 +0100 Subject: [PATCH 09/13] MOBILE-2915 recaptcha: Change recaptcha button string --- scripts/langindex.json | 1 + src/assets/lang/en.json | 1 + src/components/recaptcha/core-recaptcha.html | 2 +- src/lang/en.json | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 2bbbdb083..4c0f0bc57 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -1608,6 +1608,7 @@ "core.remove": "moodle", "core.required": "moodle", "core.requireduserdatamissing": "local_moodlemobileapp", + "core.resourcedisplayopen": "moodle", "core.resources": "moodle", "core.restore": "moodle", "core.retry": "local_moodlemobileapp", diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 9f14d682a..e0c8c523a 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -1608,6 +1608,7 @@ "core.remove": "Remove", "core.required": "Required", "core.requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.
{{$a}}", + "core.resourcedisplayopen": "Open", "core.resources": "Resources", "core.restore": "Restore", "core.retry": "Retry", diff --git a/src/components/recaptcha/core-recaptcha.html b/src/components/recaptcha/core-recaptcha.html index a0688a12b..d4e096dba 100644 --- a/src/components/recaptcha/core-recaptcha.html +++ b/src/components/recaptcha/core-recaptcha.html @@ -2,7 +2,7 @@
- +

{{ 'core.answered' | translate }}

{{ 'core.login.recaptchaexpired' | translate }}

diff --git a/src/lang/en.json b/src/lang/en.json index 7b7086f67..3df5da21b 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -196,6 +196,7 @@ "remove": "Remove", "required": "Required", "requireduserdatamissing": "This user lacks some required profile data. Please enter the data in your site and try again.
{{$a}}", + "resourcedisplayopen": "Open", "resources": "Resources", "restore": "Restore", "retry": "Retry", From ce8699a03f8d7e267a9464bfca11c970753763e6 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 27 Mar 2019 18:55:29 +0100 Subject: [PATCH 10/13] MOBILE-2915 mod: Fix feedback and workshop prefetch and sync --- src/addon/mod/feedback/components/index/index.ts | 2 ++ src/addon/mod/workshop/components/index/index.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/addon/mod/feedback/components/index/index.ts b/src/addon/mod/feedback/components/index/index.ts index 76610926d..55ffc4d21 100644 --- a/src/addon/mod/feedback/components/index/index.ts +++ b/src/addon/mod/feedback/components/index/index.ts @@ -36,6 +36,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity @Input() tab = 'overview'; @Input() group = 0; + component = AddonModFeedbackProvider.COMPONENT; moduleName = 'feedback'; access = { @@ -67,6 +68,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity firstSelectedTab: number; protected submitObserver: any; + protected syncEventName = AddonModFeedbackSyncProvider.AUTO_SYNCED; constructor(injector: Injector, private feedbackProvider: AddonModFeedbackProvider, @Optional() content: Content, private feedbackOffline: AddonModFeedbackOfflineProvider, private groupsProvider: CoreGroupsProvider, diff --git a/src/addon/mod/workshop/components/index/index.ts b/src/addon/mod/workshop/components/index/index.ts index 496039184..1515e91da 100644 --- a/src/addon/mod/workshop/components/index/index.ts +++ b/src/addon/mod/workshop/components/index/index.ts @@ -32,6 +32,7 @@ import { AddonModWorkshopOfflineProvider } from '../../providers/offline'; export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivityComponent { @Input() group = 0; + component = AddonModWorkshopProvider.COMPONENT; moduleName = 'workshop'; workshop: any; page = 0; @@ -64,6 +65,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity protected obsAssessmentSaved: any; protected appResumeSubscription: any; protected syncObserver: any; + protected syncEventName = AddonModWorkshopSyncProvider.AUTO_SYNCED; constructor(injector: Injector, private workshopProvider: AddonModWorkshopProvider, @Optional() content: Content, private workshopOffline: AddonModWorkshopOfflineProvider, private groupsProvider: CoreGroupsProvider, From 322d6ad2ca863878c13a787471f9256c6545d408 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 28 Mar 2019 09:21:44 +0100 Subject: [PATCH 11/13] MOBILE-2915 lesson: Improve buttons displayed if finished offline --- .../components/index/addon-mod-lesson-index.html | 14 +++++++++++--- src/addon/mod/lesson/components/index/index.ts | 6 ++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html index 61a19ce3c..c0c7b311a 100644 --- a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html @@ -58,7 +58,7 @@ {{ 'addon.mod_lesson.review' | translate }} - +

@@ -73,7 +73,7 @@
- +

@@ -87,7 +87,7 @@

- + {{ 'core.start' | translate }} @@ -98,6 +98,14 @@
+ + + + + {{ 'addon.mod_lesson.continue' | translate }} + + + diff --git a/src/addon/mod/lesson/components/index/index.ts b/src/addon/mod/lesson/components/index/index.ts index 0f98b9444..3750b56dc 100644 --- a/src/addon/mod/lesson/components/index/index.ts +++ b/src/addon/mod/lesson/components/index/index.ts @@ -56,6 +56,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo reportLoaded: boolean; // Whether the report data has been loaded. selectedGroupName: string; // The name of the selected group. overview: any; // Reports overview data. + finishedOffline: boolean; // Whether a retake was finished in offline. protected syncEventName = AddonModLessonSyncProvider.AUTO_SYNCED; protected accessInfo: any; // Lesson access info. @@ -159,6 +160,11 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo } })); + // Check if the ser has a finished retake in offline. + promises.push(this.lessonOffline.hasFinishedRetake(this.lesson.id).then((finished) => { + this.finishedOffline = finished; + })); + // Update the list of content pages viewed and question attempts. promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount)); promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount)); From f969f99e019dbd10ff27b495518855a10ddf0c42 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 28 Mar 2019 11:00:49 +0100 Subject: [PATCH 12/13] MOBILE-2915 lesson: Fix review after sync if no retakes --- .../index/addon-mod-lesson-index.html | 95 ++++++++++--------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html index c0c7b311a..c72ea903e 100644 --- a/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html +++ b/src/addon/mod/lesson/components/index/addon-mod-lesson-index.html @@ -51,61 +51,64 @@ - + + -

{{ 'addon.mod_lesson.retakefinishedinsync' | translate }}

+

{{ 'addon.mod_lesson.retakefinishedinsync' | translate }}

{{ 'addon.mod_lesson.review' | translate }}
- - -

- - - - {{ 'core.no' | translate }} - - - {{ 'core.yes' | translate }} - - - -
+ + + +

+ + + + {{ 'core.no' | translate }} + + + {{ 'core.yes' | translate }} + + + +
- - -

- - {{ 'addon.mod_lesson.continue' | translate }} - - -
+ + +

+ + {{ 'addon.mod_lesson.continue' | translate }} + + +
- - -

-
+ + +

+
- - - - {{ 'core.start' | translate }} - - - - {{ 'addon.mod_lesson.preview' | translate }} - - - + + + + {{ 'core.start' | translate }} + + + + {{ 'addon.mod_lesson.preview' | translate }} + + + - - - - {{ 'addon.mod_lesson.continue' | translate }} - - - + + + + {{ 'addon.mod_lesson.continue' | translate }} + + + +
From 644f3c8a8bb76ae970180bd0fa2117ff7a82d86c Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 28 Mar 2019 11:59:24 +0100 Subject: [PATCH 13/13] MOBILE-2915 lesson: Fix 'End of cluster' text displayed --- src/addon/mod/lesson/pages/player/player.html | 4 ++-- src/addon/mod/lesson/providers/helper.ts | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/addon/mod/lesson/pages/player/player.html b/src/addon/mod/lesson/pages/player/player.html index 428adceef..0c2e2ac0b 100644 --- a/src/addon/mod/lesson/pages/player/player.html +++ b/src/addon/mod/lesson/pages/player/player.html @@ -32,14 +32,14 @@ - +
- + diff --git a/src/addon/mod/lesson/providers/helper.ts b/src/addon/mod/lesson/providers/helper.ts index e88652f6c..234c0fd45 100644 --- a/src/addon/mod/lesson/providers/helper.ts +++ b/src/addon/mod/lesson/providers/helper.ts @@ -27,7 +27,8 @@ import { AddonModLessonProvider } from './lesson'; export class AddonModLessonHelperProvider { constructor(private domUtils: CoreDomUtilsProvider, private fb: FormBuilder, private translate: TranslateService, - private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider) { } + private textUtils: CoreTextUtilsProvider, private timeUtils: CoreTimeUtilsProvider, + private lessonProvider: AddonModLessonProvider) { } /** * Given the HTML of next activity link, format it to extract the href and the text. @@ -149,8 +150,15 @@ export class AddonModLessonHelperProvider { return contents.innerHTML.trim(); } - // Cannot find contents element, return the page.contents (some elements like videos might not work). - return data.page.contents; + // Cannot find contents element. + if (this.lessonProvider.isQuestionPage(data.page.type) || + data.page.qtype == AddonModLessonProvider.LESSON_PAGE_BRANCHTABLE) { + // Return page.contents to prevent having duplicated elements (some elements like videos might not work). + return data.page.contents; + } else { + // It's an end of cluster, end of branch, etc. Return the whole pagecontent to match what's displayed in web. + return data.pagecontent; + } } /**