Home | History | Annotate | Download | only in cr
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 /**
      6  * @fileoverview This contains an implementation of the EventTarget interface
      7  * as defined by DOM Level 2 Events.
      8  */
      9 
     10 cr.define('cr', function() {
     11 
     12   /**
     13    * Creates a new EventTarget. This class implements the DOM level 2
     14    * EventTarget interface and can be used wherever those are used.
     15    * @constructor
     16    */
     17   function EventTarget() {
     18   }
     19 
     20   EventTarget.prototype = {
     21 
     22     /**
     23      * Adds an event listener to the target.
     24      * @param {string} type The name of the event.
     25      * @param {!Function|{handleEvent:Function}} handler The handler for the
     26      *     event. This is called when the event is dispatched.
     27      */
     28     addEventListener: function(type, handler) {
     29       if (!this.listeners_)
     30         this.listeners_ = Object.create(null);
     31       if (!(type in this.listeners_)) {
     32         this.listeners_[type] = [handler];
     33       } else {
     34         var handlers = this.listeners_[type];
     35         if (handlers.indexOf(handler) < 0)
     36           handlers.push(handler);
     37       }
     38     },
     39 
     40     /**
     41      * Removes an event listener from the target.
     42      * @param {string} type The name of the event.
     43      * @param {!Function|{handleEvent:Function}} handler The handler for the
     44      *     event.
     45      */
     46     removeEventListener: function(type, handler) {
     47       if (!this.listeners_)
     48         return;
     49       if (type in this.listeners_) {
     50         var handlers = this.listeners_[type];
     51         var index = handlers.indexOf(handler);
     52         if (index >= 0) {
     53           // Clean up if this was the last listener.
     54           if (handlers.length == 1)
     55             delete this.listeners_[type];
     56           else
     57             handlers.splice(index, 1);
     58         }
     59       }
     60     },
     61 
     62     /**
     63      * Dispatches an event and calls all the listeners that are listening to
     64      * the type of the event.
     65      * @param {!cr.event.Event} event The event to dispatch.
     66      * @return {boolean} Whether the default action was prevented. If someone
     67      *     calls preventDefault on the event object then this returns false.
     68      */
     69     dispatchEvent: function(event) {
     70       if (!this.listeners_)
     71         return true;
     72 
     73       // Since we are using DOM Event objects we need to override some of the
     74       // properties and methods so that we can emulate this correctly.
     75       var self = this;
     76       event.__defineGetter__('target', function() {
     77         return self;
     78       });
     79       event.preventDefault = function() {
     80         this.returnValue = false;
     81       };
     82 
     83       var type = event.type;
     84       var prevented = 0;
     85       if (type in this.listeners_) {
     86         // Clone to prevent removal during dispatch
     87         var handlers = this.listeners_[type].concat();
     88         for (var i = 0, handler; handler = handlers[i]; i++) {
     89           if (handler.handleEvent)
     90             prevented |= handler.handleEvent.call(handler, event) === false;
     91           else
     92             prevented |= handler.call(this, event) === false;
     93         }
     94       }
     95 
     96       return !prevented && event.returnValue;
     97     }
     98   };
     99 
    100   // Export
    101   return {
    102     EventTarget: EventTarget
    103   };
    104 });
    105