// (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 { Subject } from 'rxjs'; import { CoreLoggerProvider } from '@providers/logger'; /** * Observer instance to stop listening to an event. */ export interface CoreEventObserver { /** * Stop the observer. */ off: () => void; } /* * Service to send and listen to events. */ @Injectable() export class CoreEventsProvider { static SESSION_EXPIRED = 'session_expired'; static PASSWORD_CHANGE_FORCED = 'password_change_forced'; static USER_NOT_FULLY_SETUP = 'user_not_fully_setup'; static SITE_POLICY_NOT_AGREED = 'site_policy_not_agreed'; static LOGIN = 'login'; static LOGOUT = 'logout'; static LANGUAGE_CHANGED = 'language_changed'; static NOTIFICATION_SOUND_CHANGED = 'notification_sound_changed'; static SITE_ADDED = 'site_added'; static SITE_UPDATED = 'site_updated'; static SITE_DELETED = 'site_deleted'; static COMPLETION_MODULE_VIEWED = 'completion_module_viewed'; static USER_DELETED = 'user_deleted'; static PACKAGE_STATUS_CHANGED = 'package_status_changed'; static COURSE_STATUS_CHANGED = 'course_status_changed'; static SECTION_STATUS_CHANGED = 'section_status_changed'; static REMOTE_ADDONS_LOADED = 'remote_addons_loaded'; static LOGIN_SITE_CHECKED = 'login_site_checked'; static LOGIN_SITE_UNCHECKED = 'login_site_unchecked'; static IAB_LOAD_START = 'inappbrowser_load_start'; static IAB_EXIT = 'inappbrowser_exit'; static APP_LAUNCHED_URL = 'app_launched_url'; // App opened with a certain URL (custom URL scheme). static FILE_SHARED = 'file_shared'; protected logger; protected observables: { [s: string]: Subject } = {}; protected uniqueEvents = {}; constructor(logger: CoreLoggerProvider) { this.logger = logger.getInstance('CoreEventsProvider'); } /** * Listen for a certain event. To stop listening to the event: * let observer = eventsProvider.on('something', myCallBack); * ... * observer.off(); * * @param {string} eventName Name of the event to listen to. * @param {Function} callBack Function to call when the event is triggered. * @param {string} [siteId] Site where to trigger the event. Undefined won't check the site. * @return {CoreEventObserver} Observer to stop listening. */ on(eventName: string, callBack: (value: any) => void, siteId?: string): CoreEventObserver { // If it's a unique event and has been triggered already, call the callBack. // We don't need to create an observer because the event won't be triggered again. if (this.uniqueEvents[eventName]) { callBack(this.uniqueEvents[eventName].data); // Return a fake observer to prevent errors. return { off: (): void => { // Nothing to do. } }; } this.logger.debug(`New observer listening to event '${eventName}'`); if (typeof this.observables[eventName] == 'undefined') { // No observable for this event, create a new one. this.observables[eventName] = new Subject(); } const subscription = this.observables[eventName].subscribe((value: any) => { if (!siteId || value.siteId == siteId) { callBack(value); } }); // Create and return a CoreEventObserver. return { off: (): void => { this.logger.debug(`Stop listening to event '${eventName}'`); subscription.unsubscribe(); } }; } /** * Triggers an event, notifying all the observers. * * @param {string} event Name of the event to trigger. * @param {any} [data] Data to pass to the observers. * @param {string} [siteId] Site where to trigger the event. Undefined means no Site. */ trigger(eventName: string, data?: any, siteId?: string): void { this.logger.debug(`Event '${eventName}' triggered.`); if (this.observables[eventName]) { if (siteId) { if (!data) { data = {}; } data.siteId = siteId; } this.observables[eventName].next(data); } } /** * Triggers a unique event, notifying all the observers. If the event has already been triggered, don't do anything. * * @param {string} event Name of the event to trigger. * @param {any} data Data to pass to the observers. * @param {string} [siteId] Site where to trigger the event. Undefined means no Site. */ triggerUnique(eventName: string, data: any, siteId?: string): void { if (this.uniqueEvents[eventName]) { this.logger.debug(`Unique event '${eventName}' ignored because it was already triggered.`); } else { this.logger.debug(`Unique event '${eventName}' triggered.`); if (siteId) { if (!data) { data = {}; } data.siteId = siteId; } // Store the data so it can be passed to observers that register from now on. this.uniqueEvents[eventName] = { data: data }; // Now pass the data to observers. if (this.observables[eventName]) { this.observables[eventName].next(data); } } } }