turbo-rails 1.3.1 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/app/assets/javascripts/turbo.js +145 -60
- data/app/assets/javascripts/turbo.min.js +5 -5
- data/app/assets/javascripts/turbo.min.js.map +1 -1
- data/app/controllers/turbo/native/navigation.rb +3 -1
- data/app/helpers/turbo/streams/action_helper.rb +4 -4
- data/app/javascript/turbo/cable_stream_source_element.js +4 -1
- data/app/javascript/turbo/fetch_requests.js +34 -3
- data/app/models/concerns/turbo/broadcastable.rb +7 -7
- data/lib/turbo/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecb315ac4b0462119b892a555ba5942ac1de84d8bdc565e31d0e166ac244a6c1
|
4
|
+
data.tar.gz: a2e2033e73b26803e9b87962ac451b825257e1f052cb86cef013e0b8eb16bbcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d830701cc6b05ceb930ed1d873998849d870f7b25701ccc3d5cede6f5659eb107e175a46465963a23bf1239fd3aeb798f105155047324644446305e1fea34d71
|
7
|
+
data.tar.gz: 0bb9370f532eb74a8230320c1aed5ac1d4e5f434873d017454ffe1c005daa124f413ffe1ee11df1cb49f325f85fcd417b9db6bd6909b234d87032d56dcb99284
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ Turbo reinvents the old HTML technique of frames without any of the drawbacks th
|
|
32
32
|
|
33
33
|
It also makes it dead easy to carve a single page into smaller pieces that can all live on their own cache timeline. While the bulk of the page might easily be cached between users, a small personalized toolbar perhaps cannot. With Turbo::Frames, you can designate the toolbar as a frame, which will be **lazy-loaded automatically** by the publicly-cached root page. This means simpler pages, easier caching schemes with fewer dependent keys, and all without needing to write a lick of custom JavaScript.
|
34
34
|
|
35
|
-
This gem provides a `turbo_frame_tag` helper to create those
|
35
|
+
This gem provides a `turbo_frame_tag` helper to create those frames.
|
36
36
|
|
37
37
|
For instance:
|
38
38
|
```erb
|
@@ -282,10 +282,6 @@ class FetchResponse {
|
|
282
282
|
}
|
283
283
|
}
|
284
284
|
|
285
|
-
function isAction(action) {
|
286
|
-
return action == "advance" || action == "replace" || action == "restore";
|
287
|
-
}
|
288
|
-
|
289
285
|
function activateScriptElement(element) {
|
290
286
|
if (element.getAttribute("data-turbo-eval") == "false") {
|
291
287
|
return element;
|
@@ -318,6 +314,7 @@ function dispatch(eventName, {target: target, cancelable: cancelable, detail: de
|
|
318
314
|
const event = new CustomEvent(eventName, {
|
319
315
|
cancelable: cancelable,
|
320
316
|
bubbles: true,
|
317
|
+
composed: true,
|
321
318
|
detail: detail
|
322
319
|
});
|
323
320
|
if (target && target.isConnected) {
|
@@ -431,6 +428,10 @@ function getHistoryMethodForAction(action) {
|
|
431
428
|
}
|
432
429
|
}
|
433
430
|
|
431
|
+
function isAction(action) {
|
432
|
+
return action == "advance" || action == "replace" || action == "restore";
|
433
|
+
}
|
434
|
+
|
434
435
|
function getVisitAction(...elements) {
|
435
436
|
const action = getAttribute("data-turbo-action", ...elements);
|
436
437
|
return isAction(action) ? action : null;
|
@@ -456,6 +457,13 @@ function setMetaContent(name, content) {
|
|
456
457
|
return element;
|
457
458
|
}
|
458
459
|
|
460
|
+
function findClosestRecursively(element, selector) {
|
461
|
+
var _a;
|
462
|
+
if (element instanceof Element) {
|
463
|
+
return element.closest(selector) || findClosestRecursively(element.assignedSlot || ((_a = element.getRootNode()) === null || _a === void 0 ? void 0 : _a.host), selector);
|
464
|
+
}
|
465
|
+
}
|
466
|
+
|
459
467
|
var FetchMethod;
|
460
468
|
|
461
469
|
(function(FetchMethod) {
|
@@ -509,9 +517,8 @@ class FetchRequest {
|
|
509
517
|
this.abortController.abort();
|
510
518
|
}
|
511
519
|
async perform() {
|
512
|
-
var _a, _b;
|
513
520
|
const {fetchOptions: fetchOptions} = this;
|
514
|
-
|
521
|
+
this.delegate.prepareRequest(this);
|
515
522
|
await this.allowRequestToBeIntercepted(fetchOptions);
|
516
523
|
try {
|
517
524
|
this.delegate.requestStarted(this);
|
@@ -753,11 +760,11 @@ class FormSubmission {
|
|
753
760
|
return true;
|
754
761
|
}
|
755
762
|
}
|
756
|
-
|
763
|
+
prepareRequest(request) {
|
757
764
|
if (!request.isIdempotent) {
|
758
765
|
const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
|
759
766
|
if (token) {
|
760
|
-
headers["X-CSRF-Token"] = token;
|
767
|
+
request.headers["X-CSRF-Token"] = token;
|
761
768
|
}
|
762
769
|
}
|
763
770
|
if (this.requestAcceptsTurboStreamResponse(request)) {
|
@@ -960,11 +967,15 @@ function submissionDoesNotDismissDialog(form, submitter) {
|
|
960
967
|
}
|
961
968
|
|
962
969
|
function submissionDoesNotTargetIFrame(form, submitter) {
|
963
|
-
|
964
|
-
|
965
|
-
|
970
|
+
if ((submitter === null || submitter === void 0 ? void 0 : submitter.hasAttribute("formtarget")) || form.hasAttribute("target")) {
|
971
|
+
const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
|
972
|
+
for (const element of document.getElementsByName(target)) {
|
973
|
+
if (element instanceof HTMLIFrameElement) return false;
|
974
|
+
}
|
975
|
+
return true;
|
976
|
+
} else {
|
977
|
+
return true;
|
966
978
|
}
|
967
|
-
return true;
|
968
979
|
}
|
969
980
|
|
970
981
|
class View {
|
@@ -1153,9 +1164,7 @@ class LinkClickObserver {
|
|
1153
1164
|
return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
|
1154
1165
|
}
|
1155
1166
|
findLinkFromClickTarget(target) {
|
1156
|
-
|
1157
|
-
return target.closest("a[href]:not([target^=_]):not([download])");
|
1158
|
-
}
|
1167
|
+
return findClosestRecursively(target, "a[href]:not([target^=_]):not([download])");
|
1159
1168
|
}
|
1160
1169
|
getLocationForLink(link) {
|
1161
1170
|
return expandURL(link.getAttribute("href") || "");
|
@@ -1163,10 +1172,14 @@ class LinkClickObserver {
|
|
1163
1172
|
}
|
1164
1173
|
|
1165
1174
|
function doesNotTargetIFrame(anchor) {
|
1166
|
-
|
1167
|
-
|
1175
|
+
if (anchor.hasAttribute("target")) {
|
1176
|
+
for (const element of document.getElementsByName(anchor.target)) {
|
1177
|
+
if (element instanceof HTMLIFrameElement) return false;
|
1178
|
+
}
|
1179
|
+
return true;
|
1180
|
+
} else {
|
1181
|
+
return true;
|
1168
1182
|
}
|
1169
|
-
return true;
|
1170
1183
|
}
|
1171
1184
|
|
1172
1185
|
class FormLinkClickObserver {
|
@@ -1184,16 +1197,26 @@ class FormLinkClickObserver {
|
|
1184
1197
|
return this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) && link.hasAttribute("data-turbo-method");
|
1185
1198
|
}
|
1186
1199
|
followedLinkToLocation(link, location) {
|
1187
|
-
const action = location.href;
|
1188
1200
|
const form = document.createElement("form");
|
1201
|
+
const type = "hidden";
|
1202
|
+
for (const [name, value] of location.searchParams) {
|
1203
|
+
form.append(Object.assign(document.createElement("input"), {
|
1204
|
+
type: type,
|
1205
|
+
name: name,
|
1206
|
+
value: value
|
1207
|
+
}));
|
1208
|
+
}
|
1209
|
+
const action = Object.assign(location, {
|
1210
|
+
search: ""
|
1211
|
+
});
|
1189
1212
|
form.setAttribute("data-turbo", "true");
|
1190
|
-
form.setAttribute("action", action);
|
1213
|
+
form.setAttribute("action", action.href);
|
1191
1214
|
form.setAttribute("hidden", "");
|
1192
1215
|
const method = link.getAttribute("data-turbo-method");
|
1193
1216
|
if (method) form.setAttribute("method", method);
|
1194
1217
|
const turboFrame = link.getAttribute("data-turbo-frame");
|
1195
1218
|
if (turboFrame) form.setAttribute("data-turbo-frame", turboFrame);
|
1196
|
-
const turboAction = link
|
1219
|
+
const turboAction = getVisitAction(link);
|
1197
1220
|
if (turboAction) form.setAttribute("data-turbo-action", turboAction);
|
1198
1221
|
const turboConfirm = link.getAttribute("data-turbo-confirm");
|
1199
1222
|
if (turboConfirm) form.setAttribute("data-turbo-confirm", turboConfirm);
|
@@ -1213,10 +1236,10 @@ class Bardo {
|
|
1213
1236
|
this.delegate = delegate;
|
1214
1237
|
this.permanentElementMap = permanentElementMap;
|
1215
1238
|
}
|
1216
|
-
static preservingPermanentElements(delegate, permanentElementMap, callback) {
|
1239
|
+
static async preservingPermanentElements(delegate, permanentElementMap, callback) {
|
1217
1240
|
const bardo = new this(delegate, permanentElementMap);
|
1218
1241
|
bardo.enter();
|
1219
|
-
callback();
|
1242
|
+
await callback();
|
1220
1243
|
bardo.leave();
|
1221
1244
|
}
|
1222
1245
|
enter() {
|
@@ -1289,8 +1312,8 @@ class Renderer {
|
|
1289
1312
|
delete this.resolvingFunctions;
|
1290
1313
|
}
|
1291
1314
|
}
|
1292
|
-
preservingPermanentElements(callback) {
|
1293
|
-
Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
|
1315
|
+
async preservingPermanentElements(callback) {
|
1316
|
+
await Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
|
1294
1317
|
}
|
1295
1318
|
focusFirstAutofocusableElement() {
|
1296
1319
|
const element = this.connectedSnapshot.firstAutofocusableElement;
|
@@ -1873,7 +1896,9 @@ class Visit {
|
|
1873
1896
|
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
1874
1897
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
1875
1898
|
action: "replace",
|
1876
|
-
response: this.response
|
1899
|
+
response: this.response,
|
1900
|
+
shouldCacheSnapshot: false,
|
1901
|
+
willRender: false
|
1877
1902
|
});
|
1878
1903
|
this.followedRedirect = true;
|
1879
1904
|
}
|
@@ -1883,11 +1908,12 @@ class Visit {
|
|
1883
1908
|
this.render((async () => {
|
1884
1909
|
this.cacheSnapshot();
|
1885
1910
|
this.performScroll();
|
1911
|
+
this.changeHistory();
|
1886
1912
|
this.adapter.visitRendered(this);
|
1887
1913
|
}));
|
1888
1914
|
}
|
1889
1915
|
}
|
1890
|
-
|
1916
|
+
prepareRequest(request) {
|
1891
1917
|
if (this.acceptsStreamResponse) {
|
1892
1918
|
request.acceptResponseType(StreamMessage.contentType);
|
1893
1919
|
}
|
@@ -2296,7 +2322,6 @@ class Navigator {
|
|
2296
2322
|
}
|
2297
2323
|
}
|
2298
2324
|
startVisit(locatable, restorationIdentifier, options = {}) {
|
2299
|
-
this.lastVisit = this.currentVisit;
|
2300
2325
|
this.stop();
|
2301
2326
|
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({
|
2302
2327
|
referrer: this.location
|
@@ -2383,12 +2408,10 @@ class Navigator {
|
|
2383
2408
|
this.delegate.visitCompleted(visit);
|
2384
2409
|
}
|
2385
2410
|
locationWithActionIsSamePage(location, action) {
|
2386
|
-
var _a;
|
2387
2411
|
const anchor = getAnchor(location);
|
2388
|
-
const
|
2389
|
-
const currentAnchor = getAnchor(lastLocation);
|
2412
|
+
const currentAnchor = getAnchor(this.view.lastRenderedLocation);
|
2390
2413
|
const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
2391
|
-
return action !== "replace" && getRequestURL(location) === getRequestURL(
|
2414
|
+
return action !== "replace" && getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) && (isRestorationToTop || anchor != null && anchor !== currentAnchor);
|
2392
2415
|
}
|
2393
2416
|
visitScrolledToSamePageLocation(oldURL, newURL) {
|
2394
2417
|
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
@@ -2399,10 +2422,8 @@ class Navigator {
|
|
2399
2422
|
get restorationIdentifier() {
|
2400
2423
|
return this.history.restorationIdentifier;
|
2401
2424
|
}
|
2402
|
-
getActionForFormSubmission(
|
2403
|
-
|
2404
|
-
const action = getAttribute("data-turbo-action", submitter, formElement);
|
2405
|
-
return isAction(action) ? action : "advance";
|
2425
|
+
getActionForFormSubmission({submitter: submitter, formElement: formElement}) {
|
2426
|
+
return getVisitAction(submitter, formElement) || "advance";
|
2406
2427
|
}
|
2407
2428
|
}
|
2408
2429
|
|
@@ -2650,7 +2671,7 @@ class PageRenderer extends Renderer {
|
|
2650
2671
|
}
|
2651
2672
|
async render() {
|
2652
2673
|
if (this.willRender) {
|
2653
|
-
this.replaceBody();
|
2674
|
+
await this.replaceBody();
|
2654
2675
|
}
|
2655
2676
|
}
|
2656
2677
|
finishRendering() {
|
@@ -2669,16 +2690,16 @@ class PageRenderer extends Renderer {
|
|
2669
2690
|
return this.newSnapshot.element;
|
2670
2691
|
}
|
2671
2692
|
async mergeHead() {
|
2693
|
+
const mergedHeadElements = this.mergeProvisionalElements();
|
2672
2694
|
const newStylesheetElements = this.copyNewHeadStylesheetElements();
|
2673
2695
|
this.copyNewHeadScriptElements();
|
2674
|
-
|
2675
|
-
this.copyNewHeadProvisionalElements();
|
2696
|
+
await mergedHeadElements;
|
2676
2697
|
await newStylesheetElements;
|
2677
2698
|
}
|
2678
|
-
replaceBody() {
|
2679
|
-
this.preservingPermanentElements((() => {
|
2699
|
+
async replaceBody() {
|
2700
|
+
await this.preservingPermanentElements((async () => {
|
2680
2701
|
this.activateNewBody();
|
2681
|
-
this.assignNewBody();
|
2702
|
+
await this.assignNewBody();
|
2682
2703
|
}));
|
2683
2704
|
}
|
2684
2705
|
get trackedElementsAreIdentical() {
|
@@ -2697,6 +2718,35 @@ class PageRenderer extends Renderer {
|
|
2697
2718
|
document.head.appendChild(activateScriptElement(element));
|
2698
2719
|
}
|
2699
2720
|
}
|
2721
|
+
async mergeProvisionalElements() {
|
2722
|
+
const newHeadElements = [ ...this.newHeadProvisionalElements ];
|
2723
|
+
for (const element of this.currentHeadProvisionalElements) {
|
2724
|
+
if (!this.isCurrentElementInElementList(element, newHeadElements)) {
|
2725
|
+
document.head.removeChild(element);
|
2726
|
+
}
|
2727
|
+
}
|
2728
|
+
for (const element of newHeadElements) {
|
2729
|
+
document.head.appendChild(element);
|
2730
|
+
}
|
2731
|
+
}
|
2732
|
+
isCurrentElementInElementList(element, elementList) {
|
2733
|
+
for (const [index, newElement] of elementList.entries()) {
|
2734
|
+
if (element.tagName == "TITLE") {
|
2735
|
+
if (newElement.tagName != "TITLE") {
|
2736
|
+
continue;
|
2737
|
+
}
|
2738
|
+
if (element.innerHTML == newElement.innerHTML) {
|
2739
|
+
elementList.splice(index, 1);
|
2740
|
+
return true;
|
2741
|
+
}
|
2742
|
+
}
|
2743
|
+
if (newElement.isEqualNode(element)) {
|
2744
|
+
elementList.splice(index, 1);
|
2745
|
+
return true;
|
2746
|
+
}
|
2747
|
+
}
|
2748
|
+
return false;
|
2749
|
+
}
|
2700
2750
|
removeCurrentHeadProvisionalElements() {
|
2701
2751
|
for (const element of this.currentHeadProvisionalElements) {
|
2702
2752
|
document.head.removeChild(element);
|
@@ -2717,8 +2767,8 @@ class PageRenderer extends Renderer {
|
|
2717
2767
|
inertScriptElement.replaceWith(activatedScriptElement);
|
2718
2768
|
}
|
2719
2769
|
}
|
2720
|
-
assignNewBody() {
|
2721
|
-
this.renderElement(this.currentElement, this.newElement);
|
2770
|
+
async assignNewBody() {
|
2771
|
+
await this.renderElement(this.currentElement, this.newElement);
|
2722
2772
|
}
|
2723
2773
|
get newHeadStylesheetElements() {
|
2724
2774
|
return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
@@ -3152,8 +3202,8 @@ class Session {
|
|
3152
3202
|
}
|
3153
3203
|
}
|
3154
3204
|
elementIsNavigatable(element) {
|
3155
|
-
const container = element
|
3156
|
-
const withinFrame = element
|
3205
|
+
const container = findClosestRecursively(element, "[data-turbo]");
|
3206
|
+
const withinFrame = findClosestRecursively(element, "turbo-frame");
|
3157
3207
|
if (this.drive || withinFrame) {
|
3158
3208
|
if (container) {
|
3159
3209
|
return container.getAttribute("data-turbo") != "false";
|
@@ -3169,8 +3219,7 @@ class Session {
|
|
3169
3219
|
}
|
3170
3220
|
}
|
3171
3221
|
getActionForLink(link) {
|
3172
|
-
|
3173
|
-
return isAction(action) ? action : "advance";
|
3222
|
+
return getVisitAction(link) || "advance";
|
3174
3223
|
}
|
3175
3224
|
get snapshot() {
|
3176
3225
|
return this.view.snapshot;
|
@@ -3238,7 +3287,10 @@ const StreamActions = {
|
|
3238
3287
|
this.targetElements.forEach((e => e.replaceWith(this.templateContent)));
|
3239
3288
|
},
|
3240
3289
|
update() {
|
3241
|
-
this.targetElements.forEach((
|
3290
|
+
this.targetElements.forEach((targetElement => {
|
3291
|
+
targetElement.innerHTML = "";
|
3292
|
+
targetElement.append(this.templateContent);
|
3293
|
+
}));
|
3242
3294
|
}
|
3243
3295
|
};
|
3244
3296
|
|
@@ -3430,7 +3482,8 @@ class FrameController {
|
|
3430
3482
|
this.fetchResponseLoaded = () => {};
|
3431
3483
|
}
|
3432
3484
|
}
|
3433
|
-
elementAppearedInViewport(
|
3485
|
+
elementAppearedInViewport(element) {
|
3486
|
+
this.proposeVisitIfNavigatedWithAction(element, element);
|
3434
3487
|
this.loadSourceURL();
|
3435
3488
|
}
|
3436
3489
|
willSubmitFormLinkToLocation(link) {
|
@@ -3455,12 +3508,12 @@ class FrameController {
|
|
3455
3508
|
}
|
3456
3509
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
3457
3510
|
const {fetchRequest: fetchRequest} = this.formSubmission;
|
3458
|
-
this.
|
3511
|
+
this.prepareRequest(fetchRequest);
|
3459
3512
|
this.formSubmission.start();
|
3460
3513
|
}
|
3461
|
-
|
3514
|
+
prepareRequest(request) {
|
3462
3515
|
var _a;
|
3463
|
-
headers["Turbo-Frame"] = this.id;
|
3516
|
+
request.headers["Turbo-Frame"] = this.id;
|
3464
3517
|
if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute("data-turbo-stream")) {
|
3465
3518
|
request.acceptResponseType(StreamMessage.contentType);
|
3466
3519
|
}
|
@@ -3542,7 +3595,6 @@ class FrameController {
|
|
3542
3595
|
}
|
3543
3596
|
navigateFrame(element, url, submitter) {
|
3544
3597
|
const frame = this.findFrameElement(element, submitter);
|
3545
|
-
this.pageSnapshot = PageSnapshot.fromElement(frame).clone();
|
3546
3598
|
frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
|
3547
3599
|
this.withCurrentNavigationElement(element, (() => {
|
3548
3600
|
frame.src = url;
|
@@ -3550,7 +3602,8 @@ class FrameController {
|
|
3550
3602
|
}
|
3551
3603
|
proposeVisitIfNavigatedWithAction(frame, element, submitter) {
|
3552
3604
|
this.action = getVisitAction(submitter, element, frame);
|
3553
|
-
if (
|
3605
|
+
if (this.action) {
|
3606
|
+
const pageSnapshot = PageSnapshot.fromElement(frame).clone();
|
3554
3607
|
const {visitCachedSnapshot: visitCachedSnapshot} = frame.delegate;
|
3555
3608
|
frame.delegate.fetchResponseLoaded = fetchResponse => {
|
3556
3609
|
if (frame.src) {
|
@@ -3567,7 +3620,7 @@ class FrameController {
|
|
3567
3620
|
willRender: false,
|
3568
3621
|
updateHistory: false,
|
3569
3622
|
restorationIdentifier: this.restorationIdentifier,
|
3570
|
-
snapshot:
|
3623
|
+
snapshot: pageSnapshot
|
3571
3624
|
};
|
3572
3625
|
if (this.action) options.action = this.action;
|
3573
3626
|
session.visit(frame.src, options);
|
@@ -4021,18 +4074,21 @@ class TurboCableStreamSourceElement extends HTMLElement {
|
|
4021
4074
|
}
|
4022
4075
|
}
|
4023
4076
|
|
4024
|
-
customElements.
|
4077
|
+
if (customElements.get("turbo-cable-stream-source") === undefined) {
|
4078
|
+
customElements.define("turbo-cable-stream-source", TurboCableStreamSourceElement);
|
4079
|
+
}
|
4025
4080
|
|
4026
4081
|
function encodeMethodIntoRequestBody(event) {
|
4027
4082
|
if (event.target instanceof HTMLFormElement) {
|
4028
4083
|
const {target: form, detail: {fetchOptions: fetchOptions}} = event;
|
4029
4084
|
form.addEventListener("turbo:submit-start", (({detail: {formSubmission: {submitter: submitter}}}) => {
|
4030
|
-
const
|
4085
|
+
const body = isBodyInit(fetchOptions.body) ? fetchOptions.body : new URLSearchParams;
|
4086
|
+
const method = determineFetchMethod(submitter, body, form);
|
4031
4087
|
if (!/get/i.test(method)) {
|
4032
4088
|
if (/post/i.test(method)) {
|
4033
|
-
|
4089
|
+
body.delete("_method");
|
4034
4090
|
} else {
|
4035
|
-
|
4091
|
+
body.set("_method", method);
|
4036
4092
|
}
|
4037
4093
|
fetchOptions.method = "post";
|
4038
4094
|
}
|
@@ -4042,6 +4098,35 @@ function encodeMethodIntoRequestBody(event) {
|
|
4042
4098
|
}
|
4043
4099
|
}
|
4044
4100
|
|
4101
|
+
function determineFetchMethod(submitter, body, form) {
|
4102
|
+
const formMethod = determineFormMethod(submitter);
|
4103
|
+
const overrideMethod = body.get("_method");
|
4104
|
+
const method = form.getAttribute("method") || "get";
|
4105
|
+
if (typeof formMethod == "string") {
|
4106
|
+
return formMethod;
|
4107
|
+
} else if (typeof overrideMethod == "string") {
|
4108
|
+
return overrideMethod;
|
4109
|
+
} else {
|
4110
|
+
return method;
|
4111
|
+
}
|
4112
|
+
}
|
4113
|
+
|
4114
|
+
function determineFormMethod(submitter) {
|
4115
|
+
if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {
|
4116
|
+
if (submitter.hasAttribute("formmethod")) {
|
4117
|
+
return submitter.formMethod;
|
4118
|
+
} else {
|
4119
|
+
return null;
|
4120
|
+
}
|
4121
|
+
} else {
|
4122
|
+
return null;
|
4123
|
+
}
|
4124
|
+
}
|
4125
|
+
|
4126
|
+
function isBodyInit(body) {
|
4127
|
+
return body instanceof FormData || body instanceof URLSearchParams;
|
4128
|
+
}
|
4129
|
+
|
4045
4130
|
addEventListener("turbo:before-fetch-request", encodeMethodIntoRequestBody);
|
4046
4131
|
|
4047
4132
|
var adapters = {
|