From 3c2f2451774c51d237de6784aa36c670f8ece35f Mon Sep 17 00:00:00 2001 From: Manuel Mujica Date: Mon, 26 Feb 2018 11:50:14 -0700 Subject: [PATCH] Use documentElement when matching delegated event targets The document object does not implement `Element.matches()` which is used to tell when a selector matches an event delegated to a parent element; using `document.documentElement` fixes the issue. Closes #41 --- can-dom-events-test.js | 14 ++++++++++++-- helpers/-make-delegate-event-tree.js | 11 ++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/can-dom-events-test.js b/can-dom-events-test.js index 3fffd18..33a510c 100644 --- a/can-dom-events-test.js +++ b/can-dom-events-test.js @@ -67,7 +67,7 @@ unit.test('domEvents.addDelegateListener works', function (assert) { var grandparent = document.createElement('div'); var parent = document.createElement('div'); var child = document.createElement('input'); - + grandparent.appendChild(parent); parent.appendChild(child); @@ -88,7 +88,7 @@ unit.test('domEvents.removeDelegateListener works', function (assert) { var grandparent = document.createElement('div'); var parent = document.createElement('div'); var child = document.createElement('input'); - + grandparent.appendChild(parent); parent.appendChild(child); @@ -150,6 +150,16 @@ unit.test("delegate events: blur should work using capture phase", function (ass domEvents.dispatch(child, "blur", false); }); +unit.test('domEvents.addDelegateListener handles document correctly', function (assert) { + var html = document.querySelector('html'); + var handler = function handler() {}; + + domEvents.addDelegateListener(html, 'click', 'input', handler); + domEvents.dispatch(html, 'click'); + domEvents.removeDelegateListener(html, 'click', 'input', handler); + assert.ok(true, 'works'); +}); + require('./helpers/make-event-registry-test'); require('./helpers/add-event-compat-test'); require('./helpers/add-event-jquery-test'); diff --git a/helpers/-make-delegate-event-tree.js b/helpers/-make-delegate-event-tree.js index e9ca2c8..075a47c 100644 --- a/helpers/-make-delegate-event-tree.js +++ b/helpers/-make-delegate-event-tree.js @@ -14,18 +14,23 @@ function makeDelegator (domEvents) { this.events = {}; // {[eventType: string]: Array<(event) -> void>} this.delegated = {}; // {[eventType: string]: (event) -> void} }; - + canReflect.assignSymbols( Delegator.prototype, { "can.setKeyValue": function(eventType, handlersBySelector){ var handler = this.delegated[eventType] = function(ev){ canReflect.each(handlersBySelector, function(handlers, selector){ var cur = ev.target; do { - if (cur.matches(selector)) { + // document does not implement `.matches` but documentElement does + var el = cur === document ? document.documentElement : cur; + if (el.matches(selector)) { handlers.forEach(function(handler){ - handler.call(cur, ev); + handler.call(el, ev); }); } + // since `el` points to `documentElement` when `cur` === document, + // we need to continue using `cur` as the loop pointer, otherwhise + // it will never end as documentElement.parentNode === document cur = cur.parentNode; } while (cur && cur !== ev.currentTarget); });