      1 /*
      2     Copyright 2008-2023
      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 <https://www.gnu.org/licenses/>
     29     and <https://opensource.org/licenses/MIT/>.
     30  */
     31
     32 /*global JXG: true, define: true*/
     33 /*jslint nomen: true, plusplus: true*/
     34
     35 /**
     36  * @fileoverview In this file the EventEmitter interface is defined.
     37  */
     38
     39 import JXG from "../jxg";
     40 import Type from "./type";
     41
     42 /**
     43  * Event namespace
     44  * @namespace
     45  */
     46 JXG.EventEmitter = {
     47     /**
     48      * Holds the registered event handlers.
     49      * @type Object
     50      */
     51     eventHandlers: {},
     52
     53     /**
     54      * Events can be suspended to prevent endless loops.
     55      * @type Object
     56      */
     57     suspended: {},
     58
     59     /**
     60      * Triggers all event handlers of this element for a given event.
     61      * @param {Array} event
     62      * @param {Array} args The arguments passed onto the event handler
     63      * @returns Reference to the object.
     64      */
     65     trigger: function (event, args) {
     66         var i, j, h, evt, len1, len2;
     67
     68         len1 = event.length;
     69         for (j = 0; j < len1; j++) {
     70             evt = this.eventHandlers[event[j]];
     71             if (!this.suspended[event[j]]) {
     72                 this.suspended[event[j]] = true;
     73                 if (evt) {
     74                     len2 = evt.length;
     75                     for (i = 0; i < len2; i++) {
     76                         h = evt[i];
     77                         h.handler.apply(h.context, args);
     78                     }
     79                 }
     80
     81                 this.suspended[event[j]] = false;
     82             }
     83         }
     84
     85         return this;
     86     },
     87
     88     /**
     89      * Register a new event handler. For a list of possible events see documentation
     90      * of the elements and objects implementing
     91      * the {@link EventEmitter} interface.
     92      *
     93      * As of version 1.5.0, it is only possible to access the element via "this" if the event listener
     94      * is supplied as regular JavaScript function and not as arrow function.
     95      *
     96      * @param {String} event
     97      * @param {Function} handler
     98      * @param {Object} [context] The context the handler will be called in, default is the element itself.
     99      * @returns Reference to the object.
    100      */
    101     on: function (event, handler, context) {
    102         if (!Type.isArray(this.eventHandlers[event])) {
    103             this.eventHandlers[event] = [];
    104         }
    105
    106         context = Type.def(context, this);
    107
    108         this.eventHandlers[event].push({
    109             handler: handler,
    110             context: context
    111         });
    112
    113         return this;
    114     },
    115
    116     /**
    117      * Unregister an event handler.
    118      * @param {String} event
    119      * @param {Function} [handler]
    120      * @returns Reference to the object.
    121      */
    122     off: function (event, handler) {
    123         var i;
    124
    125         if (!event || !Type.isArray(this.eventHandlers[event])) {
    126             return this;
    127         }
    128
    129         if (handler) {
    130             i = Type.indexOf(this.eventHandlers[event], handler, "handler");
    131             if (i > -1) {
    132                 this.eventHandlers[event].splice(i, 1);
    133             }
    134
    135             if (this.eventHandlers[event].length === 0) {
    136                 delete this.eventHandlers[event];
    137             }
    138         } else {
    139             delete this.eventHandlers[event];
    140         }
    141
    142         return this;
    143     },
    144
    145     /**
    146      * @description Implements the functionality from this interface in the given object.
    147      * All objects getting their event handling
    148      * capabilities from this method should document it by adding
    149      * the <tt>on, off, triggerEventHandlers</tt> via the
    150      * borrows tag as methods to their documentation:
    151      * <pre>@borrows JXG.EventEmitter#on as this.on</pre>
    152      * @param {Object} o
    153      */
    154     eventify: function (o) {
    155         o.eventHandlers = {};
    156         o.on = this.on;
    157         o.off = this.off;
    158         o.triggerEventHandlers = this.trigger;
    159         o.trigger = this.trigger;
    160         o.suspended = {};
    161     }
    162 };
    163
    164 export default JXG.EventEmitter;
    165