Merge pull request #94 from twidi/handle-events-and-content-after-handleSwap-extensions

Handle events and content after `handleSwap` in extensions
This commit is contained in:
chg20 2020-06-17 18:05:45 -07:00 committed by GitHub
commit 6c8930028c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 8 deletions

View File

@ -5,7 +5,7 @@ htmx.defineExtension('morphdom-swap', {
handleSwap: function (swapStyle, target, fragment) {
if (swapStyle === 'morphdom') {
morphdom(target, fragment.outerHTML);
return true;
return [target]; // let htmx handle the new content
}
}
});

View File

@ -417,7 +417,7 @@ return (function () {
while(fragment.childNodes.length > 0){
var child = fragment.firstChild;
parentNode.insertBefore(child, insertBefore);
if (child.nodeType !== Node.TEXT_NODE) {
if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) {
settleInfo.tasks.push(makeAjaxLoadTask(child));
}
}
@ -519,7 +519,17 @@ return (function () {
for (var i = 0; i < extensions.length; i++) {
var ext = extensions[i];
try {
if (ext.handleSwap(swapStyle, target, fragment, settleInfo)) {
var newElements = ext.handleSwap(swapStyle, target, fragment, settleInfo);
if (newElements) {
if (typeof newElements.length !== 'undefined') {
// if handleSwap returns an array (like) of elements, we handle them
for (var j = 0; j < newElements.length; j++) {
var child = newElements[j];
if (child.nodeType !== Node.TEXT_NODE && child.nodeType !== Node.COMMENT_NODE) {
settleInfo.tasks.push(makeAjaxLoadTask(child));
}
}
}
return;
}
} catch (e) {
@ -973,8 +983,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) {
@ -1007,7 +1017,7 @@ return (function () {
var eventResult = elt.dispatchEvent(event);
withExtensions(elt, function (extension) {
eventResult = eventResult && (extension.onEvent(eventName, event) !== false)
});
}, detail.extensions);
return eventResult;
}
@ -1426,7 +1436,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;

71
test/ext/index.js Normal file
View File

@ -0,0 +1,71 @@
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.push(evt.detail.elt);
}
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);
return [parentEl.appendChild(fragment)]; // return the newly added element
}
});
});
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", '<button>Clicked!</button>');
var div = make('<div hx-ext="ext-testswap"><button hx-get="/test" hx-swap="testswap">Click Me!</button></div>');
var btn = div.firstChild;
btn.click()
this.server.respond();
afterSwapCalls.should.equal(1);
afterSettleCalls.should.equal(1);
loadCalls.length.should.equal(1);
loadCalls[0].textContent.should.equal('Clicked!'); // the new button is loaded
});
it('handleSwap: new content is handled by htmx', function() {
this.server.respondWith("GET", "/test", '<button id="test-ext-testswap">Clicked!<span hx-get="/test-inner" hx-trigger="load"></span></button>');
this.server.respondWith("GET", "/test-inner", 'Loaded!');
make('<div hx-ext="ext-testswap"><button hx-get="/test" hx-swap="testswap">Click Me!</button></div>').querySelector('button').click();
this.server.respond(); // call /test via button trigger=click
var btn = byId('test-ext-testswap');
btn.textContent.should.equal('Clicked!');
afterSwapCalls.should.equal(1);
loadCalls.length.should.equal(1);
loadCalls[0].textContent.should.equal('Clicked!'); // the new button is loaded
this.server.respond(); // call /test-inner via span trigger=load
btn.textContent.should.equal("Clicked!Loaded!");
afterSwapCalls.should.equal(2);
loadCalls.length.should.equal(2);
loadCalls[1].textContent.should.equal('Loaded!'); // the new span is loaded
});
});

View File

@ -18,4 +18,14 @@ describe("morphdom-swap extension", function() {
btn.innerHTML.should.equal("Clicked!");
});
});
it('works with htmx elements in new content', function () {
this.server.respondWith("GET", "/test", '<button>Clicked!<span hx-get="/test-inner" hx-trigger="load" hx-swap="morphdom"></span></button>');
this.server.respondWith("GET", "/test-inner", 'Loaded!');
var btn = make('<div hx-ext="morphdom-swap"><button hx-get="/test" hx-swap="morphdom">Click Me!</button></div>').querySelector('button');
btn.click();
this.server.respond(); // call /test via button trigger=click
this.server.respond(); // call /test-inner via span trigger=load
btn.innerHTML.should.equal("Clicked!Loaded!");
});
});

View File

@ -90,6 +90,8 @@
</script>
<!-- extension tests -->
<script src="ext/index.js"></script>
<script src="../src/ext/method-override.js"></script>
<script src="ext/method-override.js"></script>