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      * @namespace
 51      */
 52     JXG.EventEmitter = {
 53         /**
 54          * Holds the registered event handlers.
 55          * @name JXG.EventEmitter#eventHandlers
 56          * @type Object
 57          */
 58         eventHandlers: {},
 59 
 60         /**
 61          * Events can be suspended to prevent endless loops.
 62          * @name JXG.EventEmitter#suspended
 63          * @type Object
 64          */
 65         suspended: {},
 66 
 67         /**
 68          * Triggers all event handlers of this element for a given event.
 69          * @name JXG.EventEmitter#triggerEventHandlers
 70          * @function
 71          * @param {Array} event
 72          * @param {Array} args The arguments passed onto the event handler
 73          * @returns Reference to the object.
 74          */
 75         trigger: function (event, args) {
 76             var i, j, h, evt, len1, len2;
 77 
 78             len1 = event.length;
 79             for (j = 0; j < len1; j++) {
 80                 evt = this.eventHandlers[event[j]];
 81 
 82                 if (!this.suspended[event[j]]) {
 83                     this.suspended[event[j]] = true;
 84 
 85                     if (evt) {
 86                         len2 = evt.length;
 87 
 88                         for (i = 0; i < len2; i++) {
 89                             h = evt[i];
 90                             h.handler.apply(h.context, args);
 91                         }
 92                     }
 93 
 94                     this.suspended[event[j]] = false;
 95                 }
 96             }
 97 
 98             return this;
 99         },
100 
101         /**
102          * Register a new event handler. For a list of possible events see documentation of the elements and objects implementing
103          * the {@link EventEmitter} interface.
104          * @name JXG.EventEmitter#on
105          * @function
106          * @param {String} event
107          * @param {Function} handler
108          * @param {Object} [context] The context the handler will be called in, default is the element itself.
109          * @returns Reference to the object.
110          */
111         on: function (event, handler, context) {
112             if (!Type.isArray(this.eventHandlers[event])) {
113                 this.eventHandlers[event] = [];
114             }
115 
116             context = Type.def(context, this);
117 
118             this.eventHandlers[event].push({
119                 handler: handler,
120                 context: context
121             });
122 
123             return this;
124         },
125 
126         /**
127          * Unregister an event handler.
128          * @name JXG.EventEmitter#off
129          * @function
130          * @param {String} event
131          * @param {Function} [handler]
132          * @returns Reference to the object.
133          */
134         off: function (event, handler) {
135             var i;
136 
137             if (!event || !Type.isArray(this.eventHandlers[event])) {
138                 return this;
139             }
140 
141             if (handler) {
142                 i = Type.indexOf(this.eventHandlers[event], handler, 'handler');
143                 if (i > -1) {
144                     this.eventHandlers[event].splice(i, 1);
145                 }
146 
147                 if (this.eventHandlers[event].length === 0) {
148                     delete this.eventHandlers[event];
149                 }
150             } else {
151                 delete this.eventHandlers[event];
152             }
153 
154             return this;
155         },
156 
157         /**
158          * @description Implements the functionality from this interface in the given object. All objects getting their event handling
159          * capabilities from this method should document it by adding the <tt>on, off, triggerEventHandlers</tt> via the
160          * borrows tag as methods to their documentation: <pre>@borrows JXG.EventEmitter#on as this.on</pre>
161          * @name JXG.EventEmitter#eventify
162          * @function
163          * @param {Object} o
164          */
165         eventify: function (o) {
166             o.eventHandlers = {};
167             o.on = this.on;
168             o.off = this.off;
169             o.triggerEventHandlers = this.trigger;
170             o.trigger = this.trigger;
171             o.suspended = {};
172         }
173     };
174 
175     return JXG.EventEmitter;
176 });
177