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}}

+
+
+ + + +
+
+ - + + + + +

{{ 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;