commit
						8b1113ab37
					
				
							
								
								
									
										2
									
								
								.github/workflows/mirror.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/mirror.yml
									
									
									
									
										vendored
									
									
								
							| @ -2,7 +2,7 @@ name: Mirror | |||||||
| 
 | 
 | ||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: [ master, integration ] |     branches: [ master, main, unscheduled, integration, beta ] | ||||||
| 
 | 
 | ||||||
| jobs: | jobs: | ||||||
|   mirror: |   mirror: | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								.github/workflows/prepare.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/prepare.yml
									
									
									
									
										vendored
									
									
								
							| @ -2,7 +2,7 @@ name: Prepare | |||||||
| 
 | 
 | ||||||
| on: | on: | ||||||
|   push: |   push: | ||||||
|     branches: [ master, integration, freemium-master ] |     branches: [ master, main, unscheduled, integration, beta, freemium-master, freemium-main ] | ||||||
| 
 | 
 | ||||||
| jobs: | jobs: | ||||||
|   prepare: |   prepare: | ||||||
|  | |||||||
| @ -1,6 +1,8 @@ | |||||||
| os: linux | os: linux | ||||||
| dist: trusty | dist: trusty | ||||||
| node_js: 14 | node_js: 14 | ||||||
|  | jdk: | ||||||
|  |   - oraclejdk11 | ||||||
| 
 | 
 | ||||||
| git: | git: | ||||||
|   depth: 3 |   depth: 3 | ||||||
| @ -51,7 +53,10 @@ jobs: | |||||||
|       - npm --version |       - npm --version | ||||||
|       - nvm --version |       - nvm --version | ||||||
|       - npm ci |       - npm ci | ||||||
|  |       - export JAVA_HOME_COPY=$JAVA_HOME | ||||||
|  |       - export JAVA_HOME=/usr/lib/jvm/java-8-oracle | ||||||
|       - yes | sdkmanager "build-tools;30.0.3" |       - yes | sdkmanager "build-tools;30.0.3" | ||||||
|  |       - export JAVA_HOME=$JAVA_HOME_COPY | ||||||
|     addons: |     addons: | ||||||
|       apt: |       apt: | ||||||
|         packages: |         packages: | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								config.xml
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								config.xml
									
									
									
									
									
								
							| @ -40,7 +40,7 @@ | |||||||
|     <preference name="SplashMaintainAspectRatio" value="true" /> |     <preference name="SplashMaintainAspectRatio" value="true" /> | ||||||
|     <preference name="SplashShowOnlyFirstTime" value="false" /> |     <preference name="SplashShowOnlyFirstTime" value="false" /> | ||||||
|     <preference name="android-minSdkVersion" value="22" /> |     <preference name="android-minSdkVersion" value="22" /> | ||||||
|     <preference name="android-targetSdkVersion" value="30" /> |     <preference name="android-targetSdkVersion" value="31" /> | ||||||
|     <preference name="AndroidPersistentFileLocation" value="Compatibility" /> |     <preference name="AndroidPersistentFileLocation" value="Compatibility" /> | ||||||
|     <preference name="AndroidInsecureFileModeEnabled" value="true" /> |     <preference name="AndroidInsecureFileModeEnabled" value="true" /> | ||||||
|     <preference name="CustomURLSchemePluginClearsAndroidIntent" value="true" /> |     <preference name="CustomURLSchemePluginClearsAndroidIntent" value="true" /> | ||||||
| @ -64,7 +64,7 @@ | |||||||
|         <resource-file src="resources/android/icon/drawable-xhdpi-smallicon.png" target="app/src/main/res/mipmap-xhdpi/smallicon.png" /> |         <resource-file src="resources/android/icon/drawable-xhdpi-smallicon.png" target="app/src/main/res/mipmap-xhdpi/smallicon.png" /> | ||||||
|         <resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" /> |         <resource-file src="resources/android/xml/network_security_config.xml" target="app/src/main/res/xml/network_security_config.xml" /> | ||||||
|         <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application/activity[@android:name='MainActivity']"> |         <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application/activity[@android:name='MainActivity']"> | ||||||
|             <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|screenLayout|smallestScreenSize" /> |             <activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|screenLayout|smallestScreenSize" android:exported="true" /> | ||||||
|         </edit-config> |         </edit-config> | ||||||
|         <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application"> |         <edit-config file="AndroidManifest.xml" mode="merge" target="/manifest/application"> | ||||||
|             <application android:largeHeap="true" android:networkSecurityConfig="@xml/network_security_config" /> |             <application android:largeHeap="true" android:networkSecurityConfig="@xml/network_security_config" /> | ||||||
| @ -196,21 +196,6 @@ | |||||||
|                 <param name="android-package" value="com.adobe.phonegap.push.PushPlugin" /> |                 <param name="android-package" value="com.adobe.phonegap.push.PushPlugin" /> | ||||||
|             </feature> |             </feature> | ||||||
|         </config-file> |         </config-file> | ||||||
|         <config-file parent="/manifest/application" target="AndroidManifest.xml"> |  | ||||||
|             <activity android:exported="true" android:name="com.adobe.phonegap.push.PushHandlerActivity" android:permission="${applicationId}.permission.PushHandlerActivity" /> |  | ||||||
|             <receiver android:name="com.adobe.phonegap.push.BackgroundActionButtonHandler" /> |  | ||||||
|             <receiver android:name="com.adobe.phonegap.push.PushDismissedHandler" /> |  | ||||||
|             <service android:name="com.adobe.phonegap.push.FCMService"> |  | ||||||
|                 <intent-filter> |  | ||||||
|                     <action android:name="com.google.firebase.MESSAGING_EVENT" /> |  | ||||||
|                 </intent-filter> |  | ||||||
|             </service> |  | ||||||
|             <service android:name="com.adobe.phonegap.push.PushInstanceIDListenerService"> |  | ||||||
|                 <intent-filter> |  | ||||||
|                     <action android:name="com.google.firebase.INSTANCE_ID_EVENT" /> |  | ||||||
|                 </intent-filter> |  | ||||||
|             </service> |  | ||||||
|         </config-file> |  | ||||||
|         <config-file parent="/*" target="res/xml/config.xml"> |         <config-file parent="/*" target="res/xml/config.xml"> | ||||||
|             <feature name="Media"> |             <feature name="Media"> | ||||||
|                 <param name="android-package" value="org.apache.cordova.media.AudioHandler" /> |                 <param name="android-package" value="org.apache.cordova.media.AudioHandler" /> | ||||||
|  | |||||||
| @ -241,13 +241,13 @@ | |||||||
|     "publisher": "Ionic Team", |     "publisher": "Ionic Team", | ||||||
|     "licenseFile": "LICENSE" |     "licenseFile": "LICENSE" | ||||||
|   }, |   }, | ||||||
|   "@moodlehq/cordova-plugin-local-notification@0.9.0-moodle.3": { |   "@moodlehq/cordova-plugin-local-notification@0.9.0-moodle.7": { | ||||||
|     "licenses": "Apache*", |     "licenses": "Apache*", | ||||||
|     "repository": "https://github.com/moodlemobile/cordova-plugin-local-notification", |     "repository": "https://github.com/moodlemobile/cordova-plugin-local-notification", | ||||||
|     "publisher": "Sebastián Katzer", |     "publisher": "Sebastián Katzer", | ||||||
|     "licenseFile": "LICENSE" |     "licenseFile": "LICENSE" | ||||||
|   }, |   }, | ||||||
|   "@moodlehq/cordova-plugin-qrscanner@3.0.1-moodle.2": { |   "@moodlehq/cordova-plugin-qrscanner@3.0.1-moodle.4": { | ||||||
|     "licenses": "MIT", |     "licenses": "MIT", | ||||||
|     "repository": "https://github.com/moodlemobile/cordova-plugin-qrscanner", |     "repository": "https://github.com/moodlemobile/cordova-plugin-qrscanner", | ||||||
|     "publisher": "Jason Dreyzehner", |     "publisher": "Jason Dreyzehner", | ||||||
| @ -258,7 +258,7 @@ | |||||||
|     "repository": "https://github.com/moodlemobile/cordova-plugin-zip", |     "repository": "https://github.com/moodlemobile/cordova-plugin-zip", | ||||||
|     "licenseFile": "LICENSE" |     "licenseFile": "LICENSE" | ||||||
|   }, |   }, | ||||||
|   "@moodlehq/phonegap-plugin-push@2.0.0-moodle.4": { |   "@moodlehq/phonegap-plugin-push@4.0.0-moodle.2": { | ||||||
|     "licenses": "MIT", |     "licenses": "MIT", | ||||||
|     "repository": "https://github.com/moodlemobile/phonegap-plugin-push", |     "repository": "https://github.com/moodlemobile/phonegap-plugin-push", | ||||||
|     "publisher": "Erisu", |     "publisher": "Erisu", | ||||||
| @ -2669,7 +2669,7 @@ | |||||||
|     "url": "https://github.com/ichernev", |     "url": "https://github.com/ichernev", | ||||||
|     "licenseFile": "LICENSE" |     "licenseFile": "LICENSE" | ||||||
|   }, |   }, | ||||||
|   "moodlemobile@4.0.0": { |   "moodlemobile@4.0.2": { | ||||||
|     "licenses": "Apache-2.0", |     "licenses": "Apache-2.0", | ||||||
|     "repository": "https://github.com/moodlehq/moodleapp", |     "repository": "https://github.com/moodlehq/moodleapp", | ||||||
|     "publisher": "Moodle Pty Ltd.", |     "publisher": "Moodle Pty Ltd.", | ||||||
|  | |||||||
							
								
								
									
										3455
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										3455
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -77,10 +77,10 @@ | |||||||
|     "@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5", |     "@moodlehq/cordova-plugin-file-transfer": "1.7.1-moodle.5", | ||||||
|     "@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3", |     "@moodlehq/cordova-plugin-inappbrowser": "5.0.0-moodle.3", | ||||||
|     "@moodlehq/cordova-plugin-ionic-webview": "5.0.0-moodle.1", |     "@moodlehq/cordova-plugin-ionic-webview": "5.0.0-moodle.1", | ||||||
|     "@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.3", |     "@moodlehq/cordova-plugin-local-notification": "0.9.0-moodle.7", | ||||||
|     "@moodlehq/cordova-plugin-qrscanner": "3.0.1-moodle.4", |     "@moodlehq/cordova-plugin-qrscanner": "3.0.1-moodle.4", | ||||||
|     "@moodlehq/cordova-plugin-zip": "3.1.0-moodle.1", |     "@moodlehq/cordova-plugin-zip": "3.1.0-moodle.1", | ||||||
|     "@moodlehq/phonegap-plugin-push": "2.0.0-moodle.4", |     "@moodlehq/phonegap-plugin-push": "4.0.0-moodle.2", | ||||||
|     "@ngx-translate/core": "^13.0.0", |     "@ngx-translate/core": "^13.0.0", | ||||||
|     "@ngx-translate/http-loader": "^6.0.0", |     "@ngx-translate/http-loader": "^6.0.0", | ||||||
|     "@types/chart.js": "^2.9.31", |     "@types/chart.js": "^2.9.31", | ||||||
| @ -232,9 +232,8 @@ | |||||||
|       "@moodlehq/cordova-plugin-zip": {}, |       "@moodlehq/cordova-plugin-zip": {}, | ||||||
|       "cordova-sqlite-storage": {}, |       "cordova-sqlite-storage": {}, | ||||||
|       "@moodlehq/phonegap-plugin-push": { |       "@moodlehq/phonegap-plugin-push": { | ||||||
|         "ANDROID_SUPPORT_V13_VERSION": "28.0.0", |         "ANDROIDX_CORE_VERSION": "1.6.+", | ||||||
|         "FCM_VERSION": "18.+", |         "FCM_VERSION": "23.+" | ||||||
|         "IOS_FIREBASE_MESSAGING_VERSION": "~> 6.32.2" |  | ||||||
|       }, |       }, | ||||||
|       "com-darryncampbell-cordova-plugin-intent": {}, |       "com-darryncampbell-cordova-plugin-intent": {}, | ||||||
|       "nl.kingsquare.cordova.background-audio": {}, |       "nl.kingsquare.cordova.background-audio": {}, | ||||||
|  | |||||||
| @ -14,7 +14,7 @@ print_title 'Generating language from code...' | |||||||
| npx gulp lang | npx gulp lang | ||||||
| 
 | 
 | ||||||
| print_title 'Getting local mobile langs' | print_title 'Getting local mobile langs' | ||||||
| git clone --branch integration --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp | git clone --branch master --depth 1 https://github.com/moodlehq/moodle-local_moodlemobileapp.git ../../moodle-local_moodlemobileapp | ||||||
| 
 | 
 | ||||||
| if [ -z $forceLang ]; then | if [ -z $forceLang ]; then | ||||||
|     get_languages |     get_languages | ||||||
|  | |||||||
| @ -15,7 +15,10 @@ | |||||||
| import { CoreConstants, ModPurpose } from '@/core/constants'; | import { CoreConstants, ModPurpose } from '@/core/constants'; | ||||||
| import { Injectable, Type } from '@angular/core'; | import { Injectable, Type } from '@angular/core'; | ||||||
| import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; | import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler'; | ||||||
| import { CoreCourseModuleHandler } from '@features/course/services/module-delegate'; | import { CoreCourseModuleData } from '@features/course/services/course-helper'; | ||||||
|  | import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; | ||||||
|  | import { CoreNavigator } from '@services/navigator'; | ||||||
|  | import { CoreDomUtils } from '@services/utils/dom'; | ||||||
| import { makeSingleton } from '@singletons'; | import { makeSingleton } from '@singletons'; | ||||||
| import { AddonModFolderIndexComponent } from '../../components/index'; | import { AddonModFolderIndexComponent } from '../../components/index'; | ||||||
| 
 | 
 | ||||||
| @ -44,6 +47,41 @@ export class AddonModFolderModuleHandlerService extends CoreModuleHandlerBase im | |||||||
|         [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, |         [CoreConstants.FEATURE_MOD_PURPOSE]: ModPurpose.MOD_PURPOSE_CONTENT, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * @inheritdoc | ||||||
|  |      */ | ||||||
|  |     async getData( | ||||||
|  |         module: CoreCourseModuleData, | ||||||
|  |         courseId: number, | ||||||
|  |         sectionId?: number, | ||||||
|  |         forCoursePage?: boolean, | ||||||
|  |     ): Promise<CoreCourseModuleHandlerData> { | ||||||
|  |         const data = await super.getData(module, courseId, sectionId, forCoursePage); | ||||||
|  | 
 | ||||||
|  |         if (module.description) { | ||||||
|  |             // Module description can contain the folder contents if it's inline, remove it.
 | ||||||
|  |             const descriptionElement = CoreDomUtils.convertToElement(module.description); | ||||||
|  | 
 | ||||||
|  |             Array.from(descriptionElement.querySelectorAll('.foldertree, .folderbuttons, .tertiary-navigation')) | ||||||
|  |                 .forEach(element => element.remove()); | ||||||
|  | 
 | ||||||
|  |             module.description = descriptionElement.innerHTML; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // @todo: Temporary fix to open inline folders. We should use a more generic solution.
 | ||||||
|  |         data.action = async (event, module, courseId, options): Promise<void> => { | ||||||
|  |             options = options || {}; | ||||||
|  |             options.params = options.params || {}; | ||||||
|  |             Object.assign(options.params, { module }); | ||||||
|  | 
 | ||||||
|  |             const routeParams = '/' + courseId + '/' + module.id; | ||||||
|  | 
 | ||||||
|  |             await CoreNavigator.navigateToSitePath(this.pageName + routeParams, options); | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         return data; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * @inheritdoc |      * @inheritdoc | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -845,8 +845,6 @@ export class AddonModForumProvider { | |||||||
|         forumId: number, |         forumId: number, | ||||||
|         options: AddonModForumGetDiscussionsInPagesOptions = {}, |         options: AddonModForumGetDiscussionsInPagesOptions = {}, | ||||||
|     ): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> { |     ): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> { | ||||||
|         options.page = options.page || 0; |  | ||||||
| 
 |  | ||||||
|         const result = { |         const result = { | ||||||
|             discussions: [] as AddonModForumDiscussion[], |             discussions: [] as AddonModForumDiscussion[], | ||||||
|             error: false, |             error: false, | ||||||
| @ -859,7 +857,10 @@ export class AddonModForumProvider { | |||||||
| 
 | 
 | ||||||
|         const getPage = (page: number): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> => |         const getPage = (page: number): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> => | ||||||
|             // Get page discussions.
 |             // Get page discussions.
 | ||||||
|             this.getDiscussions(forumId, options).then((response) => { |             this.getDiscussions(forumId, { | ||||||
|  |                 ...options, | ||||||
|  |                 page, | ||||||
|  |             }).then((response) => { | ||||||
|                 result.discussions = result.discussions.concat(response.discussions); |                 result.discussions = result.discussions.concat(response.discussions); | ||||||
|                 numPages--; |                 numPages--; | ||||||
| 
 | 
 | ||||||
| @ -876,7 +877,7 @@ export class AddonModForumProvider { | |||||||
|             }) |             }) | ||||||
|         ; |         ; | ||||||
| 
 | 
 | ||||||
|         return getPage(options.page); |         return getPage(options.page ?? 0); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -916,7 +917,7 @@ export class AddonModForumProvider { | |||||||
|                     .getDiscussionsInPages(forum.id, { |                     .getDiscussionsInPages(forum.id, { | ||||||
|                         cmId: forum.cmid, |                         cmId: forum.cmid, | ||||||
|                         sortOrder: sortOrder.value, |                         sortOrder: sortOrder.value, | ||||||
|                         readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE, |                         readingStrategy: CoreSitesReadingStrategy.ONLY_CACHE, | ||||||
|                     }) |                     }) | ||||||
|                     .then((response) => { |                     .then((response) => { | ||||||
|                         // Now invalidate the WS calls.
 |                         // Now invalidate the WS calls.
 | ||||||
|  | |||||||
| @ -128,7 +128,7 @@ | |||||||
|                                     <core-download-refresh *ngIf="downloadEnabled && module.handlerData?.showDownloadButton && |                                     <core-download-refresh *ngIf="downloadEnabled && module.handlerData?.showDownloadButton && | ||||||
|                                         module.downloadStatus != statusDownloaded" [status]="module.downloadStatus" [enabled]="true" |                                         module.downloadStatus != statusDownloaded" [status]="module.downloadStatus" [enabled]="true" | ||||||
|                                         [canTrustDownload]="true" [loading]="module.spinner || module.handlerData.spinner" |                                         [canTrustDownload]="true" [loading]="module.spinner || module.handlerData.spinner" | ||||||
|                                         (action)="prefetchModule(module, section)"> |                                         (action)="prefetchModule(module, $event)"> | ||||||
|                                     </core-download-refresh> |                                     </core-download-refresh> | ||||||
|                                     <ion-button fill="clear" (click)="deleteForModule(module, section)" |                                     <ion-button fill="clear" (click)="deleteForModule(module, section)" | ||||||
|                                         *ngIf="!module.calculatingSize && module.totalSize > 0" color="danger"> |                                         *ngIf="!module.calculatingSize && module.totalSize > 0" color="danger"> | ||||||
|  | |||||||
| @ -104,7 +104,7 @@ export class CoreSite { | |||||||
|         '3.9': 2020061500, |         '3.9': 2020061500, | ||||||
|         '3.10': 2020110900, |         '3.10': 2020110900, | ||||||
|         '3.11': 2021051700, |         '3.11': 2021051700, | ||||||
|         '4.0': 2021100300, // @todo [4.0] replace with right value when released. Using a tmp value to be able to test new things.
 |         '4.0': 2022041900, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Possible cache update frequencies.
 |     // Possible cache update frequencies.
 | ||||||
|  | |||||||
| @ -195,7 +195,9 @@ export class CoreBlockDelegateService extends CoreDelegate<CoreBlockHandler> { | |||||||
|      * @return Whether is enabled or disabled in site. |      * @return Whether is enabled or disabled in site. | ||||||
|      */ |      */ | ||||||
|     protected isFeatureDisabled(handler: CoreBlockHandler, site: CoreSite): boolean { |     protected isFeatureDisabled(handler: CoreBlockHandler, site: CoreSite): boolean { | ||||||
|         return this.areBlocksDisabledInSite(site) || super.isFeatureDisabled(handler, site); |         // Allow displaying my overview even if all blocks are disabled, to avoid having an empty My Courses.
 | ||||||
|  |         return (this.areBlocksDisabledInSite(site) && handler.blockName !== 'myoverview') || | ||||||
|  |             super.isFeatureDisabled(handler, site); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -24,8 +24,8 @@ | |||||||
|                     </core-format-text> |                     </core-format-text> | ||||||
|                 </h1> |                 </h1> | ||||||
|             </ion-label> |             </ion-label> | ||||||
|             <ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser" [href]="externalUrl" core-link [showBrowserWarning]="false" |             <ion-button fill="clear" *ngIf="displayOptions.displayOpenInBrowser && externalUrl" [href]="externalUrl" core-link | ||||||
|                 [attr.aria-label]="'core.openinbrowser' | translate" slot="end"> |                 [showBrowserWarning]="false" [attr.aria-label]="'core.openinbrowser' | translate" slot="end"> | ||||||
|                 <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> |                 <ion-icon name="fas-external-link-alt" slot="icon-only" aria-hidden="true"></ion-icon> | ||||||
|             </ion-button> |             </ion-button> | ||||||
|         </ion-item> |         </ion-item> | ||||||
|  | |||||||
| @ -27,8 +27,7 @@ | |||||||
|         </div> |         </div> | ||||||
|     </ng-container> |     </ng-container> | ||||||
| 
 | 
 | ||||||
|     <ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" |     <ion-item class="ion-text-wrap" button detail="false" (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname"> | ||||||
|         [class.item-disabled]="course.visible == 0"> |  | ||||||
| 
 | 
 | ||||||
|         <ng-container *ngIf="layout == 'list' || layout == 'listwithenrol'"> |         <ng-container *ngIf="layout == 'list' || layout == 'listwithenrol'"> | ||||||
|             <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" slot="start" class="course-icon core-course-thumb" |             <ion-icon *ngIf="!course.courseImage" name="fas-graduation-cap" slot="start" class="course-icon core-course-thumb" | ||||||
| @ -74,6 +73,13 @@ | |||||||
|                         </core-format-text> |                         </core-format-text> | ||||||
|                     </ion-label> |                     </ion-label> | ||||||
|                 </ion-chip> |                 </ion-chip> | ||||||
|  | 
 | ||||||
|  |                 <ion-chip color="info" *ngIf="course.visible == 0" | ||||||
|  |                     class="core-course-additional-info ion-text-wrap core-course-hidden-message"> | ||||||
|  |                     <ion-label> | ||||||
|  |                         {{ 'core.course.hiddenfromstudents' | translate }} | ||||||
|  |                     </ion-label> | ||||||
|  |                 </ion-chip> | ||||||
|             </div> |             </div> | ||||||
| 
 | 
 | ||||||
|             <div *ngIf="layout != 'summarycard' && isEnrolled && progress >= 0 && completionUserTracked !== false" |             <div *ngIf="layout != 'summarycard' && isEnrolled && progress >= 0 && completionUserTracked !== false" | ||||||
|  | |||||||
| @ -97,6 +97,10 @@ ion-chip { | |||||||
|     margin-left: 0; |     margin-left: 0; | ||||||
|     margin-right: 0; |     margin-right: 0; | ||||||
|     max-width: 100%; |     max-width: 100%; | ||||||
|  | 
 | ||||||
|  |     &.core-course-category { | ||||||
|  |         @include margin-horizontal(0px, 8px); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ | |||||||
|         <img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt="" /> |         <img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt="" /> | ||||||
|     </div> |     </div> | ||||||
|     <ion-item button (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" class="core-course-header" |     <ion-item button (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" class="core-course-header" | ||||||
|         [class.item-disabled]="course.visible == 0" |  | ||||||
|         [class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" detail="false"> |         [class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" detail="false"> | ||||||
|         <ion-label class="ion-text-wrap core-course-title" |         <ion-label class="ion-text-wrap core-course-title" | ||||||
|             [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)" |             [class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)" | ||||||
|  | |||||||
| @ -113,6 +113,7 @@ | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Common styles. | ||||||
| :host-context(.core-horizontal-scroll) { | :host-context(.core-horizontal-scroll) { | ||||||
|     @include horizontal_scroll_item(80%, 250px, 300px); |     @include horizontal_scroll_item(80%, 250px, 300px); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ import { AsyncComponent } from '@classes/async-component'; | |||||||
| import { PageLoadsManager } from '@classes/page-loads-manager'; | import { PageLoadsManager } from '@classes/page-loads-manager'; | ||||||
| import { CorePromisedValue } from '@classes/promised-value'; | import { CorePromisedValue } from '@classes/promised-value'; | ||||||
| import { CoreBlockComponent } from '@features/block/components/block/block'; | import { CoreBlockComponent } from '@features/block/components/block/block'; | ||||||
|  | import { CoreBlockDelegate } from '@features/block/services/block-delegate'; | ||||||
| import { CoreCourseBlock } from '@features/course/services/course'; | import { CoreCourseBlock } from '@features/course/services/course'; | ||||||
| import { CoreCoursesDashboard, CoreCoursesDashboardProvider } from '@features/courses/services/dashboard'; | import { CoreCoursesDashboard, CoreCoursesDashboardProvider } from '@features/courses/services/dashboard'; | ||||||
| import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager'; | import { CoreMainMenuDeepLinkManager } from '@features/mainmenu/classes/deep-link-manager'; | ||||||
| @ -98,22 +99,30 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncCompone | |||||||
|         const available = await CoreCoursesDashboard.isAvailable(); |         const available = await CoreCoursesDashboard.isAvailable(); | ||||||
|         const disabled = await CoreCourses.isMyCoursesDisabled(); |         const disabled = await CoreCourses.isMyCoursesDisabled(); | ||||||
| 
 | 
 | ||||||
|  |         const supportsMyParam = !!CoreSites.getCurrentSite()?.isVersionGreaterEqualThan('4.0'); | ||||||
|  | 
 | ||||||
|         if (available && !disabled) { |         if (available && !disabled) { | ||||||
|             try { |             try { | ||||||
|                 const blocks = await loadWatcher.watchRequest( |                 const blocks = await loadWatcher.watchRequest( | ||||||
|                     CoreCoursesDashboard.getDashboardBlocksObservable({ |                     CoreCoursesDashboard.getDashboardBlocksObservable({ | ||||||
|                         myPage: this.myPageCourses, |                         myPage: supportsMyParam ? this.myPageCourses : undefined, | ||||||
|                         readingStrategy: loadWatcher.getReadingStrategy(), |                         readingStrategy: loadWatcher.getReadingStrategy(), | ||||||
|                     }), |                     }), | ||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 // My overview block should always be in main blocks, but check side blocks too just in case.
 |                 // My overview block should always be in main blocks, but check side blocks too just in case.
 | ||||||
|                 this.loadedBlock = blocks.mainBlocks.concat(blocks.sideBlocks).find((block) => block.name == 'myoverview'); |                 this.loadedBlock = blocks.mainBlocks.concat(blocks.sideBlocks).find((block) => block.name == 'myoverview'); | ||||||
|                 this.hasSideBlocks = blocks.sideBlocks.length > 0; |                 this.hasSideBlocks = supportsMyParam && CoreBlockDelegate.hasSupportedBlock(blocks.sideBlocks); | ||||||
| 
 | 
 | ||||||
|                 await CoreUtils.nextTicks(2); |                 await CoreUtils.nextTicks(2); | ||||||
| 
 | 
 | ||||||
|                 this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent; |                 this.myOverviewBlock = this.block?.dynamicComponent?.instance as AddonBlockMyOverviewComponent; | ||||||
|  | 
 | ||||||
|  |                 if (!this.loadedBlock && !supportsMyParam) { | ||||||
|  |                     // In old sites, display the block even if not found in Dashboard.
 | ||||||
|  |                     // This is because the "My courses" page doesn't exist in the site so it can't be configured.
 | ||||||
|  |                     this.loadFallbackBlock(); | ||||||
|  |                 } | ||||||
|             } catch (error) { |             } catch (error) { | ||||||
|                 CoreDomUtils.showErrorModal(error); |                 CoreDomUtils.showErrorModal(error); | ||||||
| 
 | 
 | ||||||
| @ -121,10 +130,9 @@ export class CoreCoursesMyCoursesPage implements OnInit, OnDestroy, AsyncCompone | |||||||
|                 this.loadFallbackBlock(); |                 this.loadFallbackBlock(); | ||||||
|             } |             } | ||||||
|         } else if (!available) { |         } else if (!available) { | ||||||
|             // WS not available, or my courses page not available. show fallback block.
 |             // WS not available, show fallback block.
 | ||||||
|             this.loadFallbackBlock(); |             this.loadFallbackBlock(); | ||||||
|         } else { |         } else { | ||||||
|             // Disabled.
 |  | ||||||
|             this.loadedBlock = undefined; |             this.loadedBlock = undefined; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -667,9 +667,14 @@ export class CorePushNotificationsProvider { | |||||||
| 
 | 
 | ||||||
|             const pushObject = Push.init(options); |             const pushObject = Push.init(options); | ||||||
| 
 | 
 | ||||||
|             pushObject.on('notification').subscribe((notification: NotificationEventResponse) => { |             pushObject.on('notification').subscribe((notification: NotificationEventResponse | {registrationType: string}) => { | ||||||
|                 // Execute the callback in the Angular zone, so change detection doesn't stop working.
 |                 // Execute the callback in the Angular zone, so change detection doesn't stop working.
 | ||||||
|                 NgZone.run(() => { |                 NgZone.run(() => { | ||||||
|  |                     if ('registrationType' in notification) { | ||||||
|  |                         // Not a valid notification, ignore.
 | ||||||
|  |                         return; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|                     this.logger.log('Received a notification', notification); |                     this.logger.log('Received a notification', notification); | ||||||
|                     this.onMessageReceived(notification); |                     this.onMessageReceived(notification); | ||||||
|                 }); |                 }); | ||||||
|  | |||||||
| @ -84,7 +84,8 @@ import { CoreContentLinksModuleIndexHandler } from '@features/contentlinks/class | |||||||
| import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; | import { CoreContentLinksDelegate } from '@features/contentlinks/services/contentlinks-delegate'; | ||||||
| import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler'; | import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classes/module-list-handler'; | ||||||
| import { CoreObject } from '@singletons/object'; | import { CoreObject } from '@singletons/object'; | ||||||
| import { CoreUrl } from '@singletons/url'; | import { CoreUrlUtils } from '@services/utils/url'; | ||||||
|  | import { CoreText } from '@singletons/text'; | ||||||
| 
 | 
 | ||||||
| const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled'; | const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled'; | ||||||
| 
 | 
 | ||||||
| @ -164,8 +165,11 @@ export class CoreSitePluginsHelperProvider { | |||||||
|     ): Promise<string> { |     ): Promise<string> { | ||||||
|         const site = await CoreSites.getSite(siteId); |         const site = await CoreSites.getSite(siteId); | ||||||
| 
 | 
 | ||||||
|         // Make sure it's an absolute URL.
 |         // Make sure it's an absolute URL. Do not use toAbsoluteURL because it can change the behaviour and break plugin styles.
 | ||||||
|         let url = handlerSchema.styles?.url ? CoreUrl.toAbsoluteURL(site.getURL(), handlerSchema.styles.url) : undefined; |         let url = handlerSchema.styles?.url; | ||||||
|  |         if (url && !CoreUrlUtils.isAbsoluteURL(url)) { | ||||||
|  |             url = CoreText.concatenatePaths(site.getURL(), url); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         if (url && handlerSchema.styles?.version) { |         if (url && handlerSchema.styles?.version) { | ||||||
|             // Add the version to the URL to prevent getting a cached file.
 |             // Add the version to the URL to prevent getting a cached file.
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user