@hotwired/turbo 8.0.20 → 8.0.21
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/dist/turbo.es2017-esm.js +242 -326
- package/dist/turbo.es2017-umd.js +242 -327
- package/package.json +2 -3
package/dist/turbo.es2017-esm.js
CHANGED
|
@@ -1,104 +1,7 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
Turbo 8.0.
|
|
3
|
-
Copyright ©
|
|
2
|
+
Turbo 8.0.21
|
|
3
|
+
Copyright © 2026 37signals LLC
|
|
4
4
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* The MIT License (MIT)
|
|
7
|
-
*
|
|
8
|
-
* Copyright (c) 2019 Javan Makhmali
|
|
9
|
-
*
|
|
10
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
12
|
-
* in the Software without restriction, including without limitation the rights
|
|
13
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
15
|
-
* furnished to do so, subject to the following conditions:
|
|
16
|
-
*
|
|
17
|
-
* The above copyright notice and this permission notice shall be included in
|
|
18
|
-
* all copies or substantial portions of the Software.
|
|
19
|
-
*
|
|
20
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
26
|
-
* THE SOFTWARE.
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
(function (prototype) {
|
|
30
|
-
if (typeof prototype.requestSubmit == "function") return
|
|
31
|
-
|
|
32
|
-
prototype.requestSubmit = function (submitter) {
|
|
33
|
-
if (submitter) {
|
|
34
|
-
validateSubmitter(submitter, this);
|
|
35
|
-
submitter.click();
|
|
36
|
-
} else {
|
|
37
|
-
submitter = document.createElement("input");
|
|
38
|
-
submitter.type = "submit";
|
|
39
|
-
submitter.hidden = true;
|
|
40
|
-
this.appendChild(submitter);
|
|
41
|
-
submitter.click();
|
|
42
|
-
this.removeChild(submitter);
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
function validateSubmitter(submitter, form) {
|
|
47
|
-
submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
|
|
48
|
-
submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
|
|
49
|
-
submitter.form == form ||
|
|
50
|
-
raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function raise(errorConstructor, message, name) {
|
|
54
|
-
throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name)
|
|
55
|
-
}
|
|
56
|
-
})(HTMLFormElement.prototype);
|
|
57
|
-
|
|
58
|
-
const submittersByForm = new WeakMap();
|
|
59
|
-
|
|
60
|
-
function findSubmitterFromClickTarget(target) {
|
|
61
|
-
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
62
|
-
const candidate = element ? element.closest("input, button") : null;
|
|
63
|
-
return candidate?.type == "submit" ? candidate : null
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function clickCaptured(event) {
|
|
67
|
-
const submitter = findSubmitterFromClickTarget(event.target);
|
|
68
|
-
|
|
69
|
-
if (submitter && submitter.form) {
|
|
70
|
-
submittersByForm.set(submitter.form, submitter);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
(function () {
|
|
75
|
-
if ("submitter" in Event.prototype) return
|
|
76
|
-
|
|
77
|
-
let prototype = window.Event.prototype;
|
|
78
|
-
// Certain versions of Safari 15 have a bug where they won't
|
|
79
|
-
// populate the submitter. This hurts TurboDrive's enable/disable detection.
|
|
80
|
-
// See https://bugs.webkit.org/show_bug.cgi?id=229660
|
|
81
|
-
if ("SubmitEvent" in window) {
|
|
82
|
-
const prototypeOfSubmitEvent = window.SubmitEvent.prototype;
|
|
83
|
-
|
|
84
|
-
if (/Apple Computer/.test(navigator.vendor) && !("submitter" in prototypeOfSubmitEvent)) {
|
|
85
|
-
prototype = prototypeOfSubmitEvent;
|
|
86
|
-
} else {
|
|
87
|
-
return // polyfill not needed
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
addEventListener("click", clickCaptured, true);
|
|
92
|
-
|
|
93
|
-
Object.defineProperty(prototype, "submitter", {
|
|
94
|
-
get() {
|
|
95
|
-
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
96
|
-
return submittersByForm.get(this.target)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
})();
|
|
101
|
-
|
|
102
5
|
const FrameLoadingStyle = {
|
|
103
6
|
eager: "eager",
|
|
104
7
|
lazy: "lazy"
|
|
@@ -374,10 +277,6 @@ function nextEventLoopTick() {
|
|
|
374
277
|
return new Promise((resolve) => setTimeout(() => resolve(), 0))
|
|
375
278
|
}
|
|
376
279
|
|
|
377
|
-
function nextMicrotask() {
|
|
378
|
-
return Promise.resolve()
|
|
379
|
-
}
|
|
380
|
-
|
|
381
280
|
function parseHTMLDocument(html = "") {
|
|
382
281
|
return new DOMParser().parseFromString(html, "text/html")
|
|
383
282
|
}
|
|
@@ -406,7 +305,7 @@ function uuid() {
|
|
|
406
305
|
} else if (i == 19) {
|
|
407
306
|
return (Math.floor(Math.random() * 4) + 8).toString(16)
|
|
408
307
|
} else {
|
|
409
|
-
return Math.floor(Math.random() *
|
|
308
|
+
return Math.floor(Math.random() * 16).toString(16)
|
|
410
309
|
}
|
|
411
310
|
})
|
|
412
311
|
.join("")
|
|
@@ -558,14 +457,13 @@ function findLinkFromClickTarget(target) {
|
|
|
558
457
|
const link = findClosestRecursively(target, "a[href], a[xlink\\:href]");
|
|
559
458
|
|
|
560
459
|
if (!link) return null
|
|
460
|
+
if (link.href.startsWith("#")) return null
|
|
561
461
|
if (link.hasAttribute("download")) return null
|
|
562
|
-
if (link.hasAttribute("target") && link.target !== "_self") return null
|
|
563
462
|
|
|
564
|
-
|
|
565
|
-
|
|
463
|
+
const linkTarget = link.getAttribute("target");
|
|
464
|
+
if (linkTarget && linkTarget !== "_self") return null
|
|
566
465
|
|
|
567
|
-
|
|
568
|
-
return expandURL(link.getAttribute("href") || "")
|
|
466
|
+
return link
|
|
569
467
|
}
|
|
570
468
|
|
|
571
469
|
function debounce(fn, delay) {
|
|
@@ -656,6 +554,10 @@ function locationIsVisitable(location, rootLocation) {
|
|
|
656
554
|
return isPrefixedBy(location, rootLocation) && !config.drive.unvisitableExtensions.has(getExtension(location))
|
|
657
555
|
}
|
|
658
556
|
|
|
557
|
+
function getLocationForLink(link) {
|
|
558
|
+
return expandURL(link.getAttribute("href") || "")
|
|
559
|
+
}
|
|
560
|
+
|
|
659
561
|
function getRequestURL(url) {
|
|
660
562
|
const anchor = getAnchor(url);
|
|
661
563
|
return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href
|
|
@@ -1071,35 +973,113 @@ function importStreamElements(fragment) {
|
|
|
1071
973
|
return fragment
|
|
1072
974
|
}
|
|
1073
975
|
|
|
1074
|
-
const
|
|
976
|
+
const identity = key => key;
|
|
1075
977
|
|
|
1076
|
-
class
|
|
1077
|
-
|
|
1078
|
-
|
|
978
|
+
class LRUCache {
|
|
979
|
+
keys = []
|
|
980
|
+
entries = {}
|
|
981
|
+
#toCacheKey
|
|
982
|
+
|
|
983
|
+
constructor(size, toCacheKey = identity) {
|
|
984
|
+
this.size = size;
|
|
985
|
+
this.#toCacheKey = toCacheKey;
|
|
986
|
+
}
|
|
1079
987
|
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
988
|
+
has(key) {
|
|
989
|
+
return this.#toCacheKey(key) in this.entries
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
get(key) {
|
|
993
|
+
if (this.has(key)) {
|
|
994
|
+
const entry = this.read(key);
|
|
995
|
+
this.touch(key);
|
|
996
|
+
return entry
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
put(key, entry) {
|
|
1001
|
+
this.write(key, entry);
|
|
1002
|
+
this.touch(key);
|
|
1003
|
+
return entry
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
clear() {
|
|
1007
|
+
for (const key of Object.keys(this.entries)) {
|
|
1008
|
+
this.evict(key);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
// Private
|
|
1013
|
+
|
|
1014
|
+
read(key) {
|
|
1015
|
+
return this.entries[this.#toCacheKey(key)]
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
write(key, entry) {
|
|
1019
|
+
this.entries[this.#toCacheKey(key)] = entry;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
touch(key) {
|
|
1023
|
+
key = this.#toCacheKey(key);
|
|
1024
|
+
const index = this.keys.indexOf(key);
|
|
1025
|
+
if (index > -1) this.keys.splice(index, 1);
|
|
1026
|
+
this.keys.unshift(key);
|
|
1027
|
+
this.trim();
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
trim() {
|
|
1031
|
+
for (const key of this.keys.splice(this.size)) {
|
|
1032
|
+
this.evict(key);
|
|
1083
1033
|
}
|
|
1084
1034
|
}
|
|
1085
1035
|
|
|
1086
|
-
|
|
1087
|
-
this.
|
|
1036
|
+
evict(key) {
|
|
1037
|
+
delete this.entries[key];
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const PREFETCH_DELAY = 100;
|
|
1042
|
+
|
|
1043
|
+
class PrefetchCache extends LRUCache {
|
|
1044
|
+
#prefetchTimeout = null
|
|
1045
|
+
#maxAges = {}
|
|
1046
|
+
|
|
1047
|
+
constructor(size = 1, prefetchDelay = PREFETCH_DELAY) {
|
|
1048
|
+
super(size, toCacheKey);
|
|
1049
|
+
this.prefetchDelay = prefetchDelay;
|
|
1050
|
+
}
|
|
1088
1051
|
|
|
1052
|
+
putLater(url, request, ttl) {
|
|
1089
1053
|
this.#prefetchTimeout = setTimeout(() => {
|
|
1090
1054
|
request.perform();
|
|
1091
|
-
this.
|
|
1055
|
+
this.put(url, request, ttl);
|
|
1092
1056
|
this.#prefetchTimeout = null;
|
|
1093
|
-
},
|
|
1057
|
+
}, this.prefetchDelay);
|
|
1094
1058
|
}
|
|
1095
1059
|
|
|
1096
|
-
|
|
1097
|
-
|
|
1060
|
+
put(url, request, ttl = cacheTtl) {
|
|
1061
|
+
super.put(url, request);
|
|
1062
|
+
this.#maxAges[toCacheKey(url)] = new Date(new Date().getTime() + ttl);
|
|
1098
1063
|
}
|
|
1099
1064
|
|
|
1100
1065
|
clear() {
|
|
1066
|
+
super.clear();
|
|
1101
1067
|
if (this.#prefetchTimeout) clearTimeout(this.#prefetchTimeout);
|
|
1102
|
-
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
evict(key) {
|
|
1071
|
+
super.evict(key);
|
|
1072
|
+
delete this.#maxAges[key];
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
has(key) {
|
|
1076
|
+
if (super.has(key)) {
|
|
1077
|
+
const maxAge = this.#maxAges[toCacheKey(key)];
|
|
1078
|
+
|
|
1079
|
+
return maxAge && maxAge > Date.now()
|
|
1080
|
+
} else {
|
|
1081
|
+
return false
|
|
1082
|
+
}
|
|
1103
1083
|
}
|
|
1104
1084
|
}
|
|
1105
1085
|
|
|
@@ -3802,6 +3782,10 @@ class PageSnapshot extends Snapshot {
|
|
|
3802
3782
|
clonedPasswordInput.value = "";
|
|
3803
3783
|
}
|
|
3804
3784
|
|
|
3785
|
+
for (const clonedNoscriptElement of clonedElement.querySelectorAll("noscript")) {
|
|
3786
|
+
clonedNoscriptElement.remove();
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3805
3789
|
return new PageSnapshot(this.documentElement, clonedElement, this.headSnapshot)
|
|
3806
3790
|
}
|
|
3807
3791
|
|
|
@@ -3809,6 +3793,10 @@ class PageSnapshot extends Snapshot {
|
|
|
3809
3793
|
return this.documentElement.getAttribute("lang")
|
|
3810
3794
|
}
|
|
3811
3795
|
|
|
3796
|
+
get dir() {
|
|
3797
|
+
return this.documentElement.getAttribute("dir")
|
|
3798
|
+
}
|
|
3799
|
+
|
|
3812
3800
|
get headElement() {
|
|
3813
3801
|
return this.headSnapshot.element
|
|
3814
3802
|
}
|
|
@@ -3839,12 +3827,12 @@ class PageSnapshot extends Snapshot {
|
|
|
3839
3827
|
return viewTransitionEnabled && !window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
3840
3828
|
}
|
|
3841
3829
|
|
|
3842
|
-
get
|
|
3843
|
-
return this.getSetting("refresh-method")
|
|
3830
|
+
get refreshMethod() {
|
|
3831
|
+
return this.getSetting("refresh-method")
|
|
3844
3832
|
}
|
|
3845
3833
|
|
|
3846
|
-
get
|
|
3847
|
-
return this.getSetting("refresh-scroll")
|
|
3834
|
+
get refreshScroll() {
|
|
3835
|
+
return this.getSetting("refresh-scroll")
|
|
3848
3836
|
}
|
|
3849
3837
|
|
|
3850
3838
|
// Private
|
|
@@ -3883,7 +3871,8 @@ const defaultOptions = {
|
|
|
3883
3871
|
willRender: true,
|
|
3884
3872
|
updateHistory: true,
|
|
3885
3873
|
shouldCacheSnapshot: true,
|
|
3886
|
-
acceptsStreamResponse: false
|
|
3874
|
+
acceptsStreamResponse: false,
|
|
3875
|
+
refresh: {}
|
|
3887
3876
|
};
|
|
3888
3877
|
|
|
3889
3878
|
const TimingMetric = {
|
|
@@ -3943,7 +3932,8 @@ class Visit {
|
|
|
3943
3932
|
updateHistory,
|
|
3944
3933
|
shouldCacheSnapshot,
|
|
3945
3934
|
acceptsStreamResponse,
|
|
3946
|
-
direction
|
|
3935
|
+
direction,
|
|
3936
|
+
refresh
|
|
3947
3937
|
} = {
|
|
3948
3938
|
...defaultOptions,
|
|
3949
3939
|
...options
|
|
@@ -3954,7 +3944,6 @@ class Visit {
|
|
|
3954
3944
|
this.snapshot = snapshot;
|
|
3955
3945
|
this.snapshotHTML = snapshotHTML;
|
|
3956
3946
|
this.response = response;
|
|
3957
|
-
this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
|
3958
3947
|
this.isPageRefresh = this.view.isPageRefresh(this);
|
|
3959
3948
|
this.visitCachedSnapshot = visitCachedSnapshot;
|
|
3960
3949
|
this.willRender = willRender;
|
|
@@ -3963,6 +3952,7 @@ class Visit {
|
|
|
3963
3952
|
this.shouldCacheSnapshot = shouldCacheSnapshot;
|
|
3964
3953
|
this.acceptsStreamResponse = acceptsStreamResponse;
|
|
3965
3954
|
this.direction = direction || Direction[action];
|
|
3955
|
+
this.refresh = refresh;
|
|
3966
3956
|
}
|
|
3967
3957
|
|
|
3968
3958
|
get adapter() {
|
|
@@ -3981,10 +3971,6 @@ class Visit {
|
|
|
3981
3971
|
return this.history.getRestorationDataForIdentifier(this.restorationIdentifier)
|
|
3982
3972
|
}
|
|
3983
3973
|
|
|
3984
|
-
get silent() {
|
|
3985
|
-
return this.isSamePage
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
3974
|
start() {
|
|
3989
3975
|
if (this.state == VisitState.initialized) {
|
|
3990
3976
|
this.recordTimingMetric(TimingMetric.visitStart);
|
|
@@ -4121,7 +4107,7 @@ class Visit {
|
|
|
4121
4107
|
const isPreview = this.shouldIssueRequest();
|
|
4122
4108
|
this.render(async () => {
|
|
4123
4109
|
this.cacheSnapshot();
|
|
4124
|
-
if (this.
|
|
4110
|
+
if (this.isPageRefresh) {
|
|
4125
4111
|
this.adapter.visitRendered(this);
|
|
4126
4112
|
} else {
|
|
4127
4113
|
if (this.view.renderPromise) await this.view.renderPromise;
|
|
@@ -4149,17 +4135,6 @@ class Visit {
|
|
|
4149
4135
|
}
|
|
4150
4136
|
}
|
|
4151
4137
|
|
|
4152
|
-
goToSamePageAnchor() {
|
|
4153
|
-
if (this.isSamePage) {
|
|
4154
|
-
this.render(async () => {
|
|
4155
|
-
this.cacheSnapshot();
|
|
4156
|
-
this.performScroll();
|
|
4157
|
-
this.changeHistory();
|
|
4158
|
-
this.adapter.visitRendered(this);
|
|
4159
|
-
});
|
|
4160
|
-
}
|
|
4161
|
-
}
|
|
4162
|
-
|
|
4163
4138
|
// Fetch request delegate
|
|
4164
4139
|
|
|
4165
4140
|
prepareRequest(request) {
|
|
@@ -4221,9 +4196,6 @@ class Visit {
|
|
|
4221
4196
|
} else {
|
|
4222
4197
|
this.scrollToAnchor() || this.view.scrollToTop();
|
|
4223
4198
|
}
|
|
4224
|
-
if (this.isSamePage) {
|
|
4225
|
-
this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);
|
|
4226
|
-
}
|
|
4227
4199
|
|
|
4228
4200
|
this.scrolled = true;
|
|
4229
4201
|
}
|
|
@@ -4262,9 +4234,7 @@ class Visit {
|
|
|
4262
4234
|
}
|
|
4263
4235
|
|
|
4264
4236
|
shouldIssueRequest() {
|
|
4265
|
-
if (this.
|
|
4266
|
-
return false
|
|
4267
|
-
} else if (this.action == "restore") {
|
|
4237
|
+
if (this.action == "restore") {
|
|
4268
4238
|
return !this.hasCachedSnapshot()
|
|
4269
4239
|
} else {
|
|
4270
4240
|
return this.willRender
|
|
@@ -4328,7 +4298,6 @@ class BrowserAdapter {
|
|
|
4328
4298
|
|
|
4329
4299
|
visit.loadCachedSnapshot();
|
|
4330
4300
|
visit.issueRequest();
|
|
4331
|
-
visit.goToSamePageAnchor();
|
|
4332
4301
|
}
|
|
4333
4302
|
|
|
4334
4303
|
visitRequestStarted(visit) {
|
|
@@ -4445,7 +4414,6 @@ class BrowserAdapter {
|
|
|
4445
4414
|
|
|
4446
4415
|
class CacheObserver {
|
|
4447
4416
|
selector = "[data-turbo-temporary]"
|
|
4448
|
-
deprecatedSelector = "[data-turbo-cache=false]"
|
|
4449
4417
|
|
|
4450
4418
|
started = false
|
|
4451
4419
|
|
|
@@ -4470,19 +4438,7 @@ class CacheObserver {
|
|
|
4470
4438
|
}
|
|
4471
4439
|
|
|
4472
4440
|
get temporaryElements() {
|
|
4473
|
-
return [...document.querySelectorAll(this.selector)
|
|
4474
|
-
}
|
|
4475
|
-
|
|
4476
|
-
get temporaryElementsWithDeprecation() {
|
|
4477
|
-
const elements = document.querySelectorAll(this.deprecatedSelector);
|
|
4478
|
-
|
|
4479
|
-
if (elements.length) {
|
|
4480
|
-
console.warn(
|
|
4481
|
-
`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`
|
|
4482
|
-
);
|
|
4483
|
-
}
|
|
4484
|
-
|
|
4485
|
-
return [...elements]
|
|
4441
|
+
return [...document.querySelectorAll(this.selector)]
|
|
4486
4442
|
}
|
|
4487
4443
|
}
|
|
4488
4444
|
|
|
@@ -4572,7 +4528,6 @@ class History {
|
|
|
4572
4528
|
restorationIdentifier = uuid()
|
|
4573
4529
|
restorationData = {}
|
|
4574
4530
|
started = false
|
|
4575
|
-
pageLoaded = false
|
|
4576
4531
|
currentIndex = 0
|
|
4577
4532
|
|
|
4578
4533
|
constructor(delegate) {
|
|
@@ -4582,7 +4537,6 @@ class History {
|
|
|
4582
4537
|
start() {
|
|
4583
4538
|
if (!this.started) {
|
|
4584
4539
|
addEventListener("popstate", this.onPopState, false);
|
|
4585
|
-
addEventListener("load", this.onPageLoad, false);
|
|
4586
4540
|
this.currentIndex = history.state?.turbo?.restorationIndex || 0;
|
|
4587
4541
|
this.started = true;
|
|
4588
4542
|
this.replace(new URL(window.location.href));
|
|
@@ -4592,7 +4546,6 @@ class History {
|
|
|
4592
4546
|
stop() {
|
|
4593
4547
|
if (this.started) {
|
|
4594
4548
|
removeEventListener("popstate", this.onPopState, false);
|
|
4595
|
-
removeEventListener("load", this.onPageLoad, false);
|
|
4596
4549
|
this.started = false;
|
|
4597
4550
|
}
|
|
4598
4551
|
}
|
|
@@ -4648,34 +4601,20 @@ class History {
|
|
|
4648
4601
|
// Event handlers
|
|
4649
4602
|
|
|
4650
4603
|
onPopState = (event) => {
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4604
|
+
const { turbo } = event.state || {};
|
|
4605
|
+
this.location = new URL(window.location.href);
|
|
4606
|
+
|
|
4607
|
+
if (turbo) {
|
|
4608
|
+
const { restorationIdentifier, restorationIndex } = turbo;
|
|
4609
|
+
this.restorationIdentifier = restorationIdentifier;
|
|
4610
|
+
const direction = restorationIndex > this.currentIndex ? "forward" : "back";
|
|
4611
|
+
this.delegate.historyPoppedToLocationWithRestorationIdentifierAndDirection(this.location, restorationIdentifier, direction);
|
|
4612
|
+
this.currentIndex = restorationIndex;
|
|
4613
|
+
} else {
|
|
4614
|
+
this.currentIndex++;
|
|
4615
|
+
this.delegate.historyPoppedWithEmptyState(this.location);
|
|
4661
4616
|
}
|
|
4662
4617
|
}
|
|
4663
|
-
|
|
4664
|
-
onPageLoad = async (_event) => {
|
|
4665
|
-
await nextMicrotask();
|
|
4666
|
-
this.pageLoaded = true;
|
|
4667
|
-
}
|
|
4668
|
-
|
|
4669
|
-
// Private
|
|
4670
|
-
|
|
4671
|
-
shouldHandlePopState() {
|
|
4672
|
-
// Safari dispatches a popstate event after window's load event, ignore it
|
|
4673
|
-
return this.pageIsLoaded()
|
|
4674
|
-
}
|
|
4675
|
-
|
|
4676
|
-
pageIsLoaded() {
|
|
4677
|
-
return this.pageLoaded || document.readyState == "complete"
|
|
4678
|
-
}
|
|
4679
4618
|
}
|
|
4680
4619
|
|
|
4681
4620
|
class LinkPrefetchObserver {
|
|
@@ -4750,7 +4689,7 @@ class LinkPrefetchObserver {
|
|
|
4750
4689
|
|
|
4751
4690
|
fetchRequest.fetchOptions.priority = "low";
|
|
4752
4691
|
|
|
4753
|
-
prefetchCache.
|
|
4692
|
+
prefetchCache.putLater(location, fetchRequest, this.#cacheTtl);
|
|
4754
4693
|
}
|
|
4755
4694
|
}
|
|
4756
4695
|
}
|
|
@@ -4766,7 +4705,7 @@ class LinkPrefetchObserver {
|
|
|
4766
4705
|
|
|
4767
4706
|
#tryToUsePrefetchedRequest = (event) => {
|
|
4768
4707
|
if (event.target.tagName !== "FORM" && event.detail.fetchOptions.method === "GET") {
|
|
4769
|
-
const cached = prefetchCache.get(event.detail.url
|
|
4708
|
+
const cached = prefetchCache.get(event.detail.url);
|
|
4770
4709
|
|
|
4771
4710
|
if (cached) {
|
|
4772
4711
|
// User clicked link, use cache response
|
|
@@ -4956,7 +4895,7 @@ class Navigator {
|
|
|
4956
4895
|
} else {
|
|
4957
4896
|
await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
|
4958
4897
|
}
|
|
4959
|
-
if(
|
|
4898
|
+
if (snapshot.refreshScroll !== "preserve") {
|
|
4960
4899
|
this.view.scrollToTop();
|
|
4961
4900
|
}
|
|
4962
4901
|
this.view.clearSnapshotCache();
|
|
@@ -4996,20 +4935,10 @@ class Navigator {
|
|
|
4996
4935
|
delete this.currentVisit;
|
|
4997
4936
|
}
|
|
4998
4937
|
|
|
4938
|
+
// Same-page links are no longer handled with a Visit.
|
|
4939
|
+
// This method is still needed for Turbo Native adapters.
|
|
4999
4940
|
locationWithActionIsSamePage(location, action) {
|
|
5000
|
-
|
|
5001
|
-
const currentAnchor = getAnchor(this.view.lastRenderedLocation);
|
|
5002
|
-
const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
|
5003
|
-
|
|
5004
|
-
return (
|
|
5005
|
-
action !== "replace" &&
|
|
5006
|
-
getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) &&
|
|
5007
|
-
(isRestorationToTop || (anchor != null && anchor !== currentAnchor))
|
|
5008
|
-
)
|
|
5009
|
-
}
|
|
5010
|
-
|
|
5011
|
-
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
5012
|
-
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
|
4941
|
+
return false
|
|
5013
4942
|
}
|
|
5014
4943
|
|
|
5015
4944
|
// Visits
|
|
@@ -5402,13 +5331,18 @@ class PageRenderer extends Renderer {
|
|
|
5402
5331
|
|
|
5403
5332
|
#setLanguage() {
|
|
5404
5333
|
const { documentElement } = this.currentSnapshot;
|
|
5405
|
-
const { lang } = this.newSnapshot;
|
|
5334
|
+
const { dir, lang } = this.newSnapshot;
|
|
5406
5335
|
|
|
5407
5336
|
if (lang) {
|
|
5408
5337
|
documentElement.setAttribute("lang", lang);
|
|
5409
5338
|
} else {
|
|
5410
5339
|
documentElement.removeAttribute("lang");
|
|
5411
5340
|
}
|
|
5341
|
+
if (dir) {
|
|
5342
|
+
documentElement.setAttribute("dir", dir);
|
|
5343
|
+
} else {
|
|
5344
|
+
documentElement.removeAttribute("dir");
|
|
5345
|
+
}
|
|
5412
5346
|
}
|
|
5413
5347
|
|
|
5414
5348
|
async mergeHead() {
|
|
@@ -5510,9 +5444,16 @@ class PageRenderer extends Renderer {
|
|
|
5510
5444
|
|
|
5511
5445
|
activateNewBody() {
|
|
5512
5446
|
document.adoptNode(this.newElement);
|
|
5447
|
+
this.removeNoscriptElements();
|
|
5513
5448
|
this.activateNewBodyScriptElements();
|
|
5514
5449
|
}
|
|
5515
5450
|
|
|
5451
|
+
removeNoscriptElements() {
|
|
5452
|
+
for (const noscriptElement of this.newElement.querySelectorAll("noscript")) {
|
|
5453
|
+
noscriptElement.remove();
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
|
|
5516
5457
|
activateNewBodyScriptElements() {
|
|
5517
5458
|
for (const inertScriptElement of this.newBodyScriptElements) {
|
|
5518
5459
|
const activatedScriptElement = activateScriptElement(inertScriptElement);
|
|
@@ -5588,58 +5529,13 @@ class MorphingPageRenderer extends PageRenderer {
|
|
|
5588
5529
|
}
|
|
5589
5530
|
}
|
|
5590
5531
|
|
|
5591
|
-
class SnapshotCache {
|
|
5592
|
-
keys = []
|
|
5593
|
-
snapshots = {}
|
|
5594
|
-
|
|
5532
|
+
class SnapshotCache extends LRUCache {
|
|
5595
5533
|
constructor(size) {
|
|
5596
|
-
|
|
5597
|
-
}
|
|
5598
|
-
|
|
5599
|
-
has(location) {
|
|
5600
|
-
return toCacheKey(location) in this.snapshots
|
|
5601
|
-
}
|
|
5602
|
-
|
|
5603
|
-
get(location) {
|
|
5604
|
-
if (this.has(location)) {
|
|
5605
|
-
const snapshot = this.read(location);
|
|
5606
|
-
this.touch(location);
|
|
5607
|
-
return snapshot
|
|
5608
|
-
}
|
|
5609
|
-
}
|
|
5610
|
-
|
|
5611
|
-
put(location, snapshot) {
|
|
5612
|
-
this.write(location, snapshot);
|
|
5613
|
-
this.touch(location);
|
|
5614
|
-
return snapshot
|
|
5534
|
+
super(size, toCacheKey);
|
|
5615
5535
|
}
|
|
5616
5536
|
|
|
5617
|
-
|
|
5618
|
-
this.
|
|
5619
|
-
}
|
|
5620
|
-
|
|
5621
|
-
// Private
|
|
5622
|
-
|
|
5623
|
-
read(location) {
|
|
5624
|
-
return this.snapshots[toCacheKey(location)]
|
|
5625
|
-
}
|
|
5626
|
-
|
|
5627
|
-
write(location, snapshot) {
|
|
5628
|
-
this.snapshots[toCacheKey(location)] = snapshot;
|
|
5629
|
-
}
|
|
5630
|
-
|
|
5631
|
-
touch(location) {
|
|
5632
|
-
const key = toCacheKey(location);
|
|
5633
|
-
const index = this.keys.indexOf(key);
|
|
5634
|
-
if (index > -1) this.keys.splice(index, 1);
|
|
5635
|
-
this.keys.unshift(key);
|
|
5636
|
-
this.trim();
|
|
5637
|
-
}
|
|
5638
|
-
|
|
5639
|
-
trim() {
|
|
5640
|
-
for (const key of this.keys.splice(this.size)) {
|
|
5641
|
-
delete this.snapshots[key];
|
|
5642
|
-
}
|
|
5537
|
+
get snapshots() {
|
|
5538
|
+
return this.entries
|
|
5643
5539
|
}
|
|
5644
5540
|
}
|
|
5645
5541
|
|
|
@@ -5653,7 +5549,7 @@ class PageView extends View {
|
|
|
5653
5549
|
}
|
|
5654
5550
|
|
|
5655
5551
|
renderPage(snapshot, isPreview = false, willRender = true, visit) {
|
|
5656
|
-
const shouldMorphPage = this.isPageRefresh(visit) && this.snapshot.
|
|
5552
|
+
const shouldMorphPage = this.isPageRefresh(visit) && (visit?.refresh?.method || this.snapshot.refreshMethod) === "morph";
|
|
5657
5553
|
const rendererClass = shouldMorphPage ? MorphingPageRenderer : PageRenderer;
|
|
5658
5554
|
|
|
5659
5555
|
const renderer = new rendererClass(this.snapshot, snapshot, isPreview, willRender);
|
|
@@ -5697,7 +5593,7 @@ class PageView extends View {
|
|
|
5697
5593
|
}
|
|
5698
5594
|
|
|
5699
5595
|
shouldPreserveScrollPosition(visit) {
|
|
5700
|
-
return this.isPageRefresh(visit) && this.snapshot.
|
|
5596
|
+
return this.isPageRefresh(visit) && (visit?.refresh?.scroll || this.snapshot.refreshScroll) === "preserve"
|
|
5701
5597
|
}
|
|
5702
5598
|
|
|
5703
5599
|
get snapshot() {
|
|
@@ -5887,11 +5783,14 @@ class Session {
|
|
|
5887
5783
|
}
|
|
5888
5784
|
}
|
|
5889
5785
|
|
|
5890
|
-
refresh(url,
|
|
5786
|
+
refresh(url, options = {}) {
|
|
5787
|
+
options = typeof options === "string" ? { requestId: options } : options;
|
|
5788
|
+
|
|
5789
|
+
const { method, requestId, scroll } = options;
|
|
5891
5790
|
const isRecentRequest = requestId && this.recentRequests.has(requestId);
|
|
5892
5791
|
const isCurrentUrl = url === document.baseURI;
|
|
5893
5792
|
if (!isRecentRequest && !this.navigator.currentVisit && isCurrentUrl) {
|
|
5894
|
-
this.visit(url, { action: "replace", shouldCacheSnapshot: false });
|
|
5793
|
+
this.visit(url, { action: "replace", shouldCacheSnapshot: false, refresh: { method, scroll } });
|
|
5895
5794
|
}
|
|
5896
5795
|
}
|
|
5897
5796
|
|
|
@@ -5995,6 +5894,12 @@ class Session {
|
|
|
5995
5894
|
}
|
|
5996
5895
|
}
|
|
5997
5896
|
|
|
5897
|
+
historyPoppedWithEmptyState(location) {
|
|
5898
|
+
this.history.replace(location);
|
|
5899
|
+
this.view.lastRenderedLocation = location;
|
|
5900
|
+
this.view.cacheSnapshot();
|
|
5901
|
+
}
|
|
5902
|
+
|
|
5998
5903
|
// Scroll observer delegate
|
|
5999
5904
|
|
|
6000
5905
|
scrollPositionChanged(position) {
|
|
@@ -6039,7 +5944,7 @@ class Session {
|
|
|
6039
5944
|
// Navigator delegate
|
|
6040
5945
|
|
|
6041
5946
|
allowsVisitingLocationWithAction(location, action) {
|
|
6042
|
-
return this.
|
|
5947
|
+
return this.applicationAllowsVisitingLocation(location)
|
|
6043
5948
|
}
|
|
6044
5949
|
|
|
6045
5950
|
visitProposedToLocation(location, options) {
|
|
@@ -6055,9 +5960,7 @@ class Session {
|
|
|
6055
5960
|
this.view.markVisitDirection(visit.direction);
|
|
6056
5961
|
}
|
|
6057
5962
|
extendURLWithDeprecatedProperties(visit.location);
|
|
6058
|
-
|
|
6059
|
-
this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
|
|
6060
|
-
}
|
|
5963
|
+
this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
|
|
6061
5964
|
}
|
|
6062
5965
|
|
|
6063
5966
|
visitCompleted(visit) {
|
|
@@ -6066,14 +5969,6 @@ class Session {
|
|
|
6066
5969
|
this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
|
|
6067
5970
|
}
|
|
6068
5971
|
|
|
6069
|
-
locationWithActionIsSamePage(location, action) {
|
|
6070
|
-
return this.navigator.locationWithActionIsSamePage(location, action)
|
|
6071
|
-
}
|
|
6072
|
-
|
|
6073
|
-
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
6074
|
-
this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
|
6075
|
-
}
|
|
6076
|
-
|
|
6077
5972
|
// Form submit observer delegate
|
|
6078
5973
|
|
|
6079
5974
|
willSubmitForm(form, submitter) {
|
|
@@ -6113,9 +6008,7 @@ class Session {
|
|
|
6113
6008
|
// Page view delegate
|
|
6114
6009
|
|
|
6115
6010
|
viewWillCacheSnapshot() {
|
|
6116
|
-
|
|
6117
|
-
this.notifyApplicationBeforeCachingSnapshot();
|
|
6118
|
-
}
|
|
6011
|
+
this.notifyApplicationBeforeCachingSnapshot();
|
|
6119
6012
|
}
|
|
6120
6013
|
|
|
6121
6014
|
allowsImmediateRender({ element }, options) {
|
|
@@ -6207,15 +6100,6 @@ class Session {
|
|
|
6207
6100
|
})
|
|
6208
6101
|
}
|
|
6209
6102
|
|
|
6210
|
-
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
|
6211
|
-
dispatchEvent(
|
|
6212
|
-
new HashChangeEvent("hashchange", {
|
|
6213
|
-
oldURL: oldURL.toString(),
|
|
6214
|
-
newURL: newURL.toString()
|
|
6215
|
-
})
|
|
6216
|
-
);
|
|
6217
|
-
}
|
|
6218
|
-
|
|
6219
6103
|
notifyApplicationAfterFrameLoad(frame) {
|
|
6220
6104
|
return dispatch("turbo:frame-load", { target: frame })
|
|
6221
6105
|
}
|
|
@@ -6301,7 +6185,7 @@ const deprecatedLocationPropertyDescriptors = {
|
|
|
6301
6185
|
};
|
|
6302
6186
|
|
|
6303
6187
|
const session = new Session(recentRequests);
|
|
6304
|
-
const { cache, navigator
|
|
6188
|
+
const { cache, navigator } = session;
|
|
6305
6189
|
|
|
6306
6190
|
/**
|
|
6307
6191
|
* Starts the main session.
|
|
@@ -6367,19 +6251,6 @@ function renderStreamMessage(message) {
|
|
|
6367
6251
|
session.renderStreamMessage(message);
|
|
6368
6252
|
}
|
|
6369
6253
|
|
|
6370
|
-
/**
|
|
6371
|
-
* Removes all entries from the Turbo Drive page cache.
|
|
6372
|
-
* Call this when state has changed on the server that may affect cached pages.
|
|
6373
|
-
*
|
|
6374
|
-
* @deprecated since version 7.2.0 in favor of `Turbo.cache.clear()`
|
|
6375
|
-
*/
|
|
6376
|
-
function clearCache() {
|
|
6377
|
-
console.warn(
|
|
6378
|
-
"Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`"
|
|
6379
|
-
);
|
|
6380
|
-
session.clearCache();
|
|
6381
|
-
}
|
|
6382
|
-
|
|
6383
6254
|
/**
|
|
6384
6255
|
* Sets the delay after which the progress bar will appear during navigation.
|
|
6385
6256
|
*
|
|
@@ -6439,7 +6310,7 @@ function morphTurboFrameElements(currentFrame, newFrame) {
|
|
|
6439
6310
|
|
|
6440
6311
|
var Turbo = /*#__PURE__*/Object.freeze({
|
|
6441
6312
|
__proto__: null,
|
|
6442
|
-
navigator: navigator
|
|
6313
|
+
navigator: navigator,
|
|
6443
6314
|
session: session,
|
|
6444
6315
|
cache: cache,
|
|
6445
6316
|
PageRenderer: PageRenderer,
|
|
@@ -6453,7 +6324,6 @@ var Turbo = /*#__PURE__*/Object.freeze({
|
|
|
6453
6324
|
connectStreamSource: connectStreamSource,
|
|
6454
6325
|
disconnectStreamSource: disconnectStreamSource,
|
|
6455
6326
|
renderStreamMessage: renderStreamMessage,
|
|
6456
|
-
clearCache: clearCache,
|
|
6457
6327
|
setProgressBarDelay: setProgressBarDelay,
|
|
6458
6328
|
setConfirmMethod: setConfirmMethod,
|
|
6459
6329
|
setFormMode: setFormMode,
|
|
@@ -6508,11 +6378,17 @@ class FrameController {
|
|
|
6508
6378
|
this.formLinkClickObserver.stop();
|
|
6509
6379
|
this.linkInterceptor.stop();
|
|
6510
6380
|
this.formSubmitObserver.stop();
|
|
6381
|
+
|
|
6382
|
+
if (!this.element.hasAttribute("recurse")) {
|
|
6383
|
+
this.#currentFetchRequest?.cancel();
|
|
6384
|
+
}
|
|
6511
6385
|
}
|
|
6512
6386
|
}
|
|
6513
6387
|
|
|
6514
6388
|
disabledChanged() {
|
|
6515
|
-
if (this.
|
|
6389
|
+
if (this.disabled) {
|
|
6390
|
+
this.#currentFetchRequest?.cancel();
|
|
6391
|
+
} else if (this.loadingStyle == FrameLoadingStyle.eager) {
|
|
6516
6392
|
this.#loadSourceURL();
|
|
6517
6393
|
}
|
|
6518
6394
|
}
|
|
@@ -6520,6 +6396,10 @@ class FrameController {
|
|
|
6520
6396
|
sourceURLChanged() {
|
|
6521
6397
|
if (this.#isIgnoringChangesTo("src")) return
|
|
6522
6398
|
|
|
6399
|
+
if (!this.sourceURL) {
|
|
6400
|
+
this.#currentFetchRequest?.cancel();
|
|
6401
|
+
}
|
|
6402
|
+
|
|
6523
6403
|
if (this.element.isConnected) {
|
|
6524
6404
|
this.complete = false;
|
|
6525
6405
|
}
|
|
@@ -6621,15 +6501,18 @@ class FrameController {
|
|
|
6621
6501
|
}
|
|
6622
6502
|
|
|
6623
6503
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
|
6504
|
+
|
|
6624
6505
|
const { fetchRequest } = this.formSubmission;
|
|
6625
|
-
this
|
|
6506
|
+
const frame = this.#findFrameElement(element, submitter);
|
|
6507
|
+
|
|
6508
|
+
this.prepareRequest(fetchRequest, frame);
|
|
6626
6509
|
this.formSubmission.start();
|
|
6627
6510
|
}
|
|
6628
6511
|
|
|
6629
6512
|
// Fetch request delegate
|
|
6630
6513
|
|
|
6631
|
-
prepareRequest(request) {
|
|
6632
|
-
request.headers["Turbo-Frame"] =
|
|
6514
|
+
prepareRequest(request, frame = this) {
|
|
6515
|
+
request.headers["Turbo-Frame"] = frame.id;
|
|
6633
6516
|
|
|
6634
6517
|
if (this.currentNavigationElement?.hasAttribute("data-turbo-stream")) {
|
|
6635
6518
|
request.acceptResponseType(StreamMessage.contentType);
|
|
@@ -6871,7 +6754,9 @@ class FrameController {
|
|
|
6871
6754
|
|
|
6872
6755
|
#findFrameElement(element, submitter) {
|
|
6873
6756
|
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
|
6874
|
-
|
|
6757
|
+
const target = this.#getFrameElementById(id);
|
|
6758
|
+
|
|
6759
|
+
return target instanceof FrameElement ? target : this.element
|
|
6875
6760
|
}
|
|
6876
6761
|
|
|
6877
6762
|
async extractForeignFrameElement(container) {
|
|
@@ -6915,9 +6800,11 @@ class FrameController {
|
|
|
6915
6800
|
}
|
|
6916
6801
|
|
|
6917
6802
|
if (id) {
|
|
6918
|
-
const frameElement = getFrameElementById(id);
|
|
6803
|
+
const frameElement = this.#getFrameElementById(id);
|
|
6919
6804
|
if (frameElement) {
|
|
6920
6805
|
return !frameElement.disabled
|
|
6806
|
+
} else if (id == "_parent") {
|
|
6807
|
+
return false
|
|
6921
6808
|
}
|
|
6922
6809
|
}
|
|
6923
6810
|
|
|
@@ -6938,8 +6825,12 @@ class FrameController {
|
|
|
6938
6825
|
return this.element.id
|
|
6939
6826
|
}
|
|
6940
6827
|
|
|
6828
|
+
get disabled() {
|
|
6829
|
+
return this.element.disabled
|
|
6830
|
+
}
|
|
6831
|
+
|
|
6941
6832
|
get enabled() {
|
|
6942
|
-
return !this.
|
|
6833
|
+
return !this.disabled
|
|
6943
6834
|
}
|
|
6944
6835
|
|
|
6945
6836
|
get sourceURL() {
|
|
@@ -6999,13 +6890,15 @@ class FrameController {
|
|
|
6999
6890
|
callback();
|
|
7000
6891
|
delete this.currentNavigationElement;
|
|
7001
6892
|
}
|
|
7002
|
-
}
|
|
7003
6893
|
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
6894
|
+
#getFrameElementById(id) {
|
|
6895
|
+
if (id != null) {
|
|
6896
|
+
const element = id === "_parent" ?
|
|
6897
|
+
this.element.parentElement.closest("turbo-frame") :
|
|
6898
|
+
document.getElementById(id);
|
|
6899
|
+
if (element instanceof FrameElement) {
|
|
6900
|
+
return element
|
|
6901
|
+
}
|
|
7009
6902
|
}
|
|
7010
6903
|
}
|
|
7011
6904
|
}
|
|
@@ -7030,6 +6923,7 @@ function activateElement(element, currentURL) {
|
|
|
7030
6923
|
|
|
7031
6924
|
const StreamActions = {
|
|
7032
6925
|
after() {
|
|
6926
|
+
this.removeDuplicateTargetSiblings();
|
|
7033
6927
|
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e.nextSibling));
|
|
7034
6928
|
},
|
|
7035
6929
|
|
|
@@ -7039,6 +6933,7 @@ const StreamActions = {
|
|
|
7039
6933
|
},
|
|
7040
6934
|
|
|
7041
6935
|
before() {
|
|
6936
|
+
this.removeDuplicateTargetSiblings();
|
|
7042
6937
|
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e));
|
|
7043
6938
|
},
|
|
7044
6939
|
|
|
@@ -7077,7 +6972,11 @@ const StreamActions = {
|
|
|
7077
6972
|
},
|
|
7078
6973
|
|
|
7079
6974
|
refresh() {
|
|
7080
|
-
|
|
6975
|
+
const method = this.getAttribute("method");
|
|
6976
|
+
const requestId = this.requestId;
|
|
6977
|
+
const scroll = this.getAttribute("scroll");
|
|
6978
|
+
|
|
6979
|
+
session.refresh(this.baseURI, { method, requestId, scroll });
|
|
7081
6980
|
}
|
|
7082
6981
|
};
|
|
7083
6982
|
|
|
@@ -7155,6 +7054,23 @@ class StreamElement extends HTMLElement {
|
|
|
7155
7054
|
return existingChildren.filter((c) => newChildrenIds.includes(c.getAttribute("id")))
|
|
7156
7055
|
}
|
|
7157
7056
|
|
|
7057
|
+
/**
|
|
7058
|
+
* Removes duplicate siblings (by ID)
|
|
7059
|
+
*/
|
|
7060
|
+
removeDuplicateTargetSiblings() {
|
|
7061
|
+
this.duplicateSiblings.forEach((c) => c.remove());
|
|
7062
|
+
}
|
|
7063
|
+
|
|
7064
|
+
/**
|
|
7065
|
+
* Gets the list of duplicate siblings (i.e. those with the same ID)
|
|
7066
|
+
*/
|
|
7067
|
+
get duplicateSiblings() {
|
|
7068
|
+
const existingChildren = this.targetElements.flatMap((e) => [...e.parentElement.children]).filter((c) => !!c.id);
|
|
7069
|
+
const newChildrenIds = [...(this.templateContent?.children || [])].filter((c) => !!c.id).map((c) => c.id);
|
|
7070
|
+
|
|
7071
|
+
return existingChildren.filter((c) => newChildrenIds.includes(c.id))
|
|
7072
|
+
}
|
|
7073
|
+
|
|
7158
7074
|
/**
|
|
7159
7075
|
* Gets the action function to be performed.
|
|
7160
7076
|
*/
|
|
@@ -7306,11 +7222,11 @@ if (customElements.get("turbo-stream-source") === undefined) {
|
|
|
7306
7222
|
}
|
|
7307
7223
|
|
|
7308
7224
|
(() => {
|
|
7309
|
-
|
|
7310
|
-
if (!
|
|
7311
|
-
if (
|
|
7225
|
+
const scriptElement = document.currentScript;
|
|
7226
|
+
if (!scriptElement) return
|
|
7227
|
+
if (scriptElement.hasAttribute("data-turbo-suppress-warning")) return
|
|
7312
7228
|
|
|
7313
|
-
element =
|
|
7229
|
+
let element = scriptElement.parentElement;
|
|
7314
7230
|
while (element) {
|
|
7315
7231
|
if (element == document.body) {
|
|
7316
7232
|
return console.warn(
|
|
@@ -7324,7 +7240,7 @@ if (customElements.get("turbo-stream-source") === undefined) {
|
|
|
7324
7240
|
——
|
|
7325
7241
|
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
|
7326
7242
|
`,
|
|
7327
|
-
|
|
7243
|
+
scriptElement.outerHTML
|
|
7328
7244
|
)
|
|
7329
7245
|
}
|
|
7330
7246
|
|
|
@@ -7335,4 +7251,4 @@ if (customElements.get("turbo-stream-source") === undefined) {
|
|
|
7335
7251
|
window.Turbo = { ...Turbo, StreamActions };
|
|
7336
7252
|
start();
|
|
7337
7253
|
|
|
7338
|
-
export { FetchEnctype, FetchMethod, FetchRequest, FetchResponse, FrameElement, FrameLoadingStyle, FrameRenderer, PageRenderer, PageSnapshot, StreamActions, StreamElement, StreamSourceElement, cache,
|
|
7254
|
+
export { FetchEnctype, FetchMethod, FetchRequest, FetchResponse, FrameElement, FrameLoadingStyle, FrameRenderer, PageRenderer, PageSnapshot, StreamActions, StreamElement, StreamSourceElement, cache, config, connectStreamSource, disconnectStreamSource, fetchWithTurboHeaders as fetch, fetchEnctypeFromString, fetchMethodFromString, isSafe, morphBodyElements, morphChildren, morphElements, morphTurboFrameElements, navigator, registerAdapter, renderStreamMessage, session, setConfirmMethod, setFormMode, setProgressBarDelay, start, visit };
|