From 86febd3efcf9f50b83426f6fc7935d4a74ce26b7 Mon Sep 17 00:00:00 2001 From: "Stephane Angel (Twidi)" Date: Fri, 12 Jun 2020 00:49:07 +0200 Subject: [PATCH] Extension.handleSwap: trigger events for extensions defined on parents If an element is replaced by an extension in `handleSwap`, the events (`afterSwap.htmx` and `afterSettle.htmx`) were not received by the `onLoad` method of extensions defined on parents of the target, because theses extensions were retrieved after the replacement, and so it was not possible to get through the parents, the target not being in the dom anymore. This commits loads the extensions for the target and save them in `eventDetail` before doing the swap, so they are accessible in `triggerEvent`, and passed to `withExtensions` that use this list if passed (else load them). A new test is added that fails without the updates in `htmx.js`. --- src/htmx.js | 8 ++++---- test/ext/index.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++ test/index.html | 2 ++ 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 test/ext/index.js diff --git a/src/htmx.js b/src/htmx.js index fc53fd54..16372a67 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -954,8 +954,8 @@ return (function () { return eventName === "processedNode.htmx" } - function withExtensions(elt, toDo) { - forEach(getExtensions(elt), function(extension){ + function withExtensions(elt, toDo, extensions) { + forEach(typeof extensions === 'undefined' ? getExtensions(elt) : extensions, function(extension){ try { toDo(extension); } catch (e) { @@ -988,7 +988,7 @@ return (function () { var eventResult = elt.dispatchEvent(event); withExtensions(elt, function (extension) { eventResult = eventResult && (extension.onEvent(eventName, event) !== false) - }); + }, detail.extensions); return eventResult; } @@ -1407,7 +1407,7 @@ return (function () { } } - var eventDetail = {xhr: xhr, target: target}; + var eventDetail = {xhr: xhr, target: target, extensions: getExtensions(elt)}; xhr.onload = function () { try { if (!triggerEvent(elt, 'beforeOnLoad.htmx', eventDetail)) return; diff --git a/test/ext/index.js b/test/ext/index.js new file mode 100644 index 00000000..45842093 --- /dev/null +++ b/test/ext/index.js @@ -0,0 +1,50 @@ +describe("default extensions behavior", function() { + + var loadCalls, afterSwapCalls, afterSettleCalls; + + beforeEach(function () { + loadCalls = afterSwapCalls = afterSettleCalls = 0; + this.server = makeServer(); + clearWorkArea(); + + htmx.defineExtension("ext-testswap", { + onEvent : function(name, evt) { + if (name === "load.htmx") { + loadCalls++; + } + if (name === "afterSwap.htmx") { + afterSwapCalls++; + } + if (name === "afterSettle.htmx") { + afterSettleCalls++; + } + }, + handleSwap: function (swapStyle, target, fragment, settleInfo) { + // simple outerHTML replacement for tests + var parentEl = target.parentElement; + parentEl.removeChild(target); + parentEl.appendChild(fragment) + return true; + } + + }); + + }); + + afterEach(function () { + this.server.restore(); + clearWorkArea(); + htmx.removeExtension("ext-testswap"); + }); + + it('handleSwap: afterSwap and afterSettle triggered if extension defined on parent', function () { + this.server.respondWith("GET", "/test", ''); + var div = make('
'); + var btn = div.firstChild; + btn.click() + this.server.respond(); + afterSwapCalls.should.equal(1); + afterSettleCalls.should.equal(1); + loadCalls.should.equal(0); // load.htmlx event on new added button is not triggered + }); +}); diff --git a/test/index.html b/test/index.html index 13fc2bd0..2f99cdf0 100644 --- a/test/index.html +++ b/test/index.html @@ -83,6 +83,8 @@ + +