1 /** 2 * Copyright (C) 2010-2014 KO GmbH <copyright@kogmbh.com> 3 * 4 * @licstart 5 * This file is part of WebODF. 6 * 7 * WebODF is free software: you can redistribute it and/or modify it 8 * under the terms of the GNU Affero General Public License (GNU AGPL) 9 * as published by the Free Software Foundation, either version 3 of 10 * the License, or (at your option) any later version. 11 * 12 * WebODF is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU Affero General Public License for more details. 16 * 17 * You should have received a copy of the GNU Affero General Public License 18 * along with WebODF. If not, see <http://www.gnu.org/licenses/>. 19 * @licend 20 * 21 * @source: http://www.webodf.org/ 22 * @source: https://github.com/kogmbh/WebODF/ 23 */ 24 25 /*global gui, core*/ 26 27 /** 28 * A helper object used to subscribe to events on multiple event sources. Tracking this makes it easier to unsubscribe 29 * to all events upon destruction. 30 * 31 * @constructor 32 * @implements {core.Destroyable} 33 */ 34 core.EventSubscriptions = function () { 35 "use strict"; 36 var /**@type{!Array.<!{eventSource: !core.EventSource, eventid: !string, callback: !Function}>}*/ 37 subscriptions = [], 38 /**@type {!core.EventNotifier}*/ 39 frameEventNotifier = new core.EventNotifier(), 40 /**@type{!Object.<!string,!Array.<!{frameEventId: !string, eventSource: !Object, task: !core.ScheduledTask}>>}*/ 41 frameSubscriptions = {}, 42 /**@type{!number}*/ 43 nextFrameEventId = 0; 44 45 /** 46 * Subscribe to the specified event on the supplied eventSource 47 * @param {!core.EventSource} eventSource 48 * @param {!string} eventid 49 * @param {!Function} callback 50 */ 51 function addSubscription(eventSource, eventid, callback) { 52 eventSource.subscribe(eventid, callback); 53 subscriptions.push({ 54 eventSource: eventSource, 55 eventid: eventid, 56 callback: callback 57 }); 58 } 59 this.addSubscription = addSubscription; 60 61 /** 62 * Register a callback that will be invoked if the supplied event id is triggered at least once before the next 63 * frame. The callback will only be triggered once per event id when the browser redraws the content. 64 * The callback takes no arguments. 65 * 66 * @param {!core.EventSource} eventSource 67 * @param {!string} eventid 68 * @param {!function():undefined} callback Event callback. This callback takes NO arguments 69 * @return {undefined} 70 */ 71 this.addFrameSubscription = function (eventSource, eventid, callback) { 72 var frameSubscription, 73 frameEventId, 74 eventFrameSubscriptions, 75 i; 76 77 if (!frameSubscriptions.hasOwnProperty(eventid)) { 78 frameSubscriptions[eventid] = []; 79 } 80 eventFrameSubscriptions = frameSubscriptions[eventid]; 81 82 for (i = 0; i < eventFrameSubscriptions.length; i += 1) { 83 if (eventFrameSubscriptions[i].eventSource === eventSource) { 84 frameSubscription = eventFrameSubscriptions[i]; 85 break; 86 } 87 } 88 89 if (!frameSubscription) { 90 frameEventId = "s" + nextFrameEventId; 91 nextFrameEventId += 1; 92 frameEventNotifier.register(frameEventId); 93 frameSubscription = { 94 // A unique frame event id is necessary in case multiple eventSources identical external event ids 95 frameEventId: frameEventId, 96 eventSource: eventSource, 97 task: core.Task.createRedrawTask(function() { 98 frameEventNotifier.emit(frameEventId, undefined); 99 }) 100 }; 101 eventFrameSubscriptions.push(frameSubscription); 102 addSubscription(eventSource, eventid, frameSubscription.task.trigger); 103 } 104 105 frameEventNotifier.subscribe(frameSubscription.frameEventId, callback); 106 }; 107 108 /** 109 * Unsubscribe all event subscriptions on all eventSources 110 * @return {undefined} 111 */ 112 function unsubscribeAll() { 113 var cleanup = []; 114 115 subscriptions.forEach(function(subscription) { 116 subscription.eventSource.unsubscribe(subscription.eventid, subscription.callback); 117 }); 118 subscriptions.length = 0; 119 120 Object.keys(frameSubscriptions).forEach(function(eventId) { 121 frameSubscriptions[eventId].forEach(function(subscriber) { 122 cleanup.push(subscriber.task.destroy); 123 }); 124 delete frameSubscriptions[eventId]; 125 }); 126 /*jslint emptyblock:true*/ 127 core.Async.destroyAll(cleanup, function() { }); 128 /*jslint emptyblock:false*/ 129 frameEventNotifier = new core.EventNotifier(); 130 } 131 this.unsubscribeAll = unsubscribeAll; 132 133 /** 134 * Destroy the object. 135 * Do not access any member of this object after this call. 136 * @param {function(!Error=):undefined} callback 137 * @return {undefined} 138 */ 139 this.destroy = function(callback) { 140 unsubscribeAll(); 141 callback(); 142 }; 143 };