@hotwired/turbo 7.0.0 → 7.1.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -0
- package/README.md +0 -2
- package/dist/turbo.es2017-esm.js +283 -89
- package/dist/turbo.es2017-umd.js +284 -89
- package/dist/types/core/drive/form_submission.d.ts +3 -0
- package/dist/types/core/drive/page_view.d.ts +2 -2
- package/dist/types/core/drive/visit.d.ts +6 -0
- package/dist/types/core/frames/frame_controller.d.ts +8 -3
- package/dist/types/core/frames/frame_redirector.d.ts +1 -0
- package/dist/types/core/index.d.ts +1 -0
- package/dist/types/core/renderer.d.ts +2 -1
- package/dist/types/core/session.d.ts +1 -1
- package/dist/types/core/url.d.ts +2 -0
- package/dist/types/elements/frame_element.d.ts +2 -0
- package/dist/types/polyfills/index.d.ts +1 -0
- package/dist/types/tests/functional/drive_disabled_tests.d.ts +2 -0
- package/dist/types/tests/functional/drive_tests.d.ts +1 -0
- package/dist/types/tests/functional/form_submission_tests.d.ts +34 -3
- package/dist/types/tests/functional/frame_tests.d.ts +23 -1
- package/dist/types/tests/functional/navigation_tests.d.ts +4 -2
- package/dist/types/tests/functional/visit_tests.d.ts +1 -0
- package/dist/types/util.d.ts +3 -0
- package/package.json +7 -2
- package/dist/turbo.es2017-esm.js.map +0 -1
- package/dist/turbo.es2017-umd.js.map +0 -1
- package/dist/turbo.es5-umd.js +0 -3954
- package/dist/turbo.es5-umd.js.map +0 -1
package/dist/turbo.es2017-esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Turbo 7.0.
|
|
2
|
+
Turbo 7.1.0-rc.3
|
|
3
3
|
Copyright © 2021 Basecamp, LLC
|
|
4
4
|
*/
|
|
5
5
|
(function () {
|
|
@@ -20,6 +20,58 @@ Copyright © 2021 Basecamp, LLC
|
|
|
20
20
|
Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
|
|
21
21
|
})();
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* The MIT License (MIT)
|
|
25
|
+
*
|
|
26
|
+
* Copyright (c) 2019 Javan Makhmali
|
|
27
|
+
*
|
|
28
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
29
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
30
|
+
* in the Software without restriction, including without limitation the rights
|
|
31
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
32
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
33
|
+
* furnished to do so, subject to the following conditions:
|
|
34
|
+
*
|
|
35
|
+
* The above copyright notice and this permission notice shall be included in
|
|
36
|
+
* all copies or substantial portions of the Software.
|
|
37
|
+
*
|
|
38
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
39
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
40
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
41
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
42
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
43
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
44
|
+
* THE SOFTWARE.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
(function(prototype) {
|
|
48
|
+
if (typeof prototype.requestSubmit == "function") return
|
|
49
|
+
|
|
50
|
+
prototype.requestSubmit = function(submitter) {
|
|
51
|
+
if (submitter) {
|
|
52
|
+
validateSubmitter(submitter, this);
|
|
53
|
+
submitter.click();
|
|
54
|
+
} else {
|
|
55
|
+
submitter = document.createElement("input");
|
|
56
|
+
submitter.type = "submit";
|
|
57
|
+
submitter.hidden = true;
|
|
58
|
+
this.appendChild(submitter);
|
|
59
|
+
submitter.click();
|
|
60
|
+
this.removeChild(submitter);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function validateSubmitter(submitter, form) {
|
|
65
|
+
submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
|
|
66
|
+
submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
|
|
67
|
+
submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function raise(errorConstructor, message, name) {
|
|
71
|
+
throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name)
|
|
72
|
+
}
|
|
73
|
+
})(HTMLFormElement.prototype);
|
|
74
|
+
|
|
23
75
|
const submittersByForm = new WeakMap;
|
|
24
76
|
function findSubmitterFromClickTarget(target) {
|
|
25
77
|
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
@@ -33,12 +85,20 @@ function clickCaptured(event) {
|
|
|
33
85
|
}
|
|
34
86
|
}
|
|
35
87
|
(function () {
|
|
36
|
-
if ("SubmitEvent" in window)
|
|
37
|
-
return;
|
|
38
88
|
if ("submitter" in Event.prototype)
|
|
39
89
|
return;
|
|
90
|
+
let prototype;
|
|
91
|
+
if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
|
|
92
|
+
prototype = window.SubmitEvent.prototype;
|
|
93
|
+
}
|
|
94
|
+
else if ("SubmitEvent" in window) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
prototype = window.Event.prototype;
|
|
99
|
+
}
|
|
40
100
|
addEventListener("click", clickCaptured, true);
|
|
41
|
-
Object.defineProperty(
|
|
101
|
+
Object.defineProperty(prototype, "submitter", {
|
|
42
102
|
get() {
|
|
43
103
|
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
44
104
|
return submittersByForm.get(this.target);
|
|
@@ -157,6 +217,10 @@ function getAnchor(url) {
|
|
|
157
217
|
return anchorMatch[1];
|
|
158
218
|
}
|
|
159
219
|
}
|
|
220
|
+
function getAction(form, submitter) {
|
|
221
|
+
const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formaction")) || form.getAttribute("action") || form.action;
|
|
222
|
+
return expandURL(action);
|
|
223
|
+
}
|
|
160
224
|
function getExtension(url) {
|
|
161
225
|
return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
|
162
226
|
}
|
|
@@ -167,6 +231,9 @@ function isPrefixedBy(baseURL, url) {
|
|
|
167
231
|
const prefix = getPrefix(url);
|
|
168
232
|
return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
|
|
169
233
|
}
|
|
234
|
+
function locationIsVisitable(location, rootLocation) {
|
|
235
|
+
return isPrefixedBy(location, rootLocation) && isHTML(location);
|
|
236
|
+
}
|
|
170
237
|
function getRequestURL(url) {
|
|
171
238
|
const anchor = getAnchor(url);
|
|
172
239
|
return anchor != null
|
|
@@ -289,6 +356,29 @@ function uuid() {
|
|
|
289
356
|
}
|
|
290
357
|
}).join("");
|
|
291
358
|
}
|
|
359
|
+
function getAttribute(attributeName, ...elements) {
|
|
360
|
+
for (const value of elements.map(element => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
|
361
|
+
if (typeof value == "string")
|
|
362
|
+
return value;
|
|
363
|
+
}
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
function markAsBusy(...elements) {
|
|
367
|
+
for (const element of elements) {
|
|
368
|
+
if (element.localName == "turbo-frame") {
|
|
369
|
+
element.setAttribute("busy", "");
|
|
370
|
+
}
|
|
371
|
+
element.setAttribute("aria-busy", "true");
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function clearBusyState(...elements) {
|
|
375
|
+
for (const element of elements) {
|
|
376
|
+
if (element.localName == "turbo-frame") {
|
|
377
|
+
element.removeAttribute("busy");
|
|
378
|
+
}
|
|
379
|
+
element.removeAttribute("aria-busy");
|
|
380
|
+
}
|
|
381
|
+
}
|
|
292
382
|
|
|
293
383
|
var FetchMethod;
|
|
294
384
|
(function (FetchMethod) {
|
|
@@ -314,13 +404,10 @@ class FetchRequest {
|
|
|
314
404
|
this.delegate = delegate;
|
|
315
405
|
this.method = method;
|
|
316
406
|
this.headers = this.defaultHeaders;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
this.body = body;
|
|
322
|
-
this.url = location;
|
|
323
|
-
}
|
|
407
|
+
this.body = body;
|
|
408
|
+
this.url = this.isIdempotent ?
|
|
409
|
+
mergeFormDataEntries(new URL(location.href), this.entries) :
|
|
410
|
+
location;
|
|
324
411
|
this.target = target;
|
|
325
412
|
}
|
|
326
413
|
get location() {
|
|
@@ -376,7 +463,7 @@ class FetchRequest {
|
|
|
376
463
|
credentials: "same-origin",
|
|
377
464
|
headers: this.headers,
|
|
378
465
|
redirect: "follow",
|
|
379
|
-
body: this.body,
|
|
466
|
+
body: this.isIdempotent ? null : this.body,
|
|
380
467
|
signal: this.abortSignal,
|
|
381
468
|
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
|
|
382
469
|
};
|
|
@@ -398,7 +485,7 @@ class FetchRequest {
|
|
|
398
485
|
cancelable: true,
|
|
399
486
|
detail: {
|
|
400
487
|
fetchOptions,
|
|
401
|
-
url: this.url
|
|
488
|
+
url: this.url,
|
|
402
489
|
resume: this.resolveRequestPromise
|
|
403
490
|
},
|
|
404
491
|
target: this.target
|
|
@@ -408,18 +495,13 @@ class FetchRequest {
|
|
|
408
495
|
}
|
|
409
496
|
}
|
|
410
497
|
function mergeFormDataEntries(url, entries) {
|
|
411
|
-
const
|
|
498
|
+
const searchParams = new URLSearchParams;
|
|
412
499
|
for (const [name, value] of entries) {
|
|
413
500
|
if (value instanceof File)
|
|
414
501
|
continue;
|
|
415
|
-
|
|
416
|
-
currentSearchParams.delete(name);
|
|
417
|
-
url.searchParams.set(name, value);
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
url.searchParams.append(name, value);
|
|
421
|
-
}
|
|
502
|
+
searchParams.append(name, value);
|
|
422
503
|
}
|
|
504
|
+
url.search = searchParams.toString();
|
|
423
505
|
return url;
|
|
424
506
|
}
|
|
425
507
|
|
|
@@ -518,6 +600,9 @@ class FormSubmission {
|
|
|
518
600
|
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
|
519
601
|
this.mustRedirect = mustRedirect;
|
|
520
602
|
}
|
|
603
|
+
static confirmMethod(message, element) {
|
|
604
|
+
return confirm(message);
|
|
605
|
+
}
|
|
521
606
|
get method() {
|
|
522
607
|
var _a;
|
|
523
608
|
const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
|
|
@@ -551,8 +636,20 @@ class FormSubmission {
|
|
|
551
636
|
return entries.concat(typeof value == "string" ? [[name, value]] : []);
|
|
552
637
|
}, []);
|
|
553
638
|
}
|
|
639
|
+
get confirmationMessage() {
|
|
640
|
+
return this.formElement.getAttribute("data-turbo-confirm");
|
|
641
|
+
}
|
|
642
|
+
get needsConfirmation() {
|
|
643
|
+
return this.confirmationMessage !== null;
|
|
644
|
+
}
|
|
554
645
|
async start() {
|
|
555
646
|
const { initialized, requesting } = FormSubmissionState;
|
|
647
|
+
if (this.needsConfirmation) {
|
|
648
|
+
const answer = FormSubmission.confirmMethod(this.confirmationMessage, this.formElement);
|
|
649
|
+
if (!answer) {
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
556
653
|
if (this.state == initialized) {
|
|
557
654
|
this.state = requesting;
|
|
558
655
|
return this.fetchRequest.perform();
|
|
@@ -576,7 +673,9 @@ class FormSubmission {
|
|
|
576
673
|
}
|
|
577
674
|
}
|
|
578
675
|
requestStarted(request) {
|
|
676
|
+
var _a;
|
|
579
677
|
this.state = FormSubmissionState.waiting;
|
|
678
|
+
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
|
|
580
679
|
dispatch("turbo:submit-start", { target: this.formElement, detail: { formSubmission: this } });
|
|
581
680
|
this.delegate.formSubmissionStarted(this);
|
|
582
681
|
}
|
|
@@ -606,7 +705,9 @@ class FormSubmission {
|
|
|
606
705
|
this.delegate.formSubmissionErrored(this, error);
|
|
607
706
|
}
|
|
608
707
|
requestFinished(request) {
|
|
708
|
+
var _a;
|
|
609
709
|
this.state = FormSubmissionState.stopped;
|
|
710
|
+
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
|
|
610
711
|
dispatch("turbo:submit-end", { target: this.formElement, detail: Object.assign({ formSubmission: this }, this.result) });
|
|
611
712
|
this.delegate.formSubmissionFinished(this);
|
|
612
713
|
}
|
|
@@ -682,10 +783,11 @@ class Snapshot {
|
|
|
682
783
|
class FormInterceptor {
|
|
683
784
|
constructor(delegate, element) {
|
|
684
785
|
this.submitBubbled = ((event) => {
|
|
685
|
-
|
|
686
|
-
|
|
786
|
+
const form = event.target;
|
|
787
|
+
if (!event.defaultPrevented && form instanceof HTMLFormElement && form.closest("turbo-frame, html") == this.element) {
|
|
687
788
|
const submitter = event.submitter || undefined;
|
|
688
|
-
|
|
789
|
+
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.method;
|
|
790
|
+
if (method != "dialog" && this.delegate.shouldInterceptFormSubmission(form, submitter)) {
|
|
689
791
|
event.preventDefault();
|
|
690
792
|
event.stopImmediatePropagation();
|
|
691
793
|
this.delegate.formSubmissionIntercepted(form, submitter);
|
|
@@ -900,10 +1002,11 @@ function createPlaceholderForPermanentElement(permanentElement) {
|
|
|
900
1002
|
}
|
|
901
1003
|
|
|
902
1004
|
class Renderer {
|
|
903
|
-
constructor(currentSnapshot, newSnapshot, isPreview) {
|
|
1005
|
+
constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {
|
|
904
1006
|
this.currentSnapshot = currentSnapshot;
|
|
905
1007
|
this.newSnapshot = newSnapshot;
|
|
906
1008
|
this.isPreview = isPreview;
|
|
1009
|
+
this.willRender = willRender;
|
|
907
1010
|
this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject });
|
|
908
1011
|
}
|
|
909
1012
|
get shouldRender() {
|
|
@@ -1279,7 +1382,9 @@ var VisitState;
|
|
|
1279
1382
|
})(VisitState || (VisitState = {}));
|
|
1280
1383
|
const defaultOptions = {
|
|
1281
1384
|
action: "advance",
|
|
1282
|
-
historyChanged: false
|
|
1385
|
+
historyChanged: false,
|
|
1386
|
+
visitCachedSnapshot: () => { },
|
|
1387
|
+
willRender: true,
|
|
1283
1388
|
};
|
|
1284
1389
|
var SystemStatusCode;
|
|
1285
1390
|
(function (SystemStatusCode) {
|
|
@@ -1299,13 +1404,16 @@ class Visit {
|
|
|
1299
1404
|
this.delegate = delegate;
|
|
1300
1405
|
this.location = location;
|
|
1301
1406
|
this.restorationIdentifier = restorationIdentifier || uuid();
|
|
1302
|
-
const { action, historyChanged, referrer, snapshotHTML, response } = Object.assign(Object.assign({}, defaultOptions), options);
|
|
1407
|
+
const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender } = Object.assign(Object.assign({}, defaultOptions), options);
|
|
1303
1408
|
this.action = action;
|
|
1304
1409
|
this.historyChanged = historyChanged;
|
|
1305
1410
|
this.referrer = referrer;
|
|
1306
1411
|
this.snapshotHTML = snapshotHTML;
|
|
1307
1412
|
this.response = response;
|
|
1308
1413
|
this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
|
1414
|
+
this.visitCachedSnapshot = visitCachedSnapshot;
|
|
1415
|
+
this.willRender = willRender;
|
|
1416
|
+
this.scrolled = !willRender;
|
|
1309
1417
|
}
|
|
1310
1418
|
get adapter() {
|
|
1311
1419
|
return this.delegate.adapter;
|
|
@@ -1407,7 +1515,7 @@ class Visit {
|
|
|
1407
1515
|
if (this.view.renderPromise)
|
|
1408
1516
|
await this.view.renderPromise;
|
|
1409
1517
|
if (isSuccessful(statusCode) && responseHTML != null) {
|
|
1410
|
-
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML));
|
|
1518
|
+
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender);
|
|
1411
1519
|
this.adapter.visitRendered(this);
|
|
1412
1520
|
this.complete();
|
|
1413
1521
|
}
|
|
@@ -1447,7 +1555,7 @@ class Visit {
|
|
|
1447
1555
|
else {
|
|
1448
1556
|
if (this.view.renderPromise)
|
|
1449
1557
|
await this.view.renderPromise;
|
|
1450
|
-
await this.view.renderPage(snapshot, isPreview);
|
|
1558
|
+
await this.view.renderPage(snapshot, isPreview, this.willRender);
|
|
1451
1559
|
this.adapter.visitRendered(this);
|
|
1452
1560
|
if (!isPreview) {
|
|
1453
1561
|
this.complete();
|
|
@@ -1457,7 +1565,8 @@ class Visit {
|
|
|
1457
1565
|
}
|
|
1458
1566
|
}
|
|
1459
1567
|
followRedirect() {
|
|
1460
|
-
|
|
1568
|
+
var _a;
|
|
1569
|
+
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
|
1461
1570
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
|
1462
1571
|
action: 'replace',
|
|
1463
1572
|
response: this.response
|
|
@@ -1480,25 +1589,27 @@ class Visit {
|
|
|
1480
1589
|
}
|
|
1481
1590
|
async requestSucceededWithResponse(request, response) {
|
|
1482
1591
|
const responseHTML = await response.responseHTML;
|
|
1592
|
+
const { redirected, statusCode } = response;
|
|
1483
1593
|
if (responseHTML == undefined) {
|
|
1484
|
-
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch });
|
|
1594
|
+
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch, redirected });
|
|
1485
1595
|
}
|
|
1486
1596
|
else {
|
|
1487
1597
|
this.redirectedToLocation = response.redirected ? response.location : undefined;
|
|
1488
|
-
this.recordResponse({ statusCode:
|
|
1598
|
+
this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
|
1489
1599
|
}
|
|
1490
1600
|
}
|
|
1491
1601
|
async requestFailedWithResponse(request, response) {
|
|
1492
1602
|
const responseHTML = await response.responseHTML;
|
|
1603
|
+
const { redirected, statusCode } = response;
|
|
1493
1604
|
if (responseHTML == undefined) {
|
|
1494
|
-
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch });
|
|
1605
|
+
this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch, redirected });
|
|
1495
1606
|
}
|
|
1496
1607
|
else {
|
|
1497
|
-
this.recordResponse({ statusCode:
|
|
1608
|
+
this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
|
1498
1609
|
}
|
|
1499
1610
|
}
|
|
1500
1611
|
requestErrored(request, error) {
|
|
1501
|
-
this.recordResponse({ statusCode: SystemStatusCode.networkFailure });
|
|
1612
|
+
this.recordResponse({ statusCode: SystemStatusCode.networkFailure, redirected: false });
|
|
1502
1613
|
}
|
|
1503
1614
|
requestFinished() {
|
|
1504
1615
|
this.finishRequest();
|
|
@@ -1555,12 +1666,12 @@ class Visit {
|
|
|
1555
1666
|
return !this.hasCachedSnapshot();
|
|
1556
1667
|
}
|
|
1557
1668
|
else {
|
|
1558
|
-
return
|
|
1669
|
+
return this.willRender;
|
|
1559
1670
|
}
|
|
1560
1671
|
}
|
|
1561
1672
|
cacheSnapshot() {
|
|
1562
1673
|
if (!this.snapshotCached) {
|
|
1563
|
-
this.view.cacheSnapshot();
|
|
1674
|
+
this.view.cacheSnapshot().then(snapshot => snapshot && this.visitCachedSnapshot(snapshot));
|
|
1564
1675
|
this.snapshotCached = true;
|
|
1565
1676
|
}
|
|
1566
1677
|
}
|
|
@@ -1596,10 +1707,10 @@ class BrowserAdapter {
|
|
|
1596
1707
|
this.navigator.startVisit(location, uuid(), options);
|
|
1597
1708
|
}
|
|
1598
1709
|
visitStarted(visit) {
|
|
1710
|
+
visit.loadCachedSnapshot();
|
|
1599
1711
|
visit.issueRequest();
|
|
1600
1712
|
visit.changeHistory();
|
|
1601
1713
|
visit.goToSamePageAnchor();
|
|
1602
|
-
visit.loadCachedSnapshot();
|
|
1603
1714
|
}
|
|
1604
1715
|
visitRequestStarted(visit) {
|
|
1605
1716
|
this.progressBar.setValue(0);
|
|
@@ -1710,7 +1821,7 @@ class FormSubmitObserver {
|
|
|
1710
1821
|
const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
|
1711
1822
|
const submitter = event.submitter || undefined;
|
|
1712
1823
|
if (form) {
|
|
1713
|
-
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.method;
|
|
1824
|
+
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
|
|
1714
1825
|
if (method != "dialog" && this.delegate.willSubmitForm(form, submitter)) {
|
|
1715
1826
|
event.preventDefault();
|
|
1716
1827
|
this.delegate.formSubmitted(form, submitter);
|
|
@@ -1754,12 +1865,11 @@ class FrameRedirector {
|
|
|
1754
1865
|
linkClickIntercepted(element, url) {
|
|
1755
1866
|
const frame = this.findFrameElement(element);
|
|
1756
1867
|
if (frame) {
|
|
1757
|
-
frame.
|
|
1758
|
-
frame.src = url;
|
|
1868
|
+
frame.delegate.linkClickIntercepted(element, url);
|
|
1759
1869
|
}
|
|
1760
1870
|
}
|
|
1761
1871
|
shouldInterceptFormSubmission(element, submitter) {
|
|
1762
|
-
return this.
|
|
1872
|
+
return this.shouldSubmit(element, submitter);
|
|
1763
1873
|
}
|
|
1764
1874
|
formSubmissionIntercepted(element, submitter) {
|
|
1765
1875
|
const frame = this.findFrameElement(element, submitter);
|
|
@@ -1768,6 +1878,13 @@ class FrameRedirector {
|
|
|
1768
1878
|
frame.delegate.formSubmissionIntercepted(element, submitter);
|
|
1769
1879
|
}
|
|
1770
1880
|
}
|
|
1881
|
+
shouldSubmit(form, submitter) {
|
|
1882
|
+
var _a;
|
|
1883
|
+
const action = getAction(form, submitter);
|
|
1884
|
+
const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
|
1885
|
+
const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/");
|
|
1886
|
+
return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
|
|
1887
|
+
}
|
|
1771
1888
|
shouldRedirect(element, submitter) {
|
|
1772
1889
|
const frame = this.findFrameElement(element, submitter);
|
|
1773
1890
|
return frame ? frame != element.closest("turbo-frame") : false;
|
|
@@ -1925,7 +2042,12 @@ class Navigator {
|
|
|
1925
2042
|
}
|
|
1926
2043
|
proposeVisit(location, options = {}) {
|
|
1927
2044
|
if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {
|
|
1928
|
-
|
|
2045
|
+
if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {
|
|
2046
|
+
this.delegate.visitProposedToLocation(location, options);
|
|
2047
|
+
}
|
|
2048
|
+
else {
|
|
2049
|
+
window.location.href = location.toString();
|
|
2050
|
+
}
|
|
1929
2051
|
}
|
|
1930
2052
|
}
|
|
1931
2053
|
startVisit(locatable, restorationIdentifier, options = {}) {
|
|
@@ -1936,12 +2058,7 @@ class Navigator {
|
|
|
1936
2058
|
submitForm(form, submitter) {
|
|
1937
2059
|
this.stop();
|
|
1938
2060
|
this.formSubmission = new FormSubmission(this, form, submitter, true);
|
|
1939
|
-
|
|
1940
|
-
this.proposeVisit(this.formSubmission.fetchRequest.url, { action: this.getActionForFormSubmission(this.formSubmission) });
|
|
1941
|
-
}
|
|
1942
|
-
else {
|
|
1943
|
-
this.formSubmission.start();
|
|
1944
|
-
}
|
|
2061
|
+
this.formSubmission.start();
|
|
1945
2062
|
}
|
|
1946
2063
|
stop() {
|
|
1947
2064
|
if (this.formSubmission) {
|
|
@@ -1974,8 +2091,9 @@ class Navigator {
|
|
|
1974
2091
|
if (formSubmission.method != FetchMethod.get) {
|
|
1975
2092
|
this.view.clearSnapshotCache();
|
|
1976
2093
|
}
|
|
1977
|
-
const { statusCode } = fetchResponse;
|
|
1978
|
-
const
|
|
2094
|
+
const { statusCode, redirected } = fetchResponse;
|
|
2095
|
+
const action = this.getActionForFormSubmission(formSubmission);
|
|
2096
|
+
const visitOptions = { action, response: { statusCode, responseHTML, redirected } };
|
|
1979
2097
|
this.proposeVisit(fetchResponse.location, visitOptions);
|
|
1980
2098
|
}
|
|
1981
2099
|
}
|
|
@@ -2027,7 +2145,7 @@ class Navigator {
|
|
|
2027
2145
|
}
|
|
2028
2146
|
getActionForFormSubmission(formSubmission) {
|
|
2029
2147
|
const { formElement, submitter } = formSubmission;
|
|
2030
|
-
const action =
|
|
2148
|
+
const action = getAttribute("data-turbo-action", submitter, formElement);
|
|
2031
2149
|
return isAction(action) ? action : "advance";
|
|
2032
2150
|
}
|
|
2033
2151
|
}
|
|
@@ -2221,7 +2339,9 @@ class PageRenderer extends Renderer {
|
|
|
2221
2339
|
this.mergeHead();
|
|
2222
2340
|
}
|
|
2223
2341
|
async render() {
|
|
2224
|
-
this.
|
|
2342
|
+
if (this.willRender) {
|
|
2343
|
+
this.replaceBody();
|
|
2344
|
+
}
|
|
2225
2345
|
}
|
|
2226
2346
|
finishRendering() {
|
|
2227
2347
|
super.finishRendering();
|
|
@@ -2359,8 +2479,8 @@ class PageView extends View {
|
|
|
2359
2479
|
this.snapshotCache = new SnapshotCache(10);
|
|
2360
2480
|
this.lastRenderedLocation = new URL(location.href);
|
|
2361
2481
|
}
|
|
2362
|
-
renderPage(snapshot, isPreview = false) {
|
|
2363
|
-
const renderer = new PageRenderer(this.snapshot, snapshot, isPreview);
|
|
2482
|
+
renderPage(snapshot, isPreview = false, willRender = true) {
|
|
2483
|
+
const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender);
|
|
2364
2484
|
return this.render(renderer);
|
|
2365
2485
|
}
|
|
2366
2486
|
renderError(snapshot) {
|
|
@@ -2375,7 +2495,9 @@ class PageView extends View {
|
|
|
2375
2495
|
this.delegate.viewWillCacheSnapshot();
|
|
2376
2496
|
const { snapshot, lastRenderedLocation: location } = this;
|
|
2377
2497
|
await nextEventLoopTick();
|
|
2378
|
-
|
|
2498
|
+
const cachedSnapshot = snapshot.clone();
|
|
2499
|
+
this.snapshotCache.put(location, cachedSnapshot);
|
|
2500
|
+
return cachedSnapshot;
|
|
2379
2501
|
}
|
|
2380
2502
|
}
|
|
2381
2503
|
getCachedSnapshotForLocation(location) {
|
|
@@ -2477,7 +2599,7 @@ class Session {
|
|
|
2477
2599
|
}
|
|
2478
2600
|
willFollowLinkToLocation(link, location) {
|
|
2479
2601
|
return this.elementDriveEnabled(link)
|
|
2480
|
-
&&
|
|
2602
|
+
&& locationIsVisitable(location, this.snapshot.rootLocation)
|
|
2481
2603
|
&& this.applicationAllowsFollowingLinkToLocation(link, location);
|
|
2482
2604
|
}
|
|
2483
2605
|
followedLinkToLocation(link, location) {
|
|
@@ -2485,14 +2607,24 @@ class Session {
|
|
|
2485
2607
|
this.convertLinkWithMethodClickToFormSubmission(link) || this.visit(location.href, { action });
|
|
2486
2608
|
}
|
|
2487
2609
|
convertLinkWithMethodClickToFormSubmission(link) {
|
|
2488
|
-
var _a;
|
|
2489
2610
|
const linkMethod = link.getAttribute("data-turbo-method");
|
|
2490
2611
|
if (linkMethod) {
|
|
2491
2612
|
const form = document.createElement("form");
|
|
2492
2613
|
form.method = linkMethod;
|
|
2493
2614
|
form.action = link.getAttribute("href") || "undefined";
|
|
2494
2615
|
form.hidden = true;
|
|
2495
|
-
(
|
|
2616
|
+
if (link.hasAttribute("data-turbo-confirm")) {
|
|
2617
|
+
form.setAttribute("data-turbo-confirm", link.getAttribute("data-turbo-confirm"));
|
|
2618
|
+
}
|
|
2619
|
+
const frame = this.getTargetFrameForLink(link);
|
|
2620
|
+
if (frame) {
|
|
2621
|
+
form.setAttribute("data-turbo-frame", frame);
|
|
2622
|
+
form.addEventListener("turbo:submit-start", () => form.remove());
|
|
2623
|
+
}
|
|
2624
|
+
else {
|
|
2625
|
+
form.addEventListener("submit", () => form.remove());
|
|
2626
|
+
}
|
|
2627
|
+
document.body.appendChild(form);
|
|
2496
2628
|
return dispatch("submit", { cancelable: true, target: form });
|
|
2497
2629
|
}
|
|
2498
2630
|
else {
|
|
@@ -2522,7 +2654,10 @@ class Session {
|
|
|
2522
2654
|
this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
|
2523
2655
|
}
|
|
2524
2656
|
willSubmitForm(form, submitter) {
|
|
2525
|
-
|
|
2657
|
+
const action = getAction(form, submitter);
|
|
2658
|
+
return this.elementDriveEnabled(form)
|
|
2659
|
+
&& (!submitter || this.elementDriveEnabled(submitter))
|
|
2660
|
+
&& locationIsVisitable(expandURL(action), this.snapshot.rootLocation);
|
|
2526
2661
|
}
|
|
2527
2662
|
formSubmitted(form, submitter) {
|
|
2528
2663
|
this.navigator.submitForm(form, submitter);
|
|
@@ -2578,6 +2713,7 @@ class Session {
|
|
|
2578
2713
|
return dispatch("turbo:before-visit", { detail: { url: location.href }, cancelable: true });
|
|
2579
2714
|
}
|
|
2580
2715
|
notifyApplicationAfterVisitingLocation(location, action) {
|
|
2716
|
+
markAsBusy(document.documentElement);
|
|
2581
2717
|
return dispatch("turbo:visit", { detail: { url: location.href, action } });
|
|
2582
2718
|
}
|
|
2583
2719
|
notifyApplicationBeforeCachingSnapshot() {
|
|
@@ -2590,6 +2726,7 @@ class Session {
|
|
|
2590
2726
|
return dispatch("turbo:render");
|
|
2591
2727
|
}
|
|
2592
2728
|
notifyApplicationAfterPageLoad(timing = {}) {
|
|
2729
|
+
clearBusyState(document.documentElement);
|
|
2593
2730
|
return dispatch("turbo:load", { detail: { url: this.location.href, timing } });
|
|
2594
2731
|
}
|
|
2595
2732
|
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
|
@@ -2624,8 +2761,17 @@ class Session {
|
|
|
2624
2761
|
const action = link.getAttribute("data-turbo-action");
|
|
2625
2762
|
return isAction(action) ? action : "advance";
|
|
2626
2763
|
}
|
|
2627
|
-
|
|
2628
|
-
|
|
2764
|
+
getTargetFrameForLink(link) {
|
|
2765
|
+
const frame = link.getAttribute("data-turbo-frame");
|
|
2766
|
+
if (frame) {
|
|
2767
|
+
return frame;
|
|
2768
|
+
}
|
|
2769
|
+
else {
|
|
2770
|
+
const container = link.closest("turbo-frame");
|
|
2771
|
+
if (container) {
|
|
2772
|
+
return container.id;
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2629
2775
|
}
|
|
2630
2776
|
get snapshot() {
|
|
2631
2777
|
return this.view.snapshot;
|
|
@@ -2643,7 +2789,7 @@ const deprecatedLocationPropertyDescriptors = {
|
|
|
2643
2789
|
};
|
|
2644
2790
|
|
|
2645
2791
|
const session = new Session;
|
|
2646
|
-
const { navigator } = session;
|
|
2792
|
+
const { navigator: navigator$1 } = session;
|
|
2647
2793
|
function start() {
|
|
2648
2794
|
session.start();
|
|
2649
2795
|
}
|
|
@@ -2668,10 +2814,13 @@ function clearCache() {
|
|
|
2668
2814
|
function setProgressBarDelay(delay) {
|
|
2669
2815
|
session.setProgressBarDelay(delay);
|
|
2670
2816
|
}
|
|
2817
|
+
function setConfirmMethod(confirmMethod) {
|
|
2818
|
+
FormSubmission.confirmMethod = confirmMethod;
|
|
2819
|
+
}
|
|
2671
2820
|
|
|
2672
2821
|
var Turbo = /*#__PURE__*/Object.freeze({
|
|
2673
2822
|
__proto__: null,
|
|
2674
|
-
navigator: navigator,
|
|
2823
|
+
navigator: navigator$1,
|
|
2675
2824
|
session: session,
|
|
2676
2825
|
PageRenderer: PageRenderer,
|
|
2677
2826
|
PageSnapshot: PageSnapshot,
|
|
@@ -2682,11 +2831,14 @@ var Turbo = /*#__PURE__*/Object.freeze({
|
|
|
2682
2831
|
disconnectStreamSource: disconnectStreamSource,
|
|
2683
2832
|
renderStreamMessage: renderStreamMessage,
|
|
2684
2833
|
clearCache: clearCache,
|
|
2685
|
-
setProgressBarDelay: setProgressBarDelay
|
|
2834
|
+
setProgressBarDelay: setProgressBarDelay,
|
|
2835
|
+
setConfirmMethod: setConfirmMethod
|
|
2686
2836
|
});
|
|
2687
2837
|
|
|
2688
2838
|
class FrameController {
|
|
2689
2839
|
constructor(element) {
|
|
2840
|
+
this.fetchResponseLoaded = (fetchResponse) => { };
|
|
2841
|
+
this.currentFetchRequest = null;
|
|
2690
2842
|
this.resolveVisitPromise = () => { };
|
|
2691
2843
|
this.connected = false;
|
|
2692
2844
|
this.hasBeenLoaded = false;
|
|
@@ -2742,11 +2894,10 @@ class FrameController {
|
|
|
2742
2894
|
this.currentURL = this.sourceURL;
|
|
2743
2895
|
if (this.sourceURL) {
|
|
2744
2896
|
try {
|
|
2745
|
-
this.element.loaded = this.visit(this.sourceURL);
|
|
2897
|
+
this.element.loaded = this.visit(expandURL(this.sourceURL));
|
|
2746
2898
|
this.appearanceObserver.stop();
|
|
2747
2899
|
await this.element.loaded;
|
|
2748
2900
|
this.hasBeenLoaded = true;
|
|
2749
|
-
session.frameLoaded(this.element);
|
|
2750
2901
|
}
|
|
2751
2902
|
catch (error) {
|
|
2752
2903
|
this.currentURL = previousURL;
|
|
@@ -2756,7 +2907,7 @@ class FrameController {
|
|
|
2756
2907
|
}
|
|
2757
2908
|
}
|
|
2758
2909
|
async loadResponse(fetchResponse) {
|
|
2759
|
-
if (fetchResponse.redirected) {
|
|
2910
|
+
if (fetchResponse.redirected || (fetchResponse.succeeded && fetchResponse.isHTML)) {
|
|
2760
2911
|
this.sourceURL = fetchResponse.response.url;
|
|
2761
2912
|
}
|
|
2762
2913
|
try {
|
|
@@ -2764,17 +2915,22 @@ class FrameController {
|
|
|
2764
2915
|
if (html) {
|
|
2765
2916
|
const { body } = parseHTMLDocument(html);
|
|
2766
2917
|
const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
|
|
2767
|
-
const renderer = new FrameRenderer(this.view.snapshot, snapshot, false);
|
|
2918
|
+
const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false);
|
|
2768
2919
|
if (this.view.renderPromise)
|
|
2769
2920
|
await this.view.renderPromise;
|
|
2770
2921
|
await this.view.render(renderer);
|
|
2771
2922
|
session.frameRendered(fetchResponse, this.element);
|
|
2923
|
+
session.frameLoaded(this.element);
|
|
2924
|
+
this.fetchResponseLoaded(fetchResponse);
|
|
2772
2925
|
}
|
|
2773
2926
|
}
|
|
2774
2927
|
catch (error) {
|
|
2775
2928
|
console.error(error);
|
|
2776
2929
|
this.view.invalidate();
|
|
2777
2930
|
}
|
|
2931
|
+
finally {
|
|
2932
|
+
this.fetchResponseLoaded = () => { };
|
|
2933
|
+
}
|
|
2778
2934
|
}
|
|
2779
2935
|
elementAppearedInViewport(element) {
|
|
2780
2936
|
this.loadSourceURL();
|
|
@@ -2800,20 +2956,15 @@ class FrameController {
|
|
|
2800
2956
|
}
|
|
2801
2957
|
this.reloadable = false;
|
|
2802
2958
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
else {
|
|
2807
|
-
const { fetchRequest } = this.formSubmission;
|
|
2808
|
-
this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest);
|
|
2809
|
-
this.formSubmission.start();
|
|
2810
|
-
}
|
|
2959
|
+
const { fetchRequest } = this.formSubmission;
|
|
2960
|
+
this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest);
|
|
2961
|
+
this.formSubmission.start();
|
|
2811
2962
|
}
|
|
2812
2963
|
prepareHeadersForRequest(headers, request) {
|
|
2813
2964
|
headers["Turbo-Frame"] = this.id;
|
|
2814
2965
|
}
|
|
2815
2966
|
requestStarted(request) {
|
|
2816
|
-
this.element
|
|
2967
|
+
markAsBusy(this.element);
|
|
2817
2968
|
}
|
|
2818
2969
|
requestPreventedHandlingResponse(request, response) {
|
|
2819
2970
|
this.resolveVisitPromise();
|
|
@@ -2831,14 +2982,14 @@ class FrameController {
|
|
|
2831
2982
|
this.resolveVisitPromise();
|
|
2832
2983
|
}
|
|
2833
2984
|
requestFinished(request) {
|
|
2834
|
-
this.element
|
|
2985
|
+
clearBusyState(this.element);
|
|
2835
2986
|
}
|
|
2836
|
-
formSubmissionStarted(
|
|
2837
|
-
|
|
2838
|
-
frame.setAttribute("busy", "");
|
|
2987
|
+
formSubmissionStarted({ formElement }) {
|
|
2988
|
+
markAsBusy(formElement, this.findFrameElement(formElement));
|
|
2839
2989
|
}
|
|
2840
2990
|
formSubmissionSucceededWithResponse(formSubmission, response) {
|
|
2841
2991
|
const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
|
|
2992
|
+
this.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
|
|
2842
2993
|
frame.delegate.loadResponse(response);
|
|
2843
2994
|
}
|
|
2844
2995
|
formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
|
@@ -2847,9 +2998,8 @@ class FrameController {
|
|
|
2847
2998
|
formSubmissionErrored(formSubmission, error) {
|
|
2848
2999
|
console.error(error);
|
|
2849
3000
|
}
|
|
2850
|
-
formSubmissionFinished(
|
|
2851
|
-
|
|
2852
|
-
frame.removeAttribute("busy");
|
|
3001
|
+
formSubmissionFinished({ formElement }) {
|
|
3002
|
+
clearBusyState(formElement, this.findFrameElement(formElement));
|
|
2853
3003
|
}
|
|
2854
3004
|
allowsImmediateRender(snapshot, resume) {
|
|
2855
3005
|
return true;
|
|
@@ -2859,10 +3009,14 @@ class FrameController {
|
|
|
2859
3009
|
viewInvalidated() {
|
|
2860
3010
|
}
|
|
2861
3011
|
async visit(url) {
|
|
2862
|
-
|
|
3012
|
+
var _a;
|
|
3013
|
+
const request = new FetchRequest(this, FetchMethod.get, url, url.searchParams, this.element);
|
|
3014
|
+
(_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
3015
|
+
this.currentFetchRequest = request;
|
|
2863
3016
|
return new Promise(resolve => {
|
|
2864
3017
|
this.resolveVisitPromise = () => {
|
|
2865
3018
|
this.resolveVisitPromise = () => { };
|
|
3019
|
+
this.currentFetchRequest = null;
|
|
2866
3020
|
resolve();
|
|
2867
3021
|
};
|
|
2868
3022
|
request.perform();
|
|
@@ -2870,12 +3024,27 @@ class FrameController {
|
|
|
2870
3024
|
}
|
|
2871
3025
|
navigateFrame(element, url, submitter) {
|
|
2872
3026
|
const frame = this.findFrameElement(element, submitter);
|
|
3027
|
+
this.proposeVisitIfNavigatedWithAction(frame, element, submitter);
|
|
2873
3028
|
frame.setAttribute("reloadable", "");
|
|
2874
3029
|
frame.src = url;
|
|
2875
3030
|
}
|
|
3031
|
+
proposeVisitIfNavigatedWithAction(frame, element, submitter) {
|
|
3032
|
+
const action = getAttribute("data-turbo-action", submitter, element, frame);
|
|
3033
|
+
if (isAction(action)) {
|
|
3034
|
+
const { visitCachedSnapshot } = new SnapshotSubstitution(frame);
|
|
3035
|
+
frame.delegate.fetchResponseLoaded = (fetchResponse) => {
|
|
3036
|
+
if (frame.src) {
|
|
3037
|
+
const { statusCode, redirected } = fetchResponse;
|
|
3038
|
+
const responseHTML = frame.ownerDocument.documentElement.outerHTML;
|
|
3039
|
+
const response = { statusCode, redirected, responseHTML };
|
|
3040
|
+
session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false });
|
|
3041
|
+
}
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
2876
3045
|
findFrameElement(element, submitter) {
|
|
2877
3046
|
var _a;
|
|
2878
|
-
const id =
|
|
3047
|
+
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
|
2879
3048
|
return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
|
|
2880
3049
|
}
|
|
2881
3050
|
async extractForeignFrameElement(container) {
|
|
@@ -2896,8 +3065,15 @@ class FrameController {
|
|
|
2896
3065
|
}
|
|
2897
3066
|
return new FrameElement();
|
|
2898
3067
|
}
|
|
3068
|
+
formActionIsVisitable(form, submitter) {
|
|
3069
|
+
const action = getAction(form, submitter);
|
|
3070
|
+
return locationIsVisitable(expandURL(action), this.rootLocation);
|
|
3071
|
+
}
|
|
2899
3072
|
shouldInterceptNavigation(element, submitter) {
|
|
2900
|
-
const id =
|
|
3073
|
+
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
|
3074
|
+
if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) {
|
|
3075
|
+
return false;
|
|
3076
|
+
}
|
|
2901
3077
|
if (!this.enabled || id == "_top") {
|
|
2902
3078
|
return false;
|
|
2903
3079
|
}
|
|
@@ -2954,6 +3130,23 @@ class FrameController {
|
|
|
2954
3130
|
get isActive() {
|
|
2955
3131
|
return this.element.isActive && this.connected;
|
|
2956
3132
|
}
|
|
3133
|
+
get rootLocation() {
|
|
3134
|
+
var _a;
|
|
3135
|
+
const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
|
3136
|
+
const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
|
|
3137
|
+
return expandURL(root);
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
class SnapshotSubstitution {
|
|
3141
|
+
constructor(element) {
|
|
3142
|
+
this.visitCachedSnapshot = ({ element }) => {
|
|
3143
|
+
var _a;
|
|
3144
|
+
const { id, clone } = this;
|
|
3145
|
+
(_a = element.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone);
|
|
3146
|
+
};
|
|
3147
|
+
this.clone = element.cloneNode(true);
|
|
3148
|
+
this.id = element.id;
|
|
3149
|
+
}
|
|
2957
3150
|
}
|
|
2958
3151
|
function getFrameElementById(id) {
|
|
2959
3152
|
if (id != null) {
|
|
@@ -2974,6 +3167,7 @@ function activateElement(element, currentURL) {
|
|
|
2974
3167
|
}
|
|
2975
3168
|
if (element instanceof FrameElement) {
|
|
2976
3169
|
element.connectedCallback();
|
|
3170
|
+
element.disconnectedCallback();
|
|
2977
3171
|
return element;
|
|
2978
3172
|
}
|
|
2979
3173
|
}
|
|
@@ -3144,4 +3338,4 @@ customElements.define("turbo-stream", StreamElement);
|
|
|
3144
3338
|
window.Turbo = Turbo;
|
|
3145
3339
|
start();
|
|
3146
3340
|
|
|
3147
|
-
export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator, registerAdapter, renderStreamMessage, session, setProgressBarDelay, start, visit };
|
|
3341
|
+
export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator$1 as navigator, registerAdapter, renderStreamMessage, session, setConfirmMethod, setProgressBarDelay, start, visit };
|