Merge pull request #4108 from crazyserver/MOBILE-4594

Mobile 4594 Update to Ionic8
main
Dani Palou 2024-07-18 10:35:17 +02:00 committed by GitHub
commit 69dcf04b44
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
94 changed files with 476 additions and 1189 deletions

View File

@ -153,7 +153,7 @@ jobs:
- name: Initialise moodle-plugin-ci - name: Initialise moodle-plugin-ci
run: | run: |
composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4.4 composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^4.5
echo $(cd ci/bin; pwd) >> $GITHUB_PATH echo $(cd ci/bin; pwd) >> $GITHUB_PATH
echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH echo $(cd ci/vendor/bin; pwd) >> $GITHUB_PATH
sudo locale-gen en_AU.UTF-8 sudo locale-gen en_AU.UTF-8

View File

@ -69,7 +69,8 @@ jobs:
cat circular-dependencies cat circular-dependencies
lines=$(cat circular-dependencies | wc -l) lines=$(cat circular-dependencies | wc -l)
echo "Total circular dependencies: $lines" echo "Total circular dependencies: $lines"
test $lines -le 185 test $lines -ge 138
test $lines -le 148
- name: JavaScript code compatibility - name: JavaScript code compatibility
run: | run: |
npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn" npx check-es-compat www/*.js --polyfills="\{Array,String,TypedArray\}.prototype.at,Object.hasOwn"

View File

@ -3,8 +3,7 @@
<ion-list> <ion-list>
<ion-item> <ion-item>
<ion-label position="floating">What is the answer to the Ultimate Question of Life, The Universe, and Everything?</ion-label> <ion-input labelPlacement="floating" [(ngModel)]="CONTENT_OTHERDATA.answer" label="What is the answer to the Ultimate Question of Life, The Universe, and Everything?"></ion-input>
<ion-input [(ngModel)]="CONTENT_OTHERDATA.answer"></ion-input>
</ion-item> </ion-item>
<ion-item *ngIf="CONTENT_OTHERDATA.answer === '42'"> <ion-item *ngIf="CONTENT_OTHERDATA.answer === '42'">
<ion-label>That is correct!</ion-label> <ion-label>That is correct!</ion-label>

131
package-lock.json generated
View File

@ -38,7 +38,7 @@
"@awesome-cordova-plugins/sqlite": "^6.7.0", "@awesome-cordova-plugins/sqlite": "^6.7.0",
"@awesome-cordova-plugins/status-bar": "^6.7.0", "@awesome-cordova-plugins/status-bar": "^6.7.0",
"@awesome-cordova-plugins/web-intent": "^6.7.0", "@awesome-cordova-plugins/web-intent": "^6.7.0",
"@ionic/angular": "^7.8.6", "@ionic/angular": "^8.2.5",
"@ionic/cordova-builders": "^11.0.0", "@ionic/cordova-builders": "^11.0.0",
"@moodlehq/cordova-plugin-advanced-http": "3.3.1-moodle.1", "@moodlehq/cordova-plugin-advanced-http": "3.3.1-moodle.1",
"@moodlehq/cordova-plugin-camera": "7.0.0-moodle.1", "@moodlehq/cordova-plugin-camera": "7.0.0-moodle.1",
@ -107,7 +107,7 @@
"@angular/cli": "^17.3.6", "@angular/cli": "^17.3.6",
"@angular/compiler-cli": "^17.3.7", "@angular/compiler-cli": "^17.3.7",
"@angular/language-service": "^17.3.7", "@angular/language-service": "^17.3.7",
"@ionic/angular-toolkit": "^10.1.1", "@ionic/angular-toolkit": "^11.0.1",
"@ionic/cli": "^7.2.0", "@ionic/cli": "^7.2.0",
"@jsdevtools/coverage-istanbul-loader": "^3.0.5", "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
"@types/faker": "^5.5.9", "@types/faker": "^5.5.9",
@ -3646,123 +3646,32 @@
"dev": true "dev": true
}, },
"node_modules/@ionic/angular": { "node_modules/@ionic/angular": {
"version": "7.8.6", "version": "8.2.5",
"resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-7.8.6.tgz", "resolved": "https://registry.npmjs.org/@ionic/angular/-/angular-8.2.5.tgz",
"integrity": "sha512-3Qe53hXpyjtx6fFcxt/NTAlauIawsGmCZJPauV5sAnSKVuX8C82C1zMAZTeJt6m2dnd71wythc98BXUXsx/UxQ==", "integrity": "sha512-vvL5TIN8YbrkW5IZ4TYw2zVa4/+boITe19nElPz1Bu7O15lEEzLe+9RqcIMDERwzgqzsBXLh1CUJk+1TXkMhJg==",
"dependencies": { "dependencies": {
"@ionic/core": "7.8.6", "@ionic/core": "8.2.5",
"ionicons": "^7.0.0", "ionicons": "^7.0.0",
"jsonc-parser": "^3.0.0", "jsonc-parser": "^3.0.0",
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/core": ">=14.0.0", "@angular/core": ">=16.0.0",
"@angular/forms": ">=14.0.0", "@angular/forms": ">=16.0.0",
"@angular/router": ">=14.0.0", "@angular/router": ">=16.0.0",
"rxjs": ">=7.5.0", "rxjs": ">=7.5.0",
"zone.js": ">=0.11.0" "zone.js": ">=0.13.0"
} }
}, },
"node_modules/@ionic/angular-toolkit": { "node_modules/@ionic/angular-toolkit": {
"version": "10.1.1", "version": "11.0.1",
"resolved": "https://registry.npmjs.org/@ionic/angular-toolkit/-/angular-toolkit-10.1.1.tgz", "resolved": "https://registry.npmjs.org/@ionic/angular-toolkit/-/angular-toolkit-11.0.1.tgz",
"integrity": "sha512-idLaBUY14M7JQmvxAGeDZvk7WcamWEHo1OHGRuLRAn+7uWrKeGxfWbnbZJhvRCLQndr8j7q3WV3Z+0APkPuKaQ==", "integrity": "sha512-dxx2RDbxDYM2nWRPIirKMJySHtqJ1u02T25PGbNb99W2Wlcmu1cza3+2/PQ8ga18yMz/dQqaGyEmPDf3ZSVO0w==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@angular-devkit/core": "^16.0.0", "@angular-devkit/core": "^17.0.0",
"@angular-devkit/schematics": "^16.0.0", "@angular-devkit/schematics": "^17.0.0",
"@schematics/angular": "^16.0.0" "@schematics/angular": "^17.0.0"
}
},
"node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/core": {
"version": "16.2.14",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-16.2.14.tgz",
"integrity": "sha512-Ui14/d2+p7lnmXlK/AX2ieQEGInBV75lonNtPQgwrYgskF8ufCuN0DyVZQUy9fJDkC+xQxbJyYrby/BS0R0e7w==",
"dev": true,
"dependencies": {
"ajv": "8.12.0",
"ajv-formats": "2.1.1",
"jsonc-parser": "3.2.0",
"picomatch": "2.3.1",
"rxjs": "7.8.1",
"source-map": "0.7.4"
},
"engines": {
"node": "^16.14.0 || >=18.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
},
"peerDependencies": {
"chokidar": "^3.5.2"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/@ionic/angular-toolkit/node_modules/@angular-devkit/schematics": {
"version": "16.2.14",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-16.2.14.tgz",
"integrity": "sha512-B6LQKInCT8w5zx5Pbroext5eFFRTCJdTwHN8GhcVS8IeKCnkeqVTQLjB4lBUg7LEm8Y7UHXwzrVxmk+f+MBXhw==",
"dev": true,
"dependencies": {
"@angular-devkit/core": "16.2.14",
"jsonc-parser": "3.2.0",
"magic-string": "0.30.1",
"ora": "5.4.1",
"rxjs": "7.8.1"
},
"engines": {
"node": "^16.14.0 || >=18.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@ionic/angular-toolkit/node_modules/@schematics/angular": {
"version": "16.2.14",
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-16.2.14.tgz",
"integrity": "sha512-YqIv727l9Qze8/OL6H9mBHc2jVXzAGRNBYnxYWqWhLbfvuVbbldo6NNIIjgv6lrl2LJSdPAAMNOD5m/f6210ug==",
"dev": true,
"dependencies": {
"@angular-devkit/core": "16.2.14",
"@angular-devkit/schematics": "16.2.14",
"jsonc-parser": "3.2.0"
},
"engines": {
"node": "^16.14.0 || >=18.10.0",
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
"yarn": ">= 1.13.0"
}
},
"node_modules/@ionic/angular-toolkit/node_modules/jsonc-parser": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
"dev": true
},
"node_modules/@ionic/angular-toolkit/node_modules/magic-string": {
"version": "0.30.1",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.1.tgz",
"integrity": "sha512-mbVKXPmS0z0G4XqFDCTllmDQ6coZzn94aMlb0o/A4HEHJCKcanlDZwYJgwnkmgD3jyWhUgj9VsPrfd972yPffA==",
"dev": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.4.15"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@ionic/angular-toolkit/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/@ionic/angular/node_modules/jsonc-parser": { "node_modules/@ionic/angular/node_modules/jsonc-parser": {
@ -4291,11 +4200,11 @@
} }
}, },
"node_modules/@ionic/core": { "node_modules/@ionic/core": {
"version": "7.8.6", "version": "8.2.5",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.8.6.tgz", "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.2.5.tgz",
"integrity": "sha512-HAYZdEmeJgOdo2kDlZkcCGHb+zs/vjU6iv4skbVBL7y+OnSv/oC2u83Yee8S3/aY0YAxkyBgu7hLTYH13Zc2Aw==", "integrity": "sha512-NhK5KfP5NL5NITibj8sOUlfI/ARNCF5rBu5HdIEfFe25MJkd0IYBQWjVaESFhSk7aB8pXEP8DIx1AHbT9e3Sog==",
"dependencies": { "dependencies": {
"@stencil/core": "^4.12.2", "@stencil/core": "^4.19.2",
"ionicons": "^7.2.2", "ionicons": "^7.2.2",
"tslib": "^2.1.0" "tslib": "^2.1.0"
} }

View File

@ -72,7 +72,7 @@
"@awesome-cordova-plugins/sqlite": "^6.7.0", "@awesome-cordova-plugins/sqlite": "^6.7.0",
"@awesome-cordova-plugins/status-bar": "^6.7.0", "@awesome-cordova-plugins/status-bar": "^6.7.0",
"@awesome-cordova-plugins/web-intent": "^6.7.0", "@awesome-cordova-plugins/web-intent": "^6.7.0",
"@ionic/angular": "^7.8.6", "@ionic/angular": "^8.2.5",
"@ionic/cordova-builders": "^11.0.0", "@ionic/cordova-builders": "^11.0.0",
"@moodlehq/cordova-plugin-advanced-http": "3.3.1-moodle.1", "@moodlehq/cordova-plugin-advanced-http": "3.3.1-moodle.1",
"@moodlehq/cordova-plugin-camera": "7.0.0-moodle.1", "@moodlehq/cordova-plugin-camera": "7.0.0-moodle.1",
@ -141,7 +141,7 @@
"@angular/cli": "^17.3.6", "@angular/cli": "^17.3.6",
"@angular/compiler-cli": "^17.3.7", "@angular/compiler-cli": "^17.3.7",
"@angular/language-service": "^17.3.7", "@angular/language-service": "^17.3.7",
"@ionic/angular-toolkit": "^10.1.1", "@ionic/angular-toolkit": "^11.0.1",
"@ionic/cli": "^7.2.0", "@ionic/cli": "^7.2.0",
"@jsdevtools/coverage-istanbul-loader": "^3.0.5", "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
"@types/faker": "^5.5.9", "@types/faker": "^5.5.9",

View File

@ -1,5 +1,5 @@
diff --git a/node_modules/@ionic/core/components/popover.js b/node_modules/@ionic/core/components/popover.js diff --git a/node_modules/@ionic/core/components/popover.js b/node_modules/@ionic/core/components/popover.js
index 21fb3e3..52ea4a6 100644 index 19b79c4..67289f4 100644
--- a/node_modules/@ionic/core/components/popover.js --- a/node_modules/@ionic/core/components/popover.js
+++ b/node_modules/@ionic/core/components/popover.js +++ b/node_modules/@ionic/core/components/popover.js
@@ -763,8 +763,10 @@ const iosEnterAnimation = (baseEl, opts) => { @@ -763,8 +763,10 @@ const iosEnterAnimation = (baseEl, opts) => {
@ -29,10 +29,10 @@ index 21fb3e3..52ea4a6 100644
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target); const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
diff --git a/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js b/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js diff --git a/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js b/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js
index 68a908b..050e544 100644 index 2dcf484..54aeac9 100644
--- a/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js --- a/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js
+++ b/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js +++ b/node_modules/@ionic/core/dist/cjs/ion-popover.cjs.entry.js
@@ -768,8 +768,10 @@ const iosEnterAnimation = (baseEl, opts) => { @@ -769,8 +769,10 @@ const iosEnterAnimation = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';
@ -45,7 +45,7 @@ index 68a908b..050e544 100644
const root = helpers.getElementRoot(baseEl); const root = helpers.getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const arrowEl = root.querySelector('.popover-arrow'); const arrowEl = root.querySelector('.popover-arrow');
@@ -889,8 +891,10 @@ const mdEnterAnimation = (baseEl, opts) => { @@ -890,8 +892,10 @@ const mdEnterAnimation = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';
@ -93,10 +93,10 @@ index 603923a..ff10a25 100644
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target); const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
diff --git a/node_modules/@ionic/core/dist/esm/ion-popover.entry.js b/node_modules/@ionic/core/dist/esm/ion-popover.entry.js diff --git a/node_modules/@ionic/core/dist/esm/ion-popover.entry.js b/node_modules/@ionic/core/dist/esm/ion-popover.entry.js
index 839e91c..abcd28f 100644 index 8ca76cf..c5b990a 100644
--- a/node_modules/@ionic/core/dist/esm/ion-popover.entry.js --- a/node_modules/@ionic/core/dist/esm/ion-popover.entry.js
+++ b/node_modules/@ionic/core/dist/esm/ion-popover.entry.js +++ b/node_modules/@ionic/core/dist/esm/ion-popover.entry.js
@@ -764,8 +764,10 @@ const iosEnterAnimation = (baseEl, opts) => { @@ -765,8 +765,10 @@ const iosEnterAnimation = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';
@ -109,7 +109,7 @@ index 839e91c..abcd28f 100644
const root = getElementRoot(baseEl); const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const arrowEl = root.querySelector('.popover-arrow'); const arrowEl = root.querySelector('.popover-arrow');
@@ -885,8 +887,10 @@ const mdEnterAnimation = (baseEl, opts) => { @@ -886,8 +888,10 @@ const mdEnterAnimation = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';
@ -123,10 +123,10 @@ index 839e91c..abcd28f 100644
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target); const referenceSizeEl = trigger || ((_a = ev === null || ev === void 0 ? void 0 : ev.detail) === null || _a === void 0 ? void 0 : _a.ionShadowTarget) || (ev === null || ev === void 0 ? void 0 : ev.target);
diff --git a/node_modules/@ionic/core/hydrate/index.js b/node_modules/@ionic/core/hydrate/index.js diff --git a/node_modules/@ionic/core/hydrate/index.js b/node_modules/@ionic/core/hydrate/index.js
index 7f898c7..a3a7669 100644 index 5a50b98..884e2ce 100644
--- a/node_modules/@ionic/core/hydrate/index.js --- a/node_modules/@ionic/core/hydrate/index.js
+++ b/node_modules/@ionic/core/hydrate/index.js +++ b/node_modules/@ionic/core/hydrate/index.js
@@ -29254,8 +29254,10 @@ const iosEnterAnimation$1 = (baseEl, opts) => { @@ -23702,8 +23702,10 @@ const iosEnterAnimation$1 = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';
@ -139,7 +139,7 @@ index 7f898c7..a3a7669 100644
const root = getElementRoot(baseEl); const root = getElementRoot(baseEl);
const contentEl = root.querySelector('.popover-content'); const contentEl = root.querySelector('.popover-content');
const arrowEl = root.querySelector('.popover-arrow'); const arrowEl = root.querySelector('.popover-arrow');
@@ -29375,8 +29377,10 @@ const mdEnterAnimation$1 = (baseEl, opts) => { @@ -23823,8 +23825,10 @@ const mdEnterAnimation$1 = (baseEl, opts) => {
const { event: ev, size, trigger, reference, side, align } = opts; const { event: ev, size, trigger, reference, side, align } = opts;
const doc = baseEl.ownerDocument; const doc = baseEl.ownerDocument;
const isRTL = doc.dir === 'rtl'; const isRTL = doc.dir === 'rtl';

View File

@ -150,6 +150,6 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
--addon-calendar-blank-day-background-color: var(--gray-900); --addon-calendar-blank-day-background-color: var(--gray-900);
} }

View File

@ -294,27 +294,6 @@ export class AddonCalendarHelperProvider {
} }
} }
/**
* Format reminders, adding calculated data.
*
* @param reminders Reminders.
* @param timestart Event timestart.
* @param siteId Site ID.
* @returns Formatted reminders.
* @deprecated since 4.1 Use AddonCalendarHelper.getEventReminders.
*/
async formatReminders(
reminders: { eventid: number }[],
timestart: number,
siteId?: string,
): Promise<AddonCalendarEventReminder[]> {
if (!reminders.length) {
return [];
}
return AddonCalendarHelper.getEventReminders(reminders[0].eventid, timestart, siteId);
}
/** /**
* Format reminders, adding calculated data. * Format reminders, adding calculated data.
* *

View File

@ -45,10 +45,7 @@ import {
CoreReminders, CoreReminders,
CoreRemindersPushNotificationData, CoreRemindersPushNotificationData,
CoreRemindersService, CoreRemindersService,
CoreRemindersUnits,
CoreReminderValueAndUnit,
} from '@features/reminders/services/reminders'; } from '@features/reminders/services/reminders';
import { CoreReminderDBRecord } from '@features/reminders/services/database/reminders';
import { CoreEvents } from '@singletons/events'; import { CoreEvents } from '@singletons/events';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { ADDON_CALENDAR_COMPONENT } from '../constants'; import { ADDON_CALENDAR_COMPONENT } from '../constants';
@ -66,18 +63,6 @@ export enum AddonCalendarEventType {
USER = 'user', USER = 'user',
} }
/**
* Units to set a reminder.
*
* @deprecated since 4.1 Use CoreReminderUnits instead.
*/
export enum AddonCalendarReminderUnits {
MINUTE = CoreConstants.SECONDS_MINUTE,
HOUR = CoreConstants.SECONDS_HOUR,
DAY = CoreConstants.SECONDS_DAY,
WEEK = CoreConstants.SECONDS_WEEK,
}
declare module '@singletons/events' { declare module '@singletons/events' {
/** /**
@ -178,17 +163,6 @@ export class AddonCalendarProvider {
return !!site?.isVersionGreaterEqualThan('3.7.1'); return !!site?.isVersionGreaterEqualThan('3.7.1');
} }
/**
* Given a number of seconds, convert it to a unit&value format compatible with reminders.
*
* @param seconds Number of seconds.
* @returns Value and unit.
* @deprecated since 4.1 Use CoreRemindersService.convertSecondsToValueAndUnit instead.
*/
static convertSecondsToValueAndUnit(seconds: number): CoreReminderValueAndUnit {
return CoreRemindersService.convertSecondsToValueAndUnit(seconds);
}
/** /**
* Delete an event. * Delete an event.
* *
@ -592,17 +566,6 @@ export class AddonCalendarProvider {
return CoreTimeUtils.userDate(time, 'core.strftimedayshort'); return CoreTimeUtils.userDate(time, 'core.strftimedayshort');
} }
/**
* Get the configured default notification time.
*
* @param siteId ID of the site. If not defined, use current site.
* @returns Promise resolved with the default time (in seconds).
* @deprecated since 4.1 Use CoreReminders.getDefaultNotificationTime instead.
*/
async getDefaultNotificationTime(siteId?: string): Promise<number> {
return CoreReminders.getDefaultNotificationTime(siteId);
}
/** /**
* Get a calendar event. If the server request fails and data is not cached, try to get it from local DB. * Get a calendar event. If the server request fails and data is not cached, try to get it from local DB.
* *
@ -780,18 +743,6 @@ export class AddonCalendarProvider {
return event.eventtype; return event.eventtype;
} }
/**
* Remove an event reminder and cancel the notification.
*
* @param id Reminder ID.
* @param siteId ID of the site the event belongs to. If not defined, use current site.
* @returns Promise resolved when the notification is updated.
* @deprecated since 4.1. Use CoreReminders.removeReminder instead.
*/
async deleteEventReminder(id: number, siteId?: string): Promise<void> {
await CoreReminders.removeReminder(id, siteId);
}
/** /**
* Get calendar events for a certain day. * Get calendar events for a certain day.
* *
@ -876,21 +827,6 @@ export class AddonCalendarProvider {
(categoryId ? categoryId : ''); (categoryId ? categoryId : '');
} }
/**
* Get a calendar reminders from local Db.
*
* @param eventId Event ID.
* @param siteId ID of the site the event belongs to. If not defined, use current site.
* @returns Promise resolved when the event data is retrieved.
* @deprecated since 4.1. Use CoreReminders.getReminders instead.
*/
async getEventReminders(eventId: number, siteId?: string): Promise<CoreReminderDBRecord[]> {
return CoreReminders.getReminders({
instanceId: eventId,
component: ADDON_CALENDAR_COMPONENT,
}, siteId);
}
/** /**
* Get the events in a certain period. The period is calculated like this: * Get the events in a certain period. The period is calculated like this:
* start time: now + daysToStart * start time: now + daysToStart
@ -1089,19 +1025,6 @@ export class AddonCalendarProvider {
(categoryId ? categoryId : ''); (categoryId ? categoryId : '');
} }
/**
* Given a value and a unit, return the translated label.
*
* @param value Value.
* @param unit Unit.
* @param addDefaultLabel Whether to add the "Default" text.
* @returns Translated label.
* @deprecated since 4.1 Use CoreReminders.getUnitValueLabel instead.
*/
getUnitValueLabel(value: number, unit: CoreRemindersUnits, addDefaultLabel = false): string {
return CoreReminders.getUnitValueLabel(value, unit, addDefaultLabel);
}
/** /**
* Get upcoming calendar events. * Get upcoming calendar events.
* *
@ -1378,16 +1301,6 @@ export class AddonCalendarProvider {
return this.isCalendarDisabledInSite(site); return this.isCalendarDisabledInSite(site);
} }
/**
* Get the next events for all the sites and schedules their notifications.
*
* @returns Promise resolved when done.
* @deprecated since 4.1 Use AddonCalendar.updateAllSitesEventReminders.
*/
async scheduleAllSitesEventsNotifications(): Promise<void> {
await AddonCalendar.updateAllSitesEventReminders();
}
/** /**
* Get the next events for all the sites and updates their reminders. * Get the next events for all the sites and updates their reminders.
*/ */
@ -1415,21 +1328,6 @@ export class AddonCalendarProvider {
await this.getEventsList(undefined, undefined, undefined, siteId); await this.getEventsList(undefined, undefined, undefined, siteId);
} }
/**
* Get the next events for all the sites and schedules their notifications.
*
* @returns Promise resolved when done.
* @deprecated since 4.1. No replacement for that function.
*/
async scheduleEventsNotifications(
events: ({ id: number; timestart: number; timeduration: number; name: string})[],
siteId?: string,
): Promise<void> {
siteId = siteId || CoreSites.getCurrentSiteId();
await AddonCalendar.updateEventsReminders(events, siteId);
}
/** /**
* Schedules the notifications for a list of events. * Schedules the notifications for a list of events.
* If an event notification time is 0, cancel its scheduled notification (if any). * If an event notification time is 0, cancel its scheduled notification (if any).
@ -1470,18 +1368,6 @@ export class AddonCalendarProvider {
})); }));
} }
/**
* Set the default notification time.
*
* @param time New default time.
* @param siteId ID of the site. If not defined, use current site.
* @returns Promise resolved when stored.
* @deprecated since 4.1 Use CoreReminders.setDefaultNotificationTime.
*/
async setDefaultNotificationTime(time: number, siteId?: string): Promise<void> {
await CoreReminders.setDefaultNotificationTime(time, siteId);
}
/** /**
* Store an event in local DB as it is. * Store an event in local DB as it is.
* *
@ -2203,13 +2089,6 @@ export type AddonCalendarUpdatedEventEvent = {
sent?: boolean; sent?: boolean;
}; };
/**
* Value and unit for reminders.
*
* @deprecated since 4.1, use CoreReminderValueAndUnit instead.
*/
export type AddonCalendarValueAndUnit = CoreReminderValueAndUnit;
/** /**
* Options to pass to submit event. * Options to pass to submit event.
*/ */

View File

@ -77,7 +77,7 @@
{{ message.timecreated | coreFormatDate: "strftimedayshort" }} {{ message.timecreated | coreFormatDate: "strftimedayshort" }}
</h3> </h3>
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom > 0 && message.id === unreadMessageFrom" color="light"> <ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom > 0 && message.id === unreadMessageFrom">
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label> <ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
<ion-icon name="fas-arrow-down" aria-hidden="true" /> <ion-icon name="fas-arrow-down" aria-hidden="true" />
</ion-chip> </ion-chip>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -40,7 +40,7 @@
} }
} }
:host-context(html.dark) ::ng-deep { :host-context(:root.dark) ::ng-deep {
ion-item.submissioneditable p { ion-item.submissioneditable p {
color: var(--danger-tint); color: var(--danger-tint);
} }

View File

@ -449,7 +449,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
this.feedback, this.feedback,
this.submitId, this.submitId,
); );
} catch (error) { } catch {
// Error ocurred, consider there are no changes. // Error ocurred, consider there are no changes.
return false; return false;
} }

View File

@ -13,7 +13,7 @@
</ion-toolbar> </ion-toolbar>
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<ion-button [hidden]="!canSaveGrades" fill="clear" (click)="submitGrade()"> <ion-button [class.hidden]="!canSaveGrades" fill="clear" (click)="submitGrade()">
{{ 'core.done' | translate }} {{ 'core.done' | translate }}
</ion-button> </ion-button>
</core-navbar-buttons> </core-navbar-buttons>

View File

@ -100,6 +100,7 @@ Feature: Test marking workflow in assignment activity in app
And I press "Grade" in the app And I press "Grade" in the app
When I set the field "Grade out of 100" to "60" in the app When I set the field "Grade out of 100" to "60" in the app
And I press "Done" in the app And I press "Done" in the app
And I wait loading to finish in the app
And I press "Student1" in the app And I press "Student1" in the app
And I press "Grade" in the app And I press "Grade" in the app
Then I should find "60 / 100" within "Current grade in assignment" "ion-item" in the app Then I should find "60 / 100" within "Current grade in assignment" "ion-item" in the app
@ -112,6 +113,7 @@ Feature: Test marking workflow in assignment activity in app
And I press "Grade" in the app And I press "Grade" in the app
When I set the field "Grade out of 100" to "80" in the app When I set the field "Grade out of 100" to "80" in the app
And I press "Done" in the app And I press "Done" in the app
And I wait loading to finish in the app
And I press "Student3" in the app And I press "Student3" in the app
And I press "Grade" in the app And I press "Grade" in the app
Then I should find "80" within "Current grade in gradebook" "ion-item" in the app Then I should find "80" within "Current grade in gradebook" "ion-item" in the app

View File

@ -24,7 +24,7 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
--recording-details-background: var(--gray-800); --recording-details-background: var(--gray-800);
--recording-details-border: var(--gray-500); --recording-details-border: var(--gray-500);
} }

View File

@ -49,6 +49,8 @@ Feature: Test basic usage of BBB activity in app
And I should be able to press "Join session" in the app And I should be able to press "Join session" in the app
When I press "Join session" in the app When I press "Join session" in the app
# TODO: This step will make behat github actions work but we should find a better way to wait for the room to start.
And I wait "3" seconds
And I wait for the BigBlueButton room to start And I wait for the BigBlueButton room to start
And I switch back to the app And I switch back to the app
Then I should find "The session is in progress." in the app Then I should find "The session is in progress." in the app
@ -68,6 +70,8 @@ Feature: Test basic usage of BBB activity in app
And I should be able to press "Join session" in the app And I should be able to press "Join session" in the app
When I press "Join session" in the app When I press "Join session" in the app
# TODO: This step will make behat github actions work but we should find a better way to wait for the room to start.
And I wait "3" seconds
And I wait for the BigBlueButton room to start And I wait for the BigBlueButton room to start
And I switch back to the app And I switch back to the app
Then I should find "The session is in progress." in the app Then I should find "The session is in progress." in the app

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -35,7 +35,7 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
.addon-mod_h5pactivity-result-table-row.item:nth-child(even) { .addon-mod_h5pactivity-result-table-row.item:nth-child(even) {
--background: var(--gray-900); --background: var(--gray-900);
} }

View File

@ -31,7 +31,7 @@
<ion-input labelPlacement="stacked" name="password" type="password" <ion-input labelPlacement="stacked" name="password" type="password"
placeholder="{{ 'core.login.password' | translate }}" core-auto-focus #passwordinput [clearOnEdit]="false" placeholder="{{ 'core.login.password' | translate }}" core-auto-focus #passwordinput [clearOnEdit]="false"
[label]="'addon.mod_lesson.enterpassword' | translate"> [label]="'addon.mod_lesson.enterpassword' | translate">
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
</ion-item> </ion-item>
<ion-button expand="block" type="submit"> <ion-button expand="block" type="submit">

View File

@ -2,7 +2,7 @@
--background-odd: var(--light); --background-odd: var(--light);
} }
:host-context(html.dark) { :host-context(:root.dark) {
--background-odd: var(--medium); --background-odd: var(--medium);
} }

View File

@ -8,6 +8,6 @@
<ion-input id="addon-mod_quiz-accessrule-password-input" name="quizpassword" type="password" <ion-input id="addon-mod_quiz-accessrule-password-input" name="quizpassword" type="password"
placeholder="{{ 'addon.mod_quiz.quizpassword' | translate }}" [formControlName]="'quizpassword'" [clearOnEdit]="false" placeholder="{{ 'addon.mod_quiz.quizpassword' | translate }}" [formControlName]="'quizpassword'" [clearOnEdit]="false"
[attr.aria-label]="'addon.mod_quiz.quizpassword' | translate"> [attr.aria-label]="'addon.mod_quiz.quizpassword' | translate">
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
</ion-item> </ion-item>

View File

@ -11,7 +11,7 @@
</ion-title> </ion-title>
<ion-buttons slot="end"> <ion-buttons slot="end">
<ion-button fill="clear" id="addon-mod_quiz-connection-error-button" [hidden]="!autoSaveError" <ion-button fill="clear" id="addon-mod_quiz-connection-error-button" [class.hidden]="!autoSaveError"
(click)="showConnectionError($event)" [ariaLabel]="'addon.mod_quiz.connectionerror' | translate" aria-haspopup="dialog"> (click)="showConnectionError($event)" [ariaLabel]="'addon.mod_quiz.connectionerror' | translate" aria-haspopup="dialog">
<ion-icon name="fas-circle-exclamation" slot="icon-only" aria-hidden="true" /> <ion-icon name="fas-circle-exclamation" slot="icon-only" aria-hidden="true" />
</ion-button> </ion-button>

View File

@ -167,12 +167,16 @@ Feature: Attempt a quiz in app
And I press "Three" in the app And I press "Three" in the app
And I set the field "Answer" to "Berlin" in the app And I set the field "Answer" to "Berlin" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I set the field "Answer" to "testing" in the app And I set the field "Answer" to "testing" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I set the field "Answer" to "5" in the app And I set the field "Answer" to "5" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I set the field "Answer" to "Testing an essay" in the app And I set the field "Answer" to "Testing an essay" in the app
And I press "Next" "ion-button" in the app And I press "Next" "ion-button" in the app
And I wait loading to finish in the app
And I press "quick" ".drag" in the app And I press "quick" ".drag" in the app
And I click on ".place1.drop" "css" And I click on ".place1.drop" "css"
And I press "fox" ".drag" in the app And I press "fox" ".drag" in the app
@ -180,26 +184,33 @@ Feature: Attempt a quiz in app
And I press "lazy" ".drag" in the app And I press "lazy" ".drag" in the app
And I click on ".place3.drop" "css" And I click on ".place3.drop" "css"
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I press "True" in the app And I press "True" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I set the field "frog" to "amphibian" in the app And I set the field "frog" to "amphibian" in the app
And I set the field "newt" to "insect" in the app And I set the field "newt" to "insect" in the app
And I set the field "cat" to "mammal" in the app And I set the field "cat" to "mammal" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
Then I should find "Text of the eighth question" in the app Then I should find "Text of the eighth question" in the app
When I press "Next" in the app When I press "Next" in the app
And I wait loading to finish in the app
And I set the field "Blank 1" to "cat" in the app And I set the field "Blank 1" to "cat" in the app
And I set the field "Blank 2" to "mat" in the app And I set the field "Blank 2" to "mat" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I press "abyssal" ".drag" in the app And I press "abyssal" ".drag" in the app
And I click on ".place6.dropzone" "css" And I click on ".place6.dropzone" "css"
And I press "trench" ".drag" in the app And I press "trench" ".drag" in the app
And I click on ".place3.dropzone" "css" And I click on ".place3.dropzone" "css"
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I press "Railway station" ".marker" in the app And I press "Railway station" ".marker" in the app
And I click on "img.dropbackground" "css" And I click on "img.dropbackground" "css"
And I press "Submit" in the app And I press "Submit" in the app
And I wait loading to finish in the app
Then I should find "Answer saved" in the app Then I should find "Answer saved" in the app
And I should find "Incomplete answer" within "10" "ion-item" in the app And I should find "Incomplete answer" within "10" "ion-item" in the app
But I should not find "Not yet answered" in the app But I should not find "Not yet answered" in the app
@ -224,8 +235,10 @@ Feature: Attempt a quiz in app
When I press "True" in the app When I press "True" in the app
And I press "Next" in the app And I press "Next" in the app
And I wait loading to finish in the app
And I press "False" in the app And I press "False" in the app
And I press "Submit" in the app And I press "Submit" in the app
And I wait loading to finish in the app
And I press "Submit all and finish" in the app And I press "Submit all and finish" in the app
Then I should find "Once you submit" in the app Then I should find "Once you submit" in the app
But I should not find "Questions without a response" in the app But I should not find "Questions without a response" in the app

View File

@ -25,7 +25,7 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
--grid-background: var(--gray-900); --grid-background: var(--gray-900);
--even-background: var(--medium); --even-background: var(--medium);
} }

View File

@ -56,7 +56,7 @@ $addon-mod-wiki-toc-level-padding: 12px !default;
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
--addon-mod-wiki-newentry-link-color: var(--danger-tint); --addon-mod-wiki-newentry-link-color: var(--danger-tint);
--addon-mod-wiki-toc-background-color: var(--medium); --addon-mod-wiki-toc-background-color: var(--medium);
} }

View File

@ -10,8 +10,7 @@
</h1> </h1>
</ion-title> </ion-title>
<ion-buttons slot="end" [hidden]="!loaded"> <ion-buttons slot="end" [hidden]="!loaded">
<ion-button *ngIf="assessmentId && access.assessingallowed" fill="clear" (click)="saveAssessment()" <ion-button *ngIf="assessmentId && access.assessingallowed" fill="clear" (click)="saveAssessment()">
[ariaLabel]="'core.save' | translate">
{{ 'core.save' | translate }} {{ 'core.save' | translate }}
</ion-button> </ion-button>
<ion-button *ngIf="canAddFeedback" fill="clear" (click)="saveEvaluation()"> <ion-button *ngIf="canAddFeedback" fill="clear" (click)="saveEvaluation()">

View File

@ -11,7 +11,8 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<core-navbar-buttons slot="end"> <core-navbar-buttons slot="end">
<ion-button [hidden]="!canDeleteNotes" slot="end" fill="clear" (click)="toggleDelete()" [ariaLabel]="'core.toggledelete' | translate"> <ion-button [class.hidden]="!canDeleteNotes" slot="end" fill="clear" (click)="toggleDelete()"
[ariaLabel]="'core.toggledelete' | translate">
<ion-icon name="fas-pen" slot="icon-only" aria-hidden="true" /> <ion-icon name="fas-pen" slot="icon-only" aria-hidden="true" />
</ion-button> </ion-button>
<core-context-menu> <core-context-menu>

View File

@ -209,72 +209,6 @@ export class AddonNotificationsProvider {
return ROOT_CACHE_KEY + 'list'; return ROOT_CACHE_KEY + 'list';
} }
/**
* Get some notifications.
*
* @param notifications Current list of loaded notifications. It's used to calculate the offset.
* @param options Other options.
* @returns Promise resolved with notifications and if can load more.
* @deprecated since 4.1. Use getNotificationsWithStatus instead.
*/
async getNotifications(
notifications: AddonNotificationsNotificationMessageFormatted[],
options?: AddonNotificationsGetNotificationsOptions,
): Promise<{notifications: AddonNotificationsNotificationMessageFormatted[]; canLoadMore: boolean}> {
notifications = notifications || [];
options = options || {};
options.limit = options.limit || AddonNotificationsProvider.LIST_LIMIT;
options.siteId = options.siteId || CoreSites.getCurrentSiteId();
let newNotifications: AddonNotificationsNotificationMessageFormatted[];
// Request 1 more notification so we can know if there are more notifications.
const originalLimit = options.limit;
options.limit = options.limit + 1;
const site = await CoreSites.getSite(options.siteId);
if (site.isVersionGreaterEqualThan('4.0')) {
// In 4.0 the app can request read and unread at the same time.
options.offset = notifications.length;
newNotifications = await this.getNotificationsWithStatus(
AddonNotificationsGetReadType.BOTH,
options,
);
} else {
// We need 2 calls, one for read and the other one for unread.
options.offset = notifications.reduce((total, current) => total + (current.read ? 0 : 1), 0);
const unread = await this.getNotificationsWithStatus(AddonNotificationsGetReadType.UNREAD, options);
newNotifications = unread;
if (unread.length < options.limit) {
// Limit not reached. Get read notifications until reach the limit.
const readOptions = {
...options,
offset: notifications.length - options.offset,
limit: options.limit - unread.length,
};
try {
const read = await this.getNotificationsWithStatus(AddonNotificationsGetReadType.READ, readOptions);
newNotifications = unread.concat(read);
} catch (error) {
if (unread.length <= 0) {
throw error;
}
}
}
}
return {
notifications: newNotifications.slice(0, originalLimit),
canLoadMore: newNotifications.length > originalLimit,
};
}
/** /**
* Get notifications from site. * Get notifications from site.
* *

View File

@ -31,7 +31,7 @@ export class CoreSiteError extends CoreError {
} }
/** /**
* @deprecated This getter should not be called directly, but it's defined for backwards compatibility with many * @deprecated since 4.4. This getter should not be called directly, but it's defined for backwards compatibility with many
* parts of the code that type errors as any and use it. We cannot rename those because the errors could also be * parts of the code that type errors as any and use it. We cannot rename those because the errors could also be
* CoreWSError instances which do have an "errorcode" property. * CoreWSError instances which do have an "errorcode" property.
* *

View File

@ -55,14 +55,6 @@ export class CorePromisedValue<T = unknown> extends CorePromise<T> {
this.rejectPromise = rejectPromise; this.rejectPromise = rejectPromise;
} }
/**
* @returns Promise.
* @deprecated since 4.1. The instance can be directly used as a promise.
*/
get promise(): Promise<T> {
return this;
}
get value(): T | null { get value(): T | null {
return this.resolvedValue ?? null; return this.resolvedValue ?? null;
} }

View File

@ -475,23 +475,6 @@ export class CoreSite extends CoreAuthenticatedSite {
await this.openWithAutoLogin(false, url, options, alertMessage); await this.openWithAutoLogin(false, url, options, alertMessage);
} }
/**
* Open a URL in browser using auto-login in the Moodle site if available and the URL belongs to the site.
*
* @param url The URL to open.
* @param alertMessage If defined, an alert will be shown before opening the browser.
* @param options Other options.
* @returns Promise resolved when done, rejected otherwise.
* @deprecated since 4.1. Use openInBrowserWithAutoLogin instead, now it always checks that URL belongs to same site.
*/
async openInBrowserWithAutoLoginIfSameSite(
url: string,
alertMessage?: string,
options: CoreUtilsOpenInBrowserOptions = {},
): Promise<void> {
return this.openInBrowserWithAutoLogin(url, alertMessage, options);
}
/** /**
* Open a URL in inappbrowser using auto-login in the Moodle site if available. * Open a URL in inappbrowser using auto-login in the Moodle site if available.
* *
@ -506,23 +489,6 @@ export class CoreSite extends CoreAuthenticatedSite {
return iabInstance; return iabInstance;
} }
/**
* Open a URL in inappbrowser using auto-login in the Moodle site if available and the URL belongs to the site.
*
* @param url The URL to open.
* @param options Override default options passed to inappbrowser.
* @param alertMessage If defined, an alert will be shown before opening the inappbrowser.
* @returns Promise resolved when done.
* @deprecated since 4.1. Use openInAppWithAutoLogin instead, now it always checks that URL belongs to same site.
*/
async openInAppWithAutoLoginIfSameSite(
url: string,
options?: InAppBrowserOptions,
alertMessage?: string,
): Promise<InAppBrowserObject> {
return this.openInAppWithAutoLogin(url, options, alertMessage);
}
/** /**
* Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available. * Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available.
* *
@ -575,25 +541,6 @@ export class CoreSite extends CoreAuthenticatedSite {
} }
} }
/**
* Open a URL in browser or InAppBrowser using auto-login in the Moodle site if available and the URL belongs to the site.
*
* @param inApp True to open it in InAppBrowser, false to open in browser.
* @param url The URL to open.
* @param options Override default options passed to inappbrowser.
* @param alertMessage If defined, an alert will be shown before opening the browser/inappbrowser.
* @returns Promise resolved when done. Resolve param is returned only if inApp=true.
* @deprecated since 4.1. Use openWithAutoLogin instead, now it always checks that URL belongs to same site.
*/
async openWithAutoLoginIfSameSite(
inApp: boolean,
url: string,
options: InAppBrowserOptions & CoreUtilsOpenInBrowserOptions = {},
alertMessage?: string,
): Promise<InAppBrowserObject | void> {
return this.openWithAutoLogin(inApp, url, options, alertMessage);
}
/** /**
* Get the config of this site. * Get the config of this site.
* It is recommended to use getStoredConfig instead since it's faster and doesn't use network. * It is recommended to use getStoredConfig instead since it's faster and doesn't use network.

View File

@ -146,7 +146,7 @@
} }
.select-icon { .select-icon {
color: var(--ion-color-step-500, gray); color: var(--ion-text-color-step-500, gray);
} }
} }

View File

@ -97,7 +97,7 @@ import { CoreSitesListComponent } from './sites-list/sites-list';
CoreProgressBarComponent, CoreProgressBarComponent,
CoreRecaptchaComponent, CoreRecaptchaComponent,
CoreSendMessageFormComponent, CoreSendMessageFormComponent,
CoreShowPasswordComponent, CoreShowPasswordComponent, // eslint-disable-line deprecation/deprecation
CoreSitePickerComponent, CoreSitePickerComponent,
CoreSplitViewComponent, CoreSplitViewComponent,
// eslint-disable-next-line deprecation/deprecation // eslint-disable-next-line deprecation/deprecation
@ -153,7 +153,7 @@ import { CoreSitesListComponent } from './sites-list/sites-list';
CoreProgressBarComponent, CoreProgressBarComponent,
CoreRecaptchaComponent, CoreRecaptchaComponent,
CoreSendMessageFormComponent, CoreSendMessageFormComponent,
CoreShowPasswordComponent, CoreShowPasswordComponent, // eslint-disable-line deprecation/deprecation
CoreSitePickerComponent, CoreSitePickerComponent,
CoreSplitViewComponent, CoreSplitViewComponent,
// eslint-disable-next-line deprecation/deprecation // eslint-disable-next-line deprecation/deprecation

View File

@ -1,4 +1,4 @@
<ion-button [hidden]="hideMenu" fill="clear" [ariaLabel]="ariaLabel" (click)="showContextMenu($event)" aria-haspopup="true" <ion-button [class.hidden]="hideMenu" fill="clear" [ariaLabel]="ariaLabel" (click)="showContextMenu($event)" aria-haspopup="true"
[attr.aria-controls]="uniqueId"> [attr.aria-controls]="uniqueId">
<ion-icon [name]="icon" slot="icon-only" aria-hidden="true" /> <ion-icon [name]="icon" slot="icon-only" aria-hidden="true" />
</ion-button> </ion-button>

View File

@ -38,7 +38,7 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
&.dimmed { &.dimmed {
--text-color: var(--gray-300); --text-color: var(--gray-300);
} }

View File

@ -78,7 +78,7 @@
--margin-end: 12px; --margin-end: 12px;
} }
:host-context(html.dark) { :host-context(:root.dark) {
&.version_40:not(.colorize), &.version_40:not(.colorize),
&.version_current { &.version_current {
background-color: var(--white); background-color: var(--white);

View File

@ -40,12 +40,12 @@ const BUTTON_HIDDEN_CLASS = 'core-navbar-button-hidden';
* *
* You can use the [hidden] input to hide all the inner buttons if a certain condition is met. * You can use the [hidden] input to hide all the inner buttons if a certain condition is met.
* *
* IMPORTANT: Do not use *ngIf in the buttons inside this component, it can cause problems. Please use [hidden] instead. * IMPORTANT: Do not use *ngIf in the buttons inside this component, it can cause problems. Please use [class.hidden] instead.
* *
* Example usage: * Example usage:
* *
* <core-navbar-buttons slot="end"> * <core-navbar-buttons slot="end">
* <ion-button [hidden]="!buttonShown" [attr.aria-label]="Do something" (click)="action()"> * <ion-button [class.hidden]="!buttonShown" [ariaLabel]="Do something" (click)="action()">
* <ion-icon name="funnel" slot="icon-only" aria-hidden="true"></ion-icon> * <ion-icon name="funnel" slot="icon-only" aria-hidden="true"></ion-icon>
* </ion-button> * </ion-button>
* </core-navbar-buttons> * </core-navbar-buttons>

View File

@ -17,7 +17,7 @@
<ion-input [ariaLabel]="placeholder | translate" class="ion-text-wrap core-ioninput-password" name="password" <ion-input [ariaLabel]="placeholder | translate" class="ion-text-wrap core-ioninput-password" name="password"
type="password" placeholder="{{ placeholder | translate }}" [(ngModel)]="password" core-auto-focus type="password" placeholder="{{ placeholder | translate }}" [(ngModel)]="password" core-auto-focus
[clearOnEdit]="false"> [clearOnEdit]="false">
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
</ion-item> </ion-item>
<ion-item *ngIf="error" class="ion-text-wrap ion-padding-top text-danger"> <ion-item *ngIf="error" class="ion-text-wrap ion-padding-top text-danger">

View File

@ -1,5 +1,2 @@
<ng-content /> <ng-content />
<ion-button fill="clear" [ariaLabel]="(shown ? 'core.hide' : 'core.show') | translate" core-suppress-events (onClick)="toggle($event)" <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" *ngIf="!this.ionInput" />
(mousedown)="doNotBlur($event)" (keydown)="doNotBlur($event)" (keyup)="toggle($event)">
<ion-icon [name]="shown ? 'fas-eye-slash' : 'fas-eye'" slot="icon-only" aria-hidden="true" />
</ion-button>

View File

@ -1,31 +0,0 @@
@use "theme/globals" as *;
:host {
display: contents;
// Only applies to deprecated way (surrounding).
::ng-deep ion-input + ion-button {
background: transparent;
padding: 0 var(--inner-padding-end) 0 4px;
margin-top: 0;
margin-bottom: 0;
position: absolute;
@include safe-area-position(null, 0px, null, null);
top: 0;
}
// Only applies to deprecated way (surrounding).
::ng-deep ion-input {
--padding-end: 56px !important;
}
::ng-deep ion-input.input-label-placement-stacked + ion-button {
top: 14px;
}
}
ion-button {
z-index: 5;
pointer-events: visible;
}

View File

@ -12,173 +12,80 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { Component, OnInit, AfterViewInit, Input, ElementRef, ContentChild } from '@angular/core'; import { Component, AfterViewInit, Input, ContentChild, ViewEncapsulation } from '@angular/core';
import { IonInput } from '@ionic/angular'; import { IonInput } from '@ionic/angular';
import { CorePlatform } from '@services/platform';
import { CoreDomUtils } from '@services/utils/dom'; import { CoreDomUtils } from '@services/utils/dom';
import { CoreUtils } from '@services/utils/utils'; import { CoreUtils } from '@services/utils/utils';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
/** /**
* This component allows to show/hide a password. * This component allows to show/hide a password.
* It's meant to be used with ion-input. * It's meant to be used with ion-input as a slot of the input.
* It's recommended to use it as a slot of the input.
* *
* @description * @description
* *
* There are 2 ways to use ths component: * There are 2 ways to use ths component:
* - Slot it to start or end on the ion-input element. * - Slot it to start or end on the ion-input element.
* - Surround the ion-input with the password with this component. This is deprecated. * - Surround the ion-input with the password with this component. Not recommended.
*
* In order to help finding the input you can specify the name of the input or the ion-input element.
*
* *
* Example of new usage: * Example of new usage:
* *
* <ion-input type="password" name="password"> * <ion-input type="password">
* <core-show-password slot="end" /> * <core-show-password slot="end" />
* </ion-input> * </ion-input>
* *
* Example deprecated usage: * Example surrounding usage:
* *
* <core-show-password> * <core-show-password>
* <ion-input type="password" name="password"></ion-input> * <ion-input type="password" />
* </core-show-password> * </core-show-password>
*
* @deprecated since 4.5. Use <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" /> instead.
*/ */
@Component({ @Component({
selector: 'core-show-password', selector: 'core-show-password',
templateUrl: 'core-show-password.html', templateUrl: 'core-show-password.html',
styleUrls: ['show-password.scss'], styles: 'core-show-password { display: contents; }',
encapsulation: ViewEncapsulation.None,
}) })
export class CoreShowPasswordComponent implements OnInit, AfterViewInit { export class CoreShowPasswordComponent implements AfterViewInit {
@Input() initialShown?: boolean | string; // Whether the password should be shown at start.
@Input() name = ''; // Deprecated. Not used anymore.
@ContentChild(IonInput) ionInput?: IonInput | HTMLIonInputElement; // Deprecated. Use slot instead.
protected input?: HTMLInputElement;
protected hostElement: HTMLElement;
protected logger: CoreLogger;
constructor(element: ElementRef) {
this.hostElement = element.nativeElement;
this.logger = CoreLogger.getInstance('CoreShowPasswordComponent');
}
get shown(): boolean {
return this.input?.type === 'text';
}
set shown(shown: boolean) {
if (!this.input) {
return;
}
this.input.type = shown ? 'text' : 'password';
}
/** /**
* @inheritdoc * @deprecated since 4.5. Not used anymore.
*/ */
ngOnInit(): void { @Input() initialShown = '';
this.shown = CoreUtils.isTrueOrOne(this.initialShown);
} /**
* @deprecated since 4.4. Not used anymore.
*/
@Input() name = '';
/**
* @deprecated since 4.4. Use slotted solution instead.
*/
@ContentChild(IonInput) ionInput?: IonInput | HTMLIonInputElement;
/** /**
* @inheritdoc * @inheritdoc
*/ */
async ngAfterViewInit(): Promise<void> { async ngAfterViewInit(): Promise<void> {
await this.setInputElement(); CoreLogger.getInstance('CoreShowPasswordComponent')
.warn('Deprecated component, use <ion-input-password-toggle /> instead.');
if (!this.input) {
return;
}
// By default, don't autocapitalize and autocorrect.
if (!this.input.getAttribute('autocorrect')) {
this.input.setAttribute('autocorrect', 'off');
}
if (!this.input.getAttribute('autocapitalize')) {
this.input.setAttribute('autocapitalize', 'none');
}
}
/**
* Set the input element to affect.
*/
protected async setInputElement(): Promise<void> {
if (!this.ionInput) {
this.ionInput = this.hostElement.closest('ion-input') ?? undefined;
this.hostElement.setAttribute('slot', 'end');
} else {
// It's outside ion-input, warn devs.
this.logger.warn('Deprecated CoreShowPasswordComponent usage, it\'s not needed to surround ion-input anymore.');
}
// eslint-disable-next-line deprecation/deprecation
if (!this.ionInput) { if (!this.ionInput) {
return; return;
} }
try { // eslint-disable-next-line deprecation/deprecation
this.input = await this.ionInput.getInputElement(); const input = await CoreUtils.ignoreErrors(this.ionInput.getInputElement());
} catch { if (!input) {
// This should never fail, but it does in some testing environment because Ionic elements are not
// rendered properly. So in case this fails it will try to find through the name and ignore the error.
const name = this.ionInput.name;
if (!name) {
return;
}
this.input = this.hostElement.querySelector<HTMLInputElement>('input[name="' + name + '"]') ?? undefined;
}
}
/**
* Toggle show/hide password.
*
* @param event The mouse event.
*/
toggle(event: Event): void {
if (event.type === 'keyup' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
return; return;
} }
event.preventDefault(); const toggle = CoreDomUtils.convertToElement('<ion-input-password-toggle slot="end" />');
event.stopPropagation(); input.parentElement?.appendChild(toggle.children[0]);
const isFocused = document.activeElement === this.input;
this.shown = !this.shown;
// In Android, the keyboard is closed when the input type changes. Focus it again.
if (this.input && isFocused && CorePlatform.isAndroid()) {
CoreDomUtils.focusElement(this.input);
}
}
/**
* Do not loose focus.
*
* @param event The mouse event.
*/
doNotBlur(event: Event): void {
if (event.type === 'keydown' && !this.isValidKeyboardKey(<KeyboardEvent>event)) {
return;
}
event.preventDefault();
event.stopPropagation();
}
/**
* Checks if Space or Enter have been pressed.
*
* @param event Keyboard Event.
* @returns Wether space or enter have been pressed.
*/
protected isValidKeyboardKey(event: KeyboardEvent): boolean {
return event.key === ' ' || event.key === 'Enter';
} }
} }

View File

@ -77,7 +77,6 @@ import { Md5 } from 'ts-md5/dist/md5';
// Import core classes that can be useful for site plugins. // Import core classes that can be useful for site plugins.
import { CoreSyncBaseProvider } from '@classes/base-sync'; import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreArray } from '@singletons/array'; import { CoreArray } from '@singletons/array';
import { CoreComponentsRegistry } from '@singletons/components-registry';
import { CoreDirectivesRegistry } from '@singletons/directives-registry'; import { CoreDirectivesRegistry } from '@singletons/directives-registry';
import { CoreDom } from '@singletons/dom'; import { CoreDom } from '@singletons/dom';
import { CoreForms } from '@singletons/form'; import { CoreForms } from '@singletons/form';
@ -295,12 +294,13 @@ export class CoreCompileProvider {
instance['CoreLoggerProvider'] = CoreLogger; instance['CoreLoggerProvider'] = CoreLogger;
instance['moment'] = moment; instance['moment'] = moment;
instance['Md5'] = Md5; instance['Md5'] = Md5;
instance['Network'] = CoreNetwork.instance; // @deprecated since 4.1, plugins should use CoreNetwork instead. /**
instance['Platform'] = CorePlatform.instance; // @deprecated since 4.1, plugins should use CorePlatform instead. * @deprecated since 4.1, plugins should use CoreNetwork instead.
* Keeping this a bit more to avoid plugins breaking.
*/
instance['Network'] = CoreNetwork.instance;
instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider; instance['CoreSyncBaseProvider'] = CoreSyncBaseProvider;
instance['CoreArray'] = CoreArray; instance['CoreArray'] = CoreArray;
// eslint-disable-next-line deprecation/deprecation
instance['CoreComponentsRegistry'] = CoreComponentsRegistry;
instance['CoreDirectivesRegistry'] = CoreDirectivesRegistry; instance['CoreDirectivesRegistry'] = CoreDirectivesRegistry;
instance['CoreNetwork'] = CoreNetwork.instance; instance['CoreNetwork'] = CoreNetwork.instance;
instance['CorePlatform'] = CorePlatform.instance; instance['CorePlatform'] = CorePlatform.instance;

View File

@ -31,7 +31,8 @@ import { Component, HostBinding, Input } from '@angular/core';
* *
* <core-course-module-description [description]="myDescription"></core-course-module-description> * <core-course-module-description [description]="myDescription"></core-course-module-description>
* *
* @deprecated since 4.0 use core-course-module-info * @deprecated since 4.0 use core-course-module-info instead.
* Keeping this a bit more to avoid plugins breaking.
*/ */
@Component({ @Component({
selector: 'core-course-module-description', selector: 'core-course-module-description',

View File

@ -50,6 +50,6 @@
height: 0 !important; height: 0 !important;
} }
:host-context(html.dark) { :host-context(:root.dark) {
--button-color: var(--gray-100); --button-color: var(--gray-100);
} }

View File

@ -198,7 +198,7 @@
} }
:host-context(html.dark) { :host-context(:root.dark) {
.activity-description-availabilityinfo { .activity-description-availabilityinfo {
.core-module-availabilityinfo { .core-module-availabilityinfo {
background: var(--gray-800); background: var(--gray-800);

View File

@ -16,14 +16,11 @@ import { NgModule } from '@angular/core';
import { CoreSharedModule } from '@/core/shared.module'; import { CoreSharedModule } from '@/core/shared.module';
import { CoreCoursesCourseListItemComponent } from './course-list-item/course-list-item'; import { CoreCoursesCourseListItemComponent } from './course-list-item/course-list-item';
import { CoreCoursesCourseProgressComponent } from './course-progress/course-progress';
import { CoreCoursesCourseOptionsMenuComponent } from './course-options-menu/course-options-menu'; import { CoreCoursesCourseOptionsMenuComponent } from './course-options-menu/course-options-menu';
@NgModule({ @NgModule({
declarations: [ declarations: [
CoreCoursesCourseListItemComponent, CoreCoursesCourseListItemComponent,
// eslint-disable-next-line deprecation/deprecation
CoreCoursesCourseProgressComponent,
CoreCoursesCourseOptionsMenuComponent, CoreCoursesCourseOptionsMenuComponent,
], ],
imports: [ imports: [
@ -31,8 +28,6 @@ import { CoreCoursesCourseOptionsMenuComponent } from './course-options-menu/cou
], ],
exports: [ exports: [
CoreCoursesCourseListItemComponent, CoreCoursesCourseListItemComponent,
// eslint-disable-next-line deprecation/deprecation
CoreCoursesCourseProgressComponent,
CoreCoursesCourseOptionsMenuComponent, CoreCoursesCourseOptionsMenuComponent,
], ],
}) })

View File

@ -29,7 +29,7 @@
} }
:host-context(html.dark) { :host-context(:root.dark) {
--button-background: rgb(0 0 0 / 30%); --button-background: rgb(0 0 0 / 30%);
} }

View File

@ -1,2 +0,0 @@
<core-courses-course-list-item [course]="course" class="core-course-progress" [showDownload]="showDownload"
[layout]="showAll ? 'card' : 'summarycard'" />

View File

@ -1,42 +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 { Component, HostBinding, Input } from '@angular/core';
import { CoreCourseListItem } from '@features/courses/services/courses';
/**
* This component is meant to display a course for a list of courses with progress.
*
* Example usage:
*
* <core-courses-course-progress [course]="course">
* </core-courses-course-progress>
*
* @deprecated since 4.0. Use core-courses-course-list-item instead.
*/
@Component({
selector: 'core-courses-course-progress',
templateUrl: 'core-courses-course-progress.html',
})
export class CoreCoursesCourseProgressComponent {
@Input() course!: CoreCourseListItem; // The course to render.
@Input() showAll = false; // If true, will show all actions, options, star and progress.
@Input() showDownload = true; // If true, will show download button. Only works if the options menu is not shown.
@HostBinding('class.deprecated') get isDeprecated(): boolean {
return true;
}
}

View File

@ -27,7 +27,7 @@
<!-- Download all courses. --> <!-- Download all courses. -->
<div *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 0" <div *ngIf="downloadCoursesEnabled && myOverviewBlock && myOverviewBlock.filteredCourses.length > 0"
class="core-button-spinner"> class="core-button-spinner">
<ion-button *ngIf="!myOverviewBlock.prefetchCoursesData.loading" fill="clear" <ion-button *ngIf="!myOverviewBlock.prefetchCoursesData.loading" fill="clear" size="default"
(click)="myOverviewBlock.prefetchCourses()" (click)="myOverviewBlock.prefetchCourses()"
[attr.aria-label]="myOverviewBlock.prefetchCoursesData.statusTranslatable | translate"> [attr.aria-label]="myOverviewBlock.prefetchCoursesData.statusTranslatable | translate">
<ion-icon [name]="myOverviewBlock.prefetchCoursesData.icon" slot="icon-only" aria-hidden="true" /> <ion-icon [name]="myOverviewBlock.prefetchCoursesData.icon" slot="icon-only" aria-hidden="true" />

View File

@ -6,7 +6,7 @@
--background: var(--rte-editor-background); --background: var(--rte-editor-background);
} }
:host-context(html.dark) { :host-context(:root.dark) {
--color: var(--white); --color: var(--white);
--button-color: var(--gray-200); --button-color: var(--gray-200);
--button-active-color: var(--gray-500); --button-active-color: var(--gray-500);

View File

@ -5,7 +5,7 @@
--core-table-border-color: var(--stroke); --core-table-border-color: var(--stroke);
} }
:host-context(html.dark) { :host-context(:root.dark) {
--icon-color: var(--gray-200); --icon-color: var(--gray-200);
} }

View File

@ -166,7 +166,7 @@
} }
:host-context(html.dark) { :host-context(:root.dark) {
@if ($core-login-button-outline-dark) { @if ($core-login-button-outline-dark) {
form ion-button { form ion-button {
--background: white; --background: white;

View File

@ -53,7 +53,7 @@
<ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}" <ion-input name="password" type="password" placeholder="{{ 'core.login.password' | translate }}"
formControlName="password" [clearOnEdit]="false" autocomplete="current-password" enterkeyhint="go" formControlName="password" [clearOnEdit]="false" autocomplete="current-password" enterkeyhint="go"
required="true" [attr.aria-label]="'core.login.password' | translate "> required="true" [attr.aria-label]="'core.login.password' | translate ">
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
</ion-item> </ion-item>
<ion-button expand="block" type="submit" [disabled]="!credForm.valid" <ion-button expand="block" type="submit" [disabled]="!credForm.valid"

View File

@ -103,7 +103,7 @@
placeholder="{{ 'core.login.password' | translate }}" formControlName="password" [clearOnEdit]="false" placeholder="{{ 'core.login.password' | translate }}" formControlName="password" [clearOnEdit]="false"
autocomplete="new-password" required="true"> autocomplete="new-password" required="true">
<div slot="label" [core-mark-required]="true">{{ 'core.login.password' | translate }}</div> <div slot="label" [core-mark-required]="true">{{ 'core.login.password' | translate }}</div>
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
<p *ngIf="settings.passwordpolicy" class="core-input-footnote"> <p *ngIf="settings.passwordpolicy" class="core-input-footnote">
{{settings.passwordpolicy}} {{settings.passwordpolicy}}

View File

@ -65,7 +65,7 @@
placeholder="{{ 'core.login.password' | translate }}" formControlName="password" [clearOnEdit]="false" placeholder="{{ 'core.login.password' | translate }}" formControlName="password" [clearOnEdit]="false"
autocomplete="current-password" enterkeyhint="go" required="true" autocomplete="current-password" enterkeyhint="go" required="true"
[attr.aria-label]="'core.login.password' | translate"> [attr.aria-label]="'core.login.password' | translate">
<core-show-password slot="end" /> <ion-input-password-toggle slot="end" showIcon="fas-eye" hideIcon="fas-eye-slash" />
</ion-input> </ion-input>
</ion-item> </ion-item>
<ion-button type="submit" expand="block" [disabled]="!credForm.valid" <ion-button type="submit" expand="block" [disabled]="!credForm.valid"

View File

@ -11,6 +11,6 @@
} }
} }
:host-context(html.dark) { :host-context(:root.dark) {
--heading-text-color: var(--gray-400); --heading-text-color: var(--gray-400);
} }

View File

@ -91,7 +91,7 @@
} }
:host-context(html.dark) ion-item { :host-context(:root.dark) ion-item {
--core-global-search-result-content-color: var(--gray-400); --core-global-search-result-content-color: var(--gray-400);
--core-global-search-result-context-color: var(--gray-500); --core-global-search-result-context-color: var(--gray-500);
} }

View File

@ -437,7 +437,7 @@ export class CoreSettingsHelperProvider {
const isDark = CoreDomUtils.hasModeClass('dark'); const isDark = CoreDomUtils.hasModeClass('dark');
if (isDark !== enable) { if (isDark !== enable) {
CoreDomUtils.toggleModeClass('dark', enable, { includeLegacy: true }); CoreDomUtils.toggleModeClass('dark', enable);
this.darkModeObservable.next(enable); this.darkModeObservable.next(enable);
CoreApp.setSystemUIColors(); CoreApp.setSystemUIColors();

View File

@ -61,6 +61,6 @@
} }
:host-context(html.dark) { :host-context(:root.dark) {
--popover-background: var(--gray-700); --popover-background: var(--gray-700);
} }

View File

@ -30,9 +30,9 @@ import { CoreDatabaseTable } from '@classes/database/database-table';
import { CorePromisedValue } from '@classes/promised-value'; import { CorePromisedValue } from '@classes/promised-value';
import { Subscription } from 'rxjs'; import { Subscription } from 'rxjs';
import { CorePlatform } from '@services/platform'; import { CorePlatform } from '@services/platform';
import { CoreNetwork, CoreNetworkConnection } from '@services/network';
import { CoreMainMenuProvider } from '@features/mainmenu/services/mainmenu'; import { CoreMainMenuProvider } from '@features/mainmenu/services/mainmenu';
import { CoreKeyboard } from '@singletons/keyboard'; import { CoreKeyboard } from '@singletons/keyboard';
import { CoreNetwork } from './network';
/** /**
* Factory to provide some global functionalities, like access to the global app database. * Factory to provide some global functionalities, like access to the global app database.
@ -210,36 +210,6 @@ export class CoreAppProvider {
return storesConfig.default; return storesConfig.default;
} }
/**
* Get platform major version number.
*
* @returns The platform major number.
* @deprecated since 4.1.1. Use CorePlatform.getPlatformMajorVersion instead.
*/
getPlatformMajorVersion(): number {
return CorePlatform.getPlatformMajorVersion();
}
/**
* Checks if the app is running in an Android mobile or tablet device.
*
* @returns Whether the app is running in an Android mobile or tablet device.
* @deprecated since 4.1.1. Use CorePlatform.isAndroid instead.
*/
isAndroid(): boolean {
return CorePlatform.isAndroid();
}
/**
* Checks if the app is running in an iOS mobile or tablet device.
*
* @returns Whether the app is running in an iOS mobile or tablet device.
* @deprecated since 4.1.1. Use CorePlatform.isIOS instead.
*/
isIOS(): boolean {
return CorePlatform.isIOS();
}
/** /**
* Check if the keyboard is closing. * Check if the keyboard is closing.
* *
@ -270,16 +240,6 @@ export class CoreAppProvider {
return CoreKeyboard.isKeyboardVisible(); return CoreKeyboard.isKeyboardVisible();
} }
/**
* Checks if the app is running in a mobile or tablet device (Cordova).
*
* @returns Whether the app is running in a mobile or tablet device.
* @deprecated since 4.1. Use CorePlatform instead.
*/
isMobile(): boolean {
return CorePlatform.isMobile();
}
/** /**
* Checks if the current window is wider than a mobile. * Checks if the current window is wider than a mobile.
* *
@ -294,31 +254,12 @@ export class CoreAppProvider {
* *
* @returns Whether the app is online. * @returns Whether the app is online.
* @deprecated since 4.1. Use CoreNetwork instead. * @deprecated since 4.1. Use CoreNetwork instead.
* Keeping this a bit more to avoid plugins breaking.
*/ */
isOnline(): boolean { isOnline(): boolean {
return CoreNetwork.isOnline(); return CoreNetwork.isOnline();
} }
/**
* Check if device uses a limited connection.
*
* @returns Whether the device uses a limited connection.
* @deprecated since 4.1. Use CoreNetwork instead.
*/
isNetworkAccessLimited(): boolean {
return CoreNetwork.isNetworkAccessLimited();
}
/**
* Check if device uses a wifi connection.
*
* @returns Whether the device uses a wifi connection.
* @deprecated since 4.1. Use CoreNetwork instead.
*/
isWifi(): boolean {
return CoreNetwork.isWifi();
}
/** /**
* Open the keyboard. * Open the keyboard.
* *
@ -561,16 +502,6 @@ export class CoreAppProvider {
StatusBar.backgroundColorByHexString(color); StatusBar.backgroundColorByHexString(color);
} }
/**
* Set value of forceOffline flag. If true, the app will think the device is offline.
*
* @param value Value to set.
* @deprecated since 4.1. Use CoreNetwork.setForceConnectionMode instead.
*/
setForceOffline(value: boolean): void {
CoreNetwork.setForceConnectionMode(value ? CoreNetworkConnection.NONE : CoreNetworkConnection.WIFI);
}
/** /**
* Get the installed version for the given schema. * Get the installed version for the given schema.
* *

View File

@ -1015,17 +1015,6 @@ export class CoreFileProvider {
return promise.then((entry) => this.getMetadata(entry)); return promise.then((entry) => this.getMetadata(entry));
} }
/**
* Remove the starting slash of a path if it's there. E.g. '/sites/filepool' -> 'sites/filepool'.
*
* @param path Path.
* @returns Path without a slash in the first position.
* @deprecated since 4.1. Use CoreText.removeStartingSlash instead.
*/
removeStartingSlash(path: string): string {
return CoreText.removeStartingSlash(path);
}
/** /**
* Convenience function to copy or move an external file. * Convenience function to copy or move an external file.
* *

View File

@ -429,16 +429,6 @@ export class CoreLocalNotificationsProvider {
} }
} }
/**
* Returns whether local notifications are available.
*
* @returns Whether local notifications are available.
* @deprecated since 4.1. It will always return true.
*/
isAvailable(): boolean {
return true;
}
/** /**
* Returns whether local notifications plugin is available. * Returns whether local notifications plugin is available.
* *

View File

@ -111,22 +111,22 @@ export class CoreNetworkService extends Network {
const hadOfflineMessage = CoreDomUtils.hasModeClass('core-offline'); const hadOfflineMessage = CoreDomUtils.hasModeClass('core-offline');
CoreDomUtils.toggleModeClass('core-offline', !isOnline, { includeLegacy: true }); CoreDomUtils.toggleModeClass('core-offline', !isOnline);
if (isOnline && hadOfflineMessage) { if (isOnline && hadOfflineMessage) {
CoreDomUtils.toggleModeClass('core-online', true, { includeLegacy: true }); CoreDomUtils.toggleModeClass('core-online', true);
setTimeout(() => { setTimeout(() => {
CoreDomUtils.toggleModeClass('core-online', false, { includeLegacy: true }); CoreDomUtils.toggleModeClass('core-online', false);
}, 3000); }, 3000);
} else if (!isOnline) { } else if (!isOnline) {
CoreDomUtils.toggleModeClass('core-online', false, { includeLegacy: true }); CoreDomUtils.toggleModeClass('core-online', false);
} }
}); });
}); });
const isOnline = this.isOnline(); const isOnline = this.isOnline();
CoreDomUtils.toggleModeClass('core-offline', !isOnline, { includeLegacy: true }); CoreDomUtils.toggleModeClass('core-offline', !isOnline);
} }
/** /**

View File

@ -51,7 +51,7 @@ describe('CoreSitesProvider', () => {
CoreHTMLClasses.initialize(); CoreHTMLClasses.initialize();
CoreSites.initialize(); CoreSites.initialize();
expect(document.documentElement.classList.contains('ionic7')).toBe(true); expect(document.documentElement.classList.contains('ionic8')).toBe(true);
const site = mock(new CoreSite('42', siteUrl, 'token', { info: { const site = mock(new CoreSite('42', siteUrl, 'token', { info: {
sitename: 'Example Campus', sitename: 'Example Campus',

View File

@ -1790,17 +1790,12 @@ export class CoreDomUtilsProvider {
* *
* @param className Class name. * @param className Class name.
* @param enable Whether to add or remove the class. * @param enable Whether to add or remove the class.
* @param options Legacy options, deprecated since 4.1.
*/ */
toggleModeClass( toggleModeClass(
className: string, className: string,
enable = false, enable = false,
options: { includeLegacy: boolean } = { includeLegacy: false },
): void { ): void {
document.documentElement.classList.toggle(className, enable); document.documentElement.classList.toggle(className, enable);
// @deprecated since 4.1.
document.body.classList.toggle(className, enable && options.includeLegacy);
} }
} }

View File

@ -215,19 +215,6 @@ export class CoreTimeUtilsProvider {
return isoString.substring(0, isoString.indexOf('.')); return isoString.substring(0, isoString.indexOf('.'));
} }
/**
* Convert a text into user timezone timestamp.
*
* @param date To convert to timestamp.
* @param applyOffset Whether to apply offset to date or not.
* @returns Converted timestamp.
* @deprecated since 4.1. Use moment(date).unix() instead.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
convertToTimestamp(date: string, applyOffset?: boolean): number {
return moment(date).unix();
}
/** /**
* Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations. * Return the localized ISO format (i.e DDMMYY) from the localized moment format. Useful for translations.
* DO NOT USE this function for ion-datetime format. Moment escapes characters with [], but ion-datetime doesn't support it. * DO NOT USE this function for ion-datetime format. Moment escapes characters with [], but ion-datetime doesn't support it.

View File

@ -1185,7 +1185,7 @@ export class CoreUtilsProvider {
if (options.showBrowserWarning || options.showBrowserWarning === undefined) { if (options.showBrowserWarning || options.showBrowserWarning === undefined) {
try { try {
await CoreWindow.confirmOpenBrowserIfNeeded(originaUrl); await CoreWindow.confirmOpenBrowserIfNeeded(originaUrl);
} catch (error) { } catch {
return; // Cancelled, stop. return; // Cancelled, stop.
} }
} }
@ -1409,16 +1409,6 @@ export class CoreUtilsProvider {
return Object.keys(enumeration).filter(k => Number.isNaN(+k)) as K[]; return Object.keys(enumeration).filter(k => Number.isNaN(+k)) as K[];
} }
/**
* Create a deferred promise that can be resolved or rejected explicitly.
*
* @returns The deferred promise.
* @deprecated since 4.1. Use CorePromisedValue instead.
*/
promiseDefer<T>(): CorePromisedValue<T> {
return new CorePromisedValue<T>();
}
/** /**
* Given a promise, returns true if it's rejected or false if it's resolved. * Given a promise, returns true if it's rejected or false if it's resolved.
* *

View File

@ -17,21 +17,6 @@
*/ */
export class CoreArray { export class CoreArray {
/**
* Check whether an array contains an item.
*
* @param arr Array.
* @param item Item.
* @returns Whether item is within the array.
* @deprecated since 4.1. Use arr.includes() instead.
*/
static contains<T>(arr: T[], item: T): boolean {
// eslint-disable-next-line no-console
console.warn('CoreArray.contains is deprecated and will be removed soon. Please use array \'includes\' instead.');
return arr.indexOf(item) !== -1;
}
/** /**
* Flatten the first dimension of a multi-dimensional array. * Flatten the first dimension of a multi-dimensional array.
* *

View File

@ -1,94 +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 { Component } from '@angular/core';
import { AsyncDirective } from '@classes/async-directive';
import { CoreDirectivesRegistry } from '@singletons/directives-registry';
/**
* Registry to keep track of component instances.
*
* @deprecated since 4.1.1. Use CoreDirectivesRegistry instead.
*/
export class CoreComponentsRegistry {
/**
* Register a component instance.
*
* @param element Root element.
* @param instance Component instance.
*/
static register(element: Element, instance: unknown): void {
CoreDirectivesRegistry.register(element, instance);
}
/**
* Resolve a component instance.
*
* @param element Root element.
* @param componentClass Component class.
* @returns Component instance.
*/
static resolve<T>(element?: Element | null, componentClass?: ComponentConstructor<T>): T | null {
return CoreDirectivesRegistry.resolve(element, componentClass);
}
/**
* Get a component instances and fail if it cannot be resolved.
*
* @param element Root element.
* @param componentClass Component class.
* @returns Component instance.
*/
static require<T>(element: Element, componentClass?: ComponentConstructor<T>): T {
return CoreDirectivesRegistry.require(element, componentClass);
}
/**
* Get a component instances and wait to be ready.
*
* @param element Root element.
* @param componentClass Component class.
* @returns Promise resolved when done.
*/
static async waitComponentReady<T extends AsyncDirective>(
element: Element | null,
componentClass?: ComponentConstructor<T>,
): Promise<void> {
return CoreDirectivesRegistry.waitDirectiveReady(element, componentClass);
}
/**
* Waits all elements matching to be ready.
*
* @param element Element where to search.
* @param selector Selector to search on parent.
* @param componentClass Component class.
* @returns Promise resolved when done.
*/
static async waitComponentsReady<T extends AsyncDirective>(
element: Element,
selector: string,
componentClass?: ComponentConstructor<T>,
): Promise<void> {
return CoreDirectivesRegistry.waitDirectivesReady(element, selector, componentClass);
}
}
/**
* Component constructor.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type ComponentConstructor<T = Component> = { new(...args: any[]): T };

View File

@ -535,20 +535,6 @@ export class CoreDom {
); );
} }
/**
* Listen to click and Enter/Space keys in an element.
*
* @param element Element to listen to events.
* @param callback Callback to call when clicked or the key is pressed.
* @deprecated since 4.1.1: Use initializeClickableElementA11y instead.
*/
static onActivate(
element: HTMLElement & {disabled?: boolean},
callback: (event: MouseEvent | KeyboardEvent) => void,
): void {
this.initializeClickableElementA11y(element, callback);
}
/** /**
* Initializes a clickable element a11y calling the click action when pressed enter or space * Initializes a clickable element a11y calling the click action when pressed enter or space
* and adding tabindex and role if needed. * and adding tabindex and role if needed.

View File

@ -34,7 +34,7 @@ export class CoreHTMLClasses {
* Initialize HTML classes. * Initialize HTML classes.
*/ */
static initialize(): void { static initialize(): void {
CoreDomUtils.toggleModeClass('ionic7', true); CoreDomUtils.toggleModeClass('ionic8', true);
CoreDomUtils.toggleModeClass('development', CoreConstants.BUILD.isDevelopment); CoreDomUtils.toggleModeClass('development', CoreConstants.BUILD.isDevelopment);
CoreHTMLClasses.addVersionClass(MOODLEAPP_VERSION_PREFIX, CoreConstants.CONFIG.versionname.replace('-dev', '')); CoreHTMLClasses.addVersionClass(MOODLEAPP_VERSION_PREFIX, CoreConstants.CONFIG.versionname.replace('-dev', ''));
@ -72,9 +72,9 @@ export class CoreHTMLClasses {
parts[1] = parts[1] || '0'; parts[1] = parts[1] || '0';
parts[2] = parts[2] || '0'; parts[2] = parts[2] || '0';
CoreDomUtils.toggleModeClass(prefix + parts[0], true, { includeLegacy: true }); CoreDomUtils.toggleModeClass(prefix + parts[0], true);
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1], true, { includeLegacy: true }); CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1], true);
CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true, { includeLegacy: true }); CoreDomUtils.toggleModeClass(prefix + parts[0] + '-' + parts[1] + '-' + parts[2], true);
} }
/** /**
@ -88,7 +88,7 @@ export class CoreHTMLClasses {
continue; continue;
} }
CoreDomUtils.toggleModeClass(modeClass, false, { includeLegacy: true }); CoreDomUtils.toggleModeClass(modeClass, false);
} }
} }

View File

@ -12,8 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { CorePath } from './path';
/** /**
* Singleton with helper functions for text manipulation. * Singleton with helper functions for text manipulation.
*/ */
@ -70,16 +68,4 @@ export class CoreText {
return text.substring(1); return text.substring(1);
} }
/**
* Concatenate two paths, adding a slash between them if needed.
*
* @param leftPath Left path.
* @param rightPath Right path.
* @returns Concatenated path.
* @deprecated since 4.1. Use CorePath.concatenatePaths instead.
*/
static concatenatePaths(leftPath: string, rightPath: string): string {
return CorePath.concatenatePaths(leftPath, rightPath);
}
} }

View File

@ -196,10 +196,13 @@ export class TestingBehatBlockingService {
await CoreUtils.nextTick(); await CoreUtils.nextTick();
const blockingElements = Array.from( const blockingElements = Array.from(
document.querySelectorAll<HTMLElement>('div.core-loading-container, ion-loading, .click-block-active'), document.querySelectorAll<HTMLElement>('div.core-loading-container, ion-loading'),
); );
const isBlocked = blockingElements.some(element => { const isBlocked = blockingElements.some(element => {
// @TODO Fix ion-loading present check with CoreDom.isElementVisible.
// ion-loading never has offsetParent since position is fixed.
// Using isElementVisible solve the problem but will block behats (like BBB).
if (!element.offsetParent) { if (!element.offsetParent) {
return false; return false;
} }

View File

@ -159,11 +159,19 @@ export class TestingBehatRuntimeService {
*/ */
async waitLoadingToFinish(): Promise<void> { async waitLoadingToFinish(): Promise<void> {
await NgZone.run(async () => { await NgZone.run(async () => {
const elements = Array.from(document.body.querySelectorAll<HTMLElement>('core-loading')) const coreLoadingsPromises: Promise<unknown>[] =
.filter((element) => CoreDom.isElementVisible(element)); Array.from(document.body.querySelectorAll<HTMLElement>('core-loading'))
.filter((element) => CoreDom.isElementVisible(element))
.map(element => CoreDirectivesRegistry.waitDirectiveReady(element, CoreLoadingComponent));
await Promise.all(elements.map(element => const ionLoadingsPromises: Promise<unknown>[] =
CoreDirectivesRegistry.waitDirectiveReady(element, CoreLoadingComponent))); Array.from(document.body.querySelectorAll<HTMLIonLoadingElement>('ion-loading'))
.filter((element) => CoreDom.isElementVisible(element))
.map(element => element.onDidDismiss());
const promises = coreLoadingsPromises.concat(ionLoadingsPromises);
await Promise.all(promises);
}); });
} }

View File

@ -143,6 +143,6 @@
} }
html.dark .core-error-accordion { :root.dark .core-error-accordion {
--background-color: var(--gray-700); --background-color: var(--gray-700);
} }

View File

@ -8,7 +8,7 @@ core-format-text {
--core-format-text-viewer-icon-background: rgb(255 255 255 / 50%); --core-format-text-viewer-icon-background: rgb(255 255 255 / 50%);
} }
html.dark core-format-text { :root.dark core-format-text {
--core-format-text-viewer-icon-background: rgb(0 0 0 / 50%); --core-format-text-viewer-icon-background: rgb(0 0 0 / 50%);
} }
@ -378,7 +378,7 @@ ion-header.ios h1 core-format-text {
} }
} }
html.dark core-format-text select, :root.dark core-format-text select,
html.dark core-rich-text-editor .core-rte-editor select { :root.dark core-rich-text-editor .core-rte-editor select {
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'); background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23FFFFFF%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
} }

View File

@ -6,25 +6,6 @@ ion-fab[core-fab] {
} }
} }
// The following 4 selectors can probably be removed after Ionic migration to 7+
ion-fab.fab-horizontal-start {
left: calc(10px + var(--ion-safe-area-right, 0px));
}
&[dir=rtl] ion-fab.fab-horizontal-start {
right: calc(10px + var(--ion-safe-area-right, 0px));
left: unset
}
ion-fab.fab-horizontal-end {
right: calc(10px + var(--ion-safe-area-right, 0px));
}
&[dir=rtl] ion-fab.fab-horizontal-end {
left: calc(10px + var(--ion-safe-area-right, 0px));
right: unset
}
ion-content.has-collapsible-footer ion-fab { ion-content.has-collapsible-footer ion-fab {
bottom: calc(var(--core-collapsible-footer-height, 0px) + 10px); bottom: calc(var(--core-collapsible-footer-height, 0px) + 10px);
@include core-transition(all, 200ms); @include core-transition(all, 200ms);

View File

@ -2,6 +2,10 @@ ion-input {
&.input-disabled.md, &.input-disabled.ios { &.input-disabled.md, &.input-disabled.ios {
opacity: var(--mdl-input-disabled-opacity); opacity: var(--mdl-input-disabled-opacity);
} }
ion-input-password-toggle {
--ion-color-primary: var(--text-color);
}
} }
input[disabled], input[disabled],

View File

@ -15,10 +15,6 @@ ion-select {
} }
ion-select-popover { ion-select-popover {
ion-list ion-radio-group ion-item.select-interface-option ion-radio.hydrated::part(container) {
opacity: 1;
}
ion-item { ion-item {
font-size: var(--text-size); font-size: var(--text-size);
} }

View File

@ -1,9 +1,9 @@
@import "../globals.scss"; @import "../globals.scss";
ion-toast { ion-toast {
--color: var(--ion-color-step-50); --color: var(--ion-text-color-step-950);
--button-color: var(--primary); --button-color: var(--primary);
--background: var(--ion-color-step-800); --background: var(--ion-background-color-step-800);
@include media-breakpoint-down(sm) { @include media-breakpoint-down(sm) {
&::part(container) { &::part(container) {

View File

@ -1,7 +1,7 @@
swiper-container { swiper-container {
--swiper-theme-color: var(--ion-color-primary, #3880ff); --swiper-theme-color: var(--ion-color-primary, #3880ff);
--swiper-pagination-bullet-inactive-color: var(--ion-color-step-200, #cccccc); --swiper-pagination-bullet-inactive-color: var(--ion-text-color-step-800, #cccccc);
--swiper-pagination-color: var(--swiper-theme-color); --swiper-pagination-color: var(--swiper-theme-color);
--swiper-pagination-progressbar-bg-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.25); --swiper-pagination-progressbar-bg-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.25);
--swiper-scrollbar-bg-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1); --swiper-scrollbar-bg-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);

View File

@ -297,7 +297,7 @@
@mixin darkmode() { @mixin darkmode() {
$root: #{&}; $root: #{&};
@at-root #{add-root-selector($root, "html.dark")} { @at-root #{add-root-selector($root, ":root.dark")} {
@content; @content;
} }
} }

View File

@ -1,13 +1,13 @@
@import "./globals.scss"; @import "./globals.scss";
html.force-safe-area-margins { :root.force-safe-area-margins {
--ion-safe-area-left: 40px; --ion-safe-area-left: 40px;
--ion-safe-area-right: 40px; --ion-safe-area-right: 40px;
--ion-safe-area-top: 40px; --ion-safe-area-top: 40px;
--ion-safe-area-bottom: 40px; --ion-safe-area-bottom: 40px;
} }
html { :root {
--zoom-level: 100%; --zoom-level: 100%;
zoom: var(--zoom-level); zoom: var(--zoom-level);
@ -21,7 +21,7 @@ a {
cursor: pointer; cursor: pointer;
} }
html[dir=rtl] { :root[dir=rtl] {
--rotate-expandable: rotate(-90deg); --rotate-expandable: rotate(-90deg);
} }
@ -488,7 +488,7 @@ video::-webkit-media-text-track-display {
/** /**
* https://github.com/ionic-team/ionic-framework/blob/6ffbdbb3b2b69290cf25753d535bc7483bd7c6e8/BREAKING.md#css-utilities * https://github.com/ionic-team/ionic-framework/blob/6ffbdbb3b2b69290cf25753d535bc7483bd7c6e8/BREAKING.md#css-utilities
*/ */
[hidden] { [hidden], .hidden {
display: none !important; display: none !important;
} }

View File

@ -8,7 +8,7 @@
* Light Theme * Light Theme
* ------------------------------------------- * -------------------------------------------
*/ */
html { :root {
} }
@ -16,6 +16,6 @@ html {
* Dark Theme * Dark Theme
* ------------------------------------------- * -------------------------------------------
*/ */
html.dark { :root.dark {
} }

View File

@ -5,171 +5,198 @@
* http://ionicframework.com/docs/theming/ * http://ionicframework.com/docs/theming/
*/ */
html.dark { @mixin dark-palette() {
& {
// Ionic shades, defined for ionic internal use.
--ion-background-color-step-0: var(--black);
--ion-background-color-step-50: var(--gray-900);
--ion-background-color-step-100: var(--gray-900);
--ion-background-color-step-150: var(--gray-800);
--ion-background-color-step-200: var(--gray-800);
--ion-background-color-step-250: var(--gray-700);
--ion-background-color-step-300: var(--gray-700);
--ion-background-color-step-350: var(--gray-600);
--ion-background-color-step-400: var(--gray-600);
--ion-background-color-step-450: var(--gray-500);
--ion-background-color-step-500: var(--gray-500);
--ion-background-color-step-550: var(--gray-400);
--ion-background-color-step-600: var(--gray-400);
--ion-background-color-step-650: var(--gray-300);
--ion-background-color-step-700: var(--gray-300);
--ion-background-color-step-750: var(--gray-200);
--ion-background-color-step-800: var(--gray-200);
--ion-background-color-step-850: var(--gray-100);
--ion-background-color-step-900: var(--gray-100);
--ion-background-color-step-950: var(--gray-100);
--ion-background-color-step-1000: var(--white);
// Ionic shades, defined for ionic internal use. --ion-text-color-step-0: var(--white);
--ion-color-step-0: var(--black); --ion-text-color-step-50: var(--gray-100);
--ion-color-step-50: var(--gray-900); --ion-text-color-step-100: var(--gray-100);
--ion-color-step-100: var(--gray-900); --ion-text-color-step-150: var(--gray-200);
--ion-color-step-150: var(--gray-800); --ion-text-color-step-200: var(--gray-200);
--ion-color-step-200: var(--gray-800); --ion-text-color-step-250: var(--gray-300);
--ion-color-step-250: var(--gray-700); --ion-text-color-step-300: var(--gray-300);
--ion-color-step-300: var(--gray-700); --ion-text-color-step-350: var(--gray-400);
--ion-color-step-350: var(--gray-600); --ion-text-color-step-400: var(--gray-400);
--ion-color-step-400: var(--gray-600); --ion-text-color-step-450: var(--gray-500);
--ion-color-step-450: var(--gray-500); --ion-text-color-step-500: var(--gray-500);
--ion-color-step-500: var(--gray-500); --ion-text-color-step-550: var(--gray-600);
--ion-color-step-550: var(--gray-400); --ion-text-color-step-600: var(--gray-600);
--ion-color-step-600: var(--gray-400); --ion-text-color-step-650: var(--gray-700);
--ion-color-step-650: var(--gray-300); --ion-text-color-step-700: var(--gray-700);
--ion-color-step-700: var(--gray-300); --ion-text-color-step-750: var(--gray-800);
--ion-color-step-750: var(--gray-200); --ion-text-color-step-800: var(--gray-800);
--ion-color-step-800: var(--gray-200); --ion-text-color-step-850: var(--gray-900);
--ion-color-step-850: var(--gray-100); --ion-text-color-step-900: var(--gray-900);
--ion-color-step-900: var(--gray-100); --ion-text-color-step-950: var(--gray-900);
--ion-color-step-950: var(--gray-100); --ion-text-color-step-1000: var(--black);
--ion-color-step-1000: var(--white);
@each $color-name, $unused in $colors { @each $color-name, $unused in $colors {
@include generate-color($color-name, $colors, 'dark'); @include generate-color($color-name, $colors, 'dark');
}
--ion-background-color: #{$background-color-dark};
--ion-background-color-rgb: #{$background-color-dark-rgb};
--text-color: #{$text-color-dark};
--ion-text-color: var(--text-color);
--ion-text-color-rgb: #{$text-color-dark-rgb};
--subdued-text-color: var(--medium);
--stroke: var(--gray-700);
--contrast-background: var(--gray-900);
--loader-shine: 90 90 90;
--drop-shadow-top: 0px 2px 5px rgb(var(--mdl-shadow-boxShadowColor) / 1);
--drop-shadow-bottom: 0px -2px 5px rgb(var(--mdl-shadow-boxShadowColor) / 1);
--ion-card-color: var(--text-color);
--ion-card-background: var(--ion-item-background);
--ion-card-border-color: var(--stroke);
--ion-border-color: var(--stroke);
--ion-item-border-color: var(--stroke);
--core-input-stroke: var(--gray-600);
--core-input-text: var(--dark);
--core-input-background: var(--gray-900);
ion-content {
--background: var(--ion-background-color);
--background-alternative: var(--gray-900);
}
--core-bottom-tabs-badge-text-color: var(--primary-contrast);
--core-bottom-tabs-background: var(--gray-900);
--core-bottom-tabs-color: var(--gray-200);
ion-action-sheet {
.action-sheet-cancel {
--button-color: var(--danger-tint);
} }
--ion-background-color: #{$background-color-dark};
--ion-background-color-rgb: #{$background-color-dark-rgb};
--text-color: #{$text-color-dark};
--ion-text-color: var(--text-color);
--ion-text-color-rgb: #{$text-color-dark-rgb};
--subdued-text-color: var(--medium);
--stroke: var(--gray-700);
--contrast-background: var(--gray-900);
--loader-shine: 90 90 90;
--drop-shadow-top: 0px 2px 5px rgb(var(--mdl-shadow-boxShadowColor) / 1);
--drop-shadow-bottom: 0px -2px 5px rgb(var(--mdl-shadow-boxShadowColor) / 1);
--ion-card-color: var(--text-color);
--ion-card-background: var(--ion-item-background);
--ion-card-border-color: var(--stroke);
--ion-border-color: var(--stroke);
--ion-item-border-color: var(--stroke);
--core-input-stroke: var(--gray-600);
--core-input-text: var(--dark);
--core-input-background: var(--gray-900);
ion-content {
--background: var(--ion-background-color);
--background-alternative: var(--gray-900);
}
--core-bottom-tabs-badge-text-color: var(--primary-contrast);
--core-bottom-tabs-background: var(--gray-900);
--core-bottom-tabs-color: var(--gray-200);
ion-action-sheet {
.action-sheet-cancel {
--button-color: var(--danger-tint);
}
}
ion-popover,
ion-popover ion-content {
--background: var(--gray-800);
--ion-item-background: var(--background);
--ion-background-color: var(--background);
}
--core-link-color: var(--info-tint);
--core-header-toolbar-background: var(--gray-900);
--core-header-toolbar-color: var(--text-color);
--core-header-toolbar-border-color: var(--stroke);
--core-tabs-background: var(--gray-900);
--core-tab-background: var(--core-tabs-background);
--core-tab-color: var(--subdued-text-color);
--core-tab-border-color: var(--gray-200);
--core-tab-color-active: var(--dark);
--core-progressbar-text-color: var(--gray-100);
--core-empty-box-icon-color: var(--gray-700);
--ion-item-background: #{$ion-item-background-dark};
--ion-item-icon-color: var(--medium);
--ion-item-detail-icon-color: var(--dark);
--core-more-icon: var(--ion-item-icon-color);
--item-divider-background: var(--ion-item-background);
--item-divider-color: var(--text-color);
--spacer-background: var(--gray-700);
--ion-searchbar-background: var(--ion-background-color);
--ion-searchbar-border-color: var(--core-input-stroke);
--ion-searchbar-color: var(--text-color);
--ion-searchbar-icon-color: var(--core-input-stroke);
--core-search-box-background: var(--ion-background-color);
--core-search-box-border-color: var(--core-input-stroke);
--core-search-box-color: var(--core-input-text);
--core-combobox-background: var(--core-input-background);
--core-combobox-color: var(--text-color);
--core-combobox-border-color: var(--core-input-stroke);
--collapsible-toggle-text: var(--medium);
--background-gradient-rgb: #{$ion-item-background-dark-rgb};
--core-login-background: var(--gray-900);
--core-login-text-color: var(--white);
--core-login-input-background: var(--core-login-background);
--core-login-input-color: var(--core-login-text-color);
--core-question-correct-color: var(--success-tint);
--core-question-correct-color-bg: var(--success-shade);
--core-question-incorrect-color: var(--danger);
--core-question-incorrect-color-bg: var(--danger-shade);
--core-question-partial-color: var(--warning-tint);
--core-question-partial-color-bg: var(--warning-shade);
--core-question-feedback-color: var(--warning-tint);
--core-question-feedback-color-bg: var(--warning-shade);
--core-question-warning-color: var(--danger);
--core-question-saved-color-bg: var(--gray-500);
--core-question-feedback-color: var(--warning-tint);
--core-question-feedback-background-color: var(--warning-shade);
--core-dd-question-selected-shadow: 2px 2px 4px var(--gray-200);
--core-dd-question-border: var(--gray-200);
--core-send-message-input-background: var(--gray-900);
--core-send-message-input-color: var(--white);
--core-navigation-background: var(--contrast-background);
--core-collapsible-footer-background: var(--contrast-background);
--core-messages-message-bg: var(--gray-800);
--core-messages-message-activated-bg: var(--gray-700);
--core-messages-message-note-text: var(--subdued-text-color);
--core-messages-message-mine-bg: var(--gray-700);
--core-messages-message-mine-activated-bg: var(--gray-600);
--core-messages-discussion-badge: var(--primary);
--core-messages-discussion-badge-text: var(--gray-100);
--addon-forum-border-color: var(--gray-500);
--addon-forum-highlight-color: var(--gray-800);
--core-table-header-background: var(--gray-900);
--core-table-odd-cell-background: var(--gray-800);
--core-table-odd-cell-hover: var(--gray-600);
--core-table-even-cell-background: var(--gray-900);
--core-table-even-cell-hover: var(--gray-700);
} }
}
ion-popover,
ion-popover ion-content { :root.dark {
--background: var(--gray-800); @include dark-palette();
--ion-item-background: var(--background);
--ion-background-color: var(--background);
}
--core-link-color: var(--info-tint);
--core-header-toolbar-background: var(--gray-900);
--core-header-toolbar-color: var(--text-color);
--core-header-toolbar-border-color: var(--stroke);
--core-tabs-background: var(--gray-900);
--core-tab-background: var(--core-tabs-background);
--core-tab-color: var(--subdued-text-color);
--core-tab-border-color: var(--gray-200);
--core-tab-color-active: var(--dark);
--core-progressbar-text-color: var(--gray-100);
--core-empty-box-icon-color: var(--gray-700);
--ion-item-background: #{$ion-item-background-dark};
--ion-item-icon-color: var(--medium);
--ion-item-detail-icon-color: var(--dark);
--core-more-icon: var(--ion-item-icon-color);
--item-divider-background: var(--ion-item-background);
--item-divider-color: var(--text-color);
--spacer-background: var(--gray-700);
--ion-searchbar-background: var(--ion-background-color);
--ion-searchbar-border-color: var(--core-input-stroke);
--ion-searchbar-color: var(--text-color);
--ion-searchbar-icon-color: var(--core-input-stroke);
--core-search-box-background: var(--ion-background-color);
--core-search-box-border-color: var(--core-input-stroke);
--core-search-box-color: var(--core-input-text);
--core-combobox-background: var(--core-input-background);
--core-combobox-color: var(--text-color);
--core-combobox-border-color: var(--core-input-stroke);
--collapsible-toggle-text: var(--medium);
--background-gradient-rgb: #{$ion-item-background-dark-rgb};
--core-login-background: var(--gray-900);
--core-login-text-color: var(--white);
--core-login-input-background: var(--core-login-background);
--core-login-input-color: var(--core-login-text-color);
--core-question-correct-color: var(--success-tint);
--core-question-correct-color-bg: var(--success-shade);
--core-question-incorrect-color: var(--danger);
--core-question-incorrect-color-bg: var(--danger-shade);
--core-question-partial-color: var(--warning-tint);
--core-question-partial-color-bg: var(--warning-shade);
--core-question-feedback-color: var(--warning-tint);
--core-question-feedback-color-bg: var(--warning-shade);
--core-question-warning-color: var(--danger);
--core-question-saved-color-bg: var(--gray-500);
--core-question-feedback-color: var(--warning-tint);
--core-question-feedback-background-color: var(--warning-shade);
--core-dd-question-selected-shadow: 2px 2px 4px var(--gray-200);
--core-dd-question-border: var(--gray-200);
--core-send-message-input-background: var(--gray-900);
--core-send-message-input-color: var(--white);
--core-navigation-background: var(--contrast-background);
--core-collapsible-footer-background: var(--contrast-background);
--core-messages-message-bg: var(--gray-800);
--core-messages-message-activated-bg: var(--gray-700);
--core-messages-message-note-text: var(--subdued-text-color);
--core-messages-message-mine-bg: var(--gray-700);
--core-messages-message-mine-activated-bg: var(--gray-600);
--core-messages-discussion-badge: var(--primary);
--core-messages-discussion-badge-text: var(--gray-100);
--addon-forum-border-color: var(--gray-500);
--addon-forum-highlight-color: var(--gray-800);
--core-table-header-background: var(--gray-900);
--core-table-odd-cell-background: var(--gray-800);
--core-table-odd-cell-hover: var(--gray-600);
--core-table-even-cell-background: var(--gray-900);
--core-table-even-cell-hover: var(--gray-700);
} }

View File

@ -2,7 +2,7 @@
@import "theme.light.scss"; @import "theme.light.scss";
@import "theme.dark.scss"; @import "theme.dark.scss";
html { :root {
// Add serif fallback font for km language in some devices. // Add serif fallback font for km language in some devices.
--ion-font-family: var(--ion-default-font), serif; --ion-font-family: var(--ion-default-font), serif;
@ -243,7 +243,7 @@ html {
} }
/** @deprecated since 4.3 **/ /** @deprecated since 4.3 **/
html { :root {
--small-radius: var(--mdl-shape-borderRadius-xs); --small-radius: var(--mdl-shape-borderRadius-xs);
--medium-radius: var(--mdl-shape-borderRadius-sm); --medium-radius: var(--mdl-shape-borderRadius-sm);
--big-radius: var(--mdl-shape-borderRadius-lg); --big-radius: var(--mdl-shape-borderRadius-lg);
@ -251,7 +251,7 @@ html {
} }
/** @deprecated since 4.4 **/ /** @deprecated since 4.4 **/
html { :root {
--font-size-normal: var(--mdl-typography-fontSize-md); --font-size-normal: var(--mdl-typography-fontSize-md);
--a11y-min-target-size: var(--a11y-sizing-minTargetSize); --a11y-min-target-size: var(--a11y-sizing-minTargetSize);
--a11y-focus-width: var(--a11y-shadow-focus-boxShadowSpread); --a11y-focus-width: var(--a11y-shadow-focus-boxShadowSpread);

View File

@ -5,7 +5,7 @@
* http://ionicframework.com/docs/theming/ * http://ionicframework.com/docs/theming/
*/ */
html { :root {
// Color palette // Color palette
--black: #{$black}; --black: #{$black};
@ -21,27 +21,49 @@ html {
--white: #{$white}; --white: #{$white};
// Ionic shades, defined for ionic internal use. // Ionic shades, defined for ionic internal use.
--ion-color-step-0: var(--white); --ion-background-color-step-0: var(--white);
--ion-color-step-50: var(--gray-100); --ion-background-color-step-50: var(--gray-100);
--ion-color-step-100: var(--gray-100); --ion-background-color-step-100: var(--gray-100);
--ion-color-step-150: var(--gray-200); --ion-background-color-step-150: var(--gray-200);
--ion-color-step-200: var(--gray-200); --ion-background-color-step-200: var(--gray-200);
--ion-color-step-250: var(--gray-300); --ion-background-color-step-250: var(--gray-300);
--ion-color-step-300: var(--gray-300); --ion-background-color-step-300: var(--gray-300);
--ion-color-step-350: var(--gray-400); --ion-background-color-step-350: var(--gray-400);
--ion-color-step-400: var(--gray-400); --ion-background-color-step-400: var(--gray-400);
--ion-color-step-450: var(--gray-500); --ion-background-color-step-450: var(--gray-500);
--ion-color-step-500: var(--gray-500); --ion-background-color-step-500: var(--gray-500);
--ion-color-step-550: var(--gray-600); --ion-background-color-step-550: var(--gray-600);
--ion-color-step-600: var(--gray-600); --ion-background-color-step-600: var(--gray-600);
--ion-color-step-650: var(--gray-700); --ion-background-color-step-650: var(--gray-700);
--ion-color-step-700: var(--gray-700); --ion-background-color-step-700: var(--gray-700);
--ion-color-step-750: var(--gray-800); --ion-background-color-step-750: var(--gray-800);
--ion-color-step-800: var(--gray-800); --ion-background-color-step-800: var(--gray-800);
--ion-color-step-850: var(--gray-900); --ion-background-color-step-850: var(--gray-900);
--ion-color-step-900: var(--gray-900); --ion-background-color-step-900: var(--gray-900);
--ion-color-step-950: var(--gray-900); --ion-background-color-step-950: var(--gray-900);
--ion-color-step-1000: var(--black); --ion-background-color-step-1000: var(--black);
--ion-text-color-step-0: var(--black);
--ion-text-color-step-50: var(--gray-900);
--ion-text-color-step-100: var(--gray-900);
--ion-text-color-step-150: var(--gray-800);
--ion-text-color-step-200: var(--gray-800);
--ion-text-color-step-250: var(--gray-700);
--ion-text-color-step-300: var(--gray-700);
--ion-text-color-step-350: var(--gray-600);
--ion-text-color-step-400: var(--gray-600);
--ion-text-color-step-450: var(--gray-500);
--ion-text-color-step-500: var(--gray-500);
--ion-text-color-step-550: var(--gray-400);
--ion-text-color-step-600: var(--gray-400);
--ion-text-color-step-650: var(--gray-300);
--ion-text-color-step-700: var(--gray-300);
--ion-text-color-step-750: var(--gray-200);
--ion-text-color-step-800: var(--gray-200);
--ion-text-color-step-850: var(--gray-100);
--ion-text-color-step-900: var(--gray-100);
--ion-text-color-step-950: var(--gray-100);
--ion-text-color-step-1000: var(--white);
@each $color-name, $unused in $colors { @each $color-name, $unused in $colors {
@include generate-color($color-name, $colors, 'light'); @include generate-color($color-name, $colors, 'light');

View File

@ -29,36 +29,34 @@
@import "components/videojs.scss"; @import "components/videojs.scss";
/* Ionic components overrides */ /* Ionic components overrides */
html { @import "components/ion-accordion.scss";
@import "components/ion-accordion.scss"; @import "components/ion-action-sheet.scss";
@import "components/ion-action-sheet.scss"; @import "components/ion-alert.scss";
@import "components/ion-alert.scss"; @import "components/ion-avatar.scss";
@import "components/ion-avatar.scss"; @import "components/ion-back-button.scss";
@import "components/ion-back-button.scss"; @import "components/ion-badge.scss";
@import "components/ion-badge.scss"; @import "components/ion-button.scss";
@import "components/ion-button.scss"; @import "components/ion-card.scss";
@import "components/ion-card.scss"; @import "components/ion-checkbox.scss";
@import "components/ion-checkbox.scss"; @import "components/ion-chip.scss";
@import "components/ion-chip.scss"; @import "components/ion-content.scss";
@import "components/ion-content.scss"; @import "components/ion-datetime.scss";
@import "components/ion-datetime.scss"; @import "components/ion-fab.scss";
@import "components/ion-fab.scss"; @import "components/ion-header.scss";
@import "components/ion-header.scss"; @import "components/ion-icon.scss";
@import "components/ion-icon.scss"; @import "components/ion-input.scss";
@import "components/ion-input.scss"; @import "components/ion-item.scss";
@import "components/ion-item.scss"; @import "components/ion-item-divider.scss";
@import "components/ion-item-divider.scss"; @import "components/ion-modal.scss";
@import "components/ion-modal.scss"; @import "components/ion-loading.scss";
@import "components/ion-loading.scss"; @import "components/ion-note.scss";
@import "components/ion-note.scss"; @import "components/ion-popover.scss";
@import "components/ion-popover.scss"; @import "components/ion-radio.scss";
@import "components/ion-radio.scss"; @import "components/ion-searchbar.scss";
@import "components/ion-searchbar.scss"; @import "components/ion-select.scss";
@import "components/ion-select.scss"; @import "components/ion-spinner.scss";
@import "components/ion-spinner.scss"; @import "components/ion-toast.scss";
@import "components/ion-toast.scss"; @import "components/swiper.scss";
@import "components/swiper.scss";
}
/* Some styles from 3rd party libraries. */ /* Some styles from 3rd party libraries. */
@import "components/bootstrap/utilities/screenreaders.scss"; @import "components/bootstrap/utilities/screenreaders.scss";
@ -67,14 +65,26 @@ html {
@import "@ionic/angular/css/core.css"; @import "@ionic/angular/css/core.css";
/* Basic CSS for apps built with Ionic */ /* Basic CSS for apps built with Ionic */
@import "@ionic/angular/css/normalize.css"; @import '@ionic/angular/css/normalize.css';
@import "@ionic/angular/css/structure.css"; @import '@ionic/angular/css/structure.css';
@import "@ionic/angular/css/typography.css"; @import '@ionic/angular/css/typography.css';
@import "@ionic/angular/css/display.css";
/* Optional CSS utils that can be commented out */ /* Optional CSS utils that can be commented out */
@import "@ionic/angular/css/padding.css"; @import '@ionic/angular/css/padding.css';
@import "@ionic/angular/css/float-elements.css"; @import '@ionic/angular/css/float-elements.css';
@import "@ionic/angular/css/text-alignment.css"; @import '@ionic/angular/css/text-alignment.css';
@import "@ionic/angular/css/text-transformation.css"; @import '@ionic/angular/css/text-transformation.css';
@import "@ionic/angular/css/flex-utils.css"; @import '@ionic/angular/css/flex-utils.css';
@import '@ionic/angular/css/display.css';
/**
* Ionic Dark Palette
* -----------------------------------------------------
* For more information, please see:
* https://ionicframework.com/docs/theming/dark-mode
*/
/* @import '@ionic/angular/css/palettes/dark.always.css'; */
/* @import '@ionic/angular/css/palettes/dark.class.css'; */
/* @import '@ionic/angular/css/palettes/dark.system.css'; */

View File

@ -2,8 +2,15 @@ This file describes API changes in the Moodle App that affect site plugins, info
For more information about upgrading, read the official documentation: https://moodledev.io/general/app/upgrading/ For more information about upgrading, read the official documentation: https://moodledev.io/general/app/upgrading/
=== 4.5.0 ===
- Ionic has been upgraded to major version 8. See breaking changes and upgrade guide here: https://ionicframework.com/docs/updating/8-0
- core-show-password has been deprecated in favor of ion-input-password-toggle
=== 4.4.0 === === 4.4.0 ===
- Ionic has been upgraded to major version 7. See breaking changes and upgrade guide here: https://ionicframework.com/docs/updating/7-0 and https://ionicframework.com/docs/updating/6-0
- Starting with this release, this file will only document breaking changes for APIs exposed to site plugins. Internal changes will no longer be documented. - Starting with this release, this file will only document breaking changes for APIs exposed to site plugins. Internal changes will no longer be documented.
- CoreCache has been deprecated, use plain object as in-memory stores instead. - CoreCache has been deprecated, use plain object as in-memory stores instead.
- Renamed CoreLoginSitesComponent to CoreLoginSitesModalComponent to make it clear that it's a modal and to avoid confusing it with the new CoreSitesListComponent. - Renamed CoreLoginSitesComponent to CoreLoginSitesModalComponent to make it clear that it's a modal and to avoid confusing it with the new CoreSitesListComponent.