commit
89123e0df7
|
@ -10,8 +10,5 @@ module.exports = {
|
|||
'!src/testing/**/*',
|
||||
],
|
||||
transformIgnorePatterns: ['node_modules/(?!@stencil|@angular|@ionic|@moodlehq|@ngx-translate|swiper)'],
|
||||
moduleNameMapper: {
|
||||
...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/src/' }),
|
||||
'^!raw-loader!.*': 'jest-raw-loader',
|
||||
},
|
||||
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/src/' }),
|
||||
};
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -29,8 +29,14 @@
|
|||
<ion-label position="stacked">
|
||||
<p class="item-heading" [core-mark-required]="true">{{ 'core.date' | translate }}</p>
|
||||
</ion-label>
|
||||
<ion-datetime formControlName="timestart" [placeholder]="'core.date' | translate" [displayFormat]="dateFormat"
|
||||
[max]="maxDate" [min]="minDate" [displayTimezone]="displayTimezone" />
|
||||
<ion-datetime-button datetime="timestart" />
|
||||
<ion-modal [keepContentsMounted]="true">
|
||||
<ng-template>
|
||||
<ion-datetime id="timestart" formControlName="timestart" presentation="date-time" [max]="maxDate" [min]="minDate">
|
||||
<span slot="title">{{'core.date' | translate}}</span>
|
||||
</ion-datetime>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
<core-input-errors [control]="form.controls.timestart" [errorMessages]="errors" />
|
||||
</ion-item>
|
||||
|
||||
|
@ -154,9 +160,15 @@
|
|||
</ion-item>
|
||||
<ion-item *ngIf="form.controls.duration.value === 1">
|
||||
<ion-label position="stacked" />
|
||||
<ion-datetime formControlName="timedurationuntil" [max]="maxDate" [min]="minDate"
|
||||
[placeholder]="'addon.calendar.durationuntil' | translate" [displayFormat]="dateFormat"
|
||||
[displayTimezone]="displayTimezone" />
|
||||
<ion-datetime-button datetime="timedurationuntil" />
|
||||
<ion-modal [keepContentsMounted]="true">
|
||||
<ng-template>
|
||||
<ion-datetime id="timedurationuntil" formControlName="timedurationuntil" [max]="maxDate" [min]="minDate"
|
||||
presentation="date-time">
|
||||
<span slot="title">{{'addon.calendar.durationuntil' | translate}}</span>
|
||||
</ion-datetime>
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
<span *ngIf="inputMode && form" [formGroup]="form">
|
||||
<span *ngIf="inputMode && form && searchFields" [formGroup]="form">
|
||||
<span *ngIf="editMode" [core-mark-required]="field.required" class="core-mark-required"></span>
|
||||
<ion-datetime [formControlName]="'f_'+field.id" [placeholder]="'core.date' | translate" [max]="maxDate" [min]="minDate"
|
||||
[disabled]="searchMode && !searchFields!['f_'+field.id+'_z']" [displayFormat]="format" [displayTimezone]="displayTimezone" />
|
||||
|
||||
<ion-datetime-button datetime="datetime" />
|
||||
<ion-modal [keepContentsMounted]="true">
|
||||
<ng-template>
|
||||
<ion-datetime id="datetime" [formControlName]="'f_'+field.id" [max]="maxDate" [min]="minDate"
|
||||
[disabled]="searchMode && !searchFields['f_'+field.id+'_z']" presentation="date" />
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
<core-input-errors *ngIf="error && editMode" [control]="form.controls['f_'+field.id]" [errorText]="error" />
|
||||
|
||||
<ion-item *ngIf="searchMode">
|
||||
<ion-label>{{ 'addon.mod_data.usedate' | translate }}</ion-label>
|
||||
<ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="searchFields!['f_'+field.id+'_z']" />
|
||||
<ion-checkbox slot="end" [formControlName]="'f_'+field.id+'_z'" [(ngModel)]="searchFields['f_'+field.id+'_z']" />
|
||||
</ion-item>
|
||||
</span>
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -18,7 +18,12 @@
|
|||
[courseId]="courseId" [wsNotFiltered]="true" />
|
||||
</span>
|
||||
</ion-label>
|
||||
<ion-datetime [formControlName]="modelName" [placeholder]="'core.choosedots' | translate" [displayFormat]="format" [max]="max"
|
||||
[min]="min" [monthNames]="monthNames" [displayTimezone]="displayTimezone" />
|
||||
|
||||
<ion-datetime-button datetime="datetime" />
|
||||
<ion-modal [keepContentsMounted]="true">
|
||||
<ng-template>
|
||||
<ion-datetime id="datetime" [formControlName]="modelName" [presentation]="ionDateTimePresentation" [max]="max" [min]="min" />
|
||||
</ng-template>
|
||||
</ion-modal>
|
||||
<core-input-errors [control]="form.controls[modelName]" />
|
||||
</ion-item>
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
|||
<label for="${toggleId}" class="core-error-info--toggle" aria-hidden="true">
|
||||
<span class="core-error-info--hide-content">
|
||||
${hideDetailsLabel}
|
||||
${ChevronUpSVG}
|
||||
<ion-icon name="chevron-up" />
|
||||
</span>
|
||||
<span class="core-error-info--show-content">
|
||||
${showDetailsLabel}
|
||||
${ChevronDownSVG}
|
||||
<ion-icon name="chevron-down" />
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
:host {
|
||||
width: 100%;
|
||||
|
||||
display: contents;
|
||||
.core-input-error-container {
|
||||
width: 100%;
|
||||
|
||||
.core-input-error {
|
||||
padding: 4px;
|
||||
color: var(--danger);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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<string, SimpleChange>): Promise<void> {
|
||||
// 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();
|
||||
|
|
|
@ -81,5 +81,9 @@ ion-item.item {
|
|||
&.restricted {
|
||||
font-size: var(--text-size);
|
||||
}
|
||||
&[role=button] {
|
||||
min-height: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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<void> {
|
||||
// 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)) {
|
||||
|
|
|
@ -815,14 +815,20 @@ export class CoreDomUtilsProvider {
|
|||
* @returns Promise resolved with the alert modal.
|
||||
*/
|
||||
async showAlertWithOptions(options: AlertOptions = {}, autocloseTime?: number): Promise<HTMLIonAlertElement> {
|
||||
const hasHTMLTags = CoreTextUtils.hasHTMLTags(<string> 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(<string> options.message);
|
||||
message = await CoreLang.filterMultilang(message);
|
||||
}
|
||||
|
||||
const alertId = <string> 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.
|
||||
|
|
|
@ -117,7 +117,6 @@ export interface AsyncInstanceWrapper<
|
|||
resetInstance(): void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export type AsyncObject = object;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<boolean | 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;
|
||||
}
|
|
@ -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 ===
|
||||
|
||||
|
|
Loading…
Reference in New Issue