/*
Copyright 2008-2026
Matthias Ehmann,
Michael Gerhaeuser,
Carsten Miller,
Bianca Valentin,
Alfred Wassermann,
Peter Wilfahrt
This file is part of JSXGraph.
JSXGraph is free software dual licensed under the GNU LGPL or MIT License.
You can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version
OR
* MIT License: https://github.com/jsxgraph/jsxgraph/blob/master/LICENSE.MIT
JSXGraph is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License and
the MIT License along with JSXGraph. If not, see <https://www.gnu.org/licenses/>
and <https://opensource.org/licenses/MIT/>.
*/
/*global JXG: true, define: true*/
/*jslint nomen: true, plusplus: true*/
/**
* @fileoverview In this file the EventEmitter interface is defined.
*/
import JXG from "../jxg.js";
import Type from "./type.js";
/**
* JXG.EventEmitter namespace handles custom event emitters.
* @namespace
*/
JXG.EventEmitter = {
/**
* Holds the registered event handlers.
* @type Object
*/
eventHandlers: {},
/**
* Events can be suspended to prevent endless loops.
* @type Object
*/
suspended: {},
/**
* Triggers all event handlers of this element for a given event.
* @param {Array} event
* @param {Array} args The arguments passed onto the event handler
* @returns Reference to the object.
*/
trigger: function (event, args) {
var i, j, h, evt, len1, len2;
len1 = event.length;
for (j = 0; j < len1; j++) {
evt = this.eventHandlers[event[j]];
if (!this.suspended[event[j]]) {
this.suspended[event[j]] = true;
if (evt) {
len2 = evt.length;
for (i = 0; i < len2; i++) {
h = evt[i];
h.handler.apply(h.context, args);
}
}
this.suspended[event[j]] = false;
}
}
return this;
},
/**
* Register a new event handler. For a list of possible events see documentation
* of the elements and objects implementing
* the {@link EventEmitter} interface.
*
* As of version 1.5.0, it is only possible to access the element via "this" if the event listener
* is supplied as regular JavaScript function and not as arrow function.
*
* @param {String} event
* @param {Function} handler
* @param {Object} [context] The context the handler will be called in, default is the element itself.
* @returns Reference to the object.
*/
on: function (event, handler, context) {
if (!Type.isArray(this.eventHandlers[event])) {
this.eventHandlers[event] = [];
}
context = Type.def(context, this);
this.eventHandlers[event].push({
handler: handler,
context: context
});
return this;
},
/**
* Unregister an event handler.
* @param {String} event
* @param {Function} [handler]
* @returns Reference to the object.
*/
off: function (event, handler) {
var i;
if (!event || !Type.isArray(this.eventHandlers[event])) {
return this;
}
if (handler) {
i = Type.indexOf(this.eventHandlers[event], handler, 'handler');
if (i > -1) {
this.eventHandlers[event].splice(i, 1);
}
if (this.eventHandlers[event].length === 0) {
delete this.eventHandlers[event];
}
} else {
delete this.eventHandlers[event];
}
return this;
},
/**
* Implements the functionality from this interface in the given object.
*
* All objects getting their event handling
* capabilities from this method should document it by adding
* the `on, off, triggerEventHandlers` via the
* borrows tag as methods to their documentation:
*
* @borrows JXG.EventEmitter#on as this.on
* @param {Object} o
*/
eventify: function (o) {
o.eventHandlers = {
clicks: 0 // Needed to handle dblclicks
};
o.on = this.on;
o.off = this.off;
o.triggerEventHandlers = this.trigger;
o.trigger = this.trigger;
o.suspended = {};
}
};
export default JXG.EventEmitter;