@hotwired/turbo 7.2.0-beta.2 → 7.2.0-rc.2
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/README.md +4 -0
- package/dist/turbo.es2017-esm.js +137 -62
- package/dist/turbo.es2017-umd.js +147 -69
- package/dist/types/core/drive/form_submission.d.ts +1 -3
- package/dist/types/core/drive/navigator.d.ts +1 -1
- package/dist/types/core/drive/visit.d.ts +2 -1
- package/dist/types/core/frames/frame_controller.d.ts +9 -3
- package/dist/types/core/index.d.ts +3 -5
- package/dist/types/core/session.d.ts +6 -10
- package/dist/types/core/snapshot.d.ts +3 -1
- package/dist/types/core/streams/stream_actions.d.ts +4 -2
- package/dist/types/core/streams/stream_message_renderer.d.ts +7 -0
- package/dist/types/elements/index.d.ts +1 -0
- package/dist/types/elements/stream_element.d.ts +5 -1
- package/dist/types/http/fetch_request.d.ts +7 -3
- package/dist/types/http/index.d.ts +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/tests/functional/drive_custom_body_tests.d.ts +1 -0
- package/dist/types/tests/helpers/page.d.ts +8 -2
- package/dist/types/util.d.ts +1 -0
- package/package.json +4 -4
package/dist/turbo.es2017-umd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Turbo 7.2.0-
|
|
2
|
+
Turbo 7.2.0-rc.1
|
|
3
3
|
Copyright © 2022 Basecamp, LLC
|
|
4
4
|
*/
|
|
5
5
|
(function (global, factory) {
|
|
@@ -113,11 +113,11 @@ Copyright © 2022 Basecamp, LLC
|
|
|
113
113
|
});
|
|
114
114
|
})();
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
exports.FrameLoadingStyle = void 0;
|
|
117
117
|
(function (FrameLoadingStyle) {
|
|
118
118
|
FrameLoadingStyle["eager"] = "eager";
|
|
119
119
|
FrameLoadingStyle["lazy"] = "lazy";
|
|
120
|
-
})(FrameLoadingStyle || (FrameLoadingStyle = {}));
|
|
120
|
+
})(exports.FrameLoadingStyle || (exports.FrameLoadingStyle = {}));
|
|
121
121
|
class FrameElement extends HTMLElement {
|
|
122
122
|
constructor() {
|
|
123
123
|
super();
|
|
@@ -212,9 +212,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
212
212
|
function frameLoadingStyleFromString(style) {
|
|
213
213
|
switch (style.toLowerCase()) {
|
|
214
214
|
case "lazy":
|
|
215
|
-
return FrameLoadingStyle.lazy;
|
|
215
|
+
return exports.FrameLoadingStyle.lazy;
|
|
216
216
|
default:
|
|
217
|
-
return FrameLoadingStyle.eager;
|
|
217
|
+
return exports.FrameLoadingStyle.eager;
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -410,6 +410,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
410
410
|
}
|
|
411
411
|
return null;
|
|
412
412
|
}
|
|
413
|
+
function hasAttribute(attributeName, ...elements) {
|
|
414
|
+
return elements.some((element) => element && element.hasAttribute(attributeName));
|
|
415
|
+
}
|
|
413
416
|
function markAsBusy(...elements) {
|
|
414
417
|
for (const element of elements) {
|
|
415
418
|
if (element.localName == "turbo-frame") {
|
|
@@ -526,7 +529,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
526
529
|
}
|
|
527
530
|
catch (error) {
|
|
528
531
|
if (error.name !== "AbortError") {
|
|
529
|
-
this.
|
|
532
|
+
if (this.willDelegateErrorHandling(error)) {
|
|
533
|
+
this.delegate.requestErrored(this, error);
|
|
534
|
+
}
|
|
530
535
|
throw error;
|
|
531
536
|
}
|
|
532
537
|
}
|
|
@@ -592,6 +597,14 @@ Copyright © 2022 Basecamp, LLC
|
|
|
592
597
|
if (event.defaultPrevented)
|
|
593
598
|
await requestInterception;
|
|
594
599
|
}
|
|
600
|
+
willDelegateErrorHandling(error) {
|
|
601
|
+
const event = dispatch("turbo:fetch-request-error", {
|
|
602
|
+
target: this.target,
|
|
603
|
+
cancelable: true,
|
|
604
|
+
detail: { request: this, error: error },
|
|
605
|
+
});
|
|
606
|
+
return !event.defaultPrevented;
|
|
607
|
+
}
|
|
595
608
|
}
|
|
596
609
|
|
|
597
610
|
class AppearanceObserver {
|
|
@@ -685,7 +698,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
685
698
|
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
|
686
699
|
this.mustRedirect = mustRedirect;
|
|
687
700
|
}
|
|
688
|
-
static confirmMethod(message, _element) {
|
|
701
|
+
static confirmMethod(message, _element, _submitter) {
|
|
689
702
|
return Promise.resolve(confirm(message));
|
|
690
703
|
}
|
|
691
704
|
get method() {
|
|
@@ -723,17 +736,11 @@ Copyright © 2022 Basecamp, LLC
|
|
|
723
736
|
return entries.concat(typeof value == "string" ? [[name, value]] : []);
|
|
724
737
|
}, []);
|
|
725
738
|
}
|
|
726
|
-
get confirmationMessage() {
|
|
727
|
-
var _a;
|
|
728
|
-
return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-confirm")) || this.formElement.getAttribute("data-turbo-confirm");
|
|
729
|
-
}
|
|
730
|
-
get needsConfirmation() {
|
|
731
|
-
return this.confirmationMessage !== null;
|
|
732
|
-
}
|
|
733
739
|
async start() {
|
|
734
740
|
const { initialized, requesting } = FormSubmissionState;
|
|
735
|
-
|
|
736
|
-
|
|
741
|
+
const confirmationMessage = getAttribute("data-turbo-confirm", this.submitter, this.formElement);
|
|
742
|
+
if (typeof confirmationMessage === "string") {
|
|
743
|
+
const answer = await FormSubmission.confirmMethod(confirmationMessage, this.formElement, this.submitter);
|
|
737
744
|
if (!answer) {
|
|
738
745
|
return;
|
|
739
746
|
}
|
|
@@ -795,10 +802,6 @@ Copyright © 2022 Basecamp, LLC
|
|
|
795
802
|
}
|
|
796
803
|
requestErrored(request, error) {
|
|
797
804
|
this.result = { success: false, error };
|
|
798
|
-
dispatch("turbo:fetch-request-error", {
|
|
799
|
-
target: this.formElement,
|
|
800
|
-
detail: { request, error },
|
|
801
|
-
});
|
|
802
805
|
this.delegate.formSubmissionErrored(this, error);
|
|
803
806
|
}
|
|
804
807
|
requestFinished(_request) {
|
|
@@ -815,7 +818,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
815
818
|
return !request.isIdempotent && this.mustRedirect;
|
|
816
819
|
}
|
|
817
820
|
requestAcceptsTurboStreamResponse(request) {
|
|
818
|
-
return !request.isIdempotent ||
|
|
821
|
+
return !request.isIdempotent || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
|
|
819
822
|
}
|
|
820
823
|
}
|
|
821
824
|
function buildFormData(formElement, submitter) {
|
|
@@ -881,10 +884,10 @@ Copyright © 2022 Basecamp, LLC
|
|
|
881
884
|
return null;
|
|
882
885
|
}
|
|
883
886
|
get permanentElements() {
|
|
884
|
-
return
|
|
887
|
+
return queryPermanentElementsAll(this.element);
|
|
885
888
|
}
|
|
886
889
|
getPermanentElementById(id) {
|
|
887
|
-
return this.element
|
|
890
|
+
return getPermanentElementById(this.element, id);
|
|
888
891
|
}
|
|
889
892
|
getPermanentElementMapForSnapshot(snapshot) {
|
|
890
893
|
const permanentElementMap = {};
|
|
@@ -898,6 +901,12 @@ Copyright © 2022 Basecamp, LLC
|
|
|
898
901
|
return permanentElementMap;
|
|
899
902
|
}
|
|
900
903
|
}
|
|
904
|
+
function getPermanentElementById(node, id) {
|
|
905
|
+
return node.querySelector(`#${id}[data-turbo-permanent]`);
|
|
906
|
+
}
|
|
907
|
+
function queryPermanentElementsAll(node) {
|
|
908
|
+
return node.querySelectorAll("[id][data-turbo-permanent]");
|
|
909
|
+
}
|
|
901
910
|
|
|
902
911
|
class FormSubmitObserver {
|
|
903
912
|
constructor(delegate, eventTarget) {
|
|
@@ -1139,6 +1148,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1139
1148
|
const turboFrame = link.getAttribute("data-turbo-frame");
|
|
1140
1149
|
if (turboFrame)
|
|
1141
1150
|
form.setAttribute("data-turbo-frame", turboFrame);
|
|
1151
|
+
const turboAction = link.getAttribute("data-turbo-action");
|
|
1152
|
+
if (turboAction)
|
|
1153
|
+
form.setAttribute("data-turbo-action", turboAction);
|
|
1142
1154
|
const turboConfirm = link.getAttribute("data-turbo-confirm");
|
|
1143
1155
|
if (turboConfirm)
|
|
1144
1156
|
form.setAttribute("data-turbo-confirm", turboConfirm);
|
|
@@ -1147,8 +1159,8 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1147
1159
|
form.setAttribute("data-turbo-stream", "");
|
|
1148
1160
|
this.delegate.submittedFormLinkToLocation(link, location, form);
|
|
1149
1161
|
document.body.appendChild(form);
|
|
1150
|
-
form.
|
|
1151
|
-
form.
|
|
1162
|
+
form.addEventListener("turbo:submit-end", () => form.remove(), { once: true });
|
|
1163
|
+
requestAnimationFrame(() => form.requestSubmit());
|
|
1152
1164
|
}
|
|
1153
1165
|
}
|
|
1154
1166
|
|
|
@@ -1519,19 +1531,19 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1519
1531
|
return element.getAttribute("data-turbo-track") == "reload";
|
|
1520
1532
|
}
|
|
1521
1533
|
function elementIsScript(element) {
|
|
1522
|
-
const tagName = element.
|
|
1534
|
+
const tagName = element.localName;
|
|
1523
1535
|
return tagName == "script";
|
|
1524
1536
|
}
|
|
1525
1537
|
function elementIsNoscript(element) {
|
|
1526
|
-
const tagName = element.
|
|
1538
|
+
const tagName = element.localName;
|
|
1527
1539
|
return tagName == "noscript";
|
|
1528
1540
|
}
|
|
1529
1541
|
function elementIsStylesheet(element) {
|
|
1530
|
-
const tagName = element.
|
|
1542
|
+
const tagName = element.localName;
|
|
1531
1543
|
return tagName == "style" || (tagName == "link" && element.getAttribute("rel") == "stylesheet");
|
|
1532
1544
|
}
|
|
1533
1545
|
function elementIsMetaElementWithName(element, name) {
|
|
1534
|
-
const tagName = element.
|
|
1546
|
+
const tagName = element.localName;
|
|
1535
1547
|
return tagName == "meta" && element.getAttribute("name") == name;
|
|
1536
1548
|
}
|
|
1537
1549
|
function elementWithoutNonce(element) {
|
|
@@ -1556,7 +1568,20 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1556
1568
|
return new this(body, new HeadSnapshot(head));
|
|
1557
1569
|
}
|
|
1558
1570
|
clone() {
|
|
1559
|
-
|
|
1571
|
+
const clonedElement = this.element.cloneNode(true);
|
|
1572
|
+
const selectElements = this.element.querySelectorAll("select");
|
|
1573
|
+
const clonedSelectElements = clonedElement.querySelectorAll("select");
|
|
1574
|
+
for (const [index, source] of selectElements.entries()) {
|
|
1575
|
+
const clone = clonedSelectElements[index];
|
|
1576
|
+
for (const option of clone.selectedOptions)
|
|
1577
|
+
option.selected = false;
|
|
1578
|
+
for (const option of source.selectedOptions)
|
|
1579
|
+
clone.options[option.index].selected = true;
|
|
1580
|
+
}
|
|
1581
|
+
for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
|
|
1582
|
+
clonedPasswordInput.value = "";
|
|
1583
|
+
}
|
|
1584
|
+
return new PageSnapshot(clonedElement, this.headSnapshot);
|
|
1560
1585
|
}
|
|
1561
1586
|
get headElement() {
|
|
1562
1587
|
return this.headSnapshot.element;
|
|
@@ -1606,6 +1631,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1606
1631
|
updateHistory: true,
|
|
1607
1632
|
shouldCacheSnapshot: true,
|
|
1608
1633
|
acceptsStreamResponse: false,
|
|
1634
|
+
initiator: document.documentElement,
|
|
1609
1635
|
};
|
|
1610
1636
|
var SystemStatusCode;
|
|
1611
1637
|
(function (SystemStatusCode) {
|
|
@@ -1615,7 +1641,6 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1615
1641
|
})(SystemStatusCode || (SystemStatusCode = {}));
|
|
1616
1642
|
class Visit {
|
|
1617
1643
|
constructor(delegate, location, restorationIdentifier, options = {}) {
|
|
1618
|
-
this.identifier = uuid();
|
|
1619
1644
|
this.timingMetrics = {};
|
|
1620
1645
|
this.followedRedirect = false;
|
|
1621
1646
|
this.historyChanged = false;
|
|
@@ -1628,7 +1653,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1628
1653
|
this.location = location;
|
|
1629
1654
|
this.restorationIdentifier = restorationIdentifier || uuid();
|
|
1630
1655
|
this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));
|
|
1631
|
-
const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse, } = Object.assign(Object.assign({}, defaultOptions), options);
|
|
1656
|
+
const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse, initiator, } = Object.assign(Object.assign({}, defaultOptions), options);
|
|
1632
1657
|
this.action = action;
|
|
1633
1658
|
this.historyChanged = historyChanged;
|
|
1634
1659
|
this.referrer = referrer;
|
|
@@ -1641,6 +1666,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1641
1666
|
this.scrolled = !willRender;
|
|
1642
1667
|
this.shouldCacheSnapshot = shouldCacheSnapshot;
|
|
1643
1668
|
this.acceptsStreamResponse = acceptsStreamResponse;
|
|
1669
|
+
this.initiator = initiator;
|
|
1644
1670
|
}
|
|
1645
1671
|
get adapter() {
|
|
1646
1672
|
return this.delegate.adapter;
|
|
@@ -1708,7 +1734,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1708
1734
|
this.simulateRequest();
|
|
1709
1735
|
}
|
|
1710
1736
|
else if (this.shouldIssueRequest() && !this.request) {
|
|
1711
|
-
this.request = new FetchRequest(this, FetchMethod.get, this.location);
|
|
1737
|
+
this.request = new FetchRequest(this, FetchMethod.get, this.location, undefined, this.initiator);
|
|
1712
1738
|
this.request.perform();
|
|
1713
1739
|
}
|
|
1714
1740
|
}
|
|
@@ -1804,7 +1830,6 @@ Copyright © 2022 Basecamp, LLC
|
|
|
1804
1830
|
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
|
1805
1831
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
|
1806
1832
|
action: "replace",
|
|
1807
|
-
willRender: false,
|
|
1808
1833
|
response: this.response,
|
|
1809
1834
|
});
|
|
1810
1835
|
this.followedRedirect = true;
|
|
@@ -2214,7 +2239,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2214
2239
|
this.delegate = delegate;
|
|
2215
2240
|
}
|
|
2216
2241
|
proposeVisit(location, options = {}) {
|
|
2217
|
-
if (this.delegate.
|
|
2242
|
+
if (this.delegate.allowsVisitingLocation(location, options)) {
|
|
2218
2243
|
if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {
|
|
2219
2244
|
return this.delegate.visitProposedToLocation(location, options);
|
|
2220
2245
|
}
|
|
@@ -2422,6 +2447,30 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2422
2447
|
}
|
|
2423
2448
|
}
|
|
2424
2449
|
|
|
2450
|
+
class StreamMessageRenderer {
|
|
2451
|
+
render({ fragment }) {
|
|
2452
|
+
Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => document.documentElement.appendChild(fragment));
|
|
2453
|
+
}
|
|
2454
|
+
enteringBardo(currentPermanentElement, newPermanentElement) {
|
|
2455
|
+
newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
|
|
2456
|
+
}
|
|
2457
|
+
leavingBardo() { }
|
|
2458
|
+
}
|
|
2459
|
+
function getPermanentElementMapForFragment(fragment) {
|
|
2460
|
+
const permanentElementsInDocument = queryPermanentElementsAll(document.documentElement);
|
|
2461
|
+
const permanentElementMap = {};
|
|
2462
|
+
for (const permanentElementInDocument of permanentElementsInDocument) {
|
|
2463
|
+
const { id } = permanentElementInDocument;
|
|
2464
|
+
for (const streamElement of fragment.querySelectorAll("turbo-stream")) {
|
|
2465
|
+
const elementInStream = getPermanentElementById(streamElement.templateElement.content, id);
|
|
2466
|
+
if (elementInStream) {
|
|
2467
|
+
permanentElementMap[id] = [permanentElementInDocument, elementInStream];
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
return permanentElementMap;
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2425
2474
|
class StreamObserver {
|
|
2426
2475
|
constructor(delegate) {
|
|
2427
2476
|
this.sources = new Set();
|
|
@@ -2782,6 +2831,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2782
2831
|
this.streamObserver = new StreamObserver(this);
|
|
2783
2832
|
this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
|
|
2784
2833
|
this.frameRedirector = new FrameRedirector(this, document.documentElement);
|
|
2834
|
+
this.streamMessageRenderer = new StreamMessageRenderer();
|
|
2785
2835
|
this.drive = true;
|
|
2786
2836
|
this.enabled = true;
|
|
2787
2837
|
this.progressBarDelay = 500;
|
|
@@ -2825,7 +2875,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2825
2875
|
this.adapter = adapter;
|
|
2826
2876
|
}
|
|
2827
2877
|
visit(location, options = {}) {
|
|
2828
|
-
const frameElement = document.getElementById(options.frame
|
|
2878
|
+
const frameElement = options.frame ? document.getElementById(options.frame) : null;
|
|
2829
2879
|
if (frameElement instanceof FrameElement) {
|
|
2830
2880
|
frameElement.src = location.toString();
|
|
2831
2881
|
return frameElement.loaded;
|
|
@@ -2841,7 +2891,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2841
2891
|
this.streamObserver.disconnectStreamSource(source);
|
|
2842
2892
|
}
|
|
2843
2893
|
renderStreamMessage(message) {
|
|
2844
|
-
|
|
2894
|
+
this.streamMessageRenderer.render(StreamMessage.wrap(message));
|
|
2845
2895
|
}
|
|
2846
2896
|
clearCache() {
|
|
2847
2897
|
this.view.clearSnapshotCache();
|
|
@@ -2886,22 +2936,27 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2886
2936
|
followedLinkToLocation(link, location) {
|
|
2887
2937
|
const action = this.getActionForLink(link);
|
|
2888
2938
|
const acceptsStreamResponse = link.hasAttribute("data-turbo-stream");
|
|
2889
|
-
this.visit(location.href, { action, acceptsStreamResponse });
|
|
2939
|
+
this.visit(location.href, { action, acceptsStreamResponse, initiator: link });
|
|
2890
2940
|
}
|
|
2891
|
-
|
|
2892
|
-
return this.locationWithActionIsSamePage(location, action) ||
|
|
2941
|
+
allowsVisitingLocation(location, options = {}) {
|
|
2942
|
+
return (this.locationWithActionIsSamePage(location, options.action) ||
|
|
2943
|
+
this.applicationAllowsVisitingLocation(location, options));
|
|
2893
2944
|
}
|
|
2894
2945
|
visitProposedToLocation(location, options) {
|
|
2895
2946
|
extendURLWithDeprecatedProperties(location);
|
|
2896
2947
|
return this.adapter.visitProposedToLocation(location, options);
|
|
2897
2948
|
}
|
|
2898
2949
|
visitStarted(visit) {
|
|
2950
|
+
if (!visit.acceptsStreamResponse) {
|
|
2951
|
+
markAsBusy(document.documentElement);
|
|
2952
|
+
}
|
|
2899
2953
|
extendURLWithDeprecatedProperties(visit.location);
|
|
2900
2954
|
if (!visit.silent) {
|
|
2901
|
-
this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
|
|
2955
|
+
this.notifyApplicationAfterVisitingLocation(visit.location, visit.action, visit.initiator);
|
|
2902
2956
|
}
|
|
2903
2957
|
}
|
|
2904
2958
|
visitCompleted(visit) {
|
|
2959
|
+
clearBusyState(document.documentElement);
|
|
2905
2960
|
this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
|
|
2906
2961
|
}
|
|
2907
2962
|
locationWithActionIsSamePage(location, action) {
|
|
@@ -2961,16 +3016,12 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2961
3016
|
frameRendered(fetchResponse, frame) {
|
|
2962
3017
|
this.notifyApplicationAfterFrameRender(fetchResponse, frame);
|
|
2963
3018
|
}
|
|
2964
|
-
frameMissing(frame, fetchResponse) {
|
|
2965
|
-
console.warn(`Completing full-page visit as matching frame for #${frame.id} was missing from the response`);
|
|
2966
|
-
return this.visit(fetchResponse.location);
|
|
2967
|
-
}
|
|
2968
3019
|
applicationAllowsFollowingLinkToLocation(link, location, ev) {
|
|
2969
3020
|
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location, ev);
|
|
2970
3021
|
return !event.defaultPrevented;
|
|
2971
3022
|
}
|
|
2972
|
-
applicationAllowsVisitingLocation(location) {
|
|
2973
|
-
const event = this.notifyApplicationBeforeVisitingLocation(location);
|
|
3023
|
+
applicationAllowsVisitingLocation(location, options = {}) {
|
|
3024
|
+
const event = this.notifyApplicationBeforeVisitingLocation(location, options.initiator);
|
|
2974
3025
|
return !event.defaultPrevented;
|
|
2975
3026
|
}
|
|
2976
3027
|
notifyApplicationAfterClickingLinkToLocation(link, location, event) {
|
|
@@ -2980,15 +3031,18 @@ Copyright © 2022 Basecamp, LLC
|
|
|
2980
3031
|
cancelable: true,
|
|
2981
3032
|
});
|
|
2982
3033
|
}
|
|
2983
|
-
notifyApplicationBeforeVisitingLocation(location) {
|
|
3034
|
+
notifyApplicationBeforeVisitingLocation(location, element) {
|
|
2984
3035
|
return dispatch("turbo:before-visit", {
|
|
3036
|
+
target: element,
|
|
2985
3037
|
detail: { url: location.href },
|
|
2986
3038
|
cancelable: true,
|
|
2987
3039
|
});
|
|
2988
3040
|
}
|
|
2989
|
-
notifyApplicationAfterVisitingLocation(location, action) {
|
|
2990
|
-
|
|
2991
|
-
|
|
3041
|
+
notifyApplicationAfterVisitingLocation(location, action, element) {
|
|
3042
|
+
return dispatch("turbo:visit", {
|
|
3043
|
+
target: element,
|
|
3044
|
+
detail: { url: location.href, action },
|
|
3045
|
+
});
|
|
2992
3046
|
}
|
|
2993
3047
|
notifyApplicationBeforeCachingSnapshot() {
|
|
2994
3048
|
return dispatch("turbo:before-cache");
|
|
@@ -3003,7 +3057,6 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3003
3057
|
return dispatch("turbo:render");
|
|
3004
3058
|
}
|
|
3005
3059
|
notifyApplicationAfterPageLoad(timing = {}) {
|
|
3006
|
-
clearBusyState(document.documentElement);
|
|
3007
3060
|
return dispatch("turbo:load", {
|
|
3008
3061
|
detail: { url: this.location.href, timing },
|
|
3009
3062
|
});
|
|
@@ -3207,7 +3260,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3207
3260
|
connect() {
|
|
3208
3261
|
if (!this.connected) {
|
|
3209
3262
|
this.connected = true;
|
|
3210
|
-
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
3263
|
+
if (this.loadingStyle == exports.FrameLoadingStyle.lazy) {
|
|
3211
3264
|
this.appearanceObserver.start();
|
|
3212
3265
|
}
|
|
3213
3266
|
else {
|
|
@@ -3228,7 +3281,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3228
3281
|
}
|
|
3229
3282
|
}
|
|
3230
3283
|
disabledChanged() {
|
|
3231
|
-
if (this.loadingStyle == FrameLoadingStyle.eager) {
|
|
3284
|
+
if (this.loadingStyle == exports.FrameLoadingStyle.eager) {
|
|
3232
3285
|
this.loadSourceURL();
|
|
3233
3286
|
}
|
|
3234
3287
|
}
|
|
@@ -3238,7 +3291,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3238
3291
|
if (this.element.isConnected) {
|
|
3239
3292
|
this.complete = false;
|
|
3240
3293
|
}
|
|
3241
|
-
if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
|
|
3294
|
+
if (this.loadingStyle == exports.FrameLoadingStyle.eager || this.hasBeenLoaded) {
|
|
3242
3295
|
this.loadSourceURL();
|
|
3243
3296
|
}
|
|
3244
3297
|
}
|
|
@@ -3248,7 +3301,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3248
3301
|
this.loadSourceURL();
|
|
3249
3302
|
}
|
|
3250
3303
|
loadingStyleChanged() {
|
|
3251
|
-
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
3304
|
+
if (this.loadingStyle == exports.FrameLoadingStyle.lazy) {
|
|
3252
3305
|
this.appearanceObserver.start();
|
|
3253
3306
|
}
|
|
3254
3307
|
else {
|
|
@@ -3285,8 +3338,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3285
3338
|
session.frameLoaded(this.element);
|
|
3286
3339
|
this.fetchResponseLoaded(fetchResponse);
|
|
3287
3340
|
}
|
|
3288
|
-
else if (this.
|
|
3289
|
-
|
|
3341
|
+
else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
|
|
3342
|
+
console.warn(`A matching frame for #${this.element.id} was missing from the response, transforming into full-page Visit.`);
|
|
3343
|
+
this.visitResponse(fetchResponse.response);
|
|
3290
3344
|
}
|
|
3291
3345
|
}
|
|
3292
3346
|
}
|
|
@@ -3344,16 +3398,13 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3344
3398
|
await this.loadResponse(response);
|
|
3345
3399
|
this.resolveVisitPromise();
|
|
3346
3400
|
}
|
|
3347
|
-
requestFailedWithResponse(request, response) {
|
|
3401
|
+
async requestFailedWithResponse(request, response) {
|
|
3348
3402
|
console.error(response);
|
|
3403
|
+
await this.loadResponse(response);
|
|
3349
3404
|
this.resolveVisitPromise();
|
|
3350
3405
|
}
|
|
3351
3406
|
requestErrored(request, error) {
|
|
3352
3407
|
console.error(error);
|
|
3353
|
-
dispatch("turbo:fetch-request-error", {
|
|
3354
|
-
target: this.element,
|
|
3355
|
-
detail: { request, error },
|
|
3356
|
-
});
|
|
3357
3408
|
this.resolveVisitPromise();
|
|
3358
3409
|
}
|
|
3359
3410
|
requestFinished(_request) {
|
|
@@ -3447,15 +3498,30 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3447
3498
|
session.history.update(method, expandURL(this.frame.src || ""), this.restorationIdentifier);
|
|
3448
3499
|
}
|
|
3449
3500
|
}
|
|
3450
|
-
|
|
3501
|
+
willHandleFrameMissingFromResponse(fetchResponse) {
|
|
3451
3502
|
this.element.setAttribute("complete", "");
|
|
3503
|
+
const response = fetchResponse.response;
|
|
3504
|
+
const visit = async (url, options = {}) => {
|
|
3505
|
+
if (url instanceof Response) {
|
|
3506
|
+
this.visitResponse(url);
|
|
3507
|
+
}
|
|
3508
|
+
else {
|
|
3509
|
+
session.visit(url, options);
|
|
3510
|
+
}
|
|
3511
|
+
};
|
|
3452
3512
|
const event = dispatch("turbo:frame-missing", {
|
|
3453
3513
|
target: this.element,
|
|
3454
|
-
detail: {
|
|
3514
|
+
detail: { response, visit },
|
|
3455
3515
|
cancelable: true,
|
|
3456
3516
|
});
|
|
3457
3517
|
return !event.defaultPrevented;
|
|
3458
3518
|
}
|
|
3519
|
+
async visitResponse(response) {
|
|
3520
|
+
const wrapped = new FetchResponse(response);
|
|
3521
|
+
const responseHTML = await wrapped.responseHTML;
|
|
3522
|
+
const { location, redirected, statusCode } = wrapped;
|
|
3523
|
+
return session.visit(location, { response: { redirected, statusCode, responseHTML } });
|
|
3524
|
+
}
|
|
3459
3525
|
findFrameElement(element, submitter) {
|
|
3460
3526
|
var _a;
|
|
3461
3527
|
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
|
@@ -3591,6 +3657,9 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3591
3657
|
}
|
|
3592
3658
|
|
|
3593
3659
|
class StreamElement extends HTMLElement {
|
|
3660
|
+
static async renderElement(newElement) {
|
|
3661
|
+
await newElement.performAction();
|
|
3662
|
+
}
|
|
3594
3663
|
async connectedCallback() {
|
|
3595
3664
|
try {
|
|
3596
3665
|
await this.render();
|
|
@@ -3605,9 +3674,10 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3605
3674
|
async render() {
|
|
3606
3675
|
var _a;
|
|
3607
3676
|
return ((_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
|
3608
|
-
|
|
3677
|
+
const event = this.beforeRenderEvent;
|
|
3678
|
+
if (this.dispatchEvent(event)) {
|
|
3609
3679
|
await nextAnimationFrame();
|
|
3610
|
-
|
|
3680
|
+
await event.detail.render(this);
|
|
3611
3681
|
}
|
|
3612
3682
|
})()));
|
|
3613
3683
|
}
|
|
@@ -3651,7 +3721,12 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3651
3721
|
return this.templateElement.content.cloneNode(true);
|
|
3652
3722
|
}
|
|
3653
3723
|
get templateElement() {
|
|
3654
|
-
if (this.firstElementChild
|
|
3724
|
+
if (this.firstElementChild === null) {
|
|
3725
|
+
const template = this.ownerDocument.createElement("template");
|
|
3726
|
+
this.appendChild(template);
|
|
3727
|
+
return template;
|
|
3728
|
+
}
|
|
3729
|
+
else if (this.firstElementChild instanceof HTMLTemplateElement) {
|
|
3655
3730
|
return this.firstElementChild;
|
|
3656
3731
|
}
|
|
3657
3732
|
this.raise("first child element must be a <template> element");
|
|
@@ -3676,7 +3751,7 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3676
3751
|
return new CustomEvent("turbo:before-stream-render", {
|
|
3677
3752
|
bubbles: true,
|
|
3678
3753
|
cancelable: true,
|
|
3679
|
-
detail: { newStream: this },
|
|
3754
|
+
detail: { newStream: this, render: StreamElement.renderElement },
|
|
3680
3755
|
});
|
|
3681
3756
|
}
|
|
3682
3757
|
get targetElementsById() {
|
|
@@ -3758,10 +3833,13 @@ Copyright © 2022 Basecamp, LLC
|
|
|
3758
3833
|
window.Turbo = Turbo;
|
|
3759
3834
|
start();
|
|
3760
3835
|
|
|
3836
|
+
exports.FrameElement = FrameElement;
|
|
3761
3837
|
exports.FrameRenderer = FrameRenderer;
|
|
3762
3838
|
exports.PageRenderer = PageRenderer;
|
|
3763
3839
|
exports.PageSnapshot = PageSnapshot;
|
|
3764
3840
|
exports.StreamActions = StreamActions;
|
|
3841
|
+
exports.StreamElement = StreamElement;
|
|
3842
|
+
exports.StreamSourceElement = StreamSourceElement;
|
|
3765
3843
|
exports.cache = cache;
|
|
3766
3844
|
exports.clearCache = clearCache;
|
|
3767
3845
|
exports.connectStreamSource = connectStreamSource;
|
|
@@ -45,7 +45,7 @@ export declare class FormSubmission {
|
|
|
45
45
|
readonly mustRedirect: boolean;
|
|
46
46
|
state: FormSubmissionState;
|
|
47
47
|
result?: FormSubmissionResult;
|
|
48
|
-
static confirmMethod(message: string, _element: HTMLFormElement): Promise<boolean>;
|
|
48
|
+
static confirmMethod(message: string, _element: HTMLFormElement, _submitter: HTMLElement | undefined): Promise<boolean>;
|
|
49
49
|
constructor(delegate: FormSubmissionDelegate, formElement: HTMLFormElement, submitter?: HTMLElement, mustRedirect?: boolean);
|
|
50
50
|
get method(): FetchMethod;
|
|
51
51
|
get action(): string;
|
|
@@ -53,8 +53,6 @@ export declare class FormSubmission {
|
|
|
53
53
|
get enctype(): FormEnctype;
|
|
54
54
|
get isIdempotent(): boolean;
|
|
55
55
|
get stringFormData(): [string, string][];
|
|
56
|
-
get confirmationMessage(): string | null;
|
|
57
|
-
get needsConfirmation(): boolean;
|
|
58
56
|
start(): Promise<void | FetchResponse>;
|
|
59
57
|
stop(): true | undefined;
|
|
60
58
|
prepareHeadersForRequest(headers: FetchRequestHeaders, request: FetchRequest): void;
|
|
@@ -4,7 +4,7 @@ import { FormSubmission } from "./form_submission";
|
|
|
4
4
|
import { Locatable } from "../url";
|
|
5
5
|
import { Visit, VisitDelegate, VisitOptions } from "./visit";
|
|
6
6
|
export declare type NavigatorDelegate = VisitDelegate & {
|
|
7
|
-
|
|
7
|
+
allowsVisitingLocation(location: URL, options: Partial<VisitOptions>): boolean;
|
|
8
8
|
visitProposedToLocation(location: URL, options: Partial<VisitOptions>): Promise<void>;
|
|
9
9
|
notifyApplicationAfterVisitingSamePageLocation(oldURL: URL, newURL: URL): void;
|
|
10
10
|
};
|
|
@@ -44,6 +44,7 @@ export declare type VisitOptions = {
|
|
|
44
44
|
shouldCacheSnapshot: boolean;
|
|
45
45
|
frame?: string;
|
|
46
46
|
acceptsStreamResponse: boolean;
|
|
47
|
+
initiator: Element;
|
|
47
48
|
};
|
|
48
49
|
export declare type VisitResponse = {
|
|
49
50
|
statusCode: number;
|
|
@@ -57,7 +58,6 @@ export declare enum SystemStatusCode {
|
|
|
57
58
|
}
|
|
58
59
|
export declare class Visit implements FetchRequestDelegate {
|
|
59
60
|
readonly delegate: VisitDelegate;
|
|
60
|
-
readonly identifier: string;
|
|
61
61
|
readonly restorationIdentifier: string;
|
|
62
62
|
readonly action: Action;
|
|
63
63
|
readonly referrer?: URL;
|
|
@@ -66,6 +66,7 @@ export declare class Visit implements FetchRequestDelegate {
|
|
|
66
66
|
readonly willRender: boolean;
|
|
67
67
|
readonly updateHistory: boolean;
|
|
68
68
|
readonly promise: Promise<void>;
|
|
69
|
+
readonly initiator: Element;
|
|
69
70
|
private resolvingFunctions;
|
|
70
71
|
followedRedirect: boolean;
|
|
71
72
|
frame?: number;
|
|
@@ -5,12 +5,16 @@ import { AppearanceObserver, AppearanceObserverDelegate } from "../../observers/
|
|
|
5
5
|
import { FormSubmission, FormSubmissionDelegate } from "../drive/form_submission";
|
|
6
6
|
import { Snapshot } from "../snapshot";
|
|
7
7
|
import { ViewDelegate, ViewRenderOptions } from "../view";
|
|
8
|
+
import { Locatable } from "../url";
|
|
8
9
|
import { FormSubmitObserver, FormSubmitObserverDelegate } from "../../observers/form_submit_observer";
|
|
9
10
|
import { FrameView } from "./frame_view";
|
|
10
11
|
import { LinkClickObserver, LinkClickObserverDelegate } from "../../observers/link_click_observer";
|
|
11
12
|
import { FormLinkClickObserver, FormLinkClickObserverDelegate } from "../../observers/form_link_click_observer";
|
|
13
|
+
import { VisitOptions } from "../drive/visit";
|
|
14
|
+
declare type VisitFallback = (location: Response | Locatable, options: Partial<VisitOptions>) => Promise<void>;
|
|
12
15
|
export declare type TurboFrameMissingEvent = CustomEvent<{
|
|
13
|
-
|
|
16
|
+
response: Response;
|
|
17
|
+
visit: VisitFallback;
|
|
14
18
|
}>;
|
|
15
19
|
export declare class FrameController implements AppearanceObserverDelegate, FetchRequestDelegate, FormSubmitObserverDelegate, FormSubmissionDelegate, FrameElementDelegate, FormLinkClickObserverDelegate, LinkClickObserverDelegate, ViewDelegate<FrameElement, Snapshot<FrameElement>> {
|
|
16
20
|
readonly element: FrameElement;
|
|
@@ -51,7 +55,7 @@ export declare class FrameController implements AppearanceObserverDelegate, Fetc
|
|
|
51
55
|
requestStarted(_request: FetchRequest): void;
|
|
52
56
|
requestPreventedHandlingResponse(_request: FetchRequest, _response: FetchResponse): void;
|
|
53
57
|
requestSucceededWithResponse(request: FetchRequest, response: FetchResponse): Promise<void>;
|
|
54
|
-
requestFailedWithResponse(request: FetchRequest, response: FetchResponse): void
|
|
58
|
+
requestFailedWithResponse(request: FetchRequest, response: FetchResponse): Promise<void>;
|
|
55
59
|
requestErrored(request: FetchRequest, error: Error): void;
|
|
56
60
|
requestFinished(_request: FetchRequest): void;
|
|
57
61
|
formSubmissionStarted({ formElement }: FormSubmission): void;
|
|
@@ -69,7 +73,8 @@ export declare class FrameController implements AppearanceObserverDelegate, Fetc
|
|
|
69
73
|
private navigateFrame;
|
|
70
74
|
private proposeVisitIfNavigatedWithAction;
|
|
71
75
|
changeHistory(): void;
|
|
72
|
-
private
|
|
76
|
+
private willHandleFrameMissingFromResponse;
|
|
77
|
+
private visitResponse;
|
|
73
78
|
private findFrameElement;
|
|
74
79
|
extractForeignFrameElement(container: ParentNode): Promise<FrameElement | null>;
|
|
75
80
|
private formActionIsVisitable;
|
|
@@ -88,3 +93,4 @@ export declare class FrameController implements AppearanceObserverDelegate, Fetc
|
|
|
88
93
|
private ignoringChangesToAttribute;
|
|
89
94
|
private withCurrentNavigationElement;
|
|
90
95
|
}
|
|
96
|
+
export {};
|