diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index f44b2ae89..538b5de28 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -69,7 +69,7 @@ jobs: cat circular-dependencies lines=$(cat circular-dependencies | wc -l) echo "Total circular dependencies: $lines" - test $lines -eq 135 + test $lines -eq 129 - name: JavaScript code compatibility run: | npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn" diff --git a/src/addons/calendar/components/components.module.ts b/src/addons/calendar/components/components.module.ts index fffd48aa8..aa476bee7 100644 --- a/src/addons/calendar/components/components.module.ts +++ b/src/addons/calendar/components/components.module.ts @@ -18,13 +18,11 @@ import { CoreSharedModule } from '@/core/shared.module'; import { AddonCalendarCalendarComponent } from './calendar/calendar'; import { AddonCalendarUpcomingEventsComponent } from './upcoming-events/upcoming-events'; -import { AddonCalendarFilterComponent } from './filter/filter'; @NgModule({ declarations: [ AddonCalendarCalendarComponent, AddonCalendarUpcomingEventsComponent, - AddonCalendarFilterComponent, ], imports: [ CoreSharedModule, @@ -32,7 +30,6 @@ import { AddonCalendarFilterComponent } from './filter/filter'; exports: [ AddonCalendarCalendarComponent, AddonCalendarUpcomingEventsComponent, - AddonCalendarFilterComponent, ], }) export class AddonCalendarComponentsModule {} diff --git a/src/addons/calendar/components/filter/filter.ts b/src/addons/calendar/components/filter/filter.ts index 8c1330e68..94db1a1ca 100644 --- a/src/addons/calendar/components/filter/filter.ts +++ b/src/addons/calendar/components/filter/filter.ts @@ -20,6 +20,7 @@ import { CoreEvents } from '@singletons/events'; import { AddonCalendarEventType, AddonCalendarProvider } from '../../services/calendar'; import { AddonCalendarFilter, AddonCalendarEventIcons } from '../../services/calendar-helper'; import { ALL_COURSES_ID } from '@features/courses/services/courses-helper'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Component to display the events filter that includes events types and a list of courses. @@ -28,6 +29,10 @@ import { ALL_COURSES_ID } from '@features/courses/services/courses-helper'; selector: 'addon-calendar-filter', templateUrl: 'filter.html', styleUrls: ['../../calendar-common.scss', 'filter.scss'], + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonCalendarFilterComponent implements OnInit { diff --git a/src/addons/calendar/pages/day/day.ts b/src/addons/calendar/pages/day/day.ts index 1edf50164..16faee918 100644 --- a/src/addons/calendar/pages/day/day.ts +++ b/src/addons/calendar/pages/day/day.ts @@ -30,7 +30,6 @@ import { AddonCalendarFilter, AddonCalendarHelper } from '../../services/calenda import { AddonCalendarSync, AddonCalendarSyncProvider } from '../../services/calendar-sync'; import { CoreCategoryData, CoreCourses, CoreEnrolledCourseData } from '@features/courses/services/courses'; import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; -import { AddonCalendarFilterComponent } from '../../components/filter/filter'; import moment from 'moment-timezone'; import { NgZone, Translate } from '@singletons'; import { CoreNavigator } from '@services/navigator'; @@ -49,6 +48,7 @@ import { AddonCalendarEventsSource } from '@addons/calendar/classes/events-sourc import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreUrl } from '@singletons/url'; import { CoreTime } from '@singletons/time'; +import { CoreModals } from '@services/modals'; /** * Page that displays the calendar events for a certain day. @@ -375,7 +375,9 @@ export class AddonCalendarDayPage implements OnInit, OnDestroy { * Show the filter menu. */ async openFilter(): Promise { - await CoreDomUtils.openSideModal({ + const { AddonCalendarFilterComponent } = await import('../../components/filter/filter'); + + await CoreModals.openSideModal({ component: AddonCalendarFilterComponent, componentProps: { courses: this.manager?.getSource().courses, diff --git a/src/addons/calendar/pages/event/event.ts b/src/addons/calendar/pages/event/event.ts index 490aec001..39924a448 100644 --- a/src/addons/calendar/pages/event/event.ts +++ b/src/addons/calendar/pages/event/event.ts @@ -24,7 +24,7 @@ import { AddonCalendarOffline } from '../../services/calendar-offline'; import { AddonCalendarSync, AddonCalendarSyncEvents, AddonCalendarSyncProvider } from '../../services/calendar-sync'; import { CoreNetwork } from '@services/network'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; import { CoreSites } from '@services/sites'; import { CoreCourse } from '@features/course/services/course'; @@ -43,6 +43,7 @@ import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/compo import { CoreLocalNotifications } from '@services/local-notifications'; import { CorePlatform } from '@services/platform'; import { CoreConfig } from '@services/config'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Page that displays a single calendar event. @@ -556,7 +557,11 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy { } if (onlineEventDeleted || this.event.id < 0) { - CoreDomUtils.showToast('addon.calendar.eventcalendareventdeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'addon.calendar.eventcalendareventdeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); // Event deleted, close the view. CoreNavigator.back(); @@ -611,7 +616,11 @@ export class AddonCalendarEventPage implements OnInit, OnDestroy { } if (data.deleted && data.deleted.indexOf(this.eventId) != -1) { - CoreDomUtils.showToast('addon.calendar.eventcalendareventdeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'addon.calendar.eventcalendareventdeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); // Event was deleted, close the view. CoreNavigator.back(); diff --git a/src/addons/calendar/pages/index/index.ts b/src/addons/calendar/pages/index/index.ts index 0943286ae..7ee837bf6 100644 --- a/src/addons/calendar/pages/index/index.ts +++ b/src/addons/calendar/pages/index/index.ts @@ -28,10 +28,10 @@ import { CoreEnrolledCourseData } from '@features/courses/services/courses'; import { ActivatedRoute, Params } from '@angular/router'; import { AddonCalendarCalendarComponent } from '../../components/calendar/calendar'; import { AddonCalendarUpcomingEventsComponent } from '../../components/upcoming-events/upcoming-events'; -import { AddonCalendarFilterComponent } from '../../components/filter/filter'; import { CoreNavigator } from '@services/navigator'; import { CoreConstants } from '@/core/constants'; import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager'; +import { CoreModals } from '@services/modals'; /** * Page that displays the calendar events. @@ -330,7 +330,9 @@ export class AddonCalendarIndexPage implements OnInit, OnDestroy { * Show the filter menu. */ async openFilter(): Promise { - await CoreDomUtils.openSideModal({ + const { AddonCalendarFilterComponent } = await import('../../components/filter/filter'); + + await CoreModals.openSideModal({ component: AddonCalendarFilterComponent, componentProps: { courses: this.courses, diff --git a/src/addons/enrol/guest/services/enrol-handler.ts b/src/addons/enrol/guest/services/enrol-handler.ts index 00c2a1313..cb5795dfb 100644 --- a/src/addons/enrol/guest/services/enrol-handler.ts +++ b/src/addons/enrol/guest/services/enrol-handler.ts @@ -25,6 +25,7 @@ import { CorePasswordModalResponse } from '@components/password-modal/password-m import { CoreDomUtils } from '@services/utils/dom'; import { CoreWSError } from '@classes/errors/wserror'; import { CoreEnrol, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol'; +import { CoreModals } from '@services/modals'; /** * Enrol handler. @@ -118,7 +119,7 @@ export class AddonEnrolGuestHandlerService implements CoreEnrolGuestHandler { }; try { - const response = await CoreDomUtils.promptPassword({ + const response = await CoreModals.promptPassword({ title: method.name, validator: validatePassword, }); diff --git a/src/addons/enrol/self/services/enrol-handler.ts b/src/addons/enrol/self/services/enrol-handler.ts index 5cc0589f0..c2838f53d 100644 --- a/src/addons/enrol/self/services/enrol-handler.ts +++ b/src/addons/enrol/self/services/enrol-handler.ts @@ -20,6 +20,7 @@ import { CorePasswordModalResponse } from '@components/password-modal/password-m import { CoreCoursesProvider } from '@features/courses/services/courses'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreEnrol, CoreEnrolEnrolmentMethod } from '@features/enrol/services/enrol'; +import { CoreModals } from '@services/modals'; /** * Enrol handler. @@ -145,7 +146,7 @@ export class AddonEnrolSelfHandlerService implements CoreEnrolSelfHandler { if (!response.validated) { try { - const response = await CoreDomUtils.promptPassword({ + const response = await CoreModals.promptPassword({ validator: validatePassword, title: method.name, placeholder: 'addon.enrol_self.password', diff --git a/src/addons/messages/pages/discussion/discussion.ts b/src/addons/messages/pages/discussion/discussion.ts index 78df7f2e3..19b55f398 100644 --- a/src/addons/messages/pages/discussion/discussion.ts +++ b/src/addons/messages/pages/discussion/discussion.ts @@ -47,6 +47,7 @@ import { CoreDom } from '@singletons/dom'; import { CoreKeyboard } from '@singletons/keyboard'; import { CoreText } from '@singletons/text'; import { CoreWait } from '@singletons/wait'; +import { CoreModals } from '@services/modals'; /** * Page that displays a message discussion page. @@ -1250,7 +1251,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView await import('@addons/messages/components/conversation-info/conversation-info.module'); // Display the group information. - const userId = await CoreDomUtils.openSideModal({ + const userId = await CoreModals.openSideModal({ component: AddonMessagesConversationInfoComponent, componentProps: { conversationId: this.conversationId, 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 8af588332..31713b758 100644 --- a/src/addons/mod/assign/classes/base-feedback-plugin-component.ts +++ b/src/addons/mod/assign/classes/base-feedback-plugin-component.ts @@ -15,7 +15,7 @@ import { Component, Input } from '@angular/core'; import { CoreCanceledError } from '@classes/errors/cancelederror'; import { CoreError } from '@classes/errors/error'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { AddonModAssignFeedbackCommentsTextData } from '../feedback/comments/services/handler'; import { AddonModAssignAssign, AddonModAssignPlugin, AddonModAssignSubmission } from '../services/assign'; @@ -49,7 +49,7 @@ export class AddonModAssignFeedbackPluginBaseComponent implements IAddonModAssig await import('@addons/mod/assign/components/edit-feedback-modal/edit-feedback-modal'); // Create the navigation modal. - const modalData = await CoreDomUtils.openModal({ + const modalData = await CoreModals.openModal({ component: AddonModAssignEditFeedbackModalComponent, componentProps: { assign: this.assign, diff --git a/src/addons/mod/assign/pages/edit/edit.ts b/src/addons/mod/assign/pages/edit/edit.ts index e421deaf0..836927079 100644 --- a/src/addons/mod/assign/pages/edit/edit.ts +++ b/src/addons/mod/assign/pages/edit/edit.ts @@ -20,7 +20,7 @@ import { CanLeave } from '@guards/can-leave'; import { CoreNavigator } from '@services/navigator'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSync } from '@services/sync'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreFormFields, CoreForms } from '@singletons/form'; import { Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; @@ -45,6 +45,7 @@ import { ADDON_MOD_ASSIGN_SUBMISSION_SAVED_EVENT, ADDON_MOD_ASSIGN_SUBMITTED_FOR_GRADING_EVENT, } from '../../constants'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Page that allows adding or editing an assigment submission. @@ -488,7 +489,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy, CanLeave { * Function called when the time is up. */ async timeUp(): Promise { - this.timeUpToast = await CoreDomUtils.showToastWithOptions({ + this.timeUpToast = await CoreToasts.show({ message: Translate.instant('addon.mod_assign.caneditsubmission'), duration: ToastDuration.STICKY, buttons: [Translate.instant('core.dismiss')], diff --git a/src/addons/mod/bigbluebuttonbn/components/components.module.ts b/src/addons/mod/bigbluebuttonbn/components/components.module.ts index d786b230c..db3d5cf55 100644 --- a/src/addons/mod/bigbluebuttonbn/components/components.module.ts +++ b/src/addons/mod/bigbluebuttonbn/components/components.module.ts @@ -25,8 +25,6 @@ import { CoreCourseComponentsModule } from '@features/course/components/componen CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModBBBIndexComponent, ], diff --git a/src/addons/mod/book/components/components.module.ts b/src/addons/mod/book/components/components.module.ts index d31d09782..c3f80c2b4 100644 --- a/src/addons/mod/book/components/components.module.ts +++ b/src/addons/mod/book/components/components.module.ts @@ -18,12 +18,10 @@ import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; import { AddonModBookIndexComponent } from './index/index'; -import { AddonModBookTocComponent } from './toc/toc'; @NgModule({ declarations: [ AddonModBookIndexComponent, - AddonModBookTocComponent, ], imports: [ CoreSharedModule, @@ -31,7 +29,6 @@ import { AddonModBookTocComponent } from './toc/toc'; ], exports: [ AddonModBookIndexComponent, - AddonModBookTocComponent, ], }) export class AddonModBookComponentsModule {} diff --git a/src/addons/mod/book/components/toc/toc.ts b/src/addons/mod/book/components/toc/toc.ts index f59ccdf2f..8aa4cf2ad 100644 --- a/src/addons/mod/book/components/toc/toc.ts +++ b/src/addons/mod/book/components/toc/toc.ts @@ -16,6 +16,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { ModalController } from '@singletons'; import { AddonModBookTocChapter, AddonModBookBookWSData } from '../../services/book'; import { AddonModBookNumbering } from '../../constants'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal to display the TOC of a book. @@ -23,7 +24,11 @@ import { AddonModBookNumbering } from '../../constants'; @Component({ selector: 'addon-mod-book-toc', templateUrl: 'toc.html', - styleUrls: ['toc.scss'], + styleUrl: 'toc.scss', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModBookTocComponent implements OnInit { diff --git a/src/addons/mod/book/pages/contents/contents.ts b/src/addons/mod/book/pages/contents/contents.ts index 77b1f47ac..39b975103 100644 --- a/src/addons/mod/book/pages/contents/contents.ts +++ b/src/addons/mod/book/pages/contents/contents.ts @@ -30,7 +30,6 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; -import { AddonModBookTocComponent } from '../../components/toc/toc'; import { AddonModBook, AddonModBookBookWSData, @@ -40,6 +39,7 @@ import { import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreUrl } from '@singletons/url'; import { ADDON_MOD_BOOK_COMPONENT, AddonModBookNavStyle } from '../../constants'; +import { CoreModals } from '@services/modals'; /** * Page that displays a book contents. @@ -250,7 +250,9 @@ export class AddonModBookContentsPage implements OnInit, OnDestroy { // Create the toc modal. const visibleChapter = this.manager?.getSelectedItem(); - const modalData = await CoreDomUtils.openSideModal({ + const { AddonModBookTocComponent } = await import('../../components/toc/toc'); + + const modalData = await CoreModals.openSideModal({ component: AddonModBookTocComponent, componentProps: { moduleId: this.cmId, diff --git a/src/addons/mod/chat/components/components.module.ts b/src/addons/mod/chat/components/components.module.ts index c0bdb4ad4..4f5182ce3 100644 --- a/src/addons/mod/chat/components/components.module.ts +++ b/src/addons/mod/chat/components/components.module.ts @@ -16,12 +16,10 @@ import { NgModule } from '@angular/core'; import { AddonModChatIndexComponent } from './index/index'; import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; -import { AddonModChatUsersModalComponent } from './users-modal/users-modal'; @NgModule({ declarations: [ AddonModChatIndexComponent, - AddonModChatUsersModalComponent, ], imports: [ CoreSharedModule, @@ -29,7 +27,6 @@ import { AddonModChatUsersModalComponent } from './users-modal/users-modal'; ], exports: [ AddonModChatIndexComponent, - AddonModChatUsersModalComponent, ], }) export class AddonModChatComponentsModule {} 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 3a8e0b435..1ebd510e7 100644 --- a/src/addons/mod/chat/components/users-modal/users-modal.ts +++ b/src/addons/mod/chat/components/users-modal/users-modal.ts @@ -11,7 +11,6 @@ // 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. - import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { CoreNetwork } from '@services/network'; import { CoreSites } from '@services/sites'; @@ -19,6 +18,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { ModalController, NgZone } from '@singletons'; import { Subscription } from 'rxjs'; import { AddonModChat, AddonModChatUser } from '../../services/chat'; +import { CoreSharedModule } from '@/core/shared.module'; /** * MMdal that displays the chat session users. @@ -26,6 +26,10 @@ import { AddonModChat, AddonModChatUser } from '../../services/chat'; @Component({ selector: 'addon-mod-chat-users-modal', templateUrl: 'users-modal.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModChatUsersModalComponent implements OnInit, OnDestroy { diff --git a/src/addons/mod/chat/pages/chat/chat.ts b/src/addons/mod/chat/pages/chat/chat.ts index f1d770852..4565e5c72 100644 --- a/src/addons/mod/chat/pages/chat/chat.ts +++ b/src/addons/mod/chat/pages/chat/chat.ts @@ -24,13 +24,14 @@ import { CoreUtils } from '@services/utils/utils'; import { NgZone, Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { Subscription } from 'rxjs'; -import { AddonModChatUsersModalComponent, AddonModChatUsersModalResult } from '../../components/users-modal/users-modal'; +import { AddonModChatUsersModalResult } from '../../components/users-modal/users-modal'; import { AddonModChat, AddonModChatUser } from '../../services/chat'; import { AddonModChatFormattedMessage, AddonModChatHelper } from '../../services/chat-helper'; import { CoreTime } from '@singletons/time'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreKeyboard } from '@singletons/keyboard'; import { CoreWait } from '@singletons/wait'; +import { CoreModals } from '@services/modals'; /** * Page that displays a chat session. @@ -186,8 +187,10 @@ export class AddonModChatChatPage implements OnInit, OnDestroy, CanLeave { * Display the chat users modal. */ async showChatUsers(): Promise { + const { AddonModChatUsersModalComponent } = await import('../../components/users-modal/users-modal'); + // Create the toc modal. - const modalData = await CoreDomUtils.openSideModal({ + const modalData = await CoreModals.openSideModal({ component: AddonModChatUsersModalComponent, componentProps: { sessionId: this.sessionId, diff --git a/src/addons/mod/choice/components/components.module.ts b/src/addons/mod/choice/components/components.module.ts index 9a1aeb7fe..bef917cc3 100644 --- a/src/addons/mod/choice/components/components.module.ts +++ b/src/addons/mod/choice/components/components.module.ts @@ -25,8 +25,6 @@ import { AddonModChoiceIndexComponent } from './index/index'; CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModChoiceIndexComponent, ], diff --git a/src/addons/mod/data/components/index/index.ts b/src/addons/mod/data/components/index/index.ts index c8c029718..94264157d 100644 --- a/src/addons/mod/data/components/index/index.ts +++ b/src/addons/mod/data/components/index/index.ts @@ -51,6 +51,7 @@ import { AddonModDataTemplateType, AddonModDataTemplateMode, } from '../../constants'; +import { CoreModals } from '@services/modals'; const contentToken = ''; @@ -401,7 +402,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp async showSearch(): Promise { const { AddonModDataSearchModalComponent } = await import('@addons/mod/data/components/search-modal/search-modal'); - const modalData = await CoreDomUtils.openModal({ + const modalData = await CoreModals.openModal({ component: AddonModDataSearchModalComponent, componentProps: { search: this.search, diff --git a/src/addons/mod/data/services/data-helper.ts b/src/addons/mod/data/services/data-helper.ts index ee443d507..faaeeb5f9 100644 --- a/src/addons/mod/data/services/data-helper.ts +++ b/src/addons/mod/data/services/data-helper.ts @@ -19,7 +19,7 @@ import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fi import { CoreRatingOffline } from '@features/rating/services/rating-offline'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreFormFields } from '@singletons/form'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; @@ -47,6 +47,7 @@ import { AddonModDataTemplateType, AddonModDataTemplateMode, } from '../constants'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Service that provides helper functions for datas. @@ -176,11 +177,11 @@ export class AddonModDataHelperProvider { CoreEvents.trigger(ADDON_MOD_DATA_ENTRY_CHANGED, { dataId: dataId, entryId: entryId }, siteId); - CoreDomUtils.showToast( - approve ? 'addon.mod_data.recordapproved' : 'addon.mod_data.recorddisapproved', - true, - ToastDuration.LONG, - ); + CoreToasts.show({ + message: approve ? 'addon.mod_data.recordapproved' : 'addon.mod_data.recorddisapproved', + translateMessage: true, + duration: ToastDuration.LONG, + }); } catch { // Ignore error, it was already displayed. } finally { @@ -883,7 +884,11 @@ export class AddonModDataHelperProvider { CoreEvents.trigger(ADDON_MOD_DATA_ENTRY_CHANGED, { dataId, entryId, deleted: true }, siteId); - CoreDomUtils.showToast('addon.mod_data.recorddeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'addon.mod_data.recorddeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); modal.dismiss(); } catch { diff --git a/src/addons/mod/feedback/components/components.module.ts b/src/addons/mod/feedback/components/components.module.ts index ce2b48392..4db944b52 100644 --- a/src/addons/mod/feedback/components/components.module.ts +++ b/src/addons/mod/feedback/components/components.module.ts @@ -25,8 +25,6 @@ import { AddonModFeedbackIndexComponent } from './index/index'; CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModFeedbackIndexComponent, ], 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 77dfa2971..0eb646d2d 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 @@ -19,6 +19,7 @@ import { PopoverController } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { AddonModForum, AddonModForumDiscussion } from '../../services/forum'; import { ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT } from '../../constants'; +import { CoreToasts } from '@services/toasts'; /** * This component is meant to display a popover with the discussion options. @@ -74,7 +75,10 @@ export class AddonModForumDiscussionOptionsMenuComponent implements OnInit { CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); PopoverController.dismiss({ action: 'lock', value: locked }); - CoreDomUtils.showToast('addon.mod_forum.lockupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.lockupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); PopoverController.dismiss(); @@ -103,7 +107,10 @@ export class AddonModForumDiscussionOptionsMenuComponent implements OnInit { CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); PopoverController.dismiss({ action: 'pin', value: pinned }); - CoreDomUtils.showToast('addon.mod_forum.pinupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.pinupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); PopoverController.dismiss(); @@ -132,7 +139,10 @@ export class AddonModForumDiscussionOptionsMenuComponent implements OnInit { CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); PopoverController.dismiss({ action: 'star', value: starred }); - CoreDomUtils.showToast('addon.mod_forum.favouriteupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.favouriteupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); PopoverController.dismiss(); diff --git a/src/addons/mod/forum/components/index/index.ts b/src/addons/mod/forum/components/index/index.ts index 7746222cd..c7b7f4035 100644 --- a/src/addons/mod/forum/components/index/index.ts +++ b/src/addons/mod/forum/components/index/index.ts @@ -65,6 +65,7 @@ import { ADDON_MOD_FORUM_SEARCH_PAGE_NAME, } from '@addons/mod/forum/constants'; import { CoreSearchGlobalSearch } from '@features/search/services/global-search'; +import { CoreToasts } from '@services/toasts'; /** * Component that displays a forum entry page. */ @@ -554,7 +555,10 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom try { if (isNewDiscussion) { - CoreDomUtils.showToast('addon.mod_forum.postaddedsuccess', true); + CoreToasts.show({ + message: 'addon.mod_forum.postaddedsuccess', + translateMessage: true, + }); const newDiscGroupId = (data as AddonModForumNewDiscussionData).groupId; diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 49f7b0db0..759782675 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -53,6 +53,7 @@ import { AddonModForumSharedPostFormData } from '../../pages/discussion/discussi 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'; /** * Components that shows a discussion post, its attachments and the action buttons allowed (reply, etc.). @@ -167,7 +168,10 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges CoreSites.getCurrentSiteId(), ); - CoreDomUtils.showToast('addon.mod_forum.deletedpost', true); + CoreToasts.show({ + message: 'addon.mod_forum.deletedpost', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); } finally { diff --git a/src/addons/mod/forum/pages/discussion/discussion.ts b/src/addons/mod/forum/pages/discussion/discussion.ts index 522ec6a07..ea1d5b137 100644 --- a/src/addons/mod/forum/pages/discussion/discussion.ts +++ b/src/addons/mod/forum/pages/discussion/discussion.ts @@ -59,6 +59,7 @@ import { ADDON_MOD_FORUM_REPLY_DISCUSSION_EVENT, } from '../../constants'; import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; +import { CoreToasts } from '@services/toasts'; type SortType = 'flat-newest' | 'flat-oldest' | 'nested'; @@ -730,7 +731,10 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes }; CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); - CoreDomUtils.showToast('addon.mod_forum.lockupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.lockupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); } finally { @@ -763,7 +767,10 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes }; CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); - CoreDomUtils.showToast('addon.mod_forum.pinupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.pinupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); } finally { @@ -796,7 +803,10 @@ export class AddonModForumDiscussionPage implements OnInit, AfterViewInit, OnDes }; CoreEvents.trigger(ADDON_MOD_FORUM_CHANGE_DISCUSSION_EVENT, data, CoreSites.getCurrentSiteId()); - CoreDomUtils.showToast('addon.mod_forum.favouriteupdated', true); + CoreToasts.show({ + message: 'addon.mod_forum.favouriteupdated', + translateMessage: true, + }); } catch (error) { CoreDomUtils.showErrorModal(error); } finally { diff --git a/src/addons/mod/glossary/components/components.module.ts b/src/addons/mod/glossary/components/components.module.ts index b35fa3942..f425cfff7 100644 --- a/src/addons/mod/glossary/components/components.module.ts +++ b/src/addons/mod/glossary/components/components.module.ts @@ -29,8 +29,6 @@ import { CoreSearchComponentsModule } from '@features/search/components/componen CoreCourseComponentsModule, CoreSearchComponentsModule, ], - providers: [ - ], exports: [ AddonModGlossaryIndexComponent, AddonModGlossaryModePickerPopoverComponent, diff --git a/src/addons/mod/glossary/pages/entry/entry.ts b/src/addons/mod/glossary/pages/entry/entry.ts index 7b55531ff..19e5637ce 100644 --- a/src/addons/mod/glossary/pages/entry/entry.ts +++ b/src/addons/mod/glossary/pages/entry/entry.ts @@ -26,7 +26,7 @@ import { CoreTag } from '@features/tag/services/tag'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { CoreNavigator } from '@services/navigator'; import { CoreNetwork } from '@services/network'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; @@ -40,6 +40,7 @@ import { CoreTime } from '@singletons/time'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { ADDON_MOD_GLOSSARY_COMPONENT, ADDON_MOD_GLOSSARY_ENTRY_UPDATED, ADDON_MOD_GLOSSARY_PAGE_NAME } from '../../constants'; import { CoreCourseContentsPage } from '@features/course/pages/contents/contents'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Page that displays a glossary entry. @@ -214,7 +215,11 @@ export class AddonModGlossaryEntryPage implements OnInit, OnDestroy { await AddonModGlossaryHelper.deleteStoredFiles(glossaryId, concept, timecreated); } - CoreDomUtils.showToast('addon.mod_glossary.entrydeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'addon.mod_glossary.entrydeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); await this.goBack(); } catch (error) { diff --git a/src/addons/mod/h5pactivity/components/components.module.ts b/src/addons/mod/h5pactivity/components/components.module.ts index f0dc5a0ca..4147400cc 100644 --- a/src/addons/mod/h5pactivity/components/components.module.ts +++ b/src/addons/mod/h5pactivity/components/components.module.ts @@ -28,8 +28,6 @@ import { CoreH5PComponentsModule } from '@features/h5p/components/components.mod CoreCourseComponentsModule, CoreH5PComponentsModule, ], - providers: [ - ], exports: [ AddonModH5PActivityIndexComponent, ], diff --git a/src/addons/mod/imscp/components/components.module.ts b/src/addons/mod/imscp/components/components.module.ts index afd155ba6..de14a9f5a 100644 --- a/src/addons/mod/imscp/components/components.module.ts +++ b/src/addons/mod/imscp/components/components.module.ts @@ -18,12 +18,10 @@ import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; import { AddonModImscpIndexComponent } from './index'; -import { AddonModImscpTocComponent } from './toc/toc'; @NgModule({ declarations: [ AddonModImscpIndexComponent, - AddonModImscpTocComponent, ], imports: [ CoreSharedModule, @@ -31,7 +29,6 @@ import { AddonModImscpTocComponent } from './toc/toc'; ], exports: [ AddonModImscpIndexComponent, - AddonModImscpTocComponent, ], }) export class AddonModImscpComponentsModule {} diff --git a/src/addons/mod/imscp/components/toc/toc.ts b/src/addons/mod/imscp/components/toc/toc.ts index 9378ba647..22527d45b 100644 --- a/src/addons/mod/imscp/components/toc/toc.ts +++ b/src/addons/mod/imscp/components/toc/toc.ts @@ -15,6 +15,7 @@ import { Component, Input } from '@angular/core'; import { ModalController } from '@singletons'; import { AddonModImscpTocItem } from '../../services/imscp'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal to display the TOC of a imscp. @@ -22,6 +23,10 @@ import { AddonModImscpTocItem } from '../../services/imscp'; @Component({ selector: 'addon-mod-imscp-toc', templateUrl: 'toc.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModImscpTocComponent { diff --git a/src/addons/mod/imscp/pages/view/view.ts b/src/addons/mod/imscp/pages/view/view.ts index 7a96a3324..41d3b782c 100644 --- a/src/addons/mod/imscp/pages/view/view.ts +++ b/src/addons/mod/imscp/pages/view/view.ts @@ -26,8 +26,8 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; -import { AddonModImscpTocComponent } from '../../components/toc/toc'; import { AddonModImscp, AddonModImscpImscp, AddonModImscpTocItem } from '../../services/imscp'; +import { CoreModals } from '@services/modals'; /** * Page that displays a IMSCP content. @@ -272,8 +272,10 @@ export class AddonModImscpViewPage implements OnInit { * Show the TOC. */ async showToc(): Promise { + const { AddonModImscpTocComponent } = await import('../../components/toc/toc'); + // Create the toc modal. - const itemHref = await CoreDomUtils.openSideModal({ + const itemHref = await CoreModals.openSideModal({ component: AddonModImscpTocComponent, componentProps: { items: this.items, diff --git a/src/addons/mod/lesson/components/components.module.ts b/src/addons/mod/lesson/components/components.module.ts index 6daa4ec51..6822ef34b 100644 --- a/src/addons/mod/lesson/components/components.module.ts +++ b/src/addons/mod/lesson/components/components.module.ts @@ -17,22 +17,17 @@ import { NgModule } from '@angular/core'; import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; import { AddonModLessonIndexComponent } from './index/index'; -import { AddonModLessonMenuModalPage } from './menu-modal/menu-modal'; @NgModule({ declarations: [ AddonModLessonIndexComponent, - AddonModLessonMenuModalPage, ], imports: [ CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModLessonIndexComponent, - AddonModLessonMenuModalPage, ], }) export class AddonModLessonComponentsModule {} diff --git a/src/addons/mod/lesson/components/menu-modal/menu-modal.ts b/src/addons/mod/lesson/components/menu-modal/menu-modal.ts index 73b257e79..f448e86f1 100644 --- a/src/addons/mod/lesson/components/menu-modal/menu-modal.ts +++ b/src/addons/mod/lesson/components/menu-modal/menu-modal.ts @@ -16,6 +16,7 @@ import { Component, Input } from '@angular/core'; import { ModalController } from '@singletons'; import { AddonModLessonPlayerPage } from '../../pages/player/player'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal that renders the lesson menu and media file. @@ -23,6 +24,10 @@ import { AddonModLessonPlayerPage } from '../../pages/player/player'; @Component({ selector: 'page-addon-mod-lesson-menu-modal', templateUrl: 'menu-modal.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModLessonMenuModalPage { diff --git a/src/addons/mod/lesson/pages/player/player.ts b/src/addons/mod/lesson/pages/player/player.ts index 6c8228e11..57c984ef3 100644 --- a/src/addons/mod/lesson/pages/player/player.ts +++ b/src/addons/mod/lesson/pages/player/player.ts @@ -28,7 +28,6 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreWSExternalFile } from '@services/ws'; import { ModalController, Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; -import { AddonModLessonMenuModalPage } from '../../components/menu-modal/menu-modal'; import { AddonModLesson, AddonModLessonEOLPageDataEntry, @@ -55,6 +54,7 @@ import { AddonModLessonSync } from '../../services/lesson-sync'; import { CoreFormFields, CoreForms } from '@singletons/form'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { ADDON_MOD_LESSON_COMPONENT, AddonModLessonJumpTo } from '../../constants'; +import { CoreModals } from '@services/modals'; /** * Page that allows attempting and reviewing a lesson. @@ -829,7 +829,9 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave { async showMenu(): Promise { this.menuShown = true; - await CoreDomUtils.openSideModal({ + const { AddonModLessonMenuModalPage } = await import('../../components/menu-modal/menu-modal'); + + await CoreModals.openSideModal({ component: AddonModLessonMenuModalPage, componentProps: { pageInstance: this, diff --git a/src/addons/mod/lesson/services/handlers/prefetch.ts b/src/addons/mod/lesson/services/handlers/prefetch.ts index 852a07d58..6df58a118 100644 --- a/src/addons/mod/lesson/services/handlers/prefetch.ts +++ b/src/addons/mod/lesson/services/handlers/prefetch.ts @@ -21,7 +21,7 @@ import { CoreFilepool } from '@services/filepool'; import { CoreGroups } from '@services/groups'; import { CoreFileSizeSum, CorePluginFileDelegate } from '@services/plugin-file-delegate'; import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreUtils } from '@services/utils/utils'; import { CoreWSFile } from '@services/ws'; import { makeSingleton, Translate } from '@singletons'; @@ -136,7 +136,7 @@ export class AddonModLessonPrefetchHandlerService extends CoreCourseActivityPref } // Create and show the modal. - const response = await CoreDomUtils.promptPassword({ + const response = await CoreModals.promptPassword({ title: 'addon.mod_lesson.enterpassword', placeholder: 'core.login.password', submit: 'addon.mod_lesson.continue', diff --git a/src/addons/mod/quiz/components/components.module.ts b/src/addons/mod/quiz/components/components.module.ts index 32f249166..82eb41016 100644 --- a/src/addons/mod/quiz/components/components.module.ts +++ b/src/addons/mod/quiz/components/components.module.ts @@ -18,7 +18,6 @@ import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; import { AddonModQuizConnectionErrorComponent } from './connection-error/connection-error'; import { AddonModQuizIndexComponent } from './index/index'; -import { AddonModQuizNavigationModalComponent } from './navigation-modal/navigation-modal'; import { AddonModQuizAttemptInfoComponent } from './attempt-info/attempt-info'; import { AddonModQuizAttemptStateComponent } from './attempt-state/attempt-state'; import { AddonModQuizQuestionCardComponent } from './question-card/question-card'; @@ -29,7 +28,6 @@ import { AddonModQuizQuestionCardComponent } from './question-card/question-card AddonModQuizAttemptStateComponent, AddonModQuizIndexComponent, AddonModQuizConnectionErrorComponent, - AddonModQuizNavigationModalComponent, AddonModQuizQuestionCardComponent, ], imports: [ @@ -41,7 +39,6 @@ import { AddonModQuizQuestionCardComponent } from './question-card/question-card AddonModQuizAttemptStateComponent, AddonModQuizIndexComponent, AddonModQuizConnectionErrorComponent, - AddonModQuizNavigationModalComponent, AddonModQuizQuestionCardComponent, ], 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 711ef23f8..1b71ea075 100644 --- a/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts +++ b/src/addons/mod/quiz/components/navigation-modal/navigation-modal.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { CoreSharedModule } from '@/core/shared.module'; import { Component, Input } from '@angular/core'; import { CoreQuestionQuestionParsed } from '@features/question/services/question'; @@ -23,6 +24,10 @@ import { ModalController } from '@singletons'; @Component({ selector: 'addon-mod-quiz-navigation-modal', templateUrl: 'navigation-modal.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModQuizNavigationModalComponent { diff --git a/src/addons/mod/quiz/pages/player/player.ts b/src/addons/mod/quiz/pages/player/player.ts index c67450887..997fd63e4 100644 --- a/src/addons/mod/quiz/pages/player/player.ts +++ b/src/addons/mod/quiz/pages/player/player.ts @@ -33,7 +33,6 @@ import { ModalController, Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { AddonModQuizAutoSave } from '../../classes/auto-save'; import { - AddonModQuizNavigationModalComponent, AddonModQuizNavigationModalReturn, AddonModQuizNavigationQuestion, } from '../../components/navigation-modal/navigation-modal'; @@ -55,6 +54,7 @@ import { CoreWSError } from '@classes/errors/wserror'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { ADDON_MOD_QUIZ_ATTEMPT_FINISHED_EVENT, AddonModQuizAttemptStates, ADDON_MOD_QUIZ_COMPONENT } from '../../constants'; import { CoreWait } from '@singletons/wait'; +import { CoreModals } from '@services/modals'; /** * Page that allows attempting a quiz. @@ -727,8 +727,10 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy, CanLeave { this.reloadNavigation = false; } + const { AddonModQuizNavigationModalComponent } = await import('../../components/navigation-modal/navigation-modal'); + // Create the navigation modal. - const modalData = await CoreDomUtils.openSideModal({ + const modalData = await CoreModals.openSideModal({ component: AddonModQuizNavigationModalComponent, componentProps: { navigation: this.navigation, diff --git a/src/addons/mod/quiz/pages/review/review.ts b/src/addons/mod/quiz/pages/review/review.ts index 524ebed9e..5cfb5e244 100644 --- a/src/addons/mod/quiz/pages/review/review.ts +++ b/src/addons/mod/quiz/pages/review/review.ts @@ -22,7 +22,6 @@ import { CoreUtils } from '@services/utils/utils'; import { CoreDom } from '@singletons/dom'; import { CoreTime } from '@singletons/time'; import { - AddonModQuizNavigationModalComponent, AddonModQuizNavigationModalReturn, AddonModQuizNavigationQuestion, } from '../../components/navigation-modal/navigation-modal'; @@ -36,6 +35,7 @@ import { import { AddonModQuizHelper } from '../../services/quiz-helper'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { ADDON_MOD_QUIZ_COMPONENT } from '../../constants'; +import { CoreModals } from '@services/modals'; /** * Page that allows reviewing a quiz attempt. @@ -265,8 +265,10 @@ export class AddonModQuizReviewPage implements OnInit { } async openNavigation(): Promise { + const { AddonModQuizNavigationModalComponent } = await import('../../components/navigation-modal/navigation-modal'); + // Create the navigation modal. - const modalData = await CoreDomUtils.openSideModal({ + const modalData = await CoreModals.openSideModal({ component: AddonModQuizNavigationModalComponent, componentProps: { navigation: this.navigation, diff --git a/src/addons/mod/quiz/services/handlers/prefetch.ts b/src/addons/mod/quiz/services/handlers/prefetch.ts index b6c17276b..9f30d9406 100644 --- a/src/addons/mod/quiz/services/handlers/prefetch.ts +++ b/src/addons/mod/quiz/services/handlers/prefetch.ts @@ -474,7 +474,6 @@ export class AddonModQuizPrefetchHandlerService extends CoreCourseActivityPrefet * @param accessInfo Quiz access info. * @param attempt Attempt. * @param modOptions Other options. - * @param siteId Site ID. * @returns Promise resolved when done. */ protected async prefetchAttemptReview( diff --git a/src/addons/mod/quiz/services/quiz-helper.ts b/src/addons/mod/quiz/services/quiz-helper.ts index 2bc6d85ea..24f2e6337 100644 --- a/src/addons/mod/quiz/services/quiz-helper.ts +++ b/src/addons/mod/quiz/services/quiz-helper.ts @@ -40,6 +40,7 @@ import { import { QuestionDisplayOptionsMarks } from '@features/question/constants'; import { CoreGroups } from '@services/groups'; import { CoreTimeUtils } from '@services/utils/time'; +import { CoreModals } from '@services/modals'; /** * Helper service that provides some features for quiz. @@ -272,7 +273,7 @@ export class AddonModQuizHelperProvider { await import('@addons/mod/quiz/components/preflight-modal/preflight-modal'); // Create and show the modal. - const modalData = await CoreDomUtils.openModal>({ + const modalData = await CoreModals.openModal>({ component: AddonModQuizPreflightModalComponent, componentProps: { title: options.title, diff --git a/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_27.png b/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_27.png index 63ba23ad2..46c036744 100644 Binary files a/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_27.png and b/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_27.png differ diff --git a/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_42.png b/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_42.png index f8affc29e..e62984bde 100644 Binary files a/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_42.png and b/src/addons/mod/quiz/tests/behat/snapshots/attempt-a-quiz-in-app-submit-a-quiz--review-a-quiz-attempt_42.png differ diff --git a/src/addons/mod/resource/components/components.module.ts b/src/addons/mod/resource/components/components.module.ts index a4e217b90..36d0dee31 100644 --- a/src/addons/mod/resource/components/components.module.ts +++ b/src/addons/mod/resource/components/components.module.ts @@ -27,8 +27,6 @@ import { AddonModResourceIndexComponent } from './index/index'; CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModResourceIndexComponent, ], diff --git a/src/addons/mod/scorm/components/components.module.ts b/src/addons/mod/scorm/components/components.module.ts index 407c08e0b..a93ced361 100644 --- a/src/addons/mod/scorm/components/components.module.ts +++ b/src/addons/mod/scorm/components/components.module.ts @@ -16,22 +16,17 @@ import { NgModule } from '@angular/core'; import { AddonModScormIndexComponent } from './index/index'; import { CoreSharedModule } from '@/core/shared.module'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; -import { AddonModScormTocComponent } from './toc/toc'; @NgModule({ declarations: [ AddonModScormIndexComponent, - AddonModScormTocComponent, ], imports: [ CoreSharedModule, CoreCourseComponentsModule, ], - providers: [ - ], exports: [ AddonModScormIndexComponent, - AddonModScormTocComponent, ], }) export class AddonModScormComponentsModule {} diff --git a/src/addons/mod/scorm/components/toc/toc.ts b/src/addons/mod/scorm/components/toc/toc.ts index d1b48186f..42199ba11 100644 --- a/src/addons/mod/scorm/components/toc/toc.ts +++ b/src/addons/mod/scorm/components/toc/toc.ts @@ -17,6 +17,7 @@ import { ModalController } from '@singletons'; import { AddonModScormGetScormAccessInformationWSResponse } from '../../services/scorm'; import { AddonModScormTOCScoWithIcon } from '../../services/scorm-helper'; import { AddonModScormMode } from '../../constants'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal to display the TOC of a SCORM. @@ -24,6 +25,10 @@ import { AddonModScormMode } from '../../constants'; @Component({ selector: 'addon-mod-scorm-toc', templateUrl: 'toc.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModScormTocComponent implements OnInit { diff --git a/src/addons/mod/scorm/pages/player/player.ts b/src/addons/mod/scorm/pages/player/player.ts index c9d4f6aa5..e3d29384d 100644 --- a/src/addons/mod/scorm/pages/player/player.ts +++ b/src/addons/mod/scorm/pages/player/player.ts @@ -23,7 +23,6 @@ import { CoreTimeUtils } from '@services/utils/time'; import { CoreUtils } from '@services/utils/utils'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { AddonModScormDataModel12 } from '../../classes/data-model-12'; -import { AddonModScormTocComponent } from '../../components/toc/toc'; import { AddonModScorm, AddonModScormAttemptCountResult, @@ -44,6 +43,7 @@ import { ADDON_MOD_SCORM_UPDATE_TOC_EVENT, } from '../../constants'; import { CoreWait } from '@singletons/wait'; +import { CoreModals } from '@services/modals'; /** * Page that allows playing a SCORM. @@ -513,7 +513,9 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { * Show the TOC. */ async openToc(): Promise { - const modalData = await CoreDomUtils.openSideModal({ + const { AddonModScormTocComponent } = await import('../../components/toc/toc'); + + const modalData = await CoreModals.openSideModal({ component: AddonModScormTocComponent, componentProps: { toc: this.toc, diff --git a/src/addons/mod/wiki/components/components.module.ts b/src/addons/mod/wiki/components/components.module.ts index 92b38259d..23e3e31ff 100644 --- a/src/addons/mod/wiki/components/components.module.ts +++ b/src/addons/mod/wiki/components/components.module.ts @@ -17,14 +17,10 @@ import { NgModule } from '@angular/core'; import { CoreCourseComponentsModule } from '@features/course/components/components.module'; import { CoreTagComponentsModule } from '@features/tag/components/components.module'; import { AddonModWikiIndexComponent } from './index/index'; -import { AddonModWikiMapModalComponent } from './map/map'; -import { AddonModWikiSubwikiPickerComponent } from './subwiki-picker/subwiki-picker'; @NgModule({ declarations: [ AddonModWikiIndexComponent, - AddonModWikiSubwikiPickerComponent, - AddonModWikiMapModalComponent, ], imports: [ CoreSharedModule, @@ -33,8 +29,6 @@ import { AddonModWikiSubwikiPickerComponent } from './subwiki-picker/subwiki-pic ], exports: [ AddonModWikiIndexComponent, - AddonModWikiSubwikiPickerComponent, - AddonModWikiMapModalComponent, ], }) export class AddonModWikiComponentsModule {} diff --git a/src/addons/mod/wiki/components/index/index.ts b/src/addons/mod/wiki/components/index/index.ts index c9940f548..853ac31f1 100644 --- a/src/addons/mod/wiki/components/index/index.ts +++ b/src/addons/mod/wiki/components/index/index.ts @@ -58,6 +58,7 @@ import { ADDON_MOD_WIKI_PAGE_CREATED_EVENT, ADDON_MOD_WIKI_PAGE_NAME, } from '../../constants'; +import { CoreModals } from '@services/modals'; /** * Component that displays a wiki entry page. @@ -663,9 +664,10 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp * Show the map. */ async openMap(): Promise { - // Create the toc modal. const { AddonModWikiMapModalComponent } = await import('../map/map'); - const modalData = await CoreDomUtils.openSideModal({ + + // Create the map modal. + const modalData = await CoreModals.openSideModal({ component: AddonModWikiMapModalComponent, componentProps: { pages: this.subwikiPages, @@ -884,6 +886,7 @@ export class AddonModWikiIndexComponent extends CoreCourseModuleMainActivityComp */ async showSubwikiPicker(event: MouseEvent): Promise { const { AddonModWikiSubwikiPickerComponent } = await import('../subwiki-picker/subwiki-picker'); + const subwiki = await CoreDomUtils.openPopover({ component: AddonModWikiSubwikiPickerComponent, componentProps: { diff --git a/src/addons/mod/wiki/components/map/map.ts b/src/addons/mod/wiki/components/map/map.ts index 9884350b0..9af480058 100644 --- a/src/addons/mod/wiki/components/map/map.ts +++ b/src/addons/mod/wiki/components/map/map.ts @@ -17,6 +17,7 @@ import { ModalController } from '@singletons'; import { AddonModWikiPageDBRecord } from '../../services/database/wiki'; import { AddonModWikiSubwikiPage, AddonModWikiWiki } from '../../services/wiki'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal to display the map of a Wiki. @@ -24,6 +25,10 @@ import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; @Component({ selector: 'page-addon-mod-wiki-map', templateUrl: 'map.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModWikiMapModalComponent implements OnInit { 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 ffbbb93e8..878d918d3 100644 --- a/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts +++ b/src/addons/mod/wiki/components/subwiki-picker/subwiki-picker.ts @@ -15,6 +15,7 @@ import { Component, Input } from '@angular/core'; import { PopoverController } from '@singletons'; import { AddonModWikiSubwiki, AddonModWikiSubwikiListGrouping } from '../../services/wiki'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Component to display the a list of subwikis in a wiki. @@ -22,6 +23,10 @@ import { AddonModWikiSubwiki, AddonModWikiSubwikiListGrouping } from '../../serv @Component({ selector: 'addon-mod-wiki-subwiki-picker', templateUrl: 'addon-mod-wiki-subwiki-picker.html', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class AddonModWikiSubwikiPickerComponent { diff --git a/src/addons/mod/workshop/components/index/index.ts b/src/addons/mod/workshop/components/index/index.ts index 628d70853..ee4337778 100644 --- a/src/addons/mod/workshop/components/index/index.ts +++ b/src/addons/mod/workshop/components/index/index.ts @@ -21,7 +21,7 @@ import { IonContent } from '@ionic/angular'; import { CoreGroupInfo, CoreGroups } from '@services/groups'; import { CoreNavigator } from '@services/navigator'; import { CorePlatform } from '@services/platform'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreUtils } from '@services/utils/utils'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { Subscription } from 'rxjs'; @@ -400,7 +400,7 @@ export class AddonModWorkshopIndexComponent extends CoreCourseModuleMainActivity const { AddonModWorkshopPhaseInfoModalComponent } = await import('@addons/mod/workshop/components/phase-modal/phase-modal'); - const modalData = await CoreDomUtils.openModal({ + const modalData = await CoreModals.openModal({ component: AddonModWorkshopPhaseInfoModalComponent, componentProps: { phases: CoreUtils.objectToArray(this.phases), diff --git a/src/addons/notes/components/add/add-modal.ts b/src/addons/notes/components/add/add-modal.ts index 1fdf03ea8..337b97dc6 100644 --- a/src/addons/notes/components/add/add-modal.ts +++ b/src/addons/notes/components/add/add-modal.ts @@ -15,11 +15,12 @@ import { AddonNotes, AddonNotesPublishState } from '@addons/notes/services/notes'; import { Component, ViewChild, ElementRef, Input } from '@angular/core'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreForms } from '@singletons/form'; import { ModalController } from '@singletons'; import { CoreKeyboard } from '@singletons/keyboard'; import { CoreSharedModule } from '@/core/shared.module'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Component that displays a text area for composing a note. @@ -62,7 +63,11 @@ export class AddonNotesAddComponent { CoreForms.triggerFormSubmittedEvent(this.formElement, sent, CoreSites.getCurrentSiteId()); ModalController.dismiss({ type: this.type, sent: true }).finally(() => { - CoreDomUtils.showToast(sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', true, ToastDuration.LONG); + CoreToasts.show({ + message: sent ? 'addon.notes.eventnotecreated' : 'core.datastoredoffline', + translateMessage: true, + duration: ToastDuration.LONG, + }); }); } catch (error){ CoreDomUtils.showErrorModal(error); diff --git a/src/addons/notes/pages/list/list.ts b/src/addons/notes/pages/list/list.ts index b31a6ac17..d4cc56a65 100644 --- a/src/addons/notes/pages/list/list.ts +++ b/src/addons/notes/pages/list/list.ts @@ -24,13 +24,15 @@ import { IonContent } from '@ionic/angular'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUrl } from '@singletons/url'; import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreTime } from '@singletons/time'; +import { CoreToasts, ToastDuration } from '@services/toasts'; +import { CoreModals } from '@services/modals'; /** * Page that displays a list of notes. @@ -196,7 +198,7 @@ export class AddonNotesListPage implements OnInit, OnDestroy { const { AddonNotesAddComponent } = await import('@addons/notes/components/add/add-modal'); - const modalData = await CoreDomUtils.openModal({ + const modalData = await CoreModals.openModal({ component: AddonNotesAddComponent, componentProps: { userId: this.userId, @@ -240,7 +242,11 @@ export class AddonNotesListPage implements OnInit, OnDestroy { this.refreshNotes(false); - CoreDomUtils.showToast('addon.notes.eventnotedeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'addon.notes.eventnotedeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'Delete note failed.'); diff --git a/src/addons/privatefiles/services/privatefiles-helper.ts b/src/addons/privatefiles/services/privatefiles-helper.ts index a00f2bd94..b12cd780a 100644 --- a/src/addons/privatefiles/services/privatefiles-helper.ts +++ b/src/addons/privatefiles/services/privatefiles-helper.ts @@ -20,6 +20,7 @@ import { CoreFileUploaderHelper } from '@features/fileuploader/services/fileuplo import { AddonPrivateFiles, AddonPrivateFilesGetUserInfoWSResult } from './privatefiles'; import { CoreError } from '@classes/errors/error'; import { makeSingleton, Translate } from '@singletons'; +import { CoreToasts } from '@services/toasts'; /** * Service that provides some helper functions regarding private and site files. @@ -64,7 +65,11 @@ export class AddonPrivateFilesHelperProvider { try { await AddonPrivateFiles.moveFromDraftToPrivate(result.itemid); - CoreDomUtils.showToast('core.fileuploader.fileuploaded', true, undefined, 'core-toast-success'); + CoreToasts.show({ + message: 'core.fileuploader.fileuploaded', + translateMessage: true, + cssClass: 'core-toast-success', + }); } finally { modal.dismiss(); } diff --git a/src/addons/qtype/ddmarker/classes/ddmarker.ts b/src/addons/qtype/ddmarker/classes/ddmarker.ts index 98d937316..49fddf82d 100644 --- a/src/addons/qtype/ddmarker/classes/ddmarker.ts +++ b/src/addons/qtype/ddmarker/classes/ddmarker.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreDomUtils } from '@services/utils/dom'; -import { CoreTextUtils } from '@services/utils/text'; +import { CoreText } from '@singletons/text'; import { CoreCoordinates, CoreDom } from '@singletons/dom'; import { CoreEventObserver } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; @@ -267,7 +267,7 @@ export class AddonQtypeDdMarkerQuestion { } // Check that a function to draw this shape exists. - const drawFunc = 'drawShape' + CoreTextUtils.ucFirst(shape); + const drawFunc = 'drawShape' + CoreText.capitalize(shape); if (!(this[drawFunc] instanceof Function)) { return; } diff --git a/src/addons/report/insights/services/handlers/action-link.ts b/src/addons/report/insights/services/handlers/action-link.ts index e91ce2386..679ae22d6 100644 --- a/src/addons/report/insights/services/handlers/action-link.ts +++ b/src/addons/report/insights/services/handlers/action-link.ts @@ -20,6 +20,7 @@ import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { makeSingleton, Translate } from '@singletons'; import { AddonReportInsights } from '../insights'; +import { CoreToasts } from '@services/toasts'; // Bulk actions supported, along with the related lang string. const BULK_ACTIONS = { @@ -64,12 +65,17 @@ export class AddonReportInsightsActionLinkHandlerService extends CoreContentLink if (BULK_ACTIONS[params.action]) { // Done, display a toast. - CoreDomUtils.showToast(Translate.instant('addon.report_insights.actionsaved', { - $a: Translate.instant(BULK_ACTIONS[params.action]), - })); + CoreToasts.show({ + message: Translate.instant('addon.report_insights.actionsaved', { + $a: Translate.instant(BULK_ACTIONS[params.action]), + }), + }); } else if (!params.forwardurl) { // Forward URL not defined, display a toast. - CoreDomUtils.showToast('core.success', true); + CoreToasts.show({ + message: 'core.success', + translateMessage: true, + }); } else { // Try to open the link in the app. const forwardUrl = decodeURIComponent(params.forwardurl); diff --git a/src/core/classes/page-loads-manager.ts b/src/core/classes/page-loads-manager.ts index a67816df0..174f6a66d 100644 --- a/src/core/classes/page-loads-manager.ts +++ b/src/core/classes/page-loads-manager.ts @@ -13,7 +13,7 @@ // limitations under the License. import { CoreNavigator } from '@services/navigator'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { Subject } from 'rxjs'; import { AsyncDirective } from './async-directive'; import { PageLoadWatcher } from './page-load-watcher'; @@ -131,7 +131,7 @@ export class PageLoadsManager { const { CoreRefreshButtonModalComponent } = await import('@components/refresh-button-modal/refresh-button-modal'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreRefreshButtonModalComponent, cssClass: 'core-modal-no-background core-modal-fullscreen', closeOnNavigate: true, diff --git a/src/core/classes/sites/authenticated-site.ts b/src/core/classes/sites/authenticated-site.ts index 20be3c9fe..a40896b9e 100644 --- a/src/core/classes/sites/authenticated-site.ts +++ b/src/core/classes/sites/authenticated-site.ts @@ -21,7 +21,7 @@ import { CoreWSPreSetsSplitRequest, CoreWSTypeExpected, } from '@services/ws'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreToasts, ToastDuration } from '@services/toasts'; import { CoreTextUtils } from '@services/utils/text'; import { CoreUtils } from '@services/utils/utils'; import { CoreConstants } from '@/core/constants'; @@ -420,7 +420,11 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite { if (wsPreSets.cleanUnicode && CoreTextUtils.hasUnicodeData(data)) { // Data will be cleaned, notify the user. - CoreDomUtils.showToast('core.unicodenotsupported', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'core.unicodenotsupported', + translateMessage: true, + duration: ToastDuration.LONG, + }); } else { // No need to clean data in this call. wsPreSets.cleanUnicode = false; diff --git a/src/core/components/combobox/combobox.ts b/src/core/components/combobox/combobox.ts index ddf7e75e8..e85060584 100644 --- a/src/core/components/combobox/combobox.ts +++ b/src/core/components/combobox/combobox.ts @@ -15,7 +15,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Translate } from '@singletons'; import { ModalOptions } from '@ionic/core'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; /** @@ -123,7 +123,7 @@ export class CoreComboboxComponent implements ControlValueAccessor { this.modalOptions.id = this.listboxId; } - const data = await CoreDomUtils.openModal(this.modalOptions); + const data = await CoreModals.openModal(this.modalOptions); this.expanded = false; if (data) { diff --git a/src/core/core.module.ts b/src/core/core.module.ts index 5a33b79e3..d94191d1f 100644 --- a/src/core/core.module.ts +++ b/src/core/core.module.ts @@ -34,6 +34,7 @@ export async function getCoreServices(): Promise[]> { const { CoreCustomURLSchemesProvider } = await import('@services/urlschemes'); const { CoreDbProvider } = await import('@services/db'); const { CoreDomUtilsProvider } = await import('@services/utils/dom'); + const { CoreToastsService } = await import('@services/toasts'); const { CoreFileHelperProvider } = await import('@services/file-helper'); const { CoreFilepoolProvider } = await import('@services/filepool'); const { CoreFileProvider } = await import('@services/file'); @@ -82,6 +83,7 @@ export async function getCoreServices(): Promise[]> { CoreSyncProvider, CoreTextUtilsProvider, CoreTimeUtilsProvider, + CoreToastsService, CoreUpdateManagerProvider, CoreUrlUtilsProvider, CoreUtilsProvider, diff --git a/src/core/features/block/components/components.module.ts b/src/core/features/block/components/components.module.ts index 62552af04..7ebf07bd9 100644 --- a/src/core/features/block/components/components.module.ts +++ b/src/core/features/block/components/components.module.ts @@ -17,7 +17,6 @@ import { CoreBlockComponent } from './block/block'; import { CoreBlockOnlyTitleComponent } from './only-title-block/only-title-block'; import { CoreBlockPreRenderedComponent } from './pre-rendered-block/pre-rendered-block'; import { CoreSharedModule } from '@/core/shared.module'; -import { CoreBlockSideBlocksComponent } from './side-blocks/side-blocks'; import { CoreBlockSideBlocksButtonComponent } from './side-blocks-button/side-blocks-button'; import { CoreBlockSideBlocksTourComponent } from './side-blocks-tour/side-blocks-tour'; @@ -26,7 +25,6 @@ import { CoreBlockSideBlocksTourComponent } from './side-blocks-tour/side-blocks CoreBlockComponent, CoreBlockOnlyTitleComponent, CoreBlockPreRenderedComponent, - CoreBlockSideBlocksComponent, CoreBlockSideBlocksButtonComponent, CoreBlockSideBlocksTourComponent, ], @@ -37,7 +35,6 @@ import { CoreBlockSideBlocksTourComponent } from './side-blocks-tour/side-blocks CoreBlockComponent, CoreBlockOnlyTitleComponent, CoreBlockPreRenderedComponent, - CoreBlockSideBlocksComponent, CoreBlockSideBlocksButtonComponent, CoreBlockSideBlocksTourComponent, ], 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 69ae1e0ac..a9d9f51ec 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 @@ -16,10 +16,9 @@ import { Component, ElementRef, Input, OnDestroy, OnInit } from '@angular/core'; import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreUserTourDirectiveOptions } from '@directives/user-tour'; import { CoreUserToursAlignment, CoreUserToursSide } from '@features/usertours/services/user-tours'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreDom } from '@singletons/dom'; import { CoreBlockSideBlocksTourComponent } from '../side-blocks-tour/side-blocks-tour'; -import { CoreBlockSideBlocksComponent } from '../side-blocks/side-blocks'; import { ContextLevel } from '@/core/constants'; /** @@ -67,8 +66,10 @@ export class CoreBlockSideBlocksButtonComponent implements OnInit, OnDestroy { /** * Open side blocks. */ - openBlocks(): void { - CoreDomUtils.openSideModal({ + async openBlocks(): Promise { + const { CoreBlockSideBlocksComponent } = await import('@features/block/components/side-blocks/side-blocks'); + + CoreModals.openSideModal({ component: CoreBlockSideBlocksComponent, componentProps: { contextLevel: this.contextLevel, 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 b677274a5..d4ac02876 100644 --- a/src/core/features/block/components/side-blocks/side-blocks.ts +++ b/src/core/features/block/components/side-blocks/side-blocks.ts @@ -24,6 +24,8 @@ import { CoreTextUtils } from '@services/utils/text'; import { CoreDom } from '@singletons/dom'; import { ContextLevel } from '@/core/constants'; import { CoreWait } from '@singletons/wait'; +import { CoreSharedModule } from '@/core/shared.module'; +import { CoreBlockComponentsModule } from '../components.module'; /** * Component that displays the list of side blocks. @@ -31,7 +33,12 @@ import { CoreWait } from '@singletons/wait'; @Component({ selector: 'core-block-side-blocks', templateUrl: 'side-blocks.html', - styleUrls: ['side-blocks.scss'], + styleUrl: 'side-blocks.scss', + standalone: true, + imports: [ + CoreSharedModule, + CoreBlockComponentsModule, + ], }) export class CoreBlockSideBlocksComponent implements OnInit { diff --git a/src/core/features/comments/pages/viewer/viewer.ts b/src/core/features/comments/pages/viewer/viewer.ts index e1a077947..a403084b6 100644 --- a/src/core/features/comments/pages/viewer/viewer.ts +++ b/src/core/features/comments/pages/viewer/viewer.ts @@ -31,7 +31,7 @@ import { ContextLevel, CoreConstants } from '@/core/constants'; import { CoreNavigator } from '@services/navigator'; import { NgZone, Translate } from '@singletons'; import { CoreUtils } from '@services/utils/utils'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; import { CoreUser } from '@features/user/services/user'; import { CoreTextUtils } from '@services/utils/text'; import { CoreError } from '@classes/errors/error'; @@ -43,6 +43,7 @@ import moment from 'moment-timezone'; import { Subscription } from 'rxjs'; import { CoreAnimations } from '@components/animations'; import { CoreKeyboard } from '@singletons/keyboard'; +import { CoreToasts, ToastDuration } from '@services/toasts'; /** * Page that displays comments. @@ -323,11 +324,11 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.area, ); - CoreDomUtils.showToast( - commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', - true, - ToastDuration.LONG, - ); + CoreToasts.show({ + message: commentsResponse ? 'core.comments.eventcommentcreated' : 'core.datastoredoffline', + translateMessage: true, + duration: ToastDuration.LONG, + }); if (commentsResponse) { this.invalidateComments(); @@ -426,7 +427,11 @@ export class CoreCommentsViewerPage implements OnInit, OnDestroy { this.invalidateComments(); - CoreDomUtils.showToast('core.comments.eventcommentdeleted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'core.comments.eventcommentdeleted', + translateMessage: true, + duration: ToastDuration.LONG, + }); } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'Delete comment failed.'); } diff --git a/src/core/features/contentlinks/services/contentlinks-helper.ts b/src/core/features/contentlinks/services/contentlinks-helper.ts index b7ba93788..4f63b6770 100644 --- a/src/core/features/contentlinks/services/contentlinks-helper.ts +++ b/src/core/features/contentlinks/services/contentlinks-helper.ts @@ -20,6 +20,7 @@ import { CoreSite } from '@classes/sites/site'; import { makeSingleton, Translate } from '@singletons'; import { CoreNavigator } from '@services/navigator'; import { CoreCustomURLSchemes } from '@services/urlschemes'; +import { CoreModals } from '@services/modals'; /** * Service that provides some features regarding content links. @@ -98,7 +99,7 @@ export class CoreContentLinksHelperProvider { const { CoreContentLinksChooseSiteModalComponent } = await import('@features/contentlinks/components/choose-site-modal/choose-site-modal'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreContentLinksChooseSiteModalComponent, componentProps: { url: url, diff --git a/src/core/features/course/classes/main-resource-component.ts b/src/core/features/course/classes/main-resource-component.ts index 24de44d23..e3b994b08 100644 --- a/src/core/features/course/classes/main-resource-component.ts +++ b/src/core/features/course/classes/main-resource-component.ts @@ -24,7 +24,7 @@ import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreLogger } from '@singletons/logger'; -import { CoreCourseModuleSummaryComponent, CoreCourseModuleSummaryResult } from '../components/module-summary/module-summary'; +import { CoreCourseModuleSummaryResult } from '../components/module-summary/module-summary'; import { CoreCourseContentsPage } from '../pages/contents/contents'; import { CoreCourse } from '../services/course'; import { CoreCourseHelper, CoreCourseModuleData } from '../services/course-helper'; @@ -33,6 +33,8 @@ import { CoreCourseModulePrefetchDelegate } from '../services/module-prefetch-de import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; import { CoreUrl } from '@singletons/url'; import { CoreTime } from '@singletons/time'; +import { CoreText } from '@singletons/text'; +import { CoreModals } from '@services/modals'; /** * Result of a resource download. @@ -232,7 +234,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, const lastDownloaded = await CoreCourseHelper.getModulePackageLastDownloaded(this.module, this.component); - this.downloadTimeReadable = CoreTextUtils.ucFirst(lastDownloaded.downloadTimeReadable); + this.downloadTimeReadable = CoreText.capitalize(lastDownloaded.downloadTimeReadable); } /** @@ -423,7 +425,9 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy, return; } - const data = await CoreDomUtils.openSideModal({ + const { CoreCourseModuleSummaryComponent } = await import('@features/course/components/module-summary/module-summary'); + + const data = await CoreModals.openSideModal({ component: CoreCourseModuleSummaryComponent, componentProps: { moduleId: this.module.id, diff --git a/src/core/features/course/components/components.module.ts b/src/core/features/course/components/components.module.ts index 4a8a1d4f1..dcac3d294 100644 --- a/src/core/features/course/components/components.module.ts +++ b/src/core/features/course/components/components.module.ts @@ -24,7 +24,6 @@ import { CoreCourseUnsupportedModuleComponent } from './unsupported-module/unsup import { CoreCourseModuleCompletionLegacyComponent } from './module-completion-legacy/module-completion-legacy'; import { CoreCourseModuleInfoComponent } from './module-info/module-info'; import { CoreCourseModuleNavigationComponent } from './module-navigation/module-navigation'; -import { CoreCourseModuleSummaryComponent } from './module-summary/module-summary'; import { CoreCourseCourseIndexTourComponent } from './course-index-tour/course-index-tour'; import { CoreRemindersComponentsModule } from '@features/reminders/components/components.module'; import { CoreCourseModuleCompletionDetailsComponent } from './module-completion-details/module-completion-details'; @@ -40,7 +39,6 @@ import { CoreCourseModuleCompletionDetailsComponent } from './module-completion- CoreCourseTagAreaComponent, CoreCourseUnsupportedModuleComponent, CoreCourseModuleNavigationComponent, - CoreCourseModuleSummaryComponent, CoreCourseModuleCompletionDetailsComponent, ], imports: [ @@ -58,7 +56,6 @@ import { CoreCourseModuleCompletionDetailsComponent } from './module-completion- CoreCourseTagAreaComponent, CoreCourseUnsupportedModuleComponent, CoreCourseModuleNavigationComponent, - CoreCourseModuleSummaryComponent, CoreCourseModuleCompletionDetailsComponent, ], }) 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 63ddb340f..e89377e26 100644 --- a/src/core/features/course/components/course-format/course-format.ts +++ b/src/core/features/course/components/course-format/course-format.ts @@ -51,8 +51,8 @@ import { CoreCourseCourseIndexTourComponent } from '../course-index-tour/course- import { CoreDom } from '@singletons/dom'; import { CoreUserTourDirectiveOptions } from '@directives/user-tour'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; -import { CoreBlockSideBlocksComponent } from '@features/block/components/side-blocks/side-blocks'; import { ContextLevel } from '@/core/constants'; +import { CoreModals } from '@services/modals'; /** * Component to display course contents using a certain format. If the format isn't found, use default one. @@ -316,7 +316,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { this.sectionChanged(section); } } else if (this.initialBlockInstanceId && this.displayBlocks && this.hasBlocks) { - CoreDomUtils.openSideModal({ + const { CoreBlockSideBlocksComponent } = await import('@features/block/components/side-blocks/side-blocks'); + + CoreModals.openSideModal({ component: CoreBlockSideBlocksComponent, componentProps: { contextLevel: ContextLevel.COURSE, @@ -431,7 +433,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { const { CoreCourseCourseIndexComponent } = await import('@features/course/components/course-index/course-index'); - const data = await CoreDomUtils.openModal({ + const data = await CoreModals.openModal({ component: CoreCourseCourseIndexComponent, initialBreakpoint: 1, breakpoints: [0, 1], 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 5b87b840c..45c6fe5d9 100644 --- a/src/core/features/course/components/module-summary/module-summary.ts +++ b/src/core/features/course/components/module-summary/module-summary.ts @@ -28,11 +28,12 @@ import { CoreFilepool } from '@services/filepool'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; -import { CoreTextUtils } from '@services/utils/text'; +import { CoreText } from '@singletons/text'; import { CoreUtils } from '@services/utils/utils'; import { ModalController, NgZone } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { Subscription } from 'rxjs'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Component to display a module summary modal. @@ -40,7 +41,11 @@ import { Subscription } from 'rxjs'; @Component({ selector: 'core-course-module-summary', templateUrl: 'module-summary.html', - styleUrls: ['module-summary.scss'], + styleUrl: 'module-summary.scss', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { @@ -222,7 +227,7 @@ export class CoreCourseModuleSummaryComponent implements OnInit, OnDestroy { if (this.canPrefetch) { if (moduleInfo.downloadTime && moduleInfo.downloadTime > 0) { - this.downloadTimeReadable = CoreTextUtils.ucFirst(moduleInfo.downloadTimeReadable); + this.downloadTimeReadable = CoreText.capitalize(moduleInfo.downloadTimeReadable); } this.prefetchLoading = moduleInfo.status === DownloadStatus.DOWNLOADING; this.prefetchDisabled = moduleInfo.status === DownloadStatus.DOWNLOADED; diff --git a/src/core/features/course/pages/module-preview/module-preview.ts b/src/core/features/course/pages/module-preview/module-preview.ts index bbaf90c66..c47db58f3 100644 --- a/src/core/features/course/pages/module-preview/module-preview.ts +++ b/src/core/features/course/pages/module-preview/module-preview.ts @@ -13,13 +13,11 @@ // limitations under the License. import { Component, OnInit } from '@angular/core'; -import { - CoreCourseModuleSummaryResult, - CoreCourseModuleSummaryComponent, -} from '@features/course/components/module-summary/module-summary'; +import { CoreCourseModuleSummaryResult } from '@features/course/components/module-summary/module-summary'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseHelper, CoreCourseModuleData, CoreCourseSection } from '@features/course/services/course-helper'; import { CoreCourseModuleDelegate } from '@features/course/services/module-delegate'; +import { CoreModals } from '@services/modals'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; @@ -106,7 +104,9 @@ export class CoreCourseModulePreviewPage implements OnInit { return; } - const data = await CoreDomUtils.openSideModal({ + const { CoreCourseModuleSummaryComponent } = await import('@features/course/components/module-summary/module-summary'); + + const data = await CoreModals.openSideModal({ component: CoreCourseModuleSummaryComponent, componentProps: { moduleId: this.module.id, diff --git a/src/core/features/course/services/course-helper.ts b/src/core/features/course/services/course-helper.ts index b3e31546f..ae96fadb4 100644 --- a/src/core/features/course/services/course-helper.ts +++ b/src/core/features/course/services/course-helper.ts @@ -69,12 +69,12 @@ import { CoreNavigationOptions, CoreNavigator } from '@services/navigator'; import { CoreSiteHomeHomeHandlerService } from '@features/sitehome/services/handlers/sitehome-home'; import { CoreStatusWithWarningsWSResponse } from '@services/ws'; import { CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper'; -import { CoreCourseSummaryPage } from '../pages/course-summary/course-summary.page'; import { CoreRemindersPushNotificationData } from '@features/reminders/services/reminders'; import { CoreLocalNotifications } from '@services/local-notifications'; import { CoreEnrol } from '@features/enrol/services/enrol'; import { CoreEnrolAction, CoreEnrolDelegate } from '@features/enrol/services/enrol-delegate'; import { LazyRoutesModule } from '@/app/app-routing.module'; +import { CoreModals } from '@services/modals'; /** * Prefetch info of a module. @@ -645,9 +645,8 @@ export class CoreCourseHelperProvider { // Now determine the status of the whole list. let status = statuses[0]; - const filepool = CoreFilepool.instance; for (let i = 1; i < statuses.length; i++) { - status = filepool.determinePackagesStatus(status, statuses[i]); + status = CoreFilepool.determinePackagesStatus(status, statuses[i]); } return status; @@ -1996,6 +1995,7 @@ export class CoreCourseHelperProvider { /** * Retrieves course summary page module. + * This is meant to be here so it can be overriden. * * @returns Course summary page module. */ @@ -2008,8 +2008,10 @@ export class CoreCourseHelperProvider { * * @param course Course selected */ - openCourseSummary(course: CoreCourseWithImageAndColor & CoreCourseAnyCourseData): void { - CoreDomUtils.openSideModal({ + async openCourseSummary(course: CoreCourseWithImageAndColor & CoreCourseAnyCourseData): Promise { + const { CoreCourseSummaryPage } = await import('../pages/course-summary/course-summary.page'); + + CoreModals.openSideModal({ component: CoreCourseSummaryPage, componentProps: { courseId: course.id, diff --git a/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts b/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts index 6bcd74ba6..dc210b959 100644 --- a/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts +++ b/src/core/features/dataprivacy/components/contactdpo/contactdpo.ts @@ -18,7 +18,8 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms'; import { CoreDataPrivacy } from '@features/dataprivacy/services/dataprivacy'; import { CoreUser } from '@features/user/services/user'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts, ToastDuration } from '@services/toasts'; import { CoreUtils } from '@services/utils/utils'; import { ModalController } from '@singletons'; @@ -80,7 +81,11 @@ export class CoreDataPrivacyContactDPOComponent implements OnInit { // Send the message. const succeed = await CoreDataPrivacy.contactDPO(this.message); if (succeed) { - CoreDomUtils.showToast('core.dataprivacy.requestsubmitted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'core.dataprivacy.requestsubmitted', + translateMessage: true, + duration: ToastDuration.LONG, + }); ModalController.dismiss(true); } } catch (error) { diff --git a/src/core/features/dataprivacy/components/newrequest/newrequest.ts b/src/core/features/dataprivacy/components/newrequest/newrequest.ts index 7939da1fd..53fde8914 100644 --- a/src/core/features/dataprivacy/components/newrequest/newrequest.ts +++ b/src/core/features/dataprivacy/components/newrequest/newrequest.ts @@ -20,7 +20,8 @@ import { CoreDataPrivacyDataRequestType, CoreDataPrivacyGetAccessInformationWSResponse, } from '@features/dataprivacy/services/dataprivacy'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts, ToastDuration } from '@services/toasts'; import { ModalController } from '@singletons'; @@ -105,7 +106,11 @@ export class CoreDataPrivacyNewRequestComponent implements OnInit { // Send the message. const requestId = await CoreDataPrivacy.createDataRequest(this.typeControl.value, this.message); if (requestId) { - CoreDomUtils.showToast('core.dataprivacy.requestsubmitted', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'core.dataprivacy.requestsubmitted', + translateMessage: true, + duration: ToastDuration.LONG, + }); ModalController.dismiss(true); } } catch (error) { diff --git a/src/core/features/dataprivacy/pages/main/main.ts b/src/core/features/dataprivacy/pages/main/main.ts index 6ac26a9cc..36fd84bd3 100644 --- a/src/core/features/dataprivacy/pages/main/main.ts +++ b/src/core/features/dataprivacy/pages/main/main.ts @@ -19,6 +19,7 @@ import { CoreDataPrivacyGetAccessInformationWSResponse, CoreDataPrivacyRequest, } from '@features/dataprivacy/services/dataprivacy'; +import { CoreModals } from '@services/modals'; import { CoreNavigator } from '@services/navigator'; import { CoreScreen } from '@services/screen'; import { CoreDomUtils } from '@services/utils/dom'; @@ -117,7 +118,7 @@ export class CoreDataPrivacyMainPage implements OnInit { await import('@features/dataprivacy/components/contactdpo/contactdpo'); // Create and show the modal. - const succeed = await CoreDomUtils.openModal({ + const succeed = await CoreModals.openModal({ component: CoreDataPrivacyContactDPOComponent, }); @@ -139,7 +140,7 @@ export class CoreDataPrivacyMainPage implements OnInit { await import('@features/dataprivacy/components/newrequest/newrequest'); // Create and show the modal. - const succeed = await CoreDomUtils.openModal({ + const succeed = await CoreModals.openModal({ component: CoreDataPrivacyNewRequestComponent, componentProps: { accessInfo: this.accessInfo, diff --git a/src/core/features/editor/components/components.module.ts b/src/core/features/editor/components/components.module.ts index 8bc9e4105..b5e3bfb65 100644 --- a/src/core/features/editor/components/components.module.ts +++ b/src/core/features/editor/components/components.module.ts @@ -24,8 +24,6 @@ import { CoreSharedModule } from '@/core/shared.module'; imports: [ CoreSharedModule, ], - providers: [ - ], exports: [ CoreEditorRichTextEditorComponent, ], 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 c611b2e4d..9a27b95d1 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 @@ -1045,7 +1045,7 @@ export class CoreEditorRichTextEditorComponent implements OnInit, AfterViewInit, * Window resized. */ protected async windowResized(): Promise { - await CoreDomUtils.waitForResizeDone(); + await CoreWait.waitForResizeDone(); this.isPhone = CoreScreen.isMobile; this.maximizeEditorSize(); diff --git a/src/core/features/fileuploader/services/fileuploader-helper.ts b/src/core/features/fileuploader/services/fileuploader-helper.ts index 1d6a8cf76..cbbad35a1 100644 --- a/src/core/features/fileuploader/services/fileuploader-helper.ts +++ b/src/core/features/fileuploader/services/fileuploader-helper.ts @@ -44,6 +44,7 @@ import { CorePath } from '@singletons/path'; import { CorePromisedValue } from '@classes/promised-value'; import { CorePlatform } from '@services/platform'; import { Chooser } from '@features/native/plugins'; +import { CoreToasts } from '@services/toasts'; /** * Helper service to upload files. @@ -457,7 +458,11 @@ export class CoreFileUploaderHelperProvider { await this.uploadGenericFile(CoreFile.getFileEntryURL(fileEntry), file.name, file.type, deleteAfterUpload, siteId); - CoreDomUtils.showToast('core.fileuploader.fileuploaded', true, undefined, 'core-toast-success'); + CoreToasts.show({ + message: 'core.fileuploader.fileuploaded', + translateMessage: true, + cssClass: 'core-toast-success', + }); } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'core.fileuploader.errorreadingfile', true); diff --git a/src/core/features/h5p/components/components.module.ts b/src/core/features/h5p/components/components.module.ts index 509b92edb..8e806fce4 100644 --- a/src/core/features/h5p/components/components.module.ts +++ b/src/core/features/h5p/components/components.module.ts @@ -26,8 +26,6 @@ import { CoreH5PIframeComponent } from './h5p-iframe/h5p-iframe'; imports: [ CoreSharedModule, ], - providers: [ - ], exports: [ CoreH5PPlayerComponent, CoreH5PIframeComponent, diff --git a/src/core/features/login/components/components.module.ts b/src/core/features/login/components/components.module.ts index 6407dd57b..1d2fc3fa7 100644 --- a/src/core/features/login/components/components.module.ts +++ b/src/core/features/login/components/components.module.ts @@ -14,14 +14,12 @@ import { NgModule } from '@angular/core'; import { CoreSharedModule } from '@/core/shared.module'; -import { CoreLoginSitesModalComponent } from './sites-modal/sites-modal'; import { CoreLoginMethodsComponent } from './login-methods/login-methods'; import { CoreLoginExceededAttemptsComponent } from '@features/login/components/exceeded-attempts/exceeded-attempts'; @NgModule({ declarations: [ CoreLoginExceededAttemptsComponent, - CoreLoginSitesModalComponent, CoreLoginMethodsComponent, ], imports: [ @@ -29,7 +27,6 @@ import { CoreLoginExceededAttemptsComponent } from '@features/login/components/e ], exports: [ CoreLoginExceededAttemptsComponent, - CoreLoginSitesModalComponent, CoreLoginMethodsComponent, ], }) diff --git a/src/core/features/login/components/sites-modal/sites-modal.ts b/src/core/features/login/components/sites-modal/sites-modal.ts index e938c4f7e..897f27487 100644 --- a/src/core/features/login/components/sites-modal/sites-modal.ts +++ b/src/core/features/login/components/sites-modal/sites-modal.ts @@ -21,6 +21,7 @@ import { CoreNavigator } from '@services/navigator'; import { CoreFilter } from '@features/filter/services/filter'; import { CoreAnimations } from '@components/animations'; import { ModalController } from '@singletons'; +import { CoreSharedModule } from '@/core/shared.module'; /** * Modal that displays a list of sites to be able to enter or delete a site. @@ -29,6 +30,10 @@ import { ModalController } from '@singletons'; selector: 'core-login-sites-modal', templateUrl: 'sites-modal.html', animations: [CoreAnimations.SLIDE_IN_OUT, CoreAnimations.SHOW_HIDE], + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class CoreLoginSitesModalComponent implements OnInit { diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index b127025c0..49202fd68 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -46,6 +46,7 @@ import { CoreSitesFactory } from '@services/sites-factory'; import { ONBOARDING_DONE } from '@features/login/constants'; import { CoreUnauthenticatedSite } from '@classes/sites/unauthenticated-site'; import { CoreKeyboard } from '@singletons/keyboard'; +import { CoreModals } from '@services/modals'; /** * Site (url) chooser when adding a new site. @@ -260,7 +261,7 @@ export class CoreLoginSitePage implements OnInit { const { CoreLoginSiteHelpComponent } = await import('@features/login/components/site-help/site-help'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreLoginSiteHelpComponent, cssClass: 'core-modal-fullscreen', }); @@ -273,7 +274,7 @@ export class CoreLoginSitePage implements OnInit { const { CoreLoginSiteOnboardingComponent } = await import('@features/login/components/site-onboarding/site-onboarding'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreLoginSiteOnboardingComponent, cssClass: 'core-modal-fullscreen', }); diff --git a/src/core/features/mainmenu/components/components.module.ts b/src/core/features/mainmenu/components/components.module.ts index c81a44b1d..763cbd86a 100644 --- a/src/core/features/mainmenu/components/components.module.ts +++ b/src/core/features/mainmenu/components/components.module.ts @@ -15,14 +15,12 @@ import { NgModule } from '@angular/core'; import { CoreSharedModule } from '@/core/shared.module'; import { CoreMainMenuUserButtonComponent } from './user-menu-button/user-menu-button'; -import { CoreMainMenuUserMenuComponent } from './user-menu/user-menu'; import { CoreLoginComponentsModule } from '@features/login/components/components.module'; import { CoreMainMenuUserMenuTourComponent } from './user-menu-tour/user-menu-tour'; @NgModule({ declarations: [ CoreMainMenuUserButtonComponent, - CoreMainMenuUserMenuComponent, CoreMainMenuUserMenuTourComponent, ], imports: [ @@ -31,7 +29,6 @@ import { CoreMainMenuUserMenuTourComponent } from './user-menu-tour/user-menu-to ], exports: [ CoreMainMenuUserButtonComponent, - CoreMainMenuUserMenuComponent, CoreMainMenuUserMenuTourComponent, ], }) 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 e747efdeb..369dfc41e 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 @@ -19,9 +19,8 @@ import { CoreUserToursAlignment, CoreUserToursSide } from '@features/usertours/s import { IonRouterOutlet } from '@ionic/angular'; import { CoreScreen } from '@services/screen'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreMainMenuUserMenuTourComponent } from '../user-menu-tour/user-menu-tour'; -import { CoreMainMenuUserMenuComponent } from '../user-menu/user-menu'; import { CoreMainMenuPage } from '@features/mainmenu/pages/menu/menu'; /** @@ -62,11 +61,13 @@ export class CoreMainMenuUserButtonComponent implements OnInit { * * @param event Click event. */ - openUserMenu(event: Event): void { + async openUserMenu(event: Event): Promise { event.preventDefault(); event.stopPropagation(); - CoreDomUtils.openSideModal({ + const { CoreMainMenuUserMenuComponent } = await import('../user-menu/user-menu'); + + CoreModals.openSideModal({ component: CoreMainMenuUserMenuComponent, }); } diff --git a/src/core/features/mainmenu/components/user-menu/user-menu.ts b/src/core/features/mainmenu/components/user-menu/user-menu.ts index af928f3c7..6cedcae32 100644 --- a/src/core/features/mainmenu/components/user-menu/user-menu.ts +++ b/src/core/features/mainmenu/components/user-menu/user-menu.ts @@ -13,11 +13,11 @@ // limitations under the License. import { CoreConstants } from '@/core/constants'; +import { CoreSharedModule } from '@/core/shared.module'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { CoreSite } from '@classes/sites/site'; import { CoreSiteInfo } from '@classes/sites/unauthenticated-site'; import { CoreFilter } from '@features/filter/services/filter'; -import { CoreLoginSitesModalComponent } from '@features/login/components/sites-modal/sites-modal'; import { CoreLoginHelper } from '@features/login/services/login-helper'; import { CoreUserAuthenticatedSupportConfig } from '@features/user/classes/support/authenticated-support-config'; import { CoreUserSupport } from '@features/user/services/support'; @@ -28,6 +28,7 @@ import { CoreUserProfileHandlerType, CoreUserDelegateContext, } from '@features/user/services/user-delegate'; +import { CoreModals } from '@services/modals'; import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; @@ -41,7 +42,11 @@ import { Subscription } from 'rxjs'; @Component({ selector: 'core-main-menu-user-menu', templateUrl: 'user-menu.html', - styleUrls: ['user-menu.scss'], + styleUrl: 'user-menu.scss', + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy { @@ -248,7 +253,9 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy { event.preventDefault(); event.stopPropagation(); - const closeAll = await CoreDomUtils.openSideModal({ + const { CoreLoginSitesModalComponent } = await import('@features/login/components/sites-modal/sites-modal'); + + const closeAll = await CoreModals.openSideModal({ component: CoreLoginSitesModalComponent, cssClass: 'core-modal-lateral core-modal-lateral-sm', }); diff --git a/src/core/features/policy/pages/acceptances/acceptances.ts b/src/core/features/policy/pages/acceptances/acceptances.ts index 3344c6957..9f4513565 100644 --- a/src/core/features/policy/pages/acceptances/acceptances.ts +++ b/src/core/features/policy/pages/acceptances/acceptances.ts @@ -26,6 +26,7 @@ import { Subscription } from 'rxjs'; import { CORE_DATAPRIVACY_FEATURE_NAME, CORE_DATAPRIVACY_PAGE_NAME } from '@features/dataprivacy/constants'; import { CoreNavigator } from '@services/navigator'; import { CoreDataPrivacy } from '@features/dataprivacy/services/dataprivacy'; +import { CoreModals } from '@services/modals'; /** * Page to view user acceptances. @@ -194,7 +195,7 @@ export class CorePolicyAcceptancesPage implements OnInit, OnDestroy { const { CorePolicyViewPolicyModalComponent } = await import('@features/policy/components/policy-modal/policy-modal'); - CoreDomUtils.openModal({ + CoreModals.openModal({ component: CorePolicyViewPolicyModalComponent, componentProps: { policy }, }); diff --git a/src/core/features/policy/pages/site-policy/site-policy.ts b/src/core/features/policy/pages/site-policy/site-policy.ts index 46e65efb1..e59851459 100644 --- a/src/core/features/policy/pages/site-policy/site-policy.ts +++ b/src/core/features/policy/pages/site-policy/site-policy.ts @@ -31,6 +31,7 @@ import { CoreScreen } from '@services/screen'; import { Subscription } from 'rxjs'; import { CoreDom } from '@singletons/dom'; import { CoreWait } from '@singletons/wait'; +import { CoreModals } from '@services/modals'; /** * Page to accept a site policy. @@ -468,7 +469,7 @@ export class CorePolicySitePolicyPage implements OnInit, OnDestroy { const { CorePolicyViewPolicyModalComponent } = await import('@features/policy/components/policy-modal/policy-modal'); - CoreDomUtils.openModal({ + CoreModals.openModal({ component: CorePolicyViewPolicyModalComponent, componentProps: { policy }, }); diff --git a/src/core/features/rating/components/aggregate/aggregate.ts b/src/core/features/rating/components/aggregate/aggregate.ts index 8f81aac08..7837e6343 100644 --- a/src/core/features/rating/components/aggregate/aggregate.ts +++ b/src/core/features/rating/components/aggregate/aggregate.ts @@ -20,8 +20,8 @@ import { CoreRatingInfoItem, CoreRatingProvider, } from '@features/rating/services/rating'; +import { CoreModals } from '@services/modals'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils } from '@services/utils/dom'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; /** @@ -120,7 +120,7 @@ export class CoreRatingAggregateComponent implements OnChanges, OnDestroy { const { CoreRatingRatingsComponent } = await import('@features/rating/components/ratings/ratings'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreRatingRatingsComponent, componentProps: { contextLevel: this.contextLevel, diff --git a/src/core/features/rating/components/rate/rate.ts b/src/core/features/rating/components/rate/rate.ts index fdd30b0e5..a7b9c562e 100644 --- a/src/core/features/rating/components/rate/rate.ts +++ b/src/core/features/rating/components/rate/rate.ts @@ -23,7 +23,8 @@ import { } from '@features/rating/services/rating'; import { CoreRatingOffline } from '@features/rating/services/rating-offline'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts, ToastDuration } from '@services/toasts'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; @@ -147,7 +148,11 @@ export class CoreRatingRateComponent implements OnChanges, OnDestroy { ); if (response === undefined) { - CoreDomUtils.showToast('core.datastoredoffline', true, ToastDuration.LONG); + CoreToasts.show({ + message: 'core.datastoredoffline', + translateMessage: true, + duration: ToastDuration.LONG, + }); } else { this.onUpdate.emit(); } diff --git a/src/core/features/reminders/components/set-button/set-button.ts b/src/core/features/reminders/components/set-button/set-button.ts index a775ad6a8..b63761b87 100644 --- a/src/core/features/reminders/components/set-button/set-button.ts +++ b/src/core/features/reminders/components/set-button/set-button.ts @@ -18,6 +18,7 @@ import { CoreDomUtils } from '@services/utils/dom'; import { CoreRemindersSetReminderMenuComponent } from '../set-reminder-menu/set-reminder-menu'; import { Translate } from '@singletons'; import { CoreTimeUtils } from '@services/utils/time'; +import { CoreToasts } from '@services/toasts'; /** * Component that displays a button to set a reminder. @@ -127,7 +128,10 @@ export class CoreRemindersSetButtonComponent implements OnInit { if (timebefore === undefined || timebefore === CoreRemindersService.DISABLED) { this.setTimebefore(undefined); - CoreDomUtils.showToast('core.reminders.reminderunset', true); + CoreToasts.show({ + message: 'core.reminders.reminderunset', + translateMessage: true, + }); return; } @@ -148,8 +152,8 @@ export class CoreRemindersSetButtonComponent implements OnInit { await CoreReminders.addReminder(reminder); const time = this.time - timebefore; - const text = Translate.instant('core.reminders.reminderset', { $a: CoreTimeUtils.userDate(time * 1000) }); - CoreDomUtils.showToast(text); + const message = Translate.instant('core.reminders.reminderset', { $a: CoreTimeUtils.userDate(time * 1000) }); + CoreToasts.show({ message }); } } diff --git a/src/core/features/reportbuilder/components/components.module.ts b/src/core/features/reportbuilder/components/components.module.ts index f8f269fc3..958aaaf4f 100644 --- a/src/core/features/reportbuilder/components/components.module.ts +++ b/src/core/features/reportbuilder/components/components.module.ts @@ -16,7 +16,6 @@ import { NgModule } from '@angular/core'; import { CoreSharedModule } from '@/core/shared.module'; import { CoreReportBuilderReportColumnComponent } from './report-column/report-column'; import { CoreReportBuilderReportDetailComponent } from './report-detail/report-detail'; -import { CoreReportBuilderReportSummaryComponent } from './report-summary/report-summary'; @NgModule({ imports: [ @@ -25,12 +24,10 @@ import { CoreReportBuilderReportSummaryComponent } from './report-summary/report declarations: [ CoreReportBuilderReportDetailComponent, CoreReportBuilderReportColumnComponent, - CoreReportBuilderReportSummaryComponent, ], exports: [ CoreReportBuilderReportDetailComponent, CoreReportBuilderReportColumnComponent, - CoreReportBuilderReportSummaryComponent, ], }) export class CoreReportBuilderComponentsModule {} 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 a08e8cd95..13b3650c5 100644 --- a/src/core/features/reportbuilder/components/report-summary/report-summary.ts +++ b/src/core/features/reportbuilder/components/report-summary/report-summary.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import { CoreSharedModule } from '@/core/shared.module'; import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { CoreReportBuilderReportDetail } from '@features/reportbuilder/services/reportbuilder'; import { CoreFormatDatePipe } from '@pipes/format-date'; @@ -21,8 +22,12 @@ import { ModalController } from '@singletons'; @Component({ selector: 'core-report-builder-report-summary', templateUrl: './report-summary.html', - styleUrls: ['./report-summary.scss'], + styleUrl: './report-summary.scss', changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class CoreReportBuilderReportSummaryComponent implements OnInit { @@ -30,6 +35,9 @@ export class CoreReportBuilderReportSummaryComponent implements OnInit { reportUrl!: string; reportDetailToDisplay!: { title: string; text: string }[]; + /** + * @inheritdoc + */ ngOnInit(): void { const formatDate = new CoreFormatDatePipe(); const site = CoreSites.getRequiredCurrentSite(); @@ -54,6 +62,9 @@ export class CoreReportBuilderReportSummaryComponent implements OnInit { ]; } + /** + * Close the modal. + */ closeModal(): void { ModalController.dismiss(); } diff --git a/src/core/features/reportbuilder/pages/report/report.ts b/src/core/features/reportbuilder/pages/report/report.ts index 958509675..1321e4629 100644 --- a/src/core/features/reportbuilder/pages/report/report.ts +++ b/src/core/features/reportbuilder/pages/report/report.ts @@ -13,10 +13,9 @@ // limitations under the License. import { Component, OnInit } from '@angular/core'; -import { CoreReportBuilderReportSummaryComponent } from '@features/reportbuilder/components/report-summary/report-summary'; import { CoreReportBuilderReportDetail } from '@features/reportbuilder/services/reportbuilder'; +import { CoreModals } from '@services/modals'; import { CoreNavigator } from '@services/navigator'; -import { CoreDomUtils } from '@services/utils/dom'; @Component({ selector: 'core-report-builder-report', @@ -26,6 +25,7 @@ export class CoreReportBuilderReportPage implements OnInit { reportId!: string; reportDetail?: CoreReportBuilderReportDetail; + /** * @inheritdoc */ @@ -42,8 +42,14 @@ export class CoreReportBuilderReportPage implements OnInit { this.reportDetail = reportDetail; } - openInfo(): void { - CoreDomUtils.openSideModal({ + /** + * Open the report info modal. + */ + async openInfo(): Promise { + const { CoreReportBuilderReportSummaryComponent } = + await import('@features/reportbuilder/components/report-summary/report-summary'); + + CoreModals.openSideModal({ component: CoreReportBuilderReportSummaryComponent, componentProps: { reportDetail: this.reportDetail }, }); 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 75eae485b..dbd15dc0a 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 @@ -23,6 +23,7 @@ import { import { CoreEvents } from '@singletons/events'; import { ModalController } from '@singletons'; import { CoreUtils } from '@services/utils/utils'; +import { CoreSharedModule } from '@/core/shared.module'; type Filter = T & { checked: boolean }; @@ -30,6 +31,10 @@ type Filter = T & { checked: boolean }; selector: 'core-search-global-search-filters', templateUrl: 'global-search-filters.html', styleUrls: ['./global-search-filters.scss'], + standalone: true, + imports: [ + CoreSharedModule, + ], }) export class CoreSearchGlobalSearchFiltersComponent implements OnInit { diff --git a/src/core/features/search/components/global-search-filters/global-search-filters.module.ts b/src/core/features/search/components/global-search-filters/global-search-filters.module.ts deleted file mode 100644 index 0cd203468..000000000 --- a/src/core/features/search/components/global-search-filters/global-search-filters.module.ts +++ /dev/null @@ -1,30 +0,0 @@ -// (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. - -import { CoreSharedModule } from '@/core/shared.module'; -import { NgModule } from '@angular/core'; - -import { CoreSearchGlobalSearchFiltersComponent } from './global-search-filters.component'; - -export { CoreSearchGlobalSearchFiltersComponent }; - -@NgModule({ - imports: [ - CoreSharedModule, - ], - declarations: [ - CoreSearchGlobalSearchFiltersComponent, - ], -}) -export class CoreSearchGlobalSearchFiltersComponentModule {} diff --git a/src/core/features/search/pages/global-search/global-search.ts b/src/core/features/search/pages/global-search/global-search.ts index c67d2abfc..00451e924 100644 --- a/src/core/features/search/pages/global-search/global-search.ts +++ b/src/core/features/search/pages/global-search/global-search.ts @@ -29,6 +29,7 @@ import { } from '@features/search/services/global-search'; import { CoreNavigator } from '@services/navigator'; import { CoreSearchBoxComponent } from '@features/search/components/search-box/search-box'; +import { CoreModals } from '@services/modals'; @Component({ selector: 'page-core-search-global-search', @@ -137,9 +138,9 @@ export class CoreSearchGlobalSearchPage implements OnInit, OnDestroy, AfterViewI */ async openFilters(): Promise { const { CoreSearchGlobalSearchFiltersComponent } = - await import('@features/search/components/global-search-filters/global-search-filters.module'); + await import('@features/search/components/global-search-filters/global-search-filters.component'); - await CoreDomUtils.openSideModal({ + await CoreModals.openSideModal({ component: CoreSearchGlobalSearchFiltersComponent, componentProps: { hideCourses: !!this.courseId, diff --git a/src/core/features/settings/pages/dev/dev.ts b/src/core/features/settings/pages/dev/dev.ts index ce9bac44b..8b2888399 100644 --- a/src/core/features/settings/pages/dev/dev.ts +++ b/src/core/features/settings/pages/dev/dev.ts @@ -24,7 +24,8 @@ import { CoreFile } from '@services/file'; import { CoreNavigator } from '@services/navigator'; import { CorePlatform } from '@services/platform'; import { CoreSites } from '@services/sites'; -import { CoreDomUtils, ToastDuration } from '@services/utils/dom'; +import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts, ToastDuration } from '@services/toasts'; import { CoreText } from '@singletons/text'; /** @@ -177,7 +178,7 @@ export class CoreSettingsDevPage implements OnInit { await CoreConfig.delete(ONBOARDING_DONE); await CoreConfig.delete(FAQ_QRCODE_INFO_DONE); - CoreDomUtils.showToast('User tours have been reseted'); + CoreToasts.show({ message: 'User tours have been reseted' }); } /** @@ -194,7 +195,10 @@ export class CoreSettingsDevPage implements OnInit { return; } - await CoreDomUtils.showToast('Caches invalidated', true, ToastDuration.LONG); + await CoreToasts.show({ + message: 'Caches invalidated', + duration: ToastDuration.LONG, + }); } /** @@ -205,7 +209,7 @@ export class CoreSettingsDevPage implements OnInit { await CoreFile.clearDeletedSitesFolder(sites); await CoreFile.clearTmpFolder(); - CoreDomUtils.showToast('File storage cleared'); + CoreToasts.show({ message: 'File storage cleared' }); } async setEnabledStagingSites(enabled: boolean): Promise { diff --git a/src/core/features/settings/pages/deviceinfo/deviceinfo.ts b/src/core/features/settings/pages/deviceinfo/deviceinfo.ts index 815976b56..fac179b89 100644 --- a/src/core/features/settings/pages/deviceinfo/deviceinfo.ts +++ b/src/core/features/settings/pages/deviceinfo/deviceinfo.ts @@ -23,7 +23,7 @@ import { CoreUtils } from '@services/utils/utils'; import { Subscription } from 'rxjs'; import { CorePushNotifications } from '@features/pushnotifications/services/pushnotifications'; import { CoreConfig } from '@services/config'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts } from '@services/toasts'; import { CoreNavigator } from '@services/navigator'; import { CorePlatform } from '@services/platform'; import { CoreNetwork } from '@services/network'; @@ -86,9 +86,6 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { protected onlineObserver?: Subscription; constructor() { - const sitesProvider = CoreSites.instance; - const device = Device.instance; - const translate = Translate.instance; const navigator = window.navigator; this.deviceInfo = { @@ -128,7 +125,7 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { this.deviceOsTranslated = matches[1]; } else { this.deviceInfo.deviceOs = 'unknown'; - this.deviceOsTranslated = translate.instant('core.unknown'); + this.deviceOsTranslated = Translate.instant('core.unknown'); } } } else { @@ -139,39 +136,35 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { this.deviceOsTranslated = matches[1]; } else { this.deviceInfo.deviceOs = 'unknown'; - this.deviceOsTranslated = translate.instant('core.unknown'); + this.deviceOsTranslated = Translate.instant('core.unknown'); } } - if (navigator) { - if (navigator.userAgent) { - this.deviceInfo.userAgent = navigator.userAgent; - } - - if (navigator.language) { - this.deviceInfo.browserLanguage = navigator.language; - } + if (navigator.userAgent) { + this.deviceInfo.userAgent = navigator.userAgent; } - if (device) { - if (device.cordova) { - this.deviceInfo.cordovaVersion = device.cordova; - } - if (device.platform) { - this.deviceInfo.platform = device.platform; - } - if (device.version) { - this.deviceInfo.osVersion = device.version; - } - if (device.model) { - this.deviceInfo.model = device.model; - } - if (device.uuid) { - this.deviceInfo.uuid = device.uuid; - } + if (navigator.language) { + this.deviceInfo.browserLanguage = navigator.language; } - const currentSite = sitesProvider.getCurrentSite(); + if (Device.cordova) { + this.deviceInfo.cordovaVersion = Device.cordova; + } + if (Device.platform) { + this.deviceInfo.platform = Device.platform; + } + if (Device.version) { + this.deviceInfo.osVersion = Device.version; + } + if (Device.model) { + this.deviceInfo.model = Device.model; + } + if (Device.uuid) { + this.deviceInfo.uuid = Device.uuid; + } + + const currentSite = CoreSites.getCurrentSite(); this.deviceInfo.siteId = currentSite?.getId(); this.deviceInfo.siteVersion = currentSite?.getInfo()?.release; @@ -190,14 +183,11 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { * Async part of the constructor. */ protected async asyncInit(): Promise { - const sitesProvider = CoreSites.instance; - const fileProvider = CoreFile.instance; - const lang = await CoreLang.getCurrentLanguage(); this.deviceInfo.currentLanguage = lang; this.currentLangName = CoreConstants.CONFIG.languages[lang]; - const currentSite = sitesProvider.getCurrentSite(); + const currentSite = CoreSites.getCurrentSite(); const isSingleFixedSite = await CoreLoginHelper.isSingleFixedSite(); const sites = await CoreLoginHelper.getAvailableSites(); const firstUrl = isSingleFixedSite && sites[0].url; @@ -207,10 +197,10 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { this.displaySiteUrl = !!this.deviceInfo.siteUrl && (currentSite ?? CoreSitesFactory.makeUnauthenticatedSite(this.deviceInfo.siteUrl)).shouldDisplayInformativeLinks(); - if (fileProvider.isAvailable()) { - const basepath = await fileProvider.getBasePath(); + if (CoreFile.isAvailable()) { + const basepath = await CoreFile.getBasePath(); this.deviceInfo.fileSystemRoot = basepath; - this.fsClickable = fileProvider.usesHTMLAPI(); + this.fsClickable = CoreFile.usesHTMLAPI(); } const showDevOptionsOnConfig = await CoreConfig.get('showDevOptions', 0); @@ -265,7 +255,10 @@ export class CoreSettingsDeviceInfoPage implements OnDestroy { this.showDevOptions = true; await CoreConfig.set('showDevOptions', 1); - CoreDomUtils.showToast('core.settings.youradev', true); + CoreToasts.show({ + message: 'core.settings.youradev', + translateMessage: true, + }); } else { this.showDevOptions = false; await CoreConfig.delete('showDevOptions'); diff --git a/src/core/features/settings/pages/site/site.ts b/src/core/features/settings/pages/site/site.ts index 32c0afa5f..a3575362c 100644 --- a/src/core/features/settings/pages/site/site.ts +++ b/src/core/features/settings/pages/site/site.ts @@ -29,6 +29,7 @@ import { NgZone } from '@singletons'; import { CoreConstants } from '@/core/constants'; import { CoreConfig } from '@services/config'; import { CoreSettingsHandlersSource } from '@features/settings/classes/settings-handlers-source'; +import { CoreToasts } from '@services/toasts'; /** * Page that displays the list of site settings pages. @@ -117,7 +118,10 @@ export class CoreSitePreferencesPage implements AfterViewInit, OnDestroy { // Using syncOnlyOnWifi false to force manual sync. await CoreSettingsHelper.synchronizeSite(false, this.siteId); - CoreDomUtils.showToast('core.settings.sitesynccompleted', true); + CoreToasts.show({ + message: 'core.settings.sitesynccompleted', + translateMessage: true, + }); } catch (error) { if (this.isDestroyed) { return; diff --git a/src/core/features/settings/pages/synchronization/synchronization.ts b/src/core/features/settings/pages/synchronization/synchronization.ts index 2bf02cdbf..2b778e6d3 100644 --- a/src/core/features/settings/pages/synchronization/synchronization.ts +++ b/src/core/features/settings/pages/synchronization/synchronization.ts @@ -25,6 +25,7 @@ import { CoreAccountsList, CoreLoginHelper } from '@features/login/services/logi import { CoreNetwork } from '@services/network'; import { Subscription } from 'rxjs'; import { CoreNavigator } from '@services/navigator'; +import { CoreToasts } from '@services/toasts'; /** * Page that displays the synchronization settings. @@ -132,7 +133,10 @@ export class CoreSettingsSynchronizationPage implements OnInit, OnDestroy { try { await CoreSettingsHelper.synchronizeSite(false, siteId); - CoreDomUtils.showToast('core.settings.sitesynccompleted', true); + CoreToasts.show({ + message: 'core.settings.sitesynccompleted', + translateMessage: true, + }); } catch (error) { if (this.isDestroyed) { return; diff --git a/src/core/features/settings/services/settings-helper.ts b/src/core/features/settings/services/settings-helper.ts index 47444868b..25bc2400a 100644 --- a/src/core/features/settings/services/settings-helper.ts +++ b/src/core/features/settings/services/settings-helper.ts @@ -136,11 +136,10 @@ export class CoreSettingsHelperProvider { // Clear cache tables. const cleanSchemas = CoreSites.getSiteTableSchemasToClear(site); const promises: Promise[] = cleanSchemas.map((name) => site.getDb().deleteRecords(name)); - const filepoolService = CoreFilepool.instance; promises.push(site.deleteFolder().then(() => { - filepoolService.clearAllPackagesStatus(siteId); - filepoolService.clearFilepool(siteId); + CoreFilepool.clearAllPackagesStatus(siteId); + CoreFilepool.clearFilepool(siteId); CoreCourse.clearAllCoursesStatus(siteId); siteInfo.spaceUsage = 0; @@ -149,7 +148,7 @@ export class CoreSettingsHelperProvider { }).catch(async (error) => { if (error && error.code === FileError.NOT_FOUND_ERR) { // Not found, set size 0. - filepoolService.clearAllPackagesStatus(siteId); + CoreFilepool.clearAllPackagesStatus(siteId); siteInfo.spaceUsage = 0; } else { // Error, recalculate the site usage. diff --git a/src/core/features/sharedfiles/services/sharedfiles-helper.ts b/src/core/features/sharedfiles/services/sharedfiles-helper.ts index ba178ba95..0c8613bcb 100644 --- a/src/core/features/sharedfiles/services/sharedfiles-helper.ts +++ b/src/core/features/sharedfiles/services/sharedfiles-helper.ts @@ -30,6 +30,7 @@ import { SHAREDFILES_PAGE_NAME } from '../constants'; import { CoreSharedFilesChooseSitePage } from '../pages/choose-site/choose-site'; import { CoreError } from '@classes/errors/error'; import { CorePlatform } from '@services/platform'; +import { CoreModals } from '@services/modals'; /** * Helper service to share files with the app. @@ -152,7 +153,7 @@ export class CoreSharedFilesHelperProvider { const { CoreSharedFilesListModalComponent } = await import('@features/sharedfiles/components/list-modal/list-modal'); - const file = await CoreDomUtils.openModal({ + const file = await CoreModals.openModal({ component: CoreSharedFilesListModalComponent, cssClass: 'core-modal-fullscreen', componentProps: { mimetypes, pick: true }, diff --git a/src/core/features/sitehome/pages/index/index.ts b/src/core/features/sitehome/pages/index/index.ts index 508e2fcc1..8e116aabf 100644 --- a/src/core/features/sitehome/pages/index/index.ts +++ b/src/core/features/sitehome/pages/index/index.ts @@ -30,8 +30,8 @@ import { CoreBlockHelper } from '@features/block/services/block-helper'; import { CoreUtils } from '@services/utils/utils'; import { CoreTime } from '@singletons/time'; import { CoreAnalytics, CoreAnalyticsEventType } from '@services/analytics'; -import { CoreBlockSideBlocksComponent } from '@features/block/components/side-blocks/side-blocks'; import { ContextLevel } from '@/core/constants'; +import { CoreModals } from '@services/modals'; /** * Page that displays site home index. @@ -227,19 +227,22 @@ export class CoreSiteHomeIndexPage implements OnInit, OnDestroy { /** * Check whether there is a focused instance in the page parameters and open it. */ - private openFocusedInstance() { + private async openFocusedInstance() { const blockInstanceId = CoreNavigator.getRouteNumberParam('blockInstanceId'); - - if (blockInstanceId) { - CoreDomUtils.openSideModal({ - component: CoreBlockSideBlocksComponent, - componentProps: { - contextLevel: ContextLevel.COURSE, - instanceId: this.siteHomeId, - initialBlockInstanceId: blockInstanceId, - }, - }); + if (!blockInstanceId) { + return; } + + const { CoreBlockSideBlocksComponent } = await import('@features/block/components/side-blocks/side-blocks'); + + CoreModals.openSideModal({ + component: CoreBlockSideBlocksComponent, + componentProps: { + contextLevel: ContextLevel.COURSE, + instanceId: this.siteHomeId, + initialBlockInstanceId: blockInstanceId, + }, + }); } } 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 f7e5a0180..6d6291235 100644 --- a/src/core/features/siteplugins/components/module-index/module-index.ts +++ b/src/core/features/siteplugins/components/module-index/module-index.ts @@ -15,10 +15,7 @@ import { Component, OnInit, OnDestroy, Input, ViewChild, HostBinding } from '@angular/core'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; -import { - CoreCourseModuleSummaryResult, - CoreCourseModuleSummaryComponent, -} from '@features/course/components/module-summary/module-summary'; +import { CoreCourseModuleSummaryResult } from '@features/course/components/module-summary/module-summary'; import { CoreCourse } from '@features/course/services/course'; import { CoreCourseModuleData } from '@features/course/services/course-helper'; import { @@ -30,7 +27,7 @@ import { CoreSitePluginsContent, CoreSitePluginsCourseModuleHandlerData, } from '@features/siteplugins/services/siteplugins'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreUtils } from '@services/utils/utils'; import { CoreSitePluginsPluginContentComponent, CoreSitePluginsPluginContentLoadedData } from '../plugin-content/plugin-content'; @@ -157,7 +154,9 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C return; } - const data = await CoreDomUtils.openSideModal({ + const { CoreCourseModuleSummaryComponent } = await import('@features/course/components/module-summary/module-summary'); + + const data = await CoreModals.openSideModal({ component: CoreCourseModuleSummaryComponent, componentProps: { moduleId: this.module.id, diff --git a/src/core/features/siteplugins/directives/call-ws.ts b/src/core/features/siteplugins/directives/call-ws.ts index 6c232973e..fc5bc0d3a 100644 --- a/src/core/features/siteplugins/directives/call-ws.ts +++ b/src/core/features/siteplugins/directives/call-ws.ts @@ -15,7 +15,7 @@ import { Directive, Input, ElementRef, Optional } from '@angular/core'; import { Translate } from '@singletons'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts } from '@services/toasts'; import { CoreUtils } from '@services/utils/utils'; import { CoreNavigator } from '@services/navigator'; import { CoreSitePluginsCallWSOnClickBaseDirective } from '../classes/call-ws-click-directive'; @@ -74,7 +74,7 @@ export class CoreSitePluginsCallWSDirective extends CoreSitePluginsCallWSOnClick if (this.successMessage !== undefined) { // Display the success message. - CoreDomUtils.showToast(this.successMessage || Translate.instant('core.success')); + CoreToasts.show({ message: this.successMessage || Translate.instant('core.success') }); } } diff --git a/src/core/services/modals.ts b/src/core/services/modals.ts index 78a1f2bf6..13df097d7 100644 --- a/src/core/services/modals.ts +++ b/src/core/services/modals.ts @@ -14,10 +14,19 @@ import { Constructor } from '@/core/utils/types'; import { Injectable } from '@angular/core'; +import { NavigationStart } from '@angular/router'; import { CoreModalComponent } from '@classes/modal-component'; +import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; import { CoreSheetModalComponent } from '@components/sheet-modal/sheet-modal'; -import { AngularFrameworkDelegate, makeSingleton } from '@singletons'; +import { AngularFrameworkDelegate, makeSingleton, ModalController, Router } from '@singletons'; import { CoreDirectivesRegistry } from '@singletons/directives-registry'; +import { Subscription, filter } from 'rxjs'; +import { Md5 } from 'ts-md5'; +import { fixOverlayAriaHidden } from '../utils/fix-aria-hidden'; +import { ModalOptions } from '@ionic/angular'; +import { CoreCanceledError } from '@classes/errors/cancelederror'; +import { CoreWSError } from '@classes/errors/wserror'; +import { CorePasswordModalResponse, CorePasswordModalParams } from '@components/password-modal/password-modal'; /** * Handles application modals. @@ -25,6 +34,8 @@ import { CoreDirectivesRegistry } from '@singletons/directives-registry'; @Injectable({ providedIn: 'root' }) export class CoreModalsService { + protected displayedModals: Record = {}; // To prevent duplicated modals. + /** * Get index of the overlay on top of the stack. * @@ -84,6 +95,118 @@ export class CoreModalsService { return modal.result; } -} + /** + * Opens a Modal. + * + * @param options Modal Options. + * @returns The modal data when the modal closes. + */ + async openModal( + options: OpenModalOptions, + ): Promise { + const { waitForDismissCompleted, closeOnNavigate, ...modalOptions } = options; + const listenCloseEvents = closeOnNavigate ?? true; // Default to true. + // TODO: Improve this if we need two modals with same component open at the same time. + const modalId = Md5.hashAsciiStr(options.component?.toString() || ''); + const alreadyDisplayed = !!this.displayedModals[modalId]; + + const modal = alreadyDisplayed + ? this.displayedModals[modalId] + : await ModalController.create(modalOptions); + + let navSubscription: Subscription | undefined; + + // Get the promise before presenting to get result if modal is suddenly hidden. + const resultPromise = waitForDismissCompleted ? modal.onDidDismiss() : modal.onWillDismiss(); + + if (!this.displayedModals[modalId]) { + // Store the modal and remove it when dismissed. + this.displayedModals[modalId] = modal; + + if (listenCloseEvents) { + // Listen navigation events to close modals. + navSubscription = Router.events + .pipe(filter(event => event instanceof NavigationStart)) + .subscribe(async () => { + modal.dismiss(); + }); + } + + await modal.present(); + } + + if (!alreadyDisplayed) { + fixOverlayAriaHidden(modal); + } + + const result = await resultPromise; + + navSubscription?.unsubscribe(); + delete this.displayedModals[modalId]; + + if (result?.data) { + return result?.data; + } + } + + /** + * Opens a side Modal. + * + * @param options Modal Options. + * @returns The modal data when the modal closes. + */ + async openSideModal( + options: OpenModalOptions, + ): Promise { + + options = Object.assign({ + cssClass: 'core-modal-lateral', + showBackdrop: true, + backdropDismiss: true, + enterAnimation: CoreModalLateralTransitionEnter, + leaveAnimation: CoreModalLateralTransitionLeave, + }, options); + + return this.openModal(options); + } + + /** + * Prompts password to the user and returns the entered text. + * + * @param passwordParams Params to show the modal. + * @returns Entered password, error and validation. + */ + async promptPassword(passwordParams?: CorePasswordModalParams): Promise { + const { CorePasswordModalComponent } = + await import('@/core/components/password-modal/password-modal.module'); + + const modalData = await CoreModals.openModal( + { + cssClass: 'core-password-modal', + showBackdrop: true, + backdropDismiss: true, + component: CorePasswordModalComponent, + componentProps: passwordParams, + }, + ); + + if (modalData === undefined) { + throw new CoreCanceledError(); + } else if (modalData instanceof CoreWSError) { + throw modalData; + } + + return modalData; + } + +} export const CoreModals = makeSingleton(CoreModalsService); + +/** + * Options for the openModal function. + */ +export type OpenModalOptions = ModalOptions & { + waitForDismissCompleted?: boolean; + closeOnNavigate?: boolean; // Default true. +}; diff --git a/src/core/services/toasts.ts b/src/core/services/toasts.ts new file mode 100644 index 000000000..683f9496d --- /dev/null +++ b/src/core/services/toasts.ts @@ -0,0 +1,75 @@ +// (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. + +import { CoreConstants } from '@/core/constants'; +import { Injectable } from '@angular/core'; +import { ToastOptions } from '@ionic/angular'; +import { Translate, ToastController, makeSingleton } from '@singletons'; +import { fixOverlayAriaHidden } from '@/core/utils/fix-aria-hidden'; + +/** + * Handles application toasts. + */ +@Injectable({ providedIn: 'root' }) +export class CoreToastsService { + + /** + * Displays an autodimissable toast modal window. + * + * @param options Options. + * @returns Promise resolved with Toast instance. + */ + async show(options: ShowToastOptions): Promise { + if (options.translateMessage && typeof options.message === 'string') { + options.message = Translate.instant(options.message); + } + + options.duration = options.duration ?? ToastDuration.SHORT; + + // Convert some values and set default values. + const toastOptions: ToastOptions = { + ...options, + duration: CoreConstants.CONFIG.toastDurations[options.duration] ?? options.duration ?? 2000, + position: options.position ?? 'bottom', + }; + + const loader = await ToastController.create(toastOptions); + + await loader.present(); + + fixOverlayAriaHidden(loader); + + return loader; + } + +} + +export const CoreToasts = makeSingleton(CoreToastsService); + +/** + * Toast duration. + */ +export enum ToastDuration { + LONG = 'long', + SHORT = 'short', + STICKY = 'sticky', +} + +/** + * Options for showToastWithOptions. + */ +export type ShowToastOptions = Omit & { + duration?: ToastDuration | number; + translateMessage?: boolean; +}; diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index c00e2f88d..e5503e6ab 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -14,7 +14,7 @@ import { Injectable, SimpleChange, KeyValueChanges } from '@angular/core'; import { IonContent } from '@ionic/angular'; -import { ModalOptions, PopoverOptions, AlertOptions, AlertButton, TextFieldTypes, ToastOptions } from '@ionic/core'; +import { PopoverOptions, AlertOptions, AlertButton, TextFieldTypes } from '@ionic/core'; import { Md5 } from 'ts-md5'; import { CoreConfig } from '@services/config'; @@ -32,22 +32,13 @@ import { makeSingleton, Translate, AlertController, - ToastController, PopoverController, - ModalController, - Router, - ActionSheetController, - LoadingController, } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreFileSizeSum } from '@services/plugin-file-delegate'; import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreBSTooltipComponent } from '@components/bs-tooltip/bs-tooltip'; -import { CoreModalLateralTransitionEnter, CoreModalLateralTransitionLeave } from '@classes/modal-lateral-transition'; import { CoreSites } from '@services/sites'; -import { NavigationStart } from '@angular/router'; -import { filter } from 'rxjs/operators'; -import { Subscription } from 'rxjs'; import { CoreNetwork } from '@services/network'; import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreUserSupport } from '@features/user/services/support'; @@ -56,10 +47,12 @@ import { CorePlatform } from '@services/platform'; import { CoreCancellablePromise } from '@classes/cancellable-promise'; import { CoreLang } from '@services/lang'; import { CorePasswordModalParams, CorePasswordModalResponse } from '@components/password-modal/password-modal'; -import { CoreWSError } from '@classes/errors/wserror'; import { CoreErrorLogs } from '@singletons/error-logs'; import { CoreKeyboard } from '@singletons/keyboard'; import { CoreWait } from '@singletons/wait'; +import { CoreToasts, ToastDuration, ShowToastOptions } from '../toasts'; +import { fixOverlayAriaHidden } from '@/core/utils/fix-aria-hidden'; +import { CoreModals, OpenModalOptions } from '@services/modals'; /* * "Utils" service with helper functions for UI, DOM elements and HTML code. @@ -78,7 +71,6 @@ export class CoreDomUtilsProvider { protected matchesFunctionName?: string; // Name of the "matches" function to use when simulating a closest call. protected debugDisplay = false; // Whether to display debug messages. Store it in a variable to make it synchronous. protected displayedAlerts: Record = {}; // To prevent duplicated alerts. - protected displayedModals: Record = {}; // To prevent duplicated modals. protected activeLoadingModals: CoreIonLoadingElement[] = []; protected logger: CoreLogger; @@ -874,7 +866,7 @@ export class CoreDomUtilsProvider { alertMessageEl && this.treatAnchors(alertMessageEl); } - this.fixAriaHidden(alert); + fixOverlayAriaHidden(alert); return; }); @@ -1375,27 +1367,26 @@ export class CoreDomUtilsProvider { /** * Displays an autodimissable toast modal window. * - * @param text The text of the toast. - * @param needsTranslate Whether the 'text' needs to be translated. + * @param message The text of the toast. + * @param translateMessage Whether the 'text' needs to be translated. * @param duration Duration in ms of the dimissable toast. * @param cssClass Class to add to the toast. * @returns Toast instance. + * + * @deprecated since 4.5. Use CoreToasts.show instead. */ async showToast( - text: string, - needsTranslate?: boolean, + message: string, + translateMessage?: boolean, duration: ToastDuration | number = ToastDuration.SHORT, cssClass: string = '', ): Promise { - if (needsTranslate) { - text = Translate.instant(text); - } - - return this.showToastWithOptions({ - message: text, - duration: duration, + return CoreToasts.show({ + message, + translateMessage, + duration, + cssClass, position: 'bottom', - cssClass: cssClass, }); } @@ -1404,22 +1395,11 @@ export class CoreDomUtilsProvider { * * @param options Options. * @returns Promise resolved with Toast instance. + * + * @deprecated since 4.5. Use CoreToasts.show instead. */ async showToastWithOptions(options: ShowToastOptions): Promise { - // Convert some values and set default values. - const toastOptions: ToastOptions = { - ...options, - duration: CoreConstants.CONFIG.toastDurations[options.duration] ?? options.duration ?? 2000, - position: options.position ?? 'bottom', - }; - - const loader = await ToastController.create(toastOptions); - - await loader.present(); - - this.fixAriaHidden(loader); - - return loader; + return CoreToasts.show(options); } /** @@ -1478,80 +1458,13 @@ export class CoreDomUtilsProvider { * * @param options Modal Options. * @returns The modal data when the modal closes. + * + * @deprecated since 4.5. Use CoreModals.openModal instead. */ async openModal( options: OpenModalOptions, ): Promise { - const { waitForDismissCompleted, closeOnNavigate, ...modalOptions } = options; - const listenCloseEvents = closeOnNavigate ?? true; // Default to true. - - // TODO: Improve this if we need two modals with same component open at the same time. - const modalId = Md5.hashAsciiStr(options.component?.toString() || ''); - const alreadyDisplayed = !!this.displayedModals[modalId]; - - const modal = alreadyDisplayed - ? this.displayedModals[modalId] - : await ModalController.create(modalOptions); - - let navSubscription: Subscription | undefined; - - // Get the promise before presenting to get result if modal is suddenly hidden. - const resultPromise = waitForDismissCompleted ? modal.onDidDismiss() : modal.onWillDismiss(); - - if (!this.displayedModals[modalId]) { - // Store the modal and remove it when dismissed. - this.displayedModals[modalId] = modal; - - if (listenCloseEvents) { - // Listen navigation events to close modals. - navSubscription = Router.events - .pipe(filter(event => event instanceof NavigationStart)) - .subscribe(async () => { - modal.dismiss(); - }); - } - - await modal.present(); - } - - if (!alreadyDisplayed) { - this.fixAriaHidden(modal); - } - - const result = await resultPromise; - - navSubscription?.unsubscribe(); - delete this.displayedModals[modalId]; - - if (result?.data) { - return result?.data; - } - } - - /** - * Temporary fix to remove aria-hidden from ion-router-outlet if needed. It can be removed once the Ionic bug is fixed. - * https://github.com/ionic-team/ionic-framework/issues/29396 - * - * @param overlay Overlay dismissed. - */ - protected async fixAriaHidden( - overlay: HTMLIonModalElement | HTMLIonPopoverElement | HTMLIonAlertElement | HTMLIonToastElement, - ): Promise { - - await overlay.onDidDismiss(); - - const overlays = await Promise.all([ - ModalController.getTop(), - PopoverController.getTop(), - ActionSheetController.getTop(), - AlertController.getTop(), - LoadingController.getTop(), - ToastController.getTop(), - ]); - - if (!overlays.find(overlay => overlay !== undefined)) { - document.querySelector('ion-router-outlet')?.removeAttribute('aria-hidden'); - } + return CoreModals.openModal(options); } /** @@ -1559,20 +1472,13 @@ export class CoreDomUtilsProvider { * * @param options Modal Options. * @returns The modal data when the modal closes. + * + * @deprecated since 4.5. Use CoreModals.openSideModal instead. */ async openSideModal( options: OpenModalOptions, ): Promise { - - options = Object.assign({ - cssClass: 'core-modal-lateral', - showBackdrop: true, - backdropDismiss: true, - enterAnimation: CoreModalLateralTransitionEnter, - leaveAnimation: CoreModalLateralTransitionLeave, - }, options); - - return this.openModal(options); + return CoreModals.openSideModal(options); } /** @@ -1603,7 +1509,7 @@ export class CoreDomUtilsProvider { await popover.present(); - this.fixAriaHidden(popover); + fixOverlayAriaHidden(popover); return popover; } @@ -1613,28 +1519,11 @@ export class CoreDomUtilsProvider { * * @param passwordParams Params to show the modal. * @returns Entered password, error and validation. + * + * @deprecated since 4.5. Use CoreModals.promptPassword instead. */ async promptPassword(passwordParams?: CorePasswordModalParams): Promise { - const { CorePasswordModalComponent } = - await import('@/core/components/password-modal/password-modal.module'); - - const modalData = await CoreDomUtils.openModal( - { - cssClass: 'core-password-modal', - showBackdrop: true, - backdropDismiss: true, - component: CorePasswordModalComponent, - componentProps: passwordParams, - }, - ); - - if (modalData === undefined) { - throw new CoreCanceledError(); - } else if (modalData instanceof CoreWSError) { - throw modalData; - } - - return modalData; + return CoreModals.promptPassword(passwordParams); } /** @@ -1656,7 +1545,7 @@ export class CoreDomUtilsProvider { } const { CoreViewerImageComponent } = await import('@features/viewer/components/image/image'); - await CoreDomUtils.openModal({ + await CoreModals.openModal({ component: CoreViewerImageComponent, componentProps: { title, @@ -1754,24 +1643,11 @@ export class CoreDomUtilsProvider { * @param windowHeight Initial window height. * @param retries Number of retries done. * @returns Promise resolved when done. + * + * @deprecated since 4.5. Use CoreWait.waitForResizeDone instead. */ async waitForResizeDone(windowWidth?: number, windowHeight?: number, retries = 0): Promise { - if (!CorePlatform.isIOS()) { - return; // Only wait in iOS. - } - - windowWidth = windowWidth || window.innerWidth; - windowHeight = windowHeight || window.innerHeight; - - if (windowWidth != window.innerWidth || windowHeight != window.innerHeight || retries >= 10) { - // Window size changed or max number of retries reached, stop. - return; - } - - // Wait a bit and try again. - await CoreWait.wait(50); - - return this.waitForResizeDone(windowWidth, windowHeight, retries+1); + return CoreWait.waitForResizeDone(windowWidth, windowHeight, retries); } /** @@ -1817,14 +1693,6 @@ export type OpenPopoverOptions = Omit & { waitForDismissCompleted?: boolean; }; -/** - * Options for the openModal function. - */ -export type OpenModalOptions = ModalOptions & { - waitForDismissCompleted?: boolean; - closeOnNavigate?: boolean; // Default true. -}; - /** * Buttons for prompt alert. */ @@ -1841,19 +1709,3 @@ export enum VerticalPoint { MID = 'mid', BOTTOM = 'bottom', } - -/** - * Toast duration. - */ -export enum ToastDuration { - LONG = 'long', - SHORT = 'short', - STICKY = 'sticky', -} - -/** - * Options for showToastWithOptions. - */ -export type ShowToastOptions = Omit & { - duration: ToastDuration | number; -}; diff --git a/src/core/services/utils/mimetype.ts b/src/core/services/utils/mimetype.ts index 5bbf67724..3125c6bf9 100644 --- a/src/core/services/utils/mimetype.ts +++ b/src/core/services/utils/mimetype.ts @@ -16,7 +16,7 @@ import { Injectable } from '@angular/core'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { CoreFile } from '@services/file'; -import { CoreTextUtils } from '@services/utils/text'; +import { CoreText } from '@singletons/text'; import { makeSingleton, Translate } from '@singletons'; import { CoreLogger } from '@singletons/logger'; import { CoreWSFile } from '@services/ws'; @@ -466,7 +466,7 @@ export class CoreMimetypeUtilsProvider { const value = attr[key]; translateParams[key] = value; translateParams[key.toUpperCase()] = value.toUpperCase(); - translateParams[CoreTextUtils.ucFirst(key)] = CoreTextUtils.ucFirst(value); + translateParams[CoreText.capitalize(key)] = CoreText.capitalize(value); } // MIME types may include + symbol but this is not permitted in string ids. @@ -486,7 +486,7 @@ export class CoreMimetypeUtilsProvider { } if (capitalise) { - result = CoreTextUtils.ucFirst(result); + result = CoreText.capitalize(result); } return result; diff --git a/src/core/services/utils/text.ts b/src/core/services/utils/text.ts index a40bcdbd9..5215f87d0 100644 --- a/src/core/services/utils/text.ts +++ b/src/core/services/utils/text.ts @@ -21,13 +21,14 @@ import { DomSanitizer, makeSingleton, Translate } from '@singletons'; import { CoreWSFile } from '@services/ws'; import { Locutus } from '@singletons/locutus'; import { CoreFileHelper } from '@services/file-helper'; -import { CoreDomUtils } from './dom'; +import { CoreModals } from '@services/modals'; import { CoreUrl } from '@singletons/url'; import { AlertButton } from '@ionic/angular'; import { CorePath } from '@singletons/path'; import { CorePlatform } from '@services/platform'; import { ContextLevel } from '@/core/constants'; import { CoreDom } from '@singletons/dom'; +import { CoreText } from '@singletons/text'; /** * Different type of errors the app can treat. @@ -1007,9 +1008,10 @@ export class CoreTextUtilsProvider { * * @param text Text to treat. * @returns Treated text. + * @deprecated since 4.5. Use CoreText.capitalize instead. */ ucFirst(text: string): string { - return text.charAt(0).toUpperCase() + text.slice(1); + return CoreText.capitalize(text); } /** @@ -1048,7 +1050,7 @@ export class CoreTextUtilsProvider { ...options, }; - await CoreDomUtils.openModal(modalOptions); + await CoreModals.openModal(modalOptions); } } diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index cdced27db..0c1724eaf 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -20,7 +20,7 @@ import { CoreEvents } from '@singletons/events'; import { CoreFile } from '@services/file'; import { CoreLang } from '@services/lang'; import { CoreWS } from '@services/ws'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreModals } from '@services/modals'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreTextUtils } from '@services/utils/text'; import { makeSingleton, InAppBrowser, FileOpener, WebIntent, Translate, NgZone } from '@singletons'; @@ -1657,7 +1657,7 @@ export class CoreUtilsProvider { async scanQR(title?: string): Promise { const { CoreViewerQRScannerComponent } = await import('@features/viewer/components/qr-scanner/qr-scanner'); - return CoreDomUtils.openModal({ + return CoreModals.openModal({ component: CoreViewerQRScannerComponent, cssClass: 'core-modal-fullscreen', componentProps: { diff --git a/src/core/singletons/dom.ts b/src/core/singletons/dom.ts index 07c0c425e..8f962cc87 100644 --- a/src/core/singletons/dom.ts +++ b/src/core/singletons/dom.ts @@ -13,10 +13,10 @@ // limitations under the License. import { CoreCancellablePromise } from '@classes/cancellable-promise'; -import { CoreDomUtils } from '@services/utils/dom'; import { CoreUtils } from '@services/utils/utils'; import { CoreEventObserver } from '@singletons/events'; import { CorePlatform } from '@services/platform'; +import { CoreWait } from './wait'; /** * Singleton with helper functions for dom. @@ -214,7 +214,7 @@ export class CoreDom { */ static onWindowResize(resizeFunction: (ev?: Event) => void, debounceDelay = 20): CoreEventObserver { const resizeListener = CoreUtils.debounce(async (ev?: Event) => { - await CoreDomUtils.waitForResizeDone(); + await CoreWait.waitForResizeDone(); resizeFunction(ev); }, debounceDelay); diff --git a/src/core/singletons/text.ts b/src/core/singletons/text.ts index 100c9be74..0a60c5a48 100644 --- a/src/core/singletons/text.ts +++ b/src/core/singletons/text.ts @@ -13,7 +13,7 @@ // limitations under the License. import { Clipboard } from '@singletons'; -import { CoreDomUtils } from '@services/utils/dom'; +import { CoreToasts } from '@services/toasts'; /** * Singleton with helper functions for text manipulation. @@ -89,7 +89,20 @@ export class CoreText { } // Show toast using ionicLoading. - CoreDomUtils.showToast('core.copiedtoclipboard', true); + CoreToasts.show({ + message: 'core.copiedtoclipboard', + translateMessage: true, + }); + } + + /** + * Make a string's first character uppercase. + * + * @param text Text to treat. + * @returns Treated text. + */ + static capitalize(text: string): string { + return text.charAt(0).toUpperCase() + text.slice(1); } } diff --git a/src/core/singletons/wait.ts b/src/core/singletons/wait.ts index d2a633464..72e6c6ea8 100644 --- a/src/core/singletons/wait.ts +++ b/src/core/singletons/wait.ts @@ -13,6 +13,7 @@ // limitations under the License. import { CoreCancellablePromise } from '@classes/cancellable-promise'; +import { CorePlatform } from '@services/platform'; /** * Singleton with helper functions to wait. @@ -83,6 +84,34 @@ export class CoreWait { ); } + /** + * In iOS the resize event is triggered before the window size changes. Wait for the size to change. + * Use of this function is discouraged. Please use CoreDom.onWindowResize to check window resize event. + * + * @param windowWidth Initial window width. + * @param windowHeight Initial window height. + * @param retries Number of retries done. + * @returns Promise resolved when done. + */ + static async waitForResizeDone(windowWidth?: number, windowHeight?: number, retries = 0): Promise { + if (!CorePlatform.isIOS()) { + return; // Only wait in iOS. + } + + windowWidth = windowWidth || window.innerWidth; + windowHeight = windowHeight || window.innerHeight; + + if (windowWidth != window.innerWidth || windowHeight != window.innerHeight || retries >= 10) { + // Window size changed or max number of retries reached, stop. + return; + } + + // Wait a bit and try again. + await CoreWait.wait(50); + + return CoreWait.waitForResizeDone(windowWidth, windowHeight, retries+1); + } + } /** diff --git a/src/core/singletons/window.ts b/src/core/singletons/window.ts index c520b9741..c14b8de93 100644 --- a/src/core/singletons/window.ts +++ b/src/core/singletons/window.ts @@ -82,7 +82,7 @@ export class CoreWindow { if (!CoreFileHelper.isOpenableInApp({ filename })) { try { await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename }); - } catch (error) { + } catch { return; // Cancelled, stop. } } diff --git a/src/core/utils/fix-aria-hidden.ts b/src/core/utils/fix-aria-hidden.ts new file mode 100644 index 000000000..68ef2f85b --- /dev/null +++ b/src/core/utils/fix-aria-hidden.ts @@ -0,0 +1,50 @@ +// (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. + +import { + ActionSheetController, + AlertController, + LoadingController, + ModalController, + PopoverController, + ToastController, +} from '@singletons'; + +/** + * Temporary fix to remove aria-hidden from ion-router-outlet if needed. It can be removed once the Ionic bug is fixed. + * https://github.com/ionic-team/ionic-framework/issues/29396 + * + * !!! Only for internal use, this function will be removed without deprecation !!! + * + * @param overlay Overlay dismissed. + */ +export async function fixOverlayAriaHidden( + overlay: HTMLIonModalElement | HTMLIonPopoverElement | HTMLIonAlertElement | HTMLIonToastElement, +): Promise { + + await overlay.onDidDismiss(); + + const overlays = await Promise.all([ + ModalController.getTop(), + PopoverController.getTop(), + ActionSheetController.getTop(), + AlertController.getTop(), + LoadingController.getTop(), + ToastController.getTop(), + ]); + + if (!overlays.find(overlay => overlay !== undefined)) { + document.querySelector('ion-router-outlet')?.removeAttribute('aria-hidden'); + } +} diff --git a/src/types/config.d.ts b/src/types/config.d.ts index cda618cf6..e3de69599 100644 --- a/src/types/config.d.ts +++ b/src/types/config.d.ts @@ -18,7 +18,7 @@ import { CoreLoginSiteInfo, CoreSitesDemoSiteData } from '@services/sites'; import { OpenFileAction } from '@services/utils/utils'; import { CoreLoginSiteFinderSettings, CoreLoginSiteSelectorListMethod } from '@features/login/services/login-helper'; import { CoreDatabaseConfiguration } from '@classes/database/database-table'; -import { ToastDuration } from '@services/utils/dom'; +import { ToastDuration } from '@services/toasts'; /* eslint-disable @typescript-eslint/naming-convention */