diff --git a/src/addon/calendar/calendar.module.ts b/src/addon/calendar/calendar.module.ts
index a79aa07dd..b36d0bf0c 100644
--- a/src/addon/calendar/calendar.module.ts
+++ b/src/addon/calendar/calendar.module.ts
@@ -15,7 +15,7 @@
import { NgModule } from '@angular/core';
import { AddonCalendarProvider } from './providers/calendar';
import { AddonCalendarHelperProvider } from './providers/helper';
-import { AddonCalendarMainMenuHandler } from './providers/handlers';
+import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
import { CoreMainMenuDelegate } from '../../core/mainmenu/providers/delegate';
import { CoreInitDelegate } from '../../providers/init';
import { CoreLocalNotificationsProvider } from '../../providers/local-notifications';
diff --git a/src/addon/calendar/providers/handlers.ts b/src/addon/calendar/providers/mainmenu-handler.ts
similarity index 100%
rename from src/addon/calendar/providers/handlers.ts
rename to src/addon/calendar/providers/mainmenu-handler.ts
diff --git a/src/classes/delegate.ts b/src/classes/delegate.ts
new file mode 100644
index 000000000..3185bf435
--- /dev/null
+++ b/src/classes/delegate.ts
@@ -0,0 +1,238 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Injectable } from '@angular/core';
+import { CoreLoggerProvider } from '../providers/logger';
+import { CoreSitesProvider } from '../providers/sites';
+import { CoreEventsProvider } from '../providers/events';
+
+export interface CoreDelegateHandler {
+ /**
+ * Name of the handler, or name and sub context (mmaMessages, mmaMessage:blockContact, ...).
+ * @type {string}
+ */
+ name: string;
+
+ /**
+ * Whether or not the handler is enabled on a site level.
+ * @return {boolean|Promise} Whether or not the handler is enabled on a site level.
+ */
+ isEnabled(): boolean|Promise;
+};
+
+/**
+ * Superclass to help creating delegates
+ */
+@Injectable()
+export class CoreDelegate {
+
+ /**
+ * Logger instance get from CoreLoggerProvider.
+ * @type {function}
+ */
+ protected logger;
+
+ /**
+ * List of registered handlers.
+ * @type {any}
+ */
+ protected handlers: {[s: string]: CoreDelegateHandler} = {};
+
+ /**
+ * List of registered handlers enabled for the current site.
+ * @type {any}
+ */
+ protected enabledHandlers: {[s: string]: CoreDelegateHandler} = {};
+
+ /**
+ * Default handler
+ * @type {CoreDelegateHandler}
+ */
+ protected defaultHandler: CoreDelegateHandler;
+
+ /**
+ * Time when last updateHandler functions started.
+ * @type {number}
+ */
+ protected lastUpdateHandlersStart: number;
+
+ /**
+ * Feature prefix to check is feature is enabled or disabled in site.
+ * This check is only made if not false. Override on the subclass or override isFeatureDisabled function.
+ * @type {string}
+ */
+ protected featurePrefix: string;
+
+ /**
+ * Constructor of the Delegate.
+ *
+ * @param {string} delegateName Delegate name used for logging purposes.
+ * @param {CoreLoggerProvider} loggerProvider CoreLoggerProvider instance, cannot be directly injected.
+ * @param {CoreSitesProvider} sitesProvider CoreSitesProvider instance, cannot be directly injected.
+ */
+ constructor(delegateName: string, protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
+ protected eventsProvider: CoreEventsProvider) {
+ this.logger = this.loggerProvider.getInstance(delegateName);
+ this.sitesProvider = sitesProvider;
+
+ // Update handlers on this cases.
+ eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this));
+ eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this));
+ eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
+ }
+
+ /**
+ * Execute a certain function in a handler.
+ * If the handler isn't found or function isn't defined, call the same function in the default handler.
+ *
+ * @param {string} handlerName The handler name.
+ * @param {string} fnName Name of the function to execute.
+ * @param {any[]} params Parameters to pass to the function.
+ * @return {any} Function returned value or default value.
+ */
+ protected executeFunction(handlerName: string, fnName: string, params?: any[]) : any {
+ let handler = this.enabledHandlers[handlerName];
+ if (handler && handler[fnName]) {
+ return handler[fnName].apply(handler, params);
+ } else if (this.defaultHandler && this.defaultHandler[fnName]) {
+ return this.defaultHandler[fnName].apply(this, params);
+ }
+ }
+
+ /**
+ * Check if a handler name has a registered handler (not necessarily enabled).
+ *
+ * @param {string} name The name of the handler.
+ * @return {boolean} If the controller is installed or not.
+ */
+ hasHandler(name: string) : boolean {
+ return typeof this.handlers[name] !== 'undefined';
+ }
+
+ /**
+ * Check if a time belongs to the last update handlers call.
+ * This is to handle the cases where updateHandlers don't finish in the same order as they're called.
+ *
+ * @param {number} time Time to check.
+ * @return {boolean} Whether it's the last call.
+ */
+ isLastUpdateCall(time: number) : boolean {
+ if (!this.lastUpdateHandlersStart) {
+ return true;
+ }
+ return time == this.lastUpdateHandlersStart;
+ }
+
+ /**
+ * Register a profile handler.
+ */
+ registerHandler(handler: CoreDelegateHandler) {
+ if (typeof this.handlers[handler.name] !== 'undefined') {
+ this.logger.log(`Addon '${handler.name}' already registered`);
+ return false;
+ }
+
+ this.logger.log(`Registered addon '${handler.name}'`);
+ this.handlers[handler.name] = handler;
+ return true;
+ }
+
+ /**
+ * Update the handler for the current site.
+ *
+ * @param {CoreDelegateHandler} handler The handler to check.
+ * @param {number} time Time this update process started.
+ * @return {Promise} Resolved when done.
+ */
+ protected updateHandler(handler: CoreDelegateHandler, time: number) : Promise {
+ let promise,
+ siteId = this.sitesProvider.getCurrentSiteId(),
+ currentSite = this.sitesProvider.getCurrentSite();
+
+ if (!this.sitesProvider.isLoggedIn()) {
+ promise = Promise.reject(null);
+ } else if (this.isFeatureDisabled(handler, currentSite)) {
+ promise = Promise.resolve(false);
+ } else {
+ promise = Promise.resolve(handler.isEnabled());
+ }
+
+ // Checks if the handler is enabled.
+ return promise.catch(() => {
+ return false;
+ }).then((enabled: boolean) => {
+ // Verify that this call is the last one that was started.
+ // Check that site hasn't changed since the check started.
+ if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) {
+ if (enabled) {
+ this.enabledHandlers[handler.name] = handler;
+ } else {
+ delete this.enabledHandlers[handler.name];
+ }
+ }
+ });
+ }
+
+ /**
+ * Check if feature is enabled or disabled in the site, depending on the feature prefix and the handler name.
+ *
+ * @param {CoreDelegateHandler} handler Handler to check.
+ * @param {any} site Site to check.
+ * @return {boolean} Whether is enabled or disabled in site.
+ */
+ protected isFeatureDisabled(handler: CoreDelegateHandler, site: any) : boolean{
+ return typeof this.featurePrefix != "undefined" && site.isFeatureDisabled(this.featurePrefix + handler.name);
+ }
+
+ /**
+ * Update the handlers for the current site.
+ *
+ * @return {Promise} Resolved when done.
+ */
+ protected updateHandlers() : Promise {
+ let promises = [],
+ now = Date.now();
+
+ this.logger.debug('Updating handlers for current site.');
+
+ this.lastUpdateHandlersStart = now;
+
+ // Loop over all the handlers.
+ for (let name in this.handlers) {
+ promises.push(this.updateHandler(this.handlers[name], now));
+ }
+
+ return Promise.all(promises).then(() => {
+ return true;
+ }, () => {
+ // Never reject.
+ return true;
+ }).then(() => {
+
+ // Verify that this call is the last one that was started.
+ if (this.isLastUpdateCall(now)) {
+ this.updateData();
+ }
+ });
+ }
+
+ /**
+ * Update handlers Data.
+ * Override this function to update handlers data.
+ */
+ updateData() {
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/core/mainmenu/providers/delegate.ts b/src/core/mainmenu/providers/delegate.ts
index a6edd6ee6..da5594cd5 100644
--- a/src/core/mainmenu/providers/delegate.ts
+++ b/src/core/mainmenu/providers/delegate.ts
@@ -14,6 +14,7 @@
import { Injectable } from '@angular/core';
import { CoreEventsProvider } from '../../../providers/events';
+import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate';
import { CoreLoggerProvider } from '../../../providers/logger';
import { CoreSitesProvider } from '../../../providers/sites';
import { Subject, BehaviorSubject } from 'rxjs';
@@ -21,26 +22,13 @@ import { Subject, BehaviorSubject } from 'rxjs';
/**
* Interface that all main menu handlers must implement.
*/
-export interface CoreMainMenuHandler {
- /**
- * Name of the handler.
- * @type {string}
- */
- name: string;
-
+export interface CoreMainMenuHandler extends CoreDelegateHandler {
/**
* The highest priority is displayed first.
* @type {number}
*/
priority: number;
- /**
- * Whether or not the handler is enabled on a site level.
- *
- * @return {boolean|Promise} True or promise resolved with true if enabled.
- */
- isEnabled(): boolean|Promise;
-
/**
* Returns the data needed to render the handler.
*
@@ -96,20 +84,17 @@ export interface CoreMainMenuHandlerToDisplay extends CoreMainMenuHandlerData {
* and notify an update in the data.
*/
@Injectable()
-export class CoreMainMenuDelegate {
- protected logger;
+export class CoreMainMenuDelegate extends CoreDelegate {
protected handlers: {[s: string]: CoreMainMenuHandler} = {};
protected enabledHandlers: {[s: string]: CoreMainMenuHandler} = {};
protected loaded = false;
- protected lastUpdateHandlersStart: number;
- protected siteHandlers: Subject = new BehaviorSubject([]);
+ protected siteHandlers: Subject = new BehaviorSubject([]);
+ protected featurePrefix = '$mmSideMenuDelegate_';
- constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) {
- this.logger = logger.getInstance('CoreMainMenuDelegate');
+ constructor(protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
+ protected eventsProvider: CoreEventsProvider) {
+ super('CoreMainMenuDelegate', loggerProvider, sitesProvider, eventsProvider);
- eventsProvider.on(CoreEventsProvider.LOGIN, this.updateHandlers.bind(this));
- eventsProvider.on(CoreEventsProvider.SITE_UPDATED, this.updateHandlers.bind(this));
- eventsProvider.on(CoreEventsProvider.REMOTE_ADDONS_LOADED, this.updateHandlers.bind(this));
eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearSiteHandlers.bind(this));
}
@@ -133,131 +118,39 @@ export class CoreMainMenuDelegate {
/**
* Get the handlers for the current site.
*
- * @return {Subject} An observable that will receive the handlers.
+ * @return {Subject} An observable that will receive the handlers.
*/
getHandlers() : Subject {
return this.siteHandlers;
}
/**
- * Check if a time belongs to the last update handlers call.
- * This is to handle the cases where updateHandlers don't finish in the same order as they're called.
- *
- * @param {number} time Time to check.
- * @return {boolean} Whether it's the last call.
+ * Update handlers Data.
*/
- isLastUpdateCall(time: number) : boolean {
- if (!this.lastUpdateHandlersStart) {
- return true;
- }
- return time == this.lastUpdateHandlersStart;
- }
+ updateData() {
+ let handlersData: any[] = [];
- /**
- * Register a handler.
- *
- * @param {CoreInitHandler} handler The handler to register.
- * @return {boolean} True if registered successfully, false otherwise.
- */
- registerHandler(handler: CoreMainMenuHandler) : boolean {
- if (typeof this.handlers[handler.name] !== 'undefined') {
- this.logger.log(`Addon '${handler.name}' already registered`);
- return false;
- }
- this.logger.log(`Registered addon '${handler.name}'`);
- this.handlers[handler.name] = handler;
- return true;
- }
+ for (let name in this.enabledHandlers) {
+ let handler = this.enabledHandlers[name],
+ data = handler.getDisplayData();
- /**
- * Update the handler for the current site.
- *
- * @param {CoreInitHandler} handler The handler to check.
- * @param {number} time Time this update process started.
- * @return {Promise} Resolved when done.
- */
- protected updateHandler(handler: CoreMainMenuHandler, time: number) : Promise {
- let promise,
- siteId = this.sitesProvider.getCurrentSiteId(),
- currentSite = this.sitesProvider.getCurrentSite();
-
- if (!this.sitesProvider.isLoggedIn()) {
- promise = Promise.reject(null);
- } else if (currentSite.isFeatureDisabled('$mmSideMenuDelegate_' + handler.name)) {
- promise = Promise.resolve(false);
- } else {
- promise = Promise.resolve(handler.isEnabled());
+ handlersData.push({
+ data: data,
+ priority: handler.priority
+ });
}
- // Checks if the handler is enabled.
- return promise.catch(() => {
- return false;
- }).then((enabled: boolean) => {
- // Verify that this call is the last one that was started.
- // Check that site hasn't changed since the check started.
- if (this.isLastUpdateCall(time) && this.sitesProvider.getCurrentSiteId() === siteId) {
- if (enabled) {
- this.enabledHandlers[handler.name] = handler;
- } else {
- delete this.enabledHandlers[handler.name];
- }
- }
+ // Sort them by priority.
+ handlersData.sort((a, b) => {
+ return b.priority - a.priority;
});
- }
- /**
- * Update the handlers for the current site.
- *
- * @return {Promise} Resolved when done.
- */
- protected updateHandlers() : Promise {
- let promises = [],
- now = Date.now();
-
- this.logger.debug('Updating handlers for current site.');
-
- this.lastUpdateHandlersStart = now;
-
- // Loop over all the handlers.
- for (let name in this.handlers) {
- promises.push(this.updateHandler(this.handlers[name], now));
- }
-
- return Promise.all(promises).then(() => {
- return true;
- }, () => {
- // Never reject.
- return true;
- }).then(() => {
- // Verify that this call is the last one that was started.
- if (this.isLastUpdateCall(now)) {
- let handlersData: any[] = [];
-
- for (let name in this.enabledHandlers) {
- let handler = this.enabledHandlers[name],
- data: CoreMainMenuHandlerToDisplay = handler.getDisplayData();
-
- data.name = handler.name;
-
- handlersData.push({
- data: data,
- priority: handler.priority
- });
- }
-
- // Sort them by priority.
- handlersData.sort((a, b) => {
- return b.priority - a.priority;
- });
-
- // Return only the display data.
- let displayData = handlersData.map((item) => {
- return item.data;
- });
-
- this.loaded = true;
- this.siteHandlers.next(displayData);
- }
+ // Return only the display data.
+ let displayData = handlersData.map((item) => {
+ return item.data;
});
+
+ this.loaded = true;
+ this.siteHandlers.next(displayData);
}
}
diff --git a/src/core/user/lang/en.json b/src/core/user/lang/en.json
index 861570f59..6ea4eb277 100644
--- a/src/core/user/lang/en.json
+++ b/src/core/user/lang/en.json
@@ -15,6 +15,7 @@
"phone1": "Phone",
"phone2": "Mobile phone",
"roles": "Roles",
+ "sendemail": "Email",
"student": "Student",
"teacher": "Non-editing teacher",
"webpage": "Web page"
diff --git a/src/core/user/pages/profile/profile.html b/src/core/user/pages/profile/profile.html
index d730e1182..efc7cba54 100644
--- a/src/core/user/pages/profile/profile.html
+++ b/src/core/user/pages/profile/profile.html
@@ -23,13 +23,40 @@
+
+
+
+
+
+ {{comHandler.title | translate}}
+
+
+
+
+
+
+
+
{{ 'core.user.details' | translate }}
-
+
+
+
+
+ {{ npHandler.title | translate }}
+
+
+
+
+
diff --git a/src/core/user/pages/profile/profile.scss b/src/core/user/pages/profile/profile.scss
index a5844f405..ff977a68f 100644
--- a/src/core/user/pages/profile/profile.scss
+++ b/src/core/user/pages/profile/profile.scss
@@ -5,4 +5,26 @@ page-core-user-profile {
bottom: 30px;
font-size: 24px;
}
+ .core-user-communication-handlers {
+ padding: 6px 2px;
+ background: $list-background-color;
+
+ .core-user-profile-handler {
+ background: $list-background-color;
+ border: 0;
+ color: $core-user-profile-communication-icons-color;
+
+ .icon {
+ border-radius: 50%;
+ width: 32px;
+ height: 32px;
+ max-width: 32px;
+ font-size: 22px;
+ line-height: 32px;
+ color: white;
+ background-color: $core-user-profile-communication-icons-color;
+ margin-bottom: 5px;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/src/core/user/pages/profile/profile.ts b/src/core/user/pages/profile/profile.ts
index 3d7bd28c7..143c5d850 100644
--- a/src/core/user/pages/profile/profile.ts
+++ b/src/core/user/pages/profile/profile.ts
@@ -23,6 +23,7 @@ import { CoreEventsProvider } from '../../../../providers/events';
import { CoreSitesProvider } from '../../../../providers/sites';
import { CoreMimetypeUtilsProvider } from '../../../../providers/utils/mimetype';
import { CoreFileUploaderHelperProvider } from '../../../fileuploader/providers/helper';
+import { CoreUserDelegate } from '../../providers/delegate';
/**
* Page that displays an user profile page.
@@ -44,11 +45,15 @@ export class CoreUserProfilePage {
title: string;
isDeleted: boolean = false;
canChangeProfilePicture: boolean = false;
+ actionHandlers = [];
+ newPageHandlers = [];
+ communicationHandlers = [];
constructor(private navParams: NavParams, private userProvider: CoreUserProvider, private userHelper: CoreUserHelperProvider,
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private eventsProvider: CoreEventsProvider,
private coursesProvider: CoreCoursesProvider, private sitesProvider: CoreSitesProvider,
- private mimetypeUtils: CoreMimetypeUtilsProvider, private fileUploaderHelper: CoreFileUploaderHelperProvider) {
+ private mimetypeUtils: CoreMimetypeUtilsProvider, private fileUploaderHelper: CoreFileUploaderHelperProvider,
+ private userDelegate: CoreUserDelegate) {
this.userId = navParams.get('userId');
this.courseId = navParams.get('courseId');
@@ -97,6 +102,29 @@ export class CoreUserProfilePage {
this.isLoadingHandlers = true;
+ this.userDelegate.getProfileHandlersFor(user, this.courseId).then((handlers) => {
+ console.error(handlers);
+ this.actionHandlers = [];
+ this.newPageHandlers = [];
+ this.communicationHandlers = [];
+ handlers.forEach((handler) => {
+ switch (handler.type) {
+ case CoreUserDelegate.TYPE_COMMUNICATION:
+ this.communicationHandlers.push(handler.data);
+ break;
+ case CoreUserDelegate.TYPE_ACTION:
+ this.actionHandlers.push(handler.data);
+ break;
+ case CoreUserDelegate.TYPE_NEW_PAGE:
+ default:
+ this.newPageHandlers.push(handler.data);
+ break;
+ }
+ });
+ }).finally(() => {
+ this.isLoadingHandlers = false;
+ });
+
}).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.user.errorloaduser', true);
});
diff --git a/src/core/user/providers/delegate.ts b/src/core/user/providers/delegate.ts
index b2ea852eb..7bb2f7638 100644
--- a/src/core/user/providers/delegate.ts
+++ b/src/core/user/providers/delegate.ts
@@ -13,18 +13,171 @@
// limitations under the License.
import { Injectable } from '@angular/core';
+import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate';
+import { CoreCoursesProvider } from '../../../core/courses/providers/courses';
import { CoreLoggerProvider } from '../../../providers/logger';
+import { CoreSitesProvider } from '../../../providers/sites';
+import { CoreEventsProvider } from '../../../providers/events';
+
+export interface CoreUserProfileHandler extends CoreDelegateHandler {
+ /**
+ * The highest priority is displayed first.
+ * @type {number}
+ */
+ priority: number;
+
+ /**
+ * A type should be specified among these:
+ * - TYPE_COMMUNICATION: will be displayed under the user avatar. Should have icon. Spinner not used.
+ * - TYPE_NEW_PAGE: will be displayed as a list of items. Should have icon. Spinner not used.
+ * Default value if none is specified.
+ * - TYPE_ACTION: will be displayed as a button and should not redirect to any state. Spinner use is recommended.
+ * @type {string}
+ */
+ type: string;
+
+ /**
+ * Whether or not the handler is enabled for a user.
+ * @param {any} user User object.
+ * @param {number} courseId Course ID where to show.
+ * @param {any} [navOptions] Navigation options for the course.
+ * @param {any} [admOptions] Admin options for the course.
+ * @return {boolean|Promise} Whether or not the handler is enabled for a user.
+ */
+ isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean|Promise;
+
+ /**
+ * Returns the data needed to render the handler.
+ * @param {any} user User object.
+ * @param {number} courseId Course ID where to show.
+ * @return {CoreUserProfileHandlerData} Data to be shown.
+ */
+ getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData;
+};
+
+export interface CoreUserProfileHandlerData {
+ /**
+ * Title to display.
+ * @type {string}
+ */
+ title: string;
+
+ /**
+ * Name of the icon to display. Mandatory for TYPE_COMMUNICATION.
+ * @type {string}
+ */
+ icon?: string;
+
+ /**
+ * Additional class to add to the HTML.
+ * @type {string}
+ */
+ class: string;
+
+ /**
+ * If enabled, element will be hidden. Only for TYPE_NEW_PAGE and TYPE_ACTION.
+ * @type {boolean}
+ */
+ hidden?: boolean;
+
+ /**
+ * If enabled will show an spinner. Only for TYPE_ACTION.
+ * @type {boolean}
+ */
+ spinner?: boolean;
+
+ /**
+ * Action to do when clicked.
+ * @param {any} $event
+ * @param {any} user User object.
+ * @param {number} courseId Course ID where to show.
+ * @return {any} Action to be done.
+ */
+ action?($event: any, user: any, courseId: number): any;
+};
/**
* Service to interact with plugins to be shown in user profile. Provides functions to register a plugin
* and notify an update in the data.
*/
@Injectable()
-export class CoreUserDelegate {
- protected logger;
+export class CoreUserDelegate extends CoreDelegate {
+ /**
+ * User profile handler type for communication.
+ * @type {string}
+ */
+ public static TYPE_COMMUNICATION = 'communication';
- constructor(logger: CoreLoggerProvider) {
- this.logger = logger.getInstance('CoreUserDelegate');
+ /**
+ * User profile handler type for new page.
+ * @type {string}
+ */
+ public static TYPE_NEW_PAGE = 'newpage';
+ /**
+ * User profile handler type for actions.
+ * @type {string}
+ */
+ public static TYPE_ACTION = 'action';
+
+ protected handlers: {[s: string]: CoreUserProfileHandler} = {};
+ protected enabledHandlers: {[s: string]: CoreUserProfileHandler} = {};
+ protected featurePrefix = '$mmUserDelegate_';
+
+ constructor(protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
+ private coursesProvider: CoreCoursesProvider, protected eventsProvider: CoreEventsProvider) {
+ super('CoreUserDelegate', loggerProvider, sitesProvider, eventsProvider);
}
+ /**
+ * Get the profile handlers for a user.
+ *
+ * @param {any} user The user object.
+ * @param {number} courseId The course ID.
+ * @return {Promise} Resolved with an array of objects containing 'priority', 'data' and 'type'.
+ */
+ getProfileHandlersFor(user: any, courseId): Promise {
+ let handlers = [],
+ promises = [];
+
+ // Retrieve course options forcing cache.
+ return this.coursesProvider.getUserCourses(true).then((courses) => {
+ let courseIds = courses.map((course) => {
+ return course.id;
+ });
+
+ return this.coursesProvider.getCoursesOptions(courseIds).then((options) => {
+ // For backwards compatibility we don't modify the courseId.
+ let courseIdForOptions = courseId || this.sitesProvider.getSiteHomeId(),
+ navOptions = options.navOptions[courseIdForOptions],
+ admOptions = options.admOptions[courseIdForOptions];
+
+ for (let name in this.enabledHandlers) {
+ // Checks if the handler is enabled for the user.
+ let handler = this.handlers[name],
+ isEnabledForUser = handler.isEnabledForUser(user, courseId, navOptions, admOptions),
+ promise = Promise.resolve(isEnabledForUser).then((enabled) => {
+ if (enabled) {
+ handlers.push({
+ data: handler.getDisplayData(user, courseId),
+ priority: handler.priority,
+ type: handler.type || CoreUserDelegate.TYPE_NEW_PAGE
+ });
+ } else {
+ return Promise.reject(null);
+ }
+ }).catch(function() {
+ // Nothing to do here, it is not enabled for this user.
+ });
+ promises.push(promise);
+ }
+
+ return Promise.all(promises).then(() => {
+ return handlers;
+ });
+ });
+ }).catch(function() {
+ // Never fails.
+ return handlers;
+ });
+ }
}
diff --git a/src/core/user/providers/user-handler.ts b/src/core/user/providers/user-handler.ts
new file mode 100644
index 000000000..3a37255e1
--- /dev/null
+++ b/src/core/user/providers/user-handler.ts
@@ -0,0 +1,70 @@
+// (C) Copyright 2015 Martin Dougiamas
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import { Injectable } from '@angular/core';
+import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from './delegate';
+import { CoreSitesProvider } from '../../../providers/sites';
+
+/**
+ * Profile links email handler.
+ */
+@Injectable()
+export class CoreUserProfileMailHandler implements CoreUserProfileHandler {
+ name = 'mmUser';
+ priority = 700;
+ type = CoreUserDelegate.TYPE_COMMUNICATION;
+
+ constructor(protected sitesProvider: CoreSitesProvider) {}
+
+ /**
+ * Check if handler is enabled.
+ *
+ * @return {boolean} Always enabled.
+ */
+ isEnabled(): boolean {
+ return true;
+ }
+
+ /**
+ * Check if handler is enabled for this user in this context.
+ *
+ * @param {any} user User to check.
+ * @param {number} courseId Course ID.
+ * @param {any} [navOptions] Course navigation options for current user. See $mmCourses#getUserNavigationOptions.
+ * @param {any} [admOptions] Course admin options for current user. See $mmCourses#getUserAdministrationOptions.
+ * @return {boolean|Promise} Promise resolved with true if enabled, resolved with false otherwise.
+ */
+ isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean|Promise {
+ // Not current user required.
+ return user.id != this.sitesProvider.getCurrentSite().getUserId() && user.email;
+ };
+
+ /**
+ * Returns the data needed to render the handler.
+ *
+ * @return {CoreUserProfileHandlerData} Data needed to render the handler.
+ */
+ getDisplayData(user: any, courseId: number): CoreUserProfileHandlerData {
+ return {
+ icon: 'mail',
+ title: 'core.user.sendemail',
+ class: 'core-user-profile-mail',
+ action: ($event, user, courseId) => {
+ $event.preventDefault();
+ $event.stopPropagation();
+ window.location.href = "mailto:" + user.email;
+ }
+ };
+ }
+}
diff --git a/src/core/user/user.module.ts b/src/core/user/user.module.ts
index 2aeae9a9e..3f052aa1d 100644
--- a/src/core/user/user.module.ts
+++ b/src/core/user/user.module.ts
@@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { CoreUserDelegate } from './providers/delegate';
import { CoreUserProvider } from './providers/user';
import { CoreUserHelperProvider } from './providers/helper';
+import { CoreUserProfileMailHandler } from './providers/user-handler';
@NgModule({
declarations: [
@@ -24,8 +25,13 @@ import { CoreUserHelperProvider } from './providers/helper';
],
providers: [
CoreUserDelegate,
+ CoreUserProfileMailHandler,
CoreUserProvider,
CoreUserHelperProvider
]
})
-export class CoreUserModule {}
+export class CoreUserModule {
+ constructor(userDelegate: CoreUserDelegate, userProfileMailHandler: CoreUserProfileMailHandler) {
+ userDelegate.registerHandler(userProfileMailHandler);
+ }
+}
diff --git a/src/theme/variables.scss b/src/theme/variables.scss
index a3e26a43a..ffaec06dd 100644
--- a/src/theme/variables.scss
+++ b/src/theme/variables.scss
@@ -195,3 +195,5 @@ $core-top-tabs-background: $white;
$core-top-tabs-color: $gray-dark;
$core-top-tabs-border: $gray;
$core-top-tabs-color-active: $core-color;
+
+$core-user-profile-communication-icons-color: $core-color;