forked from EVOgeek/Vmeda.Online
		
	
						commit
						cc5c476019
					
				| @ -39,10 +39,10 @@ import { CoreLogger } from '@singletons/logger'; | |||||||
| }) | }) | ||||||
| export class AddonBlockTimelineComponent implements OnInit, ICoreBlockComponent { | export class AddonBlockTimelineComponent implements OnInit, ICoreBlockComponent { | ||||||
| 
 | 
 | ||||||
|     sort = new FormControl(); |     sort = new FormControl(AddonBlockTimelineSort.ByDates); | ||||||
|     sort$!: Observable<AddonBlockTimelineSort>; |     sort$!: Observable<AddonBlockTimelineSort>; | ||||||
|     sortOptions!: AddonBlockTimelineOption<AddonBlockTimelineSort>[]; |     sortOptions!: AddonBlockTimelineOption<AddonBlockTimelineSort>[]; | ||||||
|     filter = new FormControl(); |     filter = new FormControl(AddonBlockTimelineFilter.Next30Days); | ||||||
|     filter$!: Observable<AddonBlockTimelineFilter>; |     filter$!: Observable<AddonBlockTimelineFilter>; | ||||||
|     statusFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[]; |     statusFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[]; | ||||||
|     dateFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[]; |     dateFilterOptions!: AddonBlockTimelineOption<AddonBlockTimelineFilter>[]; | ||||||
|  | |||||||
| @ -78,9 +78,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | |||||||
| 
 | 
 | ||||||
|     // Form variables.
 |     // Form variables.
 | ||||||
|     form: FormGroup; |     form: FormGroup; | ||||||
|     typeControl: FormControl; |     typeControl: FormControl<AddonCalendarEventType | null>; | ||||||
|     groupControl: FormControl; |     groupControl: FormControl<number | null>; | ||||||
|     descriptionControl: FormControl; |     descriptionControl: FormControl<string>; | ||||||
| 
 | 
 | ||||||
|     // Reminders.
 |     // Reminders.
 | ||||||
|     remindersEnabled = false; |     remindersEnabled = false; | ||||||
| @ -103,9 +103,9 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | |||||||
|         this.form = new FormGroup({}); |         this.form = new FormGroup({}); | ||||||
| 
 | 
 | ||||||
|         // Initialize form variables.
 |         // Initialize form variables.
 | ||||||
|         this.typeControl = this.fb.control('', Validators.required); |         this.typeControl = this.fb.control(null, Validators.required); | ||||||
|         this.groupControl = this.fb.control(''); |         this.groupControl = this.fb.control(null); | ||||||
|         this.descriptionControl = this.fb.control(''); |         this.descriptionControl = this.fb.control('', { nonNullable: true }); | ||||||
|         this.form.addControl('name', this.fb.control('', Validators.required)); |         this.form.addControl('name', this.fb.control('', Validators.required)); | ||||||
|         this.form.addControl('eventtype', this.typeControl); |         this.form.addControl('eventtype', this.typeControl); | ||||||
|         this.form.addControl('categoryid', this.fb.control('')); |         this.form.addControl('categoryid', this.fb.control('')); | ||||||
| @ -322,11 +322,11 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | |||||||
| 
 | 
 | ||||||
|         this.form.controls.name.setValue(event.name); |         this.form.controls.name.setValue(event.name); | ||||||
|         this.form.controls.timestart.setValue(CoreTimeUtils.toDatetimeFormat(event.timestart * 1000)); |         this.form.controls.timestart.setValue(CoreTimeUtils.toDatetimeFormat(event.timestart * 1000)); | ||||||
|         this.form.controls.eventtype.setValue(event.eventtype); |         this.typeControl.setValue(event.eventtype as AddonCalendarEventType); | ||||||
|         this.form.controls.categoryid.setValue(event.categoryid || ''); |         this.form.controls.categoryid.setValue(event.categoryid || ''); | ||||||
|         this.form.controls.courseid.setValue(courseId || ''); |         this.form.controls.courseid.setValue(courseId || ''); | ||||||
|         this.form.controls.groupcourseid.setValue(courseId || ''); |         this.form.controls.groupcourseid.setValue(courseId || ''); | ||||||
|         this.form.controls.groupid.setValue(event.groupid || ''); |         this.groupControl.setValue(event.groupid || null); | ||||||
|         this.form.controls.description.setValue(event.description); |         this.form.controls.description.setValue(event.description); | ||||||
|         this.form.controls.location.setValue(event.location); |         this.form.controls.location.setValue(event.location); | ||||||
| 
 | 
 | ||||||
| @ -410,7 +410,7 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { | |||||||
|         try { |         try { | ||||||
|             await this.loadGroups(courseId); |             await this.loadGroups(courseId); | ||||||
| 
 | 
 | ||||||
|             this.groupControl.setValue(''); |             this.groupControl.setValue(null); | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             CoreDomUtils.showErrorModalDefault(error, 'Error getting data.'); |             CoreDomUtils.showErrorModalDefault(error, 'Error getting data.'); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -34,7 +34,7 @@ import { AddonModAssignFeedbackPluginBaseComponent } from '@addons/mod/assign/cl | |||||||
| }) | }) | ||||||
| export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedbackPluginBaseComponent implements OnInit { | export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedbackPluginBaseComponent implements OnInit { | ||||||
| 
 | 
 | ||||||
|     control?: FormControl; |     control?: FormControl<string>; | ||||||
|     component = AddonModAssignProvider.COMPONENT; |     component = AddonModAssignProvider.COMPONENT; | ||||||
|     text = ''; |     text = ''; | ||||||
|     isSent = false; |     isSent = false; | ||||||
| @ -76,7 +76,7 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb | |||||||
|                     } |                     } | ||||||
|                 }); |                 }); | ||||||
|             } else if (this.edit) { |             } else if (this.edit) { | ||||||
|                 this.control = this.fb.control(this.text); |                 this.control = this.fb.control(this.text, { nonNullable: true }); | ||||||
|             } |             } | ||||||
|         } finally { |         } finally { | ||||||
|             this.loaded = true; |             this.loaded = true; | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ import { AddonModAssignSubmissionOnlineTextPluginData } from '../services/handle | |||||||
| }) | }) | ||||||
| export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignSubmissionPluginBaseComponent implements OnInit { | export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignSubmissionPluginBaseComponent implements OnInit { | ||||||
| 
 | 
 | ||||||
|     control?: FormControl; |     control?: FormControl<string>; | ||||||
|     words = 0; |     words = 0; | ||||||
|     component = AddonModAssignProvider.COMPONENT; |     component = AddonModAssignProvider.COMPONENT; | ||||||
|     text = ''; |     text = ''; | ||||||
| @ -94,7 +94,7 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS | |||||||
|                 }); |                 }); | ||||||
|             } else { |             } else { | ||||||
|                 // Create and add the control.
 |                 // Create and add the control.
 | ||||||
|                 this.control = this.fb.control(this.text); |                 this.control = this.fb.control(this.text, { nonNullable: true }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // Calculate initial words.
 |             // Calculate initial words.
 | ||||||
|  | |||||||
| @ -83,7 +83,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges | |||||||
| 
 | 
 | ||||||
|     @ViewChild('replyFormEl') formElement!: ElementRef; |     @ViewChild('replyFormEl') formElement!: ElementRef; | ||||||
| 
 | 
 | ||||||
|     messageControl = new FormControl(); |     messageControl = new FormControl<string | null>(null); | ||||||
| 
 | 
 | ||||||
|     uniqueId!: string; |     uniqueId!: string; | ||||||
|     defaultReplySubject!: string; |     defaultReplySubject!: string; | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ export class AddonModForumNewDiscussionPage implements OnInit, OnDestroy, CanLea | |||||||
|     @ViewChild(CoreEditorRichTextEditorComponent) messageEditor!: CoreEditorRichTextEditorComponent; |     @ViewChild(CoreEditorRichTextEditorComponent) messageEditor!: CoreEditorRichTextEditorComponent; | ||||||
| 
 | 
 | ||||||
|     component = AddonModForumProvider.COMPONENT; |     component = AddonModForumProvider.COMPONENT; | ||||||
|     messageControl = new FormControl(); |     messageControl = new FormControl<string | null>(null); | ||||||
|     groupsLoaded = false; |     groupsLoaded = false; | ||||||
|     showGroups = false; |     showGroups = false; | ||||||
|     hasOffline = false; |     hasOffline = false; | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ export class AddonModGlossaryEditPage implements OnInit, CanLeave { | |||||||
|     courseId!: number; |     courseId!: number; | ||||||
|     loaded = false; |     loaded = false; | ||||||
|     glossary?: AddonModGlossaryGlossary; |     glossary?: AddonModGlossaryGlossary; | ||||||
|     definitionControl = new FormControl(); |     definitionControl = new FormControl<string | null>(null); | ||||||
|     categories: AddonModGlossaryCategory[] = []; |     categories: AddonModGlossaryCategory[] = []; | ||||||
|     showAliases = true; |     showAliases = true; | ||||||
|     editorExtraParams: Record<string, unknown> = {}; |     editorExtraParams: Record<string, unknown> = {}; | ||||||
|  | |||||||
| @ -369,7 +369,7 @@ export class AddonModLessonHelperProvider { | |||||||
|             }; |             }; | ||||||
| 
 | 
 | ||||||
|             // Init the control.
 |             // Init the control.
 | ||||||
|             essayQuestion.control = this.formBuilder.control(''); |             essayQuestion.control = this.formBuilder.control('', { nonNullable: true }); | ||||||
|             questionForm.addControl(essayQuestion.textarea.name, essayQuestion.control); |             questionForm.addControl(essayQuestion.textarea.name, essayQuestion.control); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -635,7 +635,7 @@ export type AddonModLessonInputQuestion = AddonModLessonQuestionBasicData & { | |||||||
| export type AddonModLessonEssayQuestion = AddonModLessonQuestionBasicData & { | export type AddonModLessonEssayQuestion = AddonModLessonQuestionBasicData & { | ||||||
|     useranswer?: string; // User answer, for reviewing.
 |     useranswer?: string; // User answer, for reviewing.
 | ||||||
|     textarea?: AddonModLessonTextareaData; // Data for the textarea.
 |     textarea?: AddonModLessonTextareaData; // Data for the textarea.
 | ||||||
|     control?: FormControl; // Form control.
 |     control?: FormControl<string>; // Form control.
 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  | |||||||
| @ -157,14 +157,14 @@ export class AddonModUrlProvider { | |||||||
|         url = url || ''; |         url = url || ''; | ||||||
| 
 | 
 | ||||||
|         const matches = url.match(/\//g); |         const matches = url.match(/\//g); | ||||||
|         const extension = CoreMimetypeUtils.getFileExtension(url); |         const extension = CoreMimetypeUtils.guessExtensionFromUrl(url); | ||||||
| 
 | 
 | ||||||
|         if (!matches || matches.length < 3 || url.slice(-1) === '/' || extension == 'php') { |         if (!matches || matches.length < 3 || url.slice(-1) === '/' || extension == 'php') { | ||||||
|             // Use default icon.
 |             // Use default icon.
 | ||||||
|             return ''; |             return ''; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const icon = CoreMimetypeUtils.getFileIcon(url); |         const icon = CoreMimetypeUtils.getExtensionIcon(extension ?? ''); | ||||||
| 
 | 
 | ||||||
|         // We do not want to return those icon types, the module icon is more appropriate.
 |         // We do not want to return those icon types, the module icon is more appropriate.
 | ||||||
|         if (icon === CoreMimetypeUtils.getFileIconForType('unknown') || |         if (icon === CoreMimetypeUtils.getFileIconForType('unknown') || | ||||||
|  | |||||||
| @ -47,7 +47,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave { | |||||||
|     courseId?: number; // Course the wiki belongs to.
 |     courseId?: number; // Course the wiki belongs to.
 | ||||||
|     title?: string; // Title to display.
 |     title?: string; // Title to display.
 | ||||||
|     pageForm: FormGroup; // The form group.
 |     pageForm: FormGroup; // The form group.
 | ||||||
|     contentControl: FormControl; // The FormControl for the page content.
 |     contentControl: FormControl<string>; // The FormControl for the page content.
 | ||||||
|     canEditTitle = false; // Whether title can be edited.
 |     canEditTitle = false; // Whether title can be edited.
 | ||||||
|     loaded = false; // Whether the data has been loaded.
 |     loaded = false; // Whether the data has been loaded.
 | ||||||
|     component = AddonModWikiProvider.COMPONENT; // Component to link the files to.
 |     component = AddonModWikiProvider.COMPONENT; // Component to link the files to.
 | ||||||
| @ -74,7 +74,7 @@ export class AddonModWikiEditPage implements OnInit, OnDestroy, CanLeave { | |||||||
|     constructor( |     constructor( | ||||||
|         protected formBuilder: FormBuilder, |         protected formBuilder: FormBuilder, | ||||||
|     ) { |     ) { | ||||||
|         this.contentControl = this.formBuilder.control(''); |         this.contentControl = this.formBuilder.control('', { nonNullable: true }); | ||||||
|         this.pageForm = this.formBuilder.group({}); |         this.pageForm = this.formBuilder.group({}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -73,7 +73,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe | |||||||
|     assessmentStrategyLoaded = false; |     assessmentStrategyLoaded = false; | ||||||
|     notSupported = false; |     notSupported = false; | ||||||
|     feedbackText = ''; |     feedbackText = ''; | ||||||
|     feedbackControl = new FormControl(); |     feedbackControl = new FormControl<string | null>(null); | ||||||
|     overallFeedkback = false; |     overallFeedkback = false; | ||||||
|     overallFeedkbackRequired = false; |     overallFeedkbackRequired = false; | ||||||
|     component = ADDON_MOD_WORKSHOP_COMPONENT; |     component = ADDON_MOD_WORKSHOP_COMPONENT; | ||||||
|  | |||||||
| @ -32,7 +32,7 @@ import { CoreFileEntry } from '@services/file-helper'; | |||||||
| }) | }) | ||||||
| export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent<AddonModQuizEssayQuestion> { | export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent<AddonModQuizEssayQuestion> { | ||||||
| 
 | 
 | ||||||
|     formControl?: FormControl; |     formControl?: FormControl<string | null>; | ||||||
|     attachments?: CoreFileEntry[]; |     attachments?: CoreFileEntry[]; | ||||||
|     uploadFilesSupported = false; |     uploadFilesSupported = false; | ||||||
| 
 | 
 | ||||||
| @ -52,7 +52,7 @@ export class AddonQtypeEssayComponent extends CoreQuestionBaseComponent<AddonMod | |||||||
| 
 | 
 | ||||||
|         this.initEssayComponent(this.review); |         this.initEssayComponent(this.review); | ||||||
| 
 | 
 | ||||||
|         this.formControl = this.fb.control(this.question?.textarea?.text); |         this.formControl = this.fb.control(this.question?.textarea?.text ?? null); | ||||||
| 
 | 
 | ||||||
|         if (this.question?.allowsAttachments && this.uploadFilesSupported && !this.review) { |         if (this.question?.allowsAttachments && this.uploadFilesSupported && !this.review) { | ||||||
|             this.loadAttachments(); |             this.loadAttachments(); | ||||||
|  | |||||||
| @ -27,20 +27,23 @@ import { CoreUtils } from '@services/utils/utils'; | |||||||
|     templateUrl: 'addon-user-profile-field-checkbox.html', |     templateUrl: 'addon-user-profile-field-checkbox.html', | ||||||
|     styleUrls: ['./checkbox.scss'], |     styleUrls: ['./checkbox.scss'], | ||||||
| }) | }) | ||||||
| export class AddonUserProfileFieldCheckboxComponent extends CoreUserProfileFieldBaseComponent { | export class AddonUserProfileFieldCheckboxComponent extends CoreUserProfileFieldBaseComponent<boolean> { | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Create the Form control. |      * Create the Form control. | ||||||
|      * |      * | ||||||
|      * @returns Form control. |      * @returns Form control. | ||||||
|      */ |      */ | ||||||
|     protected createFormControl(field: AuthEmailSignupProfileField): FormControl { |     protected createFormControl(field: AuthEmailSignupProfileField): FormControl<boolean> { | ||||||
|         const formData = { |         const formData = { | ||||||
|             value: CoreUtils.isTrueOrOne(field.defaultdata), |             value: CoreUtils.isTrueOrOne(field.defaultdata), | ||||||
|             disabled: this.disabled, |             disabled: this.disabled, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         return new FormControl(formData, this.required && !field.locked ? Validators.requiredTrue : null); |         return new FormControl(formData, { | ||||||
|  |             validators: this.required && !field.locked ? Validators.requiredTrue : null, | ||||||
|  |             nonNullable: true, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-p | |||||||
|     selector: 'addon-user-profile-field-datetime', |     selector: 'addon-user-profile-field-datetime', | ||||||
|     templateUrl: 'addon-user-profile-field-datetime.html', |     templateUrl: 'addon-user-profile-field-datetime.html', | ||||||
| }) | }) | ||||||
| export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent { | export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent<string | undefined> { | ||||||
| 
 | 
 | ||||||
|     ionDateTimePresentation = 'date'; |     ionDateTimePresentation = 'date'; | ||||||
|     min?: string; |     min?: string; | ||||||
| @ -84,13 +84,16 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField | |||||||
|      * |      * | ||||||
|      * @returns Form control. |      * @returns Form control. | ||||||
|      */ |      */ | ||||||
|     protected createFormControl(field: AuthEmailSignupProfileField): FormControl { |     protected createFormControl(field: AuthEmailSignupProfileField): FormControl<string | undefined> { | ||||||
|         const formData = { |         const formData = { | ||||||
|             value: field.defaultdata != '0' ? field.defaultdata : undefined, |             value: field.defaultdata != '0' ? field.defaultdata : undefined, | ||||||
|             disabled: this.disabled, |             disabled: this.disabled, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         return new FormControl(formData, this.required && !field.locked ? Validators.required : null); |         return new FormControl(formData, { | ||||||
|  |             validators: this.required && !field.locked ? Validators.required : null, | ||||||
|  |             nonNullable: true, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -11,9 +11,17 @@ | |||||||
|         </ion-button> |         </ion-button> | ||||||
|     </core-navbar-buttons> |     </core-navbar-buttons> | ||||||
| 
 | 
 | ||||||
|     <iframe #iframe class="core-iframe" [attr.id]="id" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" |     <!-- allowfullscreen cannot be set dynamically using attribute binding, define 2 iframe elements. --> | ||||||
|         [attr.allowfullscreen]="allowFullscreen ? 'allowfullscreen' : null" [class.core-iframe-loading]="loading"> |     <ng-container *ngIf="allowFullscreen"> | ||||||
|     </iframe> |         <iframe #iframe class="core-iframe" [attr.id]="id" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" | ||||||
|  |             allowfullscreen="true" [class.core-iframe-loading]="loading"> | ||||||
|  |         </iframe> | ||||||
|  |     </ng-container> | ||||||
|  |     <ng-container *ngIf="!allowFullscreen"> | ||||||
|  |         <iframe #iframe class="core-iframe" [attr.id]="id" [ngStyle]="{'width': iframeWidth, 'height': iframeHeight}" [src]="safeUrl" | ||||||
|  |             [class.core-iframe-loading]="loading"> | ||||||
|  |         </iframe> | ||||||
|  |     </ng-container> | ||||||
| 
 | 
 | ||||||
|     <ion-button *ngIf="!loading && displayHelp" expand="block" fill="clear" (click)="openIframeHelpModal()" aria-haspopup="dialog" |     <ion-button *ngIf="!loading && displayHelp" expand="block" fill="clear" (click)="openIframeHelpModal()" aria-haspopup="dialog" | ||||||
|         class="core-button-as-link core-iframe-help"> |         class="core-button-as-link core-iframe-help"> | ||||||
|  | |||||||
| @ -85,12 +85,6 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { | |||||||
| 
 | 
 | ||||||
|         this.initialized = true; |         this.initialized = true; | ||||||
| 
 | 
 | ||||||
|         this.iframeWidth = (this.iframeWidth && CoreDomUtils.formatPixelsSize(this.iframeWidth)) || '100%'; |  | ||||||
|         this.iframeHeight = (this.iframeHeight && CoreDomUtils.formatPixelsSize(this.iframeHeight)) || '100%'; |  | ||||||
|         this.allowFullscreen = CoreUtils.isTrueOrOne(this.allowFullscreen); |  | ||||||
|         this.showFullscreenOnToolbar = CoreUtils.isTrueOrOne(this.showFullscreenOnToolbar); |  | ||||||
|         this.autoFullscreenOnRotate = CoreUtils.isTrueOrOne(this.autoFullscreenOnRotate); |  | ||||||
| 
 |  | ||||||
|         if (this.showFullscreenOnToolbar || this.autoFullscreenOnRotate) { |         if (this.showFullscreenOnToolbar || this.autoFullscreenOnRotate) { | ||||||
|             // Leave fullscreen when navigating.
 |             // Leave fullscreen when navigating.
 | ||||||
|             this.navSubscription = Router.events |             this.navSubscription = Router.events | ||||||
| @ -157,6 +151,22 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { | |||||||
|      * Detect changes on input properties. |      * Detect changes on input properties. | ||||||
|      */ |      */ | ||||||
|     async ngOnChanges(changes: {[name: string]: SimpleChange }): Promise<void> { |     async ngOnChanges(changes: {[name: string]: SimpleChange }): Promise<void> { | ||||||
|  |         if (changes.iframeWidth) { | ||||||
|  |             this.iframeWidth = (this.iframeWidth && CoreDomUtils.formatPixelsSize(this.iframeWidth)) || '100%'; | ||||||
|  |         } | ||||||
|  |         if (changes.iframeHeight) { | ||||||
|  |             this.iframeHeight = (this.iframeHeight && CoreDomUtils.formatPixelsSize(this.iframeHeight)) || '100%'; | ||||||
|  |         } | ||||||
|  |         if (changes.allowFullscreen) { | ||||||
|  |             this.allowFullscreen = CoreUtils.isTrueOrOne(this.allowFullscreen); | ||||||
|  |         } | ||||||
|  |         if (changes.showFullscreenOnToolbar) { | ||||||
|  |             this.showFullscreenOnToolbar = CoreUtils.isTrueOrOne(this.showFullscreenOnToolbar); | ||||||
|  |         } | ||||||
|  |         if (changes.autoFullscreenOnRotate) { | ||||||
|  |             this.autoFullscreenOnRotate = CoreUtils.isTrueOrOne(this.autoFullscreenOnRotate); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (!changes.src) { |         if (!changes.src) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -40,7 +40,7 @@ import { FormControl } from '@angular/forms'; | |||||||
| }) | }) | ||||||
| export class CoreInputErrorsComponent implements OnInit, OnChanges { | export class CoreInputErrorsComponent implements OnInit, OnChanges { | ||||||
| 
 | 
 | ||||||
|     @Input() control?: FormControl; // Needed to be able to check the validity of the input.
 |     @Input() control?: FormControl<unknown>; // Needed to be able to check the validity of the input.
 | ||||||
|     @Input() errorMessages: Record<string, string> = {}; // Error messages to show. Keys must be the name of the error.
 |     @Input() errorMessages: Record<string, string> = {}; // Error messages to show. Keys must be the name of the error.
 | ||||||
|     @Input() errorText = ''; // Set other non automatic errors.
 |     @Input() errorText = ''; // Set other non automatic errors.
 | ||||||
|     errorKeys: string[] = []; |     errorKeys: string[] = []; | ||||||
|  | |||||||
| @ -47,8 +47,8 @@ export class CoreSitesListComponent<T extends CoreSiteBasicInfo> { | |||||||
|     @Input() currentSiteClickable?: boolean; // If set, specify a different clickable value for current site.
 |     @Input() currentSiteClickable?: boolean; // If set, specify a different clickable value for current site.
 | ||||||
|     @Output() onSiteClicked = new EventEmitter<T>(); |     @Output() onSiteClicked = new EventEmitter<T>(); | ||||||
| 
 | 
 | ||||||
|     @ContentChild('siteItem') siteItemTemplate?: TemplateRef<unknown>; |     @ContentChild('siteItem') siteItemTemplate?: TemplateRef<{site: T; isCurrentSite: boolean}>; | ||||||
|     @ContentChild('siteLabel') siteLabelTemplate?: TemplateRef<unknown>; |     @ContentChild('siteLabel') siteLabelTemplate?: TemplateRef<{site: T; isCurrentSite: boolean}>; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Check whether a site is clickable. |      * Check whether a site is clickable. | ||||||
|  | |||||||
| @ -67,7 +67,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe | |||||||
|         }, 0); |         }, 0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @ContentChild(TemplateRef) template?: TemplateRef<unknown>; // Template defined by the content.
 |     @ContentChild(TemplateRef) template?: TemplateRef<{item: Item; active: boolean}>; // Template defined by the content.
 | ||||||
| 
 | 
 | ||||||
|     protected hostElement: HTMLElement; |     protected hostElement: HTMLElement; | ||||||
|     protected unsubscribe?: () => void; |     protected unsubscribe?: () => void; | ||||||
|  | |||||||
| @ -68,7 +68,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | |||||||
|     @Input() id = ''; // An ID to identify the tab.
 |     @Input() id = ''; // An ID to identify the tab.
 | ||||||
|     @Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); |     @Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); | ||||||
| 
 | 
 | ||||||
|     @ContentChild(TemplateRef) template?: TemplateRef<unknown>; // Template defined by the content.
 |     @ContentChild(TemplateRef) template?: TemplateRef<void>; // Template defined by the content.
 | ||||||
| 
 | 
 | ||||||
|     element: HTMLElement; // The core-tab element.
 |     element: HTMLElement; // The core-tab element.
 | ||||||
|     loaded = false; |     loaded = false; | ||||||
|  | |||||||
| @ -66,7 +66,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|     // @todo Implement ControlValueAccessor https://angular.io/api/forms/ControlValueAccessor.
 |     // @todo Implement ControlValueAccessor https://angular.io/api/forms/ControlValueAccessor.
 | ||||||
| 
 | 
 | ||||||
|     @Input() placeholder = ''; // Placeholder to set in textarea.
 |     @Input() placeholder = ''; // Placeholder to set in textarea.
 | ||||||
|     @Input() control?: FormControl; // Form control.
 |     @Input() control?: FormControl<string | undefined | null>; // Form control.
 | ||||||
|     @Input() name = 'core-rich-text-editor'; // Name to set to the textarea.
 |     @Input() name = 'core-rich-text-editor'; // Name to set to the textarea.
 | ||||||
|     @Input() component?: string; // The component to link the files to.
 |     @Input() component?: string; // The component to link the files to.
 | ||||||
|     @Input() componentId?: number; // An ID to use in conjunction with the component.
 |     @Input() componentId?: number; // An ID to use in conjunction with the component.
 | ||||||
| @ -75,7 +75,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|     @Input() contextInstanceId?: number; // The instance ID related to the context.
 |     @Input() contextInstanceId?: number; // The instance ID related to the context.
 | ||||||
|     @Input() elementId?: string; // An ID to set to the element.
 |     @Input() elementId?: string; // An ID to set to the element.
 | ||||||
|     @Input() draftExtraParams?: Record<string, unknown>; // Extra params to identify the draft.
 |     @Input() draftExtraParams?: Record<string, unknown>; // Extra params to identify the draft.
 | ||||||
|     @Output() contentChanged: EventEmitter<string>; |     @Output() contentChanged: EventEmitter<string | undefined | null>; | ||||||
| 
 | 
 | ||||||
|     @ViewChild('editor') editor?: ElementRef; // WYSIWYG editor.
 |     @ViewChild('editor') editor?: ElementRef; // WYSIWYG editor.
 | ||||||
|     @ViewChild('textarea') textarea?: IonTextarea; // Textarea editor.
 |     @ViewChild('textarea') textarea?: IonTextarea; // Textarea editor.
 | ||||||
| @ -190,8 +190,8 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|         // Setup the editor.
 |         // Setup the editor.
 | ||||||
|         this.editorElement = this.editor?.nativeElement as HTMLDivElement; |         this.editorElement = this.editor?.nativeElement as HTMLDivElement; | ||||||
|         this.setContent(this.control?.value); |         this.setContent(this.control?.value); | ||||||
|         this.originalContent = this.control?.value; |         this.originalContent = this.control?.value ?? undefined; | ||||||
|         this.lastDraft = this.control?.value; |         this.lastDraft = this.control?.value ?? ''; | ||||||
| 
 | 
 | ||||||
|         // Use paragraph on enter.
 |         // Use paragraph on enter.
 | ||||||
|         // eslint-disable-next-line deprecation/deprecation
 |         // eslint-disable-next-line deprecation/deprecation
 | ||||||
| @ -261,19 +261,19 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
| 
 | 
 | ||||||
|             // Apply the new content.
 |             // Apply the new content.
 | ||||||
|             this.setContent(newValue); |             this.setContent(newValue); | ||||||
|             this.originalContent = newValue; |             this.originalContent = newValue ?? undefined; | ||||||
|             this.infoMessage = undefined; |             this.infoMessage = undefined; | ||||||
| 
 | 
 | ||||||
|             // Save a draft so the original content is saved.
 |             // Save a draft so the original content is saved.
 | ||||||
|             this.lastDraft = newValue; |             this.lastDraft = newValue ?? ''; | ||||||
|             CoreEditorOffline.saveDraft( |             CoreEditorOffline.saveDraft( | ||||||
|                 this.contextLevel || '', |                 this.contextLevel || '', | ||||||
|                 this.contextInstanceId || 0, |                 this.contextInstanceId || 0, | ||||||
|                 this.elementId || '', |                 this.elementId || '', | ||||||
|                 this.draftExtraParams || {}, |                 this.draftExtraParams || {}, | ||||||
|                 this.pageInstance, |                 this.pageInstance, | ||||||
|                 newValue, |                 this.lastDraft, | ||||||
|                 newValue, |                 this.originalContent, | ||||||
|             ); |             ); | ||||||
|         }); |         }); | ||||||
| 
 | 
 | ||||||
| @ -579,7 +579,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|      * @param value text |      * @param value text | ||||||
|      * @returns If value is null only a white space. |      * @returns If value is null only a white space. | ||||||
|      */ |      */ | ||||||
|     protected isNullOrWhiteSpace(value: string | null): boolean { |     protected isNullOrWhiteSpace(value: string | null | undefined): boolean { | ||||||
|         if (value == null || value === undefined) { |         if (value == null || value === undefined) { | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
| @ -595,7 +595,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|      * |      * | ||||||
|      * @param value New content. |      * @param value New content. | ||||||
|      */ |      */ | ||||||
|     protected setContent(value: string | null): void { |     protected setContent(value: string | null | undefined): void { | ||||||
|         if (!this.editorElement || !this.textarea) { |         if (!this.editorElement || !this.textarea) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -974,7 +974,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             const newText = this.control.value; |             const newText = this.control.value ?? ''; | ||||||
| 
 | 
 | ||||||
|             if (this.lastDraft == newText) { |             if (this.lastDraft == newText) { | ||||||
|                 // Text hasn't changed, nothing to save.
 |                 // Text hasn't changed, nothing to save.
 | ||||||
|  | |||||||
| @ -69,8 +69,8 @@ export class CoreLoginEmailSignupPage implements OnInit { | |||||||
| 
 | 
 | ||||||
|     // Data for age verification.
 |     // Data for age verification.
 | ||||||
|     ageVerificationForm: FormGroup; |     ageVerificationForm: FormGroup; | ||||||
|     countryControl: FormControl; |     countryControl: FormControl<string>; | ||||||
|     signUpCountryControl?: FormControl; |     signUpCountryControl?: FormControl<string>; | ||||||
|     isMinor = false; // Whether the user is minor age.
 |     isMinor = false; // Whether the user is minor age.
 | ||||||
|     ageDigitalConsentVerification?: boolean; // Whether the age verification is enabled.
 |     ageDigitalConsentVerification?: boolean; // Whether the age verification is enabled.
 | ||||||
|     supportName?: string; |     supportName?: string; | ||||||
| @ -93,7 +93,7 @@ export class CoreLoginEmailSignupPage implements OnInit { | |||||||
|         this.ageVerificationForm = this.fb.group({ |         this.ageVerificationForm = this.fb.group({ | ||||||
|             age: ['', Validators.required], |             age: ['', Validators.required], | ||||||
|         }); |         }); | ||||||
|         this.countryControl = this.fb.control('', Validators.required); |         this.countryControl = this.fb.control('', { validators: Validators.required, nonNullable: true }); | ||||||
|         this.ageVerificationForm.addControl('country', this.countryControl); |         this.ageVerificationForm.addControl('country', this.countryControl); | ||||||
| 
 | 
 | ||||||
|         // Create the signupForm with the basic controls. More controls will be added later.
 |         // Create the signupForm with the basic controls. More controls will be added later.
 | ||||||
| @ -141,7 +141,7 @@ export class CoreLoginEmailSignupPage implements OnInit { | |||||||
|      */ |      */ | ||||||
|     protected completeFormGroup(): void { |     protected completeFormGroup(): void { | ||||||
|         this.signupForm.addControl('city', this.fb.control(this.settings?.defaultcity || '')); |         this.signupForm.addControl('city', this.fb.control(this.settings?.defaultcity || '')); | ||||||
|         this.signUpCountryControl = this.fb.control(this.settings?.country || ''); |         this.signUpCountryControl = this.fb.control(this.settings?.country || '', { nonNullable: true }); | ||||||
|         this.signupForm.addControl('country', this.signUpCountryControl); |         this.signupForm.addControl('country', this.signUpCountryControl); | ||||||
| 
 | 
 | ||||||
|         // Add the name fields.
 |         // Add the name fields.
 | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ import { CoreUserProfileField } from '@features/user/services/user'; | |||||||
| @Component({ | @Component({ | ||||||
|     template: '', |     template: '', | ||||||
| }) | }) | ||||||
| export abstract class CoreUserProfileFieldBaseComponent implements OnInit { | export abstract class CoreUserProfileFieldBaseComponent<T = string> implements OnInit { | ||||||
| 
 | 
 | ||||||
|     @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered.
 |     @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered.
 | ||||||
|     @Input() signup = false; // True if editing the field in signup. Defaults to false.
 |     @Input() signup = false; // True if editing the field in signup. Defaults to false.
 | ||||||
| @ -36,7 +36,7 @@ export abstract class CoreUserProfileFieldBaseComponent implements OnInit { | |||||||
|     @Input() contextInstanceId?: number; // The instance ID related to the context.
 |     @Input() contextInstanceId?: number; // The instance ID related to the context.
 | ||||||
|     @Input() courseId?: number; // Course ID the field belongs to (if any). It can be used to improve performance with filters.
 |     @Input() courseId?: number; // Course ID the field belongs to (if any). It can be used to improve performance with filters.
 | ||||||
| 
 | 
 | ||||||
|     control?: FormControl; |     control?: FormControl<T>; | ||||||
|     modelName = ''; |     modelName = ''; | ||||||
|     value?: string; |     value?: string; | ||||||
|     required?: boolean; |     required?: boolean; | ||||||
| @ -91,13 +91,16 @@ export abstract class CoreUserProfileFieldBaseComponent implements OnInit { | |||||||
|      * |      * | ||||||
|      * @returns Form control. |      * @returns Form control. | ||||||
|      */ |      */ | ||||||
|     protected createFormControl(field: AuthEmailSignupProfileField): FormControl { |     protected createFormControl(field: AuthEmailSignupProfileField): FormControl<T> { | ||||||
|         const formData = { |         const formData = { | ||||||
|             value: field.defaultdata, |             value: (field.defaultdata ?? '') as T, | ||||||
|             disabled: this.disabled, |             disabled: this.disabled, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         return new FormControl(formData, this.required && !field.locked ? Validators.required : null); |         return new FormControl(formData, { | ||||||
|  |             validators: this.required && !field.locked ? Validators.required : null, | ||||||
|  |             nonNullable: true, | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -312,17 +312,12 @@ export class CoreMimetypeUtilsProvider { | |||||||
|      * @returns The lowercased extension without the dot, or undefined. |      * @returns The lowercased extension without the dot, or undefined. | ||||||
|      */ |      */ | ||||||
|     guessExtensionFromUrl(fileUrl: string): string | undefined { |     guessExtensionFromUrl(fileUrl: string): string | undefined { | ||||||
|         const split = CoreUrl.removeUrlAnchor(fileUrl).split('.'); |         const parsed = CoreUrl.parse(fileUrl); | ||||||
|  |         const split = parsed?.path?.split('.'); | ||||||
|         let extension: string | undefined; |         let extension: string | undefined; | ||||||
| 
 | 
 | ||||||
|         if (split.length > 1) { |         if (split && split.length > 1) { | ||||||
|             let candidate = split[split.length - 1].toLowerCase(); |             const candidate = split[split.length - 1].toLowerCase(); | ||||||
|             // Remove params if any.
 |  | ||||||
|             const position = candidate.indexOf('?'); |  | ||||||
|             if (position > -1) { |  | ||||||
|                 candidate = candidate.substring(0, position); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (EXTENSION_REGEX.test(candidate)) { |             if (EXTENSION_REGEX.test(candidate)) { | ||||||
|                 extension = candidate; |                 extension = candidate; | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -22,10 +22,10 @@ import { catchError, filter } from 'rxjs/operators'; | |||||||
|  * @param control Form control. |  * @param control Form control. | ||||||
|  * @returns Form control value observable. |  * @returns Form control value observable. | ||||||
|  */ |  */ | ||||||
| export function formControlValue<T = unknown>(control: FormControl): Observable<T> { | export function formControlValue<T = unknown>(control: FormControl<T | null>): Observable<T> { | ||||||
|     return control.valueChanges.pipe( |     return control.valueChanges.pipe( | ||||||
|         startWithOnSubscribed(() => control.value), |         startWithOnSubscribed(() => control.value), | ||||||
|         filter(value => value !== null), |         filter((value): value is T => value !== null), | ||||||
|     ); |     ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user