forked from EVOgeek/Vmeda.Online
		
	
						commit
						831f4f0d9e
					
				@ -14,8 +14,14 @@
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreCourseUserAdminOrNavOptionIndexed } from '@features/courses/services/courses';
 | 
			
		||||
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonBadges } from '../badges';
 | 
			
		||||
 | 
			
		||||
@ -25,52 +31,58 @@ import { AddonBadges } from '../badges';
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonBadgesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonBadges';
 | 
			
		||||
    priority = 50;
 | 
			
		||||
    name = 'AddonBadges:fakename'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
 | 
			
		||||
    priority = 300;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if handler is enabled.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Always enabled.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonBadges.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if handler is enabled for this user in this context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param navOptions Course navigation options for current user. See CoreCoursesProvider.getUserNavigationOptions.
 | 
			
		||||
     * @return True if enabled, false otherwise.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForCourse(
 | 
			
		||||
    async isEnabledForContext(
 | 
			
		||||
        context: CoreUserDelegateContext,
 | 
			
		||||
        courseId: number,
 | 
			
		||||
        navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
 | 
			
		||||
    ): Promise<boolean> {
 | 
			
		||||
        // Check if feature is disabled.
 | 
			
		||||
        const currentSite = CoreSites.getCurrentSite();
 | 
			
		||||
        if (!currentSite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context === CoreUserDelegateContext.USER_MENU) {
 | 
			
		||||
            if (currentSite.isFeatureDisabled('CoreUserDelegate_AddonBadges:account')) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (currentSite.isFeatureDisabled('CoreUserDelegate_AddonBadges')) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (navOptions && navOptions.badges !== undefined) {
 | 
			
		||||
            return navOptions.badges;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // If we reach here, it means we are opening the user site profile.
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the data needed to render the handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Data needed to render the handler.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(): CoreUserProfileHandlerData {
 | 
			
		||||
        return {
 | 
			
		||||
            icon: 'fas-trophy',
 | 
			
		||||
            title: 'addon.badges.badges',
 | 
			
		||||
            action: (event, user, courseId): void => {
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                CoreNavigator.navigateToSitePath('/badges', {
 | 
			
		||||
                    params: { courseId, userId: user.id },
 | 
			
		||||
                    params: { courseId: contextId, userId: user.id },
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -13,8 +13,14 @@
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreUserProfileHandler, CoreUserProfileHandlerData, CoreUserDelegateService } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonBlog } from '../blog';
 | 
			
		||||
 | 
			
		||||
@ -24,8 +30,8 @@ import { AddonBlog } from '../blog';
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonBlogUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonBlog:blogs';
 | 
			
		||||
    priority = 300;
 | 
			
		||||
    name = 'AddonBlog'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
 | 
			
		||||
    priority = 200;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -35,6 +41,27 @@ export class AddonBlogUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
        return AddonBlog.isPluginEnabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext): Promise<boolean> {
 | 
			
		||||
        // Check if feature is disabled.
 | 
			
		||||
        const currentSite = CoreSites.getCurrentSite();
 | 
			
		||||
        if (!currentSite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context === CoreUserDelegateContext.USER_MENU) {
 | 
			
		||||
            if (currentSite.isFeatureDisabled('CoreUserDelegate_AddonBlog:account')) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (currentSite.isFeatureDisabled('CoreUserDelegate_AddonBlog:blogs')) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
@ -43,11 +70,11 @@ export class AddonBlogUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
            icon: 'far-newspaper',
 | 
			
		||||
            title: 'addon.blog.blogentries',
 | 
			
		||||
            class: 'addon-blog-handler',
 | 
			
		||||
            action: (event, user, courseId): void => {
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                CoreNavigator.navigateToSitePath('/blog', {
 | 
			
		||||
                    params: { courseId, userId: user.id },
 | 
			
		||||
                    params: { courseId: contextId, userId: user.id },
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ export class AddonCalendarMainMenuHandlerService implements CoreMainMenuHandler
 | 
			
		||||
    static readonly PAGE_NAME = 'calendar';
 | 
			
		||||
 | 
			
		||||
    name = 'AddonCalendar';
 | 
			
		||||
    priority = 800;
 | 
			
		||||
    priority = 550;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled on a site level.
 | 
			
		||||
 | 
			
		||||
@ -16,9 +16,15 @@ import { ADDON_COMPETENCY_COMPETENCIES_PAGE, ADDON_COMPETENCY_LEARNING_PLANS_PAG
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { COURSE_PAGE_NAME } from '@features/course/course.module';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserProfileHandler, CoreUserDelegateService, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { PARTICIPANTS_PAGE_NAME } from '@features/user/user.module';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonCompetency } from '../competency';
 | 
			
		||||
 | 
			
		||||
@ -28,8 +34,8 @@ import { AddonCompetency } from '../competency';
 | 
			
		||||
@Injectable( { providedIn: 'root' })
 | 
			
		||||
export class AddonCompetencyUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonCompetency:learningPlan';
 | 
			
		||||
    priority = 900;
 | 
			
		||||
    name = 'AddonCompetency'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
 | 
			
		||||
    priority = 100;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
    cacheEnabled = true;
 | 
			
		||||
 | 
			
		||||
@ -43,10 +49,32 @@ export class AddonCompetencyUserHandlerService implements CoreUserProfileHandler
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, courseId?: number): Promise<boolean> {
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext): Promise<boolean> {
 | 
			
		||||
        // Check if feature is disabled.
 | 
			
		||||
        const currentSite = CoreSites.getCurrentSite();
 | 
			
		||||
        if (!currentSite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context === CoreUserDelegateContext.USER_MENU) {
 | 
			
		||||
            // This option used to belong to main menu, check the original disabled feature value.
 | 
			
		||||
            if (currentSite.isFeatureDisabled('CoreMainMenuDelegate_AddonCompetency')) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (currentSite.isFeatureDisabled('CoreUserDelegate_AddonCompetency:learningPlan')) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, context: CoreUserDelegateContext, contextId: number): Promise<boolean> {
 | 
			
		||||
        try {
 | 
			
		||||
            if (courseId) {
 | 
			
		||||
                return AddonCompetency.canViewUserCompetenciesInCourse(courseId, user.id);
 | 
			
		||||
            if (context === CoreUserDelegateContext.COURSE) {
 | 
			
		||||
                return await AddonCompetency.canViewUserCompetenciesInCourse(contextId, user.id);
 | 
			
		||||
            } else {
 | 
			
		||||
                const plans = await AddonCompetency.getLearningPlans(user.id);
 | 
			
		||||
 | 
			
		||||
@ -61,21 +89,8 @@ export class AddonCompetencyUserHandlerService implements CoreUserProfileHandler
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, courseId: number): CoreUserProfileHandlerData {
 | 
			
		||||
        if (courseId) {
 | 
			
		||||
            return {
 | 
			
		||||
                icon: 'fas-award',
 | 
			
		||||
                title: 'addon.competency.competencies',
 | 
			
		||||
                class: 'addon-competency-handler',
 | 
			
		||||
                action: (event, user, courseId): void => {
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                    event.stopPropagation();
 | 
			
		||||
                    CoreNavigator.navigateToSitePath(
 | 
			
		||||
                        [COURSE_PAGE_NAME, courseId, PARTICIPANTS_PAGE_NAME, user.id, ADDON_COMPETENCY_COMPETENCIES_PAGE].join('/'),
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
        } else {
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, context: CoreUserDelegateContext): CoreUserProfileHandlerData {
 | 
			
		||||
        if (context !== CoreUserDelegateContext.COURSE) {
 | 
			
		||||
            return {
 | 
			
		||||
                icon: 'fas-route',
 | 
			
		||||
                title: 'addon.competency.learningplans',
 | 
			
		||||
@ -89,6 +104,19 @@ export class AddonCompetencyUserHandlerService implements CoreUserProfileHandler
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
            icon: 'fas-award',
 | 
			
		||||
            title: 'addon.competency.competencies',
 | 
			
		||||
            class: 'addon-competency-handler',
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                CoreNavigator.navigateToSitePath(
 | 
			
		||||
                    [COURSE_PAGE_NAME, contextId, PARTICIPANTS_PAGE_NAME, user.id, ADDON_COMPETENCY_COMPETENCIES_PAGE].join('/'),
 | 
			
		||||
                );
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,12 @@
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserProfileHandler, CoreUserDelegateService, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { AddonCourseCompletion } from '../coursecompletion';
 | 
			
		||||
@ -25,9 +30,9 @@ import { AddonCourseCompletion } from '../coursecompletion';
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class AddonCourseCompletionUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonCourseCompletion';
 | 
			
		||||
    name = 'AddonCourseCompletion:viewCompletion';
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
    priority = 200;
 | 
			
		||||
    priority = 350;
 | 
			
		||||
    cacheEnabled = true;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -40,15 +45,19 @@ export class AddonCourseCompletionUserHandlerService implements CoreUserProfileH
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForCourse(courseId?: number): Promise<boolean> {
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext, courseId: number): Promise<boolean> {
 | 
			
		||||
        if (context !== CoreUserDelegateContext.COURSE) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return AddonCourseCompletion.isPluginViewEnabledForCourse(courseId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, courseId?: number): Promise<boolean> {
 | 
			
		||||
        return await AddonCourseCompletion.isPluginViewEnabledForUser(courseId!, user.id);
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, context: CoreUserDelegateContext,  contextId: number): Promise<boolean> {
 | 
			
		||||
        return await AddonCourseCompletion.isPluginViewEnabledForUser(contextId, user.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -59,11 +68,11 @@ export class AddonCourseCompletionUserHandlerService implements CoreUserProfileH
 | 
			
		||||
            icon: 'fas-tasks',
 | 
			
		||||
            title: 'addon.coursecompletion.coursecompletion',
 | 
			
		||||
            class: 'addon-coursecompletion-handler',
 | 
			
		||||
            action: (event, user, courseId): void => {
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                CoreNavigator.navigateToSitePath('/coursecompletion', {
 | 
			
		||||
                    params: { courseId, userId: user.id },
 | 
			
		||||
                    params: { courseId: contextId, userId: user.id },
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -32,9 +32,7 @@ export class AddonMessagesSendMessageUserHandlerService implements CoreUserProfi
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_COMMUNICATION;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if handler is enabled.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Promise resolved with true if enabled, rejected or resolved with false otherwise.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): Promise<boolean> {
 | 
			
		||||
        return AddonMessages.isPluginEnabled();
 | 
			
		||||
@ -43,15 +41,12 @@ export class AddonMessagesSendMessageUserHandlerService implements CoreUserProfi
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForCourse(): Promise<boolean> {
 | 
			
		||||
    async isEnabledForContext(): Promise<boolean> {
 | 
			
		||||
        return !!CoreSites.getCurrentSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if handler is enabled for this user in this context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param user User to check.
 | 
			
		||||
     * @return Promise resolved with true if enabled, resolved with false otherwise.
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile): Promise<boolean> {
 | 
			
		||||
        const currentSite = CoreSites.getRequiredCurrentSite();
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,12 @@
 | 
			
		||||
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserProfileHandler, CoreUserDelegateService, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
@ -27,7 +32,7 @@ import { AddonNotes } from '../notes';
 | 
			
		||||
export class AddonNotesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'AddonNotes:notes';
 | 
			
		||||
    priority = 100;
 | 
			
		||||
    priority = 250;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
    cacheEnabled = true;
 | 
			
		||||
 | 
			
		||||
@ -41,14 +46,14 @@ export class AddonNotesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, courseId?: number): Promise<boolean> {
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, context: CoreUserDelegateContext, contextId: number): Promise<boolean> {
 | 
			
		||||
        // Active course required.
 | 
			
		||||
        if (!courseId || user.id == CoreSites.getCurrentSiteUserId()) {
 | 
			
		||||
        if (context !== CoreUserDelegateContext.COURSE || !contextId || user.id == CoreSites.getCurrentSiteUserId()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // We are not using isEnabledForCourse because we need to cache the call.
 | 
			
		||||
        return AddonNotes.isPluginViewNotesEnabledForCourse(courseId);
 | 
			
		||||
        return AddonNotes.isPluginViewNotesEnabledForCourse(contextId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -59,11 +64,11 @@ export class AddonNotesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
            icon: 'fas-receipt',
 | 
			
		||||
            title: 'addon.notes.notes',
 | 
			
		||||
            class: 'addon-notes-handler',
 | 
			
		||||
            action: (event, user, courseId): void => {
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
                CoreNavigator.navigateToSitePath('/notes', {
 | 
			
		||||
                    params: { courseId, userId: user.id },
 | 
			
		||||
                    params: { courseId: contextId, userId: user.id },
 | 
			
		||||
                });
 | 
			
		||||
            },
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,12 @@ import { Injectable } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
import { AddonPrivateFiles } from '@/addons/privatefiles/services/privatefiles';
 | 
			
		||||
import { makeSingleton } from '@singletons';
 | 
			
		||||
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
@ -30,7 +35,7 @@ export class AddonPrivateFilesUserHandlerService implements CoreUserProfileHandl
 | 
			
		||||
    static readonly PAGE_NAME = 'private';
 | 
			
		||||
 | 
			
		||||
    name = 'AddonPrivateFiles';
 | 
			
		||||
    priority = 300;
 | 
			
		||||
    priority = 400;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
    cacheEnabled = true;
 | 
			
		||||
 | 
			
		||||
@ -44,9 +49,28 @@ export class AddonPrivateFilesUserHandlerService implements CoreUserProfileHandl
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile): Promise<boolean> {
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext): Promise<boolean> {
 | 
			
		||||
        // Private files only available in user menu.
 | 
			
		||||
        if (context !== CoreUserDelegateContext.USER_MENU) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check if feature is disabled.
 | 
			
		||||
        const currentSite = CoreSites.getCurrentSite();
 | 
			
		||||
        if (!currentSite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // This option used to belong to main menu, check the original disabled feature value.
 | 
			
		||||
        return !currentSite.isFeatureDisabled('CoreMainMenuDelegate_AddonPrivateFiles');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, context: CoreUserDelegateContext): Promise<boolean> {
 | 
			
		||||
        // Private files only available for the current user.
 | 
			
		||||
        return user.id == CoreSites.getCurrentSiteUserId();
 | 
			
		||||
        return user.id == CoreSites.getCurrentSiteUserId() && context === CoreUserDelegateContext.USER_MENU;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { GRADES_PAGE_NAME } from '@features/grades/grades.module';
 | 
			
		||||
import { CoreGrades } from '@features/grades/services/grades';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
    CoreUserDelegateService ,
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
@ -35,8 +36,8 @@ import { makeSingleton } from '@singletons';
 | 
			
		||||
@Injectable({ providedIn: 'root' })
 | 
			
		||||
export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
 | 
			
		||||
    name = 'CoreGrades:viewGrades';
 | 
			
		||||
    priority = 400;
 | 
			
		||||
    name = 'CoreGrades'; // This name doesn't match any disabled feature, they'll be checked in isEnabledForContext.
 | 
			
		||||
    priority = 500;
 | 
			
		||||
    type = CoreUserDelegateService.TYPE_NEW_PAGE;
 | 
			
		||||
    cacheEnabled = true;
 | 
			
		||||
 | 
			
		||||
@ -50,8 +51,23 @@ export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForCourse(courseId?: number): Promise<boolean> {
 | 
			
		||||
        if (courseId) {
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext, courseId: number): Promise<boolean> {
 | 
			
		||||
        // Check if feature is disabled.
 | 
			
		||||
        const currentSite = CoreSites.getCurrentSite();
 | 
			
		||||
        if (!currentSite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context === CoreUserDelegateContext.USER_MENU) {
 | 
			
		||||
            // This option used to belong to main menu, check the original disabled feature value.
 | 
			
		||||
            if (currentSite.isFeatureDisabled('CoreMainMenuDelegate_CoreGrades')) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (currentSite.isFeatureDisabled('CoreUserDelegate_CoreGrades:viewGrades')) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (context === CoreUserDelegateContext.COURSE) {
 | 
			
		||||
            return CoreUtils.ignoreErrors(CoreGrades.isPluginEnabledForCourse(courseId), false);
 | 
			
		||||
        } else {
 | 
			
		||||
            return CoreGrades.isCourseGradesEnabled();
 | 
			
		||||
@ -61,9 +77,9 @@ export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, courseId?: number): Promise<boolean> {
 | 
			
		||||
        if (courseId) {
 | 
			
		||||
            return CoreUtils.promiseWorks(CoreGrades.getCourseGradesTable(courseId, user.id));
 | 
			
		||||
    async isEnabledForUser(user: CoreUserProfile, context: CoreUserDelegateContext, contextId: number): Promise<boolean> {
 | 
			
		||||
        if (context === CoreUserDelegateContext.COURSE) {
 | 
			
		||||
            return CoreUtils.promiseWorks(CoreGrades.getCourseGradesTable(contextId, user.id));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // All course grades only available for the current user.
 | 
			
		||||
@ -73,17 +89,17 @@ export class CoreGradesUserHandlerService implements CoreUserProfileHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, courseId?: number): CoreUserProfileHandlerData {
 | 
			
		||||
        if (courseId) {
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, context: CoreUserDelegateContext): CoreUserProfileHandlerData {
 | 
			
		||||
        if (context === CoreUserDelegateContext.COURSE) {
 | 
			
		||||
            return {
 | 
			
		||||
                icon: 'fas-chart-bar',
 | 
			
		||||
                title: 'core.grades.grades',
 | 
			
		||||
                class: 'core-grades-user-handler',
 | 
			
		||||
                action: (event, user, courseId): void => {
 | 
			
		||||
                action: (event, user, context, contextId): void => {
 | 
			
		||||
                    event.preventDefault();
 | 
			
		||||
                    event.stopPropagation();
 | 
			
		||||
                    CoreNavigator.navigateToSitePath(
 | 
			
		||||
                        [COURSE_PAGE_NAME, courseId, PARTICIPANTS_PAGE_NAME, user.id, GRADES_PAGE_NAME].join('/'),
 | 
			
		||||
                        [COURSE_PAGE_NAME, contextId, PARTICIPANTS_PAGE_NAME, user.id, GRADES_PAGE_NAME].join('/'),
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@
 | 
			
		||||
    </ion-list>
 | 
			
		||||
</ion-content>
 | 
			
		||||
<ion-footer>
 | 
			
		||||
    <ion-item button lines="full" (click)="switchAccounts($event)" detail="true" class="ion-text-wrap">
 | 
			
		||||
    <ion-item *ngIf="displaySwitchAccount" button lines="full" (click)="switchAccounts($event)" detail="true" class="ion-text-wrap">
 | 
			
		||||
        <ion-icon name="fas-exchange-alt" slot="start" aria-hidden="true"></ion-icon>
 | 
			
		||||
        <ion-label>
 | 
			
		||||
            <p class="item-heading">{{ 'core.mainmenu.switchaccount' | translate }}</p>
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,12 @@ import { CoreSite, CoreSiteInfo } from '@classes/site';
 | 
			
		||||
import { CoreLoginSitesComponent } from '@features/login/components/sites/sites';
 | 
			
		||||
import { CoreLoginHelper } from '@features/login/services/login-helper';
 | 
			
		||||
import { CoreUser, CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserProfileHandlerData, CoreUserDelegate, CoreUserDelegateService } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
    CoreUserDelegate,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
@ -44,6 +49,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
    handlersLoaded = false;
 | 
			
		||||
    loaded = false;
 | 
			
		||||
    user?: CoreUserProfile;
 | 
			
		||||
    displaySwitchAccount = true;
 | 
			
		||||
 | 
			
		||||
    protected subscription!: Subscription;
 | 
			
		||||
 | 
			
		||||
@ -55,6 +61,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
        this.siteInfo = currentSite.getInfo();
 | 
			
		||||
        this.siteName = currentSite.getSiteName();
 | 
			
		||||
        this.siteUrl = currentSite.getURL();
 | 
			
		||||
        this.displaySwitchAccount = !currentSite.isFeatureDisabled('NoDelegate_SwitchAccount');
 | 
			
		||||
 | 
			
		||||
        this.loaded = true;
 | 
			
		||||
 | 
			
		||||
@ -64,20 +71,21 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
        if (this.siteInfo) {
 | 
			
		||||
            this.user = await CoreUser.getProfile(this.siteInfo.userid);
 | 
			
		||||
 | 
			
		||||
            this.subscription = CoreUserDelegate.getProfileHandlersFor(this.user).subscribe((handlers) => {
 | 
			
		||||
                if (!handlers || !this.user) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                this.handlers = [];
 | 
			
		||||
                handlers.forEach((handler) => {
 | 
			
		||||
                    if (handler.type == CoreUserDelegateService.TYPE_NEW_PAGE) {
 | 
			
		||||
                        this.handlers.push(handler.data);
 | 
			
		||||
            this.subscription = CoreUserDelegate.getProfileHandlersFor(this.user, CoreUserDelegateContext.USER_MENU)
 | 
			
		||||
                .subscribe((handlers) => {
 | 
			
		||||
                    if (!handlers || !this.user) {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.handlersLoaded = CoreUserDelegate.areHandlersLoaded(this.user.id);
 | 
			
		||||
            });
 | 
			
		||||
                    this.handlers = [];
 | 
			
		||||
                    handlers.forEach((handler) => {
 | 
			
		||||
                        if (handler.type == CoreUserDelegateService.TYPE_NEW_PAGE) {
 | 
			
		||||
                            this.handlers.push(handler.data);
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    this.handlersLoaded = CoreUserDelegate.areHandlersLoaded(this.user.id, CoreUserDelegateContext.USER_MENU);
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -150,7 +158,7 @@ export class CoreMainMenuUserMenuComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
        await this.close(event);
 | 
			
		||||
 | 
			
		||||
        handler.action(event, this.user);
 | 
			
		||||
        handler.action(event, this.user, CoreUserDelegateContext.USER_MENU);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -19,9 +19,13 @@ import {
 | 
			
		||||
    CoreSitePluginsUserHandlerData,
 | 
			
		||||
} from '@features/siteplugins/services/siteplugins';
 | 
			
		||||
import { CoreUserProfile } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandler,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreSites } from '@services/sites';
 | 
			
		||||
import { CoreUtils, PromiseDefer } from '@services/utils/utils';
 | 
			
		||||
import { Md5 } from 'ts-md5';
 | 
			
		||||
import { CoreSitePluginsBaseHandler } from './base-handler';
 | 
			
		||||
@ -55,11 +59,7 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
 | 
			
		||||
    /**
 | 
			
		||||
     * @inheritdoc
 | 
			
		||||
     */
 | 
			
		||||
    async isEnabledForCourse(
 | 
			
		||||
        courseId?: number,
 | 
			
		||||
    ): Promise<boolean> {
 | 
			
		||||
        courseId = courseId || CoreSites.getCurrentSiteHomeId();
 | 
			
		||||
 | 
			
		||||
    async isEnabledForContext(context: CoreUserDelegateContext, courseId: number): Promise<boolean> {
 | 
			
		||||
        // Check if it's enabled for the course.
 | 
			
		||||
        return CoreSitePlugins.isHandlerEnabledForCourse(
 | 
			
		||||
            courseId,
 | 
			
		||||
@ -89,12 +89,12 @@ export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandle
 | 
			
		||||
            title: this.title,
 | 
			
		||||
            icon: this.handlerSchema.displaydata?.icon,
 | 
			
		||||
            class: this.handlerSchema.displaydata?.class,
 | 
			
		||||
            action: (event: Event, user: CoreUserProfile, courseId?: number): void => {
 | 
			
		||||
            action: (event, user, context, contextId): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
                const args = {
 | 
			
		||||
                    courseid: courseId,
 | 
			
		||||
                    courseid: contextId,
 | 
			
		||||
                    userid: user.id,
 | 
			
		||||
                };
 | 
			
		||||
                const hash = <string> Md5.hashAsciiStr(JSON.stringify(args));
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,12 @@ import { CoreDomUtils } from '@services/utils/dom';
 | 
			
		||||
import { CoreEventObserver, CoreEvents } from '@singletons/events';
 | 
			
		||||
import { CoreUser, CoreUserProfile, CoreUserProvider } from '@features/user/services/user';
 | 
			
		||||
import { CoreUserHelper } from '@features/user/services/user-helper';
 | 
			
		||||
import { CoreUserDelegate, CoreUserDelegateService, CoreUserProfileHandlerData } from '@features/user/services/user-delegate';
 | 
			
		||||
import {
 | 
			
		||||
    CoreUserDelegate,
 | 
			
		||||
    CoreUserDelegateContext,
 | 
			
		||||
    CoreUserDelegateService,
 | 
			
		||||
    CoreUserProfileHandlerData,
 | 
			
		||||
} from '@features/user/services/user-delegate';
 | 
			
		||||
import { CoreUtils } from '@services/utils/utils';
 | 
			
		||||
import { CoreNavigator } from '@services/navigator';
 | 
			
		||||
import { CoreCourses } from '@features/courses/services/courses';
 | 
			
		||||
@ -131,7 +136,9 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
            // If there's already a subscription, unsubscribe because we'll get a new one.
 | 
			
		||||
            this.subscription?.unsubscribe();
 | 
			
		||||
 | 
			
		||||
            this.subscription = CoreUserDelegate.getProfileHandlersFor(user, this.courseId).subscribe((handlers) => {
 | 
			
		||||
            const context = this.courseId ? CoreUserDelegateContext.COURSE : CoreUserDelegateContext.SITE;
 | 
			
		||||
 | 
			
		||||
            this.subscription = CoreUserDelegate.getProfileHandlersFor(user, context, this.courseId).subscribe((handlers) => {
 | 
			
		||||
                this.actionHandlers = [];
 | 
			
		||||
                this.newPageHandlers = [];
 | 
			
		||||
                this.communicationHandlers = [];
 | 
			
		||||
@ -150,7 +157,7 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                this.isLoadingHandlers = !CoreUserDelegate.areHandlersLoaded(user.id);
 | 
			
		||||
                this.isLoadingHandlers = !CoreUserDelegate.areHandlersLoaded(user.id, context, this.courseId);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
@ -208,7 +215,8 @@ export class CoreUserProfilePage implements OnInit, OnDestroy {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handler.action(event, this.user, this.courseId);
 | 
			
		||||
        const context = this.courseId ? CoreUserDelegateContext.COURSE : CoreUserDelegateContext.SITE;
 | 
			
		||||
        handler.action(event, this.user, context, this.courseId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@ export class CoreUserProfileMailHandlerService implements CoreUserProfileHandler
 | 
			
		||||
            icon: 'mail',
 | 
			
		||||
            title: 'core.user.sendemail',
 | 
			
		||||
            class: 'core-user-profile-mail',
 | 
			
		||||
            action: (event: Event, user: CoreUserProfile): void => {
 | 
			
		||||
            action: (event, user): void => {
 | 
			
		||||
                event.preventDefault();
 | 
			
		||||
                event.stopPropagation();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -47,15 +47,17 @@ export interface CoreUserProfileHandler extends CoreDelegateHandler {
 | 
			
		||||
    cacheEnabled?: boolean;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Whether or not the handler is enabled for a course.
 | 
			
		||||
     * Whether or not the handler is enabled for a context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID where to show.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @param navOptions Navigation options for the course.
 | 
			
		||||
     * @param admOptions Admin options for the course.
 | 
			
		||||
     * @return Whether or not the handler is enabled for a user.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabledForCourse?(
 | 
			
		||||
        courseId?: number,
 | 
			
		||||
    isEnabledForContext?(
 | 
			
		||||
        context: CoreUserDelegateContext,
 | 
			
		||||
        contextId: number,
 | 
			
		||||
        navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
 | 
			
		||||
        admOptions?: CoreCourseUserAdminOrNavOptionIndexed,
 | 
			
		||||
    ): Promise<boolean>;
 | 
			
		||||
@ -64,22 +66,21 @@ export interface CoreUserProfileHandler extends CoreDelegateHandler {
 | 
			
		||||
     * Whether or not the handler is enabled for a user.
 | 
			
		||||
     *
 | 
			
		||||
     * @param user User object.
 | 
			
		||||
     * @param courseId Course ID where to show.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Whether or not the handler is enabled for a user.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabledForUser?(
 | 
			
		||||
        user: CoreUserProfile,
 | 
			
		||||
        courseId?: number,
 | 
			
		||||
    ): Promise<boolean>;
 | 
			
		||||
    isEnabledForUser?(user: CoreUserProfile, context: CoreUserDelegateContext, contextId: number): Promise<boolean>;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Returns the data needed to render the handler.
 | 
			
		||||
     *
 | 
			
		||||
     * @param user User object.
 | 
			
		||||
     * @param courseId Course ID where to show.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Data to be shown.
 | 
			
		||||
     */
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, courseId?: number): CoreUserProfileHandlerData;
 | 
			
		||||
    getDisplayData(user: CoreUserProfile, context: CoreUserDelegateContext, contextId: number): CoreUserProfileHandlerData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -136,9 +137,10 @@ export interface CoreUserProfileHandlerData {
 | 
			
		||||
     *
 | 
			
		||||
     * @param event Click event.
 | 
			
		||||
     * @param user User object.
 | 
			
		||||
     * @param courseId Course ID being viewed. If not defined, site context.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     */
 | 
			
		||||
    action(event: Event, user: CoreUserProfile, courseId?: number): void;
 | 
			
		||||
    action(event: Event, user: CoreUserProfile, context: CoreUserDelegateContext, contextId?: number): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -199,24 +201,16 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
    protected featurePrefix = 'CoreUserDelegate_';
 | 
			
		||||
 | 
			
		||||
    // Hold the handlers and the observable to notify them for each user.
 | 
			
		||||
    protected userHandlers: {
 | 
			
		||||
        [userId: number]: {
 | 
			
		||||
            loaded: boolean; // Whether the handlers are loaded.
 | 
			
		||||
            handlers: CoreUserProfileHandlerToDisplay[]; // List of handlers.
 | 
			
		||||
            observable: Subject<CoreUserProfileHandlerToDisplay[]>; // Observale to notify the handlers.
 | 
			
		||||
        };
 | 
			
		||||
    } = {};
 | 
			
		||||
    protected userHandlers: Record<number, Record<string, CoreUserDelegateHandlersData>> = {};
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super('CoreUserDelegate', true);
 | 
			
		||||
 | 
			
		||||
        CoreEvents.on(CoreUserDelegateService.UPDATE_HANDLER_EVENT, (data) => {
 | 
			
		||||
            if (!data || !data.handler || !this.userHandlers[data.userId]) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            const handlersData = this.getHandlersData(data.userId, data.context, data.contextId);
 | 
			
		||||
 | 
			
		||||
            // Search the handler.
 | 
			
		||||
            const handler = this.userHandlers[data.userId].handlers.find((userHandler) => userHandler.name == data.handler);
 | 
			
		||||
            const handler = handlersData.handlers.find((userHandler) => userHandler.name == data.handler);
 | 
			
		||||
 | 
			
		||||
            if (!handler) {
 | 
			
		||||
                return;
 | 
			
		||||
@ -224,7 +218,7 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
 | 
			
		||||
            // Update the data and notify.
 | 
			
		||||
            Object.assign(handler.data, data.data);
 | 
			
		||||
            this.userHandlers[data.userId].observable.next(this.userHandlers[data.userId].handlers);
 | 
			
		||||
            handlersData.observable.next(handlersData.handlers);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        CoreEvents.on(CoreEvents.LOGOUT, () => {
 | 
			
		||||
@ -232,31 +226,41 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        CoreEvents.on(CoreUserProvider.PROFILE_REFRESHED, (data) => {
 | 
			
		||||
            this.clearHandlerCache(data.courseId, data.userId);
 | 
			
		||||
            const context = data.courseId ? CoreUserDelegateContext.COURSE : CoreUserDelegateContext.SITE;
 | 
			
		||||
            this.clearHandlerCache(data.userId, context, data.courseId);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if handlers are loaded.
 | 
			
		||||
     * Check if handlers are loaded for a certain user and context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId User ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return True if handlers are loaded, false otherwise.
 | 
			
		||||
     */
 | 
			
		||||
    areHandlersLoaded(userId: number): boolean {
 | 
			
		||||
        return this.userHandlers[userId]?.loaded;
 | 
			
		||||
    areHandlersLoaded(userId: number, context: CoreUserDelegateContext, contextId?: number): boolean {
 | 
			
		||||
        return this.getHandlersData(userId, context, contextId).loaded;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear current user handlers.
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId The user to clear.
 | 
			
		||||
     * @param userId The user to clear. Undefined for all users.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     */
 | 
			
		||||
    clearUserHandlers(userId: number): void {
 | 
			
		||||
        const userData = this.userHandlers[userId];
 | 
			
		||||
    clearUserHandlers(userId?: number, context?: CoreUserDelegateContext, contextId?: number): void {
 | 
			
		||||
        if (!userId) {
 | 
			
		||||
            this.userHandlers = {};
 | 
			
		||||
        } else if (!context) {
 | 
			
		||||
            delete this.userHandlers[userId];
 | 
			
		||||
        } else {
 | 
			
		||||
            const handlersData = this.getHandlersData(userId, context, contextId);
 | 
			
		||||
 | 
			
		||||
        if (userData) {
 | 
			
		||||
            userData.handlers = [];
 | 
			
		||||
            userData.observable.next([]);
 | 
			
		||||
            userData.loaded = false;
 | 
			
		||||
            handlersData.handlers = [];
 | 
			
		||||
            handlersData.observable.next([]);
 | 
			
		||||
            handlersData.loaded = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -264,58 +268,65 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
     * Get the profile handlers for a user.
 | 
			
		||||
     *
 | 
			
		||||
     * @param user The user object.
 | 
			
		||||
     * @param courseId The course ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Resolved with the handlers.
 | 
			
		||||
     */
 | 
			
		||||
    getProfileHandlersFor(user: CoreUserProfile, courseId?: number): Subject<CoreUserProfileHandlerToDisplay[]> {
 | 
			
		||||
        // Initialize the user handlers if it isn't initialized already.
 | 
			
		||||
        if (!this.userHandlers[user.id]) {
 | 
			
		||||
            this.userHandlers[user.id] = {
 | 
			
		||||
                loaded: false,
 | 
			
		||||
                handlers: [],
 | 
			
		||||
                observable: new BehaviorSubject<CoreUserProfileHandlerToDisplay[]>([]),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    getProfileHandlersFor(
 | 
			
		||||
        user: CoreUserProfile,
 | 
			
		||||
        context: CoreUserDelegateContext,
 | 
			
		||||
        contextId?: number,
 | 
			
		||||
    ): Subject<CoreUserProfileHandlerToDisplay[]> {
 | 
			
		||||
        this.calculateUserHandlers(user, context, contextId);
 | 
			
		||||
 | 
			
		||||
        this.calculateUserHandlers(user, courseId);
 | 
			
		||||
 | 
			
		||||
        return this.userHandlers[user.id].observable;
 | 
			
		||||
        return this.getHandlersData(user.id, context, contextId).observable;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the profile handlers for a user.
 | 
			
		||||
     *
 | 
			
		||||
     * @param user The user object.
 | 
			
		||||
     * @param courseId The course ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected async calculateUserHandlers(user: CoreUserProfile, courseId?: number): Promise<void> {
 | 
			
		||||
    protected async calculateUserHandlers(
 | 
			
		||||
        user: CoreUserProfile,
 | 
			
		||||
        context: CoreUserDelegateContext,
 | 
			
		||||
        contextId?: number,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        // Get course options.
 | 
			
		||||
        const courses = await CoreCourses.getUserCourses(true);
 | 
			
		||||
        const courseIds = courses.map((course) => course.id);
 | 
			
		||||
 | 
			
		||||
        const options = await CoreCourses.getCoursesAdminAndNavOptions(courseIds);
 | 
			
		||||
 | 
			
		||||
        // For backwards compatibility we don't modify the courseId.
 | 
			
		||||
        const courseIdForOptions = courseId || CoreSites.getCurrentSiteHomeId();
 | 
			
		||||
        const courseId = context === CoreUserDelegateContext.COURSE && contextId ? contextId : CoreSites.getCurrentSiteHomeId();
 | 
			
		||||
 | 
			
		||||
        const navOptions = options.navOptions[courseIdForOptions];
 | 
			
		||||
        const admOptions = options.admOptions[courseIdForOptions];
 | 
			
		||||
        const navOptions = options.navOptions[courseId];
 | 
			
		||||
        const admOptions = options.admOptions[courseId];
 | 
			
		||||
 | 
			
		||||
        const userData = this.userHandlers[user.id];
 | 
			
		||||
        userData.handlers = [];
 | 
			
		||||
        const handlersData = this.getHandlersData(user.id, context, contextId);
 | 
			
		||||
        handlersData.handlers = [];
 | 
			
		||||
 | 
			
		||||
        await CoreUtils.allPromises(Object.keys(this.enabledHandlers).map(async (name) => {
 | 
			
		||||
            // Checks if the handler is enabled for the user.
 | 
			
		||||
            const handler = this.handlers[name];
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                const enabled = await this.getAndCacheEnabledForUserFromHandler(handler, user, courseId, navOptions, admOptions);
 | 
			
		||||
                const enabled = await this.getAndCacheEnabledForUserFromHandler(
 | 
			
		||||
                    handler,
 | 
			
		||||
                    user,
 | 
			
		||||
                    context,
 | 
			
		||||
                    courseId,
 | 
			
		||||
                    navOptions,
 | 
			
		||||
                    admOptions,
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                if (enabled) {
 | 
			
		||||
                    userData.handlers.push({
 | 
			
		||||
                    handlersData.handlers.push({
 | 
			
		||||
                        name: name,
 | 
			
		||||
                        data: handler.getDisplayData(user, courseId),
 | 
			
		||||
                        data: handler.getDisplayData(user, context, courseId),
 | 
			
		||||
                        priority: handler.priority || 0,
 | 
			
		||||
                        type: handler.type || CoreUserDelegateService.TYPE_NEW_PAGE,
 | 
			
		||||
                    });
 | 
			
		||||
@ -326,9 +337,9 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        // Sort them by priority.
 | 
			
		||||
        userData.handlers.sort((a, b) => b.priority! - a.priority!);
 | 
			
		||||
        userData.loaded = true;
 | 
			
		||||
        userData.observable.next(userData.handlers);
 | 
			
		||||
        handlersData.handlers.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
 | 
			
		||||
        handlersData.loaded = true;
 | 
			
		||||
        handlersData.observable.next(handlersData.handlers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -336,7 +347,8 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
     *
 | 
			
		||||
     * @param handler Handler object.
 | 
			
		||||
     * @param user User object.
 | 
			
		||||
     * @param courseId Course ID where to show.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @param navOptions Navigation options for the course.
 | 
			
		||||
     * @param admOptions Admin options for the course.
 | 
			
		||||
     * @return Whether or not the handler is enabled for a user.
 | 
			
		||||
@ -344,12 +356,13 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
    protected async getAndCacheEnabledForUserFromHandler(
 | 
			
		||||
        handler: CoreUserProfileHandler,
 | 
			
		||||
        user: CoreUserProfile,
 | 
			
		||||
        courseId?: number,
 | 
			
		||||
        navOptions?: CoreCourseUserAdminOrNavOptionIndexed,
 | 
			
		||||
        admOptions?: CoreCourseUserAdminOrNavOptionIndexed,
 | 
			
		||||
        context: CoreUserDelegateContext,
 | 
			
		||||
        contextId: number,
 | 
			
		||||
        navOptions: CoreCourseUserAdminOrNavOptionIndexed = {},
 | 
			
		||||
        admOptions: CoreCourseUserAdminOrNavOptionIndexed = {},
 | 
			
		||||
    ): Promise<boolean> {
 | 
			
		||||
        if (handler.isEnabledForCourse) {
 | 
			
		||||
            const enabledOnCourse = await handler.isEnabledForCourse(courseId, navOptions, admOptions);
 | 
			
		||||
        if (handler.isEnabledForContext) {
 | 
			
		||||
            const enabledOnCourse = await handler.isEnabledForContext(context, contextId, navOptions, admOptions);
 | 
			
		||||
 | 
			
		||||
            if (!enabledOnCourse) {
 | 
			
		||||
                // If is not enabled in the course, is not enabled for the user.
 | 
			
		||||
@ -364,14 +377,14 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return handler.isEnabledForUser(user, courseId);
 | 
			
		||||
            return handler.isEnabledForUser(user, context, contextId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.enabledForUserCache[handler.name] === undefined) {
 | 
			
		||||
            this.enabledForUserCache[handler.name] = {};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const cacheKey = this.getCacheKey(courseId, user.id);
 | 
			
		||||
        const cacheKey = this.getCacheKey(user.id, context, contextId);
 | 
			
		||||
        const cache = this.enabledForUserCache[handler.name][cacheKey];
 | 
			
		||||
 | 
			
		||||
        if (cache !== undefined) {
 | 
			
		||||
@ -380,7 +393,7 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
 | 
			
		||||
        let enabled = true; // Default value.
 | 
			
		||||
        if (handler.isEnabledForUser) {
 | 
			
		||||
            enabled = await handler.isEnabledForUser(user, courseId);
 | 
			
		||||
            enabled = await handler.isEnabledForUser(user, context, contextId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.enabledForUserCache[handler.name][cacheKey] = enabled;
 | 
			
		||||
@ -390,14 +403,15 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Clear handler enabled for user cache.
 | 
			
		||||
     * If a courseId and userId are specified, it will only delete the entry for that user and course.
 | 
			
		||||
     * If a userId and context are specified, it will only delete the entry for that user and context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param userId User ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     */
 | 
			
		||||
    protected clearHandlerCache(courseId?: number, userId?: number): void {
 | 
			
		||||
        if (courseId && userId) {
 | 
			
		||||
            const cacheKey = this.getCacheKey(courseId, userId);
 | 
			
		||||
    protected clearHandlerCache(userId?: number, context?: CoreUserDelegateContext, contextId?: number): void {
 | 
			
		||||
        if (userId && context) {
 | 
			
		||||
            const cacheKey = this.getCacheKey(userId, context, contextId);
 | 
			
		||||
 | 
			
		||||
            Object.keys(this.enabledHandlers).forEach((name) => {
 | 
			
		||||
                const cache = this.enabledForUserCache[name];
 | 
			
		||||
@ -412,25 +426,81 @@ export class CoreUserDelegateService extends CoreDelegate<CoreUserProfileHandler
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a cache key to identify a course and a user.
 | 
			
		||||
     * Get a cache key to identify a user and context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param courseId Course ID.
 | 
			
		||||
     * @param userId User ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getCacheKey(courseId = 0, userId = 0): string {
 | 
			
		||||
        return courseId + '#' + userId;
 | 
			
		||||
    protected getCacheKey(userId: number, context: CoreUserDelegateContext, contextId?: number): string {
 | 
			
		||||
        return `${userId}#${this.getContextKey(context, contextId)}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a string to identify a context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return String to identify the context.
 | 
			
		||||
     */
 | 
			
		||||
    protected getContextKey(context: CoreUserDelegateContext, contextId?: number): string {
 | 
			
		||||
        return `${context}#${contextId ?? 0}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get handlers data for a user and context.
 | 
			
		||||
     *
 | 
			
		||||
     * @param userId User ID.
 | 
			
		||||
     * @param context Context.
 | 
			
		||||
     * @param contextId Context ID.
 | 
			
		||||
     * @return Handlers data.
 | 
			
		||||
     */
 | 
			
		||||
    protected getHandlersData(userId: number, context: CoreUserDelegateContext, contextId?: number): CoreUserDelegateHandlersData {
 | 
			
		||||
        // Initialize the data if it doesn't exist.
 | 
			
		||||
        const contextKey = this.getContextKey(context, contextId);
 | 
			
		||||
        this.userHandlers[userId] = this.userHandlers[userId] || {};
 | 
			
		||||
 | 
			
		||||
        if (!this.userHandlers[userId][contextKey]) {
 | 
			
		||||
            this.userHandlers[userId][contextKey] = {
 | 
			
		||||
                loaded: false,
 | 
			
		||||
                handlers: [],
 | 
			
		||||
                observable: new BehaviorSubject<CoreUserProfileHandlerToDisplay[]>([]),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this.userHandlers[userId][contextKey];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const CoreUserDelegate = makeSingleton(CoreUserDelegateService);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handlers data for a user and context.
 | 
			
		||||
 */
 | 
			
		||||
type CoreUserDelegateHandlersData = {
 | 
			
		||||
    loaded: boolean; // Whether the handlers are loaded.
 | 
			
		||||
    handlers: CoreUserProfileHandlerToDisplay[]; // List of handlers.
 | 
			
		||||
    observable: Subject<CoreUserProfileHandlerToDisplay[]>; // Observable to notify the handlers.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Context levels enumeration.
 | 
			
		||||
 */
 | 
			
		||||
export enum CoreUserDelegateContext {
 | 
			
		||||
    SITE = 'site',
 | 
			
		||||
    COURSE = 'course',
 | 
			
		||||
    USER_MENU = 'user_menu',
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Data passed to UPDATE_HANDLER_EVENT event.
 | 
			
		||||
 */
 | 
			
		||||
export type CoreUserUpdateHandlerData = {
 | 
			
		||||
    handler: string; // Name of the handler.
 | 
			
		||||
    userId: number; // User affected.
 | 
			
		||||
    context: CoreUserDelegateContext; // Context affected.
 | 
			
		||||
    contextId?: number; // ID related to the context.
 | 
			
		||||
    data: Record<string, unknown>; // Data to set to the handler.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -67,6 +67,7 @@ export class CoreTextUtilsProvider {
 | 
			
		||||
        { old: /files_sitefiles/g, new: 'AddonPrivateFilesSiteFiles' },
 | 
			
		||||
        { old: /files_upload/g, new: 'AddonPrivateFilesUpload' },
 | 
			
		||||
        { old: /_mmaModAssign/g, new: '_AddonModAssign' },
 | 
			
		||||
        { old: /_mmaModBigbluebuttonbn/g, new: '_AddonModBBB' },
 | 
			
		||||
        { old: /_mmaModBook/g, new: '_AddonModBook' },
 | 
			
		||||
        { old: /_mmaModChat/g, new: '_AddonModChat' },
 | 
			
		||||
        { old: /_mmaModChoice/g, new: '_AddonModChoice' },
 | 
			
		||||
@ -89,6 +90,7 @@ export class CoreTextUtilsProvider {
 | 
			
		||||
        { old: /_mmaModWiki/g, new: '_AddonModWiki' },
 | 
			
		||||
        { old: /_mmaModWorkshop/g, new: '_AddonModWorkshop' },
 | 
			
		||||
        { old: /remoteAddOn_/g, new: 'sitePlugin_' },
 | 
			
		||||
        { old: /AddonNotes:addNote/g, new: 'AddonNotes:notes' },
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    protected template: HTMLTemplateElement = document.createElement('template'); // A template element to convert HTML to element.
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,10 @@ information provided here is intended especially for developers.
 | 
			
		||||
- CoreCourse.getModuleBasicInfoByInstance and CoreCourse.getModuleBasicInfo have been modified to accept an "options" parameter instead of only siteId.
 | 
			
		||||
- The function CoreFilepool.isFileDownloadingByUrl now returns Promise<boolean> instead of relying on resolve/reject.
 | 
			
		||||
- downloadEnabled input has been removed from CoreBlockSideBlocksComponent, CoreCourseFormatComponent, CoreCourseFormatSingleActivityComponent and CoreCourseModuleComponent.
 | 
			
		||||
- There were several breaking changes done in CoreUserDelegate and its handlers:
 | 
			
		||||
    The function CoreUserDelegate.getProfileHandlersFor must now receive a context + contextId instead of a courseId.
 | 
			
		||||
    The user handler function isEnabledForCourse is now called isEnabledForContext and receives a context + contextId instead of a courseId.
 | 
			
		||||
    Some user handler's functions have also changed to accept context + contextId instead of a courseId: isEnabledForUser, getDisplayData, action.
 | 
			
		||||
 | 
			
		||||
=== 3.9.5 ===
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user