      1 /*
      2     Copyright 2008-2013
      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