diff --git a/src/addons/mod/assign/submission/file/component/file.ts b/src/addons/mod/assign/submission/file/component/file.ts index 6e9b73f43..79d8ecfd0 100644 --- a/src/addons/mod/assign/submission/file/component/file.ts +++ b/src/addons/mod/assign/submission/file/component/file.ts @@ -44,12 +44,6 @@ export class AddonModAssignSubmissionFileComponent extends AddonModAssignSubmiss * Component being initialized. */ async ngOnInit(): Promise { - // Get the offline data. - const filesData = await CoreUtils.ignoreErrors( - AddonModAssignOffline.getSubmission(this.assign.id), - undefined, - ); - this.acceptedTypes = this.configs?.filetypeslist; this.maxSize = this.configs?.maxsubmissionsizebytes ? parseInt(this.configs.maxsubmissionsizebytes, 10) @@ -58,6 +52,12 @@ export class AddonModAssignSubmissionFileComponent extends AddonModAssignSubmiss ? parseInt(this.configs.maxfilesubmissions, 10) : undefined; + // Get the offline data. + const filesData = await CoreUtils.ignoreErrors( + AddonModAssignOffline.getSubmission(this.assign.id), + undefined, + ); + try { if (filesData && filesData.plugindata && filesData.plugindata.files_filemanager) { const offlineDataFiles = filesData.plugindata.files_filemanager; diff --git a/src/addons/mod/glossary/pages/edit/edit.html b/src/addons/mod/glossary/pages/edit/edit.html index b533fdfa0..765701f60 100644 --- a/src/addons/mod/glossary/pages/edit/edit.html +++ b/src/addons/mod/glossary/pages/edit/edit.html @@ -41,7 +41,7 @@ {{ 'addon.mod_glossary.aliases' | translate }} - diff --git a/src/addons/mod/scorm/components/index/index.ts b/src/addons/mod/scorm/components/index/index.ts index 1573fea4c..945ba9112 100644 --- a/src/addons/mod/scorm/components/index/index.ts +++ b/src/addons/mod/scorm/components/index/index.ts @@ -19,6 +19,7 @@ import { CoreCourseContentsPage } from '@features/course/pages/contents/contents import { CoreCourse } from '@features/course/services/course'; import { IonContent } from '@ionic/angular'; import { CoreNavigator } from '@services/navigator'; +import { CoreSync } from '@services/sync'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; @@ -584,9 +585,17 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom /** * Performs the sync of the activity. * + * @param retries Number of retries done. * @return Promise resolved when done. */ - protected async sync(): Promise { + protected async sync(retries = 0): Promise { + if (CoreSync.isBlocked(AddonModScormProvider.COMPONENT, this.scorm!.id) && retries < 5) { + // Sync is currently blocked, this can happen when SCORM player is left. Retry in a bit. + await CoreUtils.wait(400); + + return this.sync(retries + 1); + } + const result = await AddonModScormSync.syncScorm(this.scorm!); if (!result.updated && this.dataSent) { diff --git a/src/addons/mod/scorm/services/handlers/prefetch.ts b/src/addons/mod/scorm/services/handlers/prefetch.ts index 634082609..f25974718 100644 --- a/src/addons/mod/scorm/services/handlers/prefetch.ts +++ b/src/addons/mod/scorm/services/handlers/prefetch.ts @@ -15,7 +15,7 @@ import { Injectable } from '@angular/core'; import { CoreError } from '@classes/errors/error'; import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; -import { CoreCourseAnyModuleData, CoreCourseCommonModWSOptions } from '@features/course/services/course'; +import { CoreCourse, CoreCourseAnyModuleData, CoreCourseCommonModWSOptions } from '@features/course/services/course'; import { CoreApp } from '@services/app'; import { CoreFile } from '@services/file'; import { CoreFilepool } from '@services/filepool'; @@ -316,8 +316,13 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe * @param siteId Site ID. * @returns Promise resolved with the SCORM. */ - protected getScorm(module: CoreCourseAnyModuleData, courseId: number, siteId?: string): Promise { - const moduleUrl = 'url' in module ? module.url : undefined; + protected async getScorm(module: CoreCourseAnyModuleData, courseId: number, siteId?: string): Promise { + let moduleUrl = 'url' in module ? module.url : undefined; + if (!moduleUrl) { + module = await CoreCourse.getModule(module.id, module.course, undefined, true, false, siteId); + + moduleUrl = module.url; + } return AddonModScorm.getScorm(courseId, module.id, { moduleUrl, siteId }); } diff --git a/src/addons/mod/scorm/services/scorm-sync.ts b/src/addons/mod/scorm/services/scorm-sync.ts index 43bdaeb38..44ba195cd 100644 --- a/src/addons/mod/scorm/services/scorm-sync.ts +++ b/src/addons/mod/scorm/services/scorm-sync.ts @@ -198,7 +198,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide if (updated) { try { // Update downloaded data. - const module = await CoreCourse.getModuleBasicInfoByInstance(scorm.id, 'scorm', siteId); + const module = await CoreCourse.getModule(scorm.coursemodule, scorm.course, undefined, false, false, siteId); await this.prefetchAfterUpdate(AddonModScormPrefetchHandler.instance, module, scorm.course, undefined, siteId); } catch { diff --git a/src/addons/mod/workshop/assessment/accumulative/component/addon-mod-workshop-assessment-strategy-accumulative.html b/src/addons/mod/workshop/assessment/accumulative/component/addon-mod-workshop-assessment-strategy-accumulative.html index 20b6319a1..33cc08a48 100644 --- a/src/addons/mod/workshop/assessment/accumulative/component/addon-mod-workshop-assessment-strategy-accumulative.html +++ b/src/addons/mod/workshop/assessment/accumulative/component/addon-mod-workshop-assessment-strategy-accumulative.html @@ -32,7 +32,8 @@ {{ 'addon.mod_workshop_assessment_accumulative.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} - + + diff --git a/src/addons/mod/workshop/assessment/comments/component/addon-mod-workshop-assessment-strategy-comments.html b/src/addons/mod/workshop/assessment/comments/component/addon-mod-workshop-assessment-strategy-comments.html index fde783cf8..fe2566390 100644 --- a/src/addons/mod/workshop/assessment/comments/component/addon-mod-workshop-assessment-strategy-comments.html +++ b/src/addons/mod/workshop/assessment/comments/component/addon-mod-workshop-assessment-strategy-comments.html @@ -14,7 +14,8 @@ {{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} - + + diff --git a/src/addons/mod/workshop/assessment/numerrors/component/addon-mod-workshop-assessment-strategy-numerrors.html b/src/addons/mod/workshop/assessment/numerrors/component/addon-mod-workshop-assessment-strategy-numerrors.html index 2b7a47b80..5449e5872 100644 --- a/src/addons/mod/workshop/assessment/numerrors/component/addon-mod-workshop-assessment-strategy-numerrors.html +++ b/src/addons/mod/workshop/assessment/numerrors/component/addon-mod-workshop-assessment-strategy-numerrors.html @@ -36,7 +36,7 @@ {{ 'addon.mod_workshop_assessment_numerrors.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} + [core-auto-rows]="selectedValues[n].peercomment"> diff --git a/src/core/components/iframe/core-iframe.html b/src/core/components/iframe/core-iframe.html index f4bca836c..dc4d5a01d 100644 --- a/src/core/components/iframe/core-iframe.html +++ b/src/core/components/iframe/core-iframe.html @@ -6,7 +6,7 @@ + * */ @Directive({ selector: 'textarea[core-auto-rows], ion-textarea[core-auto-rows]', }) -export class CoreAutoRowsDirective implements AfterViewInit { +export class CoreAutoRowsDirective implements AfterViewInit, OnChanges { protected height = 0; + @Input('core-auto-rows') value?: string; // eslint-disable-line @angular-eslint/no-input-rename @Output() onResize: EventEmitter; // Emit when resizing the textarea. constructor(protected element: ElementRef) { this.onResize = new EventEmitter(); } - @HostListener('input') onInput(): void { - this.resize(); - } - - @HostListener('change') onChange(): void { - // Fired on reset. Wait to the change to be finished. - setTimeout(() => { - this.resize(); - }, 300); - } - /** - * Resize after content. + * Resize after initialized. */ ngAfterViewInit(): void { // Wait for rendering of child views. @@ -55,6 +45,18 @@ export class CoreAutoRowsDirective implements AfterViewInit { }, 300); } + /** + * Resize when content changes. + */ + ngOnChanges(): void { + this.resize(); + + if (this.value === '') { + // Maybe the form was resetted. In that case it takes a bit to update the height. + setTimeout(() => this.resize(), 300); + } + } + /** * Resize the textarea. */ diff --git a/src/core/features/courses/pages/my-courses/my-courses.ts b/src/core/features/courses/pages/my-courses/my-courses.ts index 967e51484..657e4e84c 100644 --- a/src/core/features/courses/pages/my-courses/my-courses.ts +++ b/src/core/features/courses/pages/my-courses/my-courses.ts @@ -206,7 +206,7 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { * Go to search courses. */ openSearch(): void { - CoreNavigator.navigate('courses/search'); + CoreNavigator.navigateToSitePath('courses/search'); } /** diff --git a/src/core/services/lang.ts b/src/core/services/lang.ts index 9f1de3abe..8e64effeb 100644 --- a/src/core/services/lang.ts +++ b/src/core/services/lang.ts @@ -19,7 +19,7 @@ import { LangChangeEvent } from '@ngx-translate/core'; import { CoreAppProvider } from '@services/app'; import { CoreConfig } from '@services/config'; import { CoreSubscriptions } from '@singletons/subscriptions'; -import { makeSingleton, Translate, Platform } from '@singletons'; +import { makeSingleton, Translate, Platform, Http } from '@singletons'; import * as moment from 'moment'; import { CoreSite } from '../classes/site'; @@ -142,24 +142,24 @@ export class CoreLangProvider { // Change the language, resolving the promise when we receive the first value. promises.push(new Promise((resolve, reject) => { - CoreSubscriptions.once(Translate.use(language), data => { - // It's a language override, load the original one first. + CoreSubscriptions.once(Translate.use(language), async data => { + // Check if it has a parent language. const fallbackLang = this.getParentLanguage(language); if (fallbackLang) { - CoreSubscriptions.once( - Translate.use(fallbackLang), - fallbackData => { - data = Object.assign(fallbackData, data); + try { + // Merge parent translations with the child ones. + const parentTranslations = Translate.translations[fallbackLang] ?? await this.readLangFile(fallbackLang); - resolve(data); - }, - // Resolve with the original language. - () => resolve(data), - ); - } else { - resolve(data); + const mergedData = Object.assign(parentTranslations, data); + + Object.assign(data, mergedData); + } catch { + // Ignore errors. + } } + + resolve(data); }, reject); })); @@ -474,6 +474,20 @@ export class CoreLangProvider { } } + /** + * Read a language file. + * + * @param lang Language code. + * @return Promise resolved with the file contents. + */ + async readLangFile(lang: string): Promise> { + const observable = Http.get(`assets/lang/${lang}.json`, { + responseType: 'json', + }); + + return > await observable.toPromise(); + } + /** * Unload custom or site plugin strings, removing them from the translations table. *