commit
						134e2d7203
					
				| @ -44,12 +44,6 @@ export class AddonModAssignSubmissionFileComponent extends AddonModAssignSubmiss | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     async ngOnInit(): Promise<void> { | ||||
|         // 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 = <CoreFileUploaderStoreFilesResult>filesData.plugindata.files_filemanager; | ||||
|  | ||||
| @ -41,7 +41,7 @@ | ||||
|                 <ion-label position="stacked" id="addon-mod-glossary-aliases-label"> | ||||
|                     {{ 'addon.mod_glossary.aliases' | translate }} | ||||
|                 </ion-label> | ||||
|                 <ion-textarea [(ngModel)]="options.aliases" rows="1" core-auto-rows | ||||
|                 <ion-textarea [(ngModel)]="options.aliases" rows="1" [core-auto-rows]="options.aliases" | ||||
|                     aria-labelledby="addon-mod-glossary-aliases-label" name="aliases"> | ||||
|                 </ion-textarea> | ||||
|             </ion-item> | ||||
|  | ||||
| @ -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<AddonModScormSyncResult> { | ||||
|     protected async sync(retries = 0): Promise<AddonModScormSyncResult> { | ||||
|         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) { | ||||
|  | ||||
| @ -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<AddonModScormScorm> { | ||||
|         const moduleUrl = 'url' in module ? module.url : undefined; | ||||
|     protected async getScorm(module: CoreCourseAnyModuleData, courseId: number, siteId?: string): Promise<AddonModScormScorm> { | ||||
|         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 }); | ||||
|     } | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -32,7 +32,8 @@ | ||||
|             <ion-label position="stacked"> | ||||
|                 {{ 'addon.mod_workshop_assessment_accumulative.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} | ||||
|             </ion-label> | ||||
|             <ion-textarea [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea> | ||||
|             <ion-textarea [(ngModel)]="selectedValues[n].peercomment" [core-auto-rows]="selectedValues[n].peercomment"> | ||||
|             </ion-textarea> | ||||
|         </ion-item> | ||||
|         <ion-item *ngIf="!edit" class="ion-text-wrap"> | ||||
|             <ion-label> | ||||
|  | ||||
| @ -14,7 +14,8 @@ | ||||
|                     {{ 'addon.mod_workshop_assessment_comments.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} | ||||
|                 </span> | ||||
|             </ion-label> | ||||
|             <ion-textarea [(ngModel)]="selectedValues[n].peercomment" core-auto-rows></ion-textarea> | ||||
|             <ion-textarea [(ngModel)]="selectedValues[n].peercomment" [core-auto-rows]="selectedValues[n].peercomment"> | ||||
|             </ion-textarea> | ||||
|             <core-input-errors *ngIf="fieldErrors['peercomment_' + n]" [errorText]="fieldErrors['peercomment_' + n]"> | ||||
|             </core-input-errors> | ||||
|         </ion-item> | ||||
|  | ||||
| @ -36,7 +36,7 @@ | ||||
|                 {{ 'addon.mod_workshop_assessment_numerrors.dimensioncommentfor' | translate : {'$a': field.dimtitle } }} | ||||
|             </ion-label> | ||||
|             <ion-textarea [(ngModel)]="selectedValues[n].peercomment" [name]="'peercomment_' + n" | ||||
|                 core-auto-rows> | ||||
|                 [core-auto-rows]="selectedValues[n].peercomment"> | ||||
|             </ion-textarea> | ||||
|         </ion-item> | ||||
|         <ion-item *ngIf="!edit" class="ion-text-wrap"> | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|     </iframe> | ||||
| 
 | ||||
|     <ion-button | ||||
|         *ngIf="!loading" | ||||
|         *ngIf="!loading && displayHelp" | ||||
|         color="dark" expand="block" fill="clear" | ||||
|         (click)="openIframeHelpModal()" | ||||
|         aria-haspopup="dialog" | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
|         [core-auto-focus]="showKeyboard" | ||||
|         [placeholder]="placeholder" | ||||
|         rows="1" | ||||
|         core-auto-rows | ||||
|         [core-auto-rows]="message" | ||||
|         [(ngModel)]="message" | ||||
|         name="message" | ||||
|         (onResize)="textareaResized()" | ||||
|  | ||||
| @ -12,41 +12,31 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Directive, ElementRef, HostListener, Output, EventEmitter, AfterViewInit } from '@angular/core'; | ||||
| import { Directive, ElementRef, Output, EventEmitter, AfterViewInit, Input, OnChanges } from '@angular/core'; | ||||
| 
 | ||||
| /** | ||||
|  * Directive to adapt a textarea rows depending on the input text. It's based on Moodle's data-auto-rows. | ||||
|  * | ||||
|  * @description | ||||
|  * Usage: | ||||
|  * <textarea class="core-textarea" [(ngModel)]="message" rows="1" core-auto-rows></textarea> | ||||
|  * <textarea class="core-textarea" [(ngModel)]="message" rows="1" [core-auto-rows]="message"></textarea> | ||||
|  */ | ||||
| @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<void>; // 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. | ||||
|      */ | ||||
|  | ||||
| @ -206,7 +206,7 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy { | ||||
|      * Go to search courses. | ||||
|      */ | ||||
|     openSearch(): void { | ||||
|         CoreNavigator.navigate('courses/search'); | ||||
|         CoreNavigator.navigateToSitePath('courses/search'); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | ||||
| @ -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<Record<string, string>> { | ||||
|         const observable = Http.get(`assets/lang/${lang}.json`, { | ||||
|             responseType: 'json', | ||||
|         }); | ||||
| 
 | ||||
|         return <Record<string, string>> await observable.toPromise(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Unload custom or site plugin strings, removing them from the translations table. | ||||
|      * | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user