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