Merge pull request #4108 from crazyserver/MOBILE-4594
Mobile 4594 Update to Ionic8
							
								
								
									
										2
									
								
								.github/workflows/acceptance.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -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
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.github/workflows/testing.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -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"
 | 
				
			||||||
 | 
				
			|||||||
@ -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
									
									
									
								
							
							
						
						@ -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"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -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",
 | 
				
			||||||
 | 
				
			|||||||
@ -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';
 | 
				
			||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB  | 
@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB  | 
@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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">
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB  | 
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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()">
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
 | 
				
			|||||||
@ -146,7 +146,7 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        .select-icon {
 | 
					        .select-icon {
 | 
				
			||||||
            color: var(--ion-color-step-500, gray);
 | 
					            color: var(--ion-text-color-step-500, gray);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:host-context(html.dark) {
 | 
					:host-context(:root.dark) {
 | 
				
			||||||
    &.dimmed {
 | 
					    &.dimmed {
 | 
				
			||||||
        --text-color: var(--gray-300);
 | 
					        --text-color: var(--gray-300);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
				
			||||||
 | 
				
			|||||||
@ -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">
 | 
				
			||||||
 | 
				
			|||||||
@ -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>
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -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';
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
 | 
				
			|||||||
@ -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',
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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,
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
				
			|||||||
@ -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%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,2 +0,0 @@
 | 
				
			|||||||
<core-courses-course-list-item [course]="course" class="core-course-progress" [showDownload]="showDownload"
 | 
					 | 
				
			||||||
    [layout]="showAll ? 'card' : 'summarycard'" />
 | 
					 | 
				
			||||||
@ -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;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -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" />
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
 | 
				
			|||||||
@ -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"
 | 
				
			||||||
 | 
				
			|||||||
@ -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}}
 | 
				
			||||||
 | 
				
			|||||||
@ -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"
 | 
				
			||||||
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB  | 
| 
		 Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB  | 
@ -11,6 +11,6 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:host-context(html.dark) {
 | 
					:host-context(:root.dark) {
 | 
				
			||||||
    --heading-text-color: var(--gray-400);
 | 
					    --heading-text-color: var(--gray-400);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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();
 | 
				
			||||||
 | 
				
			|||||||
@ -61,6 +61,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:host-context(html.dark) {
 | 
					:host-context(:root.dark) {
 | 
				
			||||||
    --popover-background: var(--gray-700);
 | 
					    --popover-background: var(--gray-700);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 | 
				
			|||||||
@ -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',
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
@ -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 };
 | 
					 | 
				
			||||||
@ -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.
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -143,6 +143,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
html.dark .core-error-accordion {
 | 
					:root.dark .core-error-accordion {
 | 
				
			||||||
    --background-color: var(--gray-700);
 | 
					    --background-color: var(--gray-700);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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],
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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) {
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
 * Light Theme
 | 
					 * Light Theme
 | 
				
			||||||
 * -------------------------------------------
 | 
					 * -------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
html {
 | 
					:root {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -16,6 +16,6 @@ html {
 | 
				
			|||||||
 * Dark Theme
 | 
					 * Dark Theme
 | 
				
			||||||
 * -------------------------------------------
 | 
					 * -------------------------------------------
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
html.dark {
 | 
					:root.dark {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -5,30 +5,52 @@
 | 
				
			|||||||
 * http://ionicframework.com/docs/theming/
 | 
					 * http://ionicframework.com/docs/theming/
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
html.dark {
 | 
					@mixin dark-palette() {
 | 
				
			||||||
 | 
					    & {
 | 
				
			||||||
        // Ionic shades, defined for ionic internal use.
 | 
					        // Ionic shades, defined for ionic internal use.
 | 
				
			||||||
    --ion-color-step-0:    var(--black);
 | 
					        --ion-background-color-step-0:    var(--black);
 | 
				
			||||||
    --ion-color-step-50:   var(--gray-900);
 | 
					        --ion-background-color-step-50:   var(--gray-900);
 | 
				
			||||||
    --ion-color-step-100:  var(--gray-900);
 | 
					        --ion-background-color-step-100:  var(--gray-900);
 | 
				
			||||||
    --ion-color-step-150:  var(--gray-800);
 | 
					        --ion-background-color-step-150:  var(--gray-800);
 | 
				
			||||||
    --ion-color-step-200:  var(--gray-800);
 | 
					        --ion-background-color-step-200:  var(--gray-800);
 | 
				
			||||||
    --ion-color-step-250:  var(--gray-700);
 | 
					        --ion-background-color-step-250:  var(--gray-700);
 | 
				
			||||||
    --ion-color-step-300:  var(--gray-700);
 | 
					        --ion-background-color-step-300:  var(--gray-700);
 | 
				
			||||||
    --ion-color-step-350:  var(--gray-600);
 | 
					        --ion-background-color-step-350:  var(--gray-600);
 | 
				
			||||||
    --ion-color-step-400:  var(--gray-600);
 | 
					        --ion-background-color-step-400:  var(--gray-600);
 | 
				
			||||||
    --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-400);
 | 
					        --ion-background-color-step-550:  var(--gray-400);
 | 
				
			||||||
    --ion-color-step-600:  var(--gray-400);
 | 
					        --ion-background-color-step-600:  var(--gray-400);
 | 
				
			||||||
    --ion-color-step-650:  var(--gray-300);
 | 
					        --ion-background-color-step-650:  var(--gray-300);
 | 
				
			||||||
    --ion-color-step-700:  var(--gray-300);
 | 
					        --ion-background-color-step-700:  var(--gray-300);
 | 
				
			||||||
    --ion-color-step-750:  var(--gray-200);
 | 
					        --ion-background-color-step-750:  var(--gray-200);
 | 
				
			||||||
    --ion-color-step-800:  var(--gray-200);
 | 
					        --ion-background-color-step-800:  var(--gray-200);
 | 
				
			||||||
    --ion-color-step-850:  var(--gray-100);
 | 
					        --ion-background-color-step-850:  var(--gray-100);
 | 
				
			||||||
    --ion-color-step-900:  var(--gray-100);
 | 
					        --ion-background-color-step-900:  var(--gray-100);
 | 
				
			||||||
    --ion-color-step-950:  var(--gray-100);
 | 
					        --ion-background-color-step-950:  var(--gray-100);
 | 
				
			||||||
    --ion-color-step-1000: var(--white);
 | 
					        --ion-background-color-step-1000: var(--white);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        --ion-text-color-step-0:    var(--white);
 | 
				
			||||||
 | 
					        --ion-text-color-step-50:   var(--gray-100);
 | 
				
			||||||
 | 
					        --ion-text-color-step-100:  var(--gray-100);
 | 
				
			||||||
 | 
					        --ion-text-color-step-150:  var(--gray-200);
 | 
				
			||||||
 | 
					        --ion-text-color-step-200:  var(--gray-200);
 | 
				
			||||||
 | 
					        --ion-text-color-step-250:  var(--gray-300);
 | 
				
			||||||
 | 
					        --ion-text-color-step-300:  var(--gray-300);
 | 
				
			||||||
 | 
					        --ion-text-color-step-350:  var(--gray-400);
 | 
				
			||||||
 | 
					        --ion-text-color-step-400:  var(--gray-400);
 | 
				
			||||||
 | 
					        --ion-text-color-step-450:  var(--gray-500);
 | 
				
			||||||
 | 
					        --ion-text-color-step-500:  var(--gray-500);
 | 
				
			||||||
 | 
					        --ion-text-color-step-550:  var(--gray-600);
 | 
				
			||||||
 | 
					        --ion-text-color-step-600:  var(--gray-600);
 | 
				
			||||||
 | 
					        --ion-text-color-step-650:  var(--gray-700);
 | 
				
			||||||
 | 
					        --ion-text-color-step-700:  var(--gray-700);
 | 
				
			||||||
 | 
					        --ion-text-color-step-750:  var(--gray-800);
 | 
				
			||||||
 | 
					        --ion-text-color-step-800:  var(--gray-800);
 | 
				
			||||||
 | 
					        --ion-text-color-step-850:  var(--gray-900);
 | 
				
			||||||
 | 
					        --ion-text-color-step-900:  var(--gray-900);
 | 
				
			||||||
 | 
					        --ion-text-color-step-950:  var(--gray-900);
 | 
				
			||||||
 | 
					        --ion-text-color-step-1000: var(--black);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @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');
 | 
				
			||||||
@ -173,3 +195,8 @@ html.dark {
 | 
				
			|||||||
        --core-table-even-cell-hover: var(--gray-700);
 | 
					        --core-table-even-cell-hover: var(--gray-700);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:root.dark {
 | 
				
			||||||
 | 
					    @include dark-palette();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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');
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,6 @@
 | 
				
			|||||||
@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";
 | 
				
			||||||
@ -58,7 +57,6 @@ html {
 | 
				
			|||||||
@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'; */
 | 
				
			||||||
 | 
				
			|||||||
@ -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.
 | 
				
			||||||
 | 
				
			|||||||