uchi 0.1.8 → 0.2.0
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.
- checksums.yaml +4 -4
- data/app/assets/javascripts/uchi/application.js +384 -317
- data/app/assets/stylesheets/uchi/application.css +8 -0
- data/app/assets/tailwind/uchi.css +5 -0
- data/app/components/uchi/field/base/show.html.erb +1 -0
- data/app/components/uchi/field/base.rb +24 -27
- data/app/components/uchi/field/boolean/index.html.erb +9 -7
- data/app/components/uchi/field/boolean/show.html.erb +9 -7
- data/app/components/uchi/field/file/show.html.erb +1 -1
- data/app/components/uchi/field/file.rb +1 -1
- data/app/components/uchi/field/has_and_belongs_to_many.rb +19 -1
- data/app/components/uchi/field/has_many.rb +20 -0
- data/app/components/uchi/field/id/show.html.erb +1 -1
- data/app/components/uchi/field/image/index.html.erb +1 -1
- data/app/components/uchi/field/image/show.html.erb +2 -2
- data/app/components/uchi/field/image.rb +1 -1
- data/app/components/uchi/field/select/edit.html.erb +1 -0
- data/app/components/uchi/field/select/index.html.erb +1 -0
- data/app/components/uchi/field/select/show.html.erb +1 -0
- data/app/components/uchi/field/select.rb +144 -0
- data/app/components/uchi/field/text.rb +1 -1
- data/app/components/uchi/ui/index/records_table/records_table.html.erb +1 -1
- data/app/controllers/uchi/repository_controller.rb +2 -2
- data/app/views/layouts/uchi/_javascript.html.erb +1 -1
- data/app/views/layouts/uchi/application.html.erb +4 -6
- data/app/views/uchi/has_many/associated_records/index.html.erb +6 -4
- data/app/views/uchi/repository/edit.html.erb +1 -1
- data/app/views/uchi/repository/new.html.erb +1 -1
- data/app/views/uchi/repository/show.html.erb +4 -4
- data/lib/uchi/field/configuration.rb +42 -5
- data/lib/uchi/repository.rb +19 -7
- data/lib/uchi/sort_order.rb +9 -4
- data/lib/uchi/version.rb +1 -1
- metadata +6 -5
- data/app/components/uchi/field/date/show.html.erb +0 -1
- data/app/components/uchi/field/number/show.html.erb +0 -1
- data/app/components/uchi/field/string/show.html.erb +0 -1
- data/app/components/uchi/field/text/show.html.erb +0 -1
|
@@ -611,7 +611,6 @@
|
|
|
611
611
|
StreamElement: () => StreamElement,
|
|
612
612
|
StreamSourceElement: () => StreamSourceElement,
|
|
613
613
|
cache: () => cache,
|
|
614
|
-
clearCache: () => clearCache,
|
|
615
614
|
config: () => config,
|
|
616
615
|
connectStreamSource: () => connectStreamSource,
|
|
617
616
|
disconnectStreamSource: () => disconnectStreamSource,
|
|
@@ -619,7 +618,11 @@
|
|
|
619
618
|
fetchEnctypeFromString: () => fetchEnctypeFromString,
|
|
620
619
|
fetchMethodFromString: () => fetchMethodFromString,
|
|
621
620
|
isSafe: () => isSafe,
|
|
622
|
-
|
|
621
|
+
morphBodyElements: () => morphBodyElements,
|
|
622
|
+
morphChildren: () => morphChildren,
|
|
623
|
+
morphElements: () => morphElements,
|
|
624
|
+
morphTurboFrameElements: () => morphTurboFrameElements,
|
|
625
|
+
navigator: () => sessionNavigator,
|
|
623
626
|
registerAdapter: () => registerAdapter,
|
|
624
627
|
renderStreamMessage: () => renderStreamMessage,
|
|
625
628
|
session: () => session,
|
|
@@ -629,62 +632,6 @@
|
|
|
629
632
|
start: () => start,
|
|
630
633
|
visit: () => visit
|
|
631
634
|
});
|
|
632
|
-
(function(prototype) {
|
|
633
|
-
if (typeof prototype.requestSubmit == "function") return;
|
|
634
|
-
prototype.requestSubmit = function(submitter2) {
|
|
635
|
-
if (submitter2) {
|
|
636
|
-
validateSubmitter(submitter2, this);
|
|
637
|
-
submitter2.click();
|
|
638
|
-
} else {
|
|
639
|
-
submitter2 = document.createElement("input");
|
|
640
|
-
submitter2.type = "submit";
|
|
641
|
-
submitter2.hidden = true;
|
|
642
|
-
this.appendChild(submitter2);
|
|
643
|
-
submitter2.click();
|
|
644
|
-
this.removeChild(submitter2);
|
|
645
|
-
}
|
|
646
|
-
};
|
|
647
|
-
function validateSubmitter(submitter2, form) {
|
|
648
|
-
submitter2 instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
|
|
649
|
-
submitter2.type == "submit" || raise(TypeError, "The specified element is not a submit button");
|
|
650
|
-
submitter2.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
|
|
651
|
-
}
|
|
652
|
-
function raise(errorConstructor, message, name) {
|
|
653
|
-
throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name);
|
|
654
|
-
}
|
|
655
|
-
})(HTMLFormElement.prototype);
|
|
656
|
-
var submittersByForm = /* @__PURE__ */ new WeakMap();
|
|
657
|
-
function findSubmitterFromClickTarget(target) {
|
|
658
|
-
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
659
|
-
const candidate = element ? element.closest("input, button") : null;
|
|
660
|
-
return candidate?.type == "submit" ? candidate : null;
|
|
661
|
-
}
|
|
662
|
-
function clickCaptured(event) {
|
|
663
|
-
const submitter2 = findSubmitterFromClickTarget(event.target);
|
|
664
|
-
if (submitter2 && submitter2.form) {
|
|
665
|
-
submittersByForm.set(submitter2.form, submitter2);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
(function() {
|
|
669
|
-
if ("submitter" in Event.prototype) return;
|
|
670
|
-
let prototype = window.Event.prototype;
|
|
671
|
-
if ("SubmitEvent" in window) {
|
|
672
|
-
const prototypeOfSubmitEvent = window.SubmitEvent.prototype;
|
|
673
|
-
if (/Apple Computer/.test(navigator.vendor) && !("submitter" in prototypeOfSubmitEvent)) {
|
|
674
|
-
prototype = prototypeOfSubmitEvent;
|
|
675
|
-
} else {
|
|
676
|
-
return;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
addEventListener("click", clickCaptured, true);
|
|
680
|
-
Object.defineProperty(prototype, "submitter", {
|
|
681
|
-
get() {
|
|
682
|
-
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
683
|
-
return submittersByForm.get(this.target);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
});
|
|
687
|
-
})();
|
|
688
635
|
var FrameLoadingStyle = {
|
|
689
636
|
eager: "eager",
|
|
690
637
|
lazy: "lazy"
|
|
@@ -957,9 +904,6 @@
|
|
|
957
904
|
function nextEventLoopTick() {
|
|
958
905
|
return new Promise((resolve) => setTimeout(() => resolve(), 0));
|
|
959
906
|
}
|
|
960
|
-
function nextMicrotask() {
|
|
961
|
-
return Promise.resolve();
|
|
962
|
-
}
|
|
963
907
|
function parseHTMLDocument(html = "") {
|
|
964
908
|
return new DOMParser().parseFromString(html, "text/html");
|
|
965
909
|
}
|
|
@@ -984,7 +928,7 @@
|
|
|
984
928
|
} else if (i == 19) {
|
|
985
929
|
return (Math.floor(Math.random() * 4) + 8).toString(16);
|
|
986
930
|
} else {
|
|
987
|
-
return Math.floor(Math.random() *
|
|
931
|
+
return Math.floor(Math.random() * 16).toString(16);
|
|
988
932
|
}
|
|
989
933
|
}).join("");
|
|
990
934
|
}
|
|
@@ -1097,10 +1041,13 @@
|
|
|
1097
1041
|
}
|
|
1098
1042
|
}
|
|
1099
1043
|
function findLinkFromClickTarget(target) {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1044
|
+
const link = findClosestRecursively(target, "a[href], a[xlink\\:href]");
|
|
1045
|
+
if (!link) return null;
|
|
1046
|
+
if (link.href.startsWith("#")) return null;
|
|
1047
|
+
if (link.hasAttribute("download")) return null;
|
|
1048
|
+
const linkTarget = link.getAttribute("target");
|
|
1049
|
+
if (linkTarget && linkTarget !== "_self") return null;
|
|
1050
|
+
return link;
|
|
1104
1051
|
}
|
|
1105
1052
|
function debounce(fn, delay) {
|
|
1106
1053
|
let timeoutId = null;
|
|
@@ -1165,12 +1112,15 @@
|
|
|
1165
1112
|
return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
|
1166
1113
|
}
|
|
1167
1114
|
function isPrefixedBy(baseURL, url) {
|
|
1168
|
-
const prefix =
|
|
1169
|
-
return baseURL.href ===
|
|
1115
|
+
const prefix = addTrailingSlash(url.origin + url.pathname);
|
|
1116
|
+
return addTrailingSlash(baseURL.href) === prefix || baseURL.href.startsWith(prefix);
|
|
1170
1117
|
}
|
|
1171
1118
|
function locationIsVisitable(location2, rootLocation) {
|
|
1172
1119
|
return isPrefixedBy(location2, rootLocation) && !config.drive.unvisitableExtensions.has(getExtension(location2));
|
|
1173
1120
|
}
|
|
1121
|
+
function getLocationForLink(link) {
|
|
1122
|
+
return expandURL(link.getAttribute("href") || "");
|
|
1123
|
+
}
|
|
1174
1124
|
function getRequestURL(url) {
|
|
1175
1125
|
const anchor = getAnchor(url);
|
|
1176
1126
|
return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
|
|
@@ -1187,9 +1137,6 @@
|
|
|
1187
1137
|
function getLastPathComponent(url) {
|
|
1188
1138
|
return getPathComponents(url).slice(-1)[0];
|
|
1189
1139
|
}
|
|
1190
|
-
function getPrefix(url) {
|
|
1191
|
-
return addTrailingSlash(url.origin + url.pathname);
|
|
1192
|
-
}
|
|
1193
1140
|
function addTrailingSlash(value) {
|
|
1194
1141
|
return value.endsWith("/") ? value : value + "/";
|
|
1195
1142
|
}
|
|
@@ -1253,13 +1200,12 @@
|
|
|
1253
1200
|
}
|
|
1254
1201
|
};
|
|
1255
1202
|
var recentRequests = new LimitedSet(20);
|
|
1256
|
-
var nativeFetch = window.fetch;
|
|
1257
1203
|
function fetchWithTurboHeaders(url, options = {}) {
|
|
1258
1204
|
const modifiedHeaders = new Headers(options.headers || {});
|
|
1259
1205
|
const requestUID = uuid();
|
|
1260
1206
|
recentRequests.add(requestUID);
|
|
1261
1207
|
modifiedHeaders.append("X-Turbo-Request-Id", requestUID);
|
|
1262
|
-
return
|
|
1208
|
+
return window.fetch(url, {
|
|
1263
1209
|
...options,
|
|
1264
1210
|
headers: modifiedHeaders
|
|
1265
1211
|
});
|
|
@@ -1513,29 +1459,92 @@
|
|
|
1513
1459
|
}
|
|
1514
1460
|
return fragment;
|
|
1515
1461
|
}
|
|
1462
|
+
var identity = (key) => key;
|
|
1463
|
+
var LRUCache = class {
|
|
1464
|
+
keys = [];
|
|
1465
|
+
entries = {};
|
|
1466
|
+
#toCacheKey;
|
|
1467
|
+
constructor(size, toCacheKey2 = identity) {
|
|
1468
|
+
this.size = size;
|
|
1469
|
+
this.#toCacheKey = toCacheKey2;
|
|
1470
|
+
}
|
|
1471
|
+
has(key) {
|
|
1472
|
+
return this.#toCacheKey(key) in this.entries;
|
|
1473
|
+
}
|
|
1474
|
+
get(key) {
|
|
1475
|
+
if (this.has(key)) {
|
|
1476
|
+
const entry = this.read(key);
|
|
1477
|
+
this.touch(key);
|
|
1478
|
+
return entry;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
put(key, entry) {
|
|
1482
|
+
this.write(key, entry);
|
|
1483
|
+
this.touch(key);
|
|
1484
|
+
return entry;
|
|
1485
|
+
}
|
|
1486
|
+
clear() {
|
|
1487
|
+
for (const key of Object.keys(this.entries)) {
|
|
1488
|
+
this.evict(key);
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
// Private
|
|
1492
|
+
read(key) {
|
|
1493
|
+
return this.entries[this.#toCacheKey(key)];
|
|
1494
|
+
}
|
|
1495
|
+
write(key, entry) {
|
|
1496
|
+
this.entries[this.#toCacheKey(key)] = entry;
|
|
1497
|
+
}
|
|
1498
|
+
touch(key) {
|
|
1499
|
+
key = this.#toCacheKey(key);
|
|
1500
|
+
const index = this.keys.indexOf(key);
|
|
1501
|
+
if (index > -1) this.keys.splice(index, 1);
|
|
1502
|
+
this.keys.unshift(key);
|
|
1503
|
+
this.trim();
|
|
1504
|
+
}
|
|
1505
|
+
trim() {
|
|
1506
|
+
for (const key of this.keys.splice(this.size)) {
|
|
1507
|
+
this.evict(key);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
evict(key) {
|
|
1511
|
+
delete this.entries[key];
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1516
1514
|
var PREFETCH_DELAY = 100;
|
|
1517
|
-
var PrefetchCache = class {
|
|
1515
|
+
var PrefetchCache = class extends LRUCache {
|
|
1518
1516
|
#prefetchTimeout = null;
|
|
1519
|
-
#
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
}
|
|
1517
|
+
#maxAges = {};
|
|
1518
|
+
constructor(size = 1, prefetchDelay = PREFETCH_DELAY) {
|
|
1519
|
+
super(size, toCacheKey);
|
|
1520
|
+
this.prefetchDelay = prefetchDelay;
|
|
1524
1521
|
}
|
|
1525
|
-
|
|
1526
|
-
this.clear();
|
|
1522
|
+
putLater(url, request, ttl) {
|
|
1527
1523
|
this.#prefetchTimeout = setTimeout(() => {
|
|
1528
1524
|
request.perform();
|
|
1529
|
-
this.
|
|
1525
|
+
this.put(url, request, ttl);
|
|
1530
1526
|
this.#prefetchTimeout = null;
|
|
1531
|
-
},
|
|
1527
|
+
}, this.prefetchDelay);
|
|
1532
1528
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1529
|
+
put(url, request, ttl = cacheTtl) {
|
|
1530
|
+
super.put(url, request);
|
|
1531
|
+
this.#maxAges[toCacheKey(url)] = new Date((/* @__PURE__ */ new Date()).getTime() + ttl);
|
|
1535
1532
|
}
|
|
1536
1533
|
clear() {
|
|
1534
|
+
super.clear();
|
|
1537
1535
|
if (this.#prefetchTimeout) clearTimeout(this.#prefetchTimeout);
|
|
1538
|
-
|
|
1536
|
+
}
|
|
1537
|
+
evict(key) {
|
|
1538
|
+
super.evict(key);
|
|
1539
|
+
delete this.#maxAges[key];
|
|
1540
|
+
}
|
|
1541
|
+
has(key) {
|
|
1542
|
+
if (super.has(key)) {
|
|
1543
|
+
const maxAge = this.#maxAges[toCacheKey(key)];
|
|
1544
|
+
return maxAge && maxAge > Date.now();
|
|
1545
|
+
} else {
|
|
1546
|
+
return false;
|
|
1547
|
+
}
|
|
1539
1548
|
}
|
|
1540
1549
|
};
|
|
1541
1550
|
var cacheTtl = 10 * 1e3;
|
|
@@ -1849,8 +1858,8 @@
|
|
|
1849
1858
|
scrollToAnchor(anchor) {
|
|
1850
1859
|
const element = this.snapshot.getElementForAnchor(anchor);
|
|
1851
1860
|
if (element) {
|
|
1852
|
-
this.scrollToElement(element);
|
|
1853
1861
|
this.focusElement(element);
|
|
1862
|
+
this.scrollToElement(element);
|
|
1854
1863
|
} else {
|
|
1855
1864
|
this.scrollToPosition({ x: 0, y: 0 });
|
|
1856
1865
|
}
|
|
@@ -2311,9 +2320,6 @@
|
|
|
2311
2320
|
}
|
|
2312
2321
|
function morphOuterHTML(ctx, oldNode, newNode) {
|
|
2313
2322
|
const oldParent = normalizeParent(oldNode);
|
|
2314
|
-
let childNodes = Array.from(oldParent.childNodes);
|
|
2315
|
-
const index = childNodes.indexOf(oldNode);
|
|
2316
|
-
const rightMargin = childNodes.length - (index + 1);
|
|
2317
2323
|
morphChildren2(
|
|
2318
2324
|
ctx,
|
|
2319
2325
|
oldParent,
|
|
@@ -2324,8 +2330,7 @@
|
|
|
2324
2330
|
oldNode.nextSibling
|
|
2325
2331
|
// end point for iteration
|
|
2326
2332
|
);
|
|
2327
|
-
|
|
2328
|
-
return childNodes.slice(index, childNodes.length - rightMargin);
|
|
2333
|
+
return Array.from(oldParent.childNodes);
|
|
2329
2334
|
}
|
|
2330
2335
|
function saveAndRestoreFocus(ctx, fn) {
|
|
2331
2336
|
if (!ctx.config.restoreFocus) return fn();
|
|
@@ -2338,8 +2343,8 @@
|
|
|
2338
2343
|
}
|
|
2339
2344
|
const { id: activeElementId, selectionStart, selectionEnd } = activeElement;
|
|
2340
2345
|
const results = fn();
|
|
2341
|
-
if (activeElementId && activeElementId !== document.activeElement?.id) {
|
|
2342
|
-
activeElement = ctx.target.querySelector(
|
|
2346
|
+
if (activeElementId && activeElementId !== document.activeElement?.getAttribute("id")) {
|
|
2347
|
+
activeElement = ctx.target.querySelector(`[id="${activeElementId}"]`);
|
|
2343
2348
|
activeElement?.focus();
|
|
2344
2349
|
}
|
|
2345
2350
|
if (activeElement && !activeElement.selectionEnd && selectionEnd) {
|
|
@@ -2371,16 +2376,22 @@
|
|
|
2371
2376
|
continue;
|
|
2372
2377
|
}
|
|
2373
2378
|
}
|
|
2374
|
-
if (newChild instanceof Element
|
|
2375
|
-
const
|
|
2376
|
-
|
|
2377
|
-
newChild.id
|
|
2378
|
-
insertionPoint,
|
|
2379
|
-
ctx
|
|
2379
|
+
if (newChild instanceof Element) {
|
|
2380
|
+
const newChildId = (
|
|
2381
|
+
/** @type {String} */
|
|
2382
|
+
newChild.getAttribute("id")
|
|
2380
2383
|
);
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
+
if (ctx.persistentIds.has(newChildId)) {
|
|
2385
|
+
const movedChild = moveBeforeById(
|
|
2386
|
+
oldParent,
|
|
2387
|
+
newChildId,
|
|
2388
|
+
insertionPoint,
|
|
2389
|
+
ctx
|
|
2390
|
+
);
|
|
2391
|
+
morphNode(movedChild, newChild, ctx);
|
|
2392
|
+
insertionPoint = movedChild.nextSibling;
|
|
2393
|
+
continue;
|
|
2394
|
+
}
|
|
2384
2395
|
}
|
|
2385
2396
|
const insertedNode = createNode(
|
|
2386
2397
|
oldParent,
|
|
@@ -2440,7 +2451,7 @@
|
|
|
2440
2451
|
softMatch = void 0;
|
|
2441
2452
|
}
|
|
2442
2453
|
}
|
|
2443
|
-
if (
|
|
2454
|
+
if (ctx.activeElementAndParents.includes(cursor)) break;
|
|
2444
2455
|
cursor = cursor.nextSibling;
|
|
2445
2456
|
}
|
|
2446
2457
|
return softMatch || null;
|
|
@@ -2468,7 +2479,8 @@
|
|
|
2468
2479
|
return oldElt.nodeType === newElt.nodeType && oldElt.tagName === newElt.tagName && // If oldElt has an `id` with possible state and it doesn't match newElt.id then avoid morphing.
|
|
2469
2480
|
// We'll still match an anonymous node with an IDed newElt, though, because if it got this far,
|
|
2470
2481
|
// its not persistent, and new nodes can't have any hidden state.
|
|
2471
|
-
|
|
2482
|
+
// We can't use .id because of form input shadowing, and we can't count on .getAttribute's presence because it could be a document-fragment
|
|
2483
|
+
(!oldElt.getAttribute?.("id") || oldElt.getAttribute?.("id") === newElt.getAttribute?.("id"));
|
|
2472
2484
|
}
|
|
2473
2485
|
return findBestMatch2;
|
|
2474
2486
|
})();
|
|
@@ -2496,14 +2508,19 @@
|
|
|
2496
2508
|
function moveBeforeById(parentNode, id, after, ctx) {
|
|
2497
2509
|
const target = (
|
|
2498
2510
|
/** @type {Element} - will always be found */
|
|
2499
|
-
ctx.target.
|
|
2511
|
+
// ctx.target.id unsafe because of form input shadowing
|
|
2512
|
+
// ctx.target could be a document fragment which doesn't have `getAttribute`
|
|
2513
|
+
ctx.target.getAttribute?.("id") === id && ctx.target || ctx.target.querySelector(`[id="${id}"]`) || ctx.pantry.querySelector(`[id="${id}"]`)
|
|
2500
2514
|
);
|
|
2501
2515
|
removeElementFromAncestorsIdMaps(target, ctx);
|
|
2502
2516
|
moveBefore(parentNode, target, after);
|
|
2503
2517
|
return target;
|
|
2504
2518
|
}
|
|
2505
2519
|
function removeElementFromAncestorsIdMaps(element, ctx) {
|
|
2506
|
-
const id =
|
|
2520
|
+
const id = (
|
|
2521
|
+
/** @type {String} */
|
|
2522
|
+
element.getAttribute("id")
|
|
2523
|
+
);
|
|
2507
2524
|
while (element = element.parentNode) {
|
|
2508
2525
|
let idSet = ctx.idMap.get(element);
|
|
2509
2526
|
if (idSet) {
|
|
@@ -2767,6 +2784,7 @@
|
|
|
2767
2784
|
idMap,
|
|
2768
2785
|
persistentIds,
|
|
2769
2786
|
pantry: createPantry(),
|
|
2787
|
+
activeElementAndParents: createActiveElementAndParents(oldNode),
|
|
2770
2788
|
callbacks: mergedConfig.callbacks,
|
|
2771
2789
|
head: mergedConfig.head
|
|
2772
2790
|
};
|
|
@@ -2788,16 +2806,32 @@
|
|
|
2788
2806
|
document.body.insertAdjacentElement("afterend", pantry);
|
|
2789
2807
|
return pantry;
|
|
2790
2808
|
}
|
|
2809
|
+
function createActiveElementAndParents(oldNode) {
|
|
2810
|
+
let activeElementAndParents = [];
|
|
2811
|
+
let elt = document.activeElement;
|
|
2812
|
+
if (elt?.tagName !== "BODY" && oldNode.contains(elt)) {
|
|
2813
|
+
while (elt) {
|
|
2814
|
+
activeElementAndParents.push(elt);
|
|
2815
|
+
if (elt === oldNode) break;
|
|
2816
|
+
elt = elt.parentElement;
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
return activeElementAndParents;
|
|
2820
|
+
}
|
|
2791
2821
|
function findIdElements(root) {
|
|
2792
2822
|
let elements = Array.from(root.querySelectorAll("[id]"));
|
|
2793
|
-
if (root.id) {
|
|
2823
|
+
if (root.getAttribute?.("id")) {
|
|
2794
2824
|
elements.push(root);
|
|
2795
2825
|
}
|
|
2796
2826
|
return elements;
|
|
2797
2827
|
}
|
|
2798
2828
|
function populateIdMapWithTree(idMap, persistentIds, root, elements) {
|
|
2799
2829
|
for (const elt of elements) {
|
|
2800
|
-
|
|
2830
|
+
const id = (
|
|
2831
|
+
/** @type {String} */
|
|
2832
|
+
elt.getAttribute("id")
|
|
2833
|
+
);
|
|
2834
|
+
if (persistentIds.has(id)) {
|
|
2801
2835
|
let current = elt;
|
|
2802
2836
|
while (current) {
|
|
2803
2837
|
let idSet = idMap.get(current);
|
|
@@ -2805,7 +2839,7 @@
|
|
|
2805
2839
|
idSet = /* @__PURE__ */ new Set();
|
|
2806
2840
|
idMap.set(current, idSet);
|
|
2807
2841
|
}
|
|
2808
|
-
idSet.add(
|
|
2842
|
+
idSet.add(id);
|
|
2809
2843
|
if (current === root) break;
|
|
2810
2844
|
current = current.parentElement;
|
|
2811
2845
|
}
|
|
@@ -2871,7 +2905,10 @@
|
|
|
2871
2905
|
);
|
|
2872
2906
|
} else if (newContent instanceof Node) {
|
|
2873
2907
|
if (newContent.parentNode) {
|
|
2874
|
-
return
|
|
2908
|
+
return (
|
|
2909
|
+
/** @type {any} */
|
|
2910
|
+
new SlicedParentNode(newContent)
|
|
2911
|
+
);
|
|
2875
2912
|
} else {
|
|
2876
2913
|
const dummyParent = document.createElement("div");
|
|
2877
2914
|
dummyParent.append(newContent);
|
|
@@ -2885,27 +2922,68 @@
|
|
|
2885
2922
|
return dummyParent;
|
|
2886
2923
|
}
|
|
2887
2924
|
}
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
{
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
get __idiomorphRoot() {
|
|
2905
|
-
return newContent;
|
|
2906
|
-
}
|
|
2925
|
+
class SlicedParentNode {
|
|
2926
|
+
/** @param {Node} node */
|
|
2927
|
+
constructor(node) {
|
|
2928
|
+
this.originalNode = node;
|
|
2929
|
+
this.realParentNode = /** @type {Element} */
|
|
2930
|
+
node.parentNode;
|
|
2931
|
+
this.previousSibling = node.previousSibling;
|
|
2932
|
+
this.nextSibling = node.nextSibling;
|
|
2933
|
+
}
|
|
2934
|
+
/** @returns {Node[]} */
|
|
2935
|
+
get childNodes() {
|
|
2936
|
+
const nodes = [];
|
|
2937
|
+
let cursor = this.previousSibling ? this.previousSibling.nextSibling : this.realParentNode.firstChild;
|
|
2938
|
+
while (cursor && cursor != this.nextSibling) {
|
|
2939
|
+
nodes.push(cursor);
|
|
2940
|
+
cursor = cursor.nextSibling;
|
|
2907
2941
|
}
|
|
2908
|
-
|
|
2942
|
+
return nodes;
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* @param {string} selector
|
|
2946
|
+
* @returns {Element[]}
|
|
2947
|
+
*/
|
|
2948
|
+
querySelectorAll(selector) {
|
|
2949
|
+
return this.childNodes.reduce(
|
|
2950
|
+
(results, node) => {
|
|
2951
|
+
if (node instanceof Element) {
|
|
2952
|
+
if (node.matches(selector)) results.push(node);
|
|
2953
|
+
const nodeList = node.querySelectorAll(selector);
|
|
2954
|
+
for (let i = 0; i < nodeList.length; i++) {
|
|
2955
|
+
results.push(nodeList[i]);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
return results;
|
|
2959
|
+
},
|
|
2960
|
+
/** @type {Element[]} */
|
|
2961
|
+
[]
|
|
2962
|
+
);
|
|
2963
|
+
}
|
|
2964
|
+
/**
|
|
2965
|
+
* @param {Node} node
|
|
2966
|
+
* @param {Node} referenceNode
|
|
2967
|
+
* @returns {Node}
|
|
2968
|
+
*/
|
|
2969
|
+
insertBefore(node, referenceNode) {
|
|
2970
|
+
return this.realParentNode.insertBefore(node, referenceNode);
|
|
2971
|
+
}
|
|
2972
|
+
/**
|
|
2973
|
+
* @param {Node} node
|
|
2974
|
+
* @param {Node} referenceNode
|
|
2975
|
+
* @returns {Node}
|
|
2976
|
+
*/
|
|
2977
|
+
moveBefore(node, referenceNode) {
|
|
2978
|
+
return this.realParentNode.moveBefore(node, referenceNode);
|
|
2979
|
+
}
|
|
2980
|
+
/**
|
|
2981
|
+
* for later use with populateIdMapWithTree to halt upwards iteration
|
|
2982
|
+
* @returns {Node}
|
|
2983
|
+
*/
|
|
2984
|
+
get __idiomorphRoot() {
|
|
2985
|
+
return this.originalNode;
|
|
2986
|
+
}
|
|
2909
2987
|
}
|
|
2910
2988
|
function parseContent(newContent) {
|
|
2911
2989
|
let parser = new DOMParser();
|
|
@@ -2951,11 +3029,21 @@
|
|
|
2951
3029
|
callbacks: new DefaultIdiomorphCallbacks(callbacks)
|
|
2952
3030
|
});
|
|
2953
3031
|
}
|
|
2954
|
-
function morphChildren(currentElement, newElement) {
|
|
3032
|
+
function morphChildren(currentElement, newElement, options = {}) {
|
|
2955
3033
|
morphElements(currentElement, newElement.childNodes, {
|
|
3034
|
+
...options,
|
|
2956
3035
|
morphStyle: "innerHTML"
|
|
2957
3036
|
});
|
|
2958
3037
|
}
|
|
3038
|
+
function shouldRefreshFrameWithMorphing(currentFrame, newFrame) {
|
|
3039
|
+
return currentFrame instanceof FrameElement && currentFrame.shouldReloadWithMorph && (!newFrame || areFramesCompatibleForRefreshing(currentFrame, newFrame)) && !currentFrame.closest("[data-turbo-permanent]");
|
|
3040
|
+
}
|
|
3041
|
+
function areFramesCompatibleForRefreshing(currentFrame, newFrame) {
|
|
3042
|
+
return newFrame instanceof Element && newFrame.nodeName === "TURBO-FRAME" && currentFrame.id === newFrame.id && (!newFrame.getAttribute("src") || urlsAreEqual(currentFrame.src, newFrame.getAttribute("src")));
|
|
3043
|
+
}
|
|
3044
|
+
function closestFrameReloadableWithMorphing(node) {
|
|
3045
|
+
return node.parentElement.closest("turbo-frame[src][refresh=morph]");
|
|
3046
|
+
}
|
|
2959
3047
|
var DefaultIdiomorphCallbacks = class {
|
|
2960
3048
|
#beforeNodeMorphed;
|
|
2961
3049
|
constructor({ beforeNodeMorphed } = {}) {
|
|
@@ -3004,7 +3092,17 @@
|
|
|
3004
3092
|
target: currentElement,
|
|
3005
3093
|
detail: { currentElement, newElement }
|
|
3006
3094
|
});
|
|
3007
|
-
morphChildren(currentElement, newElement
|
|
3095
|
+
morphChildren(currentElement, newElement, {
|
|
3096
|
+
callbacks: {
|
|
3097
|
+
beforeNodeMorphed: (node, newNode) => {
|
|
3098
|
+
if (shouldRefreshFrameWithMorphing(node, newNode) && closestFrameReloadableWithMorphing(node) === currentElement) {
|
|
3099
|
+
node.reload();
|
|
3100
|
+
return false;
|
|
3101
|
+
}
|
|
3102
|
+
return true;
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
});
|
|
3008
3106
|
}
|
|
3009
3107
|
async preservingPermanentElements(callback) {
|
|
3010
3108
|
return await callback();
|
|
@@ -3225,11 +3323,17 @@
|
|
|
3225
3323
|
for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
|
|
3226
3324
|
clonedPasswordInput.value = "";
|
|
3227
3325
|
}
|
|
3326
|
+
for (const clonedNoscriptElement of clonedElement.querySelectorAll("noscript")) {
|
|
3327
|
+
clonedNoscriptElement.remove();
|
|
3328
|
+
}
|
|
3228
3329
|
return new _PageSnapshot(this.documentElement, clonedElement, this.headSnapshot);
|
|
3229
3330
|
}
|
|
3230
3331
|
get lang() {
|
|
3231
3332
|
return this.documentElement.getAttribute("lang");
|
|
3232
3333
|
}
|
|
3334
|
+
get dir() {
|
|
3335
|
+
return this.documentElement.getAttribute("dir");
|
|
3336
|
+
}
|
|
3233
3337
|
get headElement() {
|
|
3234
3338
|
return this.headSnapshot.element;
|
|
3235
3339
|
}
|
|
@@ -3250,13 +3354,14 @@
|
|
|
3250
3354
|
return this.getSetting("visit-control") != "reload";
|
|
3251
3355
|
}
|
|
3252
3356
|
get prefersViewTransitions() {
|
|
3253
|
-
|
|
3357
|
+
const viewTransitionEnabled = this.getSetting("view-transition") === "true" || this.headSnapshot.getMetaValue("view-transition") === "same-origin";
|
|
3358
|
+
return viewTransitionEnabled && !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
3254
3359
|
}
|
|
3255
|
-
get
|
|
3256
|
-
return this.getSetting("refresh-method")
|
|
3360
|
+
get refreshMethod() {
|
|
3361
|
+
return this.getSetting("refresh-method");
|
|
3257
3362
|
}
|
|
3258
|
-
get
|
|
3259
|
-
return this.getSetting("refresh-scroll")
|
|
3363
|
+
get refreshScroll() {
|
|
3364
|
+
return this.getSetting("refresh-scroll");
|
|
3260
3365
|
}
|
|
3261
3366
|
// Private
|
|
3262
3367
|
getSetting(name) {
|
|
@@ -3289,7 +3394,8 @@
|
|
|
3289
3394
|
willRender: true,
|
|
3290
3395
|
updateHistory: true,
|
|
3291
3396
|
shouldCacheSnapshot: true,
|
|
3292
|
-
acceptsStreamResponse: false
|
|
3397
|
+
acceptsStreamResponse: false,
|
|
3398
|
+
refresh: {}
|
|
3293
3399
|
};
|
|
3294
3400
|
var TimingMetric = {
|
|
3295
3401
|
visitStart: "visitStart",
|
|
@@ -3342,7 +3448,8 @@
|
|
|
3342
3448
|
updateHistory,
|
|
3343
3449
|
shouldCacheSnapshot,
|
|
3344
3450
|
acceptsStreamResponse,
|
|
3345
|
-
direction
|
|
3451
|
+
direction,
|
|
3452
|
+
refresh
|
|
3346
3453
|
} = {
|
|
3347
3454
|
...defaultOptions,
|
|
3348
3455
|
...options
|
|
@@ -3353,7 +3460,6 @@
|
|
|
3353
3460
|
this.snapshot = snapshot;
|
|
3354
3461
|
this.snapshotHTML = snapshotHTML;
|
|
3355
3462
|
this.response = response;
|
|
3356
|
-
this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
|
3357
3463
|
this.isPageRefresh = this.view.isPageRefresh(this);
|
|
3358
3464
|
this.visitCachedSnapshot = visitCachedSnapshot;
|
|
3359
3465
|
this.willRender = willRender;
|
|
@@ -3362,6 +3468,7 @@
|
|
|
3362
3468
|
this.shouldCacheSnapshot = shouldCacheSnapshot;
|
|
3363
3469
|
this.acceptsStreamResponse = acceptsStreamResponse;
|
|
3364
3470
|
this.direction = direction || Direction[action];
|
|
3471
|
+
this.refresh = refresh;
|
|
3365
3472
|
}
|
|
3366
3473
|
get adapter() {
|
|
3367
3474
|
return this.delegate.adapter;
|
|
@@ -3375,9 +3482,6 @@
|
|
|
3375
3482
|
get restorationData() {
|
|
3376
3483
|
return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
|
|
3377
3484
|
}
|
|
3378
|
-
get silent() {
|
|
3379
|
-
return this.isSamePage;
|
|
3380
|
-
}
|
|
3381
3485
|
start() {
|
|
3382
3486
|
if (this.state == VisitState.initialized) {
|
|
3383
3487
|
this.recordTimingMetric(TimingMetric.visitStart);
|
|
@@ -3496,7 +3600,7 @@
|
|
|
3496
3600
|
const isPreview = this.shouldIssueRequest();
|
|
3497
3601
|
this.render(async () => {
|
|
3498
3602
|
this.cacheSnapshot();
|
|
3499
|
-
if (this.
|
|
3603
|
+
if (this.isPageRefresh) {
|
|
3500
3604
|
this.adapter.visitRendered(this);
|
|
3501
3605
|
} else {
|
|
3502
3606
|
if (this.view.renderPromise) await this.view.renderPromise;
|
|
@@ -3520,16 +3624,6 @@
|
|
|
3520
3624
|
this.followedRedirect = true;
|
|
3521
3625
|
}
|
|
3522
3626
|
}
|
|
3523
|
-
goToSamePageAnchor() {
|
|
3524
|
-
if (this.isSamePage) {
|
|
3525
|
-
this.render(async () => {
|
|
3526
|
-
this.cacheSnapshot();
|
|
3527
|
-
this.performScroll();
|
|
3528
|
-
this.changeHistory();
|
|
3529
|
-
this.adapter.visitRendered(this);
|
|
3530
|
-
});
|
|
3531
|
-
}
|
|
3532
|
-
}
|
|
3533
3627
|
// Fetch request delegate
|
|
3534
3628
|
prepareRequest(request) {
|
|
3535
3629
|
if (this.acceptsStreamResponse) {
|
|
@@ -3583,9 +3677,6 @@
|
|
|
3583
3677
|
} else {
|
|
3584
3678
|
this.scrollToAnchor() || this.view.scrollToTop();
|
|
3585
3679
|
}
|
|
3586
|
-
if (this.isSamePage) {
|
|
3587
|
-
this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);
|
|
3588
|
-
}
|
|
3589
3680
|
this.scrolled = true;
|
|
3590
3681
|
}
|
|
3591
3682
|
}
|
|
@@ -3615,9 +3706,7 @@
|
|
|
3615
3706
|
return typeof this.response == "object";
|
|
3616
3707
|
}
|
|
3617
3708
|
shouldIssueRequest() {
|
|
3618
|
-
if (this.
|
|
3619
|
-
return false;
|
|
3620
|
-
} else if (this.action == "restore") {
|
|
3709
|
+
if (this.action == "restore") {
|
|
3621
3710
|
return !this.hasCachedSnapshot();
|
|
3622
3711
|
} else {
|
|
3623
3712
|
return this.willRender;
|
|
@@ -3667,9 +3756,9 @@
|
|
|
3667
3756
|
}
|
|
3668
3757
|
visitStarted(visit2) {
|
|
3669
3758
|
this.location = visit2.location;
|
|
3759
|
+
this.redirectedToLocation = null;
|
|
3670
3760
|
visit2.loadCachedSnapshot();
|
|
3671
3761
|
visit2.issueRequest();
|
|
3672
|
-
visit2.goToSamePageAnchor();
|
|
3673
3762
|
}
|
|
3674
3763
|
visitRequestStarted(visit2) {
|
|
3675
3764
|
this.progressBar.setValue(0);
|
|
@@ -3681,6 +3770,9 @@
|
|
|
3681
3770
|
}
|
|
3682
3771
|
visitRequestCompleted(visit2) {
|
|
3683
3772
|
visit2.loadResponse();
|
|
3773
|
+
if (visit2.response.redirected) {
|
|
3774
|
+
this.redirectedToLocation = visit2.redirectedToLocation;
|
|
3775
|
+
}
|
|
3684
3776
|
}
|
|
3685
3777
|
visitRequestFailedWithStatusCode(visit2, statusCode) {
|
|
3686
3778
|
switch (statusCode) {
|
|
@@ -3753,7 +3845,7 @@
|
|
|
3753
3845
|
};
|
|
3754
3846
|
reload(reason) {
|
|
3755
3847
|
dispatch("turbo:reload", { detail: reason });
|
|
3756
|
-
window.location.href = this.location?.toString() || window.location.href;
|
|
3848
|
+
window.location.href = (this.redirectedToLocation || this.location)?.toString() || window.location.href;
|
|
3757
3849
|
}
|
|
3758
3850
|
get navigator() {
|
|
3759
3851
|
return this.session.navigator;
|
|
@@ -3761,7 +3853,6 @@
|
|
|
3761
3853
|
};
|
|
3762
3854
|
var CacheObserver = class {
|
|
3763
3855
|
selector = "[data-turbo-temporary]";
|
|
3764
|
-
deprecatedSelector = "[data-turbo-cache=false]";
|
|
3765
3856
|
started = false;
|
|
3766
3857
|
start() {
|
|
3767
3858
|
if (!this.started) {
|
|
@@ -3781,16 +3872,7 @@
|
|
|
3781
3872
|
}
|
|
3782
3873
|
};
|
|
3783
3874
|
get temporaryElements() {
|
|
3784
|
-
return [...document.querySelectorAll(this.selector)
|
|
3785
|
-
}
|
|
3786
|
-
get temporaryElementsWithDeprecation() {
|
|
3787
|
-
const elements = document.querySelectorAll(this.deprecatedSelector);
|
|
3788
|
-
if (elements.length) {
|
|
3789
|
-
console.warn(
|
|
3790
|
-
`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`
|
|
3791
|
-
);
|
|
3792
|
-
}
|
|
3793
|
-
return [...elements];
|
|
3875
|
+
return [...document.querySelectorAll(this.selector)];
|
|
3794
3876
|
}
|
|
3795
3877
|
};
|
|
3796
3878
|
var FrameRedirector = class {
|
|
@@ -3858,7 +3940,6 @@
|
|
|
3858
3940
|
restorationIdentifier = uuid();
|
|
3859
3941
|
restorationData = {};
|
|
3860
3942
|
started = false;
|
|
3861
|
-
pageLoaded = false;
|
|
3862
3943
|
currentIndex = 0;
|
|
3863
3944
|
constructor(delegate) {
|
|
3864
3945
|
this.delegate = delegate;
|
|
@@ -3866,7 +3947,6 @@
|
|
|
3866
3947
|
start() {
|
|
3867
3948
|
if (!this.started) {
|
|
3868
3949
|
addEventListener("popstate", this.onPopState, false);
|
|
3869
|
-
addEventListener("load", this.onPageLoad, false);
|
|
3870
3950
|
this.currentIndex = history.state?.turbo?.restorationIndex || 0;
|
|
3871
3951
|
this.started = true;
|
|
3872
3952
|
this.replace(new URL(window.location.href));
|
|
@@ -3875,7 +3955,6 @@
|
|
|
3875
3955
|
stop() {
|
|
3876
3956
|
if (this.started) {
|
|
3877
3957
|
removeEventListener("popstate", this.onPopState, false);
|
|
3878
|
-
removeEventListener("load", this.onPageLoad, false);
|
|
3879
3958
|
this.started = false;
|
|
3880
3959
|
}
|
|
3881
3960
|
}
|
|
@@ -3919,29 +3998,19 @@
|
|
|
3919
3998
|
}
|
|
3920
3999
|
// Event handlers
|
|
3921
4000
|
onPopState = (event) => {
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
4001
|
+
const { turbo } = event.state || {};
|
|
4002
|
+
this.location = new URL(window.location.href);
|
|
4003
|
+
if (turbo) {
|
|
4004
|
+
const { restorationIdentifier, restorationIndex } = turbo;
|
|
4005
|
+
this.restorationIdentifier = restorationIdentifier;
|
|
4006
|
+
const direction = restorationIndex > this.currentIndex ? "forward" : "back";
|
|
4007
|
+
this.delegate.historyPoppedToLocationWithRestorationIdentifierAndDirection(this.location, restorationIdentifier, direction);
|
|
4008
|
+
this.currentIndex = restorationIndex;
|
|
4009
|
+
} else {
|
|
4010
|
+
this.currentIndex++;
|
|
4011
|
+
this.delegate.historyPoppedWithEmptyState(this.location);
|
|
3932
4012
|
}
|
|
3933
4013
|
};
|
|
3934
|
-
onPageLoad = async (_event) => {
|
|
3935
|
-
await nextMicrotask();
|
|
3936
|
-
this.pageLoaded = true;
|
|
3937
|
-
};
|
|
3938
|
-
// Private
|
|
3939
|
-
shouldHandlePopState() {
|
|
3940
|
-
return this.pageIsLoaded();
|
|
3941
|
-
}
|
|
3942
|
-
pageIsLoaded() {
|
|
3943
|
-
return this.pageLoaded || document.readyState == "complete";
|
|
3944
|
-
}
|
|
3945
4014
|
};
|
|
3946
4015
|
var LinkPrefetchObserver = class {
|
|
3947
4016
|
started = false;
|
|
@@ -3999,7 +4068,8 @@
|
|
|
3999
4068
|
new URLSearchParams(),
|
|
4000
4069
|
target
|
|
4001
4070
|
);
|
|
4002
|
-
|
|
4071
|
+
fetchRequest.fetchOptions.priority = "low";
|
|
4072
|
+
prefetchCache.putLater(location2, fetchRequest, this.#cacheTtl);
|
|
4003
4073
|
}
|
|
4004
4074
|
}
|
|
4005
4075
|
};
|
|
@@ -4012,7 +4082,7 @@
|
|
|
4012
4082
|
};
|
|
4013
4083
|
#tryToUsePrefetchedRequest = (event) => {
|
|
4014
4084
|
if (event.target.tagName !== "FORM" && event.detail.fetchOptions.method === "GET") {
|
|
4015
|
-
const cached = prefetchCache.get(event.detail.url
|
|
4085
|
+
const cached = prefetchCache.get(event.detail.url);
|
|
4016
4086
|
if (cached) {
|
|
4017
4087
|
event.detail.fetchRequest = cached;
|
|
4018
4088
|
}
|
|
@@ -4161,7 +4231,7 @@
|
|
|
4161
4231
|
} else {
|
|
4162
4232
|
await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
|
4163
4233
|
}
|
|
4164
|
-
if (
|
|
4234
|
+
if (snapshot.refreshScroll !== "preserve") {
|
|
4165
4235
|
this.view.scrollToTop();
|
|
4166
4236
|
}
|
|
4167
4237
|
this.view.clearSnapshotCache();
|
|
@@ -4190,14 +4260,10 @@
|
|
|
4190
4260
|
this.delegate.visitCompleted(visit2);
|
|
4191
4261
|
delete this.currentVisit;
|
|
4192
4262
|
}
|
|
4263
|
+
// Same-page links are no longer handled with a Visit.
|
|
4264
|
+
// This method is still needed for Turbo Native adapters.
|
|
4193
4265
|
locationWithActionIsSamePage(location2, action) {
|
|
4194
|
-
|
|
4195
|
-
const currentAnchor = getAnchor(this.view.lastRenderedLocation);
|
|
4196
|
-
const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
|
4197
|
-
return action !== "replace" && getRequestURL(location2) === getRequestURL(this.view.lastRenderedLocation) && (isRestorationToTop || anchor != null && anchor !== currentAnchor);
|
|
4198
|
-
}
|
|
4199
|
-
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
4200
|
-
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
|
4266
|
+
return false;
|
|
4201
4267
|
}
|
|
4202
4268
|
// Visits
|
|
4203
4269
|
get location() {
|
|
@@ -4516,12 +4582,17 @@
|
|
|
4516
4582
|
}
|
|
4517
4583
|
#setLanguage() {
|
|
4518
4584
|
const { documentElement } = this.currentSnapshot;
|
|
4519
|
-
const { lang } = this.newSnapshot;
|
|
4585
|
+
const { dir, lang } = this.newSnapshot;
|
|
4520
4586
|
if (lang) {
|
|
4521
4587
|
documentElement.setAttribute("lang", lang);
|
|
4522
4588
|
} else {
|
|
4523
4589
|
documentElement.removeAttribute("lang");
|
|
4524
4590
|
}
|
|
4591
|
+
if (dir) {
|
|
4592
|
+
documentElement.setAttribute("dir", dir);
|
|
4593
|
+
} else {
|
|
4594
|
+
documentElement.removeAttribute("dir");
|
|
4595
|
+
}
|
|
4525
4596
|
}
|
|
4526
4597
|
async mergeHead() {
|
|
4527
4598
|
const mergedHeadElements = this.mergeProvisionalElements();
|
|
@@ -4601,8 +4672,14 @@
|
|
|
4601
4672
|
}
|
|
4602
4673
|
activateNewBody() {
|
|
4603
4674
|
document.adoptNode(this.newElement);
|
|
4675
|
+
this.removeNoscriptElements();
|
|
4604
4676
|
this.activateNewBodyScriptElements();
|
|
4605
4677
|
}
|
|
4678
|
+
removeNoscriptElements() {
|
|
4679
|
+
for (const noscriptElement of this.newElement.querySelectorAll("noscript")) {
|
|
4680
|
+
noscriptElement.remove();
|
|
4681
|
+
}
|
|
4682
|
+
}
|
|
4606
4683
|
activateNewBodyScriptElements() {
|
|
4607
4684
|
for (const inertScriptElement of this.newBodyScriptElements) {
|
|
4608
4685
|
const activatedScriptElement = activateScriptElement(inertScriptElement);
|
|
@@ -4640,12 +4717,15 @@
|
|
|
4640
4717
|
static renderElement(currentElement, newElement) {
|
|
4641
4718
|
morphElements(currentElement, newElement, {
|
|
4642
4719
|
callbacks: {
|
|
4643
|
-
beforeNodeMorphed: (
|
|
4720
|
+
beforeNodeMorphed: (node, newNode) => {
|
|
4721
|
+
if (shouldRefreshFrameWithMorphing(node, newNode) && !closestFrameReloadableWithMorphing(node)) {
|
|
4722
|
+
node.reload();
|
|
4723
|
+
return false;
|
|
4724
|
+
}
|
|
4725
|
+
return true;
|
|
4726
|
+
}
|
|
4644
4727
|
}
|
|
4645
4728
|
});
|
|
4646
|
-
for (const frame of currentElement.querySelectorAll("turbo-frame")) {
|
|
4647
|
-
if (canRefreshFrame(frame)) frame.reload();
|
|
4648
|
-
}
|
|
4649
4729
|
dispatch("turbo:morph", { detail: { currentElement, newElement } });
|
|
4650
4730
|
}
|
|
4651
4731
|
async preservingPermanentElements(callback) {
|
|
@@ -4658,51 +4738,12 @@
|
|
|
4658
4738
|
return false;
|
|
4659
4739
|
}
|
|
4660
4740
|
};
|
|
4661
|
-
|
|
4662
|
-
return frame instanceof FrameElement && frame.src && frame.refresh === "morph" && !frame.closest("[data-turbo-permanent]");
|
|
4663
|
-
}
|
|
4664
|
-
var SnapshotCache = class {
|
|
4665
|
-
keys = [];
|
|
4666
|
-
snapshots = {};
|
|
4741
|
+
var SnapshotCache = class extends LRUCache {
|
|
4667
4742
|
constructor(size) {
|
|
4668
|
-
|
|
4669
|
-
}
|
|
4670
|
-
has(location2) {
|
|
4671
|
-
return toCacheKey(location2) in this.snapshots;
|
|
4672
|
-
}
|
|
4673
|
-
get(location2) {
|
|
4674
|
-
if (this.has(location2)) {
|
|
4675
|
-
const snapshot = this.read(location2);
|
|
4676
|
-
this.touch(location2);
|
|
4677
|
-
return snapshot;
|
|
4678
|
-
}
|
|
4679
|
-
}
|
|
4680
|
-
put(location2, snapshot) {
|
|
4681
|
-
this.write(location2, snapshot);
|
|
4682
|
-
this.touch(location2);
|
|
4683
|
-
return snapshot;
|
|
4743
|
+
super(size, toCacheKey);
|
|
4684
4744
|
}
|
|
4685
|
-
|
|
4686
|
-
this.
|
|
4687
|
-
}
|
|
4688
|
-
// Private
|
|
4689
|
-
read(location2) {
|
|
4690
|
-
return this.snapshots[toCacheKey(location2)];
|
|
4691
|
-
}
|
|
4692
|
-
write(location2, snapshot) {
|
|
4693
|
-
this.snapshots[toCacheKey(location2)] = snapshot;
|
|
4694
|
-
}
|
|
4695
|
-
touch(location2) {
|
|
4696
|
-
const key = toCacheKey(location2);
|
|
4697
|
-
const index = this.keys.indexOf(key);
|
|
4698
|
-
if (index > -1) this.keys.splice(index, 1);
|
|
4699
|
-
this.keys.unshift(key);
|
|
4700
|
-
this.trim();
|
|
4701
|
-
}
|
|
4702
|
-
trim() {
|
|
4703
|
-
for (const key of this.keys.splice(this.size)) {
|
|
4704
|
-
delete this.snapshots[key];
|
|
4705
|
-
}
|
|
4745
|
+
get snapshots() {
|
|
4746
|
+
return this.entries;
|
|
4706
4747
|
}
|
|
4707
4748
|
};
|
|
4708
4749
|
var PageView = class extends View {
|
|
@@ -4713,7 +4754,7 @@
|
|
|
4713
4754
|
return this.snapshot.prefersViewTransitions && newSnapshot.prefersViewTransitions;
|
|
4714
4755
|
}
|
|
4715
4756
|
renderPage(snapshot, isPreview = false, willRender = true, visit2) {
|
|
4716
|
-
const shouldMorphPage = this.isPageRefresh(visit2) && this.snapshot.
|
|
4757
|
+
const shouldMorphPage = this.isPageRefresh(visit2) && (visit2?.refresh?.method || this.snapshot.refreshMethod) === "morph";
|
|
4717
4758
|
const rendererClass = shouldMorphPage ? MorphingPageRenderer : PageRenderer;
|
|
4718
4759
|
const renderer = new rendererClass(this.snapshot, snapshot, isPreview, willRender);
|
|
4719
4760
|
if (!renderer.shouldRender) {
|
|
@@ -4748,7 +4789,7 @@
|
|
|
4748
4789
|
return !visit2 || this.lastRenderedLocation.pathname === visit2.location.pathname && visit2.action === "replace";
|
|
4749
4790
|
}
|
|
4750
4791
|
shouldPreserveScrollPosition(visit2) {
|
|
4751
|
-
return this.isPageRefresh(visit2) && this.snapshot.
|
|
4792
|
+
return this.isPageRefresh(visit2) && (visit2?.refresh?.scroll || this.snapshot.refreshScroll) === "preserve";
|
|
4752
4793
|
}
|
|
4753
4794
|
get snapshot() {
|
|
4754
4795
|
return PageSnapshot.fromElement(this.element);
|
|
@@ -4905,11 +4946,13 @@
|
|
|
4905
4946
|
this.navigator.proposeVisit(expandURL(location2), options);
|
|
4906
4947
|
}
|
|
4907
4948
|
}
|
|
4908
|
-
refresh(url,
|
|
4949
|
+
refresh(url, options = {}) {
|
|
4950
|
+
options = typeof options === "string" ? { requestId: options } : options;
|
|
4951
|
+
const { method, requestId, scroll } = options;
|
|
4909
4952
|
const isRecentRequest = requestId && this.recentRequests.has(requestId);
|
|
4910
4953
|
const isCurrentUrl = url === document.baseURI;
|
|
4911
4954
|
if (!isRecentRequest && !this.navigator.currentVisit && isCurrentUrl) {
|
|
4912
|
-
this.visit(url, { action: "replace", shouldCacheSnapshot: false });
|
|
4955
|
+
this.visit(url, { action: "replace", shouldCacheSnapshot: false, refresh: { method, scroll } });
|
|
4913
4956
|
}
|
|
4914
4957
|
}
|
|
4915
4958
|
connectStreamSource(source) {
|
|
@@ -4988,6 +5031,11 @@
|
|
|
4988
5031
|
});
|
|
4989
5032
|
}
|
|
4990
5033
|
}
|
|
5034
|
+
historyPoppedWithEmptyState(location2) {
|
|
5035
|
+
this.history.replace(location2);
|
|
5036
|
+
this.view.lastRenderedLocation = location2;
|
|
5037
|
+
this.view.cacheSnapshot();
|
|
5038
|
+
}
|
|
4991
5039
|
// Scroll observer delegate
|
|
4992
5040
|
scrollPositionChanged(position) {
|
|
4993
5041
|
this.history.updateRestorationData({ scrollPosition: position });
|
|
@@ -5013,7 +5061,7 @@
|
|
|
5013
5061
|
}
|
|
5014
5062
|
// Navigator delegate
|
|
5015
5063
|
allowsVisitingLocationWithAction(location2, action) {
|
|
5016
|
-
return this.
|
|
5064
|
+
return this.applicationAllowsVisitingLocation(location2);
|
|
5017
5065
|
}
|
|
5018
5066
|
visitProposedToLocation(location2, options) {
|
|
5019
5067
|
extendURLWithDeprecatedProperties(location2);
|
|
@@ -5026,21 +5074,13 @@
|
|
|
5026
5074
|
this.view.markVisitDirection(visit2.direction);
|
|
5027
5075
|
}
|
|
5028
5076
|
extendURLWithDeprecatedProperties(visit2.location);
|
|
5029
|
-
|
|
5030
|
-
this.notifyApplicationAfterVisitingLocation(visit2.location, visit2.action);
|
|
5031
|
-
}
|
|
5077
|
+
this.notifyApplicationAfterVisitingLocation(visit2.location, visit2.action);
|
|
5032
5078
|
}
|
|
5033
5079
|
visitCompleted(visit2) {
|
|
5034
5080
|
this.view.unmarkVisitDirection();
|
|
5035
5081
|
clearBusyState(document.documentElement);
|
|
5036
5082
|
this.notifyApplicationAfterPageLoad(visit2.getTimingMetrics());
|
|
5037
5083
|
}
|
|
5038
|
-
locationWithActionIsSamePage(location2, action) {
|
|
5039
|
-
return this.navigator.locationWithActionIsSamePage(location2, action);
|
|
5040
|
-
}
|
|
5041
|
-
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
5042
|
-
this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
|
5043
|
-
}
|
|
5044
5084
|
// Form submit observer delegate
|
|
5045
5085
|
willSubmitForm(form, submitter2) {
|
|
5046
5086
|
const action = getAction$1(form, submitter2);
|
|
@@ -5066,9 +5106,7 @@
|
|
|
5066
5106
|
}
|
|
5067
5107
|
// Page view delegate
|
|
5068
5108
|
viewWillCacheSnapshot() {
|
|
5069
|
-
|
|
5070
|
-
this.notifyApplicationBeforeCachingSnapshot();
|
|
5071
|
-
}
|
|
5109
|
+
this.notifyApplicationBeforeCachingSnapshot();
|
|
5072
5110
|
}
|
|
5073
5111
|
allowsImmediateRender({ element }, options) {
|
|
5074
5112
|
const event = this.notifyApplicationBeforeRender(element, options);
|
|
@@ -5140,14 +5178,6 @@
|
|
|
5140
5178
|
detail: { url: this.location.href, timing }
|
|
5141
5179
|
});
|
|
5142
5180
|
}
|
|
5143
|
-
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
|
5144
|
-
dispatchEvent(
|
|
5145
|
-
new HashChangeEvent("hashchange", {
|
|
5146
|
-
oldURL: oldURL.toString(),
|
|
5147
|
-
newURL: newURL.toString()
|
|
5148
|
-
})
|
|
5149
|
-
);
|
|
5150
|
-
}
|
|
5151
5181
|
notifyApplicationAfterFrameLoad(frame) {
|
|
5152
5182
|
return dispatch("turbo:frame-load", { target: frame });
|
|
5153
5183
|
}
|
|
@@ -5207,7 +5237,7 @@
|
|
|
5207
5237
|
}
|
|
5208
5238
|
};
|
|
5209
5239
|
var session = new Session(recentRequests);
|
|
5210
|
-
var { cache, navigator:
|
|
5240
|
+
var { cache, navigator: sessionNavigator } = session;
|
|
5211
5241
|
function start() {
|
|
5212
5242
|
session.start();
|
|
5213
5243
|
}
|
|
@@ -5226,12 +5256,6 @@
|
|
|
5226
5256
|
function renderStreamMessage(message) {
|
|
5227
5257
|
session.renderStreamMessage(message);
|
|
5228
5258
|
}
|
|
5229
|
-
function clearCache() {
|
|
5230
|
-
console.warn(
|
|
5231
|
-
"Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`"
|
|
5232
|
-
);
|
|
5233
|
-
session.clearCache();
|
|
5234
|
-
}
|
|
5235
5259
|
function setProgressBarDelay(delay) {
|
|
5236
5260
|
console.warn(
|
|
5237
5261
|
"Please replace `Turbo.setProgressBarDelay(delay)` with `Turbo.config.drive.progressBarDelay = delay`. The top-level function is deprecated and will be removed in a future version of Turbo.`"
|
|
@@ -5250,26 +5274,35 @@
|
|
|
5250
5274
|
);
|
|
5251
5275
|
config.forms.mode = mode;
|
|
5252
5276
|
}
|
|
5277
|
+
function morphBodyElements(currentBody, newBody) {
|
|
5278
|
+
MorphingPageRenderer.renderElement(currentBody, newBody);
|
|
5279
|
+
}
|
|
5280
|
+
function morphTurboFrameElements(currentFrame, newFrame) {
|
|
5281
|
+
MorphingFrameRenderer.renderElement(currentFrame, newFrame);
|
|
5282
|
+
}
|
|
5253
5283
|
var Turbo = /* @__PURE__ */ Object.freeze({
|
|
5254
5284
|
__proto__: null,
|
|
5255
|
-
navigator: navigator$1,
|
|
5256
|
-
session,
|
|
5257
|
-
cache,
|
|
5258
5285
|
PageRenderer,
|
|
5259
5286
|
PageSnapshot,
|
|
5260
5287
|
FrameRenderer,
|
|
5261
5288
|
fetch: fetchWithTurboHeaders,
|
|
5262
5289
|
config,
|
|
5290
|
+
session,
|
|
5291
|
+
cache,
|
|
5292
|
+
navigator: sessionNavigator,
|
|
5263
5293
|
start,
|
|
5264
5294
|
registerAdapter,
|
|
5265
5295
|
visit,
|
|
5266
5296
|
connectStreamSource,
|
|
5267
5297
|
disconnectStreamSource,
|
|
5268
5298
|
renderStreamMessage,
|
|
5269
|
-
clearCache,
|
|
5270
5299
|
setProgressBarDelay,
|
|
5271
5300
|
setConfirmMethod,
|
|
5272
|
-
setFormMode
|
|
5301
|
+
setFormMode,
|
|
5302
|
+
morphBodyElements,
|
|
5303
|
+
morphTurboFrameElements,
|
|
5304
|
+
morphChildren,
|
|
5305
|
+
morphElements
|
|
5273
5306
|
});
|
|
5274
5307
|
var TurboFrameMissingError = class extends Error {
|
|
5275
5308
|
};
|
|
@@ -5313,15 +5346,23 @@
|
|
|
5313
5346
|
this.formLinkClickObserver.stop();
|
|
5314
5347
|
this.linkInterceptor.stop();
|
|
5315
5348
|
this.formSubmitObserver.stop();
|
|
5349
|
+
if (!this.element.hasAttribute("recurse")) {
|
|
5350
|
+
this.#currentFetchRequest?.cancel();
|
|
5351
|
+
}
|
|
5316
5352
|
}
|
|
5317
5353
|
}
|
|
5318
5354
|
disabledChanged() {
|
|
5319
|
-
if (this.
|
|
5355
|
+
if (this.disabled) {
|
|
5356
|
+
this.#currentFetchRequest?.cancel();
|
|
5357
|
+
} else if (this.loadingStyle == FrameLoadingStyle.eager) {
|
|
5320
5358
|
this.#loadSourceURL();
|
|
5321
5359
|
}
|
|
5322
5360
|
}
|
|
5323
5361
|
sourceURLChanged() {
|
|
5324
5362
|
if (this.#isIgnoringChangesTo("src")) return;
|
|
5363
|
+
if (!this.sourceURL) {
|
|
5364
|
+
this.#currentFetchRequest?.cancel();
|
|
5365
|
+
}
|
|
5325
5366
|
if (this.element.isConnected) {
|
|
5326
5367
|
this.complete = false;
|
|
5327
5368
|
}
|
|
@@ -5403,12 +5444,13 @@
|
|
|
5403
5444
|
}
|
|
5404
5445
|
this.formSubmission = new FormSubmission(this, element, submitter2);
|
|
5405
5446
|
const { fetchRequest } = this.formSubmission;
|
|
5406
|
-
this
|
|
5447
|
+
const frame = this.#findFrameElement(element, submitter2);
|
|
5448
|
+
this.prepareRequest(fetchRequest, frame);
|
|
5407
5449
|
this.formSubmission.start();
|
|
5408
5450
|
}
|
|
5409
5451
|
// Fetch request delegate
|
|
5410
|
-
prepareRequest(request) {
|
|
5411
|
-
request.headers["Turbo-Frame"] =
|
|
5452
|
+
prepareRequest(request, frame = this) {
|
|
5453
|
+
request.headers["Turbo-Frame"] = frame.id;
|
|
5412
5454
|
if (this.currentNavigationElement?.hasAttribute("data-turbo-stream")) {
|
|
5413
5455
|
request.acceptResponseType(StreamMessage.contentType);
|
|
5414
5456
|
}
|
|
@@ -5598,7 +5640,8 @@
|
|
|
5598
5640
|
}
|
|
5599
5641
|
#findFrameElement(element, submitter2) {
|
|
5600
5642
|
const id = getAttribute("data-turbo-frame", submitter2, element) || this.element.getAttribute("target");
|
|
5601
|
-
|
|
5643
|
+
const target = this.#getFrameElementById(id);
|
|
5644
|
+
return target instanceof FrameElement ? target : this.element;
|
|
5602
5645
|
}
|
|
5603
5646
|
async extractForeignFrameElement(container) {
|
|
5604
5647
|
let element;
|
|
@@ -5632,9 +5675,11 @@
|
|
|
5632
5675
|
return false;
|
|
5633
5676
|
}
|
|
5634
5677
|
if (id) {
|
|
5635
|
-
const frameElement = getFrameElementById(id);
|
|
5678
|
+
const frameElement = this.#getFrameElementById(id);
|
|
5636
5679
|
if (frameElement) {
|
|
5637
5680
|
return !frameElement.disabled;
|
|
5681
|
+
} else if (id == "_parent") {
|
|
5682
|
+
return false;
|
|
5638
5683
|
}
|
|
5639
5684
|
}
|
|
5640
5685
|
if (!session.elementIsNavigatable(element)) {
|
|
@@ -5649,8 +5694,11 @@
|
|
|
5649
5694
|
get id() {
|
|
5650
5695
|
return this.element.id;
|
|
5651
5696
|
}
|
|
5697
|
+
get disabled() {
|
|
5698
|
+
return this.element.disabled;
|
|
5699
|
+
}
|
|
5652
5700
|
get enabled() {
|
|
5653
|
-
return !this.
|
|
5701
|
+
return !this.disabled;
|
|
5654
5702
|
}
|
|
5655
5703
|
get sourceURL() {
|
|
5656
5704
|
if (this.element.src) {
|
|
@@ -5699,15 +5747,15 @@
|
|
|
5699
5747
|
callback();
|
|
5700
5748
|
delete this.currentNavigationElement;
|
|
5701
5749
|
}
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5750
|
+
#getFrameElementById(id) {
|
|
5751
|
+
if (id != null) {
|
|
5752
|
+
const element = id === "_parent" ? this.element.parentElement.closest("turbo-frame") : document.getElementById(id);
|
|
5753
|
+
if (element instanceof FrameElement) {
|
|
5754
|
+
return element;
|
|
5755
|
+
}
|
|
5708
5756
|
}
|
|
5709
5757
|
}
|
|
5710
|
-
}
|
|
5758
|
+
};
|
|
5711
5759
|
function activateElement(element, currentURL) {
|
|
5712
5760
|
if (element) {
|
|
5713
5761
|
const src = element.getAttribute("src");
|
|
@@ -5726,6 +5774,7 @@
|
|
|
5726
5774
|
}
|
|
5727
5775
|
var StreamActions = {
|
|
5728
5776
|
after() {
|
|
5777
|
+
this.removeDuplicateTargetSiblings();
|
|
5729
5778
|
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e.nextSibling));
|
|
5730
5779
|
},
|
|
5731
5780
|
append() {
|
|
@@ -5733,6 +5782,7 @@
|
|
|
5733
5782
|
this.targetElements.forEach((e) => e.append(this.templateContent));
|
|
5734
5783
|
},
|
|
5735
5784
|
before() {
|
|
5785
|
+
this.removeDuplicateTargetSiblings();
|
|
5736
5786
|
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e));
|
|
5737
5787
|
},
|
|
5738
5788
|
prepend() {
|
|
@@ -5764,7 +5814,10 @@
|
|
|
5764
5814
|
});
|
|
5765
5815
|
},
|
|
5766
5816
|
refresh() {
|
|
5767
|
-
|
|
5817
|
+
const method = this.getAttribute("method");
|
|
5818
|
+
const requestId = this.requestId;
|
|
5819
|
+
const scroll = this.getAttribute("scroll");
|
|
5820
|
+
session.refresh(this.baseURI, { method, requestId, scroll });
|
|
5768
5821
|
}
|
|
5769
5822
|
};
|
|
5770
5823
|
var StreamElement = class _StreamElement extends HTMLElement {
|
|
@@ -5809,6 +5862,20 @@
|
|
|
5809
5862
|
const newChildrenIds = [...this.templateContent?.children || []].filter((c) => !!c.getAttribute("id")).map((c) => c.getAttribute("id"));
|
|
5810
5863
|
return existingChildren.filter((c) => newChildrenIds.includes(c.getAttribute("id")));
|
|
5811
5864
|
}
|
|
5865
|
+
/**
|
|
5866
|
+
* Removes duplicate siblings (by ID)
|
|
5867
|
+
*/
|
|
5868
|
+
removeDuplicateTargetSiblings() {
|
|
5869
|
+
this.duplicateSiblings.forEach((c) => c.remove());
|
|
5870
|
+
}
|
|
5871
|
+
/**
|
|
5872
|
+
* Gets the list of duplicate siblings (i.e. those with the same ID)
|
|
5873
|
+
*/
|
|
5874
|
+
get duplicateSiblings() {
|
|
5875
|
+
const existingChildren = this.targetElements.flatMap((e) => [...e.parentElement.children]).filter((c) => !!c.id);
|
|
5876
|
+
const newChildrenIds = [...this.templateContent?.children || []].filter((c) => !!c.id).map((c) => c.id);
|
|
5877
|
+
return existingChildren.filter((c) => newChildrenIds.includes(c.id));
|
|
5878
|
+
}
|
|
5812
5879
|
/**
|
|
5813
5880
|
* Gets the action function to be performed.
|
|
5814
5881
|
*/
|
|
@@ -5935,10 +6002,10 @@
|
|
|
5935
6002
|
customElements.define("turbo-stream-source", StreamSourceElement);
|
|
5936
6003
|
}
|
|
5937
6004
|
(() => {
|
|
5938
|
-
|
|
5939
|
-
if (!
|
|
5940
|
-
if (
|
|
5941
|
-
element =
|
|
6005
|
+
const scriptElement = document.currentScript;
|
|
6006
|
+
if (!scriptElement) return;
|
|
6007
|
+
if (scriptElement.hasAttribute("data-turbo-suppress-warning")) return;
|
|
6008
|
+
let element = scriptElement.parentElement;
|
|
5942
6009
|
while (element) {
|
|
5943
6010
|
if (element == document.body) {
|
|
5944
6011
|
return console.warn(
|
|
@@ -5952,7 +6019,7 @@
|
|
|
5952
6019
|
——
|
|
5953
6020
|
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
|
5954
6021
|
`,
|
|
5955
|
-
|
|
6022
|
+
scriptElement.outerHTML
|
|
5956
6023
|
);
|
|
5957
6024
|
}
|
|
5958
6025
|
element = element.parentElement;
|
|
@@ -8578,7 +8645,7 @@
|
|
|
8578
8645
|
};
|
|
8579
8646
|
var useClickOutside = (composableController, options = {}) => {
|
|
8580
8647
|
const controller = composableController;
|
|
8581
|
-
const { onlyVisible, dispatchEvent
|
|
8648
|
+
const { onlyVisible, dispatchEvent, events, eventPrefix } = Object.assign({}, defaultOptions$5, options);
|
|
8582
8649
|
const onEvent = (event) => {
|
|
8583
8650
|
const targetElement = (options === null || options === void 0 ? void 0 : options.element) || controller.element;
|
|
8584
8651
|
if (targetElement.contains(event.target) || !isElementInViewport(targetElement) && onlyVisible) {
|
|
@@ -8587,7 +8654,7 @@
|
|
|
8587
8654
|
if (controller.clickOutside) {
|
|
8588
8655
|
controller.clickOutside(event);
|
|
8589
8656
|
}
|
|
8590
|
-
if (
|
|
8657
|
+
if (dispatchEvent) {
|
|
8591
8658
|
const eventName = composeEventName("click:outside", controller, eventPrefix);
|
|
8592
8659
|
const clickOutsideEvent = extendedEvent(eventName, event, {
|
|
8593
8660
|
controller
|
|
@@ -9521,7 +9588,7 @@
|
|
|
9521
9588
|
|
|
9522
9589
|
@hotwired/turbo/dist/turbo.es2017-esm.js:
|
|
9523
9590
|
(*!
|
|
9524
|
-
Turbo 8.0.
|
|
9525
|
-
Copyright ©
|
|
9591
|
+
Turbo 8.0.23
|
|
9592
|
+
Copyright © 2026 37signals LLC
|
|
9526
9593
|
*)
|
|
9527
9594
|
*/
|