MOBILE-2317 user: Add User Delegate
parent
2f2b16f9fa
commit
e836171c02
|
@ -15,7 +15,7 @@
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { AddonCalendarProvider } from './providers/calendar';
|
import { AddonCalendarProvider } from './providers/calendar';
|
||||||
import { AddonCalendarHelperProvider } from './providers/helper';
|
import { AddonCalendarHelperProvider } from './providers/helper';
|
||||||
import { AddonCalendarMainMenuHandler } from './providers/handlers';
|
import { AddonCalendarMainMenuHandler } from './providers/mainmenu-handler';
|
||||||
import { CoreMainMenuDelegate } from '../../core/mainmenu/providers/delegate';
|
import { CoreMainMenuDelegate } from '../../core/mainmenu/providers/delegate';
|
||||||
import { CoreInitDelegate } from '../../providers/init';
|
import { CoreInitDelegate } from '../../providers/init';
|
||||||
import { CoreLocalNotificationsProvider } from '../../providers/local-notifications';
|
import { CoreLocalNotificationsProvider } from '../../providers/local-notifications';
|
||||||
|
|
|
@ -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<boolean>} Whether or not the handler is enabled on a site level.
|
||||||
|
*/
|
||||||
|
isEnabled(): boolean|Promise<boolean>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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<void>} Resolved when done.
|
||||||
|
*/
|
||||||
|
protected updateHandler(handler: CoreDelegateHandler, time: number) : Promise<void> {
|
||||||
|
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<void>} Resolved when done.
|
||||||
|
*/
|
||||||
|
protected updateHandlers() : Promise<void> {
|
||||||
|
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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreEventsProvider } from '../../../providers/events';
|
import { CoreEventsProvider } from '../../../providers/events';
|
||||||
|
import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate';
|
||||||
import { CoreLoggerProvider } from '../../../providers/logger';
|
import { CoreLoggerProvider } from '../../../providers/logger';
|
||||||
import { CoreSitesProvider } from '../../../providers/sites';
|
import { CoreSitesProvider } from '../../../providers/sites';
|
||||||
import { Subject, BehaviorSubject } from 'rxjs';
|
import { Subject, BehaviorSubject } from 'rxjs';
|
||||||
|
@ -21,26 +22,13 @@ import { Subject, BehaviorSubject } from 'rxjs';
|
||||||
/**
|
/**
|
||||||
* Interface that all main menu handlers must implement.
|
* Interface that all main menu handlers must implement.
|
||||||
*/
|
*/
|
||||||
export interface CoreMainMenuHandler {
|
export interface CoreMainMenuHandler extends CoreDelegateHandler {
|
||||||
/**
|
|
||||||
* Name of the handler.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The highest priority is displayed first.
|
* The highest priority is displayed first.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
priority: number;
|
priority: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the handler is enabled on a site level.
|
|
||||||
*
|
|
||||||
* @return {boolean|Promise<boolean>} True or promise resolved with true if enabled.
|
|
||||||
*/
|
|
||||||
isEnabled(): boolean|Promise<boolean>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the data needed to render the handler.
|
* Returns the data needed to render the handler.
|
||||||
*
|
*
|
||||||
|
@ -96,20 +84,17 @@ export interface CoreMainMenuHandlerToDisplay extends CoreMainMenuHandlerData {
|
||||||
* and notify an update in the data.
|
* and notify an update in the data.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreMainMenuDelegate {
|
export class CoreMainMenuDelegate extends CoreDelegate {
|
||||||
protected logger;
|
|
||||||
protected handlers: {[s: string]: CoreMainMenuHandler} = {};
|
protected handlers: {[s: string]: CoreMainMenuHandler} = {};
|
||||||
protected enabledHandlers: {[s: string]: CoreMainMenuHandler} = {};
|
protected enabledHandlers: {[s: string]: CoreMainMenuHandler} = {};
|
||||||
protected loaded = false;
|
protected loaded = false;
|
||||||
protected lastUpdateHandlersStart: number;
|
protected siteHandlers: Subject<CoreMainMenuHandlerToDisplay[]> = new BehaviorSubject<CoreMainMenuHandlerData[]>([]);
|
||||||
protected siteHandlers: Subject<CoreMainMenuHandlerToDisplay[]> = new BehaviorSubject<CoreMainMenuHandlerToDisplay[]>([]);
|
protected featurePrefix = '$mmSideMenuDelegate_';
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, eventsProvider: CoreEventsProvider) {
|
constructor(protected loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
|
||||||
this.logger = logger.getInstance('CoreMainMenuDelegate');
|
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));
|
eventsProvider.on(CoreEventsProvider.LOGOUT, this.clearSiteHandlers.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,131 +118,39 @@ export class CoreMainMenuDelegate {
|
||||||
/**
|
/**
|
||||||
* Get the handlers for the current site.
|
* Get the handlers for the current site.
|
||||||
*
|
*
|
||||||
* @return {Subject<CoreMainMenuHandlerData[]>} An observable that will receive the handlers.
|
* @return {Subject<CoreMainMenuHandlerToDisplay[]>} An observable that will receive the handlers.
|
||||||
*/
|
*/
|
||||||
getHandlers() : Subject<CoreMainMenuHandlerToDisplay[]> {
|
getHandlers() : Subject<CoreMainMenuHandlerToDisplay[]> {
|
||||||
return this.siteHandlers;
|
return this.siteHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a time belongs to the last update handlers call.
|
* Update handlers Data.
|
||||||
* 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 {
|
updateData() {
|
||||||
if (!this.lastUpdateHandlersStart) {
|
let handlersData: any[] = [];
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return time == this.lastUpdateHandlersStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
for (let name in this.enabledHandlers) {
|
||||||
* Register a handler.
|
let handler = this.enabledHandlers[name],
|
||||||
*
|
data = handler.getDisplayData();
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
handlersData.push({
|
||||||
* Update the handler for the current site.
|
data: data,
|
||||||
*
|
priority: handler.priority
|
||||||
* @param {CoreInitHandler} handler The handler to check.
|
});
|
||||||
* @param {number} time Time this update process started.
|
|
||||||
* @return {Promise<void>} Resolved when done.
|
|
||||||
*/
|
|
||||||
protected updateHandler(handler: CoreMainMenuHandler, time: number) : Promise<void> {
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the handler is enabled.
|
// Sort them by priority.
|
||||||
return promise.catch(() => {
|
handlersData.sort((a, b) => {
|
||||||
return false;
|
return b.priority - a.priority;
|
||||||
}).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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Return only the display data.
|
||||||
* Update the handlers for the current site.
|
let displayData = handlersData.map((item) => {
|
||||||
*
|
return item.data;
|
||||||
* @return {Promise<void>} Resolved when done.
|
|
||||||
*/
|
|
||||||
protected updateHandlers() : Promise<void> {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.loaded = true;
|
||||||
|
this.siteHandlers.next(displayData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"phone1": "Phone",
|
"phone1": "Phone",
|
||||||
"phone2": "Mobile phone",
|
"phone2": "Mobile phone",
|
||||||
"roles": "Roles",
|
"roles": "Roles",
|
||||||
|
"sendemail": "Email",
|
||||||
"student": "Student",
|
"student": "Student",
|
||||||
"teacher": "Non-editing teacher",
|
"teacher": "Non-editing teacher",
|
||||||
"webpage": "Web page"
|
"webpage": "Web page"
|
||||||
|
|
|
@ -23,13 +23,40 @@
|
||||||
</p>
|
</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-grid ion-item class="core-user-communication-handlers" *ngIf="(communicationHandlers && communicationHandlers.length) || isLoadingHandlers">
|
||||||
|
<ion-row no-padding align-items-center text-center>
|
||||||
|
<ion-col align-self-center *ngIf="communicationHandlers && communicationHandlers.length">
|
||||||
|
<a *ngFor="let comHandler of communicationHandlers" (click)="comHandler.action($event, user, courseId)" [ngClass]="['core-user-profile-handler', comHandler.class]" title="{{comHandler.title | translate}}">
|
||||||
|
<ion-icon [name]="comHandler.icon"></ion-icon>
|
||||||
|
<p>{{comHandler.title | translate}}</p>
|
||||||
|
</a>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col text-center class="core-loading-handlers" *ngIf="isLoadingHandlers">
|
||||||
|
<ion-spinner></ion-spinner>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
|
||||||
<a ion-item text-wrap class="core-user-profile-handler" navPush="CoreUserAboutPage" [navParams]="{courseId: courseId, userId: userId}" title="{{ 'core.user.details' | translate }}">
|
<a ion-item text-wrap class="core-user-profile-handler" navPush="CoreUserAboutPage" [navParams]="{courseId: courseId, userId: userId}" title="{{ 'core.user.details' | translate }}">
|
||||||
<ion-icon name="person" item-start></ion-icon>
|
<ion-icon name="person" item-start></ion-icon>
|
||||||
<h2>{{ 'core.user.details' | translate }}</h2>
|
<h2>{{ 'core.user.details' | translate }}</h2>
|
||||||
</a>
|
</a>
|
||||||
<ion-item text-center *ngIf="isLoadingHandlers">
|
<ion-item text-center class="core-loading-handlers" *ngIf="isLoadingHandlers">
|
||||||
<ion-spinner></ion-spinner>
|
<ion-spinner></ion-spinner>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
|
<a *ngFor="let npHandler of newPageHandlers" ion-item text-wrap [ngClass]="['core-user-profile-handler', npHandler.class]" (click)="npHandler.action($event, user, courseId)" [hidden]="npHandler.hidden" title="{{ npHandler.title | translate }}">
|
||||||
|
<ion-icon *ngIf="npHandler.icon" [name]="npHandler.icon" item-start></ion-icon>
|
||||||
|
<h2>{{ npHandler.title | translate }}</h2>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ion-item *ngIf="actionHandlers && actionHandlers.length">
|
||||||
|
<button *ngFor="let actHandler of actionHandlers" ion-button block outline [ngClass]="['core-user-profile-handler', actHandler.class]" (click)="actHandler.action($event)" [hidden]="actHandler.hidden" title="{{ actHandler.title | translate }}">
|
||||||
|
<ion-icon *ngIf="actHandler.icon" [name]="actHandler.icon" item-start></ion-icon>
|
||||||
|
{{ actHandler.title | translate }}
|
||||||
|
<ion-spinner *ngIf="actHandler.spinner" item-end></ion-spinner>
|
||||||
|
</button>
|
||||||
|
</ion-item>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
<core-empty-box *ngIf="!user && !isDeleted" icon="person" [message]=" 'core.user.detailsnotavailable' | translate"></core-empty-box>
|
<core-empty-box *ngIf="!user && !isDeleted" icon="person" [message]=" 'core.user.detailsnotavailable' | translate"></core-empty-box>
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,26 @@ page-core-user-profile {
|
||||||
bottom: 30px;
|
bottom: 30px;
|
||||||
font-size: 24px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@ import { CoreEventsProvider } from '../../../../providers/events';
|
||||||
import { CoreSitesProvider } from '../../../../providers/sites';
|
import { CoreSitesProvider } from '../../../../providers/sites';
|
||||||
import { CoreMimetypeUtilsProvider } from '../../../../providers/utils/mimetype';
|
import { CoreMimetypeUtilsProvider } from '../../../../providers/utils/mimetype';
|
||||||
import { CoreFileUploaderHelperProvider } from '../../../fileuploader/providers/helper';
|
import { CoreFileUploaderHelperProvider } from '../../../fileuploader/providers/helper';
|
||||||
|
import { CoreUserDelegate } from '../../providers/delegate';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Page that displays an user profile page.
|
* Page that displays an user profile page.
|
||||||
|
@ -44,11 +45,15 @@ export class CoreUserProfilePage {
|
||||||
title: string;
|
title: string;
|
||||||
isDeleted: boolean = false;
|
isDeleted: boolean = false;
|
||||||
canChangeProfilePicture: boolean = false;
|
canChangeProfilePicture: boolean = false;
|
||||||
|
actionHandlers = [];
|
||||||
|
newPageHandlers = [];
|
||||||
|
communicationHandlers = [];
|
||||||
|
|
||||||
constructor(private navParams: NavParams, private userProvider: CoreUserProvider, private userHelper: CoreUserHelperProvider,
|
constructor(private navParams: NavParams, private userProvider: CoreUserProvider, private userHelper: CoreUserHelperProvider,
|
||||||
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private eventsProvider: CoreEventsProvider,
|
private domUtils: CoreDomUtilsProvider, private translate: TranslateService, private eventsProvider: CoreEventsProvider,
|
||||||
private coursesProvider: CoreCoursesProvider, private sitesProvider: CoreSitesProvider,
|
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.userId = navParams.get('userId');
|
||||||
this.courseId = navParams.get('courseId');
|
this.courseId = navParams.get('courseId');
|
||||||
|
|
||||||
|
@ -97,6 +102,29 @@ export class CoreUserProfilePage {
|
||||||
|
|
||||||
this.isLoadingHandlers = true;
|
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) => {
|
}).catch((error) => {
|
||||||
this.domUtils.showErrorModalDefault(error, 'core.user.errorloaduser', true);
|
this.domUtils.showErrorModalDefault(error, 'core.user.errorloaduser', true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,18 +13,171 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CoreDelegate, CoreDelegateHandler } from '../../../classes/delegate';
|
||||||
|
import { CoreCoursesProvider } from '../../../core/courses/providers/courses';
|
||||||
import { CoreLoggerProvider } from '../../../providers/logger';
|
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<boolean>} Whether or not the handler is enabled for a user.
|
||||||
|
*/
|
||||||
|
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean|Promise<boolean>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Service to interact with plugins to be shown in user profile. Provides functions to register a plugin
|
||||||
* and notify an update in the data.
|
* and notify an update in the data.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CoreUserDelegate {
|
export class CoreUserDelegate extends CoreDelegate {
|
||||||
protected logger;
|
/**
|
||||||
|
* 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<any>} Resolved with an array of objects containing 'priority', 'data' and 'type'.
|
||||||
|
*/
|
||||||
|
getProfileHandlersFor(user: any, courseId): Promise<any> {
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<boolean>} Promise resolved with true if enabled, resolved with false otherwise.
|
||||||
|
*/
|
||||||
|
isEnabledForUser(user: any, courseId: number, navOptions?: any, admOptions?: any): boolean|Promise<boolean> {
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
|
||||||
import { CoreUserDelegate } from './providers/delegate';
|
import { CoreUserDelegate } from './providers/delegate';
|
||||||
import { CoreUserProvider } from './providers/user';
|
import { CoreUserProvider } from './providers/user';
|
||||||
import { CoreUserHelperProvider } from './providers/helper';
|
import { CoreUserHelperProvider } from './providers/helper';
|
||||||
|
import { CoreUserProfileMailHandler } from './providers/user-handler';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -24,8 +25,13 @@ import { CoreUserHelperProvider } from './providers/helper';
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
CoreUserDelegate,
|
CoreUserDelegate,
|
||||||
|
CoreUserProfileMailHandler,
|
||||||
CoreUserProvider,
|
CoreUserProvider,
|
||||||
CoreUserHelperProvider
|
CoreUserHelperProvider
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreUserModule {}
|
export class CoreUserModule {
|
||||||
|
constructor(userDelegate: CoreUserDelegate, userProfileMailHandler: CoreUserProfileMailHandler) {
|
||||||
|
userDelegate.registerHandler(userProfileMailHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -195,3 +195,5 @@ $core-top-tabs-background: $white;
|
||||||
$core-top-tabs-color: $gray-dark;
|
$core-top-tabs-color: $gray-dark;
|
||||||
$core-top-tabs-border: $gray;
|
$core-top-tabs-border: $gray;
|
||||||
$core-top-tabs-color-active: $core-color;
|
$core-top-tabs-color-active: $core-color;
|
||||||
|
|
||||||
|
$core-user-profile-communication-icons-color: $core-color;
|
||||||
|
|
Loading…
Reference in New Issue