1 /* 2 Copyright 2008-2024 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.js"; 40 import Type from "./type.js"; 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 clicks: 0 // Needed to handle dblclicks 157 }; 158 o.on = this.on; 159 o.off = this.off; 160 o.triggerEventHandlers = this.trigger; 161 o.trigger = this.trigger; 162 o.suspended = {}; 163 } 164 }; 165 166 export default JXG.EventEmitter; 167