diff --git a/jest.config.js b/jest.config.js index 4e39677f74e..fde4afd9cba 100644 --- a/jest.config.js +++ b/jest.config.js @@ -10,8 +10,5 @@ module.exports = { '!src/testing/**/*', ], transformIgnorePatterns: ['node_modules/(?!@stencil|@angular|@ionic|@moodlehq|@ngx-translate|swiper)'], - moduleNameMapper: { - ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/src/' }), - '^!raw-loader!.*': 'jest-raw-loader', - }, + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/src/' }), }; diff --git a/package-lock.json b/package-lock.json index 13db67f1a99..26ac4b7680d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -141,7 +141,6 @@ "gulp-slash": "^1.1.3", "jest": "^29.7.0", "jest-preset-angular": "^13.1.4", - "jest-raw-loader": "^1.0.1", "jsonc-parser": "^2.3.1", "keytar": "^7.2.0", "minimatch": "^5.1.0", @@ -18822,12 +18821,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/jest-raw-loader": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz", - "integrity": "sha512-g9oaAjeC4/rIJk1Wd3RxVbOfMizowM7LSjEJqa4R9qDX0OjQNABXOhH+GaznUp+DjTGVPi2vPPbQXyX87DOnYg==", - "dev": true - }, "node_modules/jest-regex-util": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", diff --git a/package.json b/package.json index ed6a23c9b34..1933cece140 100644 --- a/package.json +++ b/package.json @@ -176,7 +176,6 @@ "gulp-slash": "^1.1.3", "jest": "^29.7.0", "jest-preset-angular": "^13.1.4", - "jest-raw-loader": "^1.0.1", "jsonc-parser": "^2.3.1", "keytar": "^7.2.0", "minimatch": "^5.1.0", diff --git a/src/addons/calendar/pages/edit-event/edit-event.html b/src/addons/calendar/pages/edit-event/edit-event.html index f949796e813..26592324da2 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.html +++ b/src/addons/calendar/pages/edit-event/edit-event.html @@ -29,8 +29,14 @@

{{ title | translate }}

{{ 'core.date' | translate }}

- + + + + + {{'core.date' | translate}} + + + @@ -154,9 +160,15 @@

{{ title | translate }}

- + + + + + {{'addon.calendar.durationuntil' | translate}} + + + diff --git a/src/addons/calendar/pages/edit-event/edit-event.ts b/src/addons/calendar/pages/edit-event/edit-event.ts index 20e9d23f480..7eb187dc49d 100644 --- a/src/addons/calendar/pages/edit-event/edit-event.ts +++ b/src/addons/calendar/pages/edit-event/edit-event.ts @@ -45,7 +45,6 @@ import { CoreForms } from '@singletons/form'; import { CoreReminders, CoreRemindersService, CoreRemindersUnits } from '@features/reminders/services/reminders'; import { CoreRemindersSetReminderMenuComponent } from '@features/reminders/components/set-reminder-menu/set-reminder-menu'; import moment from 'moment-timezone'; -import { CoreAppProvider } from '@services/app'; /** * Page that displays a form to create/edit an event. @@ -61,7 +60,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { @ViewChild('editEventForm') formElement!: ElementRef; title = 'addon.calendar.newevent'; - dateFormat: string; component = AddonCalendarProvider.COMPONENT; loaded = false; hasOffline = false; @@ -78,7 +76,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { eventId?: number; maxDate: string; minDate: string; - displayTimezone?: string; // Form variables. form: FormGroup; @@ -107,11 +104,6 @@ export class AddonCalendarEditEventPage implements OnInit, OnDestroy, CanLeave { required: Translate.instant('core.required'), }; - // Calculate format to use. ion-datetime doesn't support escaping characters ([]), so we remove them. - this.dateFormat = CoreTimeUtils.convertPHPToMoment(Translate.instant('core.strftimedatetimeshort')) - .replace(/[[\]]/g, ''); - this.displayTimezone = CoreAppProvider.getForcedTimezone(); - this.form = new FormGroup({}); // Initialize form variables. diff --git a/src/addons/mod/data/fields/date/component/addon-mod-data-field-date.html b/src/addons/mod/data/fields/date/component/addon-mod-data-field-date.html index 596b8cf4973..5e2b2c81703 100644 --- a/src/addons/mod/data/fields/date/component/addon-mod-data-field-date.html +++ b/src/addons/mod/data/fields/date/component/addon-mod-data-field-date.html @@ -1,12 +1,18 @@ - + - + + + + + + + {{ 'addon.mod_data.usedate' | translate }} - + diff --git a/src/addons/mod/data/fields/date/component/date.ts b/src/addons/mod/data/fields/date/component/date.ts index 91e9c4041d3..bcda3ada62e 100644 --- a/src/addons/mod/data/fields/date/component/date.ts +++ b/src/addons/mod/data/fields/date/component/date.ts @@ -13,9 +13,7 @@ // limitations under the License. import { Component } from '@angular/core'; -import { CoreAppProvider } from '@services/app'; import { CoreTimeUtils } from '@services/utils/time'; -import { Translate } from '@singletons'; import moment, { Moment } from 'moment-timezone'; import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-field-plugin-component'; @@ -28,11 +26,9 @@ import { AddonModDataFieldPluginBaseComponent } from '../../../classes/base-fiel }) export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginBaseComponent { - format!: string; displayDate?: number; maxDate?: string; minDate?: string; - displayTimezone?: string; /** * @inheritdoc @@ -48,23 +44,18 @@ export class AddonModDataFieldDateComponent extends AddonModDataFieldPluginBaseC let momentInstance: Moment; - // Calculate format to use. - this.format = CoreTimeUtils.fixFormatForDatetime(CoreTimeUtils.convertPHPToMoment( - Translate.instant('core.strftimedate'), - )); this.maxDate = CoreTimeUtils.getDatetimeDefaultMax(); this.minDate = CoreTimeUtils.getDatetimeDefaultMin(); - this.displayTimezone = CoreAppProvider.getForcedTimezone(); - if (this.searchMode) { + if (this.searchMode && this.searchFields) { this.addControl('f_' + this.field.id + '_z'); - momentInstance = this.searchFields!['f_' + this.field.id + '_y'] - ? moment(this.searchFields!['f_' + this.field.id + '_y'] + '-' + - this.searchFields!['f_' + this.field.id + '_m'] + '-' + this.searchFields!['f_' + this.field.id + '_d']) + momentInstance = this.searchFields['f_' + this.field.id + '_y'] + ? moment(this.searchFields['f_' + this.field.id + '_y'] + '-' + + this.searchFields['f_' + this.field.id + '_m'] + '-' + this.searchFields['f_' + this.field.id + '_d']) : moment(); - this.searchFields!['f_' + this.field.id] = CoreTimeUtils.toDatetimeFormat(momentInstance.unix() * 1000); + this.searchFields['f_' + this.field.id] = CoreTimeUtils.toDatetimeFormat(momentInstance.unix() * 1000); } else { momentInstance = this.value?.content ? moment(parseInt(this.value.content, 10) * 1000) diff --git a/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html b/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html index 8e2a2134944..af214ff513e 100644 --- a/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html +++ b/src/addons/userprofilefield/datetime/component/addon-user-profile-field-datetime.html @@ -18,7 +18,12 @@ [courseId]="courseId" [wsNotFiltered]="true" /> - + + + + + + + diff --git a/src/addons/userprofilefield/datetime/component/datetime.ts b/src/addons/userprofilefield/datetime/component/datetime.ts index c97a0400a39..c65fec86f71 100644 --- a/src/addons/userprofilefield/datetime/component/datetime.ts +++ b/src/addons/userprofilefield/datetime/component/datetime.ts @@ -19,10 +19,7 @@ import { CoreTimeUtils } from '@services/utils/time'; import { CoreUtils } from '@services/utils/utils'; import { AuthEmailSignupProfileField } from '@features/login/services/login-helper'; import { CoreUserProfileField } from '@features/user/services/user'; -import { Translate } from '@singletons'; import { CoreUserProfileFieldBaseComponent } from '@features/user/classes/base-profilefield-component'; -import { CoreLang } from '@services/lang'; -import { CoreAppProvider } from '@services/app'; /** * Directive to render a datetime user profile field. @@ -33,13 +30,11 @@ import { CoreAppProvider } from '@services/app'; }) export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileFieldBaseComponent { - format?: string; + ionDateTimePresentation = 'date'; min?: string; max?: string; valueNumber?: number; displayValue?: string; - monthNames?: string[]; - displayTimezone?: string; /** * Init the data when the field is meant to be displayed without editing. @@ -64,16 +59,11 @@ export class AddonUserProfileFieldDatetimeComponent extends CoreUserProfileField protected initForEdit(field: AuthEmailSignupProfileField): void { super.initForEdit(field); - this.monthNames = CoreLang.getMonthNames(); - this.displayTimezone = CoreAppProvider.getForcedTimezone(); - // Check if it's only date or it has time too. const hasTime = CoreUtils.isTrueOrOne(field.param3); // Calculate format to use. - this.format = CoreTimeUtils.fixFormatForDatetime(CoreTimeUtils.convertPHPToMoment( - Translate.instant('core.' + (hasTime ? 'strftimedatetime' : 'strftimedate')), - )); + this.ionDateTimePresentation = hasTime ? 'date-time' : 'date'; // Check min value. if (field.param1 && Number(field.param1)) { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b295b17234b..d0a5dcfd4f2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -52,6 +52,8 @@ export function createTranslateLoader(http: HttpClient): TranslateHttpLoader { IonicModule.forRoot( { navAnimation: moodleTransitionAnimation, + innerHTMLTemplatesEnabled: true, + sanitizerEnabled: true, }, ), HttpClientModule, // HttpClient is used to make JSON requests. It fails for HEAD requests because there is no content. diff --git a/src/core/components/error-info/error-info.ts b/src/core/components/error-info/error-info.ts index 948d27eb1a7..4104e7f3e40 100644 --- a/src/core/components/error-info/error-info.ts +++ b/src/core/components/error-info/error-info.ts @@ -15,8 +15,6 @@ import { Component, ElementRef, Input, OnChanges, OnInit } from '@angular/core'; import { Translate } from '@singletons'; import { CoreForms } from '@singletons/form'; -import ChevronUpSVG from '!raw-loader!ionicons/dist/svg/chevron-up.svg'; -import ChevronDownSVG from '!raw-loader!ionicons/dist/svg/chevron-down.svg'; /** * Component to show error details. @@ -54,11 +52,11 @@ export class CoreErrorInfoComponent implements OnInit, OnChanges { diff --git a/src/core/components/input-errors/input-errors.scss b/src/core/components/input-errors/input-errors.scss index 32cabaf50f7..0d73958b97a 100644 --- a/src/core/components/input-errors/input-errors.scss +++ b/src/core/components/input-errors/input-errors.scss @@ -1,7 +1,8 @@ :host { - width: 100%; - + display: contents; .core-input-error-container { + width: 100%; + .core-input-error { padding: 4px; color: var(--danger); diff --git a/src/core/components/sheet-modal/sheet-modal.scss b/src/core/components/sheet-modal/sheet-modal.scss index b1170cfcd4d..ce18b284911 100644 --- a/src/core/components/sheet-modal/sheet-modal.scss +++ b/src/core/components/sheet-modal/sheet-modal.scss @@ -2,6 +2,7 @@ :host { --backdrop-opacity: var(--ion-backdrop-opacity, 0.4); + --border-radius: var(--modal-radius); width: 100%; height: 100%; @@ -17,7 +18,7 @@ } .sheet-modal--wrapper { - border-radius: var(--radius-lg) var(--radius-lg) 0 0; + border-radius: var(--border-radius) var(--border-radius) 0 0; @include padding(24px, 16px, 24px, 16px); background-color: var(--ion-overlay-background-color, var(--ion-background-color, #fff)); diff --git a/src/core/features/compile/components/compile-html/compile-html.ts b/src/core/features/compile/components/compile-html/compile-html.ts index 97edd339737..1a6fad10b4f 100644 --- a/src/core/features/compile/components/compile-html/compile-html.ts +++ b/src/core/features/compile/components/compile-html/compile-html.ts @@ -92,7 +92,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { } /** - * Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays). + * @inheritdoc */ ngDoCheck(): void { if (!this.componentInstance || this.creatingComponent) { @@ -111,7 +111,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { } /** - * Detect changes on input properties. + * @inheritdoc */ async ngOnChanges(changes: Record): Promise { // Only compile if text/javascript has changed or the forceCompile flag has been set to true. @@ -148,7 +148,7 @@ export class CoreCompileHtmlComponent implements OnChanges, OnDestroy, DoCheck { } /** - * Component destroyed. + * @inheritdoc */ ngOnDestroy(): void { this.componentRef?.destroy(); diff --git a/src/core/features/course/components/course-index/course-index.scss b/src/core/features/course/components/course-index/course-index.scss index 2b2aa5de050..d191638dcea 100644 --- a/src/core/features/course/components/course-index/course-index.scss +++ b/src/core/features/course/components/course-index/course-index.scss @@ -81,5 +81,9 @@ ion-item.item { &.restricted { font-size: var(--text-size); } + &[role=button] { + min-height: auto; + min-width: auto; + } } } diff --git a/src/core/features/login/pages/site/site.ts b/src/core/features/login/pages/site/site.ts index b85b1c865fb..cbca54a66f9 100644 --- a/src/core/features/login/pages/site/site.ts +++ b/src/core/features/login/pages/site/site.ts @@ -459,8 +459,8 @@ export class CoreLoginSitePage implements OnInit { }); if (errorDetails) { + // Avoid sanitizing JS. const containerElement = alertElement.querySelector('.core-error-info-container'); - if (containerElement) { containerElement.innerHTML = CoreErrorInfoComponent.render(errorDetails, errorCode); } diff --git a/src/core/services/lang.ts b/src/core/services/lang.ts index 797b32ba9ad..00c7e65f26f 100644 --- a/src/core/services/lang.ts +++ b/src/core/services/lang.ts @@ -27,6 +27,7 @@ import { CorePlatform } from '@services/platform'; import { AddonFilterMultilangHandler } from '@addons/filter/multilang/services/handlers/multilang'; import { AddonFilterMultilang2Handler } from '@addons/filter/multilang2/services/handlers/multilang2'; import { firstValueFrom } from 'rxjs'; +import { CoreLogger } from '@singletons/logger'; /* * Service to handle language features, like changing the current language. @@ -40,6 +41,11 @@ export class CoreLangProvider { protected customStrings: CoreLanguageObject = {}; // Strings defined using the admin tool. protected customStringsRaw?: string; protected sitePluginsStrings: CoreLanguageObject = {}; // Strings defined by site plugins. + protected logger: CoreLogger; + + constructor() { + this.logger = CoreLogger.getInstance('CoreLang'); + } async initialize(): Promise { // Set fallback language and language to use until the app determines the right language to use. @@ -171,13 +177,21 @@ export class CoreLangProvider { // Use british english when parent english is loaded. moment.locale(language == 'en' ? 'en-gb' : language); + const previousLanguage = this.currentLanguage ?? this.getDefaultLanguage(); + this.currentLanguage = language; try { - await Promise.all([ - this.reloadLanguageStrings(), - CoreConfig.set('current_language', language), - ]); + await this.reloadLanguageStrings(); + await CoreConfig.set('current_language', language); + } catch (error) { + if (language !== previousLanguage) { + this.logger.error(`Language ${language} not available, reverting to ${previousLanguage}`, error); + + return this.changeCurrentLanguage(previousLanguage); + } + + throw error; } finally { // Load the custom and site plugins strings for the language. if (this.loadLangStrings(this.customStrings, language) || this.loadLangStrings(this.sitePluginsStrings, language)) { diff --git a/src/core/services/utils/dom.ts b/src/core/services/utils/dom.ts index feae6ef72b2..d44738c6e16 100644 --- a/src/core/services/utils/dom.ts +++ b/src/core/services/utils/dom.ts @@ -815,14 +815,20 @@ export class CoreDomUtilsProvider { * @returns Promise resolved with the alert modal. */ async showAlertWithOptions(options: AlertOptions = {}, autocloseTime?: number): Promise { - const hasHTMLTags = CoreTextUtils.hasHTMLTags( options.message || ''); + let message = typeof options.message == 'string' + ? options.message + : options.message?.value || ''; + + const hasHTMLTags = CoreTextUtils.hasHTMLTags(message); if (hasHTMLTags && !CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('3.7')) { // Treat multilang. - options.message = await CoreLang.filterMultilang( options.message); + message = await CoreLang.filterMultilang(message); } - const alertId = Md5.hashAsciiStr((options.header || '') + '#' + (options.message || '')); + options.message = message; + + const alertId = Md5.hashAsciiStr((options.header || '') + '#' + (message|| '')); if (this.displayedAlerts[alertId]) { // There's already an alert with the same message and title. Return it. diff --git a/src/core/utils/async-instance.ts b/src/core/utils/async-instance.ts index 187f64c1962..088ff66b071 100644 --- a/src/core/utils/async-instance.ts +++ b/src/core/utils/async-instance.ts @@ -117,7 +117,6 @@ export interface AsyncInstanceWrapper< resetInstance(): void; } -// eslint-disable-next-line @typescript-eslint/ban-types export type AsyncObject = object; /** diff --git a/src/theme/theme.base.scss b/src/theme/theme.base.scss index 738bf9a4981..31fbe0ba54e 100644 --- a/src/theme/theme.base.scss +++ b/src/theme/theme.base.scss @@ -518,7 +518,7 @@ ion-alert .alert-button.timed-button{ } ion-alert { - --border-radius: var(--radius-xl); + --border-radius: var(--modal-radius); &.md, &.ios { --max-width: 80%; @@ -545,7 +545,7 @@ ion-alert { } ion-loading { - --border-radius: var(--radius-xl); + --border-radius: var(--modal-radius); .loading-wrapper { border-radius: var(--border-radius) !important; @@ -1585,37 +1585,6 @@ ion-item.item-input.item-multiple-inputs { } } -// Focus highlight for accessibility. -.ion-focused:not(.item-multiple-inputs):not(:focus), -ion-input.has-focus, -ion-card:focus { - @include core-focus(); -} -.ion-focused.item-multiple-inputs, -.ion-focused.ion-activatable { - ion-toggle:focus-within, - ion-select:focus-within, - ion-checkbox:focus-within, - ion-radio:focus-within { - @include core-focus(); - } -} - -// Treat cases where there's a focusable element inside an item, like a button. -ion-item.item-input:not(.item-multiple-inputs):not(:focus), -ion-item.item-has-focus:not(.item-multiple-inputs):not(:focus), -ion-item.item-input ion-input.has-focus { - position: relative; - &::after { - box-shadow: revert; - opacity: revert; - z-index: revert; - } - .item-highlight, .item-inner-highlight { - position: unset; - } -} - ion-item-divider.item, ion-item.item.divider { min-height: var(--min-height); @@ -1653,6 +1622,42 @@ ion-item.item { outline: none; } +// Focus highlight for accessibility. +.ion-focused:not(.item-multiple-inputs):not(:focus), +ion-input.has-focus, +ion-card:focus { + @include core-focus(); + + :focus-visible, + .clickable:focus { + box-shadow: none; + } +} + +.ion-focused.item-multiple-inputs { + ion-toggle:focus-within, + ion-select:focus-within, + ion-checkbox:focus-within, + ion-radio:focus-within { + @include core-focus(); + } +} + +// Treat cases where there's a focusable element inside an item, like a button. +ion-item.item-input:not(.item-multiple-inputs):not(:focus), +ion-item.item-has-focus:not(.item-multiple-inputs):not(:focus), +ion-item.item-input ion-input.has-focus { + position: relative; + &::after { + box-shadow: revert; + opacity: revert; + z-index: revert; + } + .item-highlight, .item-inner-highlight { + position: unset; + } +} + textarea, button, select, input, a, .clickable { &:focus { @include core-focus-style(); @@ -1660,10 +1665,6 @@ textarea, button, select, input, a, .clickable { } } -.ion-focused:not(.item-multiple-inputs):not(:focus) .clickable:focus { - box-shadow: none; -} - ion-loading:focus-visible, ion-alert:focus-visible, ion-popover:focus-visible, @@ -1672,11 +1673,6 @@ ion-modal:focus-visible { border-radius: 0; } -input { - --placeholder-color: var(--ion-placeholder-color); - --placeholder-opacity: .85; -} - ion-input .native-input { &:focus, &:focus-visible { box-shadow: none; @@ -1684,6 +1680,11 @@ ion-input .native-input { } } +input { + --placeholder-color: var(--ion-placeholder-color); + --placeholder-opacity: .85; +} + // Disable scroll on parent ion contents to enabled PTR on the ones inside the splitview. See split-view component for more info. ion-content.disable-scroll-y::part(scroll) { touch-action: auto; @@ -1916,6 +1917,9 @@ ion-modal { --border-radius: var(--modal-radius); } } + &.ion-datetime-button-overlay { + --border-radius: var(--modal-radius); + } &.core-modal-lateral, &.core-modal-fullscreen { @@ -1973,3 +1977,10 @@ ion-popover { [hidden] { display: none !important; } + +// Ion Datetime +ion-item.item-label-stacked ion-datetime-button { + margin-top: 8px; + margin-bottom: 8px; + align-self: self-end; +} diff --git a/src/types/angular.d.ts b/src/types/angular.d.ts deleted file mode 100644 index ca503972d88..00000000000 --- a/src/types/angular.d.ts +++ /dev/null @@ -1,27 +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 { UrlTree } from '@angular/router'; -import { NavigationOptions } from '@ionic/angular/common/providers/nav-controller'; - -declare module '@ionic/angular' { - - export class NavController { - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigateForward(url: string | UrlTree | any[], options?: NavigationOptions): Promise; - - } - -} diff --git a/src/types/raw.d.ts b/src/types/raw.d.ts deleted file mode 100644 index 131f583291d..00000000000 --- a/src/types/raw.d.ts +++ /dev/null @@ -1,19 +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. - -declare module '!raw-loader!*' { - const contents: string; - - export = contents; -} diff --git a/upgrade.txt b/upgrade.txt index 69a177f0b50..76fb4cca7e8 100644 --- a/upgrade.txt +++ b/upgrade.txt @@ -9,6 +9,7 @@ For more information about upgrading, read the official documentation: https://m - Renamed CoreLoginSitesComponent to CoreLoginSitesModalComponent to make it clear that it's a modal and to avoid confusing it with the new CoreSitesListComponent. - Removed CoreToLocaleStringPipe deprecated since 3.6.0 - With the upgrade to Ionic 7 ion-slides is no longer supported and now you need to use swiper-container and swiper-slide. More info here: https://ionicframework.com/docs/angular/slides + - With the upgrade to Ionic7 ion-datetime has changed its usage. We recommend using ion-datetime-button. More info here: https://ionicframework.com/docs/updating/6-0#datetime === 4.3.0 ===