1 /*
  2     Copyright 2008-2021
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
 13 
 14     You can redistribute it and/or modify it under the terms of the
 15 
 16       * GNU Lesser General Public License as published by
 17         the Free Software Foundation, either version 3 of the License, or
 18         (at your option) any later version
 19       OR
 20       * MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
 21 
 22     JSXGraph is distributed in the hope that it will be useful,
 23     but WITHOUT ANY WARRANTY; without even the implied warranty of
 24     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 25     GNU Lesser General Public License for more details.
 26 
 27     You should have received a copy of the GNU Lesser General Public License and
 28     the MIT License along with JSXGraph. If not, see <http://www.gnu.org/licenses/>
 29     and <http://opensource.org/licenses/MIT/>.
 30  */
 31 
 32 
 33 /*global JXG: true, define: true*/
 34 /*jslint nomen: true, plusplus: true*/
 35 
 36 /* depends:
 37  jxg
 38  utils/type
 39  */
 40 
 41 /**
 42  * @fileoverview In this file the EventEmitter interface is defined.
 43  */
 44 
 45 define(['jxg', 'utils/type'], function (JXG, Type) {
 46 
 47     "use strict";
 48 
 49     /**
 50      * Event namespace
 51      * @namespace
 52      */
 53     JXG.EventEmitter = {
 54         /**
 55          * Holds the registered event handlers.
 56          * @type Object
 57          */
 58         eventHandlers: {},
 59 
 60         /**
 61          * Events can be suspended to prevent endless loops.
 62          * @type Object
 63          */
 64         suspended: {},
 65 
 66         /**
 67          * Triggers all event handlers of this element for a given event.
 68          * @param {Array} event
 69          * @param {Array} args The arguments passed onto the event handler
 70          * @returns Reference to the object.
 71          */
 72         trigger: function (event, args) {
 73             var i, j, h, evt, len1, len2;
 74 
 75             len1 = event.length;
 76             for (j = 0; j < len1; j++) {
 77                 evt = this.eventHandlers[event[j]];
 78 
 79                 if (!this.suspended[event[j]]) {
 80                     this.suspended[event[j]] = true;
 81 
 82                     if (evt) {
 83                         len2 = evt.length;
 84 
 85                         for (i = 0; i < len2; i++) {
 86                             h = evt[i];
 87                             h.handler.apply(h.context, args);
 88                         }
 89                     }
 90 
 91                     this.suspended[event[j]] = false;
 92                 }
 93             }
 94 
 95             return this;
 96         },
 97 
 98         /**
 99          * Register a new event handler. For a list of possible events see documentation
100          * of the elements and objects implementing
101          * the {@link EventEmitter} interface.
102          * @param {String} event
103          * @param {Function} handler
104          * @param {Object} [context] The context the handler will be called in, default is the element itself.
105          * @returns Reference to the object.
106          */
107         on: function (event, handler, context) {
108             if (!Type.isArray(this.eventHandlers[event])) {
109                 this.eventHandlers[event] = [];
110             }
111 
112             context = Type.def(context, this);
113 
114             this.eventHandlers[event].push({
115                 handler: handler,
116                 context: context
117             });
118 
119             return this;
120         },
121 
122         /**
123          * Unregister an event handler.
124          * @param {String} event
125          * @param {Function} [handler]
126          * @returns Reference to the object.
127          */
128         off: function (event, handler) {
129             var i;
130 
131             if (!event || !Type.isArray(this.eventHandlers[event])) {
132                 return this;
133             }
134 
135             if (handler) {
136                 i = Type.indexOf(this.eventHandlers[event], handler, 'handler');
137                 if (i > -1) {
138                     this.eventHandlers[event].splice(i, 1);
139                 }
140 
141                 if (this.eventHandlers[event].length === 0) {
142                     delete this.eventHandlers[event];
143                 }
144             } else {
145                 delete this.eventHandlers[event];
146             }
147 
148             return this;
149         },
150 
151         /**
152          * @description Implements the functionality from this interface in the given object.
153          * All objects getting their event handling
154          * capabilities from this method should document it by adding
155          * the <tt>on, off, triggerEventHandlers</tt> via the
156          * borrows tag as methods to their documentation:
157          * <pre>@borrows JXG.EventEmitter#on as this.on</pre>
158          * @param {Object} o
159          */
160         eventify: function (o) {
161             o.eventHandlers = {};
162             o.on = this.on;
163             o.off = this.off;
164             o.triggerEventHandlers = this.trigger;
165             o.trigger = this.trigger;
166             o.suspended = {};
167         }
168     };
169 
170     return JXG.EventEmitter;
171 });
172