-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes #153 - Bubbling event listeners are attached too late
Attach bubbling event listeners lazily when initializing widgets for the first time.
- Loading branch information
1 parent
0491bb6
commit a03498c
Showing
3 changed files
with
83 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
var _addEventListener = require('./addEventListener'); | ||
var updateManager = require('./update-manager'); | ||
|
||
var attachBubbleEventListeners = function() { | ||
var body = document.body; | ||
// Here's where we handle event delegation using our own mechanism | ||
// for delegating events. For each event that we have white-listed | ||
// as supporting bubble, we will attach a listener to the root | ||
// document.body element. When we get notified of a triggered event, | ||
// we again walk up the tree starting at the target associated | ||
// with the event to find any mappings for event. Each mapping | ||
// is from a DOM event type to a method of a widget. | ||
require('./bubble').forEach(function addBubbleHandler(eventType) { | ||
_addEventListener(body, eventType, function(event) { | ||
var propagationStopped = false; | ||
|
||
// Monkey-patch to fix #97 | ||
var oldStopPropagation = event.stopPropagation; | ||
|
||
event.stopPropagation = function() { | ||
oldStopPropagation.call(event); | ||
propagationStopped = true; | ||
}; | ||
|
||
updateManager.batchUpdate(function() { | ||
var curNode = event.target; | ||
if (!curNode) { | ||
return; | ||
} | ||
|
||
// Search up the tree looking DOM events mapped to target | ||
// widget methods | ||
var attrName = 'data-w-on' + eventType; | ||
var targetMethod; | ||
var targetWidget; | ||
|
||
// Attributes will have the following form: | ||
// w-on<event_type>="<target_method>|<widget_id>" | ||
|
||
do { | ||
if ((targetMethod = curNode.getAttribute(attrName))) { | ||
var separator = targetMethod.lastIndexOf('|'); | ||
var targetWidgetId = targetMethod.substring(separator+1); | ||
targetWidget = document.getElementById(targetWidgetId).__widget; | ||
|
||
if (!targetWidget) { | ||
throw new Error('Widget not found: ' + targetWidgetId); | ||
} | ||
targetMethod = targetMethod.substring(0, separator); | ||
|
||
var targetFunc = targetWidget[targetMethod]; | ||
if (!targetFunc) { | ||
throw new Error('Method not found on widget ' + targetWidget.id + ': ' + targetMethod); | ||
} | ||
|
||
// Invoke the widget method | ||
targetWidget[targetMethod](event, curNode); | ||
if (propagationStopped) { | ||
break; | ||
} | ||
} | ||
} while((curNode = curNode.parentNode) && curNode.getAttribute); | ||
}); | ||
}); | ||
}); | ||
}; | ||
|
||
exports.init = function() { | ||
if (attachBubbleEventListeners) { | ||
// Only attach event listeners once... | ||
attachBubbleEventListeners(); | ||
attachBubbleEventListeners = null; // This is a one time thing | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters