mirror of
https://github.com/bigskysoftware/htmx.git
synced 2026-04-17 19:45:04 +00:00
make response handling configurable
This commit is contained in:
64
src/htmx.js
64
src/htmx.js
@@ -75,7 +75,12 @@ return (function () {
|
||||
globalViewTransitions: false,
|
||||
methodsThatUseUrlParams: ["get"],
|
||||
selfRequestsOnly: false,
|
||||
scrollIntoViewOnBoost: true
|
||||
scrollIntoViewOnBoost: true,
|
||||
responseHandling: [
|
||||
{code:"203", swap: false},
|
||||
{code:"[23]..", swap: true},
|
||||
{code:"[45]..", swap: false, error:true},
|
||||
]
|
||||
},
|
||||
parseInterval:parseInterval,
|
||||
_:internalEval,
|
||||
@@ -3388,6 +3393,24 @@ return (function () {
|
||||
}
|
||||
}
|
||||
|
||||
function codeMatches(responseHandlingConfig, status) {
|
||||
var regExp = new RegExp(responseHandlingConfig.code);
|
||||
return regExp.test(status);
|
||||
}
|
||||
|
||||
function resolveResponseHandling(xhr) {
|
||||
for (var i = 0; i < htmx.config.responseHandling.length; i++) {
|
||||
var responseHandlingElement = htmx.config.responseHandling[i];
|
||||
if (codeMatches(responseHandlingElement, xhr.status)) {
|
||||
return responseHandlingElement;
|
||||
}
|
||||
}
|
||||
// no matches, return no swap
|
||||
return {
|
||||
swap: false
|
||||
}
|
||||
}
|
||||
|
||||
function handleAjaxResponse(elt, responseInfo) {
|
||||
var xhr = responseInfo.xhr;
|
||||
var target = responseInfo.target;
|
||||
@@ -3429,27 +3452,45 @@ return (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasHeader(xhr,/HX-Retarget:/i)) {
|
||||
responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget"));
|
||||
}
|
||||
|
||||
var historyUpdate = determineHistoryUpdates(elt, responseInfo);
|
||||
|
||||
// by default htmx only swaps on 200 return codes and does not swap
|
||||
// on 204 'No Content'
|
||||
// this can be ovverriden by responding to the htmx:beforeSwap event and
|
||||
// overriding the detail.shouldSwap property
|
||||
var shouldSwap = xhr.status >= 200 && xhr.status < 400 && xhr.status !== 204;
|
||||
var responseHandling = resolveResponseHandling(xhr);
|
||||
var shouldSwap = responseHandling.swap;
|
||||
var isError = !!responseHandling.error;
|
||||
var ignoreTitle = htmx.config.ignoreTitle || responseHandling.ignoreTitle
|
||||
var selectOverride = responseHandling.select;
|
||||
if (responseHandling.target) {
|
||||
responseInfo.target = querySelectorExt(elt, responseHandling.target);
|
||||
}
|
||||
var swapOverride = etc.swapOverride;
|
||||
if (swapOverride == null && responseHandling.swapOverride) {
|
||||
swapOverride = responseHandling.swapOverride;
|
||||
}
|
||||
|
||||
// response headers override response handling config
|
||||
if (hasHeader(xhr,/HX-Retarget:/i)) {
|
||||
responseInfo.target = getDocument().querySelector(xhr.getResponseHeader("HX-Retarget"));
|
||||
}
|
||||
if (hasHeader(xhr,/HX-Reswap:/i)) {
|
||||
swapOverride = xhr.getResponseHeader("HX-Reswap");
|
||||
}
|
||||
|
||||
var serverResponse = xhr.response;
|
||||
var isError = xhr.status >= 400;
|
||||
var ignoreTitle = htmx.config.ignoreTitle
|
||||
var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle }, responseInfo);
|
||||
var beforeSwapDetails = mergeObjects({shouldSwap: shouldSwap, serverResponse:serverResponse, isError:isError, ignoreTitle:ignoreTitle, selectOverride:selectOverride }, responseInfo);
|
||||
|
||||
if (responseHandling.event && !triggerEvent(target, responseHandling.event, beforeSwapDetails)) return;
|
||||
|
||||
if (!triggerEvent(target, 'htmx:beforeSwap', beforeSwapDetails)) return;
|
||||
|
||||
target = beforeSwapDetails.target; // allow re-targeting
|
||||
serverResponse = beforeSwapDetails.serverResponse; // allow updating content
|
||||
isError = beforeSwapDetails.isError; // allow updating error
|
||||
ignoreTitle = beforeSwapDetails.ignoreTitle; // allow updating ignoring title
|
||||
selectOverride = beforeSwapDetails.selectOverride; //allow updating select override
|
||||
|
||||
responseInfo.target = target; // Make updated target available to response events
|
||||
responseInfo.failed = isError; // Make failed property available to response events
|
||||
@@ -3469,10 +3510,6 @@ return (function () {
|
||||
saveCurrentPageToHistory();
|
||||
}
|
||||
|
||||
var swapOverride = etc.swapOverride;
|
||||
if (hasHeader(xhr,/HX-Reswap:/i)) {
|
||||
swapOverride = xhr.getResponseHeader("HX-Reswap");
|
||||
}
|
||||
var swapSpec = getSwapSpecification(elt, swapOverride);
|
||||
|
||||
if (swapSpec.hasOwnProperty('ignoreTitle')) {
|
||||
@@ -3501,7 +3538,6 @@ return (function () {
|
||||
// safari issue - see https://github.com/microsoft/playwright/issues/5894
|
||||
}
|
||||
|
||||
var selectOverride;
|
||||
if (hasHeader(xhr, /HX-Reselect:/i)) {
|
||||
selectOverride = xhr.getResponseHeader("HX-Reselect");
|
||||
}
|
||||
|
||||
248
test/core/config.js
Normal file
248
test/core/config.js
Normal file
@@ -0,0 +1,248 @@
|
||||
describe("htmx config test", function () {
|
||||
|
||||
beforeEach(function () {
|
||||
this.server = makeServer();
|
||||
clearWorkArea();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
this.server.restore();
|
||||
clearWorkArea();
|
||||
});
|
||||
|
||||
it('swaps normally with no config update', function () {
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
|
||||
responseCode = 200; // 200 should cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("200");
|
||||
|
||||
responseCode = 203; // 203 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
|
||||
responseCode = 300; // 300 should cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("300");
|
||||
|
||||
responseCode = 400; // 400 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
|
||||
responseCode = 500; // 500 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
});
|
||||
|
||||
it('swap all config should swap everything', function () {
|
||||
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = [{code: '...', swap: true}];
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
|
||||
responseCode = 200; // 200 should cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("200");
|
||||
|
||||
responseCode = 203; // 203 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("203");
|
||||
|
||||
responseCode = 300; // 300 should cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("300");
|
||||
|
||||
responseCode = 400; // 400 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("400");
|
||||
|
||||
responseCode = 500; // 500 should not cause a swap by default
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("500");
|
||||
} finally {
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can change the target of a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap: true, target: "#a-div"})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var div = make('<div id="a-div">Another Div</div>')
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
div.innerHTML.should.equal("444");
|
||||
} finally {
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can change the swap type of a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap: true, target: "#a-div", swapOverride:"outerHTML"})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var div = make('<div><div id="a-div">Another Div</div></div>')
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
div.innerHTML.should.equal("444");
|
||||
} finally {
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can change the select of a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap: true, select: ".foo"})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "<div><a class='foo'>" + responseCode + "</a></div>");
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("<a class=\"foo\">444</a>");
|
||||
} finally {
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can change if the title is ignored for a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
var originalTitle = document.title;
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap:true, ignoreTitle:true})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "<title>Should Not Be Set</title>" + responseCode);
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("444");
|
||||
document.title.should.equal(originalTitle);
|
||||
} finally {
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can change if error for a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
var errorDetected = false;
|
||||
var handler = htmx.on('htmx:responseError', function() {
|
||||
errorDetected = true;
|
||||
});
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap:true, error:false})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("444");
|
||||
errorDetected.should.equal(false);
|
||||
} finally {
|
||||
htmx.off('htmx:responseError', handler);
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
it('can trigger an event for a given response code', function () {
|
||||
var originalResponseHandling = htmx.config.responseHandling;
|
||||
var myEventWasTriggered = false;
|
||||
var handler = htmx.on('myEvent', function() {
|
||||
myEventWasTriggered = true;
|
||||
});
|
||||
try {
|
||||
|
||||
htmx.config.responseHandling = originalResponseHandling.slice();
|
||||
htmx.config.responseHandling.unshift({code: "444", swap:false, error:false, event:'myEvent'})
|
||||
|
||||
var responseCode = null;
|
||||
this.server.respondWith("GET", "/test", function (xhr, id) {
|
||||
xhr.respond(responseCode, {"Content-Type": "application/json"}, "" + responseCode);
|
||||
});
|
||||
|
||||
responseCode = 444;
|
||||
var btn = make('<button hx-get="/test">Click Me!</button>')
|
||||
btn.click();
|
||||
this.server.respond();
|
||||
btn.innerHTML.should.equal("Click Me!");
|
||||
myEventWasTriggered.should.equal(true);
|
||||
} finally {
|
||||
htmx.off('htmx:responseError', handler);
|
||||
htmx.config.responseHandling = originalResponseHandling;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -58,6 +58,7 @@
|
||||
<script src="core/internals.js"></script>
|
||||
<script src="core/api.js"></script>
|
||||
<script src="core/ajax.js"></script>
|
||||
<script src="core/config.js"></script>
|
||||
<script src="core/extensions.js"></script>
|
||||
<script src="core/verbs.js"></script>
|
||||
<script src="core/parameters.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user