1 goog.provide('lime.events.EventDispatcher');
  2 
  3 goog.require('lime.events.Event');
  4 
  5 /**
  6  * EventDispatcher object. Deals with event handlers
  7  * @param {lime.Director} director Director object.
  8  * @constructor
  9  */
 10 lime.events.EventDispatcher = function(director) {
 11     this.director = director;
 12     this.handlers = {};
 13     this.swallows = {};
 14 
 15 };
 16 
 17 /**
 18  * Register the event listener for node
 19  * @param {lime.Node} node Node that responds to events.
 20  * @param {string} eventType type of event to listen.
 21  */
 22 lime.events.EventDispatcher.prototype.register = function(node, eventType) {
 23     if (!goog.isDef(this.handlers[eventType])) {
 24         this.handlers[eventType] = [node];
 25         //base element switch here because safari fires touchend on
 26         //dom tree changes otherwise
 27         goog.events.listen(eventType.substring(0, 5) == 'touch' && node!=this.director ?
 28             document : (eventType.substring(0, 3) == 'key' ?
 29             window : this.director.domElement.parentNode), eventType,
 30             this, false, this);
 31     }
 32     else {
 33         if (!goog.array.contains(this.handlers[eventType], node)) {
 34             this.handlers[eventType].push(node);
 35             this.handlers[eventType].sort(lime.Node.compareNode);
 36         }
 37     }
 38 };
 39 
 40 /**
 41  * Release the event listener for node
 42  * @param {lime.Node} node Node that responds to events.
 43  * @param {string} eventType type of event to release.
 44  */
 45 lime.events.EventDispatcher.prototype.release = function(node, eventType) {
 46     if (goog.isDef(this.handlers[eventType])) {
 47          goog.array.remove(this.handlers[eventType], node);
 48          if (!this.handlers[eventType].length) {
 49              goog.events.unlisten(this.director.domElement.parentNode,
 50                  eventType, this, false, this);
 51             delete this.handlers[eventType];
 52          }
 53     }
 54 };
 55 
 56 /**
 57  * Update order of handler nodes. Called on tree changes.
 58  * @param {lime.Node} node Node that has changed.
 59  */
 60 lime.events.EventDispatcher.prototype.updateDispatchOrder = function(node){
 61     for(var eventType in this.handlers){
 62         var handlers = this.handlers[eventType];
 63         if(goog.array.contains(handlers,node)){
 64             handlers.sort(lime.Node.compareNode);
 65         }
 66     }
 67 }
 68 
 69 /**
 70  * Setup swallow rule for an event. Swallow means that next events from
 71  * same interaction will go straight to the handler
 72  * @param {lime.events.Event} e Event.
 73  * @param {string} type Event type.
 74  * @param {function(lime.events.Event)} handler Function to call.
 75  */
 76 lime.events.EventDispatcher.prototype.swallow = function(e, type, handler) {
 77    /*
 78    // don't remember why this check was needed
 79    if (e.type != 'mousedown' && e.type != 'touchstart' &&
 80         e.type != 'touchmove' && e.type != 'keydown') return;*/
 81     var id = e.identifier;
 82     if (!goog.isDef(this.swallows[id])) {
 83         this.swallows[id] = [];
 84     }
 85     this.swallows[id].push([e.targetObject, type, handler]);
 86     //console.log('listen');
 87     goog.events.listen(e.targetObject, type, goog.nullFunction);
 88 };
 89 
 90 /**
 91  * Handle DOM event
 92  * @param {Event} e Event.
 93  */
 94 lime.events.EventDispatcher.prototype.handleEvent = function(e) {
 95 
 96     if (!goog.isDef(this.handlers[e.type])) return;
 97 
 98     var handlers = this.handlers[e.type].slice(), didhandle = false;
 99 
100     var touchIndex = 0, doBreak = 0;
101 
102     while (!doBreak) {
103 
104     var ee = new lime.events.Event(this);
105     ee.type = e.type;
106     ee.event = e;
107 
108     if (e.type.substring(0, 5) == 'touch') {
109         var touch = e.getBrowserEvent().changedTouches[touchIndex];
110         ee.screenPosition = new goog.math.Coordinate(touch.pageX, touch.pageY);
111         ee.identifier = touch.identifier;
112         touchIndex++;
113 
114         if (touchIndex >= e.getBrowserEvent().changedTouches.length) {
115             doBreak = 1;
116         }
117     }
118     else {
119         ee.screenPosition = new goog.math.Coordinate(e.clientX, e.clientY);
120         doBreak = 1;
121     }
122 
123     if (goog.isDef(this.swallows[ee.identifier])) {
124         var s = this.swallows[ee.identifier];
125 
126         for (var i = 0; i < s.length; i++) {
127             if (s[i][1] == e.type || (goog.isArray(s[i][1]) &&
128                     goog.array.contains(s[i][1], e.type))) {
129 
130                 var handler = s[i][0];
131                 ee.targetObject = handler;
132                 ee.position = handler.screenToLocal(ee.screenPosition);
133                 s[i][2].call(handler, ee);
134                 didhandle = true;
135             }
136         }
137         //handler.dispatchEvent(ee);
138 
139         if (e.type == 'touchend' || e.type == 'touchcancel' ||
140             e.type == 'mouseup' || e.type == 'keyup') {
141             delete ee.targetObject;
142             ee.release();
143         }
144     }
145     else {
146         for (var i = 0; i < handlers.length; i++) {
147 
148             var handler = handlers[i];
149 
150             if (this.director.getCurrentScene() != handler.getScene() &&
151                 handler != this.director) continue;
152 
153             if (handler.getHidden() || !handler.inTree_) continue;
154 
155             ee.targetObject = handler;
156 
157             if (handler.hitTest(ee) || e.type.substring(0, 3) == 'key') {
158 
159                 ee.targetObject = handler;
160                 handler.dispatchEvent(ee);
161                 didhandle = true;
162 
163                 if (ee.event.propagationStopped_) break;
164             }
165 
166         }
167 
168     }
169 
170     }
171 
172     if (didhandle)
173     e.preventDefault();
174 
175 };
176