From 3d7cfeba4237f85ff1ef589f53f77b60bee00239 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 18 Jun 2024 15:35:07 +0200 Subject: [PATCH 1/5] MOBILE-4612 core: Mark required inputs in components --- .../classes/base-feedback-plugin-component.ts | 8 ++++---- .../base-submission-plugin-component.ts | 6 +++--- .../edit-feedback-modal.ts | 8 ++++---- .../feedback-plugin/feedback-plugin.ts | 8 ++++---- .../submission-plugin/submission-plugin.ts | 6 +++--- .../components/submission/submission.ts | 6 +++--- .../components/users-modal/users-modal.ts | 4 ++-- .../classes/base-field-plugin-component.ts | 4 ++-- .../mod/data/components/action/action.ts | 8 ++++---- .../components/field-plugin/field-plugin.ts | 4 ++-- .../components/search-modal/search-modal.ts | 6 +++--- .../discussion-options-menu.ts | 6 +++--- .../post-options-menu/post-options-menu.ts | 6 +++--- src/addons/mod/forum/components/post/post.ts | 20 +++++++++---------- .../components/attempt-info/attempt-info.ts | 4 ++-- .../preflight-modal/preflight-modal.ts | 6 +++--- .../components/question-card/question-card.ts | 2 +- src/addons/mod/scorm/components/toc/toc.ts | 6 +++--- .../subwiki-picker/subwiki-picker.ts | 2 +- .../classes/assessment-strategy-component.ts | 14 ++++++------- .../assessment-strategy.ts | 10 +++++----- .../components/assessment/assessment.ts | 12 +++++------ .../components/phase-modal/phase-modal.ts | 6 +++--- .../components/submission/submission.ts | 10 +++++----- .../workshop/pages/submission/submission.html | 4 ++-- src/addons/notes/components/add/add-modal.ts | 2 +- .../components/course-image/course-image.ts | 2 +- .../group-selector/group-selector.ts | 2 +- .../infinite-loading/infinite-loading.ts | 2 +- .../components/progress-bar/progress-bar.ts | 2 +- .../components/sheet-modal/sheet-modal.ts | 2 +- src/core/components/sites-list/sites-list.ts | 2 +- src/core/components/tabs/tab.ts | 2 +- src/core/directives/user-tour.ts | 2 +- .../block/classes/base-block-component.ts | 8 ++++---- .../features/block/components/block/block.ts | 8 ++++---- .../side-blocks-button/side-blocks-button.ts | 4 ++-- .../components/side-blocks/side-blocks.ts | 4 ++-- .../comments/components/comments/comments.ts | 8 ++++---- .../components/compile-html/compile-html.ts | 2 +- .../choose-site-modal/choose-site-modal.ts | 2 +- .../course/classes/main-resource-component.ts | 4 ++-- .../components/course-format/course-format.ts | 2 +- .../components/module-info/module-info.ts | 8 ++++---- .../module-navigation/module-navigation.ts | 4 ++-- .../course/components/module/module.ts | 2 +- .../course-list-item/course-list-item.ts | 2 +- .../course-options-menu.ts | 4 ++-- .../audio-histogram/audio-histogram.ts | 2 +- .../exceeded-attempts/exceeded-attempts.ts | 2 +- .../rating/components/aggregate/aggregate.ts | 12 +++++------ .../features/rating/components/rate/rate.ts | 18 ++++++++--------- .../rating/components/ratings/ratings.ts | 16 +++++++-------- .../components/report-column/report-column.ts | 12 +++++------ .../components/report-detail/report-detail.ts | 2 +- .../report-summary/report-summary.ts | 2 +- .../global-search-result.ts | 2 +- .../siteplugins/classes/call-ws-directive.ts | 2 +- .../assign-feedback/assign-feedback.ts | 8 ++++---- .../assign-submission/assign-submission.ts | 6 +++--- .../components/module-index/module-index.ts | 4 ++-- .../plugin-content/plugin-content.ts | 2 +- .../workshop-assessment-strategy.ts | 14 ++++++------- .../components/user-tour/user-tour.ts | 6 +++--- 64 files changed, 183 insertions(+), 183 deletions(-) diff --git a/src/addons/mod/assign/classes/base-feedback-plugin-component.ts b/src/addons/mod/assign/classes/base-feedback-plugin-component.ts index 31713b7583c..f2211a3bc03 100644 --- a/src/addons/mod/assign/classes/base-feedback-plugin-component.ts +++ b/src/addons/mod/assign/classes/base-feedback-plugin-component.ts @@ -27,10 +27,10 @@ import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } }) export class AddonModAssignFeedbackPluginBaseComponent implements IAddonModAssignFeedbackPluginComponent { - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. - @Input() userId!: number; // The user ID of the submission. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) userId!: number; // The user ID of the submission. @Input() configs?: Record; // The configs for the plugin. @Input() canEdit = false; // Whether the user can edit. @Input() edit = false; // Whether the user is editing. diff --git a/src/addons/mod/assign/classes/base-submission-plugin-component.ts b/src/addons/mod/assign/classes/base-submission-plugin-component.ts index 56f938d0b4c..b2251af07fb 100644 --- a/src/addons/mod/assign/classes/base-submission-plugin-component.ts +++ b/src/addons/mod/assign/classes/base-submission-plugin-component.ts @@ -23,9 +23,9 @@ import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } }) export class AddonModAssignSubmissionPluginBaseComponent { - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input() configs?: Record; // The configs for the plugin. @Input() edit = false; // Whether the user is editing. @Input() allowOffline = false; // Whether to allow offline. diff --git a/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts b/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts index 35682d76f77..aafd35365b7 100644 --- a/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts +++ b/src/addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal.ts @@ -37,10 +37,10 @@ import { AddonModAssignComponentsModule } from '../components.module'; }) export class AddonModAssignEditFeedbackModalComponent { - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. - @Input() userId!: number; // The user ID of the submission. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) userId!: number; // The user ID of the submission. @ViewChild('editFeedbackForm') formElement?: ElementRef; diff --git a/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts b/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts index 136e991b51b..dbec8e19d92 100644 --- a/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts +++ b/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts @@ -37,10 +37,10 @@ export class AddonModAssignFeedbackPluginComponent implements OnInit { @ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent; - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. - @Input() userId!: number; // The user ID of the submission. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) userId!: number; // The user ID of the submission. @Input() canEdit = false; // Whether the user can edit. @Input() edit = false; // Whether the user is editing. diff --git a/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts b/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts index 93210b120e5..929bf34a45a 100644 --- a/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts +++ b/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts @@ -37,9 +37,9 @@ export class AddonModAssignSubmissionPluginComponent implements OnInit { @ViewChild(CoreDynamicComponent) dynamicComponent!: CoreDynamicComponent; - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input() edit = false; // Whether the user is editing. @Input() allowOffline = false; // Whether to allow offline. diff --git a/src/addons/mod/assign/components/submission/submission.ts b/src/addons/mod/assign/components/submission/submission.ts index 420b6970181..5d414803067 100644 --- a/src/addons/mod/assign/components/submission/submission.ts +++ b/src/addons/mod/assign/components/submission/submission.ts @@ -82,9 +82,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can @ViewChildren(AddonModAssignSubmissionPluginComponent) submissionComponents!: QueryList; - @Input() courseId!: number; // Course ID the submission belongs to. - @Input() moduleId!: number; // Module ID the submission belongs to. - @Input() submitId!: number; // User that did the submission. + @Input({ required: true }) courseId!: number; // Course ID the submission belongs to. + @Input({ required: true }) moduleId!: number; // Module ID the submission belongs to. + @Input() submitId!: number; // User that did the submission. Defaults to current user @Input() blindId?: number; // Blinded user ID (if it's blinded). loaded = false; // Whether data has been loaded. diff --git a/src/addons/mod/chat/components/users-modal/users-modal.ts b/src/addons/mod/chat/components/users-modal/users-modal.ts index 1ebd510e79f..6f40a45fd80 100644 --- a/src/addons/mod/chat/components/users-modal/users-modal.ts +++ b/src/addons/mod/chat/components/users-modal/users-modal.ts @@ -33,8 +33,8 @@ import { CoreSharedModule } from '@/core/shared.module'; }) export class AddonModChatUsersModalComponent implements OnInit, OnDestroy { - @Input() sessionId!: string; - @Input() cmId!: number; + @Input({ required: true }) sessionId!: string; + @Input({ required: true }) cmId!: number; users: AddonModChatUser[] = []; usersLoaded = false; diff --git a/src/addons/mod/data/classes/base-field-plugin-component.ts b/src/addons/mod/data/classes/base-field-plugin-component.ts index 93483a02891..72a64b03c3e 100644 --- a/src/addons/mod/data/classes/base-field-plugin-component.ts +++ b/src/addons/mod/data/classes/base-field-plugin-component.ts @@ -26,8 +26,8 @@ import { AddonModDataTemplateMode } from '../constants'; }) export abstract class AddonModDataFieldPluginBaseComponent implements OnInit, OnChanges { - @Input() mode!: AddonModDataTemplateMode; // The render mode. - @Input() field!: AddonModDataField; // The field to render. + @Input({ required: true }) mode!: AddonModDataTemplateMode; // The render mode. + @Input({ required: true }) field!: AddonModDataField; // The field to render. @Input() value?: Partial; // The value of the field. @Input() database?: AddonModDataData; // Database object. @Input() error?: string; // Error when editing. diff --git a/src/addons/mod/data/components/action/action.ts b/src/addons/mod/data/components/action/action.ts index 10022f9f821..57a9da66d41 100644 --- a/src/addons/mod/data/components/action/action.ts +++ b/src/addons/mod/data/components/action/action.ts @@ -45,10 +45,10 @@ import { export class AddonModDataActionComponent implements OnInit { @Input() access?: AddonModDataGetDataAccessInformationWSResponse; // Access info. - @Input() mode!: AddonModDataTemplateMode; // The render mode. - @Input() action!: AddonModDataAction; // The field to render. - @Input() entry!: AddonModDataEntry; // The value of the field. - @Input() database!: AddonModDataData; // Database object. + @Input({ required: true }) mode!: AddonModDataTemplateMode; // The render mode. + @Input({ required: true }) action!: AddonModDataAction; // The field to render. + @Input({ required: true }) entry!: AddonModDataEntry; // The value of the field. + @Input({ required: true }) database!: AddonModDataData; // Database object. @Input() title = ''; // Name of the module. @Input() group = 0; // Module group. @Input() offset?: number; // Offset of the entry. diff --git a/src/addons/mod/data/components/field-plugin/field-plugin.ts b/src/addons/mod/data/components/field-plugin/field-plugin.ts index 3527ccee39b..f364c1a6758 100644 --- a/src/addons/mod/data/components/field-plugin/field-plugin.ts +++ b/src/addons/mod/data/components/field-plugin/field-plugin.ts @@ -32,8 +32,8 @@ export class AddonModDataFieldPluginComponent implements OnInit, OnChanges { @ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent; - @Input() mode!: AddonModDataTemplateMode; // The render mode. - @Input() field!: AddonModDataField; // The field to render. + @Input({ required: true }) mode!: AddonModDataTemplateMode; // The render mode. + @Input({ required: true }) field!: AddonModDataField; // The field to render. @Input() value?: unknown; // The value of the field. @Input() database?: AddonModDataData; // Database object. @Input() error?: string; // Error when editing. diff --git a/src/addons/mod/data/components/search-modal/search-modal.ts b/src/addons/mod/data/components/search-modal/search-modal.ts index 2867c9feade..9f7cf1086d3 100644 --- a/src/addons/mod/data/components/search-modal/search-modal.ts +++ b/src/addons/mod/data/components/search-modal/search-modal.ts @@ -50,9 +50,9 @@ export class AddonModDataSearchModalComponent implements OnInit { @ViewChild('searchFormEl') formElement!: ElementRef; - @Input() search!: AddonModDataSearchDataParams; - @Input() fields!: Record; - @Input() database!: AddonModDataData; + @Input({ required: true }) search!: AddonModDataSearchDataParams; + @Input({ required: true }) fields!: Record; + @Input({ required: true }) database!: AddonModDataData; advancedSearch = ''; advancedIndexed: CoreFormFields = {}; diff --git a/src/addons/mod/forum/components/discussion-options-menu/discussion-options-menu.ts b/src/addons/mod/forum/components/discussion-options-menu/discussion-options-menu.ts index 0eb646d2de3..91e3041fa8d 100644 --- a/src/addons/mod/forum/components/discussion-options-menu/discussion-options-menu.ts +++ b/src/addons/mod/forum/components/discussion-options-menu/discussion-options-menu.ts @@ -30,9 +30,9 @@ import { CoreToasts } from '@services/toasts'; }) export class AddonModForumDiscussionOptionsMenuComponent implements OnInit { - @Input() discussion!: AddonModForumDiscussion; // The discussion. - @Input() forumId!: number; // The forum Id. - @Input() cmId!: number; // The component module Id. + @Input({ required: true }) discussion!: AddonModForumDiscussion; // The discussion. + @Input({ required: true }) forumId!: number; // The forum Id. + @Input({ required: true }) cmId!: number; // The component module Id. canPin = false; diff --git a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts index 8dccdcb0250..e7f44e28bc2 100644 --- a/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts +++ b/src/addons/mod/forum/components/post-options-menu/post-options-menu.ts @@ -30,9 +30,9 @@ import { CoreNetworkError } from '@classes/errors/network-error'; }) export class AddonModForumPostOptionsMenuComponent implements OnInit { - @Input() post!: AddonModForumPost; // The post. - @Input() cmId!: number; - @Input() forumId!: number; // The forum Id. + @Input({ required: true }) post!: AddonModForumPost; // The post. + @Input({ required: true }) cmId!: number; + @Input({ required: true }) forumId!: number; // The forum Id. canEdit = false; canDelete = false; diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 75978267557..496b313b88c 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -65,17 +65,17 @@ import { CoreToasts } from '@services/toasts'; }) export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges { - @Input() post!: AddonModForumPost; // Post. - @Input() courseId!: number; // Post's course ID. - @Input() discussionId!: number; // Post's' discussion ID. + @Input({ required: true }) post!: AddonModForumPost; // Post. + @Input({ required: true }) courseId!: number; // Post's course ID. + @Input({ required: true }) discussionId!: number; // Post's' discussion ID. @Input() discussion?: AddonModForumDiscussion; // Post's' discussion, only for starting posts. - @Input() component!: string; // Component this post belong to. - @Input() componentId!: number; // Component ID. - @Input() formData!: AddonModForumSharedPostFormData; // Object with the new post data. Usually shared between posts. - @Input() originalData!: Omit; // Original post data. Usually shared between posts. - @Input() trackPosts!: boolean; // True if post is being tracked. - @Input() forum!: AddonModForumData; // The forum the post belongs to. Required for attachments and offline posts. - @Input() accessInfo!: AddonModForumAccessInformation; // Forum access information. + @Input({ required: true }) component!: string; // Component this post belong to. + @Input({ required: true }) componentId!: number; // Component ID. + @Input({ required: true }) formData!: AddonModForumSharedPostFormData; // New post data. Usually shared between posts. + @Input({ required: true }) originalData!: Omit; // Original data. Usually shared between posts. + @Input({ required: true }) trackPosts!: boolean; // True if post is being tracked. + @Input({ required: true }) forum!: AddonModForumData; // The forum the post belongs to. + @Input({ required: true }) accessInfo!: AddonModForumAccessInformation; // Forum access information. @Input() parentSubject?: string; // Subject of parent post. @Input() ratingInfo?: CoreRatingInfo; // Rating info item. @Input() leavingPage?: boolean; // Whether the page that contains this post is being left and will be destroyed. diff --git a/src/addons/mod/quiz/components/attempt-info/attempt-info.ts b/src/addons/mod/quiz/components/attempt-info/attempt-info.ts index 25c0498aca0..4e6ef30c63f 100644 --- a/src/addons/mod/quiz/components/attempt-info/attempt-info.ts +++ b/src/addons/mod/quiz/components/attempt-info/attempt-info.ts @@ -30,8 +30,8 @@ import { isSafeNumber } from '@/core/utils/types'; }) export class AddonModQuizAttemptInfoComponent implements OnChanges { - @Input() quiz!: AddonModQuizQuizData; - @Input() attempt!: AddonModQuizAttempt; + @Input({ required: true }) quiz!: AddonModQuizQuizData; + @Input({ required: true }) attempt!: AddonModQuizAttempt; @Input() additionalData?: AddonModQuizWSAdditionalData[]; // Additional data to display for the attempt. isFinished = false; diff --git a/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts b/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts index 4ec740b22f7..59d06ca3290 100644 --- a/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts +++ b/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts @@ -39,12 +39,12 @@ export class AddonModQuizPreflightModalComponent implements OnInit { @ViewChild('preflightFormEl') formElement?: ElementRef; - @Input() title!: string; + @Input({ required: true }) title!: string; @Input() quiz?: AddonModQuizQuizWSData; @Input() attempt?: AddonModQuizAttemptWSData; @Input() prefetch?: boolean; - @Input() siteId!: string; - @Input() rules!: string[]; + @Input({ required: true }) siteId!: string; + @Input({ required: true }) rules!: string[]; preflightForm: FormGroup; accessRulesData: { component: Type; data: Record}[] = []; // Component and data for each access rule. diff --git a/src/addons/mod/quiz/components/question-card/question-card.ts b/src/addons/mod/quiz/components/question-card/question-card.ts index 0f6c4c87aa2..b89c912cb4a 100644 --- a/src/addons/mod/quiz/components/question-card/question-card.ts +++ b/src/addons/mod/quiz/components/question-card/question-card.ts @@ -25,6 +25,6 @@ import { CoreQuestionQuestionForView } from '@features/question/services/questio }) export class AddonModQuizQuestionCardComponent { - @Input() question!: CoreQuestionQuestionForView; + @Input({ required: true }) question!: CoreQuestionQuestionForView; } diff --git a/src/addons/mod/scorm/components/toc/toc.ts b/src/addons/mod/scorm/components/toc/toc.ts index 42199ba110c..f91d0bbcf83 100644 --- a/src/addons/mod/scorm/components/toc/toc.ts +++ b/src/addons/mod/scorm/components/toc/toc.ts @@ -35,9 +35,9 @@ export class AddonModScormTocComponent implements OnInit { @Input() toc: AddonModScormTOCScoWithIcon[] = []; @Input() attemptToContinue?: number; @Input() selected?: number; - @Input() moduleId!: number; - @Input() courseId!: number; - @Input() accessInfo!: AddonModScormGetScormAccessInformationWSResponse; + @Input({ required: true }) moduleId!: number; + @Input({ required: true }) courseId!: number; + @Input({ required: true }) accessInfo!: AddonModScormGetScormAccessInformationWSResponse; @Input() mode = ''; isBrowse = false; diff --git a/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts b/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts index 878d918d311..adfb4821ad2 100644 --- a/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts +++ b/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts @@ -32,7 +32,7 @@ export class AddonModWikiSubwikiPickerComponent { @Input() courseId?: number; @Input() subwikis: AddonModWikiSubwikiListGrouping[] = []; - @Input() currentSubwiki!: AddonModWikiSubwiki; + @Input({ required: true }) currentSubwiki!: AddonModWikiSubwiki; /** * Checks if the given subwiki is the one currently selected. diff --git a/src/addons/mod/workshop/classes/assessment-strategy-component.ts b/src/addons/mod/workshop/classes/assessment-strategy-component.ts index 1e9c85548bf..6d0f5780b05 100644 --- a/src/addons/mod/workshop/classes/assessment-strategy-component.ts +++ b/src/addons/mod/workshop/classes/assessment-strategy-component.ts @@ -24,13 +24,13 @@ import { AddonModWorkshopSubmissionAssessmentWithFormData } from '../services/wo }) export class AddonModWorkshopAssessmentStrategyBaseComponent { - @Input() workshopId!: number; - @Input() assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input() edit!: boolean; - @Input() selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; - @Input() fieldErrors!: Record; - @Input() strategy!: string; - @Input() moduleId!: number; + @Input({ required: true }) workshopId!: number; + @Input({ required: true }) assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; + @Input({ required: true }) edit!: boolean; + @Input({ required: true }) selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; + @Input({ required: true }) fieldErrors!: Record; + @Input({ required: true }) strategy!: string; + @Input({ required: true }) moduleId!: number; @Input() courseId?: number; } diff --git a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts index 503174cf52e..1e6709cfa07 100644 --- a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts +++ b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts @@ -52,11 +52,11 @@ import { }) export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDestroy { - @Input() workshop!: AddonModWorkshopData; - @Input() access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; - @Input() assessmentId!: number; - @Input() userId!: number; - @Input() strategy!: string; + @Input({ required: true }) workshop!: AddonModWorkshopData; + @Input({ required: true }) access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; + @Input({ required: true }) assessmentId!: number; + @Input({ required: true }) userId!: number; + @Input({ required: true }) strategy!: string; @Input() edit = false; @ViewChild('assessmentForm') formElement!: ElementRef; diff --git a/src/addons/mod/workshop/components/assessment/assessment.ts b/src/addons/mod/workshop/components/assessment/assessment.ts index 1e6464bc073..6fac33bd21b 100644 --- a/src/addons/mod/workshop/components/assessment/assessment.ts +++ b/src/addons/mod/workshop/components/assessment/assessment.ts @@ -36,12 +36,12 @@ import { AddonModWorkshopOffline } from '../../services/workshop-offline'; }) export class AddonModWorkshopAssessmentComponent implements OnInit { - @Input() assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input() courseId!: number; - @Input() workshop!: AddonModWorkshopData; - @Input() access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; - @Input() submission!: AddonModWorkshopSubmissionDataWithOfflineData; - @Input() module!: CoreCourseModuleData; + @Input({ required: true }) assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; + @Input({ required: true }) courseId!: number; + @Input({ required: true }) workshop!: AddonModWorkshopData; + @Input({ required: true }) access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; + @Input({ required: true }) submission!: AddonModWorkshopSubmissionDataWithOfflineData; + @Input({ required: true }) module!: CoreCourseModuleData; canViewAssessment = false; canSelfAssess = false; diff --git a/src/addons/mod/workshop/components/phase-modal/phase-modal.ts b/src/addons/mod/workshop/components/phase-modal/phase-modal.ts index 95bc52faabc..c437404ec79 100644 --- a/src/addons/mod/workshop/components/phase-modal/phase-modal.ts +++ b/src/addons/mod/workshop/components/phase-modal/phase-modal.ts @@ -31,10 +31,10 @@ import { CoreSharedModule } from '@/core/shared.module'; }) export class AddonModWorkshopPhaseInfoModalComponent implements OnInit { - @Input() phases!: AddonModWorkshopPhaseDataWithSwitch[]; - @Input() workshopPhase!: AddonModWorkshopPhase; + @Input({ required: true }) phases!: AddonModWorkshopPhaseDataWithSwitch[]; + @Input({ required: true }) workshopPhase!: AddonModWorkshopPhase; @Input() showSubmit = false; - @Input() externalUrl!: string; + @Input({ required: true }) externalUrl!: string; ngOnInit(): void { diff --git a/src/addons/mod/workshop/components/submission/submission.ts b/src/addons/mod/workshop/components/submission/submission.ts index 53ae4a89150..6dfbe5226dc 100644 --- a/src/addons/mod/workshop/components/submission/submission.ts +++ b/src/addons/mod/workshop/components/submission/submission.ts @@ -41,11 +41,11 @@ import { ADDON_MOD_WORKSHOP_COMPONENT, ADDON_MOD_WORKSHOP_PAGE_NAME, AddonModWor }) export class AddonModWorkshopSubmissionComponent implements OnInit { - @Input() submission!: AddonModWorkshopSubmissionDataWithOfflineData; - @Input() module!: CoreCourseModuleData; - @Input() workshop!: AddonModWorkshopData; - @Input() access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; - @Input() courseId!: number; + @Input({ required: true }) submission!: AddonModWorkshopSubmissionDataWithOfflineData; + @Input({ required: true }) module!: CoreCourseModuleData; + @Input({ required: true }) workshop!: AddonModWorkshopData; + @Input({ required: true }) access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; + @Input({ required: true }) courseId!: number; @Input() assessment?: AddonModWorkshopSubmissionAssessmentWithFormData; @Input() summary = false; diff --git a/src/addons/mod/workshop/pages/submission/submission.html b/src/addons/mod/workshop/pages/submission/submission.html index dde29a6976a..0a4ed502901 100644 --- a/src/addons/mod/workshop/pages/submission/submission.html +++ b/src/addons/mod/workshop/pages/submission/submission.html @@ -88,8 +88,8 @@

{{ 'addon.mod_workshop.receivedgrades' | translate }}

{{ 'addon.mod_workshop.givengrades' | translate }}

- +
diff --git a/src/addons/notes/components/add/add-modal.ts b/src/addons/notes/components/add/add-modal.ts index 337b97dc67e..c4c12b786ca 100644 --- a/src/addons/notes/components/add/add-modal.ts +++ b/src/addons/notes/components/add/add-modal.ts @@ -36,7 +36,7 @@ export class AddonNotesAddComponent { @ViewChild('itemEdit') formElement?: ElementRef; - @Input() courseId!: number; + @Input({ required: true }) courseId!: number; @Input() userId?: number; @Input() type: AddonNotesPublishState = 'personal'; text = ''; diff --git a/src/core/components/course-image/course-image.ts b/src/core/components/course-image/course-image.ts index dc440b81ac9..16be9d56962 100644 --- a/src/core/components/course-image/course-image.ts +++ b/src/core/components/course-image/course-image.ts @@ -24,7 +24,7 @@ import { CoreColors } from '@singletons/colors'; }) export class CoreCourseImageComponent implements OnInit, OnChanges { - @Input() course!: CoreCourseListItem; + @Input({ required: true }) course!: CoreCourseListItem; @Input() fill = false; protected element: HTMLElement; diff --git a/src/core/components/group-selector/group-selector.ts b/src/core/components/group-selector/group-selector.ts index 41dbcfe29e2..df9139a342c 100644 --- a/src/core/components/group-selector/group-selector.ts +++ b/src/core/components/group-selector/group-selector.ts @@ -34,7 +34,7 @@ export class CoreGroupSelectorComponent { @Input() groupInfo?: CoreGroupInfo; @Input() multipleGroupsMessage?: string; - @Input() selected!: number; + @Input({ required: true }) selected!: number; @Input() courseId?: number; @Output() selectedChange = new EventEmitter(); diff --git a/src/core/components/infinite-loading/infinite-loading.ts b/src/core/components/infinite-loading/infinite-loading.ts index 49103a3df96..8999b0093c8 100644 --- a/src/core/components/infinite-loading/infinite-loading.ts +++ b/src/core/components/infinite-loading/infinite-loading.ts @@ -30,7 +30,7 @@ const THRESHOLD = .15; // % of the scroll element height that must be close to t }) export class CoreInfiniteLoadingComponent implements OnChanges { - @Input() enabled!: boolean; + @Input({ required: true }) enabled!: boolean; @Input() error = false; @Input() position: 'top' | 'bottom' = 'bottom'; @Output() action: EventEmitter<() => void>; // Will emit an event when triggered. diff --git a/src/core/components/progress-bar/progress-bar.ts b/src/core/components/progress-bar/progress-bar.ts index 932e63ddce5..1d30c770c08 100644 --- a/src/core/components/progress-bar/progress-bar.ts +++ b/src/core/components/progress-bar/progress-bar.ts @@ -30,7 +30,7 @@ import { DomSanitizer, Translate } from '@singletons'; }) export class CoreProgressBarComponent implements OnChanges { - @Input() progress!: number | string; // Percentage from 0 to 100. Negative number will show an indeterminate progress bar. + @Input({ required: true }) progress!: number | string; // Percentage (0 to 100). Negative number will show an indeterminate bar. @Input() text?: string; // Percentage in text to be shown at the right. If not defined, progress will be used. @Input() a11yText?: string; // Accessibility text to read before the percentage. @Input() ariaDescribedBy?: string; // ID of the element that described the progress, if any. diff --git a/src/core/components/sheet-modal/sheet-modal.ts b/src/core/components/sheet-modal/sheet-modal.ts index e93409c7cb8..af8ce0f1777 100644 --- a/src/core/components/sheet-modal/sheet-modal.ts +++ b/src/core/components/sheet-modal/sheet-modal.ts @@ -28,7 +28,7 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry'; }) export class CoreSheetModalComponent implements AfterViewInit { - @Input() component!: Constructor; + @Input({ required: true }) component!: Constructor; @Input() componentProps?: Record; @ViewChild('wrapper') wrapper?: ElementRef; diff --git a/src/core/components/sites-list/sites-list.ts b/src/core/components/sites-list/sites-list.ts index 0edb15b4fc7..d54d9d339c2 100644 --- a/src/core/components/sites-list/sites-list.ts +++ b/src/core/components/sites-list/sites-list.ts @@ -42,7 +42,7 @@ import { CoreSitesFactory } from '@services/sites-factory'; }) export class CoreSitesListComponent { - @Input() accountsList!: CoreAccountsList; + @Input({ required: true }) accountsList!: CoreAccountsList; @Input() sitesClickable = false; // Whether the sites are clickable. @Input() currentSiteClickable?: boolean; // If set, specify a different clickable value for current site. @Output() onSiteClicked = new EventEmitter(); diff --git a/src/core/components/tabs/tab.ts b/src/core/components/tabs/tab.ts index dd276f647a8..a7294e67f5a 100644 --- a/src/core/components/tabs/tab.ts +++ b/src/core/components/tabs/tab.ts @@ -45,7 +45,7 @@ import { CoreTabsComponent } from './tabs'; }) export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { - @Input() title!: string; // The tab title. + @Input({ required: true }) title!: string; // The tab title. @Input() icon?: string; // The tab icon. @Input() badge?: string; // A badge to add in the tab. @Input() badgeStyle?: string; // The badge color. diff --git a/src/core/directives/user-tour.ts b/src/core/directives/user-tour.ts index 04d3636ea58..cb40cb38bda 100644 --- a/src/core/directives/user-tour.ts +++ b/src/core/directives/user-tour.ts @@ -25,7 +25,7 @@ import { CoreDom } from '@singletons/dom'; }) export class CoreUserTourDirective implements OnInit, OnDestroy { - @Input() userTour!: CoreUserTourDirectiveOptions; + @Input({ required: true }) userTour!: CoreUserTourDirectiveOptions; private tour?: CoreUserToursUserTour | null; private element: HTMLElement; diff --git a/src/core/features/block/classes/base-block-component.ts b/src/core/features/block/classes/base-block-component.ts index 05bec595cdf..cfb6402c020 100644 --- a/src/core/features/block/classes/base-block-component.ts +++ b/src/core/features/block/classes/base-block-component.ts @@ -32,10 +32,10 @@ import { CorePromisedValue } from '@classes/promised-value'; }) export abstract class CoreBlockBaseComponent implements OnInit, OnChanges, ICoreBlockComponent, AsyncDirective { - @Input() title!: string; // The block title. - @Input() block!: CoreCourseBlock; // The block to render. - @Input() contextLevel!: ContextLevel; // The context where the block will be used. - @Input() instanceId!: number; // The instance ID associated with the context level. + @Input({ required: true }) title!: string; // The block title. + @Input({ required: true }) block!: CoreCourseBlock; // The block to render. + @Input({ required: true }) contextLevel!: ContextLevel; // The context where the block will be used. + @Input({ required: true }) instanceId!: number; // The instance ID associated with the context level. @Input() link?: string; // Link to go when clicked. @Input() linkParams?: Params; // Link params to go when clicked. @Input() navOptions?: CoreNavigationOptions; // Navigation options. diff --git a/src/core/features/block/components/block/block.ts b/src/core/features/block/components/block/block.ts index a89f4ee0966..684e5c7cdfd 100644 --- a/src/core/features/block/components/block/block.ts +++ b/src/core/features/block/components/block/block.ts @@ -32,10 +32,10 @@ export class CoreBlockComponent implements OnChanges, OnDestroy { @ViewChild(CoreDynamicComponent) dynamicComponent?: CoreDynamicComponent; - @Input() block!: CoreCourseBlock; // The block to render. - @Input() contextLevel!: ContextLevel; // The context where the block will be used. - @Input() instanceId!: number; // The instance ID associated with the context level. - @Input() extraData!: Record; // Any extra data to be passed to the block. + @Input({ required: true }) block!: CoreCourseBlock; // The block to render. + @Input({ required: true }) contextLevel!: ContextLevel; // The context where the block will be used. + @Input({ required: true }) instanceId!: number; // The instance ID associated with the context level. + @Input() extraData?: Record; // Any extra data to be passed to the block. @Input() labelledBy?: string; componentClass?: Type; // The class of the component to render. diff --git a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts index a9d9f51eca8..cf159c64144 100644 --- a/src/core/features/block/components/side-blocks-button/side-blocks-button.ts +++ b/src/core/features/block/components/side-blocks-button/side-blocks-button.ts @@ -31,8 +31,8 @@ import { ContextLevel } from '@/core/constants'; }) export class CoreBlockSideBlocksButtonComponent implements OnInit, OnDestroy { - @Input() contextLevel!: ContextLevel; - @Input() instanceId!: number; + @Input({ required: true }) contextLevel!: ContextLevel; + @Input({ required: true }) instanceId!: number; @Input() myDashboardPage?: string; userTour: CoreUserTourDirectiveOptions = { diff --git a/src/core/features/block/components/side-blocks/side-blocks.ts b/src/core/features/block/components/side-blocks/side-blocks.ts index d4ac0287673..23eee8649cb 100644 --- a/src/core/features/block/components/side-blocks/side-blocks.ts +++ b/src/core/features/block/components/side-blocks/side-blocks.ts @@ -42,8 +42,8 @@ import { CoreBlockComponentsModule } from '../components.module'; }) export class CoreBlockSideBlocksComponent implements OnInit { - @Input() contextLevel!: ContextLevel; - @Input() instanceId!: number; + @Input({ required: true }) contextLevel!: ContextLevel; + @Input({ required: true }) instanceId!: number; @Input() initialBlockInstanceId?: number; @Input() myDashboardPage?: string; diff --git a/src/core/features/comments/components/comments/comments.ts b/src/core/features/comments/components/comments/comments.ts index d780b9ebb97..e465839b404 100644 --- a/src/core/features/comments/components/comments/comments.ts +++ b/src/core/features/comments/components/comments/comments.ts @@ -33,10 +33,10 @@ import { ContextLevel } from '@/core/constants'; }) export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestroy { - @Input() contextLevel!: ContextLevel; - @Input() instanceId!: number; - @Input() component!: string; - @Input() itemId!: number; + @Input({ required: true }) contextLevel!: ContextLevel; + @Input({ required: true }) instanceId!: number; + @Input({ required: true }) component!: string; + @Input({ required: true }) itemId!: number; @Input() area = ''; @Input() title?: string; @Output() onLoading = new EventEmitter(); // Event that indicates whether the component is loading data. diff --git a/src/core/features/compile/components/compile-html/compile-html.ts b/src/core/features/compile/components/compile-html/compile-html.ts index 10c0c3d2a4d..76d453d89fa 100644 --- a/src/core/features/compile/components/compile-html/compile-html.ts +++ b/src/core/features/compile/components/compile-html/compile-html.ts @@ -63,7 +63,7 @@ import { CoreDom } from '@singletons/dom'; }) export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { - @Input() text!: string; // The HTML text to display. + @Input({ required: true }) text!: string; // The HTML text to display. @Input() javascript?: string; // The Javascript to execute in the component. @Input() jsData?: Record; // Data to pass to the fake component. @Input() cssCode?: string; // The styles to apply. diff --git a/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts b/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts index 15c4e29d1e3..fa546b31763 100644 --- a/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts +++ b/src/core/features/contentlinks/components/choose-site-modal/choose-site-modal.ts @@ -36,7 +36,7 @@ import { CoreSharedModule } from '@/core/shared.module'; }) export class CoreContentLinksChooseSiteModalComponent implements OnInit { - @Input() url!: string; + @Input({ required: true }) url!: string; sites: CoreSiteBasicInfo[] = []; loaded = false; diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index e3b994b08da..40a2e7cda9e 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -52,8 +52,8 @@ export type CoreCourseResourceDownloadResult = { }) export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, CoreCourseModuleMainComponent { - @Input() module!: CoreCourseModuleData; // The module of the component. - @Input() courseId!: number; // Course ID the component belongs to. + @Input({ required: true }) module!: CoreCourseModuleData; // The module of the component. + @Input({ required: true }) courseId!: number; // Course ID the component belongs to. @Output() dataRetrieved = new EventEmitter(); // Called to notify changes the index page from the main component. showLoading = true; // Whether to show loading. diff --git a/src/core/features/course/components/course-format/course-format.ts b/src/core/features/course/components/course-format/course-format.ts index 311864b22c7..c0edc183c8c 100644 --- a/src/core/features/course/components/course-format/course-format.ts +++ b/src/core/features/course/components/course-format/course-format.ts @@ -84,7 +84,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { static readonly LOAD_MORE_ACTIVITIES = 10; // How many activities should load each time showMoreActivities is called. - @Input() course!: CoreCourseAnyCourseData; // The course to render. + @Input({ required: true }) course!: CoreCourseAnyCourseData; // The course to render. @Input() sections: CoreCourseSectionToDisplay[] = []; // List of course sections. @Input() initialSectionId?: number; // The section to load first (by ID). @Input() initialSectionNumber?: number; // The section to load first (by number). diff --git a/src/core/features/course/components/module-info/module-info.ts b/src/core/features/course/components/module-info/module-info.ts index 75999e0d81a..c372b936b4a 100644 --- a/src/core/features/course/components/module-info/module-info.ts +++ b/src/core/features/course/components/module-info/module-info.ts @@ -35,11 +35,11 @@ import { CoreSites } from '@services/sites'; }) export class CoreCourseModuleInfoComponent implements OnInit { - @Input() module!: CoreCourseModuleData; // The module to render. - @Input() courseId!: number; // The courseId the module belongs to. + @Input({ required: true }) module!: CoreCourseModuleData; // The module to render. + @Input({ required: true }) courseId!: number; // The courseId the module belongs to. - @Input() component!: string; // Component for format text directive. - @Input() componentId!: string | number; // Component ID to use in conjunction with the component. + @Input({ required: true }) component!: string; // Component for format text directive. + @Input({ required: true }) componentId!: string | number; // Component ID to use in conjunction with the component. @Input() description?: string | false; // The description to display. If false, no description will be shown. @Input() expandDescription = false; // If the description should be expanded by default. diff --git a/src/core/features/course/components/module-navigation/module-navigation.ts b/src/core/features/course/components/module-navigation/module-navigation.ts index 33aca98d54d..ce555d49455 100644 --- a/src/core/features/course/components/module-navigation/module-navigation.ts +++ b/src/core/features/course/components/module-navigation/module-navigation.ts @@ -36,8 +36,8 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; }) export class CoreCourseModuleNavigationComponent implements OnInit, OnDestroy { - @Input() courseId!: number; // Course ID. - @Input() currentModuleId!: number; // Current module Id. + @Input({ required: true }) courseId!: number; // Course ID. + @Input({ required: true }) currentModuleId!: number; // Current module Id. nextModule?: CoreCourseModuleData; previousModule?: CoreCourseModuleData; diff --git a/src/core/features/course/components/module/module.ts b/src/core/features/course/components/module/module.ts index f8c86775127..d6aa7cee0e4 100644 --- a/src/core/features/course/components/module/module.ts +++ b/src/core/features/course/components/module/module.ts @@ -45,7 +45,7 @@ import { BehaviorSubject } from 'rxjs'; }) export class CoreCourseModuleComponent implements OnInit, OnDestroy { - @Input() module!: CoreCourseModuleData; // The module to render. + @Input({ required: true }) module!: CoreCourseModuleData; // The module to render. @Input() section?: CoreCourseSection; // The section the module belongs to. @Input() showActivityDates = false; // Whether to show activity dates. @Input() showCompletionConditions = false; // Whether to show activity completion conditions. 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 ebf2a8bdd9a..1fdc3d89c78 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 @@ -43,7 +43,7 @@ import { CoreDownloadStatusTranslatable } from '@components/download-refresh/dow }) export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, OnChanges { - @Input() course!: CoreCourseListItem; // The course to render. + @Input({ required: true }) course!: CoreCourseListItem; // The course to render. @Input() showDownload = false; // If true, will show download button. @Input() layout: 'listwithenrol'|'summarycard'|'list'|'card' = 'listwithenrol'; diff --git a/src/core/features/courses/components/course-options-menu/course-options-menu.ts b/src/core/features/courses/components/course-options-menu/course-options-menu.ts index b8bece69c55..271c3e07fd3 100644 --- a/src/core/features/courses/components/course-options-menu/course-options-menu.ts +++ b/src/core/features/courses/components/course-options-menu/course-options-menu.ts @@ -27,8 +27,8 @@ import { PopoverController } from '@singletons'; }) export class CoreCoursesCourseOptionsMenuComponent implements OnInit { - @Input() course!: CoreEnrolledCourseDataWithExtraInfoAndOptions; // The course. - @Input() prefetch!: CorePrefetchStatusInfo; // The prefecth info. + @Input({ required: true }) course!: CoreEnrolledCourseDataWithExtraInfoAndOptions; // The course. + @Input({ required: true }) prefetch!: CorePrefetchStatusInfo; // The prefecth info. downloadCourseEnabled = false; diff --git a/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts b/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts index 7ced49f269a..886b92ae642 100644 --- a/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts +++ b/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts @@ -31,7 +31,7 @@ export class CoreFileUploaderAudioHistogramComponent implements AfterViewInit, O private static readonly BARS_MIN_HEIGHT = 4; private static readonly BARS_GUTTER = 4; - @Input() analyser!: AnalyserNode; + @Input({ required: true }) analyser!: AnalyserNode; @Input() paused?: boolean; @ViewChild('canvas') canvasRef?: ElementRef; diff --git a/src/core/features/login/components/exceeded-attempts/exceeded-attempts.ts b/src/core/features/login/components/exceeded-attempts/exceeded-attempts.ts index 867dc4e459d..57b4b8a3035 100644 --- a/src/core/features/login/components/exceeded-attempts/exceeded-attempts.ts +++ b/src/core/features/login/components/exceeded-attempts/exceeded-attempts.ts @@ -23,7 +23,7 @@ import { CoreUserSupport } from '@features/user/services/support'; }) export class CoreLoginExceededAttemptsComponent implements OnInit { - @Input() supportConfig!: CoreUserSupportConfig; + @Input({ required: true }) supportConfig!: CoreUserSupportConfig; @Input() supportSubject?: string; canContactSupport = false; diff --git a/src/core/features/rating/components/aggregate/aggregate.ts b/src/core/features/rating/components/aggregate/aggregate.ts index 7837e6343f6..9687202ed45 100644 --- a/src/core/features/rating/components/aggregate/aggregate.ts +++ b/src/core/features/rating/components/aggregate/aggregate.ts @@ -33,12 +33,12 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; }) export class CoreRatingAggregateComponent implements OnChanges, OnDestroy { - @Input() ratingInfo!: CoreRatingInfo; - @Input() contextLevel!: ContextLevel; - @Input() instanceId!: number; - @Input() itemId!: number; - @Input() aggregateMethod!: number; - @Input() scaleId!: number; + @Input({ required: true }) ratingInfo!: CoreRatingInfo; + @Input({ required: true }) contextLevel!: ContextLevel; + @Input({ required: true }) instanceId!: number; + @Input({ required: true }) itemId!: number; + @Input({ required: true }) aggregateMethod!: number; + @Input({ required: true }) scaleId!: number; @Input() courseId?: number; item?: CoreRatingInfoItem; diff --git a/src/core/features/rating/components/rate/rate.ts b/src/core/features/rating/components/rate/rate.ts index a7b9c562ee4..5768ce81202 100644 --- a/src/core/features/rating/components/rate/rate.ts +++ b/src/core/features/rating/components/rate/rate.ts @@ -37,15 +37,15 @@ import { CoreEventObserver, CoreEvents } from '@singletons/events'; }) export class CoreRatingRateComponent implements OnChanges, OnDestroy { - @Input() ratingInfo!: CoreRatingInfo; - @Input() contextLevel!: ContextLevel; // Context level: course, module, user, etc. - @Input() instanceId!: number; // Context instance id. - @Input() itemId!: number; // Item id. Example: forum post id. - @Input() itemSetId!: number; // Item set id. Example: forum discussion id. - @Input() courseId!: number; - @Input() aggregateMethod!: number; - @Input() scaleId!: number; - @Input() userId!: number; + @Input({ required: true }) ratingInfo!: CoreRatingInfo; + @Input({ required: true }) contextLevel!: ContextLevel; // Context level: course, module, user, etc. + @Input({ required: true }) instanceId!: number; // Context instance id. + @Input({ required: true }) itemId!: number; // Item id. Example: forum post id. + @Input({ required: true }) itemSetId!: number; // Item set id. Example: forum discussion id. + @Input({ required: true }) courseId!: number; + @Input({ required: true }) aggregateMethod!: number; + @Input({ required: true }) scaleId!: number; + @Input({ required: true }) userId!: number; @Output() protected onLoading: EventEmitter; // Eevent that indicates whether the component is loading data. @Output() protected onUpdate: EventEmitter; // Event emitted when the rating is updated online. diff --git a/src/core/features/rating/components/ratings/ratings.ts b/src/core/features/rating/components/ratings/ratings.ts index 5dc9aa6f8a3..005476c11b9 100644 --- a/src/core/features/rating/components/ratings/ratings.ts +++ b/src/core/features/rating/components/ratings/ratings.ts @@ -31,14 +31,14 @@ import { ModalController } from '@singletons'; }) export class CoreRatingRatingsComponent implements OnInit { - @Input() contextLevel!: ContextLevel; - @Input() instanceId!: number; - @Input() ratingComponent!: string; - @Input() ratingArea!: string; - @Input() aggregateMethod!: number; - @Input() itemId!: number; - @Input() scaleId!: number; - @Input() courseId!: number; + @Input({ required: true }) contextLevel!: ContextLevel; + @Input({ required: true }) instanceId!: number; + @Input({ required: true }) ratingComponent!: string; + @Input({ required: true }) ratingArea!: string; + @Input({ required: true }) aggregateMethod!: number; + @Input({ required: true }) itemId!: number; + @Input({ required: true }) scaleId!: number; + @Input({ required: true }) courseId!: number; loaded = false; ratings: CoreRatingItemRating[] = []; diff --git a/src/core/features/reportbuilder/components/report-column/report-column.ts b/src/core/features/reportbuilder/components/report-column/report-column.ts index 5d086c93abf..a7c55302361 100644 --- a/src/core/features/reportbuilder/components/report-column/report-column.ts +++ b/src/core/features/reportbuilder/components/report-column/report-column.ts @@ -25,12 +25,12 @@ export class CoreReportBuilderReportColumnComponent { @Input() isExpanded = false; @Input() isExpandable = false; @Input() showFirstTitle = false; - @Input() columnIndex!: number; - @Input() rowIndex!: number; - @Input() column!: string | number; - @Input() contextId!: number; - @Input() header!: string; - @Input() source!: string; + @Input({ required: true }) columnIndex!: number; + @Input({ required: true }) rowIndex!: number; + @Input({ required: true }) column!: string | number; + @Input({ required: true }) contextId!: number; + @Input({ required: true }) header!: string; + @Input({ required: true }) source!: string; @Output() onToggleRow: EventEmitter = new EventEmitter(); isString = (value: unknown): boolean => CoreReportBuilder.isString(value); diff --git a/src/core/features/reportbuilder/components/report-detail/report-detail.ts b/src/core/features/reportbuilder/components/report-detail/report-detail.ts index 5be2882727a..5776d71ffd3 100644 --- a/src/core/features/reportbuilder/components/report-detail/report-detail.ts +++ b/src/core/features/reportbuilder/components/report-detail/report-detail.ts @@ -40,7 +40,7 @@ import { map } from 'rxjs/operators'; }) export class CoreReportBuilderReportDetailComponent implements OnInit { - @Input() reportId!: string; + @Input({ required: true }) reportId!: string; @Input() isBlock = true; @Input() perPage?: number; @Input() layout: 'card' | 'table' | 'adaptative' = 'adaptative'; diff --git a/src/core/features/reportbuilder/components/report-summary/report-summary.ts b/src/core/features/reportbuilder/components/report-summary/report-summary.ts index 13b3650c5f0..7db580ef8d0 100644 --- a/src/core/features/reportbuilder/components/report-summary/report-summary.ts +++ b/src/core/features/reportbuilder/components/report-summary/report-summary.ts @@ -31,7 +31,7 @@ import { ModalController } from '@singletons'; }) export class CoreReportBuilderReportSummaryComponent implements OnInit { - @Input() reportDetail!: CoreReportBuilderReportDetail; + @Input({ required: true }) reportDetail!: CoreReportBuilderReportDetail; reportUrl!: string; reportDetailToDisplay!: { title: string; text: string }[]; diff --git a/src/core/features/search/components/global-search-result/global-search-result.ts b/src/core/features/search/components/global-search-result/global-search-result.ts index 7e60f15e6f2..ae02fedfb10 100644 --- a/src/core/features/search/components/global-search-result/global-search-result.ts +++ b/src/core/features/search/components/global-search-result/global-search-result.ts @@ -22,7 +22,7 @@ import { CoreSearchGlobalSearchResult, CoreSearchGlobalSearchResultContext } fro }) export class CoreSearchGlobalSearchResultComponent implements OnChanges { - @Input() result!: CoreSearchGlobalSearchResult; + @Input({ required: true }) result!: CoreSearchGlobalSearchResult; @Input() showCourse?: boolean; renderedContext: CoreSearchGlobalSearchResultContext | null = null; diff --git a/src/core/features/siteplugins/classes/call-ws-directive.ts b/src/core/features/siteplugins/classes/call-ws-directive.ts index f17b7d8a4d4..ead49d373e1 100644 --- a/src/core/features/siteplugins/classes/call-ws-directive.ts +++ b/src/core/features/siteplugins/classes/call-ws-directive.ts @@ -27,7 +27,7 @@ import { CoreFormFields, CoreForms } from '@singletons/form'; @Directive() export class CoreSitePluginsCallWSBaseDirective implements OnInit, OnDestroy { - @Input() name!: string; // The name of the WS to call. + @Input({ required: true }) name!: string; // The name of the WS to call. @Input() params?: Record; // The params for the WS call. @Input() preSets?: CoreSiteWSPreSets; // The preSets for the WS call. @Input() useOtherDataForWS?: string[] | unknown; // Whether to include other data in the params for the WS. diff --git a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts index 213f4361a83..ce1b2e54d6e 100644 --- a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts +++ b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts @@ -28,10 +28,10 @@ import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/class }) export class CoreSitePluginsAssignFeedbackComponent extends CoreSitePluginsCompileInitComponent implements OnInit { - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. - @Input() userId!: number; // The user ID of the submission. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) userId!: number; // The user ID of the submission. @Input() configs?: Record; // The configs for the plugin. @Input() canEdit = false; // Whether the user can edit. @Input() edit = false; // Whether the user is editing. diff --git a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts index ed723258719..a00da205455 100644 --- a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts +++ b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts @@ -28,9 +28,9 @@ import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/class }) export class CoreSitePluginsAssignSubmissionComponent extends CoreSitePluginsCompileInitComponent implements OnInit { - @Input() assign!: AddonModAssignAssign; // The assignment. - @Input() submission!: AddonModAssignSubmission; // The submission. - @Input() plugin!: AddonModAssignPlugin; // The plugin object. + @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. + @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. + @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input() configs?: Record; // The configs for the plugin. @Input() edit = false; // Whether the user is editing. @Input() allowOffline = false; // Whether to allow offline. diff --git a/src/core/features/siteplugins/components/module-index/module-index.ts b/src/core/features/siteplugins/components/module-index/module-index.ts index 6d629123570..49f51aca9e2 100644 --- a/src/core/features/siteplugins/components/module-index/module-index.ts +++ b/src/core/features/siteplugins/components/module-index/module-index.ts @@ -41,8 +41,8 @@ import { CoreSitePluginsPluginContentComponent, CoreSitePluginsPluginContentLoad }) export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, CoreCourseModuleMainComponent { - @Input() module!: CoreCourseModuleData; // The module. - @Input() courseId!: number; // Course ID the module belongs to. + @Input({ required: true }) module!: CoreCourseModuleData; // The module. + @Input({ required: true }) courseId!: number; // Course ID the module belongs to. @Input() pageTitle?: string; // Current page title. It can be used by the "new-content" directives. @ViewChild(CoreSitePluginsPluginContentComponent) content?: CoreSitePluginsPluginContentComponent; diff --git a/src/core/features/siteplugins/components/plugin-content/plugin-content.ts b/src/core/features/siteplugins/components/plugin-content/plugin-content.ts index 49634c4a92b..6a501b8d80c 100644 --- a/src/core/features/siteplugins/components/plugin-content/plugin-content.ts +++ b/src/core/features/siteplugins/components/plugin-content/plugin-content.ts @@ -50,7 +50,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck { @ViewChild('compile') compileComponent?: CoreCompileHtmlComponent; @HostBinding('class') @Input() component = ''; - @Input() method!: string; + @Input({ required: true }) method!: string; @Input() args?: Record; @Input() initResult?: CoreSitePluginsContent | null; // Result of the init WS call of the handler. @Input() data: Record = {}; // Data to pass to the component. diff --git a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts index 2030ab47427..7b89221ff1d 100644 --- a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts +++ b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts @@ -28,13 +28,13 @@ import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/class }) export class CoreSitePluginsWorkshopAssessmentStrategyComponent extends CoreSitePluginsCompileInitComponent implements OnInit { - @Input() workshopId!: number; - @Input() assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input() edit!: boolean; - @Input() selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; - @Input() fieldErrors!: Record; - @Input() strategy!: string; - @Input() moduleId!: number; + @Input({ required: true }) workshopId!: number; + @Input({ required: true }) assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; + @Input({ required: true }) edit!: boolean; + @Input({ required: true }) selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; + @Input({ required: true }) fieldErrors!: Record; + @Input({ required: true }) strategy!: string; + @Input({ required: true }) moduleId!: number; @Input() courseId?: number; /** diff --git a/src/core/features/usertours/components/user-tour/user-tour.ts b/src/core/features/usertours/components/user-tour/user-tour.ts index 2f278d8fc23..0d0aacce63b 100644 --- a/src/core/features/usertours/components/user-tour/user-tour.ts +++ b/src/core/features/usertours/components/user-tour/user-tour.ts @@ -52,9 +52,9 @@ const BACKDROP_DISMISS_SAFETY_TRESHOLD = 1000; }) export class CoreUserToursUserTourComponent implements AfterViewInit, OnDestroy { - @Input() container!: HTMLElement; - @Input() id!: string; - @Input() component!: unknown; + @Input({ required: true }) container!: HTMLElement; + @Input({ required: true }) id!: string; + @Input({ required: true }) component!: unknown; @Input() componentProps?: Record; @Input() focus?: HTMLElement; @Input() side?: CoreUserToursSide; From d45fc9c7a70a5a3b127f6985fe5c2dbcf7c0b221 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 20 Jun 2024 16:38:50 +0200 Subject: [PATCH 2/5] MOBILE-4612 core: Create and use toBoolean input transform --- .../timeline/components/events/events.ts | 7 ++-- .../calendar/components/calendar/calendar.ts | 11 +++--- .../classes/base-feedback-plugin-component.ts | 5 +-- .../base-submission-plugin-component.ts | 5 +-- .../feedback-plugin/feedback-plugin.ts | 5 +-- .../submission-plugin/submission-plugin.ts | 5 +-- src/addons/mod/forum/components/post/post.ts | 7 ++-- .../component/offlineattempts.ts | 3 +- .../password/component/password.ts | 3 +- .../timelimit/component/timelimit.ts | 3 +- .../components/attempt-state/attempt-state.ts | 3 +- .../navigation-modal/navigation-modal.ts | 7 ++-- .../preflight-modal/preflight-modal.ts | 3 +- .../classes/assessment-strategy-component.ts | 3 +- .../assessment-strategy.ts | 3 +- .../components/phase-modal/phase-modal.ts | 3 +- .../components/submission/submission.ts | 3 +- .../deferredcbm/component/deferredcbm.ts | 5 +-- .../component/informationitem.ts | 5 +-- src/core/classes/tabs.ts | 3 +- .../components/attachments/attachments.ts | 11 +++--- src/core/components/bs-tooltip/bs-tooltip.ts | 3 +- .../button-with-spinner.ts | 3 +- src/core/components/chart/chart.ts | 9 ++--- src/core/components/chrono/chrono.ts | 7 ++-- src/core/components/combobox/combobox.ts | 3 +- .../context-menu/context-menu-item.ts | 19 +++++------ .../components/course-image/course-image.ts | 3 +- .../download-refresh/download-refresh.ts | 7 ++-- src/core/components/empty-box/empty-box.ts | 5 +-- src/core/components/file/file.ts | 19 +++++------ src/core/components/files/files.ts | 16 ++++----- src/core/components/iframe/iframe.ts | 19 +++-------- .../infinite-loading/infinite-loading.ts | 5 +-- src/core/components/loading/loading.ts | 9 ++--- src/core/components/local-file/local-file.ts | 9 +++-- .../components/mark-required/mark-required.ts | 15 +++----- src/core/components/message/message.ts | 3 +- src/core/components/mod-icon/mod-icon.ts | 7 ++-- src/core/components/recaptcha/recaptcha.ts | 3 +- .../send-message-form/send-message-form.ts | 14 +++----- src/core/components/sites-list/sites-list.ts | 5 +-- src/core/components/tabs/tabs.ts | 3 +- src/core/components/timer/timer.ts | 11 +++--- .../components/user-avatar/user-avatar.ts | 5 +-- src/core/directives/aria-button.ts | 3 +- src/core/directives/auto-focus.ts | 6 ++-- src/core/directives/collapsible-footer.ts | 6 ++-- src/core/directives/collapsible-header.ts | 7 ++-- src/core/directives/format-text.ts | 33 +++++++++--------- src/core/directives/link.ts | 20 +++++------ .../comments/components/comments/comments.ts | 3 +- .../components/compile-html/compile-html.ts | 5 +-- .../components/course-format/course-format.ts | 3 +- .../module-completion/module-completion.ts | 5 +-- .../module-description/module-description.ts | 3 +- .../components/module-info/module-info.ts | 9 ++--- .../module-summary/module-summary.ts | 3 +- .../course/components/module/module.ts | 19 ++++++----- .../course-list-item/course-list-item.ts | 3 +- .../rich-text-editor/rich-text-editor.ts | 5 +-- .../components/capture-media/capture-media.ts | 3 +- .../audio-histogram/audio-histogram.ts | 3 +- .../h5p/components/h5p-iframe/h5p-iframe.ts | 3 +- .../components/login-methods/login-methods.ts | 3 +- .../user-menu-button/user-menu-button.ts | 3 +- .../classes/base-question-component.ts | 5 +-- .../question/components/question/question.ts | 7 ++-- .../components/report-column/report-column.ts | 7 ++-- .../components/report-detail/report-detail.ts | 3 +- .../global-search-filters.component.ts | 3 +- .../global-search-result.ts | 5 +-- .../components/search-box/search-box.ts | 12 +++---- .../components/list-modal/list-modal.ts | 7 ++-- .../sharedfiles/components/list/list.ts | 9 ++--- .../classes/call-ws-click-directive.ts | 6 ++-- .../assign-feedback/assign-feedback.ts | 5 +-- .../assign-submission/assign-submission.ts | 5 +-- .../question-behaviour/question-behaviour.ts | 7 ++-- .../components/question/question.ts | 5 +-- .../quiz-access-rule/quiz-access-rule.ts | 3 +- .../user-profile-field/user-profile-field.ts | 7 ++-- .../workshop-assessment-strategy.ts | 3 +- .../directives/call-ws-new-content.ts | 8 ++--- .../siteplugins/directives/call-ws.ts | 10 +++--- .../siteplugins/directives/new-content.ts | 8 ++--- .../classes/base-profilefield-component.ts | 7 ++-- .../user-profile-field/user-profile-field.ts | 9 ++--- .../features/viewer/components/text/text.ts | 5 +-- src/core/transforms/boolean.ts | 34 +++++++++++++++++++ 90 files changed, 348 insertions(+), 285 deletions(-) create mode 100644 src/core/transforms/boolean.ts diff --git a/src/addons/block/timeline/components/events/events.ts b/src/addons/block/timeline/components/events/events.ts index 041c2275574..bb69312bcd6 100644 --- a/src/addons/block/timeline/components/events/events.ts +++ b/src/addons/block/timeline/components/events/events.ts @@ -19,6 +19,7 @@ import { CoreTextUtils } from '@services/utils/text'; import { CoreEnrolledCourseDataWithOptions } from '@features/courses/services/courses-helper'; import { AddonBlockTimelineDayEvents } from '@addons/block/timeline/classes/section'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Directive to render a list of events in course overview. @@ -36,9 +37,9 @@ export class AddonBlockTimelineEventsComponent implements OnInit { @Input() events: AddonBlockTimelineDayEvents[] = []; // The events to render. @Input() course?: CoreEnrolledCourseDataWithOptions; // Whether to show the course name. - @Input() showInlineCourse = true; // Whether to show the course name within event items. - @Input() canLoadMore = false; // Whether more events can be loaded. - @Input() loadingMore = false; // Whether loading is ongoing. + @Input({ transform: toBoolean }) showInlineCourse = true; // Whether to show the course name within event items. + @Input({ transform: toBoolean }) canLoadMore = false; // Whether more events can be loaded. + @Input({ transform: toBoolean }) loadingMore = false; // Whether loading is ongoing. @Output() loadMore = new EventEmitter(); // Notify that more events should be loaded. colorizeIcons = false; diff --git a/src/addons/calendar/components/calendar/calendar.ts b/src/addons/calendar/components/calendar/calendar.ts index e2df7777129..2920b385141 100644 --- a/src/addons/calendar/components/calendar/calendar.ts +++ b/src/addons/calendar/components/calendar/calendar.ts @@ -53,6 +53,7 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreUrl } from '@singletons/url'; import { CoreTime } from '@singletons/time'; import { Translate } from '@singletons'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays a calendar. @@ -69,9 +70,9 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro @Input() initialYear?: number; // Initial year to load. @Input() initialMonth?: number; // Initial month to load. @Input() filter?: AddonCalendarFilter; // Filter to apply. - @Input() hidden?: boolean; // Whether the component is hidden. - @Input() canNavigate?: string | boolean; // Whether to include arrows to change the month. Defaults to true. - @Input() displayNavButtons?: string | boolean; // Whether to display nav buttons created by this component. Defaults to true. + @Input({ transform: toBoolean }) hidden = false; // Whether the component is hidden. + @Input({ transform: toBoolean }) canNavigate = true; // Whether to include arrows to change the month + @Input({ transform: toBoolean }) displayNavButtons = true; // Whether to display nav buttons created by this component. @Output() onEventClicked = new EventEmitter(); @Output() onDayClicked = new EventEmitter<{day: number; month: number; year: number}>(); @@ -145,10 +146,6 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro * @inheritdoc */ ngOnInit(): void { - this.canNavigate = typeof this.canNavigate == 'undefined' ? true : CoreUtils.isTrueOrOne(this.canNavigate); - this.displayNavButtons = typeof this.displayNavButtons == 'undefined' ? true : - CoreUtils.isTrueOrOne(this.displayNavButtons); - const source = new AddonCalendarMonthSlidesItemsManagerSource(this, moment({ year: this.initialYear, month: this.initialMonth ? this.initialMonth - 1 : undefined, diff --git a/src/addons/mod/assign/classes/base-feedback-plugin-component.ts b/src/addons/mod/assign/classes/base-feedback-plugin-component.ts index f2211a3bc03..fd740ca950c 100644 --- a/src/addons/mod/assign/classes/base-feedback-plugin-component.ts +++ b/src/addons/mod/assign/classes/base-feedback-plugin-component.ts @@ -18,6 +18,7 @@ import { CoreError } from '@classes/errors/error'; import { CoreModals } from '@services/modals'; import { AddonModAssignFeedbackCommentsTextData } from '../feedback/comments/services/handler'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '../services/assign'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Base class for component to render a feedback plugin. @@ -32,8 +33,8 @@ export class AddonModAssignFeedbackPluginBaseComponent implements IAddonModAssig @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input({ required: true }) userId!: number; // The user ID of the submission. @Input() configs?: Record; // The configs for the plugin. - @Input() canEdit = false; // Whether the user can edit. - @Input() edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) canEdit = false; // Whether the user can edit. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. /** * Open a modal to edit the feedback plugin. diff --git a/src/addons/mod/assign/classes/base-submission-plugin-component.ts b/src/addons/mod/assign/classes/base-submission-plugin-component.ts index b2251af07fb..f245c0a98b1 100644 --- a/src/addons/mod/assign/classes/base-submission-plugin-component.ts +++ b/src/addons/mod/assign/classes/base-submission-plugin-component.ts @@ -14,6 +14,7 @@ import { Component, Input } from '@angular/core'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '../services/assign'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Base class for component to render a submission plugin. @@ -27,8 +28,8 @@ export class AddonModAssignSubmissionPluginBaseComponent { @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input() configs?: Record; // The configs for the plugin. - @Input() edit = false; // Whether the user is editing. - @Input() allowOffline = false; // Whether to allow offline. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) allowOffline = false; // Whether to allow offline. /** * Invalidate the data. diff --git a/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts b/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts index dbec8e19d92..0d3fd81a5bf 100644 --- a/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts +++ b/src/addons/mod/assign/components/feedback-plugin/feedback-plugin.ts @@ -25,6 +25,7 @@ import { import { AddonModAssignHelper, AddonModAssignPluginConfig } from '../../services/assign-helper'; import { AddonModAssignFeedbackDelegate } from '../../services/feedback-delegate'; import { ADDON_MOD_ASSIGN_COMPONENT } from '../../constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays an assignment feedback plugin. @@ -41,8 +42,8 @@ export class AddonModAssignFeedbackPluginComponent implements OnInit { @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input({ required: true }) userId!: number; // The user ID of the submission. - @Input() canEdit = false; // Whether the user can edit. - @Input() edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) canEdit = false; // Whether the user can edit. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. pluginComponent?: Type; // Component to render the plugin. data?: AddonModAssignFeedbackPluginData; // Data to pass to the component. diff --git a/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts b/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts index 929bf34a45a..4010a919301 100644 --- a/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts +++ b/src/addons/mod/assign/components/submission-plugin/submission-plugin.ts @@ -25,6 +25,7 @@ import { AddonModAssignSubmissionDelegate } from '../../services/submission-dele import { CoreFileEntry } from '@services/file-helper'; import type { AddonModAssignSubmissionPluginBaseComponent } from '@addons/mod/assign/classes/base-submission-plugin-component'; import { ADDON_MOD_ASSIGN_COMPONENT } from '../../constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays an assignment submission plugin. @@ -40,8 +41,8 @@ export class AddonModAssignSubmissionPluginComponent implements OnInit { @Input({ required: true }) assign!: AddonModAssignAssign; // The assignment. @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. - @Input() edit = false; // Whether the user is editing. - @Input() allowOffline = false; // Whether to allow offline. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) allowOffline = false; // Whether to allow offline. pluginComponent?: Type; // Component to render the plugin. data?: AddonModAssignSubmissionPluginData; // Data to pass to the component. diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 496b313b88c..0662f5a3221 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -54,6 +54,7 @@ import { CoreDom } from '@singletons/dom'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, ADDON_MOD_FORUM_COMPONENT } from '../../constants'; import { CoreToasts } from '@services/toasts'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.). @@ -73,13 +74,13 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges @Input({ required: true }) componentId!: number; // Component ID. @Input({ required: true }) formData!: AddonModForumSharedPostFormData; // New post data. Usually shared between posts. @Input({ required: true }) originalData!: Omit; // Original data. Usually shared between posts. - @Input({ required: true }) trackPosts!: boolean; // True if post is being tracked. + @Input({ required: true, transform: toBoolean }) trackPosts = false; // True if post is being tracked. @Input({ required: true }) forum!: AddonModForumData; // The forum the post belongs to. @Input({ required: true }) accessInfo!: AddonModForumAccessInformation; // Forum access information. @Input() parentSubject?: string; // Subject of parent post. @Input() ratingInfo?: CoreRatingInfo; // Rating info item. - @Input() leavingPage?: boolean; // Whether the page that contains this post is being left and will be destroyed. - @Input() highlight = false; + @Input({ transform: toBoolean }) leavingPage = false; // Whether the page that contains this post is being left. + @Input({ transform: toBoolean }) highlight = false; @Output() onPostChange: EventEmitter = new EventEmitter(); // Event emitted when a reply is posted or modified. @ViewChild('replyFormEl') formElement!: ElementRef; diff --git a/src/addons/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts b/src/addons/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts index ea9238e3ebe..bcf26e13718 100644 --- a/src/addons/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts +++ b/src/addons/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { AddonModQuizAttemptWSData, AddonModQuizQuizWSData } from '@addons/mod/quiz/services/quiz'; import { AddonModQuizSync } from '@addons/mod/quiz/services/quiz-sync'; import { Component, OnInit, Input } from '@angular/core'; @@ -29,7 +30,7 @@ export class AddonModQuizAccessOfflineAttemptsComponent implements OnInit { @Input() rule?: string; // The name of the rule. @Input() quiz?: AddonModQuizQuizWSData; // The quiz the rule belongs to. @Input() attempt?: AddonModQuizAttemptWSData; // The attempt being started/continued. - @Input() prefetch?: boolean; // Whether the user is prefetching the quiz. + @Input({ transform: toBoolean }) prefetch = false; // Whether the user is prefetching the quiz. @Input() siteId?: string; // Site ID. @Input() form?: FormGroup; // Form where to add the form control. diff --git a/src/addons/mod/quiz/accessrules/password/component/password.ts b/src/addons/mod/quiz/accessrules/password/component/password.ts index 77ce32ac58f..65e3215dcbc 100644 --- a/src/addons/mod/quiz/accessrules/password/component/password.ts +++ b/src/addons/mod/quiz/accessrules/password/component/password.ts @@ -16,6 +16,7 @@ import { Component, OnInit, Input } from '@angular/core'; import { FormGroup, FormBuilder } from '@angular/forms'; import { AddonModQuizAttemptWSData, AddonModQuizQuizWSData } from '@addons/mod/quiz/services/quiz'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to render the preflight for password. @@ -29,7 +30,7 @@ export class AddonModQuizAccessPasswordComponent implements OnInit { @Input() rule?: string; // The name of the rule. @Input() quiz?: AddonModQuizQuizWSData; // The quiz the rule belongs to. @Input() attempt?: AddonModQuizAttemptWSData; // The attempt being started/continued. - @Input() prefetch?: boolean; // Whether the user is prefetching the quiz. + @Input({ transform: toBoolean }) prefetch = false; // Whether the user is prefetching the quiz. @Input() siteId?: string; // Site ID. @Input() form?: FormGroup; // Form where to add the form control. diff --git a/src/addons/mod/quiz/accessrules/timelimit/component/timelimit.ts b/src/addons/mod/quiz/accessrules/timelimit/component/timelimit.ts index b66ae5b3c00..b702e889adb 100644 --- a/src/addons/mod/quiz/accessrules/timelimit/component/timelimit.ts +++ b/src/addons/mod/quiz/accessrules/timelimit/component/timelimit.ts @@ -17,6 +17,7 @@ import { FormGroup } from '@angular/forms'; import { AddonModQuizAttemptWSData, AddonModQuizQuizWSData } from '@addons/mod/quiz/services/quiz'; import { CoreTime } from '@singletons/time'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to render the preflight for time limit. @@ -30,7 +31,7 @@ export class AddonModQuizAccessTimeLimitComponent implements OnInit { @Input() rule?: string; // The name of the rule. @Input() quiz?: AddonModQuizQuizWSData; // The quiz the rule belongs to. @Input() attempt?: AddonModQuizAttemptWSData; // The attempt being started/continued. - @Input() prefetch?: boolean; // Whether the user is prefetching the quiz. + @Input({ transform: toBoolean }) prefetch = false; // Whether the user is prefetching the quiz. @Input() siteId?: string; // Site ID. @Input() form?: FormGroup; // Form where to add the form control. diff --git a/src/addons/mod/quiz/components/attempt-state/attempt-state.ts b/src/addons/mod/quiz/components/attempt-state/attempt-state.ts index dd165198a5f..11bae29dfcd 100644 --- a/src/addons/mod/quiz/components/attempt-state/attempt-state.ts +++ b/src/addons/mod/quiz/components/attempt-state/attempt-state.ts @@ -14,6 +14,7 @@ import { Component, Input, OnChanges } from '@angular/core'; import { AddonModQuiz } from '../../services/quiz'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays an attempt state. @@ -26,7 +27,7 @@ import { AddonModQuiz } from '../../services/quiz'; export class AddonModQuizAttemptStateComponent implements OnChanges { @Input() state = ''; - @Input() finishedOffline = false; + @Input({ transform: toBoolean }) finishedOffline = false; readableState = ''; color = ''; diff --git a/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts b/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts index 1b71ea075d6..5950c7b0488 100644 --- a/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts +++ b/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts @@ -13,6 +13,7 @@ // limitations under the License. import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input } from '@angular/core'; import { CoreQuestionQuestionParsed } from '@features/question/services/question'; @@ -32,11 +33,11 @@ import { ModalController } from '@singletons'; export class AddonModQuizNavigationModalComponent { @Input() navigation?: AddonModQuizNavigationQuestion[]; // Whether the user is reviewing the attempt. - @Input() summaryShown?: boolean; // Whether summary is currently being shown. + @Input({ transform: toBoolean }) summaryShown = false; // Whether summary is currently being shown. @Input() nextPage?: number; // Next page. @Input() currentPage?: number; // Current page. - @Input() isReview?: boolean; // Whether the user is reviewing the attempt. - @Input() isSequential?: boolean; // Whether quiz navigation is sequential. + @Input({ transform: toBoolean }) isReview = false; // Whether the user is reviewing the attempt. + @Input({ transform: toBoolean }) isSequential = false; // Whether quiz navigation is sequential. /** * Close modal. diff --git a/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts b/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts index 59d06ca3290..975f4ae429a 100644 --- a/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts +++ b/src/addons/mod/quiz/components/preflight-modal/preflight-modal.ts @@ -23,6 +23,7 @@ import { AddonModQuizAccessRuleDelegate } from '../../services/access-rules-dele import { AddonModQuizAttemptWSData, AddonModQuizQuizWSData } from '../../services/quiz'; import { CoreDom } from '@singletons/dom'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Modal that renders the access rules for a quiz. @@ -42,7 +43,7 @@ export class AddonModQuizPreflightModalComponent implements OnInit { @Input({ required: true }) title!: string; @Input() quiz?: AddonModQuizQuizWSData; @Input() attempt?: AddonModQuizAttemptWSData; - @Input() prefetch?: boolean; + @Input({ transform: toBoolean }) prefetch = false; @Input({ required: true }) siteId!: string; @Input({ required: true }) rules!: string[]; diff --git a/src/addons/mod/workshop/classes/assessment-strategy-component.ts b/src/addons/mod/workshop/classes/assessment-strategy-component.ts index 6d0f5780b05..d9ffa86267b 100644 --- a/src/addons/mod/workshop/classes/assessment-strategy-component.ts +++ b/src/addons/mod/workshop/classes/assessment-strategy-component.ts @@ -15,6 +15,7 @@ import { Component, Input } from '@angular/core'; import { AddonModWorkshopGetAssessmentFormFieldsParsedData } from '../services/workshop'; import { AddonModWorkshopSubmissionAssessmentWithFormData } from '../services/workshop-helper'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Base class for component to render an assessment strategy. @@ -26,7 +27,7 @@ export class AddonModWorkshopAssessmentStrategyBaseComponent { @Input({ required: true }) workshopId!: number; @Input({ required: true }) assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input({ required: true }) edit!: boolean; + @Input({ required: true, transform: toBoolean }) edit = false; @Input({ required: true }) selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; @Input({ required: true }) fieldErrors!: Record; @Input({ required: true }) strategy!: string; diff --git a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts index 1e6709cfa07..1c190804777 100644 --- a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts +++ b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts @@ -42,6 +42,7 @@ import { ADDON_MOD_WORKSHOP_COMPONENT, AddonModWorkshopOverallFeedbackMode, } from '@addons/mod/workshop/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays workshop assessment strategy form. @@ -57,7 +58,7 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe @Input({ required: true }) assessmentId!: number; @Input({ required: true }) userId!: number; @Input({ required: true }) strategy!: string; - @Input() edit = false; + @Input({ transform: toBoolean }) edit = false; @ViewChild('assessmentForm') formElement!: ElementRef; diff --git a/src/addons/mod/workshop/components/phase-modal/phase-modal.ts b/src/addons/mod/workshop/components/phase-modal/phase-modal.ts index c437404ec79..a6a138526ec 100644 --- a/src/addons/mod/workshop/components/phase-modal/phase-modal.ts +++ b/src/addons/mod/workshop/components/phase-modal/phase-modal.ts @@ -18,6 +18,7 @@ import { ModalController } from '@singletons'; import { AddonModWorkshopPhaseData, AddonModWorkshopPhaseTaskData } from '../../services/workshop'; import { AddonModWorkshopPhase } from '../../constants'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Page that displays the phase info modal. @@ -33,7 +34,7 @@ export class AddonModWorkshopPhaseInfoModalComponent implements OnInit { @Input({ required: true }) phases!: AddonModWorkshopPhaseDataWithSwitch[]; @Input({ required: true }) workshopPhase!: AddonModWorkshopPhase; - @Input() showSubmit = false; + @Input({ transform: toBoolean }) showSubmit = false; @Input({ required: true }) externalUrl!: string; ngOnInit(): void { diff --git a/src/addons/mod/workshop/components/submission/submission.ts b/src/addons/mod/workshop/components/submission/submission.ts index 6dfbe5226dc..0b3481f0958 100644 --- a/src/addons/mod/workshop/components/submission/submission.ts +++ b/src/addons/mod/workshop/components/submission/submission.ts @@ -30,6 +30,7 @@ import { } from '../../services/workshop-helper'; import { AddonModWorkshopOffline } from '../../services/workshop-offline'; import { ADDON_MOD_WORKSHOP_COMPONENT, ADDON_MOD_WORKSHOP_PAGE_NAME, AddonModWorkshopPhase } from '@addons/mod/workshop/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays workshop submission. @@ -47,7 +48,7 @@ export class AddonModWorkshopSubmissionComponent implements OnInit { @Input({ required: true }) access!: AddonModWorkshopGetWorkshopAccessInformationWSResponse; @Input({ required: true }) courseId!: number; @Input() assessment?: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input() summary = false; + @Input({ transform: toBoolean }) summary = false; component = ADDON_MOD_WORKSHOP_COMPONENT; componentId?: number; diff --git a/src/addons/qbehaviour/deferredcbm/component/deferredcbm.ts b/src/addons/qbehaviour/deferredcbm/component/deferredcbm.ts index ab931d06ad1..3214d423226 100644 --- a/src/addons/qbehaviour/deferredcbm/component/deferredcbm.ts +++ b/src/addons/qbehaviour/deferredcbm/component/deferredcbm.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, EventEmitter } from '@angular/core'; import { CoreQuestionBehaviourButton, CoreQuestionQuestion } from '@features/question/services/question-helper'; @@ -30,11 +31,11 @@ export class AddonQbehaviourDeferredCBMComponent { @Input() component?: string; // The component the question belongs to. @Input() componentId?: number; // ID of the component the question belongs to. @Input() attemptId?: number; // Attempt ID. - @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input({ transform: toBoolean }) offlineEnabled = false; // Whether the question can be answered in offline. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. - @Input() review?: boolean; // Whether the user is in review mode. + @Input({ transform: toBoolean }) review = false; // Whether the user is in review mode. @Input() preferredBehaviour?: string; // Preferred behaviour. @Output() buttonClicked = new EventEmitter(); // Will emit when a behaviour button is clicked. @Output() onAbort = new EventEmitter(); // Should emit an event if the question should be aborted. diff --git a/src/addons/qbehaviour/informationitem/component/informationitem.ts b/src/addons/qbehaviour/informationitem/component/informationitem.ts index f3a6a64a200..1dd6717c380 100644 --- a/src/addons/qbehaviour/informationitem/component/informationitem.ts +++ b/src/addons/qbehaviour/informationitem/component/informationitem.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, EventEmitter } from '@angular/core'; import { CoreQuestionBehaviourButton, CoreQuestionQuestion } from '@features/question/services/question-helper'; @@ -30,11 +31,11 @@ export class AddonQbehaviourInformationItemComponent { @Input() component?: string; // The component the question belongs to. @Input() componentId?: number; // ID of the component the question belongs to. @Input() attemptId?: number; // Attempt ID. - @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input({ transform: toBoolean }) offlineEnabled = false; // Whether the question can be answered in offline. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. - @Input() review?: boolean; // Whether the user is in review mode. + @Input({ transform: toBoolean }) review = false; // Whether the user is in review mode. @Input() preferredBehaviour?: string; // Preferred behaviour. @Output() buttonClicked = new EventEmitter(); // Will emit when a behaviour button is clicked. @Output() onAbort = new EventEmitter(); // Should emit an event if the question should be aborted. diff --git a/src/core/classes/tabs.ts b/src/core/classes/tabs.ts index 08d76b5648a..cf0b196146e 100644 --- a/src/core/classes/tabs.ts +++ b/src/core/classes/tabs.ts @@ -39,6 +39,7 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry'; import { Swiper } from 'swiper'; import { SwiperOptions } from 'swiper/types'; import { CoreSwiper } from '@singletons/swiper'; +import { toBoolean } from '../transforms/boolean'; /** * Class to abstract some common code for tabs. @@ -52,7 +53,7 @@ export class CoreTabsBaseComponent implements AfterViewIn protected static readonly MIN_TAB_WIDTH = 107; @Input() selectedIndex = 0; // Index of the tab to select. - @Input() hideUntil = false; // Determine when should the contents be shown. + @Input({ transform: toBoolean }) hideUntil = false; // Determine when should the contents be shown. @Output() protected ionChange = new EventEmitter(); // Emitted when the tab changes. protected swiper?: Swiper; diff --git a/src/core/components/attachments/attachments.ts b/src/core/components/attachments/attachments.ts index ca67ff38a0d..c844e8206f9 100644 --- a/src/core/components/attachments/attachments.ts +++ b/src/core/components/attachments/attachments.ts @@ -25,6 +25,7 @@ import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuplo import { CoreFileEntry } from '@services/file-helper'; import { CoreCourses } from '@features/courses/services/courses'; import { CoreUtils } from '@services/utils/utils'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to render attachments, allow adding more and delete the current ones. @@ -51,9 +52,9 @@ export class CoreAttachmentsComponent implements OnInit { @Input() maxSubmissions?: number; // Max number of attachments. -1 means unlimited, not defined means unknown limit. @Input() component?: string; // Component the downloaded files will be linked to. @Input() componentId?: string | number; // Component ID. - @Input() allowOffline?: boolean | string; // Whether to allow selecting files in offline. + @Input({ transform: toBoolean }) allowOffline = false; // Whether to allow selecting files in offline. @Input() acceptedTypes?: string; // List of supported filetypes. If undefined, all types supported. - @Input() required?: boolean; // Whether to display the required mark. + @Input({ transform: toBoolean }) required = false; // Whether to display the required mark. @Input() courseId?: number; // Course ID. @Input() title = Translate.instant('core.fileuploader.attachedfiles'); // Title to display. @@ -131,9 +132,7 @@ export class CoreAttachmentsComponent implements OnInit { * Add a new attachment. */ async add(): Promise { - const allowOffline = !!this.allowOffline && this.allowOffline !== 'false'; - - if (!allowOffline && !CoreNetwork.isOnline()) { + if (!this.allowOffline && !CoreNetwork.isOnline()) { CoreDomUtils.showErrorModal('core.fileuploader.errormustbeonlinetoupload', true); return; @@ -142,7 +141,7 @@ export class CoreAttachmentsComponent implements OnInit { const mimetypes = this.fileTypes && this.fileTypes.mimetypes; try { - const result = await CoreFileUploaderHelper.selectFile(this.maxSize, allowOffline, undefined, mimetypes); + const result = await CoreFileUploaderHelper.selectFile(this.maxSize, this.allowOffline, undefined, mimetypes); this.files?.push(result); } catch (error) { diff --git a/src/core/components/bs-tooltip/bs-tooltip.ts b/src/core/components/bs-tooltip/bs-tooltip.ts index f3738b099bb..3e7825ddb9b 100644 --- a/src/core/components/bs-tooltip/bs-tooltip.ts +++ b/src/core/components/bs-tooltip/bs-tooltip.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input } from '@angular/core'; /** @@ -24,6 +25,6 @@ import { Component, Input } from '@angular/core'; export class CoreBSTooltipComponent { @Input() content = ''; - @Input() html?: boolean; + @Input({ transform: toBoolean }) html = false; } diff --git a/src/core/components/button-with-spinner/button-with-spinner.ts b/src/core/components/button-with-spinner/button-with-spinner.ts index 76cfa0c5c7a..ab6b611e782 100644 --- a/src/core/components/button-with-spinner/button-with-spinner.ts +++ b/src/core/components/button-with-spinner/button-with-spinner.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input } from '@angular/core'; import { CoreAnimations } from '@components/animations'; @@ -31,7 +32,7 @@ import { CoreAnimations } from '@components/animations'; }) export class CoreButtonWithSpinnerComponent { - @Input() loading = true; + @Input({ transform: toBoolean }) loading = true; @Input() loadingLabel = 'core.loading'; } diff --git a/src/core/components/chart/chart.ts b/src/core/components/chart/chart.ts index dd566186dab..5f5affbd38b 100644 --- a/src/core/components/chart/chart.ts +++ b/src/core/components/chart/chart.ts @@ -13,10 +13,10 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, OnDestroy, OnInit, ElementRef, OnChanges, ViewChild, SimpleChange } from '@angular/core'; import { CoreFilter } from '@features/filter/services/filter'; import { CoreFilterHelper } from '@features/filter/services/filter-helper'; -import { CoreUtils } from '@services/utils/utils'; import { ChartLegendLabelItem, ChartLegendOptions } from 'chart.js'; /** @@ -50,11 +50,12 @@ export class CoreChartComponent implements OnDestroy, OnInit, OnChanges { @Input() type?: string; // Type of chart. @Input() legend?: ChartLegendOptions; // Legend options. @Input() height = 300; // Height of the chart element. - @Input() filter?: boolean | string; // Whether to filter labels. If not defined, true if contextLevel and instanceId are set. + @Input({ transform: toBoolean }) filter?: boolean; // Whether to filter labels. + // If not defined, true if contextLevel and instanceId are set. @Input() contextLevel?: ContextLevel; // The context level of the text. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. - @Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the labels for some reason. + @Input({ transform: toBoolean }) wsNotFiltered = false; // If true it means the WS didn't filter the labels for some reason. @ViewChild('canvas') canvas?: ElementRef; chart?: ChartWithLegend; @@ -158,7 +159,7 @@ export class CoreChartComponent implements OnDestroy, OnInit, OnChanges { clean: true, singleLine: true, courseId: this.courseId, - wsNotFiltered: CoreUtils.isTrueOrOne(this.wsNotFiltered), + wsNotFiltered: this.wsNotFiltered, }; const filters = await CoreFilterHelper.getFilters(this.contextLevel, this.contextInstanceId, options); diff --git a/src/core/components/chrono/chrono.ts b/src/core/components/chrono/chrono.ts index 0604cc65e66..18823991dbc 100644 --- a/src/core/components/chrono/chrono.ts +++ b/src/core/components/chrono/chrono.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, @@ -42,11 +43,11 @@ import { }) export class CoreChronoComponent implements OnInit, OnChanges, OnDestroy { - @Input() running?: boolean; // Set it to true to start the chrono. Set it to false to stop it. + @Input({ transform: toBoolean }) running = false; // Set it to true to start the chrono. Set it to false to stop it. @Input() startTime = 0; // Number of milliseconds to put in the chrono before starting. @Input() endTime?: number; // Number of milliseconds to stop the chrono. - @Input() reset?: boolean; // Set it to true to reset the chrono. - @Input() hours = true; + @Input({ transform: toBoolean }) reset = false; // Set it to true to reset the chrono. + @Input({ transform: toBoolean }) hours = true; @Output() onEnd: EventEmitter; // Will emit an event when the endTime is reached. time = 0; diff --git a/src/core/components/combobox/combobox.ts b/src/core/components/combobox/combobox.ts index e85060584f6..51a8ee8a339 100644 --- a/src/core/components/combobox/combobox.ts +++ b/src/core/components/combobox/combobox.ts @@ -17,6 +17,7 @@ import { Translate } from '@singletons'; import { ModalOptions } from '@ionic/core'; import { CoreModals } from '@services/modals'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that show a combo select button (combobox). @@ -52,7 +53,7 @@ export class CoreComboboxComponent implements ControlValueAccessor { @Input() interface: 'popover' | 'modal' = 'popover'; @Input() label = Translate.instant('core.show'); // Aria label. - @Input() disabled = false; + @Input({ transform: toBoolean }) disabled = false; @Input() selection = ''; @Output() onChange = new EventEmitter(); // Will emit an event the value changed. diff --git a/src/core/components/context-menu/context-menu-item.ts b/src/core/components/context-menu/context-menu-item.ts index 25a2ab4d460..3008fc82d9b 100644 --- a/src/core/components/context-menu/context-menu-item.ts +++ b/src/core/components/context-menu/context-menu-item.ts @@ -14,6 +14,7 @@ import { Component, Input, Output, OnInit, OnDestroy, EventEmitter, OnChanges, SimpleChange } from '@angular/core'; import { CoreContextMenuComponent } from '../context-menu/context-menu'; +import { toBoolean } from '@/core/transforms/boolean'; /** * This directive adds a item to the Context Menu popover. @@ -40,19 +41,19 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange // If is "toggle" a toggle switch will be shown. // If no icon or spinner is selected, no action or link will work. // If href but no iconAction is provided arrow-right will be used. - @Input() iconSlash?: boolean; // Display a red slash over the icon. + @Input({ transform: toBoolean }) iconSlash = false; // Display a red slash over the icon. @Input() ariaAction?: string; // Aria label to add to iconAction. If not set, it will be equal to content. @Input() href?: string; // Link to go if no action provided. - @Input() captureLink?: boolean | string; // Whether the link needs to be captured by the app. - @Input() autoLogin: boolean | string = true; // Whether the link needs to be opened using auto-login. - @Input() closeOnClick = true; // Whether to close the popover when the item is clicked. + @Input({ transform: toBoolean }) captureLink = false; // Whether the link needs to be captured by the app. + @Input({ transform: toBoolean }) autoLogin = true; // Whether the link needs to be opened using auto-login. + @Input({ transform: toBoolean }) closeOnClick = true; // Whether to close the popover when the item is clicked. @Input() priority?: number; // Used to sort items. The highest priority, the highest position. @Input() badge?: string; // A badge to show in the item. @Input() badgeClass?: number; // A class to set in the badge. @Input() badgeA11yText?: string; // Description for the badge, if needed. - @Input() hidden?: boolean; // Whether the item should be hidden. - @Input() showBrowserWarning = true; // Whether to show a warning before opening browser (for links). Defaults to true. - @Input() toggle = false; // Whether the toggle is on or off. + @Input({ transform: toBoolean }) hidden = false; // Whether the item should be hidden. + @Input({ transform: toBoolean }) showBrowserWarning = true; // Whether to show a warning before opening browser (for links). + @Input({ transform: toBoolean }) toggle = false; // Whether the toggle is on or off. @Output() action?: EventEmitter<() => void>; // Will emit an event when the item clicked. @Output() onClosed?: EventEmitter<() => void>; // Will emit an event when the popover is closed because the item was clicked. @Output() toggleChange = new EventEmitter();// Will emit an event when toggle changes to enable 2-way data binding. @@ -94,10 +95,6 @@ export class CoreContextMenuItemComponent implements OnInit, OnDestroy, OnChange * @param event Event. */ toggleChanged(event: Event): void { - if (this.toggle === undefined) { - return; - } - event.preventDefault(); event.stopPropagation(); this.toggleChange.emit(this.toggle); diff --git a/src/core/components/course-image/course-image.ts b/src/core/components/course-image/course-image.ts index 16be9d56962..46ce93d9f2e 100644 --- a/src/core/components/course-image/course-image.ts +++ b/src/core/components/course-image/course-image.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, ElementRef, OnInit, OnChanges, HostBinding } from '@angular/core'; import { CoreCourseListItem } from '@features/courses/services/courses'; import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; @@ -25,7 +26,7 @@ import { CoreColors } from '@singletons/colors'; export class CoreCourseImageComponent implements OnInit, OnChanges { @Input({ required: true }) course!: CoreCourseListItem; - @Input() fill = false; + @Input({ transform: toBoolean }) fill = false; protected element: HTMLElement; diff --git a/src/core/components/download-refresh/download-refresh.ts b/src/core/components/download-refresh/download-refresh.ts index 31ae0425639..a4f491726b9 100644 --- a/src/core/components/download-refresh/download-refresh.ts +++ b/src/core/components/download-refresh/download-refresh.ts @@ -15,6 +15,7 @@ import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { DownloadStatus } from '@/core/constants'; import { CoreAnimations } from '@components/animations'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to show a download button with refresh option, the spinner and the status of it. @@ -34,9 +35,9 @@ export class CoreDownloadRefreshComponent implements OnInit { @Input() status?: DownloadStatus; // Download status. @Input() statusesTranslatable?: Partial; // Download statuses translatable strings. @Input() statusSubject = ''; // Status subject to use on name filed in the translatable string. - @Input() enabled = false; // Whether the download is enabled. - @Input() loading = true; // Force loading status when is not downloading. - @Input() canTrustDownload = false; // If false, refresh will be shown if downloaded. + @Input({ transform: toBoolean }) enabled = false; // Whether the download is enabled. + @Input({ transform: toBoolean }) loading = true; // Force loading status when is not downloading. + @Input({ transform: toBoolean }) canTrustDownload = false; // If false, refresh will be shown if downloaded. @Output() action: EventEmitter; // Will emit an event when the item clicked. /** diff --git a/src/core/components/empty-box/empty-box.ts b/src/core/components/empty-box/empty-box.ts index 1507ab73fd5..55006152f50 100644 --- a/src/core/components/empty-box/empty-box.ts +++ b/src/core/components/empty-box/empty-box.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, HostBinding, Input } from '@angular/core'; /** @@ -30,13 +31,13 @@ import { Component, HostBinding, Input } from '@angular/core'; export class CoreEmptyBoxComponent { @Input() message = ''; // Message to display. - @Input() dimmed = false; // Wether the box is dimmed or not. + @Input({ transform: toBoolean }) dimmed = false; // Wether the box is dimmed or not. @Input() icon?: string; // Name of the icon to use. @Input() image?: string; // Image source. If an icon is provided, image won't be used. /** * @deprecated since 4.4. Not used anymore. */ - @Input() flipIconRtl = false; + @Input({ transform: toBoolean }) flipIconRtl = false; @HostBinding('class.dimmed') get isDimmed(): boolean { diff --git a/src/core/components/file/file.ts b/src/core/components/file/file.ts index a525a5ec2cf..e425446666d 100644 --- a/src/core/components/file/file.ts +++ b/src/core/components/file/file.ts @@ -27,6 +27,7 @@ import { DownloadStatus } from '@/core/constants'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreWSFile } from '@services/ws'; import { CorePlatform } from '@services/platform'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to handle a remote file. Shows the file name, icon (depending on mimetype) and a button @@ -41,11 +42,11 @@ export class CoreFileComponent implements OnInit, OnDestroy { @Input() file?: CoreWSFile; // The file. @Input() component?: string; // Component the file belongs to. @Input() componentId?: string | number; // Component ID. - @Input() canDelete?: boolean | string; // Whether file can be deleted. - @Input() alwaysDownload?: boolean | string; // Whether it should always display the refresh button when the file is downloaded. - @Input() canDownload?: boolean | string = true; // Whether file can be downloaded. - @Input() showSize?: boolean | string = true; // Whether show filesize. - @Input() showTime?: boolean | string = true; // Whether show file time modified. + @Input({ transform: toBoolean }) canDelete = false; // Whether file can be deleted. + @Input({ transform: toBoolean }) alwaysDownload = false; // True to always display the refresh button when file is downloaded. + @Input({ transform: toBoolean }) canDownload = true; // Whether file can be downloaded. + @Input({ transform: toBoolean }) showSize = true; // Whether show filesize. + @Input({ transform: toBoolean }) showTime = true; // Whether show file time modified. @Output() onDelete: EventEmitter; // Will notify when the delete button is clicked. isDownloading?: boolean; @@ -77,10 +78,6 @@ export class CoreFileComponent implements OnInit, OnDestroy { return; } - this.canDelete = CoreUtils.isTrueOrOne(this.canDelete); - this.alwaysDownload = CoreUtils.isTrueOrOne(this.alwaysDownload); - this.canDownload = CoreUtils.isTrueOrOne(this.canDownload); - this.fileUrl = CoreFileHelper.getFileUrl(this.file); this.timemodified = this.file.timemodified || 0; this.siteId = CoreSites.getCurrentSiteId(); @@ -92,11 +89,11 @@ export class CoreFileComponent implements OnInit, OnDestroy { this.openButtonIcon = this.defaultIsOpenWithPicker ? 'fas-file' : 'fas-share-from-square'; this.openButtonLabel = this.defaultIsOpenWithPicker ? 'core.openfile' : 'core.openwith'; - if (CoreUtils.isTrueOrOne(this.showSize) && this.fileSize && this.fileSize >= 0) { + if (this.showSize && this.fileSize && this.fileSize >= 0) { this.fileSizeReadable = CoreTextUtils.bytesToSize(this.fileSize, 2); } - this.showTime = CoreUtils.isTrueOrOne(this.showTime) && this.timemodified > 0; + this.showTime = this.showTime && this.timemodified > 0; if ('isexternalfile' in this.file && this.file.isexternalfile) { this.alwaysDownload = true; // Always show the download button in external files. diff --git a/src/core/components/files/files.ts b/src/core/components/files/files.ts index 7aefe96406b..f76da07d60a 100644 --- a/src/core/components/files/files.ts +++ b/src/core/components/files/files.ts @@ -12,11 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, OnInit, DoCheck, KeyValueDiffers } from '@angular/core'; import { CoreFileEntry } from '@services/file-helper'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; -import { CoreUtils } from '@services/utils/utils'; /** * Component to render a file list. @@ -33,11 +33,11 @@ export class CoreFilesComponent implements OnInit, DoCheck { @Input() files: CoreFileEntry[] = []; // List of files. @Input() component?: string; // Component the downloaded files will be linked to. @Input() componentId?: string | number; // Component ID. - @Input() alwaysDownload?: boolean | string; // Whether it should always display the refresh button when the file is downloaded. - @Input() canDownload?: boolean | string = true; // Whether file can be downloaded. - @Input() showSize?: boolean | string = true; // Whether show filesize. - @Input() showTime?: boolean | string = true; // Whether show file time modified. - @Input() showInline = false; // If true, it will reorder and try to show inline files first. + @Input({ transform: toBoolean }) alwaysDownload = false; // True to always display the refresh button when file is downloaded. + @Input({ transform: toBoolean }) canDownload = true; // Whether file can be downloaded. + @Input({ transform: toBoolean }) showSize = true; // Whether show filesize. + @Input({ transform: toBoolean }) showTime = true; // Whether show file time modified. + @Input({ transform: toBoolean }) showInline = false; // If true, it will reorder and try to show inline files first. @Input() extraHtml?: string[]; // Extra HTML for each attachment. Each HTML should be at the same position as the attachment. contentText?: string; @@ -53,7 +53,7 @@ export class CoreFilesComponent implements OnInit, DoCheck { * @inheritdoc */ ngOnInit(): void { - if (CoreUtils.isTrueOrOne(this.showInline) && this.files) { + if (this.showInline && this.files) { this.renderInlineFiles(); } } @@ -62,7 +62,7 @@ export class CoreFilesComponent implements OnInit, DoCheck { * Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays). */ ngDoCheck(): void { - if (CoreUtils.isTrueOrOne(this.showInline) && this.files) { + if (this.showInline && this.files) { // Check if there's any change in the files array. const changes = this.differ.diff(this.files); if (changes) { diff --git a/src/core/components/iframe/iframe.ts b/src/core/components/iframe/iframe.ts index 5012f912840..1fca966a9b7 100644 --- a/src/core/components/iframe/iframe.ts +++ b/src/core/components/iframe/iframe.ts @@ -21,7 +21,6 @@ import { CoreFile } from '@services/file'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreUrl } from '@singletons/url'; import { CoreIframeUtils } from '@services/utils/iframe'; -import { CoreUtils } from '@services/utils/utils'; import { DomSanitizer, Router, StatusBar } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreScreen, CoreScreenOrientation } from '@services/screen'; @@ -29,6 +28,7 @@ import { Subscription } from 'rxjs'; import { filter } from 'rxjs/operators'; import { NavigationStart } from '@angular/router'; import { CoreSites } from '@services/sites'; +import { toBoolean } from '@/core/transforms/boolean'; @Component({ selector: 'core-iframe', @@ -49,10 +49,10 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { @Input() id: string | null = null; @Input() iframeWidth = '100%'; @Input() iframeHeight = '100%'; - @Input() allowFullscreen?: boolean | string; - @Input() showFullscreenOnToolbar?: boolean | string; - @Input() autoFullscreenOnRotate?: boolean | string; - @Input() allowAutoLogin = true; + @Input({ transform: toBoolean }) allowFullscreen = false; + @Input({ transform: toBoolean }) showFullscreenOnToolbar = false; + @Input({ transform: toBoolean }) autoFullscreenOnRotate = false; + @Input({ transform: toBoolean }) allowAutoLogin = true; @Output() loaded: EventEmitter = new EventEmitter(); loading?: boolean; @@ -167,15 +167,6 @@ export class CoreIframeComponent implements OnChanges, OnDestroy { 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) { return; diff --git a/src/core/components/infinite-loading/infinite-loading.ts b/src/core/components/infinite-loading/infinite-loading.ts index 8999b0093c8..2959281c14c 100644 --- a/src/core/components/infinite-loading/infinite-loading.ts +++ b/src/core/components/infinite-loading/infinite-loading.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, EventEmitter, OnChanges, SimpleChange, ViewChild, ElementRef } from '@angular/core'; import { IonInfiniteScroll } from '@ionic/angular'; import { CoreWait } from '@singletons/wait'; @@ -30,8 +31,8 @@ const THRESHOLD = .15; // % of the scroll element height that must be close to t }) export class CoreInfiniteLoadingComponent implements OnChanges { - @Input({ required: true }) enabled!: boolean; - @Input() error = false; + @Input({ required: true, transform: toBoolean }) enabled = false; + @Input({ transform: toBoolean }) error = false; @Input() position: 'top' | 'bottom' = 'bottom'; @Output() action: EventEmitter<() => void>; // Will emit an event when triggered. diff --git a/src/core/components/loading/loading.ts b/src/core/components/loading/loading.ts index f890c40ee86..bba7bb8730e 100644 --- a/src/core/components/loading/loading.ts +++ b/src/core/components/loading/loading.ts @@ -22,6 +22,7 @@ import { CorePromisedValue } from '@classes/promised-value'; import { AsyncDirective } from '@classes/async-directive'; import { CorePlatform } from '@services/platform'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to show a loading spinner and message while data is being loaded. @@ -51,9 +52,9 @@ import { CoreWait } from '@singletons/wait'; }) export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, AsyncDirective, OnDestroy { - @Input() hideUntil: unknown = false; // Determine when should the contents be shown. + @Input({ transform: toBoolean }) hideUntil = false; // Determine when should the contents be shown. @Input() message?: string; // Message to show while loading. - @Input() fullscreen = true; // Use the whole screen. + @Input({ transform: toBoolean }) fullscreen = true; // Use the whole screen. uniqueId: string; loaded = false; @@ -108,7 +109,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A * @inheritdoc */ ngAfterViewInit(): void { - this.changeState(!!this.hideUntil); + this.changeState(this.hideUntil); } /** @@ -116,7 +117,7 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A */ ngOnChanges(changes: { [name: string]: SimpleChange }): void { if (changes.hideUntil) { - this.changeState(!!this.hideUntil); + this.changeState(this.hideUntil); } } diff --git a/src/core/components/local-file/local-file.ts b/src/core/components/local-file/local-file.ts index cddbd6a7232..0c4b129499d 100644 --- a/src/core/components/local-file/local-file.ts +++ b/src/core/components/local-file/local-file.ts @@ -27,6 +27,7 @@ import { CoreUtils, CoreUtilsOpenFileOptions, OpenFileAction } from '@services/u import { CoreForms } from '@singletons/form'; import { CorePath } from '@singletons/path'; import { CorePlatform } from '@services/platform'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to handle a local file. Only files inside the app folder can be managed. @@ -41,8 +42,8 @@ import { CorePlatform } from '@services/platform'; export class CoreLocalFileComponent implements OnInit { @Input() file?: FileEntry; // A fileEntry retrieved using CoreFileProvider.getFile or similar. - @Input() manage?: boolean | string; // Whether the user can manage the file (edit and delete). - @Input() overrideClick?: boolean | string; // Whether the default item click should be overridden. + @Input({ transform: toBoolean }) manage = false; // Whether the user can manage the file (edit and delete). + @Input({ transform: toBoolean }) overrideClick = false; // Whether the default item click should be overridden. @Output() onDelete = new EventEmitter(); // Will notify when the file is deleted. @Output() onRename = new EventEmitter<{ file: FileEntry }>(); // Will notify when the file is renamed. @Output() onClick = new EventEmitter(); // Will notify when the file is clicked. Only if overrideClick is true. @@ -67,8 +68,6 @@ export class CoreLocalFileComponent implements OnInit { * @inheritdoc */ async ngOnInit(): Promise { - this.manage = CoreUtils.isTrueOrOne(this.manage); - if (!this.file) { return; } @@ -119,7 +118,7 @@ export class CoreLocalFileComponent implements OnInit { e.preventDefault(); e.stopPropagation(); - if (!isOpenButton && CoreUtils.isTrueOrOne(this.overrideClick) && this.onClick.observed) { + if (!isOpenButton && this.overrideClick && this.onClick.observed) { this.onClick.emit(); return; diff --git a/src/core/components/mark-required/mark-required.ts b/src/core/components/mark-required/mark-required.ts index f0bc34b516b..e6ed33d3eac 100644 --- a/src/core/components/mark-required/mark-required.ts +++ b/src/core/components/mark-required/mark-required.ts @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, OnInit, AfterViewInit, ElementRef } from '@angular/core'; +import { toBoolean } from '@/core/transforms/boolean'; +import { Component, Input, AfterViewInit, ElementRef } from '@angular/core'; import { CoreTextUtils } from '@services/utils/text'; -import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; /** @@ -33,9 +33,9 @@ import { Translate } from '@singletons'; templateUrl: 'core-mark-required.html', styleUrls: ['mark-required.scss'], }) -export class CoreMarkRequiredComponent implements OnInit, AfterViewInit { +export class CoreMarkRequiredComponent implements AfterViewInit { - @Input('core-mark-required') coreMarkRequired: boolean | string = true; + @Input({ alias: 'core-mark-required', transform: toBoolean }) coreMarkRequired = true; protected hostElement: HTMLElement; requiredLabel = Translate.instant('core.required'); @@ -46,13 +46,6 @@ export class CoreMarkRequiredComponent implements OnInit, AfterViewInit { this.hostElement = element.nativeElement; } - /** - * @inheritdoc - */ - ngOnInit(): void { - this.coreMarkRequired = CoreUtils.isTrueOrOne(this.coreMarkRequired); - } - /** * @inheritdoc */ diff --git a/src/core/components/message/message.ts b/src/core/components/message/message.ts index d9d1a057204..b8982f72360 100644 --- a/src/core/components/message/message.ts +++ b/src/core/components/message/message.ts @@ -19,6 +19,7 @@ import { CoreSites } from '@services/sites'; import { CoreText } from '@singletons/text'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUserWithAvatar } from '@components/user-avatar/user-avatar'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to handle a message in a conversation. @@ -39,7 +40,7 @@ export class CoreMessageComponent implements OnInit { @Input() instanceId = 0; @Input() courseId?: number; @Input() contextLevel: ContextLevel = ContextLevel.SYSTEM; - @Input() showDelete = false; + @Input({ transform: toBoolean }) showDelete = false; @Output() onDeleteMessage = new EventEmitter(); @Output() onUndoDeleteMessage = new EventEmitter(); @Output() afterRender = new EventEmitter(); diff --git a/src/core/components/mod-icon/mod-icon.ts b/src/core/components/mod-icon/mod-icon.ts index 7e1a26cb8ec..ab8727dfee2 100644 --- a/src/core/components/mod-icon/mod-icon.ts +++ b/src/core/components/mod-icon/mod-icon.ts @@ -13,6 +13,7 @@ // limitations under the License. import { CoreConstants, ModPurpose } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { ChangeDetectionStrategy, Component, @@ -54,10 +55,10 @@ export class CoreModIconComponent implements OnInit, OnChanges { @Input() fallbackTranslation = ''; // Fallback translation string if cannot auto translate. @Input() componentId?: number; // Component Id for external icons. @Input() modicon?: string; // Module icon url or local url. - @Input() showAlt = true; // Show alt otherwise it's only presentation icon. + @Input({ transform: toBoolean }) showAlt = true; // Show alt otherwise it's only presentation icon. @Input() purpose: ModPurpose = ModPurpose.MOD_PURPOSE_OTHER; // Purpose of the module. - @Input() @HostBinding('class.colorize') colorize = true; // Colorize the icon. Only applies on 4.0 onwards. - @Input() isBranded?: boolean; // If icon is branded and no colorize will be applied. + @Input({ transform: toBoolean }) @HostBinding('class.colorize') colorize = true; // Colorize the icon. Only applies on 4.0+. + @Input({ transform: toBoolean }) isBranded = false; // If icon is branded and no colorize will be applied. @HostBinding('class.branded') brandedClass?: boolean; diff --git a/src/core/components/recaptcha/recaptcha.ts b/src/core/components/recaptcha/recaptcha.ts index ef4608f4a4a..f37662f3c18 100644 --- a/src/core/components/recaptcha/recaptcha.ts +++ b/src/core/components/recaptcha/recaptcha.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, OnInit } from '@angular/core'; import { CoreLang, CoreLangFormat } from '@services/lang'; @@ -32,7 +33,7 @@ export class CoreRecaptchaComponent implements OnInit { @Input() publicKey?: string; // The site public key. @Input() modelValueName = 'recaptcharesponse'; // Name of the model property where to store the response. @Input() siteUrl = ''; // The site URL. If not defined, current site. - @Input() showRequiredError = false; // Whether to display the required error if recaptcha hasn't been answered. + @Input({ transform: toBoolean }) showRequiredError = false; // Whether to display the required error if recaptcha not answered. expired = false; diff --git a/src/core/components/send-message-form/send-message-form.ts b/src/core/components/send-message-form/send-message-form.ts index fe624981c00..8f0a4be5ba1 100644 --- a/src/core/components/send-message-form/send-message-form.ts +++ b/src/core/components/send-message-form/send-message-form.ts @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef } from '@angular/core'; +import { Component, Input, Output, EventEmitter, ViewChild, ElementRef } from '@angular/core'; import { CoreConfig } from '@services/config'; import { CoreEvents } from '@singletons/events'; import { CoreSites } from '@services/sites'; -import { CoreUtils } from '@services/utils/utils'; import { CoreTextUtils } from '@services/utils/text'; import { CoreConstants } from '@/core/constants'; import { CoreForms } from '@singletons/form'; import { CorePlatform } from '@services/platform'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a "send message form". @@ -37,12 +37,12 @@ import { CorePlatform } from '@services/platform'; templateUrl: 'core-send-message-form.html', styleUrls: ['send-message-form.scss'], }) -export class CoreSendMessageFormComponent implements OnInit { +export class CoreSendMessageFormComponent { @Input() message = ''; // Input text. @Input() placeholder = ''; // Placeholder for the input area. - @Input() showKeyboard = false; // If keyboard is shown or not. - @Input() sendDisabled = false; // If send is disabled. + @Input({ transform: toBoolean }) showKeyboard = false; // If keyboard is shown or not. + @Input({ transform: toBoolean }) sendDisabled = false; // If send is disabled. @Output() onSubmit: EventEmitter; // Send data when submitting the message form. @Output() onResize: EventEmitter; // Emit when resizing the textarea. @@ -68,10 +68,6 @@ export class CoreSendMessageFormComponent implements OnInit { }, CoreSites.getCurrentSiteId()); } - ngOnInit(): void { - this.showKeyboard = CoreUtils.isTrueOrOne(this.showKeyboard); - } - /** * Form submitted. * diff --git a/src/core/components/sites-list/sites-list.ts b/src/core/components/sites-list/sites-list.ts index d54d9d339c2..78d83c89fb3 100644 --- a/src/core/components/sites-list/sites-list.ts +++ b/src/core/components/sites-list/sites-list.ts @@ -17,6 +17,7 @@ import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } fro import { CoreSiteBasicInfo } from '@services/sites'; import { CoreAccountsList } from '@features/login/services/login-helper'; import { CoreSitesFactory } from '@services/sites-factory'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a list of sites (accounts). @@ -43,8 +44,8 @@ import { CoreSitesFactory } from '@services/sites-factory'; export class CoreSitesListComponent { @Input({ required: true }) accountsList!: CoreAccountsList; - @Input() sitesClickable = false; // Whether the sites are clickable. - @Input() currentSiteClickable?: boolean; // If set, specify a different clickable value for current site. + @Input({ transform: toBoolean }) sitesClickable = false; // Whether the sites are clickable. + @Input({ transform: toBoolean }) currentSiteClickable = false; // If set, specify a different clickable value for current site. @Output() onSiteClicked = new EventEmitter(); @ContentChild('siteItem') siteItemTemplate?: TemplateRef<{site: T; isCurrentSite: boolean}>; diff --git a/src/core/components/tabs/tabs.ts b/src/core/components/tabs/tabs.ts index ae8782a5632..a84bf2e4d35 100644 --- a/src/core/components/tabs/tabs.ts +++ b/src/core/components/tabs/tabs.ts @@ -22,6 +22,7 @@ import { import { CoreTabsBaseComponent } from '@classes/tabs'; import { CoreTabComponent } from './tab'; +import { toBoolean } from '@/core/transforms/boolean'; /** * This component displays some top scrollable tabs that will autohide on vertical scroll. @@ -44,7 +45,7 @@ import { CoreTabComponent } from './tab'; }) export class CoreTabsComponent extends CoreTabsBaseComponent implements AfterViewInit { - @Input() parentScrollable = false; // Determine if the scroll should be in the parent content or the tab itself. + @Input({ transform: toBoolean }) parentScrollable = false; // Determine if scroll should be in the parent content or the tab. @Input() layout: 'icon-top' | 'icon-start' | 'icon-end' | 'icon-bottom' | 'icon-hide' | 'label-hide' = 'icon-hide'; @ViewChild('originalTabs') diff --git a/src/core/components/timer/timer.ts b/src/core/components/timer/timer.ts index eefe50a374f..15ba62e7b3f 100644 --- a/src/core/components/timer/timer.ts +++ b/src/core/components/timer/timer.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, EventEmitter, OnInit, OnDestroy, ElementRef } from '@angular/core'; import { CoreUser } from '@features/user/services/user'; @@ -35,7 +36,7 @@ export class CoreTimerComponent implements OnInit, OnDestroy { @Input() timeLeftClass?: string; // Name of the class to apply with each second. By default, 'core-timer-timeleft-'. @Input() timeLeftClassThreshold = 100; // Number of seconds to start adding the timeLeftClass. Set it to -1 to not add it. @Input() align = 'start'; // Where to align the time and text. Defaults to 'start'. Other values: 'center', 'end'. - @Input() hidable = false; // Whether the user can hide the time left. + @Input({ transform: toBoolean }) hidable = false; // Whether the user can hide the time left. @Input() timeUpText?: string; // Text to show when the timer reaches 0. If not defined, 'core.timesup'. @Input() mode: CoreTimerMode = CoreTimerMode.ITEM; // How to display data. @Input() underTimeClassThresholds = []; // Number of seconds to add the class 'core-timer-under-'. @@ -45,7 +46,7 @@ export class CoreTimerComponent implements OnInit, OnDestroy { /** * @deprecated since 4.4. Use hidable instead. */ - @Input() hiddable?: boolean; // Whether the user can hide the time left. + @Input({ transform: toBoolean }) hiddable = false; // Whether the user can hide the time left. timeLeft?: number; // Seconds left to end. modeBasic = CoreTimerMode.BASIC; @@ -63,9 +64,9 @@ export class CoreTimerComponent implements OnInit, OnDestroy { */ async ngOnInit(): Promise { // eslint-disable-next-line deprecation/deprecation - if (this.hiddable !== undefined && this.hidable === undefined) { - // eslint-disable-next-line deprecation/deprecation - this.hidable = this.hiddable; + if (this.hiddable && !this.hidable) { + + this.hidable = true; } const timeLeftClass = this.timeLeftClass || 'core-timer-timeleft-'; diff --git a/src/core/components/user-avatar/user-avatar.ts b/src/core/components/user-avatar/user-avatar.ts index cc85a0f4cc1..de961ba4b8d 100644 --- a/src/core/components/user-avatar/user-avatar.ts +++ b/src/core/components/user-avatar/user-avatar.ts @@ -23,6 +23,7 @@ import { CoreNetwork } from '@services/network'; import { CoreUserHelper } from '@features/user/services/user-helper'; import { CoreUrl } from '@singletons/url'; import { CoreSiteInfo } from '@classes/sites/unauthenticated-site'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a "user avatar". @@ -40,11 +41,11 @@ export class CoreUserAvatarComponent implements OnInit, OnChanges, OnDestroy { @Input() site?: CoreSiteBasicInfo | CoreSiteInfo; // Site info contains user info. // The following params will override the ones in user object. @Input() profileUrl?: string; - @Input() linkProfile = true; // Avoid linking to the profile if wanted. + @Input({ transform: toBoolean }) linkProfile = true; // Avoid linking to the profile if wanted. @Input() fullname?: string; @Input() userId?: number; // If provided or found it will be used to link the image to the profile. @Input() courseId?: number; - @Input() checkOnline = false; // If want to check and show online status. + @Input({ transform: toBoolean }) checkOnline = false; // If want to check and show online status. @Input() siteId?: string; avatarUrl?: string; diff --git a/src/core/directives/aria-button.ts b/src/core/directives/aria-button.ts index ec05e4cabf4..c0edf0bee54 100644 --- a/src/core/directives/aria-button.ts +++ b/src/core/directives/aria-button.ts @@ -14,6 +14,7 @@ import { Directive, ElementRef, OnInit, Output, EventEmitter, OnChanges, SimpleChanges, Input } from '@angular/core'; import { CoreDom } from '@singletons/dom'; +import { toBoolean } from '../transforms/boolean'; /** * Directive to emulate click and key actions following aria role button. @@ -25,7 +26,7 @@ export class CoreAriaButtonClickDirective implements OnInit, OnChanges { protected element: HTMLElement; - @Input() disabled = false; + @Input({ transform: toBoolean }) disabled = false; @Output() ariaButtonClick = new EventEmitter(); constructor( diff --git a/src/core/directives/auto-focus.ts b/src/core/directives/auto-focus.ts index f531d74c04a..7c35e9cbaa0 100644 --- a/src/core/directives/auto-focus.ts +++ b/src/core/directives/auto-focus.ts @@ -15,9 +15,9 @@ import { Directive, Input, ElementRef, AfterViewInit } from '@angular/core'; import { CoreDomUtils } from '@services/utils/dom'; -import { CoreUtils } from '@services/utils/utils'; import { CoreDom } from '@singletons/dom'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '../transforms/boolean'; /** * Directive to auto focus an element when a view is loaded. @@ -32,7 +32,7 @@ import { CoreWait } from '@singletons/wait'; }) export class CoreAutoFocusDirective implements AfterViewInit { - @Input('core-auto-focus') autoFocus: boolean | string = true; + @Input({ alias: 'core-auto-focus', transform: toBoolean }) autoFocus = true; protected element: HTMLIonInputElement | HTMLIonTextareaElement | HTMLIonSearchbarElement | HTMLElement; @@ -44,7 +44,7 @@ export class CoreAutoFocusDirective implements AfterViewInit { * @inheritdoc */ async ngAfterViewInit(): Promise { - if (CoreUtils.isFalseOrZero(this.autoFocus)) { + if (!this.autoFocus) { return; } diff --git a/src/core/directives/collapsible-footer.ts b/src/core/directives/collapsible-footer.ts index 6fd746d4228..7c87d145063 100644 --- a/src/core/directives/collapsible-footer.ts +++ b/src/core/directives/collapsible-footer.ts @@ -24,6 +24,7 @@ import { CoreLoadingComponent } from '@components/loading/loading'; import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreDom } from '@singletons/dom'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '../transforms/boolean'; /** * Directive to make an element fixed at the bottom collapsible when scrolling. @@ -37,7 +38,7 @@ import { CoreWait } from '@singletons/wait'; }) export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { - @Input() appearOnBottom = false; + @Input({ transform: toBoolean }) appearOnBottom = false; // Whether footer should re-appear when reaching the bottom. protected id = '0'; protected element: HTMLElement; @@ -67,9 +68,6 @@ export class CoreCollapsibleFooterDirective implements OnInit, OnDestroy { */ async ngOnInit(): Promise { this.id = String(CoreUtils.getUniqueId('CoreCollapsibleFooterDirective')); - - // Only if not present or explicitly falsy it will be false. - this.appearOnBottom = !CoreUtils.isFalseOrZero(this.appearOnBottom); this.slotPromise = CoreDom.slotOnContent(this.element); await this.slotPromise; diff --git a/src/core/directives/collapsible-header.ts b/src/core/directives/collapsible-header.ts index b20031439aa..1f09bad8f75 100644 --- a/src/core/directives/collapsible-header.ts +++ b/src/core/directives/collapsible-header.ts @@ -20,7 +20,6 @@ import { CoreTabsOutletComponent } from '@components/tabs-outlet/tabs-outlet'; import { CoreTabsComponent } from '@components/tabs/tabs'; import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; import { ScrollDetail } from '@ionic/core'; -import { CoreUtils } from '@services/utils/utils'; import { CoreDirectivesRegistry } from '@singletons/directives-registry'; import { CoreDom } from '@singletons/dom'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; @@ -28,6 +27,7 @@ import { CoreMath } from '@singletons/math'; import { Subscription } from 'rxjs'; import { CoreFormatTextDirective } from './format-text'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '../transforms/boolean'; declare module '@singletons/events' { @@ -75,7 +75,7 @@ export const COLLAPSIBLE_HEADER_UPDATED = 'collapsible_header_updated'; }) export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDestroy { - @Input() collapsible = true; + @Input({ transform: toBoolean }) collapsible = true; protected page?: HTMLElement; protected collapsedHeader: HTMLIonHeaderElement; @@ -106,8 +106,6 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest * @inheritdoc */ ngOnInit(): void { - this.collapsible = !CoreUtils.isFalseOrZero(this.collapsible); - if (CoreDom.closest(this.collapsedHeader, 'core-tabs-outlet')) { this.collapsible = false; } @@ -142,7 +140,6 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest */ async ngOnChanges(changes: {[name: string]: SimpleChange}): Promise { if (changes.collapsible && !changes.collapsible.firstChange) { - this.collapsible = !CoreUtils.isFalseOrZero(changes.collapsible.currentValue); this.enabled = this.collapsible; await this.init(); diff --git a/src/core/directives/format-text.ts b/src/core/directives/format-text.ts index eea0da0df25..2af1d794c9b 100644 --- a/src/core/directives/format-text.ts +++ b/src/core/directives/format-text.ts @@ -56,6 +56,7 @@ import { CoreUrl } from '@singletons/url'; import { CoreIcons } from '@singletons/icons'; import { ContextLevel } from '../constants'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '../transforms/boolean'; /** * Directive to format text rendered. It renders the HTML and treats all links and media, using CoreLinkDirective @@ -77,19 +78,20 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec @Input() siteId?: string; // Site ID to use. @Input() component?: string; // Component for CoreExternalContentDirective. @Input() componentId?: string | number; // Component ID to use in conjunction with the component. - @Input() adaptImg?: boolean | string = true; // Whether to adapt images to screen width. - @Input() clean?: boolean | string; // Whether all the HTML tags should be removed. - @Input() singleLine?: boolean | string; // Whether new lines should be removed (all text in single line). Only if clean=true. + @Input({ transform: toBoolean }) adaptImg = true; // Whether to adapt images to screen width. + @Input({ transform: toBoolean }) clean = false; // Whether all the HTML tags should be removed. + @Input({ transform: toBoolean }) singleLine = false; // Whether new lines should be removed. Only if clean=true. @Input() highlight?: string; // Text to highlight. - @Input() filter?: boolean | string; // Whether to filter the text. If not defined, true if contextLevel and instanceId are set. + @Input({ transform: toBoolean }) filter?: boolean; // Whether to filter the text. + // If not defined, true if contextLevel and instanceId are set. @Input() contextLevel?: ContextLevel; // The context level of the text. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. - @Input() wsNotFiltered?: boolean | string; // If true it means the WS didn't filter the text for some reason. - @Input() captureLinks?: boolean; // Whether links should tried to be opened inside the app. Defaults to true. - @Input() openLinksInApp?: boolean; // Whether links should be opened in InAppBrowser. - @Input() hideIfEmpty = false; // If true, the tag will contain nothing if text is empty. - @Input() disabled?: boolean; // If disabled, autoplay elements will be disabled. + @Input({ transform: toBoolean }) wsNotFiltered = false; // If true it means the WS didn't filter the text for some reason. + @Input({ transform: toBoolean }) captureLinks = true; // Whether links should tried to be opened inside the app. + @Input({ transform: toBoolean }) openLinksInApp = false; // Whether links should be opened in InAppBrowser. + @Input({ transform: toBoolean }) hideIfEmpty = false; // If true, the tag will contain nothing if text is empty. + @Input({ transform: toBoolean }) disabled = false; // If disabled, autoplay elements will be disabled. @Output() afterRender: EventEmitter; // Called when the data is rendered. @Output() onClick: EventEmitter = new EventEmitter(); // Called when clicked. @@ -361,7 +363,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec } if (!this.element.getAttribute('singleLine')) { - this.element.setAttribute('singleLine', String(CoreUtils.isTrueOrOne(this.singleLine))); + this.element.setAttribute('singleLine', String(this.singleLine)); } this.text = this.text ? this.text.trim() : ''; @@ -423,15 +425,14 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec this.contextInstanceId = this.courseId; } - const filter = this.filter === undefined ? - !!(this.contextLevel && this.contextInstanceId !== undefined) : CoreUtils.isTrueOrOne(this.filter); + const filter = this.filter ?? !!(this.contextLevel && this.contextInstanceId !== undefined); const options: CoreFilterFormatTextOptions = { - clean: CoreUtils.isTrueOrOne(this.clean), - singleLine: CoreUtils.isTrueOrOne(this.singleLine), + clean: this.clean, + singleLine: this.singleLine, highlight: this.highlight, courseId: this.courseId, - wsNotFiltered: CoreUtils.isTrueOrOne(this.wsNotFiltered), + wsNotFiltered: this.wsNotFiltered, }; let formatted: string; @@ -521,7 +522,7 @@ export class CoreFormatTextDirective implements OnChanges, OnDestroy, AsyncDirec externalImages.push(externalImage); } - if (CoreUtils.isTrueOrOne(this.adaptImg) && !img.classList.contains('icon')) { + if (this.adaptImg && !img.classList.contains('icon')) { this.adaptImage(img); } }); diff --git a/src/core/directives/link.ts b/src/core/directives/link.ts index e3d1f397117..61ad4c40d5d 100644 --- a/src/core/directives/link.ts +++ b/src/core/directives/link.ts @@ -27,6 +27,7 @@ import { CoreCustomURLSchemes } from '@services/urlschemes'; import { DomSanitizer } from '@singletons'; import { CoreFilepool } from '@services/filepool'; import { CoreDom } from '@singletons/dom'; +import { toBoolean } from '../transforms/boolean'; /** * Directive to open a link in external browser or in the app. @@ -37,10 +38,10 @@ import { CoreDom } from '@singletons/dom'; export class CoreLinkDirective implements OnInit { @Input() href?: string | SafeUrl; // Link URL. - @Input() capture?: boolean | string; // If the link needs to be captured by the app. - @Input() inApp?: boolean | string; // True to open in embedded browser, false to open in system browser. - @Input() autoLogin: boolean | string = true; // Whether to try to use auto-login. Values yes/no/check are deprecated. - @Input() showBrowserWarning = true; // Whether to show a warning before opening browser. Defaults to true. + @Input({ transform: toBoolean }) capture = false; // If the link needs to be captured by the app. + @Input({ transform: toBoolean }) inApp = false; // True to open in embedded browser, false to open in system browser. + @Input({ transform: toBoolean }) autoLogin = true; // Whether to try to use auto-login. + @Input({ transform: toBoolean }) showBrowserWarning = true; // Whether to show a warning before opening browser. protected element: HTMLElement | HTMLIonFabButtonElement | HTMLIonButtonElement | HTMLIonItemElement; @@ -93,7 +94,7 @@ export class CoreLinkDirective implements OnInit { const openIn = this.element.getAttribute('data-open-in'); - if (CoreUtils.isTrueOrOne(this.capture)) { + if (this.capture) { const treated = await CoreContentLinksHelper.handleLink(CoreTextUtils.decodeURI(href), undefined, true, true); if (!treated) { @@ -177,8 +178,7 @@ export class CoreLinkDirective implements OnInit { */ protected async openExternalLink(href: string, openIn?: string | null): Promise { // Priority order is: core-link inApp attribute > forceOpenLinksIn setting > data-open-in HTML attribute. - const openInApp = this.inApp !== undefined ? - CoreUtils.isTrueOrOne(this.inApp) : + const openInApp = this.inApp ?? (CoreConstants.CONFIG.forceOpenLinksIn !== 'browser' && (CoreConstants.CONFIG.forceOpenLinksIn === 'app' || openIn === 'app')); @@ -219,11 +219,7 @@ export class CoreLinkDirective implements OnInit { } } - const autoLogin = typeof this.autoLogin === 'boolean' ? - this.autoLogin : - !CoreUtils.isFalseOrZero(this.autoLogin) && this.autoLogin !== 'no'; // Support deprecated values yes/no/check. - - if (autoLogin) { + if (this.autoLogin) { if (openInApp) { await currentSite.openInAppWithAutoLogin(href); } else { diff --git a/src/core/features/comments/components/comments/comments.ts b/src/core/features/comments/components/comments/comments.ts index e465839b404..9e9f44828fa 100644 --- a/src/core/features/comments/components/comments/comments.ts +++ b/src/core/features/comments/components/comments/comments.ts @@ -22,6 +22,7 @@ import { CoreSites } from '@services/sites'; import { CoreNavigator } from '@services/navigator'; import { CoreUtils } from '@services/utils/utils'; import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays the count of comments. @@ -41,7 +42,7 @@ export class CoreCommentsCommentsComponent implements OnInit, OnChanges, OnDestr @Input() title?: string; @Output() onLoading = new EventEmitter(); // Event that indicates whether the component is loading data. @Input() courseId?: number; // Course ID the comments belong to. It can be used to improve performance with filters. - @Input() showItem = false; // Show button as an item. + @Input({ transform: toBoolean }) showItem = false; // Show button as an item. commentsLoaded = false; commentsCount = ''; diff --git a/src/core/features/compile/components/compile-html/compile-html.ts b/src/core/features/compile/components/compile-html/compile-html.ts index 76d453d89fa..0fa63f9c100 100644 --- a/src/core/features/compile/components/compile-html/compile-html.ts +++ b/src/core/features/compile/components/compile-html/compile-html.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, @@ -70,7 +71,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { @Input() stylesPath?: string; // The styles URL to apply (only if cssCode is not set). @Input() extraImports: unknown[] = []; // Extra import modules. @Input() extraProviders: Type[] = []; // Extra providers. - @Input() forceCompile = false; // Set it to true to force compile even if the text/javascript hasn't changed. + @Input({ transform: toBoolean }) forceCompile = false; // True to force compile even if the text/javascript hasn't changed. @Output() created = new EventEmitter(); // Will emit an event when the component is instantiated. @Output() compiling = new EventEmitter(); // Event that indicates whether the template is being compiled. @@ -122,7 +123,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { // Only compile if text/javascript has changed or the forceCompile flag has been set to true. if (this.text === undefined || !(changes.text || changes.javascript || changes.cssCode || changes.stylesPath || - (changes.forceCompile && CoreUtils.isTrueOrOne(this.forceCompile)))) { + (changes.forceCompile && this.forceCompile))) { return; } diff --git a/src/core/features/course/components/course-format/course-format.ts b/src/core/features/course/components/course-format/course-format.ts index c0edc183c8c..6ff2a58049c 100644 --- a/src/core/features/course/components/course-format/course-format.ts +++ b/src/core/features/course/components/course-format/course-format.ts @@ -58,6 +58,7 @@ import { CoreBlockComponentsModule } from '@features/block/components/components import { CoreCourseComponentsModule } from '../components.module'; import { CoreSites } from '@services/sites'; import { COURSE_ALL_SECTIONS_PREFERRED_PREFIX } from '@features/course/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display course contents using a certain format. If the format isn't found, use default one. @@ -90,7 +91,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { @Input() initialSectionNumber?: number; // The section to load first (by number). @Input() initialBlockInstanceId?: number; // The instance to focus. @Input() moduleId?: number; // The module ID to scroll to. Must be inside the initial selected section. - @Input() isGuest?: boolean; // If user is accessing using an ACCESS_GUEST enrolment method. + @Input({ transform: toBoolean }) isGuest = false; // If user is accessing using an ACCESS_GUEST enrolment method. // eslint-disable-next-line @typescript-eslint/no-explicit-any @ViewChildren(CoreDynamicComponent) dynamicComponents?: QueryList>; diff --git a/src/core/features/course/components/module-completion/module-completion.ts b/src/core/features/course/components/module-completion/module-completion.ts index dccb6d57396..9962b2631f9 100644 --- a/src/core/features/course/components/module-completion/module-completion.ts +++ b/src/core/features/course/components/module-completion/module-completion.ts @@ -24,6 +24,7 @@ import { CoreCourseHelper } from '@features/course/services/course-helper'; import { CoreUser } from '@features/user/services/user'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to handle activity completion. It shows a checkbox with the current status, and allows manually changing @@ -43,8 +44,8 @@ export class CoreCourseModuleCompletionComponent extends CoreCourseModuleCompletionBaseComponent implements OnInit, OnChanges, OnDestroy { - @Input() showCompletionConditions = false; // Whether to show activity completion conditions. - @Input() showManualCompletion = false; // Whether to show manual completion. + @Input({ transform: toBoolean }) showCompletionConditions = false; // Whether to show activity completion conditions. + @Input({ transform: toBoolean }) showManualCompletion = false; // Whether to show manual completion. completed = false; accessibleDescription: string | null = null; diff --git a/src/core/features/course/components/module-description/module-description.ts b/src/core/features/course/components/module-description/module-description.ts index f55b42cb83f..8bf369c2465 100644 --- a/src/core/features/course/components/module-description/module-description.ts +++ b/src/core/features/course/components/module-description/module-description.ts @@ -14,6 +14,7 @@ import { ContextLevel } from '@/core/constants'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, HostBinding, Input } from '@angular/core'; /** @@ -49,7 +50,7 @@ export class CoreCourseModuleDescriptionComponent { @Input() note?: string; // A note to display along with the description. @Input() component?: string; // Component for format text directive. @Input() componentId?: string | number; // Component ID to use in conjunction with the component. - @Input() showFull?: string | boolean; // Whether to always display the full description. + @Input({ transform: toBoolean }) showFull = false; // Whether to always display the full description. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. diff --git a/src/core/features/course/components/module-info/module-info.ts b/src/core/features/course/components/module-info/module-info.ts index c372b936b4a..fee40aba2ed 100644 --- a/src/core/features/course/components/module-info/module-info.ts +++ b/src/core/features/course/components/module-info/module-info.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleCompletionData, CoreCourseModuleData } from '@features/course/services/course-helper'; @@ -42,13 +43,13 @@ export class CoreCourseModuleInfoComponent implements OnInit { @Input({ required: true }) componentId!: string | number; // Component ID to use in conjunction with the component. @Input() description?: string | false; // The description to display. If false, no description will be shown. - @Input() expandDescription = false; // If the description should be expanded by default. + @Input({ transform: toBoolean }) expandDescription = false; // If the description should be expanded by default. - @Input() showAvailabilityInfo = false; // If show availability info on the box. + @Input({ transform: toBoolean }) showAvailabilityInfo = false; // If show availability info on the box. - @Input() hasDataToSync = false; // If the activity has any data to be synced. + @Input({ transform: toBoolean }) hasDataToSync = false; // If the activity has any data to be synced. - @Input() showManualCompletion = true; // Whether to show manual completion, true by default. + @Input({ transform: toBoolean }) showManualCompletion = true; // Whether to show manual completion, true by default. @Output() completionChanged = new EventEmitter(); // Notify when completion changes. modicon = ''; diff --git a/src/core/features/course/components/module-summary/module-summary.ts b/src/core/features/course/components/module-summary/module-summary.ts index 45c6fe5d9b0..a14798a7582 100644 --- a/src/core/features/course/components/module-summary/module-summary.ts +++ b/src/core/features/course/components/module-summary/module-summary.ts @@ -34,6 +34,7 @@ import { ModalController, NgZone } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { Subscription } from 'rxjs'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a module summary modal. @@ -54,7 +55,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { @Input() moduleId = 0; // Module ID the component belongs to. @Input() component = ''; // Component name. @Input() description = ''; // Module description. - @Input() hasOffline = false; // If it has offline data to be synced. + @Input({ transform: toBoolean }) hasOffline = false; // If it has offline data to be synced. @Input() displayOptions: CoreCourseModuleSummaryDisplayOptions = {}; loaded = false; // If the component has been loaded. diff --git a/src/core/features/course/components/module/module.ts b/src/core/features/course/components/module/module.ts index d6aa7cee0e4..afe4c154565 100644 --- a/src/core/features/course/components/module/module.ts +++ b/src/core/features/course/components/module/module.ts @@ -30,6 +30,7 @@ import { import { CoreConstants, DownloadStatus } from '@/core/constants'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { BehaviorSubject } from 'rxjs'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a module entry in a list of modules. @@ -47,15 +48,15 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy { @Input({ required: true }) module!: CoreCourseModuleData; // The module to render. @Input() section?: CoreCourseSection; // The section the module belongs to. - @Input() showActivityDates = false; // Whether to show activity dates. - @Input() showCompletionConditions = false; // Whether to show activity completion conditions. - @Input() showLegacyCompletion?: boolean; // Whether to show module completion in the old format. - @Input() showCompletion = true; // Whether to show module completion. - @Input() showAvailability = true; // Whether to show module availability. - @Input() showExtra = true; // Whether to show extra badges. - @Input() showDownloadStatus = true; // Whether to show download status. - @Input() showIndentation = true; // Whether to show indentation - @Input() isLastViewed = false; // Whether it's the last module viewed in a course. + @Input({ transform: toBoolean }) showActivityDates = false; // Whether to show activity dates. + @Input({ transform: toBoolean }) showCompletionConditions = false; // Whether to show activity completion conditions. + @Input({ transform: toBoolean }) showLegacyCompletion?: boolean; // Whether to show module completion in the old format. + @Input({ transform: toBoolean }) showCompletion = true; // Whether to show module completion. + @Input({ transform: toBoolean }) showAvailability = true; // Whether to show module availability. + @Input({ transform: toBoolean }) showExtra = true; // Whether to show extra badges. + @Input({ transform: toBoolean }) showDownloadStatus = true; // Whether to show download status. + @Input({ transform: toBoolean }) showIndentation = true; // Whether to show indentation + @Input({ transform: toBoolean }) isLastViewed = false; // Whether it's the last module viewed in a course. @Output() completionChanged = new EventEmitter(); // Notify when module completion changes. @HostBinding('class.indented') indented = false; 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 1fdc3d89c78..344cdf30b34 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 @@ -28,6 +28,7 @@ import { CoreCoursesHelper, CoreEnrolledCourseDataWithExtraInfoAndOptions } from import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu'; import { CoreEnrolHelper } from '@features/enrol/services/enrol-helper'; import { CoreDownloadStatusTranslatable } from '@components/download-refresh/download-refresh'; +import { toBoolean } from '@/core/transforms/boolean'; /** * This directive is meant to display an item for a list of courses. @@ -44,7 +45,7 @@ import { CoreDownloadStatusTranslatable } from '@components/download-refresh/dow export class CoreCoursesCourseListItemComponent implements OnInit, OnDestroy, OnChanges { @Input({ required: true }) course!: CoreCourseListItem; // The course to render. - @Input() showDownload = false; // If true, will show download button. + @Input({ transform: toBoolean }) showDownload = false; // If true, will show download button. @Input() layout: 'listwithenrol'|'summarycard'|'list'|'card' = 'listwithenrol'; enrolmentIcons: CoreCoursesEnrolmentIcons[] = []; diff --git a/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts b/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts index 9a27b95d109..5e4fb95ea9f 100644 --- a/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts +++ b/src/core/features/editor/components/rich-text-editor/rich-text-editor.ts @@ -47,6 +47,7 @@ import { ContextLevel } from '@/core/constants'; import { CoreSwiper } from '@singletons/swiper'; import { CoreTextUtils } from '@services/utils/text'; import { CoreWait } from '@singletons/wait'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a rich text editor if enabled. @@ -73,7 +74,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, @Input() name = 'core-rich-text-editor'; // Name to set to the textarea. @Input() component?: string; // The component to link the files to. @Input() componentId?: number; // An ID to use in conjunction with the component. - @Input() autoSave?: boolean | string; // Whether to auto-save the contents in a draft. Defaults to true. + @Input({ transform: toBoolean }) autoSave = true; // Whether to auto-save the contents in a draft. @Input() contextLevel?: ContextLevel; // The context level of the text. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() elementId?: string; // An ID to set to the element. @@ -887,7 +888,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, */ protected shouldAutoSaveDrafts(): boolean { return !!CoreSites.getCurrentSite() && - (this.autoSave === undefined || CoreUtils.isTrueOrOne(this.autoSave)) && + this.autoSave && this.contextLevel !== undefined && this.contextInstanceId !== undefined && this.elementId !== undefined; diff --git a/src/core/features/emulator/components/capture-media/capture-media.ts b/src/core/features/emulator/components/capture-media/capture-media.ts index 9c7c5172421..c997268e47e 100644 --- a/src/core/features/emulator/components/capture-media/capture-media.ts +++ b/src/core/features/emulator/components/capture-media/capture-media.ts @@ -24,6 +24,7 @@ import { CoreError } from '@classes/errors/error'; import { CoreCaptureError } from '@classes/errors/captureerror'; import { CoreCanceledError } from '@classes/errors/cancelederror'; import { CorePath } from '@singletons/path'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Page to capture media in browser. @@ -41,7 +42,7 @@ export class CoreEmulatorCaptureMediaComponent implements OnInit, OnDestroy { @Input() mimetype?: string; @Input() extension?: string; @Input() quality?: number; // Only for images. - @Input() returnDataUrl?: boolean; // Whether it should return a data img. Only for images. + @Input({ transform: toBoolean }) returnDataUrl = false; // Whether it should return a data img. Only for images. @ViewChild('streamVideo') streamVideo?: ElementRef; @ViewChild('previewVideo') previewVideo?: ElementRef; diff --git a/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts b/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts index 886b92ae642..cdd0e8cd0b4 100644 --- a/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts +++ b/src/core/features/fileuploader/components/audio-histogram/audio-histogram.ts @@ -13,6 +13,7 @@ // limitations under the License. import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core'; @Component({ @@ -32,7 +33,7 @@ export class CoreFileUploaderAudioHistogramComponent implements AfterViewInit, O private static readonly BARS_GUTTER = 4; @Input({ required: true }) analyser!: AnalyserNode; - @Input() paused?: boolean; + @Input({ transform: toBoolean }) paused = false; @ViewChild('canvas') canvasRef?: ElementRef; private element: HTMLElement; diff --git a/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts b/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts index 0fd4d67b31c..d3542f469e7 100644 --- a/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts +++ b/src/core/features/h5p/components/h5p-iframe/h5p-iframe.ts @@ -30,6 +30,7 @@ import { CoreLogger } from '@singletons/logger'; import { CoreH5PCore, CoreH5PDisplayOptions } from '../../classes/core'; import { CoreH5PHelper } from '../../classes/helper'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to render an iframe with an H5P package. @@ -45,7 +46,7 @@ export class CoreH5PIframeComponent implements OnChanges, OnDestroy { @Input() onlinePlayerUrl?: string; // The URL of the online player to display the H5P package. @Input() trackComponent?: string; // Component to send xAPI events to. @Input() contextId?: number; // Context ID. Required for tracking. - @Input() enableInAppFullscreen?: boolean; // Whether to enable our custom in-app fullscreen feature. + @Input({ transform: toBoolean }) enableInAppFullscreen = false; // Whether to enable our custom in-app fullscreen feature. @Input() saveFreq?: number; // Save frequency (in seconds) if enabled. @Input() state?: string; // Initial content state. @Output() onIframeUrlSet = new EventEmitter<{src: string; online: boolean}>(); diff --git a/src/core/features/login/components/login-methods/login-methods.ts b/src/core/features/login/components/login-methods/login-methods.ts index b7f252a346d..88ac5a23e58 100644 --- a/src/core/features/login/components/login-methods/login-methods.ts +++ b/src/core/features/login/components/login-methods/login-methods.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, OnInit } from '@angular/core'; import { CoreSiteIdentityProvider, CoreSitePublicConfigResponse } from '@classes/sites/unauthenticated-site'; import { CoreLoginHelper, CoreLoginMethod } from '@features/login/services/login-helper'; @@ -27,7 +28,7 @@ import { CoreDomUtils } from '@services/utils/dom'; }) export class CoreLoginMethodsComponent implements OnInit { - @Input() reconnect = false; + @Input({ transform: toBoolean }) reconnect = false; @Input() siteUrl = ''; @Input() siteConfig?: CoreSitePublicConfigResponse; @Input() redirectData?: CoreRedirectPayload; diff --git a/src/core/features/mainmenu/components/user-menu-button/user-menu-button.ts b/src/core/features/mainmenu/components/user-menu-button/user-menu-button.ts index 369dfc41e00..a15b2a8e708 100644 --- a/src/core/features/mainmenu/components/user-menu-button/user-menu-button.ts +++ b/src/core/features/mainmenu/components/user-menu-button/user-menu-button.ts @@ -22,6 +22,7 @@ import { CoreSites } from '@services/sites'; import { CoreModals } from '@services/modals'; import { CoreMainMenuUserMenuTourComponent } from '../user-menu-tour/user-menu-tour'; import { CoreMainMenuPage } from '@features/mainmenu/pages/menu/menu'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display an avatar on the header to open user menu. @@ -35,7 +36,7 @@ import { CoreMainMenuPage } from '@features/mainmenu/pages/menu/menu'; }) export class CoreMainMenuUserButtonComponent implements OnInit { - @Input() alwaysShow = false; + @Input({ transform: toBoolean }) alwaysShow = false; siteInfo?: CoreSiteInfo; isMainScreen = false; userTour: CoreUserTourDirectiveOptions = { diff --git a/src/core/features/question/classes/base-question-component.ts b/src/core/features/question/classes/base-question-component.ts index 09642ba353b..78fc86068c1 100644 --- a/src/core/features/question/classes/base-question-component.ts +++ b/src/core/features/question/classes/base-question-component.ts @@ -24,6 +24,7 @@ import { CoreIonicColorNames } from '@singletons/colors'; import { CoreLogger } from '@singletons/logger'; import { CoreQuestionBehaviourButton, CoreQuestionHelper, CoreQuestionQuestion } from '../services/question-helper'; import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Base class for components to render a question. @@ -37,11 +38,11 @@ export class CoreQuestionBaseComponent(); // Will emit when a behaviour button is clicked. @Output() onAbort = new EventEmitter(); // Should emit an event if the question should be aborted. diff --git a/src/core/features/question/components/question/question.ts b/src/core/features/question/components/question/question.ts index 7932bcc1b25..7a7fbf7efb9 100644 --- a/src/core/features/question/components/question/question.ts +++ b/src/core/features/question/components/question/question.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, OnInit, EventEmitter, ChangeDetectorRef, Type, ElementRef } from '@angular/core'; import { AsyncDirective } from '@classes/async-directive'; import { CorePromisedValue } from '@classes/promised-value'; @@ -41,11 +42,11 @@ export class CoreQuestionComponent implements OnInit, AsyncDirective { @Input() componentId?: number; // ID of the component the question belongs to. @Input() attemptId?: number; // Attempt ID. @Input() usageId?: number; // Usage ID. - @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input({ transform: toBoolean }) offlineEnabled = false; // Whether the question can be answered in offline. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. - @Input() review?: boolean; // Whether the user is in review mode. + @Input({ transform: toBoolean }) review = false; // Whether the user is in review mode. @Input() preferredBehaviour?: string; // Behaviour to use. @Output() buttonClicked = new EventEmitter(); // Will emit when a behaviour button is clicked. @Output() onAbort= new EventEmitter(); // Will emit an event if the question should be aborted. @@ -78,8 +79,6 @@ export class CoreQuestionComponent implements OnInit, AsyncDirective { * @inheritdoc */ async ngOnInit(): Promise { - this.offlineEnabled = CoreUtils.isTrueOrOne(this.offlineEnabled); - if (!this.question || (this.question.type != 'random' && !CoreQuestionDelegate.isQuestionSupported(this.question.type))) { this.promisedReady.resolve(); diff --git a/src/core/features/reportbuilder/components/report-column/report-column.ts b/src/core/features/reportbuilder/components/report-column/report-column.ts index a7c55302361..42700014557 100644 --- a/src/core/features/reportbuilder/components/report-column/report-column.ts +++ b/src/core/features/reportbuilder/components/report-column/report-column.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CoreReportBuilder } from '@features/reportbuilder/services/reportbuilder'; @@ -22,9 +23,9 @@ import { CoreReportBuilder } from '@features/reportbuilder/services/reportbuilde }) export class CoreReportBuilderReportColumnComponent { - @Input() isExpanded = false; - @Input() isExpandable = false; - @Input() showFirstTitle = false; + @Input({ transform: toBoolean }) isExpanded = false; + @Input({ transform: toBoolean }) isExpandable = false; + @Input({ transform: toBoolean }) showFirstTitle = false; @Input({ required: true }) columnIndex!: number; @Input({ required: true }) rowIndex!: number; @Input({ required: true }) column!: string | number; diff --git a/src/core/features/reportbuilder/components/report-detail/report-detail.ts b/src/core/features/reportbuilder/components/report-detail/report-detail.ts index 5776d71ffd3..45073ea0599 100644 --- a/src/core/features/reportbuilder/components/report-detail/report-detail.ts +++ b/src/core/features/reportbuilder/components/report-detail/report-detail.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { CoreError } from '@classes/errors/error'; import { @@ -41,7 +42,7 @@ import { map } from 'rxjs/operators'; export class CoreReportBuilderReportDetailComponent implements OnInit { @Input({ required: true }) reportId!: string; - @Input() isBlock = true; + @Input({ transform: toBoolean }) isBlock = true; @Input() perPage?: number; @Input() layout: 'card' | 'table' | 'adaptative' = 'adaptative'; @Output() onReportLoaded = new EventEmitter(); diff --git a/src/core/features/search/components/global-search-filters/global-search-filters.component.ts b/src/core/features/search/components/global-search-filters/global-search-filters.component.ts index dbd15dc0aef..c956f216e1c 100644 --- a/src/core/features/search/components/global-search-filters/global-search-filters.component.ts +++ b/src/core/features/search/components/global-search-filters/global-search-filters.component.ts @@ -24,6 +24,7 @@ import { CoreEvents } from '@singletons/events'; import { ModalController } from '@singletons'; import { CoreUtils } from '@services/utils/utils'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; type Filter = T & { checked: boolean }; @@ -43,7 +44,7 @@ export class CoreSearchGlobalSearchFiltersComponent implements OnInit { allCourses: boolean | null = true; courses: Filter[] = []; - @Input() hideCourses?: boolean; + @Input({ transform: toBoolean }) hideCourses = false; @Input() filters?: CoreSearchGlobalSearchFilters; private newFilters: CoreSearchGlobalSearchFilters = {}; diff --git a/src/core/features/search/components/global-search-result/global-search-result.ts b/src/core/features/search/components/global-search-result/global-search-result.ts index ae02fedfb10..62a215561b6 100644 --- a/src/core/features/search/components/global-search-result/global-search-result.ts +++ b/src/core/features/search/components/global-search-result/global-search-result.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, Output, EventEmitter, OnChanges } from '@angular/core'; import { CoreSearchGlobalSearchResult, CoreSearchGlobalSearchResultContext } from '@features/search/services/global-search'; @@ -23,7 +24,7 @@ import { CoreSearchGlobalSearchResult, CoreSearchGlobalSearchResultContext } fro export class CoreSearchGlobalSearchResultComponent implements OnChanges { @Input({ required: true }) result!: CoreSearchGlobalSearchResult; - @Input() showCourse?: boolean; + @Input({ transform: toBoolean }) showCourse = true; renderedContext: CoreSearchGlobalSearchResultContext | null = null; renderedIcon: string | null = null; @@ -46,7 +47,7 @@ export class CoreSearchGlobalSearchResultComponent implements OnChanges { private computeRenderedContext(): CoreSearchGlobalSearchResultContext | null { const context = { ...this.result.context } ?? {}; - if (this.showCourse === false) { + if (!this.showCourse) { delete context.courseName; } diff --git a/src/core/features/search/components/search-box/search-box.ts b/src/core/features/search/components/search-box/search-box.ts index 1db5989c809..6494339ec90 100644 --- a/src/core/features/search/components/search-box/search-box.ts +++ b/src/core/features/search/components/search-box/search-box.ts @@ -15,11 +15,11 @@ import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreUtils } from '@services/utils/utils'; import { CoreSearchHistory } from '../../services/search-history.service'; import { Translate } from '@singletons'; import { CoreSearchHistoryDBRecord } from '../../services/search-history-db'; import { CoreForms } from '@singletons/form'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display a "search box". @@ -41,11 +41,11 @@ export class CoreSearchBoxComponent implements OnInit { @Input() searchLabel?: string; // Label to be used on action button. @Input() placeholder?: string; // Placeholder text for search text input. @Input() autocorrect = 'on'; // Enables/disable Autocorrection on search text input. - @Input() spellcheck: string | boolean = true; // Enables/disable Spellchecker on search text input. - @Input() autoFocus: string | boolean = false; // Enables/disable Autofocus when entering view. + @Input({ transform: toBoolean }) spellcheck = true; // Enables/disable Spellchecker on search text input. + @Input({ transform: toBoolean }) autoFocus = false; // Enables/disable Autofocus when entering view. @Input() lengthCheck = 3; // Check value length before submit. If 0, any string will be submitted. - @Input() showClear = true; // Show/hide clear button. - @Input() disabled = false; // Disables the input text. + @Input({ transform: toBoolean }) showClear = true; // Show/hide clear button. + @Input({ transform: toBoolean }) disabled = false; // Disables the input text. @Input() initialSearch = ''; // Initial search text. /* If provided. It will save and display a history of searches for this particular Id. @@ -72,8 +72,6 @@ export class CoreSearchBoxComponent implements OnInit { ngOnInit(): void { this.searchLabel = this.searchLabel || Translate.instant('core.search'); this.placeholder = this.placeholder || Translate.instant('core.search'); - this.spellcheck = CoreUtils.isTrueOrOne(this.spellcheck); - this.showClear = CoreUtils.isTrueOrOne(this.showClear); this.searchText = this.initialSearch; if (this.searchArea) { diff --git a/src/core/features/sharedfiles/components/list-modal/list-modal.ts b/src/core/features/sharedfiles/components/list-modal/list-modal.ts index f084b0cec5d..6138c50fd04 100644 --- a/src/core/features/sharedfiles/components/list-modal/list-modal.ts +++ b/src/core/features/sharedfiles/components/list-modal/list-modal.ts @@ -13,6 +13,7 @@ // limitations under the License. import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, OnInit, Input } from '@angular/core'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; @@ -36,10 +37,10 @@ export class CoreSharedFilesListModalComponent implements OnInit { @Input() siteId?: string; @Input() mimetypes?: string[]; - @Input() manage?: boolean; - @Input() pick?: boolean; // To pick a file you MUST use a modal. + @Input({ transform: toBoolean }) manage = false; + @Input({ transform: toBoolean }) pick = false; // To pick a file you MUST use a modal. @Input() path?: string; - @Input() hideSitePicker?: boolean; + @Input({ transform: toBoolean }) hideSitePicker = false; title?: string; diff --git a/src/core/features/sharedfiles/components/list/list.ts b/src/core/features/sharedfiles/components/list/list.ts index 221a0429548..c35c1944dca 100644 --- a/src/core/features/sharedfiles/components/list/list.ts +++ b/src/core/features/sharedfiles/components/list/list.ts @@ -21,6 +21,7 @@ import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CorePath } from '@singletons/path'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component to display the list of shared files, either as a modal or inside a page. @@ -33,11 +34,11 @@ export class CoreSharedFilesListComponent implements OnInit, OnDestroy { @Input() siteId?: string; @Input() mimetypes?: string[]; - @Input() isModal?: boolean; // Whether the component is loaded in a modal. - @Input() manage?: boolean; - @Input() pick?: boolean; // To pick a file you MUST use a modal. + @Input({ transform: toBoolean }) isModal = false; // Whether the component is loaded in a modal. + @Input({ transform: toBoolean }) manage = false; + @Input({ transform: toBoolean }) pick = false; // To pick a file you MUST use a modal. @Input() path?: string; - @Input() showSitePicker?: boolean; + @Input({ transform: toBoolean }) showSitePicker = false; @Output() onPathChanged = new EventEmitter(); @Output() onFilePicked = new EventEmitter(); diff --git a/src/core/features/siteplugins/classes/call-ws-click-directive.ts b/src/core/features/siteplugins/classes/call-ws-click-directive.ts index e09d7fe0ed5..43f4b8bd215 100644 --- a/src/core/features/siteplugins/classes/call-ws-click-directive.ts +++ b/src/core/features/siteplugins/classes/call-ws-click-directive.ts @@ -16,10 +16,10 @@ import { Input, OnInit, ElementRef, Directive } from '@angular/core'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; -import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content'; import { CoreSitePluginsCallWSBaseDirective } from './call-ws-directive'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Base class for directives to call a WS when the element is clicked. @@ -30,7 +30,7 @@ import { CoreSitePluginsCallWSBaseDirective } from './call-ws-directive'; export class CoreSitePluginsCallWSOnClickBaseDirective extends CoreSitePluginsCallWSBaseDirective implements OnInit { @Input() confirmMessage?: string; // Message to confirm the action. If not supplied, no confirmation. If empty, default message. - @Input() showError?: boolean | string; // Whether to show an error message if the WS call fails. Defaults to true. + @Input({ transform: toBoolean }) showError = true; // Whether to show an error message if the WS call fails. constructor( element: ElementRef, @@ -72,7 +72,7 @@ export class CoreSitePluginsCallWSOnClickBaseDirective extends CoreSitePluginsCa try { await super.callWS(); } catch (error) { - if (this.showError === undefined || CoreUtils.isTrueOrOne(this.showError)) { + if (this.showError) { CoreDomUtils.showErrorModalDefault( error, Translate.instant('core.serverconnection', { diff --git a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts index ce1b2e54d6e..26050d2d632 100644 --- a/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts +++ b/src/core/features/siteplugins/components/assign-feedback/assign-feedback.ts @@ -17,6 +17,7 @@ import { Component, OnInit, Input } from '@angular/core'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '@addons/mod/assign/services/assign'; import { AddonModAssignFeedbackDelegate } from '@addons/mod/assign/services/feedback-delegate'; import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/classes/compile-init-component'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays an assign feedback plugin created using a site plugin. @@ -33,8 +34,8 @@ export class CoreSitePluginsAssignFeedbackComponent extends CoreSitePluginsCompi @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input({ required: true }) userId!: number; // The user ID of the submission. @Input() configs?: Record; // The configs for the plugin. - @Input() canEdit = false; // Whether the user can edit. - @Input() edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) canEdit = false; // Whether the user can edit. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. /** * @inheritdoc diff --git a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts index a00da205455..6fdf3d7bec9 100644 --- a/src/core/features/siteplugins/components/assign-submission/assign-submission.ts +++ b/src/core/features/siteplugins/components/assign-submission/assign-submission.ts @@ -17,6 +17,7 @@ import { Component, OnInit, Input } from '@angular/core'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '@addons/mod/assign/services/assign'; import { AddonModAssignSubmissionDelegate } from '@addons/mod/assign/services/submission-delegate'; import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/classes/compile-init-component'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays an assign submission plugin created using a site plugin. @@ -32,8 +33,8 @@ export class CoreSitePluginsAssignSubmissionComponent extends CoreSitePluginsCom @Input({ required: true }) submission!: AddonModAssignSubmission; // The submission. @Input({ required: true }) plugin!: AddonModAssignPlugin; // The plugin object. @Input() configs?: Record; // The configs for the plugin. - @Input() edit = false; // Whether the user is editing. - @Input() allowOffline = false; // Whether to allow offline. + @Input({ transform: toBoolean }) edit = false; // Whether the user is editing. + @Input({ transform: toBoolean }) allowOffline = false; // Whether to allow offline. /** * @inheritdoc diff --git a/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts b/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts index 8eed777762a..382051be7b2 100644 --- a/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts +++ b/src/core/features/siteplugins/components/question-behaviour/question-behaviour.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { CoreQuestionBehaviourDelegate } from '@features/question/services/behaviour-delegate'; @@ -33,11 +34,11 @@ export class CoreSitePluginsQuestionBehaviourComponent extends CoreSitePluginsCo @Input() component?: string; // The component the question belongs to. @Input() componentId?: number; // ID of the component the question belongs to. @Input() attemptId?: number; // Attempt ID. - @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input({ transform: toBoolean }) offlineEnabled = false; // Whether the question can be answered in offline. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. - @Input() review?: boolean; // Whether the user is in review mode. + @Input({ transform: toBoolean }) review = false; // Whether the user is in review mode. @Input() preferredBehaviour?: string; // Preferred behaviour. @Output() buttonClicked = new EventEmitter(); // Will emit when a behaviour button is clicked. @Output() onAbort = new EventEmitter(); // Should emit an event if the question should be aborted. @@ -58,6 +59,8 @@ export class CoreSitePluginsQuestionBehaviourComponent extends CoreSitePluginsCo this.jsData.offlineEnabled = this.offlineEnabled; this.jsData.contextLevel = this.contextLevel; this.jsData.contextInstanceId = this.contextInstanceId; + this.jsData.courseId = this.courseId; + this.jsData.review = this.review; this.jsData.buttonClicked = this.buttonClicked; this.jsData.onAbort = this.onAbort; diff --git a/src/core/features/siteplugins/components/question/question.ts b/src/core/features/siteplugins/components/question/question.ts index 8c9bd7a39ac..686080ced83 100644 --- a/src/core/features/siteplugins/components/question/question.ts +++ b/src/core/features/siteplugins/components/question/question.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; import { AddonModQuizQuestion } from '@features/question/classes/base-question-component'; @@ -34,11 +35,11 @@ export class CoreSitePluginsQuestionComponent extends CoreSitePluginsCompileInit @Input() component?: string; // The component the question belongs to. @Input() componentId?: number; // ID of the component the question belongs to. @Input() attemptId?: number; // Attempt ID. - @Input() offlineEnabled?: boolean | string; // Whether the question can be answered in offline. + @Input({ transform: toBoolean }) offlineEnabled = false; // Whether the question can be answered in offline. @Input() contextLevel?: ContextLevel; // The context level. @Input() contextInstanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the question belongs to (if any). It can be used to improve performance with filters. - @Input() review?: boolean; // Whether the user is in review mode. + @Input({ transform: toBoolean }) review = false; // Whether the user is in review mode. @Input() preferredBehaviour?: string; // Preferred behaviour. @Output() buttonClicked = new EventEmitter(); // Will emit when a behaviour button is clicked. @Output() onAbort = new EventEmitter(); // Should emit an event if the question should be aborted. diff --git a/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts b/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts index 7c4c2a50223..a030e888c60 100644 --- a/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts +++ b/src/core/features/siteplugins/components/quiz-access-rule/quiz-access-rule.ts @@ -18,6 +18,7 @@ import { FormGroup } from '@angular/forms'; import { AddonModQuizAccessRuleDelegate } from '@addons/mod/quiz/services/access-rules-delegate'; import { AddonModQuizAttemptWSData, AddonModQuizQuizWSData } from '@addons/mod/quiz/services/quiz'; import { CoreSitePluginsCompileInitComponent } from '@features/siteplugins/classes/compile-init-component'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Component that displays a quiz access rule created using a site plugin. @@ -32,7 +33,7 @@ export class CoreSitePluginsQuizAccessRuleComponent extends CoreSitePluginsCompi @Input() rule?: string; // The name of the rule. @Input() quiz?: AddonModQuizQuizWSData; // The quiz the rule belongs to. @Input() attempt?: AddonModQuizAttemptWSData; // The attempt being started/continued. - @Input() prefetch?: boolean; // Whether the user is prefetching the quiz. + @Input({ transform: toBoolean }) prefetch = false; // Whether the user is prefetching the quiz. @Input() siteId?: string; // Site ID. @Input() form?: FormGroup; // Form where to add the form control. diff --git a/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts b/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts index f67f4802129..17a804768a7 100644 --- a/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts +++ b/src/core/features/siteplugins/components/user-profile-field/user-profile-field.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, OnInit, Input } from '@angular/core'; import { FormGroup } from '@angular/forms'; @@ -32,9 +33,9 @@ import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profi export class CoreSitePluginsUserProfileFieldComponent extends CoreSitePluginsCompileInitComponent implements OnInit { @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered. - @Input() signup = false; // True if editing the field in signup. Defaults to false. - @Input() edit = false; // True if editing the field. Defaults to false. - @Input() disabled = false; // True if disabled. Defaults to false. + @Input({ transform: toBoolean }) signup = false; // True if editing the field in signup. + @Input({ transform: toBoolean }) edit = false; // True if editing the field. + @Input({ transform: toBoolean }) disabled = false; // True if disabled. @Input() form?: FormGroup; // Form where to add the form control. Required if edit=true or signup=true. @Input() registerAuth?: string; // Register auth method. E.g. 'email'. @Input() contextLevel?: ContextLevel; // The context level. diff --git a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts index 7b89221ff1d..db0fc69495e 100644 --- a/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts +++ b/src/core/features/siteplugins/components/workshop-assessment-strategy/workshop-assessment-strategy.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { toBoolean } from '@/core/transforms/boolean'; import { AddonWorkshopAssessmentStrategyDelegate } from '@addons/mod/workshop/services/assessment-strategy-delegate'; import { AddonModWorkshopGetAssessmentFormFieldsParsedData } from '@addons/mod/workshop/services/workshop'; import { AddonModWorkshopSubmissionAssessmentWithFormData } from '@addons/mod/workshop/services/workshop-helper'; @@ -30,7 +31,7 @@ export class CoreSitePluginsWorkshopAssessmentStrategyComponent extends CoreSite @Input({ required: true }) workshopId!: number; @Input({ required: true }) assessment!: AddonModWorkshopSubmissionAssessmentWithFormData; - @Input({ required: true }) edit!: boolean; + @Input({ required: true, transform: toBoolean }) edit = false; @Input({ required: true }) selectedValues!: AddonModWorkshopGetAssessmentFormFieldsParsedData[]; @Input({ required: true }) fieldErrors!: Record; @Input({ required: true }) strategy!: string; diff --git a/src/core/features/siteplugins/directives/call-ws-new-content.ts b/src/core/features/siteplugins/directives/call-ws-new-content.ts index 729a8130aa6..7568380e492 100644 --- a/src/core/features/siteplugins/directives/call-ws-new-content.ts +++ b/src/core/features/siteplugins/directives/call-ws-new-content.ts @@ -15,12 +15,12 @@ import { Directive, Input, ElementRef, Optional } from '@angular/core'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreNavigator } from '@services/navigator'; -import { CoreUtils } from '@services/utils/utils'; import { Md5 } from 'ts-md5'; import { CoreSitePluginsCallWSOnClickBaseDirective } from '../classes/call-ws-click-directive'; import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content'; import { CoreSitePlugins } from '../services/siteplugins'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Directive to call a WS when the element is clicked and load a new content passing the WS result as args. This new content @@ -59,14 +59,14 @@ export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCal @Input() method?: string; // The method to get the new content. If not provided, use the same method as current page. @Input() args?: Record; // The params to get the new content. @Input() title?: string; // The title to display with the new content. Only if samePage=false. - @Input() samePage?: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page. + @Input({ transform: toBoolean }) samePage = false; // Whether to display the content in same page or open a new one. @Input() useOtherData?: string[] | unknown; // Whether to include other data in the args. @Input() form?: string; // ID or name to identify a form. The form data will be retrieved and sent to the WS. // JS variables to pass to the new page so they can be used in the template or JS. // If true is supplied instead of an object, all initial variables from current page will be copied. @Input() jsData?: Record | boolean; @Input() newContentPreSets?: CoreSiteWSPreSets; // The preSets for the WS call of the new content. - @Input() ptrEnabled?: boolean | string; // Whether PTR should be enabled in the new page. Defaults to true. + @Input({ transform: toBoolean }) ptrEnabled = true; // Whether PTR should be enabled in the new page. constructor( element: ElementRef, @@ -93,7 +93,7 @@ export class CoreSitePluginsCallWSNewContentDirective extends CoreSitePluginsCal jsData = this.parentContent?.data || {}; } - if (CoreUtils.isTrueOrOne(this.samePage)) { + if (this.samePage) { // Update the parent content (if it exists). this.parentContent?.updateContent(args, this.component, this.method, jsData, this.newContentPreSets); } else { diff --git a/src/core/features/siteplugins/directives/call-ws.ts b/src/core/features/siteplugins/directives/call-ws.ts index fc5bc0d3a25..8b29b4d6b0e 100644 --- a/src/core/features/siteplugins/directives/call-ws.ts +++ b/src/core/features/siteplugins/directives/call-ws.ts @@ -16,10 +16,10 @@ import { Directive, Input, ElementRef, Optional } from '@angular/core'; import { Translate } from '@singletons'; import { CoreToasts } from '@services/toasts'; -import { CoreUtils } from '@services/utils/utils'; import { CoreNavigator } from '@services/navigator'; import { CoreSitePluginsCallWSOnClickBaseDirective } from '../classes/call-ws-click-directive'; import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Directive to call a WS when the element is clicked. The action to do when the WS call is successful depends on the input data: @@ -52,8 +52,8 @@ import { CoreSitePluginsPluginContentComponent } from '../components/plugin-cont export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClickBaseDirective { @Input() successMessage?: string; // Message to show on success. If not supplied, no message. If empty, default message. - @Input() goBackOnSuccess?: boolean | string; // Whether to go back if the WS call is successful. - @Input() refreshOnSuccess?: boolean | string; // Whether to refresh the current view if the WS call is successful. + @Input({ transform: toBoolean }) goBackOnSuccess = false; // Whether to go back if the WS call is successful. + @Input({ transform: toBoolean }) refreshOnSuccess = false; // Whether to refresh the current view if the WS call is successful. constructor( element: ElementRef, @@ -66,9 +66,9 @@ export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClick * @inheritdoc */ protected async wsCallSuccess(): Promise { - if (CoreUtils.isTrueOrOne(this.goBackOnSuccess)) { + if (this.goBackOnSuccess) { await CoreNavigator.back(); - } else if (CoreUtils.isTrueOrOne(this.refreshOnSuccess) && this.parentContent) { + } else if (this.refreshOnSuccess && this.parentContent) { this.parentContent.refreshContent(true); } diff --git a/src/core/features/siteplugins/directives/new-content.ts b/src/core/features/siteplugins/directives/new-content.ts index a22d57e2c76..31d207fbbfa 100644 --- a/src/core/features/siteplugins/directives/new-content.ts +++ b/src/core/features/siteplugins/directives/new-content.ts @@ -17,10 +17,10 @@ import { Md5 } from 'ts-md5'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreNavigator } from '@services/navigator'; -import { CoreUtils } from '@services/utils/utils'; import { CoreSitePluginsPluginContentComponent } from '../components/plugin-content/plugin-content'; import { CoreSitePlugins } from '../services/siteplugins'; import { CoreForms } from '@singletons/form'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Directive to display a new site plugin content when clicked. This new content can be displayed in a new page or in the @@ -51,14 +51,14 @@ export class CoreSitePluginsNewContentDirective implements OnInit { @Input() method?: string; // The method to get the new content. If not provided, use the same method as current page. @Input() args?: Record; // The params to get the new content. @Input() title?: string; // The title to display with the new content. Only if samePage=false. - @Input() samePage?: boolean | string; // Whether to display the content in same page or open a new one. Defaults to new page. + @Input({ transform: toBoolean }) samePage = false; // Whether to display the content in same page or open a new one. @Input() useOtherData?: string[] | unknown; // Whether to include other data in the args. @Input() form?: string; // ID or name to identify a form. The form data will be retrieved and sent to the WS. // JS variables to pass to the new page so they can be used in the template or JS. // If true is supplied instead of an object, all initial variables from current page will be copied. @Input() jsData?: Record | boolean; @Input() preSets?: CoreSiteWSPreSets; // The preSets for the WS call of the new content. - @Input() ptrEnabled?: boolean | string; // Whether PTR should be enabled in the new page. Defaults to true. + @Input({ transform: toBoolean }) ptrEnabled = true; // Whether PTR should be enabled in the new page. protected element: HTMLElement; @@ -92,7 +92,7 @@ export class CoreSitePluginsNewContentDirective implements OnInit { jsData = this.parentContent?.data || {}; } - if (CoreUtils.isTrueOrOne(this.samePage)) { + if (this.samePage) { // Update the parent content (if it exists). this.parentContent?.updateContent(args, this.component, this.method, jsData, this.preSets); } else { diff --git a/src/core/features/user/classes/base-profilefield-component.ts b/src/core/features/user/classes/base-profilefield-component.ts index ae8edbfe6c1..2c48f0f2db2 100644 --- a/src/core/features/user/classes/base-profilefield-component.ts +++ b/src/core/features/user/classes/base-profilefield-component.ts @@ -13,6 +13,7 @@ // limitations under the License. import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input, OnInit } from '@angular/core'; import { FormGroup, Validators, FormControl } from '@angular/forms'; @@ -28,9 +29,9 @@ import { CoreUserProfileField } from '@features/user/services/user'; export abstract class CoreUserProfileFieldBaseComponent implements OnInit { @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered. - @Input() signup = false; // True if editing the field in signup. Defaults to false. - @Input() edit = false; // True if editing the field. Defaults to false. - @Input() disabled = false; // True if disabled. Defaults to false. + @Input({ transform: toBoolean }) signup = false; // True if editing the field in signup. + @Input({ transform: toBoolean }) edit = false; // True if editing the field. + @Input({ transform: toBoolean }) disabled = false; // True if disabled. @Input() form?: FormGroup; // Form where to add the form control. Required if edit=true or signup=true. @Input() registerAuth?: string; // Register auth method. E.g. 'email'. @Input() contextLevel?: ContextLevel; // The context level. diff --git a/src/core/features/user/components/user-profile-field/user-profile-field.ts b/src/core/features/user/components/user-profile-field/user-profile-field.ts index c3b4e82e526..9a33ee6edce 100644 --- a/src/core/features/user/components/user-profile-field/user-profile-field.ts +++ b/src/core/features/user/components/user-profile-field/user-profile-field.ts @@ -20,6 +20,7 @@ import { CoreUserProfileField } from '@features/user/services/user'; import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate'; import { CoreUtils } from '@services/utils/utils'; import { ContextLevel } from '@/core/constants'; +import { toBoolean } from '@/core/transforms/boolean'; /** * Directive to render user profile field. @@ -31,8 +32,8 @@ import { ContextLevel } from '@/core/constants'; export class CoreUserProfileFieldComponent implements OnInit { @Input() field?: AuthEmailSignupProfileField | CoreUserProfileField; // The profile field to be rendered. - @Input() signup = false; // True if editing the field in signup. Defaults to false. - @Input() edit = false; // True if editing the field. Defaults to false. + @Input({ transform: toBoolean }) signup = false; // True if editing the field in signup. + @Input({ transform: toBoolean }) edit = false; // True if editing the field. @Input() form?: FormGroup; // Form where to add the form control. Required if edit=true or signup=true. @Input() registerAuth?: string; // Register auth method. E.g. 'email'. @Input() contextLevel?: ContextLevel; // The context level. @@ -57,13 +58,13 @@ export class CoreUserProfileFieldComponent implements OnInit { } this.data.field = this.field; - this.data.edit = CoreUtils.isTrueOrOne(this.edit); + this.data.edit = this.edit; this.data.contextLevel = this.contextLevel; this.data.contextInstanceId = this.contextInstanceId; this.data.courseId = this.courseId; if (this.edit) { - this.data.signup = CoreUtils.isTrueOrOne(this.signup); + this.data.signup = this.signup; this.data.disabled = 'locked' in this.field && CoreUtils.isTrueOrOne(this.field.locked); this.data.form = this.form; this.data.registerAuth = this.registerAuth; diff --git a/src/core/features/viewer/components/text/text.ts b/src/core/features/viewer/components/text/text.ts index 37029e7ba15..a7ea45cda43 100644 --- a/src/core/features/viewer/components/text/text.ts +++ b/src/core/features/viewer/components/text/text.ts @@ -14,6 +14,7 @@ import { ContextLevel } from '@/core/constants'; import { CoreSharedModule } from '@/core/shared.module'; +import { toBoolean } from '@/core/transforms/boolean'; import { Component, Input } from '@angular/core'; import { CoreFileEntry } from '@services/file-helper'; @@ -39,11 +40,11 @@ export class CoreViewerTextComponent { @Input() component?: string; // Component to use in format-text. @Input() componentId?: string | number; // Component ID to use in format-text. @Input() files?: CoreFileEntry[]; // List of files. - @Input() filter?: boolean; // Whether to filter the text. + @Input({ transform: toBoolean }) filter?: boolean; // Whether to filter the text. @Input() contextLevel?: ContextLevel; // The context level. @Input() instanceId?: number; // The instance ID related to the context. @Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters. - @Input() displayCopyButton?: boolean; // Whether to display a button to copy the contents. + @Input({ transform: toBoolean }) displayCopyButton = false; // Whether to display a button to copy the contents. /** * Close modal. diff --git a/src/core/transforms/boolean.ts b/src/core/transforms/boolean.ts new file mode 100644 index 00000000000..88fc7b96198 --- /dev/null +++ b/src/core/transforms/boolean.ts @@ -0,0 +1,34 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * Transform an Input value to a boolean. + * False values are: 0, '0', 'false', false, undefined, null. + * Please notice that empty strings are considered true for consistency with HTML. + * + * @param value Value to transform. + * @returns Transformed value. + */ +export function toBoolean(value: unknown): boolean { + if (value === undefined || value === null) { + return false; + } + + if (value === '') { + // Empty string is considered true for consistency with HTML, where putting an attribute without value means true. + return true; + } + + return !(value === false || value === 'false' || Number(value) === 0); +} From c4748c5238027f8b8219b386c2f315c2e4372715 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 20 Jun 2024 16:53:34 +0200 Subject: [PATCH 3/5] MOBILE-4612 core: Remove deprecated values yes/no for auto login --- .../badges/pages/issued-badge/issued-badge.html | 14 +++++++------- src/addons/calendar/pages/event/event.html | 2 +- src/core/components/sites-list/sites-list.html | 2 +- .../login/pages/email-signup/email-signup.html | 2 +- .../mainmenu/components/user-menu/user-menu.html | 4 ++-- src/core/features/settings/pages/about/about.html | 8 ++++---- .../settings/pages/deviceinfo/deviceinfo.html | 4 ++-- .../features/settings/pages/licenses/licenses.html | 12 ++++++------ src/core/features/user/pages/about/about.html | 6 +++--- src/core/features/viewer/pages/iframe/iframe.ts | 5 +---- 10 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/addons/badges/pages/issued-badge/issued-badge.html b/src/addons/badges/pages/issued-badge/issued-badge.html index 5f06dc1d613..9686be66d7e 100644 --- a/src/addons/badges/pages/issued-badge/issued-badge.html +++ b/src/addons/badges/pages/issued-badge/issued-badge.html @@ -49,7 +49,7 @@

{{ 'addon.badges.issuerdetails' | translate}}

{{ 'addon.badges.contact' | translate}}

-

+

{{ badge.issuercontact }}

@@ -95,7 +95,7 @@

{{ 'addon.badges.badgedetails' | translate}}

{{ 'addon.badges.imageauthoremail' | translate}}

-

+

{{ badge.imageauthoremail }}

@@ -103,7 +103,7 @@

{{ 'addon.badges.badgedetails' | translate}}

{{ 'addon.badges.imageauthorurl' | translate}}

-

{{ badge.imageauthorurl }}

+

{{ badge.imageauthorurl }}

@@ -166,7 +166,7 @@

{{ 'addon.badges.bendorsement' | translate}}

{{ 'addon.badges.issueremail' | translate}}

- + {{ badge.endorsement.issueremail }}

@@ -175,7 +175,7 @@

{{ 'addon.badges.bendorsement' | translate}}

{{ 'addon.badges.issuerurl' | translate}}

-

{{ badge.endorsement.issuerurl }}

+

{{ badge.endorsement.issuerurl }}

@@ -187,7 +187,7 @@

{{ 'addon.badges.bendorsement' | translate}}

{{ 'addon.badges.claimid' | translate}}

-

{{ badge.endorsement.claimid }}

+

{{ badge.endorsement.claimid }}

@@ -225,7 +225,7 @@

{{ 'addon.badges.alignment' | translate}}

+ [autoLogin]="false">

{{ alignment.targetname }}

diff --git a/src/addons/calendar/pages/event/event.html b/src/addons/calendar/pages/event/event.html index 6f21e79ef02..b7f1ff8e427 100644 --- a/src/addons/calendar/pages/event/event.html +++ b/src/addons/calendar/pages/event/event.html @@ -104,7 +104,7 @@

{{ 'core.location' | translate}}

- + diff --git a/src/core/components/sites-list/sites-list.html b/src/core/components/sites-list/sites-list.html index 429820659d8..890c487643b 100644 --- a/src/core/components/sites-list/sites-list.html +++ b/src/core/components/sites-list/sites-list.html @@ -27,7 +27,7 @@

- + {{ site.siteUrlWithoutProtocol }}

diff --git a/src/core/features/login/pages/email-signup/email-signup.html b/src/core/features/login/pages/email-signup/email-signup.html index 51c27f8597f..ff8eb087e6e 100644 --- a/src/core/features/login/pages/email-signup/email-signup.html +++ b/src/core/features/login/pages/email-signup/email-signup.html @@ -27,7 +27,7 @@

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

{{ 'core.login.signuprequiredfieldnotsupported' | translate }}
- + {{ 'core.openinbrowser' | translate }} diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.html b/src/core/features/mainmenu/components/user-menu/user-menu.html index 6dc40ca15f6..7063eba8e20 100644 --- a/src/core/features/mainmenu/components/user-menu/user-menu.html +++ b/src/core/features/mainmenu/components/user-menu/user-menu.html @@ -17,7 +17,7 @@

+ [href]="siteUrl" core-link>

- {{ siteUrl }} + {{ siteUrl }}
diff --git a/src/core/features/settings/pages/about/about.html b/src/core/features/settings/pages/about/about.html index ce17902b339..83002f36721 100644 --- a/src/core/features/settings/pages/about/about.html +++ b/src/core/features/settings/pages/about/about.html @@ -17,12 +17,12 @@