masks 0.3.1 → 0.4.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/builds/masks/application.css +1 -1
- data/app/assets/builds/masks/application.js +2153 -726
- data/app/assets/builds/masks/application.js.map +4 -4
- data/app/assets/javascripts/controllers/application.js +1 -1
- data/app/assets/javascripts/controllers/index.js +9 -0
- data/app/assets/javascripts/controllers/table_controller.js +15 -0
- data/app/assets/stylesheets/application.css +12 -4
- data/app/controllers/concerns/masks/controller.rb +1 -1
- data/app/controllers/masks/manage/actors_controller.rb +72 -1
- data/app/controllers/masks/manage/base_controller.rb +10 -2
- data/app/controllers/masks/manage/clients_controller.rb +84 -0
- data/app/controllers/masks/manage/dashboard_controller.rb +15 -0
- data/app/controllers/masks/manage/devices_controller.rb +19 -0
- data/app/controllers/masks/openid/authorizations_controller.rb +45 -0
- data/app/controllers/masks/openid/discoveries_controller.rb +55 -0
- data/app/controllers/masks/openid/tokens_controller.rb +45 -0
- data/app/controllers/masks/openid/userinfo_controller.rb +28 -0
- data/app/controllers/masks/sessions_controller.rb +1 -1
- data/app/models/concerns/masks/access.rb +2 -2
- data/app/models/masks/access/actor_password.rb +2 -1
- data/app/models/masks/access/actor_signup.rb +1 -2
- data/app/models/masks/credentials/access_token.rb +60 -0
- data/app/models/masks/credentials/key.rb +1 -1
- data/app/models/masks/credentials/return_to.rb +27 -0
- data/app/models/masks/mask.rb +12 -1
- data/app/models/masks/openid/authorization.rb +116 -0
- data/app/models/masks/openid/token.rb +56 -0
- data/app/models/masks/rails/actor.rb +23 -1
- data/app/models/masks/rails/openid/access_token.rb +55 -0
- data/app/models/masks/rails/openid/authorization.rb +45 -0
- data/app/models/masks/rails/openid/client.rb +186 -0
- data/app/models/masks/rails/openid/id_token.rb +43 -0
- data/app/models/masks/sessions/access.rb +2 -1
- data/app/resources/masks/session_resource.rb +1 -1
- data/app/views/layouts/masks/manage.html.erb +22 -5
- data/app/views/masks/actor_mailer/recover_credentials.html.erb +2 -3
- data/app/views/masks/actor_mailer/verify_email.html.erb +2 -3
- data/app/views/masks/actors/current.html.erb +7 -14
- data/app/views/masks/application/_header.html.erb +3 -4
- data/app/views/masks/backup_codes/new.html.erb +34 -20
- data/app/views/masks/emails/new.html.erb +14 -8
- data/app/views/masks/keys/new.html.erb +7 -7
- data/app/views/masks/manage/actors/index.html.erb +101 -37
- data/app/views/masks/manage/{actor → actors}/show.html.erb +63 -17
- data/app/views/masks/manage/clients/index.html.erb +102 -0
- data/app/views/masks/manage/clients/show.html.erb +156 -0
- data/app/views/masks/manage/dashboard/index.html.erb +10 -0
- data/app/views/masks/manage/devices/index.html.erb +47 -0
- data/app/views/masks/one_time_code/new.html.erb +41 -24
- data/app/views/masks/openid/authorizations/error.html.erb +23 -0
- data/app/views/masks/openid/authorizations/new.html.erb +46 -0
- data/app/views/masks/passwords/edit.html.erb +20 -7
- data/app/views/masks/recoveries/new.html.erb +2 -4
- data/app/views/masks/recoveries/password.html.erb +2 -3
- data/app/views/masks/sessions/new.html.erb +22 -23
- data/config/initializers/inflections.rb +5 -0
- data/config/locales/en.yml +23 -2
- data/config/routes.rb +40 -3
- data/db/migrate/20240329182422_support_openid.rb +64 -0
- data/lib/generators/masks/install/templates/masks.json +4 -1
- data/lib/masks/configuration.rb +22 -9
- data/lib/masks/version.rb +1 -1
- data/lib/masks.rb +1 -0
- data/lib/tasks/masks_tasks.rake +3 -2
- data/masks.json +47 -6
- metadata +59 -11
- data/app/assets/builds/application.css +0 -4764
- data/app/assets/builds/application.js +0 -8236
- data/app/assets/builds/application.js.map +0 -7
- data/app/controllers/masks/manage/actor_controller.rb +0 -35
@@ -14,8 +14,8 @@
|
|
14
14
|
var init_adapters = __esm({
|
15
15
|
"node_modules/@rails/actioncable/src/adapters.js"() {
|
16
16
|
adapters_default = {
|
17
|
-
logger:
|
18
|
-
WebSocket:
|
17
|
+
logger: typeof console !== "undefined" ? console : void 0,
|
18
|
+
WebSocket: typeof WebSocket !== "undefined" ? WebSocket : void 0
|
19
19
|
};
|
20
20
|
}
|
21
21
|
});
|
@@ -596,21 +596,38 @@
|
|
596
596
|
});
|
597
597
|
|
598
598
|
// node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
599
|
+
var turbo_es2017_esm_exports = {};
|
600
|
+
__export(turbo_es2017_esm_exports, {
|
601
|
+
FetchEnctype: () => FetchEnctype,
|
602
|
+
FetchMethod: () => FetchMethod,
|
603
|
+
FetchRequest: () => FetchRequest,
|
604
|
+
FetchResponse: () => FetchResponse,
|
605
|
+
FrameElement: () => FrameElement,
|
606
|
+
FrameLoadingStyle: () => FrameLoadingStyle,
|
607
|
+
FrameRenderer: () => FrameRenderer,
|
608
|
+
PageRenderer: () => PageRenderer,
|
609
|
+
PageSnapshot: () => PageSnapshot,
|
610
|
+
StreamActions: () => StreamActions,
|
611
|
+
StreamElement: () => StreamElement,
|
612
|
+
StreamSourceElement: () => StreamSourceElement,
|
613
|
+
cache: () => cache,
|
614
|
+
clearCache: () => clearCache,
|
615
|
+
connectStreamSource: () => connectStreamSource,
|
616
|
+
disconnectStreamSource: () => disconnectStreamSource,
|
617
|
+
fetch: () => fetchWithTurboHeaders,
|
618
|
+
fetchEnctypeFromString: () => fetchEnctypeFromString,
|
619
|
+
fetchMethodFromString: () => fetchMethodFromString,
|
620
|
+
isSafe: () => isSafe,
|
621
|
+
navigator: () => navigator$1,
|
622
|
+
registerAdapter: () => registerAdapter,
|
623
|
+
renderStreamMessage: () => renderStreamMessage,
|
624
|
+
session: () => session,
|
625
|
+
setConfirmMethod: () => setConfirmMethod,
|
626
|
+
setFormMode: () => setFormMode,
|
627
|
+
setProgressBarDelay: () => setProgressBarDelay,
|
628
|
+
start: () => start,
|
629
|
+
visit: () => visit
|
630
|
+
});
|
614
631
|
(function(prototype) {
|
615
632
|
if (typeof prototype.requestSubmit == "function")
|
616
633
|
return;
|
@@ -640,7 +657,7 @@
|
|
640
657
|
function findSubmitterFromClickTarget(target) {
|
641
658
|
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
642
659
|
const candidate = element ? element.closest("input, button") : null;
|
643
|
-
return
|
660
|
+
return candidate?.type == "submit" ? candidate : null;
|
644
661
|
}
|
645
662
|
function clickCaptured(event) {
|
646
663
|
const submitter = findSubmitterFromClickTarget(event.target);
|
@@ -652,10 +669,13 @@
|
|
652
669
|
if ("submitter" in Event.prototype)
|
653
670
|
return;
|
654
671
|
let prototype = window.Event.prototype;
|
655
|
-
if ("SubmitEvent" in window
|
656
|
-
|
657
|
-
|
658
|
-
|
672
|
+
if ("SubmitEvent" in window) {
|
673
|
+
const prototypeOfSubmitEvent = window.SubmitEvent.prototype;
|
674
|
+
if (/Apple Computer/.test(navigator.vendor) && !("submitter" in prototypeOfSubmitEvent)) {
|
675
|
+
prototype = prototypeOfSubmitEvent;
|
676
|
+
} else {
|
677
|
+
return;
|
678
|
+
}
|
659
679
|
}
|
660
680
|
addEventListener("click", clickCaptured, true);
|
661
681
|
Object.defineProperty(prototype, "submitter", {
|
@@ -666,18 +686,18 @@
|
|
666
686
|
}
|
667
687
|
});
|
668
688
|
})();
|
669
|
-
var FrameLoadingStyle
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
})(FrameLoadingStyle || (FrameLoadingStyle = {}));
|
689
|
+
var FrameLoadingStyle = {
|
690
|
+
eager: "eager",
|
691
|
+
lazy: "lazy"
|
692
|
+
};
|
674
693
|
var FrameElement = class _FrameElement extends HTMLElement {
|
694
|
+
static delegateConstructor = void 0;
|
695
|
+
loaded = Promise.resolve();
|
675
696
|
static get observedAttributes() {
|
676
|
-
return ["disabled", "
|
697
|
+
return ["disabled", "loading", "src"];
|
677
698
|
}
|
678
699
|
constructor() {
|
679
700
|
super();
|
680
|
-
this.loaded = Promise.resolve();
|
681
701
|
this.delegate = new _FrameElement.delegateConstructor(this);
|
682
702
|
}
|
683
703
|
connectedCallback() {
|
@@ -692,17 +712,21 @@
|
|
692
712
|
attributeChangedCallback(name) {
|
693
713
|
if (name == "loading") {
|
694
714
|
this.delegate.loadingStyleChanged();
|
695
|
-
} else if (name == "complete") {
|
696
|
-
this.delegate.completeChanged();
|
697
715
|
} else if (name == "src") {
|
698
716
|
this.delegate.sourceURLChanged();
|
699
|
-
} else {
|
717
|
+
} else if (name == "disabled") {
|
700
718
|
this.delegate.disabledChanged();
|
701
719
|
}
|
702
720
|
}
|
721
|
+
/**
|
722
|
+
* Gets the URL to lazily load source HTML from
|
723
|
+
*/
|
703
724
|
get src() {
|
704
725
|
return this.getAttribute("src");
|
705
726
|
}
|
727
|
+
/**
|
728
|
+
* Sets the URL to lazily load source HTML from
|
729
|
+
*/
|
706
730
|
set src(value) {
|
707
731
|
if (value) {
|
708
732
|
this.setAttribute("src", value);
|
@@ -710,9 +734,31 @@
|
|
710
734
|
this.removeAttribute("src");
|
711
735
|
}
|
712
736
|
}
|
737
|
+
/**
|
738
|
+
* Gets the refresh mode for the frame.
|
739
|
+
*/
|
740
|
+
get refresh() {
|
741
|
+
return this.getAttribute("refresh");
|
742
|
+
}
|
743
|
+
/**
|
744
|
+
* Sets the refresh mode for the frame.
|
745
|
+
*/
|
746
|
+
set refresh(value) {
|
747
|
+
if (value) {
|
748
|
+
this.setAttribute("refresh", value);
|
749
|
+
} else {
|
750
|
+
this.removeAttribute("refresh");
|
751
|
+
}
|
752
|
+
}
|
753
|
+
/**
|
754
|
+
* Determines if the element is loading
|
755
|
+
*/
|
713
756
|
get loading() {
|
714
757
|
return frameLoadingStyleFromString(this.getAttribute("loading") || "");
|
715
758
|
}
|
759
|
+
/**
|
760
|
+
* Sets the value of if the element is loading
|
761
|
+
*/
|
716
762
|
set loading(value) {
|
717
763
|
if (value) {
|
718
764
|
this.setAttribute("loading", value);
|
@@ -720,9 +766,19 @@
|
|
720
766
|
this.removeAttribute("loading");
|
721
767
|
}
|
722
768
|
}
|
769
|
+
/**
|
770
|
+
* Gets the disabled state of the frame.
|
771
|
+
*
|
772
|
+
* If disabled, no requests will be intercepted by the frame.
|
773
|
+
*/
|
723
774
|
get disabled() {
|
724
775
|
return this.hasAttribute("disabled");
|
725
776
|
}
|
777
|
+
/**
|
778
|
+
* Sets the disabled state of the frame.
|
779
|
+
*
|
780
|
+
* If disabled, no requests will be intercepted by the frame.
|
781
|
+
*/
|
726
782
|
set disabled(value) {
|
727
783
|
if (value) {
|
728
784
|
this.setAttribute("disabled", "");
|
@@ -730,9 +786,19 @@
|
|
730
786
|
this.removeAttribute("disabled");
|
731
787
|
}
|
732
788
|
}
|
789
|
+
/**
|
790
|
+
* Gets the autoscroll state of the frame.
|
791
|
+
*
|
792
|
+
* If true, the frame will be scrolled into view automatically on update.
|
793
|
+
*/
|
733
794
|
get autoscroll() {
|
734
795
|
return this.hasAttribute("autoscroll");
|
735
796
|
}
|
797
|
+
/**
|
798
|
+
* Sets the autoscroll state of the frame.
|
799
|
+
*
|
800
|
+
* If true, the frame will be scrolled into view automatically on update.
|
801
|
+
*/
|
736
802
|
set autoscroll(value) {
|
737
803
|
if (value) {
|
738
804
|
this.setAttribute("autoscroll", "");
|
@@ -740,15 +806,27 @@
|
|
740
806
|
this.removeAttribute("autoscroll");
|
741
807
|
}
|
742
808
|
}
|
809
|
+
/**
|
810
|
+
* Determines if the element has finished loading
|
811
|
+
*/
|
743
812
|
get complete() {
|
744
813
|
return !this.delegate.isLoading;
|
745
814
|
}
|
815
|
+
/**
|
816
|
+
* Gets the active state of the frame.
|
817
|
+
*
|
818
|
+
* If inactive, source changes will not be observed.
|
819
|
+
*/
|
746
820
|
get isActive() {
|
747
821
|
return this.ownerDocument === document && !this.isPreview;
|
748
822
|
}
|
823
|
+
/**
|
824
|
+
* Sets the active state of the frame.
|
825
|
+
*
|
826
|
+
* If inactive, source changes will not be observed.
|
827
|
+
*/
|
749
828
|
get isPreview() {
|
750
|
-
|
751
|
-
return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
|
829
|
+
return this.ownerDocument?.documentElement?.hasAttribute("data-turbo-preview");
|
752
830
|
}
|
753
831
|
};
|
754
832
|
function frameLoadingStyleFromString(style) {
|
@@ -770,8 +848,8 @@
|
|
770
848
|
return anchorMatch[1];
|
771
849
|
}
|
772
850
|
}
|
773
|
-
function getAction(form, submitter) {
|
774
|
-
const action =
|
851
|
+
function getAction$1(form, submitter) {
|
852
|
+
const action = submitter?.getAttribute("formaction") || form.getAttribute("action") || form.action;
|
775
853
|
return expandURL(action);
|
776
854
|
}
|
777
855
|
function getExtension(url) {
|
@@ -893,6 +971,13 @@
|
|
893
971
|
}
|
894
972
|
return event;
|
895
973
|
}
|
974
|
+
function nextRepaint() {
|
975
|
+
if (document.visibilityState === "hidden") {
|
976
|
+
return nextEventLoopTick();
|
977
|
+
} else {
|
978
|
+
return nextAnimationFrame();
|
979
|
+
}
|
980
|
+
}
|
896
981
|
function nextAnimationFrame() {
|
897
982
|
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
898
983
|
}
|
@@ -931,7 +1016,7 @@
|
|
931
1016
|
}).join("");
|
932
1017
|
}
|
933
1018
|
function getAttribute(attributeName, ...elements) {
|
934
|
-
for (const value of elements.map((element) => element
|
1019
|
+
for (const value of elements.map((element) => element?.getAttribute(attributeName))) {
|
935
1020
|
if (typeof value == "string")
|
936
1021
|
return value;
|
937
1022
|
}
|
@@ -1002,19 +1087,73 @@
|
|
1002
1087
|
return element;
|
1003
1088
|
}
|
1004
1089
|
function findClosestRecursively(element, selector) {
|
1005
|
-
var _a;
|
1006
1090
|
if (element instanceof Element) {
|
1007
|
-
return element.closest(selector) || findClosestRecursively(element.assignedSlot ||
|
1091
|
+
return element.closest(selector) || findClosestRecursively(element.assignedSlot || element.getRootNode()?.host, selector);
|
1092
|
+
}
|
1093
|
+
}
|
1094
|
+
function elementIsFocusable(element) {
|
1095
|
+
const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
|
1096
|
+
return !!element && element.closest(inertDisabledOrHidden) == null && typeof element.focus == "function";
|
1097
|
+
}
|
1098
|
+
function queryAutofocusableElement(elementOrDocumentFragment) {
|
1099
|
+
return Array.from(elementOrDocumentFragment.querySelectorAll("[autofocus]")).find(elementIsFocusable);
|
1100
|
+
}
|
1101
|
+
async function around(callback, reader) {
|
1102
|
+
const before = reader();
|
1103
|
+
callback();
|
1104
|
+
await nextAnimationFrame();
|
1105
|
+
const after = reader();
|
1106
|
+
return [before, after];
|
1107
|
+
}
|
1108
|
+
function doesNotTargetIFrame(anchor) {
|
1109
|
+
if (anchor.hasAttribute("target")) {
|
1110
|
+
for (const element of document.getElementsByName(anchor.target)) {
|
1111
|
+
if (element instanceof HTMLIFrameElement)
|
1112
|
+
return false;
|
1113
|
+
}
|
1114
|
+
}
|
1115
|
+
return true;
|
1116
|
+
}
|
1117
|
+
function findLinkFromClickTarget(target) {
|
1118
|
+
return findClosestRecursively(target, "a[href]:not([target^=_]):not([download])");
|
1119
|
+
}
|
1120
|
+
function getLocationForLink(link) {
|
1121
|
+
return expandURL(link.getAttribute("href") || "");
|
1122
|
+
}
|
1123
|
+
function debounce(fn, delay) {
|
1124
|
+
let timeoutId = null;
|
1125
|
+
return (...args) => {
|
1126
|
+
const callback = () => fn.apply(this, args);
|
1127
|
+
clearTimeout(timeoutId);
|
1128
|
+
timeoutId = setTimeout(callback, delay);
|
1129
|
+
};
|
1130
|
+
}
|
1131
|
+
var LimitedSet = class extends Set {
|
1132
|
+
constructor(maxSize) {
|
1133
|
+
super();
|
1134
|
+
this.maxSize = maxSize;
|
1008
1135
|
}
|
1136
|
+
add(value) {
|
1137
|
+
if (this.size >= this.maxSize) {
|
1138
|
+
const iterator = this.values();
|
1139
|
+
const oldestValue = iterator.next().value;
|
1140
|
+
this.delete(oldestValue);
|
1141
|
+
}
|
1142
|
+
super.add(value);
|
1143
|
+
}
|
1144
|
+
};
|
1145
|
+
var recentRequests = new LimitedSet(20);
|
1146
|
+
var nativeFetch = window.fetch;
|
1147
|
+
function fetchWithTurboHeaders(url, options = {}) {
|
1148
|
+
const modifiedHeaders = new Headers(options.headers || {});
|
1149
|
+
const requestUID = uuid();
|
1150
|
+
recentRequests.add(requestUID);
|
1151
|
+
modifiedHeaders.append("X-Turbo-Request-Id", requestUID);
|
1152
|
+
return nativeFetch(url, {
|
1153
|
+
...options,
|
1154
|
+
headers: modifiedHeaders
|
1155
|
+
});
|
1009
1156
|
}
|
1010
|
-
var FetchMethod;
|
1011
|
-
(function(FetchMethod2) {
|
1012
|
-
FetchMethod2[FetchMethod2["get"] = 0] = "get";
|
1013
|
-
FetchMethod2[FetchMethod2["post"] = 1] = "post";
|
1014
|
-
FetchMethod2[FetchMethod2["put"] = 2] = "put";
|
1015
|
-
FetchMethod2[FetchMethod2["patch"] = 3] = "patch";
|
1016
|
-
FetchMethod2[FetchMethod2["delete"] = 4] = "delete";
|
1017
|
-
})(FetchMethod || (FetchMethod = {}));
|
1018
1157
|
function fetchMethodFromString(method) {
|
1019
1158
|
switch (method.toLowerCase()) {
|
1020
1159
|
case "get":
|
@@ -1029,17 +1168,75 @@
|
|
1029
1168
|
return FetchMethod.delete;
|
1030
1169
|
}
|
1031
1170
|
}
|
1171
|
+
var FetchMethod = {
|
1172
|
+
get: "get",
|
1173
|
+
post: "post",
|
1174
|
+
put: "put",
|
1175
|
+
patch: "patch",
|
1176
|
+
delete: "delete"
|
1177
|
+
};
|
1178
|
+
function fetchEnctypeFromString(encoding) {
|
1179
|
+
switch (encoding.toLowerCase()) {
|
1180
|
+
case FetchEnctype.multipart:
|
1181
|
+
return FetchEnctype.multipart;
|
1182
|
+
case FetchEnctype.plain:
|
1183
|
+
return FetchEnctype.plain;
|
1184
|
+
default:
|
1185
|
+
return FetchEnctype.urlEncoded;
|
1186
|
+
}
|
1187
|
+
}
|
1188
|
+
var FetchEnctype = {
|
1189
|
+
urlEncoded: "application/x-www-form-urlencoded",
|
1190
|
+
multipart: "multipart/form-data",
|
1191
|
+
plain: "text/plain"
|
1192
|
+
};
|
1032
1193
|
var FetchRequest = class {
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1194
|
+
abortController = new AbortController();
|
1195
|
+
#resolveRequestPromise = (_value) => {
|
1196
|
+
};
|
1197
|
+
constructor(delegate, method, location2, requestBody = new URLSearchParams(), target = null, enctype = FetchEnctype.urlEncoded) {
|
1198
|
+
const [url, body] = buildResourceAndBody(expandURL(location2), method, requestBody, enctype);
|
1037
1199
|
this.delegate = delegate;
|
1038
|
-
this.
|
1039
|
-
this.headers = this.defaultHeaders;
|
1040
|
-
this.body = body;
|
1041
|
-
this.url = location2;
|
1200
|
+
this.url = url;
|
1042
1201
|
this.target = target;
|
1202
|
+
this.fetchOptions = {
|
1203
|
+
credentials: "same-origin",
|
1204
|
+
redirect: "follow",
|
1205
|
+
method,
|
1206
|
+
headers: { ...this.defaultHeaders },
|
1207
|
+
body,
|
1208
|
+
signal: this.abortSignal,
|
1209
|
+
referrer: this.delegate.referrer?.href
|
1210
|
+
};
|
1211
|
+
this.enctype = enctype;
|
1212
|
+
}
|
1213
|
+
get method() {
|
1214
|
+
return this.fetchOptions.method;
|
1215
|
+
}
|
1216
|
+
set method(value) {
|
1217
|
+
const fetchBody = this.isSafe ? this.url.searchParams : this.fetchOptions.body || new FormData();
|
1218
|
+
const fetchMethod = fetchMethodFromString(value) || FetchMethod.get;
|
1219
|
+
this.url.search = "";
|
1220
|
+
const [url, body] = buildResourceAndBody(this.url, fetchMethod, fetchBody, this.enctype);
|
1221
|
+
this.url = url;
|
1222
|
+
this.fetchOptions.body = body;
|
1223
|
+
this.fetchOptions.method = fetchMethod;
|
1224
|
+
}
|
1225
|
+
get headers() {
|
1226
|
+
return this.fetchOptions.headers;
|
1227
|
+
}
|
1228
|
+
set headers(value) {
|
1229
|
+
this.fetchOptions.headers = value;
|
1230
|
+
}
|
1231
|
+
get body() {
|
1232
|
+
if (this.isSafe) {
|
1233
|
+
return this.url.searchParams;
|
1234
|
+
} else {
|
1235
|
+
return this.fetchOptions.body;
|
1236
|
+
}
|
1237
|
+
}
|
1238
|
+
set body(value) {
|
1239
|
+
this.fetchOptions.body = value;
|
1043
1240
|
}
|
1044
1241
|
get location() {
|
1045
1242
|
return this.url;
|
@@ -1056,14 +1253,19 @@
|
|
1056
1253
|
async perform() {
|
1057
1254
|
const { fetchOptions } = this;
|
1058
1255
|
this.delegate.prepareRequest(this);
|
1059
|
-
await this
|
1256
|
+
const event = await this.#allowRequestToBeIntercepted(fetchOptions);
|
1060
1257
|
try {
|
1061
1258
|
this.delegate.requestStarted(this);
|
1062
|
-
|
1259
|
+
if (event.detail.fetchRequest) {
|
1260
|
+
this.response = event.detail.fetchRequest.response;
|
1261
|
+
} else {
|
1262
|
+
this.response = fetchWithTurboHeaders(this.url.href, fetchOptions);
|
1263
|
+
}
|
1264
|
+
const response = await this.response;
|
1063
1265
|
return await this.receive(response);
|
1064
1266
|
} catch (error2) {
|
1065
1267
|
if (error2.name !== "AbortError") {
|
1066
|
-
if (this
|
1268
|
+
if (this.#willDelegateErrorHandling(error2)) {
|
1067
1269
|
this.delegate.requestErrored(this, error2);
|
1068
1270
|
}
|
1069
1271
|
throw error2;
|
@@ -1088,25 +1290,13 @@
|
|
1088
1290
|
}
|
1089
1291
|
return fetchResponse;
|
1090
1292
|
}
|
1091
|
-
get fetchOptions() {
|
1092
|
-
var _a;
|
1093
|
-
return {
|
1094
|
-
method: FetchMethod[this.method].toUpperCase(),
|
1095
|
-
credentials: "same-origin",
|
1096
|
-
headers: this.headers,
|
1097
|
-
redirect: "follow",
|
1098
|
-
body: this.isSafe ? null : this.body,
|
1099
|
-
signal: this.abortSignal,
|
1100
|
-
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
|
1101
|
-
};
|
1102
|
-
}
|
1103
1293
|
get defaultHeaders() {
|
1104
1294
|
return {
|
1105
1295
|
Accept: "text/html, application/xhtml+xml"
|
1106
1296
|
};
|
1107
1297
|
}
|
1108
1298
|
get isSafe() {
|
1109
|
-
return this.method
|
1299
|
+
return isSafe(this.method);
|
1110
1300
|
}
|
1111
1301
|
get abortSignal() {
|
1112
1302
|
return this.abortController.signal;
|
@@ -1114,21 +1304,23 @@
|
|
1114
1304
|
acceptResponseType(mimeType) {
|
1115
1305
|
this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
|
1116
1306
|
}
|
1117
|
-
async allowRequestToBeIntercepted(fetchOptions) {
|
1118
|
-
const requestInterception = new Promise((resolve) => this
|
1307
|
+
async #allowRequestToBeIntercepted(fetchOptions) {
|
1308
|
+
const requestInterception = new Promise((resolve) => this.#resolveRequestPromise = resolve);
|
1119
1309
|
const event = dispatch("turbo:before-fetch-request", {
|
1120
1310
|
cancelable: true,
|
1121
1311
|
detail: {
|
1122
1312
|
fetchOptions,
|
1123
1313
|
url: this.url,
|
1124
|
-
resume: this
|
1314
|
+
resume: this.#resolveRequestPromise
|
1125
1315
|
},
|
1126
1316
|
target: this.target
|
1127
1317
|
});
|
1318
|
+
this.url = event.detail.url;
|
1128
1319
|
if (event.defaultPrevented)
|
1129
1320
|
await requestInterception;
|
1321
|
+
return event;
|
1130
1322
|
}
|
1131
|
-
willDelegateErrorHandling(error2) {
|
1323
|
+
#willDelegateErrorHandling(error2) {
|
1132
1324
|
const event = dispatch("turbo:fetch-request-error", {
|
1133
1325
|
target: this.target,
|
1134
1326
|
cancelable: true,
|
@@ -1137,15 +1329,37 @@
|
|
1137
1329
|
return !event.defaultPrevented;
|
1138
1330
|
}
|
1139
1331
|
};
|
1332
|
+
function isSafe(fetchMethod) {
|
1333
|
+
return fetchMethodFromString(fetchMethod) == FetchMethod.get;
|
1334
|
+
}
|
1335
|
+
function buildResourceAndBody(resource, method, requestBody, enctype) {
|
1336
|
+
const searchParams = Array.from(requestBody).length > 0 ? new URLSearchParams(entriesExcludingFiles(requestBody)) : resource.searchParams;
|
1337
|
+
if (isSafe(method)) {
|
1338
|
+
return [mergeIntoURLSearchParams(resource, searchParams), null];
|
1339
|
+
} else if (enctype == FetchEnctype.urlEncoded) {
|
1340
|
+
return [resource, searchParams];
|
1341
|
+
} else {
|
1342
|
+
return [resource, requestBody];
|
1343
|
+
}
|
1344
|
+
}
|
1345
|
+
function entriesExcludingFiles(requestBody) {
|
1346
|
+
const entries = [];
|
1347
|
+
for (const [name, value] of requestBody) {
|
1348
|
+
if (value instanceof File)
|
1349
|
+
continue;
|
1350
|
+
else
|
1351
|
+
entries.push([name, value]);
|
1352
|
+
}
|
1353
|
+
return entries;
|
1354
|
+
}
|
1355
|
+
function mergeIntoURLSearchParams(url, requestBody) {
|
1356
|
+
const searchParams = new URLSearchParams(entriesExcludingFiles(requestBody));
|
1357
|
+
url.search = searchParams.toString();
|
1358
|
+
return url;
|
1359
|
+
}
|
1140
1360
|
var AppearanceObserver = class {
|
1361
|
+
started = false;
|
1141
1362
|
constructor(delegate, element) {
|
1142
|
-
this.started = false;
|
1143
|
-
this.intersect = (entries) => {
|
1144
|
-
const lastEntry = entries.slice(-1)[0];
|
1145
|
-
if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
1146
|
-
this.delegate.elementAppearedInViewport(this.element);
|
1147
|
-
}
|
1148
|
-
};
|
1149
1363
|
this.delegate = delegate;
|
1150
1364
|
this.element = element;
|
1151
1365
|
this.intersectionObserver = new IntersectionObserver(this.intersect);
|
@@ -1162,8 +1376,15 @@
|
|
1162
1376
|
this.intersectionObserver.unobserve(this.element);
|
1163
1377
|
}
|
1164
1378
|
}
|
1379
|
+
intersect = (entries) => {
|
1380
|
+
const lastEntry = entries.slice(-1)[0];
|
1381
|
+
if (lastEntry?.isIntersecting) {
|
1382
|
+
this.delegate.elementAppearedInViewport(this.element);
|
1383
|
+
}
|
1384
|
+
};
|
1165
1385
|
};
|
1166
1386
|
var StreamMessage = class {
|
1387
|
+
static contentType = "text/vnd.turbo-stream.html";
|
1167
1388
|
static wrap(message) {
|
1168
1389
|
if (typeof message == "string") {
|
1169
1390
|
return new this(createDocumentFragment(message));
|
@@ -1175,7 +1396,6 @@
|
|
1175
1396
|
this.fragment = importStreamElements(fragment);
|
1176
1397
|
}
|
1177
1398
|
};
|
1178
|
-
StreamMessage.contentType = "text/vnd.turbo-stream.html";
|
1179
1399
|
function importStreamElements(fragment) {
|
1180
1400
|
for (const element of fragment.querySelectorAll("turbo-stream")) {
|
1181
1401
|
const streamElement = document.importNode(element, true);
|
@@ -1186,81 +1406,83 @@
|
|
1186
1406
|
}
|
1187
1407
|
return fragment;
|
1188
1408
|
}
|
1189
|
-
var
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
})(FormSubmissionState || (FormSubmissionState = {}));
|
1198
|
-
var FormEnctype;
|
1199
|
-
(function(FormEnctype2) {
|
1200
|
-
FormEnctype2["urlEncoded"] = "application/x-www-form-urlencoded";
|
1201
|
-
FormEnctype2["multipart"] = "multipart/form-data";
|
1202
|
-
FormEnctype2["plain"] = "text/plain";
|
1203
|
-
})(FormEnctype || (FormEnctype = {}));
|
1204
|
-
function formEnctypeFromString(encoding) {
|
1205
|
-
switch (encoding.toLowerCase()) {
|
1206
|
-
case FormEnctype.multipart:
|
1207
|
-
return FormEnctype.multipart;
|
1208
|
-
case FormEnctype.plain:
|
1209
|
-
return FormEnctype.plain;
|
1210
|
-
default:
|
1211
|
-
return FormEnctype.urlEncoded;
|
1409
|
+
var PREFETCH_DELAY = 100;
|
1410
|
+
var PrefetchCache = class {
|
1411
|
+
#prefetchTimeout = null;
|
1412
|
+
#prefetched = null;
|
1413
|
+
get(url) {
|
1414
|
+
if (this.#prefetched && this.#prefetched.url === url && this.#prefetched.expire > Date.now()) {
|
1415
|
+
return this.#prefetched.request;
|
1416
|
+
}
|
1212
1417
|
}
|
1213
|
-
|
1418
|
+
setLater(url, request, ttl) {
|
1419
|
+
this.clear();
|
1420
|
+
this.#prefetchTimeout = setTimeout(() => {
|
1421
|
+
request.perform();
|
1422
|
+
this.set(url, request, ttl);
|
1423
|
+
this.#prefetchTimeout = null;
|
1424
|
+
}, PREFETCH_DELAY);
|
1425
|
+
}
|
1426
|
+
set(url, request, ttl) {
|
1427
|
+
this.#prefetched = { url, request, expire: new Date((/* @__PURE__ */ new Date()).getTime() + ttl) };
|
1428
|
+
}
|
1429
|
+
clear() {
|
1430
|
+
if (this.#prefetchTimeout)
|
1431
|
+
clearTimeout(this.#prefetchTimeout);
|
1432
|
+
this.#prefetched = null;
|
1433
|
+
}
|
1434
|
+
};
|
1435
|
+
var cacheTtl = 10 * 1e3;
|
1436
|
+
var prefetchCache = new PrefetchCache();
|
1437
|
+
var FormSubmissionState = {
|
1438
|
+
initialized: "initialized",
|
1439
|
+
requesting: "requesting",
|
1440
|
+
waiting: "waiting",
|
1441
|
+
receiving: "receiving",
|
1442
|
+
stopping: "stopping",
|
1443
|
+
stopped: "stopped"
|
1444
|
+
};
|
1214
1445
|
var FormSubmission = class _FormSubmission {
|
1446
|
+
state = FormSubmissionState.initialized;
|
1215
1447
|
static confirmMethod(message, _element, _submitter) {
|
1216
1448
|
return Promise.resolve(confirm(message));
|
1217
1449
|
}
|
1218
1450
|
constructor(delegate, formElement, submitter, mustRedirect = false) {
|
1219
|
-
|
1451
|
+
const method = getMethod(formElement, submitter);
|
1452
|
+
const action = getAction(getFormAction(formElement, submitter), method);
|
1453
|
+
const body = buildFormData(formElement, submitter);
|
1454
|
+
const enctype = getEnctype(formElement, submitter);
|
1220
1455
|
this.delegate = delegate;
|
1221
1456
|
this.formElement = formElement;
|
1222
1457
|
this.submitter = submitter;
|
1223
|
-
this.
|
1224
|
-
this.location = expandURL(this.action);
|
1225
|
-
if (this.method == FetchMethod.get) {
|
1226
|
-
mergeFormDataEntries(this.location, [...this.body.entries()]);
|
1227
|
-
}
|
1228
|
-
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
1458
|
+
this.fetchRequest = new FetchRequest(this, method, action, body, formElement, enctype);
|
1229
1459
|
this.mustRedirect = mustRedirect;
|
1230
1460
|
}
|
1231
1461
|
get method() {
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1462
|
+
return this.fetchRequest.method;
|
1463
|
+
}
|
1464
|
+
set method(value) {
|
1465
|
+
this.fetchRequest.method = value;
|
1235
1466
|
}
|
1236
1467
|
get action() {
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
} else {
|
1242
|
-
return this.formElement.getAttribute("action") || formElementAction || "";
|
1243
|
-
}
|
1468
|
+
return this.fetchRequest.url.toString();
|
1469
|
+
}
|
1470
|
+
set action(value) {
|
1471
|
+
this.fetchRequest.url = expandURL(value);
|
1244
1472
|
}
|
1245
1473
|
get body() {
|
1246
|
-
|
1247
|
-
return new URLSearchParams(this.stringFormData);
|
1248
|
-
} else {
|
1249
|
-
return this.formData;
|
1250
|
-
}
|
1474
|
+
return this.fetchRequest.body;
|
1251
1475
|
}
|
1252
1476
|
get enctype() {
|
1253
|
-
|
1254
|
-
return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
|
1477
|
+
return this.fetchRequest.enctype;
|
1255
1478
|
}
|
1256
1479
|
get isSafe() {
|
1257
1480
|
return this.fetchRequest.isSafe;
|
1258
1481
|
}
|
1259
|
-
get
|
1260
|
-
return
|
1261
|
-
return entries.concat(typeof value == "string" ? [[name, value]] : []);
|
1262
|
-
}, []);
|
1482
|
+
get location() {
|
1483
|
+
return this.fetchRequest.url;
|
1263
1484
|
}
|
1485
|
+
// The submission process
|
1264
1486
|
async start() {
|
1265
1487
|
const { initialized, requesting } = FormSubmissionState;
|
1266
1488
|
const confirmationMessage = getAttribute("data-turbo-confirm", this.submitter, this.formElement);
|
@@ -1283,6 +1505,7 @@
|
|
1283
1505
|
return true;
|
1284
1506
|
}
|
1285
1507
|
}
|
1508
|
+
// Fetch request delegate
|
1286
1509
|
prepareRequest(request) {
|
1287
1510
|
if (!request.isSafe) {
|
1288
1511
|
const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
|
@@ -1295,10 +1518,10 @@
|
|
1295
1518
|
}
|
1296
1519
|
}
|
1297
1520
|
requestStarted(_request) {
|
1298
|
-
var _a;
|
1299
1521
|
this.state = FormSubmissionState.waiting;
|
1300
|
-
|
1522
|
+
this.submitter?.setAttribute("disabled", "");
|
1301
1523
|
this.setSubmitsWith();
|
1524
|
+
markAsBusy(this.formElement);
|
1302
1525
|
dispatch("turbo:submit-start", {
|
1303
1526
|
target: this.formElement,
|
1304
1527
|
detail: { formSubmission: this }
|
@@ -1306,12 +1529,16 @@
|
|
1306
1529
|
this.delegate.formSubmissionStarted(this);
|
1307
1530
|
}
|
1308
1531
|
requestPreventedHandlingResponse(request, response) {
|
1532
|
+
prefetchCache.clear();
|
1309
1533
|
this.result = { success: response.succeeded, fetchResponse: response };
|
1310
1534
|
}
|
1311
1535
|
requestSucceededWithResponse(request, response) {
|
1312
1536
|
if (response.clientError || response.serverError) {
|
1313
1537
|
this.delegate.formSubmissionFailedWithResponse(this, response);
|
1314
|
-
|
1538
|
+
return;
|
1539
|
+
}
|
1540
|
+
prefetchCache.clear();
|
1541
|
+
if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {
|
1315
1542
|
const error2 = new Error("Form responses must redirect to another location");
|
1316
1543
|
this.delegate.formSubmissionErrored(this, error2);
|
1317
1544
|
} else {
|
@@ -1329,16 +1556,17 @@
|
|
1329
1556
|
this.delegate.formSubmissionErrored(this, error2);
|
1330
1557
|
}
|
1331
1558
|
requestFinished(_request) {
|
1332
|
-
var _a;
|
1333
1559
|
this.state = FormSubmissionState.stopped;
|
1334
|
-
|
1560
|
+
this.submitter?.removeAttribute("disabled");
|
1335
1561
|
this.resetSubmitterText();
|
1562
|
+
clearBusyState(this.formElement);
|
1336
1563
|
dispatch("turbo:submit-end", {
|
1337
1564
|
target: this.formElement,
|
1338
|
-
detail:
|
1565
|
+
detail: { formSubmission: this, ...this.result }
|
1339
1566
|
});
|
1340
1567
|
this.delegate.formSubmissionFinished(this);
|
1341
1568
|
}
|
1569
|
+
// Private
|
1342
1570
|
setSubmitsWith() {
|
1343
1571
|
if (!this.submitter || !this.submitsWith)
|
1344
1572
|
return;
|
@@ -1368,14 +1596,13 @@
|
|
1368
1596
|
return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
|
1369
1597
|
}
|
1370
1598
|
get submitsWith() {
|
1371
|
-
|
1372
|
-
return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-submits-with");
|
1599
|
+
return this.submitter?.getAttribute("data-turbo-submits-with");
|
1373
1600
|
}
|
1374
1601
|
};
|
1375
1602
|
function buildFormData(formElement, submitter) {
|
1376
1603
|
const formData = new FormData(formElement);
|
1377
|
-
const name = submitter
|
1378
|
-
const value = submitter
|
1604
|
+
const name = submitter?.getAttribute("name");
|
1605
|
+
const value = submitter?.getAttribute("value");
|
1379
1606
|
if (name) {
|
1380
1607
|
formData.append(name, value || "");
|
1381
1608
|
}
|
@@ -1394,15 +1621,27 @@
|
|
1394
1621
|
function responseSucceededWithoutRedirect(response) {
|
1395
1622
|
return response.statusCode == 200 && !response.redirected;
|
1396
1623
|
}
|
1397
|
-
function
|
1398
|
-
const
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1624
|
+
function getFormAction(formElement, submitter) {
|
1625
|
+
const formElementAction = typeof formElement.action === "string" ? formElement.action : null;
|
1626
|
+
if (submitter?.hasAttribute("formaction")) {
|
1627
|
+
return submitter.getAttribute("formaction") || "";
|
1628
|
+
} else {
|
1629
|
+
return formElement.getAttribute("action") || formElementAction || "";
|
1403
1630
|
}
|
1404
|
-
|
1405
|
-
|
1631
|
+
}
|
1632
|
+
function getAction(formAction, fetchMethod) {
|
1633
|
+
const action = expandURL(formAction);
|
1634
|
+
if (isSafe(fetchMethod)) {
|
1635
|
+
action.search = "";
|
1636
|
+
}
|
1637
|
+
return action;
|
1638
|
+
}
|
1639
|
+
function getMethod(formElement, submitter) {
|
1640
|
+
const method = submitter?.getAttribute("formmethod") || formElement.getAttribute("method") || "";
|
1641
|
+
return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
|
1642
|
+
}
|
1643
|
+
function getEnctype(formElement, submitter) {
|
1644
|
+
return fetchEnctypeFromString(submitter?.getAttribute("formenctype") || formElement.enctype);
|
1406
1645
|
}
|
1407
1646
|
var Snapshot = class {
|
1408
1647
|
constructor(element) {
|
@@ -1424,14 +1663,7 @@
|
|
1424
1663
|
return this.element.isConnected;
|
1425
1664
|
}
|
1426
1665
|
get firstAutofocusableElement() {
|
1427
|
-
|
1428
|
-
for (const element of this.element.querySelectorAll("[autofocus]")) {
|
1429
|
-
if (element.closest(inertDisabledOrHidden) == null)
|
1430
|
-
return element;
|
1431
|
-
else
|
1432
|
-
continue;
|
1433
|
-
}
|
1434
|
-
return null;
|
1666
|
+
return queryAutofocusableElement(this.element);
|
1435
1667
|
}
|
1436
1668
|
get permanentElements() {
|
1437
1669
|
return queryPermanentElementsAll(this.element);
|
@@ -1458,23 +1690,8 @@
|
|
1458
1690
|
return node.querySelectorAll("[id][data-turbo-permanent]");
|
1459
1691
|
}
|
1460
1692
|
var FormSubmitObserver = class {
|
1693
|
+
started = false;
|
1461
1694
|
constructor(delegate, eventTarget) {
|
1462
|
-
this.started = false;
|
1463
|
-
this.submitCaptured = () => {
|
1464
|
-
this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
|
1465
|
-
this.eventTarget.addEventListener("submit", this.submitBubbled, false);
|
1466
|
-
};
|
1467
|
-
this.submitBubbled = (event) => {
|
1468
|
-
if (!event.defaultPrevented) {
|
1469
|
-
const form = event.target instanceof HTMLFormElement ? event.target : void 0;
|
1470
|
-
const submitter = event.submitter || void 0;
|
1471
|
-
if (form && submissionDoesNotDismissDialog(form, submitter) && submissionDoesNotTargetIFrame(form, submitter) && this.delegate.willSubmitForm(form, submitter)) {
|
1472
|
-
event.preventDefault();
|
1473
|
-
event.stopImmediatePropagation();
|
1474
|
-
this.delegate.formSubmitted(form, submitter);
|
1475
|
-
}
|
1476
|
-
}
|
1477
|
-
};
|
1478
1695
|
this.delegate = delegate;
|
1479
1696
|
this.eventTarget = eventTarget;
|
1480
1697
|
}
|
@@ -1490,14 +1707,29 @@
|
|
1490
1707
|
this.started = false;
|
1491
1708
|
}
|
1492
1709
|
}
|
1710
|
+
submitCaptured = () => {
|
1711
|
+
this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
|
1712
|
+
this.eventTarget.addEventListener("submit", this.submitBubbled, false);
|
1713
|
+
};
|
1714
|
+
submitBubbled = (event) => {
|
1715
|
+
if (!event.defaultPrevented) {
|
1716
|
+
const form = event.target instanceof HTMLFormElement ? event.target : void 0;
|
1717
|
+
const submitter = event.submitter || void 0;
|
1718
|
+
if (form && submissionDoesNotDismissDialog(form, submitter) && submissionDoesNotTargetIFrame(form, submitter) && this.delegate.willSubmitForm(form, submitter)) {
|
1719
|
+
event.preventDefault();
|
1720
|
+
event.stopImmediatePropagation();
|
1721
|
+
this.delegate.formSubmitted(form, submitter);
|
1722
|
+
}
|
1723
|
+
}
|
1724
|
+
};
|
1493
1725
|
};
|
1494
1726
|
function submissionDoesNotDismissDialog(form, submitter) {
|
1495
|
-
const method =
|
1727
|
+
const method = submitter?.getAttribute("formmethod") || form.getAttribute("method");
|
1496
1728
|
return method != "dialog";
|
1497
1729
|
}
|
1498
1730
|
function submissionDoesNotTargetIFrame(form, submitter) {
|
1499
|
-
if (
|
1500
|
-
const target =
|
1731
|
+
if (submitter?.hasAttribute("formtarget") || form.hasAttribute("target")) {
|
1732
|
+
const target = submitter?.getAttribute("formtarget") || form.target;
|
1501
1733
|
for (const element of document.getElementsByName(target)) {
|
1502
1734
|
if (element instanceof HTMLIFrameElement)
|
1503
1735
|
return false;
|
@@ -1508,14 +1740,15 @@
|
|
1508
1740
|
}
|
1509
1741
|
}
|
1510
1742
|
var View = class {
|
1743
|
+
#resolveRenderPromise = (_value) => {
|
1744
|
+
};
|
1745
|
+
#resolveInterceptionPromise = (_value) => {
|
1746
|
+
};
|
1511
1747
|
constructor(delegate, element) {
|
1512
|
-
this.resolveRenderPromise = (_value) => {
|
1513
|
-
};
|
1514
|
-
this.resolveInterceptionPromise = (_value) => {
|
1515
|
-
};
|
1516
1748
|
this.delegate = delegate;
|
1517
1749
|
this.element = element;
|
1518
1750
|
}
|
1751
|
+
// Scrolling
|
1519
1752
|
scrollToAnchor(anchor) {
|
1520
1753
|
const element = this.snapshot.getElementForAnchor(anchor);
|
1521
1754
|
if (element) {
|
@@ -1551,28 +1784,30 @@
|
|
1551
1784
|
get scrollRoot() {
|
1552
1785
|
return window;
|
1553
1786
|
}
|
1787
|
+
// Rendering
|
1554
1788
|
async render(renderer) {
|
1555
|
-
const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
|
1789
|
+
const { isPreview, shouldRender, willRender, newSnapshot: snapshot } = renderer;
|
1790
|
+
const shouldInvalidate = willRender;
|
1556
1791
|
if (shouldRender) {
|
1557
1792
|
try {
|
1558
|
-
this.renderPromise = new Promise((resolve) => this
|
1793
|
+
this.renderPromise = new Promise((resolve) => this.#resolveRenderPromise = resolve);
|
1559
1794
|
this.renderer = renderer;
|
1560
1795
|
await this.prepareToRenderSnapshot(renderer);
|
1561
|
-
const renderInterception = new Promise((resolve) => this
|
1562
|
-
const options = { resume: this
|
1796
|
+
const renderInterception = new Promise((resolve) => this.#resolveInterceptionPromise = resolve);
|
1797
|
+
const options = { resume: this.#resolveInterceptionPromise, render: this.renderer.renderElement, renderMethod: this.renderer.renderMethod };
|
1563
1798
|
const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
|
1564
1799
|
if (!immediateRender)
|
1565
1800
|
await renderInterception;
|
1566
1801
|
await this.renderSnapshot(renderer);
|
1567
|
-
this.delegate.viewRenderedSnapshot(snapshot, isPreview);
|
1802
|
+
this.delegate.viewRenderedSnapshot(snapshot, isPreview, this.renderer.renderMethod);
|
1568
1803
|
this.delegate.preloadOnLoadLinksForView(this.element);
|
1569
1804
|
this.finishRenderingSnapshot(renderer);
|
1570
1805
|
} finally {
|
1571
1806
|
delete this.renderer;
|
1572
|
-
this
|
1807
|
+
this.#resolveRenderPromise(void 0);
|
1573
1808
|
delete this.renderPromise;
|
1574
1809
|
}
|
1575
|
-
} else {
|
1810
|
+
} else if (shouldInvalidate) {
|
1576
1811
|
this.invalidate(renderer.reloadReason);
|
1577
1812
|
}
|
1578
1813
|
}
|
@@ -1590,6 +1825,12 @@
|
|
1590
1825
|
this.element.removeAttribute("data-turbo-preview");
|
1591
1826
|
}
|
1592
1827
|
}
|
1828
|
+
markVisitDirection(direction) {
|
1829
|
+
this.element.setAttribute("data-turbo-visit-direction", direction);
|
1830
|
+
}
|
1831
|
+
unmarkVisitDirection() {
|
1832
|
+
this.element.removeAttribute("data-turbo-visit-direction");
|
1833
|
+
}
|
1593
1834
|
async renderSnapshot(renderer) {
|
1594
1835
|
await renderer.render();
|
1595
1836
|
}
|
@@ -1607,26 +1848,6 @@
|
|
1607
1848
|
};
|
1608
1849
|
var LinkInterceptor = class {
|
1609
1850
|
constructor(delegate, element) {
|
1610
|
-
this.clickBubbled = (event) => {
|
1611
|
-
if (this.respondsToEventTarget(event.target)) {
|
1612
|
-
this.clickEvent = event;
|
1613
|
-
} else {
|
1614
|
-
delete this.clickEvent;
|
1615
|
-
}
|
1616
|
-
};
|
1617
|
-
this.linkClicked = (event) => {
|
1618
|
-
if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
|
1619
|
-
if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
|
1620
|
-
this.clickEvent.preventDefault();
|
1621
|
-
event.preventDefault();
|
1622
|
-
this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
|
1623
|
-
}
|
1624
|
-
}
|
1625
|
-
delete this.clickEvent;
|
1626
|
-
};
|
1627
|
-
this.willVisit = (_event) => {
|
1628
|
-
delete this.clickEvent;
|
1629
|
-
};
|
1630
1851
|
this.delegate = delegate;
|
1631
1852
|
this.element = element;
|
1632
1853
|
}
|
@@ -1640,31 +1861,34 @@
|
|
1640
1861
|
document.removeEventListener("turbo:click", this.linkClicked);
|
1641
1862
|
document.removeEventListener("turbo:before-visit", this.willVisit);
|
1642
1863
|
}
|
1864
|
+
clickBubbled = (event) => {
|
1865
|
+
if (this.respondsToEventTarget(event.target)) {
|
1866
|
+
this.clickEvent = event;
|
1867
|
+
} else {
|
1868
|
+
delete this.clickEvent;
|
1869
|
+
}
|
1870
|
+
};
|
1871
|
+
linkClicked = (event) => {
|
1872
|
+
if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
|
1873
|
+
if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
|
1874
|
+
this.clickEvent.preventDefault();
|
1875
|
+
event.preventDefault();
|
1876
|
+
this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
|
1877
|
+
}
|
1878
|
+
}
|
1879
|
+
delete this.clickEvent;
|
1880
|
+
};
|
1881
|
+
willVisit = (_event) => {
|
1882
|
+
delete this.clickEvent;
|
1883
|
+
};
|
1643
1884
|
respondsToEventTarget(target) {
|
1644
1885
|
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
1645
1886
|
return element && element.closest("turbo-frame, html") == this.element;
|
1646
1887
|
}
|
1647
1888
|
};
|
1648
1889
|
var LinkClickObserver = class {
|
1890
|
+
started = false;
|
1649
1891
|
constructor(delegate, eventTarget) {
|
1650
|
-
this.started = false;
|
1651
|
-
this.clickCaptured = () => {
|
1652
|
-
this.eventTarget.removeEventListener("click", this.clickBubbled, false);
|
1653
|
-
this.eventTarget.addEventListener("click", this.clickBubbled, false);
|
1654
|
-
};
|
1655
|
-
this.clickBubbled = (event) => {
|
1656
|
-
if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
|
1657
|
-
const target = event.composedPath && event.composedPath()[0] || event.target;
|
1658
|
-
const link = this.findLinkFromClickTarget(target);
|
1659
|
-
if (link && doesNotTargetIFrame(link)) {
|
1660
|
-
const location2 = this.getLocationForLink(link);
|
1661
|
-
if (this.delegate.willFollowLinkToLocation(link, location2, event)) {
|
1662
|
-
event.preventDefault();
|
1663
|
-
this.delegate.followedLinkToLocation(link, location2);
|
1664
|
-
}
|
1665
|
-
}
|
1666
|
-
}
|
1667
|
-
};
|
1668
1892
|
this.delegate = delegate;
|
1669
1893
|
this.eventTarget = eventTarget;
|
1670
1894
|
}
|
@@ -1680,27 +1904,27 @@
|
|
1680
1904
|
this.started = false;
|
1681
1905
|
}
|
1682
1906
|
}
|
1907
|
+
clickCaptured = () => {
|
1908
|
+
this.eventTarget.removeEventListener("click", this.clickBubbled, false);
|
1909
|
+
this.eventTarget.addEventListener("click", this.clickBubbled, false);
|
1910
|
+
};
|
1911
|
+
clickBubbled = (event) => {
|
1912
|
+
if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
|
1913
|
+
const target = event.composedPath && event.composedPath()[0] || event.target;
|
1914
|
+
const link = findLinkFromClickTarget(target);
|
1915
|
+
if (link && doesNotTargetIFrame(link)) {
|
1916
|
+
const location2 = getLocationForLink(link);
|
1917
|
+
if (this.delegate.willFollowLinkToLocation(link, location2, event)) {
|
1918
|
+
event.preventDefault();
|
1919
|
+
this.delegate.followedLinkToLocation(link, location2);
|
1920
|
+
}
|
1921
|
+
}
|
1922
|
+
}
|
1923
|
+
};
|
1683
1924
|
clickEventIsSignificant(event) {
|
1684
1925
|
return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
|
1685
1926
|
}
|
1686
|
-
findLinkFromClickTarget(target) {
|
1687
|
-
return findClosestRecursively(target, "a[href]:not([target^=_]):not([download])");
|
1688
|
-
}
|
1689
|
-
getLocationForLink(link) {
|
1690
|
-
return expandURL(link.getAttribute("href") || "");
|
1691
|
-
}
|
1692
1927
|
};
|
1693
|
-
function doesNotTargetIFrame(anchor) {
|
1694
|
-
if (anchor.hasAttribute("target")) {
|
1695
|
-
for (const element of document.getElementsByName(anchor.target)) {
|
1696
|
-
if (element instanceof HTMLIFrameElement)
|
1697
|
-
return false;
|
1698
|
-
}
|
1699
|
-
return true;
|
1700
|
-
} else {
|
1701
|
-
return true;
|
1702
|
-
}
|
1703
|
-
}
|
1704
1928
|
var FormLinkClickObserver = class {
|
1705
1929
|
constructor(delegate, element) {
|
1706
1930
|
this.delegate = delegate;
|
@@ -1712,8 +1936,16 @@
|
|
1712
1936
|
stop() {
|
1713
1937
|
this.linkInterceptor.stop();
|
1714
1938
|
}
|
1939
|
+
// Link hover observer delegate
|
1940
|
+
canPrefetchRequestToLocation(link, location2) {
|
1941
|
+
return false;
|
1942
|
+
}
|
1943
|
+
prefetchAndCacheRequestToLocation(link, location2) {
|
1944
|
+
return;
|
1945
|
+
}
|
1946
|
+
// Link click observer delegate
|
1715
1947
|
willFollowLinkToLocation(link, location2, originalEvent) {
|
1716
|
-
return this.delegate.willSubmitFormLinkToLocation(link, location2, originalEvent) && link.hasAttribute("data-turbo-method");
|
1948
|
+
return this.delegate.willSubmitFormLinkToLocation(link, location2, originalEvent) && (link.hasAttribute("data-turbo-method") || link.hasAttribute("data-turbo-stream"));
|
1717
1949
|
}
|
1718
1950
|
followedLinkToLocation(link, location2) {
|
1719
1951
|
const form = document.createElement("form");
|
@@ -1782,7 +2014,7 @@
|
|
1782
2014
|
}
|
1783
2015
|
replacePlaceholderWithPermanentElement(permanentElement) {
|
1784
2016
|
const placeholder = this.getPlaceholderById(permanentElement.id);
|
1785
|
-
placeholder
|
2017
|
+
placeholder?.replaceWith(permanentElement);
|
1786
2018
|
}
|
1787
2019
|
getPlaceholderById(id) {
|
1788
2020
|
return this.placeholders.find((element) => element.content == id);
|
@@ -1798,8 +2030,8 @@
|
|
1798
2030
|
return element;
|
1799
2031
|
}
|
1800
2032
|
var Renderer = class {
|
2033
|
+
#activeElement = null;
|
1801
2034
|
constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
1802
|
-
this.activeElement = null;
|
1803
2035
|
this.currentSnapshot = currentSnapshot;
|
1804
2036
|
this.newSnapshot = newSnapshot;
|
1805
2037
|
this.isPreview = isPreview;
|
@@ -1816,6 +2048,8 @@
|
|
1816
2048
|
prepareToRender() {
|
1817
2049
|
return;
|
1818
2050
|
}
|
2051
|
+
render() {
|
2052
|
+
}
|
1819
2053
|
finishRendering() {
|
1820
2054
|
if (this.resolvingFunctions) {
|
1821
2055
|
this.resolvingFunctions.resolve();
|
@@ -1827,21 +2061,22 @@
|
|
1827
2061
|
}
|
1828
2062
|
focusFirstAutofocusableElement() {
|
1829
2063
|
const element = this.connectedSnapshot.firstAutofocusableElement;
|
1830
|
-
if (
|
2064
|
+
if (element) {
|
1831
2065
|
element.focus();
|
1832
2066
|
}
|
1833
2067
|
}
|
2068
|
+
// Bardo delegate
|
1834
2069
|
enteringBardo(currentPermanentElement) {
|
1835
|
-
if (this
|
2070
|
+
if (this.#activeElement)
|
1836
2071
|
return;
|
1837
2072
|
if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
|
1838
|
-
this
|
2073
|
+
this.#activeElement = this.currentSnapshot.activeElement;
|
1839
2074
|
}
|
1840
2075
|
}
|
1841
2076
|
leavingBardo(currentPermanentElement) {
|
1842
|
-
if (currentPermanentElement.contains(this
|
1843
|
-
this
|
1844
|
-
this
|
2077
|
+
if (currentPermanentElement.contains(this.#activeElement) && this.#activeElement instanceof HTMLElement) {
|
2078
|
+
this.#activeElement.focus();
|
2079
|
+
this.#activeElement = null;
|
1845
2080
|
}
|
1846
2081
|
}
|
1847
2082
|
get connectedSnapshot() {
|
@@ -1856,18 +2091,17 @@
|
|
1856
2091
|
get permanentElementMap() {
|
1857
2092
|
return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
|
1858
2093
|
}
|
2094
|
+
get renderMethod() {
|
2095
|
+
return "replace";
|
2096
|
+
}
|
1859
2097
|
};
|
1860
|
-
function elementIsFocusable(element) {
|
1861
|
-
return element && typeof element.focus == "function";
|
1862
|
-
}
|
1863
2098
|
var FrameRenderer = class extends Renderer {
|
1864
2099
|
static renderElement(currentElement, newElement) {
|
1865
|
-
var _a;
|
1866
2100
|
const destinationRange = document.createRange();
|
1867
2101
|
destinationRange.selectNodeContents(currentElement);
|
1868
2102
|
destinationRange.deleteContents();
|
1869
2103
|
const frameElement = newElement;
|
1870
|
-
const sourceRange =
|
2104
|
+
const sourceRange = frameElement.ownerDocument?.createRange();
|
1871
2105
|
if (sourceRange) {
|
1872
2106
|
sourceRange.selectNodeContents(frameElement);
|
1873
2107
|
currentElement.appendChild(sourceRange.extractContents());
|
@@ -1881,14 +2115,14 @@
|
|
1881
2115
|
return true;
|
1882
2116
|
}
|
1883
2117
|
async render() {
|
1884
|
-
await
|
2118
|
+
await nextRepaint();
|
1885
2119
|
this.preservingPermanentElements(() => {
|
1886
2120
|
this.loadFrameElement();
|
1887
2121
|
});
|
1888
2122
|
this.scrollFrameIntoView();
|
1889
|
-
await
|
2123
|
+
await nextRepaint();
|
1890
2124
|
this.focusFirstAutofocusableElement();
|
1891
|
-
await
|
2125
|
+
await nextRepaint();
|
1892
2126
|
this.activateScriptElements();
|
1893
2127
|
}
|
1894
2128
|
loadFrameElement() {
|
@@ -1932,6 +2166,8 @@
|
|
1932
2166
|
}
|
1933
2167
|
}
|
1934
2168
|
var ProgressBar = class _ProgressBar {
|
2169
|
+
static animationDuration = 300;
|
2170
|
+
/*ms*/
|
1935
2171
|
static get defaultCSS() {
|
1936
2172
|
return unindent`
|
1937
2173
|
.turbo-progress-bar {
|
@@ -1949,13 +2185,10 @@
|
|
1949
2185
|
}
|
1950
2186
|
`;
|
1951
2187
|
}
|
2188
|
+
hiding = false;
|
2189
|
+
value = 0;
|
2190
|
+
visible = false;
|
1952
2191
|
constructor() {
|
1953
|
-
this.hiding = false;
|
1954
|
-
this.value = 0;
|
1955
|
-
this.visible = false;
|
1956
|
-
this.trickle = () => {
|
1957
|
-
this.setValue(this.value + Math.random() / 100);
|
1958
|
-
};
|
1959
2192
|
this.stylesheetElement = this.createStylesheetElement();
|
1960
2193
|
this.progressElement = this.createProgressElement();
|
1961
2194
|
this.installStylesheetElement();
|
@@ -1983,6 +2216,7 @@
|
|
1983
2216
|
this.value = value;
|
1984
2217
|
this.refresh();
|
1985
2218
|
}
|
2219
|
+
// Private
|
1986
2220
|
installStylesheetElement() {
|
1987
2221
|
document.head.insertBefore(this.stylesheetElement, document.head.firstChild);
|
1988
2222
|
}
|
@@ -2010,6 +2244,9 @@
|
|
2010
2244
|
window.clearInterval(this.trickleInterval);
|
2011
2245
|
delete this.trickleInterval;
|
2012
2246
|
}
|
2247
|
+
trickle = () => {
|
2248
|
+
this.setValue(this.value + Math.random() / 100);
|
2249
|
+
};
|
2013
2250
|
refresh() {
|
2014
2251
|
requestAnimationFrame(() => {
|
2015
2252
|
this.progressElement.style.width = `${10 + this.value * 90}%`;
|
@@ -2033,20 +2270,22 @@
|
|
2033
2270
|
return getMetaContent("csp-nonce");
|
2034
2271
|
}
|
2035
2272
|
};
|
2036
|
-
ProgressBar.animationDuration = 300;
|
2037
2273
|
var HeadSnapshot = class extends Snapshot {
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2274
|
+
detailsByOuterHTML = this.children.filter((element) => !elementIsNoscript(element)).map((element) => elementWithoutNonce(element)).reduce((result, element) => {
|
2275
|
+
const { outerHTML } = element;
|
2276
|
+
const details = outerHTML in result ? result[outerHTML] : {
|
2277
|
+
type: elementType(element),
|
2278
|
+
tracked: elementIsTracked(element),
|
2279
|
+
elements: []
|
2280
|
+
};
|
2281
|
+
return {
|
2282
|
+
...result,
|
2283
|
+
[outerHTML]: {
|
2284
|
+
...details,
|
2285
|
+
elements: [...details.elements, element]
|
2286
|
+
}
|
2287
|
+
};
|
2288
|
+
}, {});
|
2050
2289
|
get trackedElementSignature() {
|
2051
2290
|
return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked).join("");
|
2052
2291
|
}
|
@@ -2077,9 +2316,11 @@
|
|
2077
2316
|
}
|
2078
2317
|
findMetaElementByName(name) {
|
2079
2318
|
return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
2080
|
-
const {
|
2319
|
+
const {
|
2320
|
+
elements: [element]
|
2321
|
+
} = this.detailsByOuterHTML[outerHTML];
|
2081
2322
|
return elementIsMetaElementWithName(element, name) ? element : result;
|
2082
|
-
}, void 0);
|
2323
|
+
}, void 0 | void 0);
|
2083
2324
|
}
|
2084
2325
|
};
|
2085
2326
|
function elementType(element) {
|
@@ -2121,11 +2362,12 @@
|
|
2121
2362
|
static fromElement(element) {
|
2122
2363
|
return this.fromDocument(element.ownerDocument);
|
2123
2364
|
}
|
2124
|
-
static fromDocument({
|
2125
|
-
return new this(body, new HeadSnapshot(head));
|
2365
|
+
static fromDocument({ documentElement, body, head }) {
|
2366
|
+
return new this(documentElement, body, new HeadSnapshot(head));
|
2126
2367
|
}
|
2127
|
-
constructor(
|
2128
|
-
super(
|
2368
|
+
constructor(documentElement, body, headSnapshot) {
|
2369
|
+
super(body);
|
2370
|
+
this.documentElement = documentElement;
|
2129
2371
|
this.headSnapshot = headSnapshot;
|
2130
2372
|
}
|
2131
2373
|
clone() {
|
@@ -2142,14 +2384,16 @@
|
|
2142
2384
|
for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
|
2143
2385
|
clonedPasswordInput.value = "";
|
2144
2386
|
}
|
2145
|
-
return new _PageSnapshot(clonedElement, this.headSnapshot);
|
2387
|
+
return new _PageSnapshot(this.documentElement, clonedElement, this.headSnapshot);
|
2388
|
+
}
|
2389
|
+
get lang() {
|
2390
|
+
return this.documentElement.getAttribute("lang");
|
2146
2391
|
}
|
2147
2392
|
get headElement() {
|
2148
2393
|
return this.headSnapshot.element;
|
2149
2394
|
}
|
2150
2395
|
get rootLocation() {
|
2151
|
-
|
2152
|
-
const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
|
2396
|
+
const root = this.getSetting("root") ?? "/";
|
2153
2397
|
return expandURL(root);
|
2154
2398
|
}
|
2155
2399
|
get cacheControlValue() {
|
@@ -2164,25 +2408,38 @@
|
|
2164
2408
|
get isVisitable() {
|
2165
2409
|
return this.getSetting("visit-control") != "reload";
|
2166
2410
|
}
|
2411
|
+
get prefersViewTransitions() {
|
2412
|
+
return this.headSnapshot.getMetaValue("view-transition") === "same-origin";
|
2413
|
+
}
|
2414
|
+
get shouldMorphPage() {
|
2415
|
+
return this.getSetting("refresh-method") === "morph";
|
2416
|
+
}
|
2417
|
+
get shouldPreserveScrollPosition() {
|
2418
|
+
return this.getSetting("refresh-scroll") === "preserve";
|
2419
|
+
}
|
2420
|
+
// Private
|
2167
2421
|
getSetting(name) {
|
2168
2422
|
return this.headSnapshot.getMetaValue(`turbo-${name}`);
|
2169
2423
|
}
|
2170
2424
|
};
|
2171
|
-
var
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
|
2179
|
-
|
2180
|
-
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2425
|
+
var ViewTransitioner = class {
|
2426
|
+
#viewTransitionStarted = false;
|
2427
|
+
#lastOperation = Promise.resolve();
|
2428
|
+
renderChange(useViewTransition, render) {
|
2429
|
+
if (useViewTransition && this.viewTransitionsAvailable && !this.#viewTransitionStarted) {
|
2430
|
+
this.#viewTransitionStarted = true;
|
2431
|
+
this.#lastOperation = this.#lastOperation.then(async () => {
|
2432
|
+
await document.startViewTransition(render).finished;
|
2433
|
+
});
|
2434
|
+
} else {
|
2435
|
+
this.#lastOperation = this.#lastOperation.then(render);
|
2436
|
+
}
|
2437
|
+
return this.#lastOperation;
|
2438
|
+
}
|
2439
|
+
get viewTransitionsAvailable() {
|
2440
|
+
return document.startViewTransition;
|
2441
|
+
}
|
2442
|
+
};
|
2186
2443
|
var defaultOptions = {
|
2187
2444
|
action: "advance",
|
2188
2445
|
historyChanged: false,
|
@@ -2193,27 +2450,62 @@
|
|
2193
2450
|
shouldCacheSnapshot: true,
|
2194
2451
|
acceptsStreamResponse: false
|
2195
2452
|
};
|
2196
|
-
var
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
2200
|
-
|
2201
|
-
}
|
2453
|
+
var TimingMetric = {
|
2454
|
+
visitStart: "visitStart",
|
2455
|
+
requestStart: "requestStart",
|
2456
|
+
requestEnd: "requestEnd",
|
2457
|
+
visitEnd: "visitEnd"
|
2458
|
+
};
|
2459
|
+
var VisitState = {
|
2460
|
+
initialized: "initialized",
|
2461
|
+
started: "started",
|
2462
|
+
canceled: "canceled",
|
2463
|
+
failed: "failed",
|
2464
|
+
completed: "completed"
|
2465
|
+
};
|
2466
|
+
var SystemStatusCode = {
|
2467
|
+
networkFailure: 0,
|
2468
|
+
timeoutFailure: -1,
|
2469
|
+
contentTypeMismatch: -2
|
2470
|
+
};
|
2471
|
+
var Direction = {
|
2472
|
+
advance: "forward",
|
2473
|
+
restore: "back",
|
2474
|
+
replace: "none"
|
2475
|
+
};
|
2202
2476
|
var Visit = class {
|
2477
|
+
identifier = uuid();
|
2478
|
+
// Required by turbo-ios
|
2479
|
+
timingMetrics = {};
|
2480
|
+
followedRedirect = false;
|
2481
|
+
historyChanged = false;
|
2482
|
+
scrolled = false;
|
2483
|
+
shouldCacheSnapshot = true;
|
2484
|
+
acceptsStreamResponse = false;
|
2485
|
+
snapshotCached = false;
|
2486
|
+
state = VisitState.initialized;
|
2487
|
+
viewTransitioner = new ViewTransitioner();
|
2203
2488
|
constructor(delegate, location2, restorationIdentifier, options = {}) {
|
2204
|
-
this.identifier = uuid();
|
2205
|
-
this.timingMetrics = {};
|
2206
|
-
this.followedRedirect = false;
|
2207
|
-
this.historyChanged = false;
|
2208
|
-
this.scrolled = false;
|
2209
|
-
this.shouldCacheSnapshot = true;
|
2210
|
-
this.acceptsStreamResponse = false;
|
2211
|
-
this.snapshotCached = false;
|
2212
|
-
this.state = VisitState.initialized;
|
2213
2489
|
this.delegate = delegate;
|
2214
2490
|
this.location = location2;
|
2215
2491
|
this.restorationIdentifier = restorationIdentifier || uuid();
|
2216
|
-
const {
|
2492
|
+
const {
|
2493
|
+
action,
|
2494
|
+
historyChanged,
|
2495
|
+
referrer,
|
2496
|
+
snapshot,
|
2497
|
+
snapshotHTML,
|
2498
|
+
response,
|
2499
|
+
visitCachedSnapshot,
|
2500
|
+
willRender,
|
2501
|
+
updateHistory,
|
2502
|
+
shouldCacheSnapshot,
|
2503
|
+
acceptsStreamResponse,
|
2504
|
+
direction
|
2505
|
+
} = {
|
2506
|
+
...defaultOptions,
|
2507
|
+
...options
|
2508
|
+
};
|
2217
2509
|
this.action = action;
|
2218
2510
|
this.historyChanged = historyChanged;
|
2219
2511
|
this.referrer = referrer;
|
@@ -2221,12 +2513,14 @@
|
|
2221
2513
|
this.snapshotHTML = snapshotHTML;
|
2222
2514
|
this.response = response;
|
2223
2515
|
this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
2516
|
+
this.isPageRefresh = this.view.isPageRefresh(this);
|
2224
2517
|
this.visitCachedSnapshot = visitCachedSnapshot;
|
2225
2518
|
this.willRender = willRender;
|
2226
2519
|
this.updateHistory = updateHistory;
|
2227
2520
|
this.scrolled = !willRender;
|
2228
2521
|
this.shouldCacheSnapshot = shouldCacheSnapshot;
|
2229
2522
|
this.acceptsStreamResponse = acceptsStreamResponse;
|
2523
|
+
this.direction = direction || Direction[action];
|
2230
2524
|
}
|
2231
2525
|
get adapter() {
|
2232
2526
|
return this.delegate.adapter;
|
@@ -2263,10 +2557,10 @@
|
|
2263
2557
|
complete() {
|
2264
2558
|
if (this.state == VisitState.started) {
|
2265
2559
|
this.recordTimingMetric(TimingMetric.visitEnd);
|
2560
|
+
this.adapter.visitCompleted(this);
|
2266
2561
|
this.state = VisitState.completed;
|
2267
2562
|
this.followRedirect();
|
2268
2563
|
if (!this.followedRedirect) {
|
2269
|
-
this.adapter.visitCompleted(this);
|
2270
2564
|
this.delegate.visitCompleted(this);
|
2271
2565
|
}
|
2272
2566
|
}
|
@@ -2275,12 +2569,12 @@
|
|
2275
2569
|
if (this.state == VisitState.started) {
|
2276
2570
|
this.state = VisitState.failed;
|
2277
2571
|
this.adapter.visitFailed(this);
|
2572
|
+
this.delegate.visitCompleted(this);
|
2278
2573
|
}
|
2279
2574
|
}
|
2280
2575
|
changeHistory() {
|
2281
|
-
var _a;
|
2282
2576
|
if (!this.historyChanged && this.updateHistory) {
|
2283
|
-
const actionForHistory = this.location.href ===
|
2577
|
+
const actionForHistory = this.location.href === this.referrer?.href ? "replace" : this.action;
|
2284
2578
|
const method = getHistoryMethodForAction(actionForHistory);
|
2285
2579
|
this.history.update(method, this.location, this.restorationIdentifier);
|
2286
2580
|
this.historyChanged = true;
|
@@ -2329,8 +2623,8 @@
|
|
2329
2623
|
if (this.view.renderPromise)
|
2330
2624
|
await this.view.renderPromise;
|
2331
2625
|
if (isSuccessful(statusCode) && responseHTML != null) {
|
2332
|
-
|
2333
|
-
this.
|
2626
|
+
const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
2627
|
+
await this.renderPageSnapshot(snapshot, false);
|
2334
2628
|
this.adapter.visitRendered(this);
|
2335
2629
|
this.complete();
|
2336
2630
|
} else {
|
@@ -2363,13 +2657,12 @@
|
|
2363
2657
|
const isPreview = this.shouldIssueRequest();
|
2364
2658
|
this.render(async () => {
|
2365
2659
|
this.cacheSnapshot();
|
2366
|
-
if (this.isSamePage) {
|
2660
|
+
if (this.isSamePage || this.isPageRefresh) {
|
2367
2661
|
this.adapter.visitRendered(this);
|
2368
2662
|
} else {
|
2369
2663
|
if (this.view.renderPromise)
|
2370
2664
|
await this.view.renderPromise;
|
2371
|
-
await this.
|
2372
|
-
this.performScroll();
|
2665
|
+
await this.renderPageSnapshot(snapshot, isPreview);
|
2373
2666
|
this.adapter.visitRendered(this);
|
2374
2667
|
if (!isPreview) {
|
2375
2668
|
this.complete();
|
@@ -2379,8 +2672,7 @@
|
|
2379
2672
|
}
|
2380
2673
|
}
|
2381
2674
|
followRedirect() {
|
2382
|
-
|
2383
|
-
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
2675
|
+
if (this.redirectedToLocation && !this.followedRedirect && this.response?.redirected) {
|
2384
2676
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
2385
2677
|
action: "replace",
|
2386
2678
|
response: this.response,
|
@@ -2400,6 +2692,7 @@
|
|
2400
2692
|
});
|
2401
2693
|
}
|
2402
2694
|
}
|
2695
|
+
// Fetch request delegate
|
2403
2696
|
prepareRequest(request) {
|
2404
2697
|
if (this.acceptsStreamResponse) {
|
2405
2698
|
request.acceptResponseType(StreamMessage.contentType);
|
@@ -2444,8 +2737,9 @@
|
|
2444
2737
|
requestFinished() {
|
2445
2738
|
this.finishRequest();
|
2446
2739
|
}
|
2740
|
+
// Scrolling
|
2447
2741
|
performScroll() {
|
2448
|
-
if (!this.scrolled && !this.view.forceReloaded) {
|
2742
|
+
if (!this.scrolled && !this.view.forceReloaded && !this.view.shouldPreserveScrollPosition(this)) {
|
2449
2743
|
if (this.action == "restore") {
|
2450
2744
|
this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
|
2451
2745
|
} else {
|
@@ -2471,12 +2765,14 @@
|
|
2471
2765
|
return true;
|
2472
2766
|
}
|
2473
2767
|
}
|
2768
|
+
// Instrumentation
|
2474
2769
|
recordTimingMetric(metric) {
|
2475
2770
|
this.timingMetrics[metric] = (/* @__PURE__ */ new Date()).getTime();
|
2476
2771
|
}
|
2477
2772
|
getTimingMetrics() {
|
2478
|
-
return
|
2773
|
+
return { ...this.timingMetrics };
|
2479
2774
|
}
|
2775
|
+
// Private
|
2480
2776
|
getHistoryMethodForAction(action) {
|
2481
2777
|
switch (action) {
|
2482
2778
|
case "replace":
|
@@ -2506,12 +2802,16 @@
|
|
2506
2802
|
}
|
2507
2803
|
async render(callback) {
|
2508
2804
|
this.cancelRender();
|
2509
|
-
await
|
2510
|
-
this.frame = requestAnimationFrame(() => resolve());
|
2511
|
-
});
|
2805
|
+
this.frame = await nextRepaint();
|
2512
2806
|
await callback();
|
2513
2807
|
delete this.frame;
|
2514
2808
|
}
|
2809
|
+
async renderPageSnapshot(snapshot, isPreview) {
|
2810
|
+
await this.viewTransitioner.renderChange(this.view.shouldTransitionTo(snapshot), async () => {
|
2811
|
+
await this.view.renderPage(snapshot, isPreview, this.willRender, this);
|
2812
|
+
this.performScroll();
|
2813
|
+
});
|
2814
|
+
}
|
2515
2815
|
cancelRender() {
|
2516
2816
|
if (this.frame) {
|
2517
2817
|
cancelAnimationFrame(this.frame);
|
@@ -2523,15 +2823,16 @@
|
|
2523
2823
|
return statusCode >= 200 && statusCode < 300;
|
2524
2824
|
}
|
2525
2825
|
var BrowserAdapter = class {
|
2826
|
+
progressBar = new ProgressBar();
|
2526
2827
|
constructor(session2) {
|
2527
|
-
this.progressBar = new ProgressBar();
|
2528
|
-
this.showProgressBar = () => {
|
2529
|
-
this.progressBar.show();
|
2530
|
-
};
|
2531
2828
|
this.session = session2;
|
2532
2829
|
}
|
2533
2830
|
visitProposedToLocation(location2, options) {
|
2534
|
-
|
2831
|
+
if (locationIsVisitable(location2, this.navigator.rootLocation)) {
|
2832
|
+
this.navigator.startVisit(location2, options?.restorationIdentifier || uuid(), options);
|
2833
|
+
} else {
|
2834
|
+
window.location.href = location2.toString();
|
2835
|
+
}
|
2535
2836
|
}
|
2536
2837
|
visitStarted(visit2) {
|
2537
2838
|
this.location = visit2.location;
|
@@ -2566,18 +2867,21 @@
|
|
2566
2867
|
}
|
2567
2868
|
}
|
2568
2869
|
visitRequestFinished(_visit) {
|
2569
|
-
this.progressBar.setValue(1);
|
2570
|
-
this.hideVisitProgressBar();
|
2571
2870
|
}
|
2572
2871
|
visitCompleted(_visit) {
|
2872
|
+
this.progressBar.setValue(1);
|
2873
|
+
this.hideVisitProgressBar();
|
2573
2874
|
}
|
2574
2875
|
pageInvalidated(reason) {
|
2575
2876
|
this.reload(reason);
|
2576
2877
|
}
|
2577
2878
|
visitFailed(_visit) {
|
2879
|
+
this.progressBar.setValue(1);
|
2880
|
+
this.hideVisitProgressBar();
|
2578
2881
|
}
|
2579
2882
|
visitRendered(_visit) {
|
2580
2883
|
}
|
2884
|
+
// Form Submission Delegate
|
2581
2885
|
formSubmissionStarted(_formSubmission) {
|
2582
2886
|
this.progressBar.setValue(0);
|
2583
2887
|
this.showFormProgressBarAfterDelay();
|
@@ -2586,6 +2890,7 @@
|
|
2586
2890
|
this.progressBar.setValue(1);
|
2587
2891
|
this.hideFormProgressBar();
|
2588
2892
|
}
|
2893
|
+
// Private
|
2589
2894
|
showVisitProgressBarAfterDelay() {
|
2590
2895
|
this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
|
2591
2896
|
}
|
@@ -2608,26 +2913,21 @@
|
|
2608
2913
|
delete this.formProgressBarTimeout;
|
2609
2914
|
}
|
2610
2915
|
}
|
2916
|
+
showProgressBar = () => {
|
2917
|
+
this.progressBar.show();
|
2918
|
+
};
|
2611
2919
|
reload(reason) {
|
2612
|
-
var _a;
|
2613
2920
|
dispatch("turbo:reload", { detail: reason });
|
2614
|
-
window.location.href =
|
2921
|
+
window.location.href = this.location?.toString() || window.location.href;
|
2615
2922
|
}
|
2616
2923
|
get navigator() {
|
2617
2924
|
return this.session.navigator;
|
2618
2925
|
}
|
2619
2926
|
};
|
2620
2927
|
var CacheObserver = class {
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
this.started = false;
|
2625
|
-
this.removeTemporaryElements = (_event) => {
|
2626
|
-
for (const element of this.temporaryElements) {
|
2627
|
-
element.remove();
|
2628
|
-
}
|
2629
|
-
};
|
2630
|
-
}
|
2928
|
+
selector = "[data-turbo-temporary]";
|
2929
|
+
deprecatedSelector = "[data-turbo-cache=false]";
|
2930
|
+
started = false;
|
2631
2931
|
start() {
|
2632
2932
|
if (!this.started) {
|
2633
2933
|
this.started = true;
|
@@ -2640,13 +2940,20 @@
|
|
2640
2940
|
removeEventListener("turbo:before-cache", this.removeTemporaryElements, false);
|
2641
2941
|
}
|
2642
2942
|
}
|
2943
|
+
removeTemporaryElements = (_event) => {
|
2944
|
+
for (const element of this.temporaryElements) {
|
2945
|
+
element.remove();
|
2946
|
+
}
|
2947
|
+
};
|
2643
2948
|
get temporaryElements() {
|
2644
2949
|
return [...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation];
|
2645
2950
|
}
|
2646
2951
|
get temporaryElementsWithDeprecation() {
|
2647
2952
|
const elements = document.querySelectorAll(this.deprecatedSelector);
|
2648
2953
|
if (elements.length) {
|
2649
|
-
console.warn(
|
2954
|
+
console.warn(
|
2955
|
+
`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`
|
2956
|
+
);
|
2650
2957
|
}
|
2651
2958
|
return [...elements];
|
2652
2959
|
}
|
@@ -2666,42 +2973,43 @@
|
|
2666
2973
|
this.linkInterceptor.stop();
|
2667
2974
|
this.formSubmitObserver.stop();
|
2668
2975
|
}
|
2976
|
+
// Link interceptor delegate
|
2669
2977
|
shouldInterceptLinkClick(element, _location, _event) {
|
2670
|
-
return this
|
2978
|
+
return this.#shouldRedirect(element);
|
2671
2979
|
}
|
2672
2980
|
linkClickIntercepted(element, url, event) {
|
2673
|
-
const frame = this
|
2981
|
+
const frame = this.#findFrameElement(element);
|
2674
2982
|
if (frame) {
|
2675
2983
|
frame.delegate.linkClickIntercepted(element, url, event);
|
2676
2984
|
}
|
2677
2985
|
}
|
2986
|
+
// Form submit observer delegate
|
2678
2987
|
willSubmitForm(element, submitter) {
|
2679
|
-
return element.closest("turbo-frame") == null && this
|
2988
|
+
return element.closest("turbo-frame") == null && this.#shouldSubmit(element, submitter) && this.#shouldRedirect(element, submitter);
|
2680
2989
|
}
|
2681
2990
|
formSubmitted(element, submitter) {
|
2682
|
-
const frame = this
|
2991
|
+
const frame = this.#findFrameElement(element, submitter);
|
2683
2992
|
if (frame) {
|
2684
2993
|
frame.delegate.formSubmitted(element, submitter);
|
2685
2994
|
}
|
2686
2995
|
}
|
2687
|
-
shouldSubmit(form, submitter) {
|
2688
|
-
|
2689
|
-
const action = getAction(form, submitter);
|
2996
|
+
#shouldSubmit(form, submitter) {
|
2997
|
+
const action = getAction$1(form, submitter);
|
2690
2998
|
const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
2691
|
-
const rootLocation = expandURL(
|
2692
|
-
return this
|
2999
|
+
const rootLocation = expandURL(meta?.content ?? "/");
|
3000
|
+
return this.#shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
|
2693
3001
|
}
|
2694
|
-
shouldRedirect(element, submitter) {
|
3002
|
+
#shouldRedirect(element, submitter) {
|
2695
3003
|
const isNavigatable = element instanceof HTMLFormElement ? this.session.submissionIsNavigatable(element, submitter) : this.session.elementIsNavigatable(element);
|
2696
3004
|
if (isNavigatable) {
|
2697
|
-
const frame = this
|
3005
|
+
const frame = this.#findFrameElement(element, submitter);
|
2698
3006
|
return frame ? frame != element.closest("turbo-frame") : false;
|
2699
3007
|
} else {
|
2700
3008
|
return false;
|
2701
3009
|
}
|
2702
3010
|
}
|
2703
|
-
findFrameElement(element, submitter) {
|
2704
|
-
const id =
|
3011
|
+
#findFrameElement(element, submitter) {
|
3012
|
+
const id = submitter?.getAttribute("data-turbo-frame") || element.getAttribute("data-turbo-frame");
|
2705
3013
|
if (id && id != "_top") {
|
2706
3014
|
const frame = this.element.querySelector(`#${id}:not([disabled])`);
|
2707
3015
|
if (frame instanceof FrameElement) {
|
@@ -2711,32 +3019,20 @@
|
|
2711
3019
|
}
|
2712
3020
|
};
|
2713
3021
|
var History = class {
|
3022
|
+
location;
|
3023
|
+
restorationIdentifier = uuid();
|
3024
|
+
restorationData = {};
|
3025
|
+
started = false;
|
3026
|
+
pageLoaded = false;
|
3027
|
+
currentIndex = 0;
|
2714
3028
|
constructor(delegate) {
|
2715
|
-
this.restorationIdentifier = uuid();
|
2716
|
-
this.restorationData = {};
|
2717
|
-
this.started = false;
|
2718
|
-
this.pageLoaded = false;
|
2719
|
-
this.onPopState = (event) => {
|
2720
|
-
if (this.shouldHandlePopState()) {
|
2721
|
-
const { turbo } = event.state || {};
|
2722
|
-
if (turbo) {
|
2723
|
-
this.location = new URL(window.location.href);
|
2724
|
-
const { restorationIdentifier } = turbo;
|
2725
|
-
this.restorationIdentifier = restorationIdentifier;
|
2726
|
-
this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
|
2727
|
-
}
|
2728
|
-
}
|
2729
|
-
};
|
2730
|
-
this.onPageLoad = async (_event) => {
|
2731
|
-
await nextMicrotask();
|
2732
|
-
this.pageLoaded = true;
|
2733
|
-
};
|
2734
3029
|
this.delegate = delegate;
|
2735
3030
|
}
|
2736
3031
|
start() {
|
2737
3032
|
if (!this.started) {
|
2738
3033
|
addEventListener("popstate", this.onPopState, false);
|
2739
3034
|
addEventListener("load", this.onPageLoad, false);
|
3035
|
+
this.currentIndex = history.state?.turbo?.restorationIndex || 0;
|
2740
3036
|
this.started = true;
|
2741
3037
|
this.replace(new URL(window.location.href));
|
2742
3038
|
}
|
@@ -2755,23 +3051,29 @@
|
|
2755
3051
|
this.update(history.replaceState, location2, restorationIdentifier);
|
2756
3052
|
}
|
2757
3053
|
update(method, location2, restorationIdentifier = uuid()) {
|
2758
|
-
|
3054
|
+
if (method === history.pushState)
|
3055
|
+
++this.currentIndex;
|
3056
|
+
const state = { turbo: { restorationIdentifier, restorationIndex: this.currentIndex } };
|
2759
3057
|
method.call(history, state, "", location2.href);
|
2760
3058
|
this.location = location2;
|
2761
3059
|
this.restorationIdentifier = restorationIdentifier;
|
2762
3060
|
}
|
3061
|
+
// Restoration data
|
2763
3062
|
getRestorationDataForIdentifier(restorationIdentifier) {
|
2764
3063
|
return this.restorationData[restorationIdentifier] || {};
|
2765
3064
|
}
|
2766
3065
|
updateRestorationData(additionalData) {
|
2767
3066
|
const { restorationIdentifier } = this;
|
2768
3067
|
const restorationData = this.restorationData[restorationIdentifier];
|
2769
|
-
this.restorationData[restorationIdentifier] =
|
3068
|
+
this.restorationData[restorationIdentifier] = {
|
3069
|
+
...restorationData,
|
3070
|
+
...additionalData
|
3071
|
+
};
|
2770
3072
|
}
|
3073
|
+
// Scroll restoration
|
2771
3074
|
assumeControlOfScrollRestoration() {
|
2772
|
-
var _a;
|
2773
3075
|
if (!this.previousScrollRestoration) {
|
2774
|
-
this.previousScrollRestoration =
|
3076
|
+
this.previousScrollRestoration = history.scrollRestoration ?? "auto";
|
2775
3077
|
history.scrollRestoration = "manual";
|
2776
3078
|
}
|
2777
3079
|
}
|
@@ -2781,6 +3083,25 @@
|
|
2781
3083
|
delete this.previousScrollRestoration;
|
2782
3084
|
}
|
2783
3085
|
}
|
3086
|
+
// Event handlers
|
3087
|
+
onPopState = (event) => {
|
3088
|
+
if (this.shouldHandlePopState()) {
|
3089
|
+
const { turbo } = event.state || {};
|
3090
|
+
if (turbo) {
|
3091
|
+
this.location = new URL(window.location.href);
|
3092
|
+
const { restorationIdentifier, restorationIndex } = turbo;
|
3093
|
+
this.restorationIdentifier = restorationIdentifier;
|
3094
|
+
const direction = restorationIndex > this.currentIndex ? "forward" : "back";
|
3095
|
+
this.delegate.historyPoppedToLocationWithRestorationIdentifierAndDirection(this.location, restorationIdentifier, direction);
|
3096
|
+
this.currentIndex = restorationIndex;
|
3097
|
+
}
|
3098
|
+
}
|
3099
|
+
};
|
3100
|
+
onPageLoad = async (_event) => {
|
3101
|
+
await nextMicrotask();
|
3102
|
+
this.pageLoaded = true;
|
3103
|
+
};
|
3104
|
+
// Private
|
2784
3105
|
shouldHandlePopState() {
|
2785
3106
|
return this.pageIsLoaded();
|
2786
3107
|
}
|
@@ -2788,22 +3109,178 @@
|
|
2788
3109
|
return this.pageLoaded || document.readyState == "complete";
|
2789
3110
|
}
|
2790
3111
|
};
|
3112
|
+
var LinkPrefetchObserver = class {
|
3113
|
+
started = false;
|
3114
|
+
#prefetchedLink = null;
|
3115
|
+
constructor(delegate, eventTarget) {
|
3116
|
+
this.delegate = delegate;
|
3117
|
+
this.eventTarget = eventTarget;
|
3118
|
+
}
|
3119
|
+
start() {
|
3120
|
+
if (this.started)
|
3121
|
+
return;
|
3122
|
+
if (this.eventTarget.readyState === "loading") {
|
3123
|
+
this.eventTarget.addEventListener("DOMContentLoaded", this.#enable, { once: true });
|
3124
|
+
} else {
|
3125
|
+
this.#enable();
|
3126
|
+
}
|
3127
|
+
}
|
3128
|
+
stop() {
|
3129
|
+
if (!this.started)
|
3130
|
+
return;
|
3131
|
+
this.eventTarget.removeEventListener("mouseenter", this.#tryToPrefetchRequest, {
|
3132
|
+
capture: true,
|
3133
|
+
passive: true
|
3134
|
+
});
|
3135
|
+
this.eventTarget.removeEventListener("mouseleave", this.#cancelRequestIfObsolete, {
|
3136
|
+
capture: true,
|
3137
|
+
passive: true
|
3138
|
+
});
|
3139
|
+
this.eventTarget.removeEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true);
|
3140
|
+
this.started = false;
|
3141
|
+
}
|
3142
|
+
#enable = () => {
|
3143
|
+
this.eventTarget.addEventListener("mouseenter", this.#tryToPrefetchRequest, {
|
3144
|
+
capture: true,
|
3145
|
+
passive: true
|
3146
|
+
});
|
3147
|
+
this.eventTarget.addEventListener("mouseleave", this.#cancelRequestIfObsolete, {
|
3148
|
+
capture: true,
|
3149
|
+
passive: true
|
3150
|
+
});
|
3151
|
+
this.eventTarget.addEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true);
|
3152
|
+
this.started = true;
|
3153
|
+
};
|
3154
|
+
#tryToPrefetchRequest = (event) => {
|
3155
|
+
if (getMetaContent("turbo-prefetch") === "false")
|
3156
|
+
return;
|
3157
|
+
const target = event.target;
|
3158
|
+
const isLink = target.matches && target.matches("a[href]:not([target^=_]):not([download])");
|
3159
|
+
if (isLink && this.#isPrefetchable(target)) {
|
3160
|
+
const link = target;
|
3161
|
+
const location2 = getLocationForLink(link);
|
3162
|
+
if (this.delegate.canPrefetchRequestToLocation(link, location2)) {
|
3163
|
+
this.#prefetchedLink = link;
|
3164
|
+
const fetchRequest = new FetchRequest(
|
3165
|
+
this,
|
3166
|
+
FetchMethod.get,
|
3167
|
+
location2,
|
3168
|
+
new URLSearchParams(),
|
3169
|
+
target
|
3170
|
+
);
|
3171
|
+
prefetchCache.setLater(location2.toString(), fetchRequest, this.#cacheTtl);
|
3172
|
+
}
|
3173
|
+
}
|
3174
|
+
};
|
3175
|
+
#cancelRequestIfObsolete = (event) => {
|
3176
|
+
if (event.target === this.#prefetchedLink)
|
3177
|
+
this.#cancelPrefetchRequest();
|
3178
|
+
};
|
3179
|
+
#cancelPrefetchRequest = () => {
|
3180
|
+
prefetchCache.clear();
|
3181
|
+
this.#prefetchedLink = null;
|
3182
|
+
};
|
3183
|
+
#tryToUsePrefetchedRequest = (event) => {
|
3184
|
+
if (event.target.tagName !== "FORM" && event.detail.fetchOptions.method === "get") {
|
3185
|
+
const cached = prefetchCache.get(event.detail.url.toString());
|
3186
|
+
if (cached) {
|
3187
|
+
event.detail.fetchRequest = cached;
|
3188
|
+
}
|
3189
|
+
prefetchCache.clear();
|
3190
|
+
}
|
3191
|
+
};
|
3192
|
+
prepareRequest(request) {
|
3193
|
+
const link = request.target;
|
3194
|
+
request.headers["X-Sec-Purpose"] = "prefetch";
|
3195
|
+
const turboFrame = link.closest("turbo-frame");
|
3196
|
+
const turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id;
|
3197
|
+
if (turboFrameTarget && turboFrameTarget !== "_top") {
|
3198
|
+
request.headers["Turbo-Frame"] = turboFrameTarget;
|
3199
|
+
}
|
3200
|
+
}
|
3201
|
+
// Fetch request interface
|
3202
|
+
requestSucceededWithResponse() {
|
3203
|
+
}
|
3204
|
+
requestStarted(fetchRequest) {
|
3205
|
+
}
|
3206
|
+
requestErrored(fetchRequest) {
|
3207
|
+
}
|
3208
|
+
requestFinished(fetchRequest) {
|
3209
|
+
}
|
3210
|
+
requestPreventedHandlingResponse(fetchRequest, fetchResponse) {
|
3211
|
+
}
|
3212
|
+
requestFailedWithResponse(fetchRequest, fetchResponse) {
|
3213
|
+
}
|
3214
|
+
get #cacheTtl() {
|
3215
|
+
return Number(getMetaContent("turbo-prefetch-cache-time")) || cacheTtl;
|
3216
|
+
}
|
3217
|
+
#isPrefetchable(link) {
|
3218
|
+
const href = link.getAttribute("href");
|
3219
|
+
if (!href)
|
3220
|
+
return false;
|
3221
|
+
if (unfetchableLink(link))
|
3222
|
+
return false;
|
3223
|
+
if (linkToTheSamePage(link))
|
3224
|
+
return false;
|
3225
|
+
if (linkOptsOut(link))
|
3226
|
+
return false;
|
3227
|
+
if (nonSafeLink(link))
|
3228
|
+
return false;
|
3229
|
+
if (eventPrevented(link))
|
3230
|
+
return false;
|
3231
|
+
return true;
|
3232
|
+
}
|
3233
|
+
};
|
3234
|
+
var unfetchableLink = (link) => {
|
3235
|
+
return link.origin !== document.location.origin || !["http:", "https:"].includes(link.protocol) || link.hasAttribute("target");
|
3236
|
+
};
|
3237
|
+
var linkToTheSamePage = (link) => {
|
3238
|
+
return link.pathname + link.search === document.location.pathname + document.location.search || link.href.startsWith("#");
|
3239
|
+
};
|
3240
|
+
var linkOptsOut = (link) => {
|
3241
|
+
if (link.getAttribute("data-turbo-prefetch") === "false")
|
3242
|
+
return true;
|
3243
|
+
if (link.getAttribute("data-turbo") === "false")
|
3244
|
+
return true;
|
3245
|
+
const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
|
3246
|
+
if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false")
|
3247
|
+
return true;
|
3248
|
+
return false;
|
3249
|
+
};
|
3250
|
+
var nonSafeLink = (link) => {
|
3251
|
+
const turboMethod = link.getAttribute("data-turbo-method");
|
3252
|
+
if (turboMethod && turboMethod.toLowerCase() !== "get")
|
3253
|
+
return true;
|
3254
|
+
if (isUJS(link))
|
3255
|
+
return true;
|
3256
|
+
if (link.hasAttribute("data-turbo-confirm"))
|
3257
|
+
return true;
|
3258
|
+
if (link.hasAttribute("data-turbo-stream"))
|
3259
|
+
return true;
|
3260
|
+
return false;
|
3261
|
+
};
|
3262
|
+
var isUJS = (link) => {
|
3263
|
+
return link.hasAttribute("data-remote") || link.hasAttribute("data-behavior") || link.hasAttribute("data-confirm") || link.hasAttribute("data-method");
|
3264
|
+
};
|
3265
|
+
var eventPrevented = (link) => {
|
3266
|
+
const event = dispatch("turbo:before-prefetch", { target: link, cancelable: true });
|
3267
|
+
return event.defaultPrevented;
|
3268
|
+
};
|
2791
3269
|
var Navigator = class {
|
2792
3270
|
constructor(delegate) {
|
2793
3271
|
this.delegate = delegate;
|
2794
3272
|
}
|
2795
3273
|
proposeVisit(location2, options = {}) {
|
2796
3274
|
if (this.delegate.allowsVisitingLocationWithAction(location2, options.action)) {
|
2797
|
-
|
2798
|
-
this.delegate.visitProposedToLocation(location2, options);
|
2799
|
-
} else {
|
2800
|
-
window.location.href = location2.toString();
|
2801
|
-
}
|
3275
|
+
this.delegate.visitProposedToLocation(location2, options);
|
2802
3276
|
}
|
2803
3277
|
}
|
2804
3278
|
startVisit(locatable, restorationIdentifier, options = {}) {
|
2805
3279
|
this.stop();
|
2806
|
-
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier,
|
3280
|
+
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, {
|
3281
|
+
referrer: this.location,
|
3282
|
+
...options
|
3283
|
+
});
|
2807
3284
|
this.currentVisit.start();
|
2808
3285
|
}
|
2809
3286
|
submitForm(form, submitter) {
|
@@ -2827,9 +3304,13 @@
|
|
2827
3304
|
get view() {
|
2828
3305
|
return this.delegate.view;
|
2829
3306
|
}
|
3307
|
+
get rootLocation() {
|
3308
|
+
return this.view.snapshot.rootLocation;
|
3309
|
+
}
|
2830
3310
|
get history() {
|
2831
3311
|
return this.delegate.history;
|
2832
3312
|
}
|
3313
|
+
// Form submission delegate
|
2833
3314
|
formSubmissionStarted(formSubmission) {
|
2834
3315
|
if (typeof this.adapter.formSubmissionStarted === "function") {
|
2835
3316
|
this.adapter.formSubmissionStarted(formSubmission);
|
@@ -2844,7 +3325,7 @@
|
|
2844
3325
|
this.view.clearSnapshotCache();
|
2845
3326
|
}
|
2846
3327
|
const { statusCode, redirected } = fetchResponse;
|
2847
|
-
const action = this
|
3328
|
+
const action = this.#getActionForFormSubmission(formSubmission, fetchResponse);
|
2848
3329
|
const visitOptions = {
|
2849
3330
|
action,
|
2850
3331
|
shouldCacheSnapshot,
|
@@ -2863,7 +3344,9 @@
|
|
2863
3344
|
} else {
|
2864
3345
|
await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
2865
3346
|
}
|
2866
|
-
|
3347
|
+
if (!snapshot.shouldPreserveScrollPosition) {
|
3348
|
+
this.view.scrollToTop();
|
3349
|
+
}
|
2867
3350
|
this.view.clearSnapshotCache();
|
2868
3351
|
}
|
2869
3352
|
}
|
@@ -2875,6 +3358,7 @@
|
|
2875
3358
|
this.adapter.formSubmissionFinished(formSubmission);
|
2876
3359
|
}
|
2877
3360
|
}
|
3361
|
+
// Visit delegate
|
2878
3362
|
visitStarted(visit2) {
|
2879
3363
|
this.delegate.visitStarted(visit2);
|
2880
3364
|
}
|
@@ -2890,38 +3374,32 @@
|
|
2890
3374
|
visitScrolledToSamePageLocation(oldURL, newURL) {
|
2891
3375
|
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
2892
3376
|
}
|
3377
|
+
// Visits
|
2893
3378
|
get location() {
|
2894
3379
|
return this.history.location;
|
2895
3380
|
}
|
2896
3381
|
get restorationIdentifier() {
|
2897
3382
|
return this.history.restorationIdentifier;
|
2898
3383
|
}
|
2899
|
-
getActionForFormSubmission(
|
2900
|
-
|
3384
|
+
#getActionForFormSubmission(formSubmission, fetchResponse) {
|
3385
|
+
const { submitter, formElement } = formSubmission;
|
3386
|
+
return getVisitAction(submitter, formElement) || this.#getDefaultAction(fetchResponse);
|
3387
|
+
}
|
3388
|
+
#getDefaultAction(fetchResponse) {
|
3389
|
+
const sameLocationRedirect = fetchResponse.redirected && fetchResponse.location.href === this.location?.href;
|
3390
|
+
return sameLocationRedirect ? "replace" : "advance";
|
2901
3391
|
}
|
2902
3392
|
};
|
2903
|
-
var PageStage
|
2904
|
-
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
})(PageStage || (PageStage = {}));
|
3393
|
+
var PageStage = {
|
3394
|
+
initial: 0,
|
3395
|
+
loading: 1,
|
3396
|
+
interactive: 2,
|
3397
|
+
complete: 3
|
3398
|
+
};
|
2910
3399
|
var PageObserver = class {
|
3400
|
+
stage = PageStage.initial;
|
3401
|
+
started = false;
|
2911
3402
|
constructor(delegate) {
|
2912
|
-
this.stage = PageStage.initial;
|
2913
|
-
this.started = false;
|
2914
|
-
this.interpretReadyState = () => {
|
2915
|
-
const { readyState } = this;
|
2916
|
-
if (readyState == "interactive") {
|
2917
|
-
this.pageIsInteractive();
|
2918
|
-
} else if (readyState == "complete") {
|
2919
|
-
this.pageIsComplete();
|
2920
|
-
}
|
2921
|
-
};
|
2922
|
-
this.pageWillUnload = () => {
|
2923
|
-
this.delegate.pageWillUnload();
|
2924
|
-
};
|
2925
3403
|
this.delegate = delegate;
|
2926
3404
|
}
|
2927
3405
|
start() {
|
@@ -2941,6 +3419,14 @@
|
|
2941
3419
|
this.started = false;
|
2942
3420
|
}
|
2943
3421
|
}
|
3422
|
+
interpretReadyState = () => {
|
3423
|
+
const { readyState } = this;
|
3424
|
+
if (readyState == "interactive") {
|
3425
|
+
this.pageIsInteractive();
|
3426
|
+
} else if (readyState == "complete") {
|
3427
|
+
this.pageIsComplete();
|
3428
|
+
}
|
3429
|
+
};
|
2944
3430
|
pageIsInteractive() {
|
2945
3431
|
if (this.stage == PageStage.loading) {
|
2946
3432
|
this.stage = PageStage.interactive;
|
@@ -2954,16 +3440,16 @@
|
|
2954
3440
|
this.delegate.pageLoaded();
|
2955
3441
|
}
|
2956
3442
|
}
|
3443
|
+
pageWillUnload = () => {
|
3444
|
+
this.delegate.pageWillUnload();
|
3445
|
+
};
|
2957
3446
|
get readyState() {
|
2958
3447
|
return document.readyState;
|
2959
3448
|
}
|
2960
3449
|
};
|
2961
3450
|
var ScrollObserver = class {
|
3451
|
+
started = false;
|
2962
3452
|
constructor(delegate) {
|
2963
|
-
this.started = false;
|
2964
|
-
this.onScroll = () => {
|
2965
|
-
this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
|
2966
|
-
};
|
2967
3453
|
this.delegate = delegate;
|
2968
3454
|
}
|
2969
3455
|
start() {
|
@@ -2979,14 +3465,25 @@
|
|
2979
3465
|
this.started = false;
|
2980
3466
|
}
|
2981
3467
|
}
|
3468
|
+
onScroll = () => {
|
3469
|
+
this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
|
3470
|
+
};
|
3471
|
+
// Private
|
2982
3472
|
updatePosition(position) {
|
2983
3473
|
this.delegate.scrollPositionChanged(position);
|
2984
3474
|
}
|
2985
3475
|
};
|
2986
3476
|
var StreamMessageRenderer = class {
|
2987
3477
|
render({ fragment }) {
|
2988
|
-
Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () =>
|
3478
|
+
Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => {
|
3479
|
+
withAutofocusFromFragment(fragment, () => {
|
3480
|
+
withPreservedFocus(() => {
|
3481
|
+
document.documentElement.appendChild(fragment);
|
3482
|
+
});
|
3483
|
+
});
|
3484
|
+
});
|
2989
3485
|
}
|
3486
|
+
// Bardo delegate
|
2990
3487
|
enteringBardo(currentPermanentElement, newPermanentElement) {
|
2991
3488
|
newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
|
2992
3489
|
}
|
@@ -3007,33 +3504,65 @@
|
|
3007
3504
|
}
|
3008
3505
|
return permanentElementMap;
|
3009
3506
|
}
|
3507
|
+
async function withAutofocusFromFragment(fragment, callback) {
|
3508
|
+
const generatedID = `turbo-stream-autofocus-${uuid()}`;
|
3509
|
+
const turboStreams = fragment.querySelectorAll("turbo-stream");
|
3510
|
+
const elementWithAutofocus = firstAutofocusableElementInStreams(turboStreams);
|
3511
|
+
let willAutofocusId = null;
|
3512
|
+
if (elementWithAutofocus) {
|
3513
|
+
if (elementWithAutofocus.id) {
|
3514
|
+
willAutofocusId = elementWithAutofocus.id;
|
3515
|
+
} else {
|
3516
|
+
willAutofocusId = generatedID;
|
3517
|
+
}
|
3518
|
+
elementWithAutofocus.id = willAutofocusId;
|
3519
|
+
}
|
3520
|
+
callback();
|
3521
|
+
await nextRepaint();
|
3522
|
+
const hasNoActiveElement = document.activeElement == null || document.activeElement == document.body;
|
3523
|
+
if (hasNoActiveElement && willAutofocusId) {
|
3524
|
+
const elementToAutofocus = document.getElementById(willAutofocusId);
|
3525
|
+
if (elementIsFocusable(elementToAutofocus)) {
|
3526
|
+
elementToAutofocus.focus();
|
3527
|
+
}
|
3528
|
+
if (elementToAutofocus && elementToAutofocus.id == generatedID) {
|
3529
|
+
elementToAutofocus.removeAttribute("id");
|
3530
|
+
}
|
3531
|
+
}
|
3532
|
+
}
|
3533
|
+
async function withPreservedFocus(callback) {
|
3534
|
+
const [activeElementBeforeRender, activeElementAfterRender] = await around(callback, () => document.activeElement);
|
3535
|
+
const restoreFocusTo = activeElementBeforeRender && activeElementBeforeRender.id;
|
3536
|
+
if (restoreFocusTo) {
|
3537
|
+
const elementToFocus = document.getElementById(restoreFocusTo);
|
3538
|
+
if (elementIsFocusable(elementToFocus) && elementToFocus != activeElementAfterRender) {
|
3539
|
+
elementToFocus.focus();
|
3540
|
+
}
|
3541
|
+
}
|
3542
|
+
}
|
3543
|
+
function firstAutofocusableElementInStreams(nodeListOfStreamElements) {
|
3544
|
+
for (const streamElement of nodeListOfStreamElements) {
|
3545
|
+
const elementWithAutofocus = queryAutofocusableElement(streamElement.templateElement.content);
|
3546
|
+
if (elementWithAutofocus)
|
3547
|
+
return elementWithAutofocus;
|
3548
|
+
}
|
3549
|
+
return null;
|
3550
|
+
}
|
3010
3551
|
var StreamObserver = class {
|
3552
|
+
sources = /* @__PURE__ */ new Set();
|
3553
|
+
#started = false;
|
3011
3554
|
constructor(delegate) {
|
3012
|
-
this.sources = /* @__PURE__ */ new Set();
|
3013
|
-
this.started = false;
|
3014
|
-
this.inspectFetchResponse = (event) => {
|
3015
|
-
const response = fetchResponseFromEvent(event);
|
3016
|
-
if (response && fetchResponseIsStream(response)) {
|
3017
|
-
event.preventDefault();
|
3018
|
-
this.receiveMessageResponse(response);
|
3019
|
-
}
|
3020
|
-
};
|
3021
|
-
this.receiveMessageEvent = (event) => {
|
3022
|
-
if (this.started && typeof event.data == "string") {
|
3023
|
-
this.receiveMessageHTML(event.data);
|
3024
|
-
}
|
3025
|
-
};
|
3026
3555
|
this.delegate = delegate;
|
3027
3556
|
}
|
3028
3557
|
start() {
|
3029
|
-
if (!this
|
3030
|
-
this
|
3558
|
+
if (!this.#started) {
|
3559
|
+
this.#started = true;
|
3031
3560
|
addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
3032
3561
|
}
|
3033
3562
|
}
|
3034
3563
|
stop() {
|
3035
|
-
if (this
|
3036
|
-
this
|
3564
|
+
if (this.#started) {
|
3565
|
+
this.#started = false;
|
3037
3566
|
removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
3038
3567
|
}
|
3039
3568
|
}
|
@@ -3052,6 +3581,18 @@
|
|
3052
3581
|
streamSourceIsConnected(source) {
|
3053
3582
|
return this.sources.has(source);
|
3054
3583
|
}
|
3584
|
+
inspectFetchResponse = (event) => {
|
3585
|
+
const response = fetchResponseFromEvent(event);
|
3586
|
+
if (response && fetchResponseIsStream(response)) {
|
3587
|
+
event.preventDefault();
|
3588
|
+
this.receiveMessageResponse(response);
|
3589
|
+
}
|
3590
|
+
};
|
3591
|
+
receiveMessageEvent = (event) => {
|
3592
|
+
if (this.#started && typeof event.data == "string") {
|
3593
|
+
this.receiveMessageHTML(event.data);
|
3594
|
+
}
|
3595
|
+
};
|
3055
3596
|
async receiveMessageResponse(response) {
|
3056
3597
|
const html = await response.responseHTML;
|
3057
3598
|
if (html) {
|
@@ -3063,15 +3604,13 @@
|
|
3063
3604
|
}
|
3064
3605
|
};
|
3065
3606
|
function fetchResponseFromEvent(event) {
|
3066
|
-
|
3067
|
-
const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;
|
3607
|
+
const fetchResponse = event.detail?.fetchResponse;
|
3068
3608
|
if (fetchResponse instanceof FetchResponse) {
|
3069
3609
|
return fetchResponse;
|
3070
3610
|
}
|
3071
3611
|
}
|
3072
3612
|
function fetchResponseIsStream(response) {
|
3073
|
-
|
3074
|
-
const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
|
3613
|
+
const contentType = response.contentType ?? "";
|
3075
3614
|
return contentType.startsWith(StreamMessage.contentType);
|
3076
3615
|
}
|
3077
3616
|
var ErrorRenderer = class extends Renderer {
|
@@ -3088,22 +3627,569 @@
|
|
3088
3627
|
documentElement.replaceChild(this.newHead, head);
|
3089
3628
|
this.renderElement(this.currentElement, this.newElement);
|
3090
3629
|
}
|
3091
|
-
activateScriptElements() {
|
3092
|
-
for (const replaceableElement of this.scriptElements) {
|
3093
|
-
const parentNode = replaceableElement.parentNode;
|
3094
|
-
if (parentNode) {
|
3095
|
-
const element = activateScriptElement(replaceableElement);
|
3096
|
-
parentNode.replaceChild(element, replaceableElement);
|
3630
|
+
activateScriptElements() {
|
3631
|
+
for (const replaceableElement of this.scriptElements) {
|
3632
|
+
const parentNode = replaceableElement.parentNode;
|
3633
|
+
if (parentNode) {
|
3634
|
+
const element = activateScriptElement(replaceableElement);
|
3635
|
+
parentNode.replaceChild(element, replaceableElement);
|
3636
|
+
}
|
3637
|
+
}
|
3638
|
+
}
|
3639
|
+
get newHead() {
|
3640
|
+
return this.newSnapshot.headSnapshot.element;
|
3641
|
+
}
|
3642
|
+
get scriptElements() {
|
3643
|
+
return document.documentElement.querySelectorAll("script");
|
3644
|
+
}
|
3645
|
+
};
|
3646
|
+
var Idiomorph = /* @__PURE__ */ function() {
|
3647
|
+
let EMPTY_SET = /* @__PURE__ */ new Set();
|
3648
|
+
let defaults = {
|
3649
|
+
morphStyle: "outerHTML",
|
3650
|
+
callbacks: {
|
3651
|
+
beforeNodeAdded: noOp,
|
3652
|
+
afterNodeAdded: noOp,
|
3653
|
+
beforeNodeMorphed: noOp,
|
3654
|
+
afterNodeMorphed: noOp,
|
3655
|
+
beforeNodeRemoved: noOp,
|
3656
|
+
afterNodeRemoved: noOp,
|
3657
|
+
beforeAttributeUpdated: noOp
|
3658
|
+
},
|
3659
|
+
head: {
|
3660
|
+
style: "merge",
|
3661
|
+
shouldPreserve: function(elt) {
|
3662
|
+
return elt.getAttribute("im-preserve") === "true";
|
3663
|
+
},
|
3664
|
+
shouldReAppend: function(elt) {
|
3665
|
+
return elt.getAttribute("im-re-append") === "true";
|
3666
|
+
},
|
3667
|
+
shouldRemove: noOp,
|
3668
|
+
afterHeadMorphed: noOp
|
3669
|
+
}
|
3670
|
+
};
|
3671
|
+
function morph(oldNode, newContent, config = {}) {
|
3672
|
+
if (oldNode instanceof Document) {
|
3673
|
+
oldNode = oldNode.documentElement;
|
3674
|
+
}
|
3675
|
+
if (typeof newContent === "string") {
|
3676
|
+
newContent = parseContent(newContent);
|
3677
|
+
}
|
3678
|
+
let normalizedContent = normalizeContent(newContent);
|
3679
|
+
let ctx = createMorphContext(oldNode, normalizedContent, config);
|
3680
|
+
return morphNormalizedContent(oldNode, normalizedContent, ctx);
|
3681
|
+
}
|
3682
|
+
function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {
|
3683
|
+
if (ctx.head.block) {
|
3684
|
+
let oldHead = oldNode.querySelector("head");
|
3685
|
+
let newHead = normalizedNewContent.querySelector("head");
|
3686
|
+
if (oldHead && newHead) {
|
3687
|
+
let promises = handleHeadElement(newHead, oldHead, ctx);
|
3688
|
+
Promise.all(promises).then(function() {
|
3689
|
+
morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {
|
3690
|
+
head: {
|
3691
|
+
block: false,
|
3692
|
+
ignore: true
|
3693
|
+
}
|
3694
|
+
}));
|
3695
|
+
});
|
3696
|
+
return;
|
3697
|
+
}
|
3698
|
+
}
|
3699
|
+
if (ctx.morphStyle === "innerHTML") {
|
3700
|
+
morphChildren(normalizedNewContent, oldNode, ctx);
|
3701
|
+
return oldNode.children;
|
3702
|
+
} else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) {
|
3703
|
+
let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);
|
3704
|
+
let previousSibling = bestMatch?.previousSibling;
|
3705
|
+
let nextSibling = bestMatch?.nextSibling;
|
3706
|
+
let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);
|
3707
|
+
if (bestMatch) {
|
3708
|
+
return insertSiblings(previousSibling, morphedNode, nextSibling);
|
3709
|
+
} else {
|
3710
|
+
return [];
|
3711
|
+
}
|
3712
|
+
} else {
|
3713
|
+
throw "Do not understand how to morph style " + ctx.morphStyle;
|
3714
|
+
}
|
3715
|
+
}
|
3716
|
+
function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
|
3717
|
+
return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
|
3718
|
+
}
|
3719
|
+
function morphOldNodeTo(oldNode, newContent, ctx) {
|
3720
|
+
if (ctx.ignoreActive && oldNode === document.activeElement)
|
3721
|
+
;
|
3722
|
+
else if (newContent == null) {
|
3723
|
+
if (ctx.callbacks.beforeNodeRemoved(oldNode) === false)
|
3724
|
+
return oldNode;
|
3725
|
+
oldNode.remove();
|
3726
|
+
ctx.callbacks.afterNodeRemoved(oldNode);
|
3727
|
+
return null;
|
3728
|
+
} else if (!isSoftMatch(oldNode, newContent)) {
|
3729
|
+
if (ctx.callbacks.beforeNodeRemoved(oldNode) === false)
|
3730
|
+
return oldNode;
|
3731
|
+
if (ctx.callbacks.beforeNodeAdded(newContent) === false)
|
3732
|
+
return oldNode;
|
3733
|
+
oldNode.parentElement.replaceChild(newContent, oldNode);
|
3734
|
+
ctx.callbacks.afterNodeAdded(newContent);
|
3735
|
+
ctx.callbacks.afterNodeRemoved(oldNode);
|
3736
|
+
return newContent;
|
3737
|
+
} else {
|
3738
|
+
if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false)
|
3739
|
+
return oldNode;
|
3740
|
+
if (oldNode instanceof HTMLHeadElement && ctx.head.ignore)
|
3741
|
+
;
|
3742
|
+
else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") {
|
3743
|
+
handleHeadElement(newContent, oldNode, ctx);
|
3744
|
+
} else {
|
3745
|
+
syncNodeFrom(newContent, oldNode, ctx);
|
3746
|
+
if (!ignoreValueOfActiveElement(oldNode, ctx)) {
|
3747
|
+
morphChildren(newContent, oldNode, ctx);
|
3748
|
+
}
|
3749
|
+
}
|
3750
|
+
ctx.callbacks.afterNodeMorphed(oldNode, newContent);
|
3751
|
+
return oldNode;
|
3752
|
+
}
|
3753
|
+
}
|
3754
|
+
function morphChildren(newParent, oldParent, ctx) {
|
3755
|
+
let nextNewChild = newParent.firstChild;
|
3756
|
+
let insertionPoint = oldParent.firstChild;
|
3757
|
+
let newChild;
|
3758
|
+
while (nextNewChild) {
|
3759
|
+
newChild = nextNewChild;
|
3760
|
+
nextNewChild = newChild.nextSibling;
|
3761
|
+
if (insertionPoint == null) {
|
3762
|
+
if (ctx.callbacks.beforeNodeAdded(newChild) === false)
|
3763
|
+
return;
|
3764
|
+
oldParent.appendChild(newChild);
|
3765
|
+
ctx.callbacks.afterNodeAdded(newChild);
|
3766
|
+
removeIdsFromConsideration(ctx, newChild);
|
3767
|
+
continue;
|
3768
|
+
}
|
3769
|
+
if (isIdSetMatch(newChild, insertionPoint, ctx)) {
|
3770
|
+
morphOldNodeTo(insertionPoint, newChild, ctx);
|
3771
|
+
insertionPoint = insertionPoint.nextSibling;
|
3772
|
+
removeIdsFromConsideration(ctx, newChild);
|
3773
|
+
continue;
|
3774
|
+
}
|
3775
|
+
let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);
|
3776
|
+
if (idSetMatch) {
|
3777
|
+
insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);
|
3778
|
+
morphOldNodeTo(idSetMatch, newChild, ctx);
|
3779
|
+
removeIdsFromConsideration(ctx, newChild);
|
3780
|
+
continue;
|
3781
|
+
}
|
3782
|
+
let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);
|
3783
|
+
if (softMatch) {
|
3784
|
+
insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);
|
3785
|
+
morphOldNodeTo(softMatch, newChild, ctx);
|
3786
|
+
removeIdsFromConsideration(ctx, newChild);
|
3787
|
+
continue;
|
3788
|
+
}
|
3789
|
+
if (ctx.callbacks.beforeNodeAdded(newChild) === false)
|
3790
|
+
return;
|
3791
|
+
oldParent.insertBefore(newChild, insertionPoint);
|
3792
|
+
ctx.callbacks.afterNodeAdded(newChild);
|
3793
|
+
removeIdsFromConsideration(ctx, newChild);
|
3794
|
+
}
|
3795
|
+
while (insertionPoint !== null) {
|
3796
|
+
let tempNode = insertionPoint;
|
3797
|
+
insertionPoint = insertionPoint.nextSibling;
|
3798
|
+
removeNode(tempNode, ctx);
|
3799
|
+
}
|
3800
|
+
}
|
3801
|
+
function ignoreAttribute(attr, to, updateType, ctx) {
|
3802
|
+
if (attr === "value" && ctx.ignoreActiveValue && to === document.activeElement) {
|
3803
|
+
return true;
|
3804
|
+
}
|
3805
|
+
return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;
|
3806
|
+
}
|
3807
|
+
function syncNodeFrom(from, to, ctx) {
|
3808
|
+
let type = from.nodeType;
|
3809
|
+
if (type === 1) {
|
3810
|
+
const fromAttributes = from.attributes;
|
3811
|
+
const toAttributes = to.attributes;
|
3812
|
+
for (const fromAttribute of fromAttributes) {
|
3813
|
+
if (ignoreAttribute(fromAttribute.name, to, "update", ctx)) {
|
3814
|
+
continue;
|
3815
|
+
}
|
3816
|
+
if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {
|
3817
|
+
to.setAttribute(fromAttribute.name, fromAttribute.value);
|
3818
|
+
}
|
3819
|
+
}
|
3820
|
+
for (let i = toAttributes.length - 1; 0 <= i; i--) {
|
3821
|
+
const toAttribute = toAttributes[i];
|
3822
|
+
if (ignoreAttribute(toAttribute.name, to, "remove", ctx)) {
|
3823
|
+
continue;
|
3824
|
+
}
|
3825
|
+
if (!from.hasAttribute(toAttribute.name)) {
|
3826
|
+
to.removeAttribute(toAttribute.name);
|
3827
|
+
}
|
3828
|
+
}
|
3829
|
+
}
|
3830
|
+
if (type === 8 || type === 3) {
|
3831
|
+
if (to.nodeValue !== from.nodeValue) {
|
3832
|
+
to.nodeValue = from.nodeValue;
|
3833
|
+
}
|
3834
|
+
}
|
3835
|
+
if (!ignoreValueOfActiveElement(to, ctx)) {
|
3836
|
+
syncInputValue(from, to, ctx);
|
3837
|
+
}
|
3838
|
+
}
|
3839
|
+
function syncBooleanAttribute(from, to, attributeName, ctx) {
|
3840
|
+
if (from[attributeName] !== to[attributeName]) {
|
3841
|
+
let ignoreUpdate = ignoreAttribute(attributeName, to, "update", ctx);
|
3842
|
+
if (!ignoreUpdate) {
|
3843
|
+
to[attributeName] = from[attributeName];
|
3844
|
+
}
|
3845
|
+
if (from[attributeName]) {
|
3846
|
+
if (!ignoreUpdate) {
|
3847
|
+
to.setAttribute(attributeName, from[attributeName]);
|
3848
|
+
}
|
3849
|
+
} else {
|
3850
|
+
if (!ignoreAttribute(attributeName, to, "remove", ctx)) {
|
3851
|
+
to.removeAttribute(attributeName);
|
3852
|
+
}
|
3853
|
+
}
|
3854
|
+
}
|
3855
|
+
}
|
3856
|
+
function syncInputValue(from, to, ctx) {
|
3857
|
+
if (from instanceof HTMLInputElement && to instanceof HTMLInputElement && from.type !== "file") {
|
3858
|
+
let fromValue = from.value;
|
3859
|
+
let toValue = to.value;
|
3860
|
+
syncBooleanAttribute(from, to, "checked", ctx);
|
3861
|
+
syncBooleanAttribute(from, to, "disabled", ctx);
|
3862
|
+
if (!from.hasAttribute("value")) {
|
3863
|
+
if (!ignoreAttribute("value", to, "remove", ctx)) {
|
3864
|
+
to.value = "";
|
3865
|
+
to.removeAttribute("value");
|
3866
|
+
}
|
3867
|
+
} else if (fromValue !== toValue) {
|
3868
|
+
if (!ignoreAttribute("value", to, "update", ctx)) {
|
3869
|
+
to.setAttribute("value", fromValue);
|
3870
|
+
to.value = fromValue;
|
3871
|
+
}
|
3872
|
+
}
|
3873
|
+
} else if (from instanceof HTMLOptionElement) {
|
3874
|
+
syncBooleanAttribute(from, to, "selected", ctx);
|
3875
|
+
} else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {
|
3876
|
+
let fromValue = from.value;
|
3877
|
+
let toValue = to.value;
|
3878
|
+
if (ignoreAttribute("value", to, "update", ctx)) {
|
3879
|
+
return;
|
3880
|
+
}
|
3881
|
+
if (fromValue !== toValue) {
|
3882
|
+
to.value = fromValue;
|
3883
|
+
}
|
3884
|
+
if (to.firstChild && to.firstChild.nodeValue !== fromValue) {
|
3885
|
+
to.firstChild.nodeValue = fromValue;
|
3886
|
+
}
|
3887
|
+
}
|
3888
|
+
}
|
3889
|
+
function handleHeadElement(newHeadTag, currentHead, ctx) {
|
3890
|
+
let added = [];
|
3891
|
+
let removed = [];
|
3892
|
+
let preserved = [];
|
3893
|
+
let nodesToAppend = [];
|
3894
|
+
let headMergeStyle = ctx.head.style;
|
3895
|
+
let srcToNewHeadNodes = /* @__PURE__ */ new Map();
|
3896
|
+
for (const newHeadChild of newHeadTag.children) {
|
3897
|
+
srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
|
3898
|
+
}
|
3899
|
+
for (const currentHeadElt of currentHead.children) {
|
3900
|
+
let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
|
3901
|
+
let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
|
3902
|
+
let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
|
3903
|
+
if (inNewContent || isPreserved) {
|
3904
|
+
if (isReAppended) {
|
3905
|
+
removed.push(currentHeadElt);
|
3906
|
+
} else {
|
3907
|
+
srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
|
3908
|
+
preserved.push(currentHeadElt);
|
3909
|
+
}
|
3910
|
+
} else {
|
3911
|
+
if (headMergeStyle === "append") {
|
3912
|
+
if (isReAppended) {
|
3913
|
+
removed.push(currentHeadElt);
|
3914
|
+
nodesToAppend.push(currentHeadElt);
|
3915
|
+
}
|
3916
|
+
} else {
|
3917
|
+
if (ctx.head.shouldRemove(currentHeadElt) !== false) {
|
3918
|
+
removed.push(currentHeadElt);
|
3919
|
+
}
|
3920
|
+
}
|
3921
|
+
}
|
3922
|
+
}
|
3923
|
+
nodesToAppend.push(...srcToNewHeadNodes.values());
|
3924
|
+
let promises = [];
|
3925
|
+
for (const newNode of nodesToAppend) {
|
3926
|
+
let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;
|
3927
|
+
if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {
|
3928
|
+
if (newElt.href || newElt.src) {
|
3929
|
+
let resolve = null;
|
3930
|
+
let promise = new Promise(function(_resolve) {
|
3931
|
+
resolve = _resolve;
|
3932
|
+
});
|
3933
|
+
newElt.addEventListener("load", function() {
|
3934
|
+
resolve();
|
3935
|
+
});
|
3936
|
+
promises.push(promise);
|
3937
|
+
}
|
3938
|
+
currentHead.appendChild(newElt);
|
3939
|
+
ctx.callbacks.afterNodeAdded(newElt);
|
3940
|
+
added.push(newElt);
|
3941
|
+
}
|
3942
|
+
}
|
3943
|
+
for (const removedElement of removed) {
|
3944
|
+
if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
|
3945
|
+
currentHead.removeChild(removedElement);
|
3946
|
+
ctx.callbacks.afterNodeRemoved(removedElement);
|
3947
|
+
}
|
3948
|
+
}
|
3949
|
+
ctx.head.afterHeadMorphed(currentHead, { added, kept: preserved, removed });
|
3950
|
+
return promises;
|
3951
|
+
}
|
3952
|
+
function noOp() {
|
3953
|
+
}
|
3954
|
+
function mergeDefaults(config) {
|
3955
|
+
let finalConfig = {};
|
3956
|
+
Object.assign(finalConfig, defaults);
|
3957
|
+
Object.assign(finalConfig, config);
|
3958
|
+
finalConfig.callbacks = {};
|
3959
|
+
Object.assign(finalConfig.callbacks, defaults.callbacks);
|
3960
|
+
Object.assign(finalConfig.callbacks, config.callbacks);
|
3961
|
+
finalConfig.head = {};
|
3962
|
+
Object.assign(finalConfig.head, defaults.head);
|
3963
|
+
Object.assign(finalConfig.head, config.head);
|
3964
|
+
return finalConfig;
|
3965
|
+
}
|
3966
|
+
function createMorphContext(oldNode, newContent, config) {
|
3967
|
+
config = mergeDefaults(config);
|
3968
|
+
return {
|
3969
|
+
target: oldNode,
|
3970
|
+
newContent,
|
3971
|
+
config,
|
3972
|
+
morphStyle: config.morphStyle,
|
3973
|
+
ignoreActive: config.ignoreActive,
|
3974
|
+
ignoreActiveValue: config.ignoreActiveValue,
|
3975
|
+
idMap: createIdMap(oldNode, newContent),
|
3976
|
+
deadIds: /* @__PURE__ */ new Set(),
|
3977
|
+
callbacks: config.callbacks,
|
3978
|
+
head: config.head
|
3979
|
+
};
|
3980
|
+
}
|
3981
|
+
function isIdSetMatch(node1, node2, ctx) {
|
3982
|
+
if (node1 == null || node2 == null) {
|
3983
|
+
return false;
|
3984
|
+
}
|
3985
|
+
if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {
|
3986
|
+
if (node1.id !== "" && node1.id === node2.id) {
|
3987
|
+
return true;
|
3988
|
+
} else {
|
3989
|
+
return getIdIntersectionCount(ctx, node1, node2) > 0;
|
3990
|
+
}
|
3991
|
+
}
|
3992
|
+
return false;
|
3993
|
+
}
|
3994
|
+
function isSoftMatch(node1, node2) {
|
3995
|
+
if (node1 == null || node2 == null) {
|
3996
|
+
return false;
|
3997
|
+
}
|
3998
|
+
return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName;
|
3999
|
+
}
|
4000
|
+
function removeNodesBetween(startInclusive, endExclusive, ctx) {
|
4001
|
+
while (startInclusive !== endExclusive) {
|
4002
|
+
let tempNode = startInclusive;
|
4003
|
+
startInclusive = startInclusive.nextSibling;
|
4004
|
+
removeNode(tempNode, ctx);
|
4005
|
+
}
|
4006
|
+
removeIdsFromConsideration(ctx, endExclusive);
|
4007
|
+
return endExclusive.nextSibling;
|
4008
|
+
}
|
4009
|
+
function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
|
4010
|
+
let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);
|
4011
|
+
let potentialMatch = null;
|
4012
|
+
if (newChildPotentialIdCount > 0) {
|
4013
|
+
let potentialMatch2 = insertionPoint;
|
4014
|
+
let otherMatchCount = 0;
|
4015
|
+
while (potentialMatch2 != null) {
|
4016
|
+
if (isIdSetMatch(newChild, potentialMatch2, ctx)) {
|
4017
|
+
return potentialMatch2;
|
4018
|
+
}
|
4019
|
+
otherMatchCount += getIdIntersectionCount(ctx, potentialMatch2, newContent);
|
4020
|
+
if (otherMatchCount > newChildPotentialIdCount) {
|
4021
|
+
return null;
|
4022
|
+
}
|
4023
|
+
potentialMatch2 = potentialMatch2.nextSibling;
|
4024
|
+
}
|
4025
|
+
}
|
4026
|
+
return potentialMatch;
|
4027
|
+
}
|
4028
|
+
function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
|
4029
|
+
let potentialSoftMatch = insertionPoint;
|
4030
|
+
let nextSibling = newChild.nextSibling;
|
4031
|
+
let siblingSoftMatchCount = 0;
|
4032
|
+
while (potentialSoftMatch != null) {
|
4033
|
+
if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {
|
4034
|
+
return null;
|
4035
|
+
}
|
4036
|
+
if (isSoftMatch(newChild, potentialSoftMatch)) {
|
4037
|
+
return potentialSoftMatch;
|
4038
|
+
}
|
4039
|
+
if (isSoftMatch(nextSibling, potentialSoftMatch)) {
|
4040
|
+
siblingSoftMatchCount++;
|
4041
|
+
nextSibling = nextSibling.nextSibling;
|
4042
|
+
if (siblingSoftMatchCount >= 2) {
|
4043
|
+
return null;
|
4044
|
+
}
|
4045
|
+
}
|
4046
|
+
potentialSoftMatch = potentialSoftMatch.nextSibling;
|
4047
|
+
}
|
4048
|
+
return potentialSoftMatch;
|
4049
|
+
}
|
4050
|
+
function parseContent(newContent) {
|
4051
|
+
let parser = new DOMParser();
|
4052
|
+
let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, "");
|
4053
|
+
if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
|
4054
|
+
let content = parser.parseFromString(newContent, "text/html");
|
4055
|
+
if (contentWithSvgsRemoved.match(/<\/html>/)) {
|
4056
|
+
content.generatedByIdiomorph = true;
|
4057
|
+
return content;
|
4058
|
+
} else {
|
4059
|
+
let htmlElement = content.firstChild;
|
4060
|
+
if (htmlElement) {
|
4061
|
+
htmlElement.generatedByIdiomorph = true;
|
4062
|
+
return htmlElement;
|
4063
|
+
} else {
|
4064
|
+
return null;
|
4065
|
+
}
|
4066
|
+
}
|
4067
|
+
} else {
|
4068
|
+
let responseDoc = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html");
|
4069
|
+
let content = responseDoc.body.querySelector("template").content;
|
4070
|
+
content.generatedByIdiomorph = true;
|
4071
|
+
return content;
|
4072
|
+
}
|
4073
|
+
}
|
4074
|
+
function normalizeContent(newContent) {
|
4075
|
+
if (newContent == null) {
|
4076
|
+
const dummyParent = document.createElement("div");
|
4077
|
+
return dummyParent;
|
4078
|
+
} else if (newContent.generatedByIdiomorph) {
|
4079
|
+
return newContent;
|
4080
|
+
} else if (newContent instanceof Node) {
|
4081
|
+
const dummyParent = document.createElement("div");
|
4082
|
+
dummyParent.append(newContent);
|
4083
|
+
return dummyParent;
|
4084
|
+
} else {
|
4085
|
+
const dummyParent = document.createElement("div");
|
4086
|
+
for (const elt of [...newContent]) {
|
4087
|
+
dummyParent.append(elt);
|
4088
|
+
}
|
4089
|
+
return dummyParent;
|
4090
|
+
}
|
4091
|
+
}
|
4092
|
+
function insertSiblings(previousSibling, morphedNode, nextSibling) {
|
4093
|
+
let stack = [];
|
4094
|
+
let added = [];
|
4095
|
+
while (previousSibling != null) {
|
4096
|
+
stack.push(previousSibling);
|
4097
|
+
previousSibling = previousSibling.previousSibling;
|
4098
|
+
}
|
4099
|
+
while (stack.length > 0) {
|
4100
|
+
let node = stack.pop();
|
4101
|
+
added.push(node);
|
4102
|
+
morphedNode.parentElement.insertBefore(node, morphedNode);
|
4103
|
+
}
|
4104
|
+
added.push(morphedNode);
|
4105
|
+
while (nextSibling != null) {
|
4106
|
+
stack.push(nextSibling);
|
4107
|
+
added.push(nextSibling);
|
4108
|
+
nextSibling = nextSibling.nextSibling;
|
4109
|
+
}
|
4110
|
+
while (stack.length > 0) {
|
4111
|
+
morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);
|
4112
|
+
}
|
4113
|
+
return added;
|
4114
|
+
}
|
4115
|
+
function findBestNodeMatch(newContent, oldNode, ctx) {
|
4116
|
+
let currentElement;
|
4117
|
+
currentElement = newContent.firstChild;
|
4118
|
+
let bestElement = currentElement;
|
4119
|
+
let score = 0;
|
4120
|
+
while (currentElement) {
|
4121
|
+
let newScore = scoreElement(currentElement, oldNode, ctx);
|
4122
|
+
if (newScore > score) {
|
4123
|
+
bestElement = currentElement;
|
4124
|
+
score = newScore;
|
3097
4125
|
}
|
4126
|
+
currentElement = currentElement.nextSibling;
|
3098
4127
|
}
|
4128
|
+
return bestElement;
|
3099
4129
|
}
|
3100
|
-
|
3101
|
-
|
4130
|
+
function scoreElement(node1, node2, ctx) {
|
4131
|
+
if (isSoftMatch(node1, node2)) {
|
4132
|
+
return 0.5 + getIdIntersectionCount(ctx, node1, node2);
|
4133
|
+
}
|
4134
|
+
return 0;
|
3102
4135
|
}
|
3103
|
-
|
3104
|
-
|
4136
|
+
function removeNode(tempNode, ctx) {
|
4137
|
+
removeIdsFromConsideration(ctx, tempNode);
|
4138
|
+
if (ctx.callbacks.beforeNodeRemoved(tempNode) === false)
|
4139
|
+
return;
|
4140
|
+
tempNode.remove();
|
4141
|
+
ctx.callbacks.afterNodeRemoved(tempNode);
|
4142
|
+
}
|
4143
|
+
function isIdInConsideration(ctx, id) {
|
4144
|
+
return !ctx.deadIds.has(id);
|
4145
|
+
}
|
4146
|
+
function idIsWithinNode(ctx, id, targetNode) {
|
4147
|
+
let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;
|
4148
|
+
return idSet.has(id);
|
4149
|
+
}
|
4150
|
+
function removeIdsFromConsideration(ctx, node) {
|
4151
|
+
let idSet = ctx.idMap.get(node) || EMPTY_SET;
|
4152
|
+
for (const id of idSet) {
|
4153
|
+
ctx.deadIds.add(id);
|
4154
|
+
}
|
4155
|
+
}
|
4156
|
+
function getIdIntersectionCount(ctx, node1, node2) {
|
4157
|
+
let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;
|
4158
|
+
let matchCount = 0;
|
4159
|
+
for (const id of sourceSet) {
|
4160
|
+
if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {
|
4161
|
+
++matchCount;
|
4162
|
+
}
|
4163
|
+
}
|
4164
|
+
return matchCount;
|
4165
|
+
}
|
4166
|
+
function populateIdMapForNode(node, idMap) {
|
4167
|
+
let nodeParent = node.parentElement;
|
4168
|
+
let idElements = node.querySelectorAll("[id]");
|
4169
|
+
for (const elt of idElements) {
|
4170
|
+
let current = elt;
|
4171
|
+
while (current !== nodeParent && current != null) {
|
4172
|
+
let idSet = idMap.get(current);
|
4173
|
+
if (idSet == null) {
|
4174
|
+
idSet = /* @__PURE__ */ new Set();
|
4175
|
+
idMap.set(current, idSet);
|
4176
|
+
}
|
4177
|
+
idSet.add(elt.id);
|
4178
|
+
current = current.parentElement;
|
4179
|
+
}
|
4180
|
+
}
|
3105
4181
|
}
|
3106
|
-
|
4182
|
+
function createIdMap(oldContent, newContent) {
|
4183
|
+
let idMap = /* @__PURE__ */ new Map();
|
4184
|
+
populateIdMapForNode(oldContent, idMap);
|
4185
|
+
populateIdMapForNode(newContent, idMap);
|
4186
|
+
return idMap;
|
4187
|
+
}
|
4188
|
+
return {
|
4189
|
+
morph,
|
4190
|
+
defaults
|
4191
|
+
};
|
4192
|
+
}();
|
3107
4193
|
var PageRenderer = class extends Renderer {
|
3108
4194
|
static renderElement(currentElement, newElement) {
|
3109
4195
|
if (document.body && newElement instanceof HTMLBodyElement) {
|
@@ -3128,6 +4214,7 @@
|
|
3128
4214
|
}
|
3129
4215
|
}
|
3130
4216
|
async prepareToRender() {
|
4217
|
+
this.#setLanguage();
|
3131
4218
|
await this.mergeHead();
|
3132
4219
|
}
|
3133
4220
|
async render() {
|
@@ -3150,12 +4237,24 @@
|
|
3150
4237
|
get newElement() {
|
3151
4238
|
return this.newSnapshot.element;
|
3152
4239
|
}
|
4240
|
+
#setLanguage() {
|
4241
|
+
const { documentElement } = this.currentSnapshot;
|
4242
|
+
const { lang } = this.newSnapshot;
|
4243
|
+
if (lang) {
|
4244
|
+
documentElement.setAttribute("lang", lang);
|
4245
|
+
} else {
|
4246
|
+
documentElement.removeAttribute("lang");
|
4247
|
+
}
|
4248
|
+
}
|
3153
4249
|
async mergeHead() {
|
3154
4250
|
const mergedHeadElements = this.mergeProvisionalElements();
|
3155
4251
|
const newStylesheetElements = this.copyNewHeadStylesheetElements();
|
3156
4252
|
this.copyNewHeadScriptElements();
|
3157
4253
|
await mergedHeadElements;
|
3158
4254
|
await newStylesheetElements;
|
4255
|
+
if (this.willRender) {
|
4256
|
+
this.removeUnusedDynamicStylesheetElements();
|
4257
|
+
}
|
3159
4258
|
}
|
3160
4259
|
async replaceBody() {
|
3161
4260
|
await this.preservingPermanentElements(async () => {
|
@@ -3179,6 +4278,11 @@
|
|
3179
4278
|
document.head.appendChild(activateScriptElement(element));
|
3180
4279
|
}
|
3181
4280
|
}
|
4281
|
+
removeUnusedDynamicStylesheetElements() {
|
4282
|
+
for (const element of this.unusedDynamicStylesheetElements) {
|
4283
|
+
document.head.removeChild(element);
|
4284
|
+
}
|
4285
|
+
}
|
3182
4286
|
async mergeProvisionalElements() {
|
3183
4287
|
const newHeadElements = [...this.newHeadProvisionalElements];
|
3184
4288
|
for (const element of this.currentHeadProvisionalElements) {
|
@@ -3231,6 +4335,14 @@
|
|
3231
4335
|
async assignNewBody() {
|
3232
4336
|
await this.renderElement(this.currentElement, this.newElement);
|
3233
4337
|
}
|
4338
|
+
get unusedDynamicStylesheetElements() {
|
4339
|
+
return this.oldHeadStylesheetElements.filter((element) => {
|
4340
|
+
return element.getAttribute("data-turbo-track") === "dynamic";
|
4341
|
+
});
|
4342
|
+
}
|
4343
|
+
get oldHeadStylesheetElements() {
|
4344
|
+
return this.currentHeadSnapshot.getStylesheetElementsNotInSnapshot(this.newHeadSnapshot);
|
4345
|
+
}
|
3234
4346
|
get newHeadStylesheetElements() {
|
3235
4347
|
return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
3236
4348
|
}
|
@@ -3247,10 +4359,107 @@
|
|
3247
4359
|
return this.newElement.querySelectorAll("script");
|
3248
4360
|
}
|
3249
4361
|
};
|
4362
|
+
var MorphRenderer = class extends PageRenderer {
|
4363
|
+
async render() {
|
4364
|
+
if (this.willRender)
|
4365
|
+
await this.#morphBody();
|
4366
|
+
}
|
4367
|
+
get renderMethod() {
|
4368
|
+
return "morph";
|
4369
|
+
}
|
4370
|
+
// Private
|
4371
|
+
async #morphBody() {
|
4372
|
+
this.#morphElements(this.currentElement, this.newElement);
|
4373
|
+
this.#reloadRemoteFrames();
|
4374
|
+
dispatch("turbo:morph", {
|
4375
|
+
detail: {
|
4376
|
+
currentElement: this.currentElement,
|
4377
|
+
newElement: this.newElement
|
4378
|
+
}
|
4379
|
+
});
|
4380
|
+
}
|
4381
|
+
#morphElements(currentElement, newElement, morphStyle = "outerHTML") {
|
4382
|
+
this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
|
4383
|
+
Idiomorph.morph(currentElement, newElement, {
|
4384
|
+
morphStyle,
|
4385
|
+
callbacks: {
|
4386
|
+
beforeNodeAdded: this.#shouldAddElement,
|
4387
|
+
beforeNodeMorphed: this.#shouldMorphElement,
|
4388
|
+
beforeAttributeUpdated: this.#shouldUpdateAttribute,
|
4389
|
+
beforeNodeRemoved: this.#shouldRemoveElement,
|
4390
|
+
afterNodeMorphed: this.#didMorphElement
|
4391
|
+
}
|
4392
|
+
});
|
4393
|
+
}
|
4394
|
+
#shouldAddElement = (node) => {
|
4395
|
+
return !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id));
|
4396
|
+
};
|
4397
|
+
#shouldMorphElement = (oldNode, newNode) => {
|
4398
|
+
if (oldNode instanceof HTMLElement) {
|
4399
|
+
if (!oldNode.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(oldNode))) {
|
4400
|
+
const event = dispatch("turbo:before-morph-element", {
|
4401
|
+
cancelable: true,
|
4402
|
+
target: oldNode,
|
4403
|
+
detail: {
|
4404
|
+
newElement: newNode
|
4405
|
+
}
|
4406
|
+
});
|
4407
|
+
return !event.defaultPrevented;
|
4408
|
+
} else {
|
4409
|
+
return false;
|
4410
|
+
}
|
4411
|
+
}
|
4412
|
+
};
|
4413
|
+
#shouldUpdateAttribute = (attributeName, target, mutationType) => {
|
4414
|
+
const event = dispatch("turbo:before-morph-attribute", { cancelable: true, target, detail: { attributeName, mutationType } });
|
4415
|
+
return !event.defaultPrevented;
|
4416
|
+
};
|
4417
|
+
#didMorphElement = (oldNode, newNode) => {
|
4418
|
+
if (newNode instanceof HTMLElement) {
|
4419
|
+
dispatch("turbo:morph-element", {
|
4420
|
+
target: oldNode,
|
4421
|
+
detail: {
|
4422
|
+
newElement: newNode
|
4423
|
+
}
|
4424
|
+
});
|
4425
|
+
}
|
4426
|
+
};
|
4427
|
+
#shouldRemoveElement = (node) => {
|
4428
|
+
return this.#shouldMorphElement(node);
|
4429
|
+
};
|
4430
|
+
#reloadRemoteFrames() {
|
4431
|
+
this.#remoteFrames().forEach((frame) => {
|
4432
|
+
if (this.#isFrameReloadedWithMorph(frame)) {
|
4433
|
+
this.#renderFrameWithMorph(frame);
|
4434
|
+
frame.reload();
|
4435
|
+
}
|
4436
|
+
});
|
4437
|
+
}
|
4438
|
+
#renderFrameWithMorph(frame) {
|
4439
|
+
frame.addEventListener("turbo:before-frame-render", (event) => {
|
4440
|
+
event.detail.render = this.#morphFrameUpdate;
|
4441
|
+
}, { once: true });
|
4442
|
+
}
|
4443
|
+
#morphFrameUpdate = (currentElement, newElement) => {
|
4444
|
+
dispatch("turbo:before-frame-morph", {
|
4445
|
+
target: currentElement,
|
4446
|
+
detail: { currentElement, newElement }
|
4447
|
+
});
|
4448
|
+
this.#morphElements(currentElement, newElement.children, "innerHTML");
|
4449
|
+
};
|
4450
|
+
#isFrameReloadedWithMorph(element) {
|
4451
|
+
return element.src && element.refresh === "morph";
|
4452
|
+
}
|
4453
|
+
#remoteFrames() {
|
4454
|
+
return Array.from(document.querySelectorAll("turbo-frame[src]")).filter((frame) => {
|
4455
|
+
return !frame.closest("[data-turbo-permanent]");
|
4456
|
+
});
|
4457
|
+
}
|
4458
|
+
};
|
3250
4459
|
var SnapshotCache = class {
|
4460
|
+
keys = [];
|
4461
|
+
snapshots = {};
|
3251
4462
|
constructor(size) {
|
3252
|
-
this.keys = [];
|
3253
|
-
this.snapshots = {};
|
3254
4463
|
this.size = size;
|
3255
4464
|
}
|
3256
4465
|
has(location2) {
|
@@ -3271,6 +4480,7 @@
|
|
3271
4480
|
clear() {
|
3272
4481
|
this.snapshots = {};
|
3273
4482
|
}
|
4483
|
+
// Private
|
3274
4484
|
read(location2) {
|
3275
4485
|
return this.snapshots[toCacheKey(location2)];
|
3276
4486
|
}
|
@@ -3292,23 +4502,25 @@
|
|
3292
4502
|
}
|
3293
4503
|
};
|
3294
4504
|
var PageView = class extends View {
|
3295
|
-
|
3296
|
-
|
3297
|
-
|
3298
|
-
|
3299
|
-
this.
|
4505
|
+
snapshotCache = new SnapshotCache(10);
|
4506
|
+
lastRenderedLocation = new URL(location.href);
|
4507
|
+
forceReloaded = false;
|
4508
|
+
shouldTransitionTo(newSnapshot) {
|
4509
|
+
return this.snapshot.prefersViewTransitions && newSnapshot.prefersViewTransitions;
|
3300
4510
|
}
|
3301
4511
|
renderPage(snapshot, isPreview = false, willRender = true, visit2) {
|
3302
|
-
const
|
4512
|
+
const shouldMorphPage = this.isPageRefresh(visit2) && this.snapshot.shouldMorphPage;
|
4513
|
+
const rendererClass = shouldMorphPage ? MorphRenderer : PageRenderer;
|
4514
|
+
const renderer = new rendererClass(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
|
3303
4515
|
if (!renderer.shouldRender) {
|
3304
4516
|
this.forceReloaded = true;
|
3305
4517
|
} else {
|
3306
|
-
visit2
|
4518
|
+
visit2?.changeHistory();
|
3307
4519
|
}
|
3308
4520
|
return this.render(renderer);
|
3309
4521
|
}
|
3310
4522
|
renderError(snapshot, visit2) {
|
3311
|
-
visit2
|
4523
|
+
visit2?.changeHistory();
|
3312
4524
|
const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
|
3313
4525
|
return this.render(renderer);
|
3314
4526
|
}
|
@@ -3328,30 +4540,37 @@
|
|
3328
4540
|
getCachedSnapshotForLocation(location2) {
|
3329
4541
|
return this.snapshotCache.get(location2);
|
3330
4542
|
}
|
4543
|
+
isPageRefresh(visit2) {
|
4544
|
+
return !visit2 || this.lastRenderedLocation.pathname === visit2.location.pathname && visit2.action === "replace";
|
4545
|
+
}
|
4546
|
+
shouldPreserveScrollPosition(visit2) {
|
4547
|
+
return this.isPageRefresh(visit2) && this.snapshot.shouldPreserveScrollPosition;
|
4548
|
+
}
|
3331
4549
|
get snapshot() {
|
3332
4550
|
return PageSnapshot.fromElement(this.element);
|
3333
4551
|
}
|
3334
4552
|
};
|
3335
4553
|
var Preloader = class {
|
3336
|
-
|
3337
|
-
|
4554
|
+
selector = "a[data-turbo-preload]";
|
4555
|
+
constructor(delegate, snapshotCache) {
|
3338
4556
|
this.delegate = delegate;
|
3339
|
-
|
3340
|
-
get snapshotCache() {
|
3341
|
-
return this.delegate.navigator.view.snapshotCache;
|
4557
|
+
this.snapshotCache = snapshotCache;
|
3342
4558
|
}
|
3343
4559
|
start() {
|
3344
4560
|
if (document.readyState === "loading") {
|
3345
|
-
|
3346
|
-
this.preloadOnLoadLinksForView(document.body);
|
3347
|
-
});
|
4561
|
+
document.addEventListener("DOMContentLoaded", this.#preloadAll);
|
3348
4562
|
} else {
|
3349
4563
|
this.preloadOnLoadLinksForView(document.body);
|
3350
4564
|
}
|
3351
4565
|
}
|
4566
|
+
stop() {
|
4567
|
+
document.removeEventListener("DOMContentLoaded", this.#preloadAll);
|
4568
|
+
}
|
3352
4569
|
preloadOnLoadLinksForView(element) {
|
3353
4570
|
for (const link of element.querySelectorAll(this.selector)) {
|
3354
|
-
this.
|
4571
|
+
if (this.delegate.shouldPreloadLink(link)) {
|
4572
|
+
this.preloadURL(link);
|
4573
|
+
}
|
3355
4574
|
}
|
3356
4575
|
}
|
3357
4576
|
async preloadURL(link) {
|
@@ -3359,41 +4578,88 @@
|
|
3359
4578
|
if (this.snapshotCache.has(location2)) {
|
3360
4579
|
return;
|
3361
4580
|
}
|
4581
|
+
const fetchRequest = new FetchRequest(this, FetchMethod.get, location2, new URLSearchParams(), link);
|
4582
|
+
await fetchRequest.perform();
|
4583
|
+
}
|
4584
|
+
// Fetch request delegate
|
4585
|
+
prepareRequest(fetchRequest) {
|
4586
|
+
fetchRequest.headers["X-Sec-Purpose"] = "prefetch";
|
4587
|
+
}
|
4588
|
+
async requestSucceededWithResponse(fetchRequest, fetchResponse) {
|
3362
4589
|
try {
|
3363
|
-
const
|
3364
|
-
const
|
3365
|
-
|
3366
|
-
this.snapshotCache.put(location2, snapshot);
|
4590
|
+
const responseHTML = await fetchResponse.responseHTML;
|
4591
|
+
const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
4592
|
+
this.snapshotCache.put(fetchRequest.url, snapshot);
|
3367
4593
|
} catch (_) {
|
3368
4594
|
}
|
3369
4595
|
}
|
4596
|
+
requestStarted(fetchRequest) {
|
4597
|
+
}
|
4598
|
+
requestErrored(fetchRequest) {
|
4599
|
+
}
|
4600
|
+
requestFinished(fetchRequest) {
|
4601
|
+
}
|
4602
|
+
requestPreventedHandlingResponse(fetchRequest, fetchResponse) {
|
4603
|
+
}
|
4604
|
+
requestFailedWithResponse(fetchRequest, fetchResponse) {
|
4605
|
+
}
|
4606
|
+
#preloadAll = () => {
|
4607
|
+
this.preloadOnLoadLinksForView(document.body);
|
4608
|
+
};
|
4609
|
+
};
|
4610
|
+
var Cache = class {
|
4611
|
+
constructor(session2) {
|
4612
|
+
this.session = session2;
|
4613
|
+
}
|
4614
|
+
clear() {
|
4615
|
+
this.session.clearCache();
|
4616
|
+
}
|
4617
|
+
resetCacheControl() {
|
4618
|
+
this.#setCacheControl("");
|
4619
|
+
}
|
4620
|
+
exemptPageFromCache() {
|
4621
|
+
this.#setCacheControl("no-cache");
|
4622
|
+
}
|
4623
|
+
exemptPageFromPreview() {
|
4624
|
+
this.#setCacheControl("no-preview");
|
4625
|
+
}
|
4626
|
+
#setCacheControl(value) {
|
4627
|
+
setMetaContent("turbo-cache-control", value);
|
4628
|
+
}
|
3370
4629
|
};
|
3371
4630
|
var Session = class {
|
3372
|
-
|
3373
|
-
|
3374
|
-
|
3375
|
-
|
3376
|
-
|
3377
|
-
|
3378
|
-
|
3379
|
-
|
3380
|
-
|
3381
|
-
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
|
3387
|
-
|
3388
|
-
|
3389
|
-
|
3390
|
-
|
3391
|
-
|
4631
|
+
navigator = new Navigator(this);
|
4632
|
+
history = new History(this);
|
4633
|
+
view = new PageView(this, document.documentElement);
|
4634
|
+
adapter = new BrowserAdapter(this);
|
4635
|
+
pageObserver = new PageObserver(this);
|
4636
|
+
cacheObserver = new CacheObserver();
|
4637
|
+
linkPrefetchObserver = new LinkPrefetchObserver(this, document);
|
4638
|
+
linkClickObserver = new LinkClickObserver(this, window);
|
4639
|
+
formSubmitObserver = new FormSubmitObserver(this, document);
|
4640
|
+
scrollObserver = new ScrollObserver(this);
|
4641
|
+
streamObserver = new StreamObserver(this);
|
4642
|
+
formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
|
4643
|
+
frameRedirector = new FrameRedirector(this, document.documentElement);
|
4644
|
+
streamMessageRenderer = new StreamMessageRenderer();
|
4645
|
+
cache = new Cache(this);
|
4646
|
+
drive = true;
|
4647
|
+
enabled = true;
|
4648
|
+
progressBarDelay = 500;
|
4649
|
+
started = false;
|
4650
|
+
formMode = "on";
|
4651
|
+
#pageRefreshDebouncePeriod = 150;
|
4652
|
+
constructor(recentRequests2) {
|
4653
|
+
this.recentRequests = recentRequests2;
|
4654
|
+
this.preloader = new Preloader(this, this.view.snapshotCache);
|
4655
|
+
this.debouncedRefresh = this.refresh;
|
4656
|
+
this.pageRefreshDebouncePeriod = this.pageRefreshDebouncePeriod;
|
3392
4657
|
}
|
3393
4658
|
start() {
|
3394
4659
|
if (!this.started) {
|
3395
4660
|
this.pageObserver.start();
|
3396
4661
|
this.cacheObserver.start();
|
4662
|
+
this.linkPrefetchObserver.start();
|
3397
4663
|
this.formLinkClickObserver.start();
|
3398
4664
|
this.linkClickObserver.start();
|
3399
4665
|
this.formSubmitObserver.start();
|
@@ -3413,6 +4679,7 @@
|
|
3413
4679
|
if (this.started) {
|
3414
4680
|
this.pageObserver.stop();
|
3415
4681
|
this.cacheObserver.stop();
|
4682
|
+
this.linkPrefetchObserver.stop();
|
3416
4683
|
this.formLinkClickObserver.stop();
|
3417
4684
|
this.linkClickObserver.stop();
|
3418
4685
|
this.formSubmitObserver.stop();
|
@@ -3420,6 +4687,7 @@
|
|
3420
4687
|
this.streamObserver.stop();
|
3421
4688
|
this.frameRedirector.stop();
|
3422
4689
|
this.history.stop();
|
4690
|
+
this.preloader.stop();
|
3423
4691
|
this.started = false;
|
3424
4692
|
}
|
3425
4693
|
}
|
@@ -3429,12 +4697,19 @@
|
|
3429
4697
|
visit(location2, options = {}) {
|
3430
4698
|
const frameElement = options.frame ? document.getElementById(options.frame) : null;
|
3431
4699
|
if (frameElement instanceof FrameElement) {
|
4700
|
+
const action = options.action || getVisitAction(frameElement);
|
4701
|
+
frameElement.delegate.proposeVisitIfNavigatedWithAction(frameElement, action);
|
3432
4702
|
frameElement.src = location2.toString();
|
3433
|
-
frameElement.loaded;
|
3434
4703
|
} else {
|
3435
4704
|
this.navigator.proposeVisit(expandURL(location2), options);
|
3436
4705
|
}
|
3437
4706
|
}
|
4707
|
+
refresh(url, requestId) {
|
4708
|
+
const isRecentRequest = requestId && this.recentRequests.has(requestId);
|
4709
|
+
if (!isRecentRequest) {
|
4710
|
+
this.visit(url, { action: "replace", shouldCacheSnapshot: false });
|
4711
|
+
}
|
4712
|
+
}
|
3438
4713
|
connectStreamSource(source) {
|
3439
4714
|
this.streamObserver.connectStreamSource(source);
|
3440
4715
|
}
|
@@ -3459,11 +4734,33 @@
|
|
3459
4734
|
get restorationIdentifier() {
|
3460
4735
|
return this.history.restorationIdentifier;
|
3461
4736
|
}
|
3462
|
-
|
4737
|
+
get pageRefreshDebouncePeriod() {
|
4738
|
+
return this.#pageRefreshDebouncePeriod;
|
4739
|
+
}
|
4740
|
+
set pageRefreshDebouncePeriod(value) {
|
4741
|
+
this.refresh = debounce(this.debouncedRefresh.bind(this), value);
|
4742
|
+
this.#pageRefreshDebouncePeriod = value;
|
4743
|
+
}
|
4744
|
+
// Preloader delegate
|
4745
|
+
shouldPreloadLink(element) {
|
4746
|
+
const isUnsafe = element.hasAttribute("data-turbo-method");
|
4747
|
+
const isStream = element.hasAttribute("data-turbo-stream");
|
4748
|
+
const frameTarget = element.getAttribute("data-turbo-frame");
|
4749
|
+
const frame = frameTarget == "_top" ? null : document.getElementById(frameTarget) || findClosestRecursively(element, "turbo-frame:not([disabled])");
|
4750
|
+
if (isUnsafe || isStream || frame instanceof FrameElement) {
|
4751
|
+
return false;
|
4752
|
+
} else {
|
4753
|
+
const location2 = new URL(element.href);
|
4754
|
+
return this.elementIsNavigatable(element) && locationIsVisitable(location2, this.snapshot.rootLocation);
|
4755
|
+
}
|
4756
|
+
}
|
4757
|
+
// History delegate
|
4758
|
+
historyPoppedToLocationWithRestorationIdentifierAndDirection(location2, restorationIdentifier, direction) {
|
3463
4759
|
if (this.enabled) {
|
3464
4760
|
this.navigator.startVisit(location2, restorationIdentifier, {
|
3465
4761
|
action: "restore",
|
3466
|
-
historyChanged: true
|
4762
|
+
historyChanged: true,
|
4763
|
+
direction
|
3467
4764
|
});
|
3468
4765
|
} else {
|
3469
4766
|
this.adapter.pageInvalidated({
|
@@ -3471,14 +4768,21 @@
|
|
3471
4768
|
});
|
3472
4769
|
}
|
3473
4770
|
}
|
4771
|
+
// Scroll observer delegate
|
3474
4772
|
scrollPositionChanged(position) {
|
3475
4773
|
this.history.updateRestorationData({ scrollPosition: position });
|
3476
4774
|
}
|
4775
|
+
// Form click observer delegate
|
3477
4776
|
willSubmitFormLinkToLocation(link, location2) {
|
3478
4777
|
return this.elementIsNavigatable(link) && locationIsVisitable(location2, this.snapshot.rootLocation);
|
3479
4778
|
}
|
3480
4779
|
submittedFormLinkToLocation() {
|
3481
4780
|
}
|
4781
|
+
// Link hover observer delegate
|
4782
|
+
canPrefetchRequestToLocation(link, location2) {
|
4783
|
+
return this.elementIsNavigatable(link) && locationIsVisitable(location2, this.snapshot.rootLocation);
|
4784
|
+
}
|
4785
|
+
// Link click observer delegate
|
3482
4786
|
willFollowLinkToLocation(link, location2, event) {
|
3483
4787
|
return this.elementIsNavigatable(link) && locationIsVisitable(location2, this.snapshot.rootLocation) && this.applicationAllowsFollowingLinkToLocation(link, location2, event);
|
3484
4788
|
}
|
@@ -3487,6 +4791,7 @@
|
|
3487
4791
|
const acceptsStreamResponse = link.hasAttribute("data-turbo-stream");
|
3488
4792
|
this.visit(location2.href, { action, acceptsStreamResponse });
|
3489
4793
|
}
|
4794
|
+
// Navigator delegate
|
3490
4795
|
allowsVisitingLocationWithAction(location2, action) {
|
3491
4796
|
return this.locationWithActionIsSamePage(location2, action) || this.applicationAllowsVisitingLocation(location2);
|
3492
4797
|
}
|
@@ -3494,9 +4799,11 @@
|
|
3494
4799
|
extendURLWithDeprecatedProperties(location2);
|
3495
4800
|
this.adapter.visitProposedToLocation(location2, options);
|
3496
4801
|
}
|
4802
|
+
// Visit delegate
|
3497
4803
|
visitStarted(visit2) {
|
3498
4804
|
if (!visit2.acceptsStreamResponse) {
|
3499
4805
|
markAsBusy(document.documentElement);
|
4806
|
+
this.view.markVisitDirection(visit2.direction);
|
3500
4807
|
}
|
3501
4808
|
extendURLWithDeprecatedProperties(visit2.location);
|
3502
4809
|
if (!visit2.silent) {
|
@@ -3504,6 +4811,7 @@
|
|
3504
4811
|
}
|
3505
4812
|
}
|
3506
4813
|
visitCompleted(visit2) {
|
4814
|
+
this.view.unmarkVisitDirection();
|
3507
4815
|
clearBusyState(document.documentElement);
|
3508
4816
|
this.notifyApplicationAfterPageLoad(visit2.getTimingMetrics());
|
3509
4817
|
}
|
@@ -3513,13 +4821,15 @@
|
|
3513
4821
|
visitScrolledToSamePageLocation(oldURL, newURL) {
|
3514
4822
|
this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
3515
4823
|
}
|
4824
|
+
// Form submit observer delegate
|
3516
4825
|
willSubmitForm(form, submitter) {
|
3517
|
-
const action = getAction(form, submitter);
|
4826
|
+
const action = getAction$1(form, submitter);
|
3518
4827
|
return this.submissionIsNavigatable(form, submitter) && locationIsVisitable(expandURL(action), this.snapshot.rootLocation);
|
3519
4828
|
}
|
3520
4829
|
formSubmitted(form, submitter) {
|
3521
4830
|
this.navigator.submitForm(form, submitter);
|
3522
4831
|
}
|
4832
|
+
// Page observer delegate
|
3523
4833
|
pageBecameInteractive() {
|
3524
4834
|
this.view.lastRenderedLocation = this.location;
|
3525
4835
|
this.notifyApplicationAfterPageLoad();
|
@@ -3530,26 +4840,30 @@
|
|
3530
4840
|
pageWillUnload() {
|
3531
4841
|
this.history.relinquishControlOfScrollRestoration();
|
3532
4842
|
}
|
4843
|
+
// Stream observer delegate
|
3533
4844
|
receivedMessageFromStream(message) {
|
3534
4845
|
this.renderStreamMessage(message);
|
3535
4846
|
}
|
4847
|
+
// Page view delegate
|
3536
4848
|
viewWillCacheSnapshot() {
|
3537
|
-
|
3538
|
-
if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {
|
4849
|
+
if (!this.navigator.currentVisit?.silent) {
|
3539
4850
|
this.notifyApplicationBeforeCachingSnapshot();
|
3540
4851
|
}
|
3541
4852
|
}
|
3542
4853
|
allowsImmediateRender({ element }, options) {
|
3543
4854
|
const event = this.notifyApplicationBeforeRender(element, options);
|
3544
|
-
const {
|
4855
|
+
const {
|
4856
|
+
defaultPrevented,
|
4857
|
+
detail: { render }
|
4858
|
+
} = event;
|
3545
4859
|
if (this.view.renderer && render) {
|
3546
4860
|
this.view.renderer.renderElement = render;
|
3547
4861
|
}
|
3548
4862
|
return !defaultPrevented;
|
3549
4863
|
}
|
3550
|
-
viewRenderedSnapshot(_snapshot, _isPreview) {
|
4864
|
+
viewRenderedSnapshot(_snapshot, _isPreview, renderMethod) {
|
3551
4865
|
this.view.lastRenderedLocation = this.history.location;
|
3552
|
-
this.notifyApplicationAfterRender();
|
4866
|
+
this.notifyApplicationAfterRender(renderMethod);
|
3553
4867
|
}
|
3554
4868
|
preloadOnLoadLinksForView(element) {
|
3555
4869
|
this.preloader.preloadOnLoadLinksForView(element);
|
@@ -3557,12 +4871,14 @@
|
|
3557
4871
|
viewInvalidated(reason) {
|
3558
4872
|
this.adapter.pageInvalidated(reason);
|
3559
4873
|
}
|
4874
|
+
// Frame element
|
3560
4875
|
frameLoaded(frame) {
|
3561
4876
|
this.notifyApplicationAfterFrameLoad(frame);
|
3562
4877
|
}
|
3563
4878
|
frameRendered(fetchResponse, frame) {
|
3564
4879
|
this.notifyApplicationAfterFrameRender(fetchResponse, frame);
|
3565
4880
|
}
|
4881
|
+
// Application events
|
3566
4882
|
applicationAllowsFollowingLinkToLocation(link, location2, ev) {
|
3567
4883
|
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location2, ev);
|
3568
4884
|
return !event.defaultPrevented;
|
@@ -3592,12 +4908,12 @@
|
|
3592
4908
|
}
|
3593
4909
|
notifyApplicationBeforeRender(newBody, options) {
|
3594
4910
|
return dispatch("turbo:before-render", {
|
3595
|
-
detail:
|
4911
|
+
detail: { newBody, ...options },
|
3596
4912
|
cancelable: true
|
3597
4913
|
});
|
3598
4914
|
}
|
3599
|
-
notifyApplicationAfterRender() {
|
3600
|
-
return dispatch("turbo:render");
|
4915
|
+
notifyApplicationAfterRender(renderMethod) {
|
4916
|
+
return dispatch("turbo:render", { detail: { renderMethod } });
|
3601
4917
|
}
|
3602
4918
|
notifyApplicationAfterPageLoad(timing = {}) {
|
3603
4919
|
return dispatch("turbo:load", {
|
@@ -3605,10 +4921,12 @@
|
|
3605
4921
|
});
|
3606
4922
|
}
|
3607
4923
|
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
3608
|
-
dispatchEvent(
|
3609
|
-
|
3610
|
-
|
3611
|
-
|
4924
|
+
dispatchEvent(
|
4925
|
+
new HashChangeEvent("hashchange", {
|
4926
|
+
oldURL: oldURL.toString(),
|
4927
|
+
newURL: newURL.toString()
|
4928
|
+
})
|
4929
|
+
);
|
3612
4930
|
}
|
3613
4931
|
notifyApplicationAfterFrameLoad(frame) {
|
3614
4932
|
return dispatch("turbo:frame-load", { target: frame });
|
@@ -3620,6 +4938,7 @@
|
|
3620
4938
|
cancelable: true
|
3621
4939
|
});
|
3622
4940
|
}
|
4941
|
+
// Helpers
|
3623
4942
|
submissionIsNavigatable(form, submitter) {
|
3624
4943
|
if (this.formMode == "off") {
|
3625
4944
|
return false;
|
@@ -3649,6 +4968,7 @@
|
|
3649
4968
|
}
|
3650
4969
|
}
|
3651
4970
|
}
|
4971
|
+
// Private
|
3652
4972
|
getActionForLink(link) {
|
3653
4973
|
return getVisitAction(link) || "advance";
|
3654
4974
|
}
|
@@ -3666,63 +4986,8 @@
|
|
3666
4986
|
}
|
3667
4987
|
}
|
3668
4988
|
};
|
3669
|
-
var
|
3670
|
-
|
3671
|
-
this.session = session2;
|
3672
|
-
}
|
3673
|
-
clear() {
|
3674
|
-
this.session.clearCache();
|
3675
|
-
}
|
3676
|
-
resetCacheControl() {
|
3677
|
-
this.setCacheControl("");
|
3678
|
-
}
|
3679
|
-
exemptPageFromCache() {
|
3680
|
-
this.setCacheControl("no-cache");
|
3681
|
-
}
|
3682
|
-
exemptPageFromPreview() {
|
3683
|
-
this.setCacheControl("no-preview");
|
3684
|
-
}
|
3685
|
-
setCacheControl(value) {
|
3686
|
-
setMetaContent("turbo-cache-control", value);
|
3687
|
-
}
|
3688
|
-
};
|
3689
|
-
var StreamActions = {
|
3690
|
-
after() {
|
3691
|
-
this.targetElements.forEach((e) => {
|
3692
|
-
var _a;
|
3693
|
-
return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling);
|
3694
|
-
});
|
3695
|
-
},
|
3696
|
-
append() {
|
3697
|
-
this.removeDuplicateTargetChildren();
|
3698
|
-
this.targetElements.forEach((e) => e.append(this.templateContent));
|
3699
|
-
},
|
3700
|
-
before() {
|
3701
|
-
this.targetElements.forEach((e) => {
|
3702
|
-
var _a;
|
3703
|
-
return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e);
|
3704
|
-
});
|
3705
|
-
},
|
3706
|
-
prepend() {
|
3707
|
-
this.removeDuplicateTargetChildren();
|
3708
|
-
this.targetElements.forEach((e) => e.prepend(this.templateContent));
|
3709
|
-
},
|
3710
|
-
remove() {
|
3711
|
-
this.targetElements.forEach((e) => e.remove());
|
3712
|
-
},
|
3713
|
-
replace() {
|
3714
|
-
this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
|
3715
|
-
},
|
3716
|
-
update() {
|
3717
|
-
this.targetElements.forEach((targetElement) => {
|
3718
|
-
targetElement.innerHTML = "";
|
3719
|
-
targetElement.append(this.templateContent);
|
3720
|
-
});
|
3721
|
-
}
|
3722
|
-
};
|
3723
|
-
var session = new Session();
|
3724
|
-
var cache = new Cache(session);
|
3725
|
-
var { navigator: navigator$1 } = session;
|
4989
|
+
var session = new Session(recentRequests);
|
4990
|
+
var { cache, navigator: navigator$1 } = session;
|
3726
4991
|
function start() {
|
3727
4992
|
session.start();
|
3728
4993
|
}
|
@@ -3742,7 +5007,9 @@
|
|
3742
5007
|
session.renderStreamMessage(message);
|
3743
5008
|
}
|
3744
5009
|
function clearCache() {
|
3745
|
-
console.warn(
|
5010
|
+
console.warn(
|
5011
|
+
"Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`"
|
5012
|
+
);
|
3746
5013
|
session.clearCache();
|
3747
5014
|
}
|
3748
5015
|
function setProgressBarDelay(delay) {
|
@@ -3754,7 +5021,7 @@
|
|
3754
5021
|
function setFormMode(mode) {
|
3755
5022
|
session.setFormMode(mode);
|
3756
5023
|
}
|
3757
|
-
var
|
5024
|
+
var Turbo2 = /* @__PURE__ */ Object.freeze({
|
3758
5025
|
__proto__: null,
|
3759
5026
|
navigator: navigator$1,
|
3760
5027
|
session,
|
@@ -3762,6 +5029,7 @@
|
|
3762
5029
|
PageRenderer,
|
3763
5030
|
PageSnapshot,
|
3764
5031
|
FrameRenderer,
|
5032
|
+
fetch: fetchWithTurboHeaders,
|
3765
5033
|
start,
|
3766
5034
|
registerAdapter,
|
3767
5035
|
visit,
|
@@ -3771,29 +5039,20 @@
|
|
3771
5039
|
clearCache,
|
3772
5040
|
setProgressBarDelay,
|
3773
5041
|
setConfirmMethod,
|
3774
|
-
setFormMode
|
3775
|
-
StreamActions
|
5042
|
+
setFormMode
|
3776
5043
|
});
|
3777
5044
|
var TurboFrameMissingError = class extends Error {
|
3778
5045
|
};
|
3779
5046
|
var FrameController = class {
|
5047
|
+
fetchResponseLoaded = (_fetchResponse) => Promise.resolve();
|
5048
|
+
#currentFetchRequest = null;
|
5049
|
+
#resolveVisitPromise = () => {
|
5050
|
+
};
|
5051
|
+
#connected = false;
|
5052
|
+
#hasBeenLoaded = false;
|
5053
|
+
#ignoredAttributes = /* @__PURE__ */ new Set();
|
5054
|
+
action = null;
|
3780
5055
|
constructor(element) {
|
3781
|
-
this.fetchResponseLoaded = (_fetchResponse) => {
|
3782
|
-
};
|
3783
|
-
this.currentFetchRequest = null;
|
3784
|
-
this.resolveVisitPromise = () => {
|
3785
|
-
};
|
3786
|
-
this.connected = false;
|
3787
|
-
this.hasBeenLoaded = false;
|
3788
|
-
this.ignoredAttributes = /* @__PURE__ */ new Set();
|
3789
|
-
this.action = null;
|
3790
|
-
this.visitCachedSnapshot = ({ element: element2 }) => {
|
3791
|
-
const frame = element2.querySelector("#" + this.element.id);
|
3792
|
-
if (frame && this.previousFrameElement) {
|
3793
|
-
frame.replaceChildren(...this.previousFrameElement.children);
|
3794
|
-
}
|
3795
|
-
delete this.previousFrameElement;
|
3796
|
-
};
|
3797
5056
|
this.element = element;
|
3798
5057
|
this.view = new FrameView(this, this.element);
|
3799
5058
|
this.appearanceObserver = new AppearanceObserver(this, this.element);
|
@@ -3802,13 +5061,14 @@
|
|
3802
5061
|
this.restorationIdentifier = uuid();
|
3803
5062
|
this.formSubmitObserver = new FormSubmitObserver(this, this.element);
|
3804
5063
|
}
|
5064
|
+
// Frame delegate
|
3805
5065
|
connect() {
|
3806
|
-
if (!this
|
3807
|
-
this
|
5066
|
+
if (!this.#connected) {
|
5067
|
+
this.#connected = true;
|
3808
5068
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
3809
5069
|
this.appearanceObserver.start();
|
3810
5070
|
} else {
|
3811
|
-
this
|
5071
|
+
this.#loadSourceURL();
|
3812
5072
|
}
|
3813
5073
|
this.formLinkClickObserver.start();
|
3814
5074
|
this.linkInterceptor.start();
|
@@ -3816,8 +5076,8 @@
|
|
3816
5076
|
}
|
3817
5077
|
}
|
3818
5078
|
disconnect() {
|
3819
|
-
if (this
|
3820
|
-
this
|
5079
|
+
if (this.#connected) {
|
5080
|
+
this.#connected = false;
|
3821
5081
|
this.appearanceObserver.stop();
|
3822
5082
|
this.formLinkClickObserver.stop();
|
3823
5083
|
this.linkInterceptor.stop();
|
@@ -3826,47 +5086,40 @@
|
|
3826
5086
|
}
|
3827
5087
|
disabledChanged() {
|
3828
5088
|
if (this.loadingStyle == FrameLoadingStyle.eager) {
|
3829
|
-
this
|
5089
|
+
this.#loadSourceURL();
|
3830
5090
|
}
|
3831
5091
|
}
|
3832
5092
|
sourceURLChanged() {
|
3833
|
-
if (this
|
5093
|
+
if (this.#isIgnoringChangesTo("src"))
|
3834
5094
|
return;
|
3835
5095
|
if (this.element.isConnected) {
|
3836
5096
|
this.complete = false;
|
3837
5097
|
}
|
3838
|
-
if (this.loadingStyle == FrameLoadingStyle.eager || this
|
3839
|
-
this
|
5098
|
+
if (this.loadingStyle == FrameLoadingStyle.eager || this.#hasBeenLoaded) {
|
5099
|
+
this.#loadSourceURL();
|
3840
5100
|
}
|
3841
5101
|
}
|
3842
5102
|
sourceURLReloaded() {
|
3843
5103
|
const { src } = this.element;
|
3844
|
-
this.
|
3845
|
-
this.element.removeAttribute("complete");
|
3846
|
-
});
|
5104
|
+
this.element.removeAttribute("complete");
|
3847
5105
|
this.element.src = null;
|
3848
5106
|
this.element.src = src;
|
3849
5107
|
return this.element.loaded;
|
3850
5108
|
}
|
3851
|
-
completeChanged() {
|
3852
|
-
if (this.isIgnoringChangesTo("complete"))
|
3853
|
-
return;
|
3854
|
-
this.loadSourceURL();
|
3855
|
-
}
|
3856
5109
|
loadingStyleChanged() {
|
3857
5110
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
3858
5111
|
this.appearanceObserver.start();
|
3859
5112
|
} else {
|
3860
5113
|
this.appearanceObserver.stop();
|
3861
|
-
this
|
5114
|
+
this.#loadSourceURL();
|
3862
5115
|
}
|
3863
5116
|
}
|
3864
|
-
async loadSourceURL() {
|
5117
|
+
async #loadSourceURL() {
|
3865
5118
|
if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
|
3866
|
-
this.element.loaded = this
|
5119
|
+
this.element.loaded = this.#visit(expandURL(this.sourceURL));
|
3867
5120
|
this.appearanceObserver.stop();
|
3868
5121
|
await this.element.loaded;
|
3869
|
-
this
|
5122
|
+
this.#hasBeenLoaded = true;
|
3870
5123
|
}
|
3871
5124
|
}
|
3872
5125
|
async loadResponse(fetchResponse) {
|
@@ -3879,36 +5132,39 @@
|
|
3879
5132
|
const document2 = parseHTMLDocument(html);
|
3880
5133
|
const pageSnapshot = PageSnapshot.fromDocument(document2);
|
3881
5134
|
if (pageSnapshot.isVisitable) {
|
3882
|
-
await this
|
5135
|
+
await this.#loadFrameResponse(fetchResponse, document2);
|
3883
5136
|
} else {
|
3884
|
-
await this
|
5137
|
+
await this.#handleUnvisitableFrameResponse(fetchResponse);
|
3885
5138
|
}
|
3886
5139
|
}
|
3887
5140
|
} finally {
|
3888
|
-
this.fetchResponseLoaded = () =>
|
3889
|
-
};
|
5141
|
+
this.fetchResponseLoaded = () => Promise.resolve();
|
3890
5142
|
}
|
3891
5143
|
}
|
5144
|
+
// Appearance observer delegate
|
3892
5145
|
elementAppearedInViewport(element) {
|
3893
|
-
this.proposeVisitIfNavigatedWithAction(element, element);
|
3894
|
-
this
|
5146
|
+
this.proposeVisitIfNavigatedWithAction(element, getVisitAction(element));
|
5147
|
+
this.#loadSourceURL();
|
3895
5148
|
}
|
5149
|
+
// Form link click observer delegate
|
3896
5150
|
willSubmitFormLinkToLocation(link) {
|
3897
|
-
return this
|
5151
|
+
return this.#shouldInterceptNavigation(link);
|
3898
5152
|
}
|
3899
5153
|
submittedFormLinkToLocation(link, _location, form) {
|
3900
|
-
const frame = this
|
5154
|
+
const frame = this.#findFrameElement(link);
|
3901
5155
|
if (frame)
|
3902
5156
|
form.setAttribute("data-turbo-frame", frame.id);
|
3903
5157
|
}
|
5158
|
+
// Link interceptor delegate
|
3904
5159
|
shouldInterceptLinkClick(element, _location, _event) {
|
3905
|
-
return this
|
5160
|
+
return this.#shouldInterceptNavigation(element);
|
3906
5161
|
}
|
3907
5162
|
linkClickIntercepted(element, location2) {
|
3908
|
-
this
|
5163
|
+
this.#navigateFrame(element, location2);
|
3909
5164
|
}
|
5165
|
+
// Form submit observer delegate
|
3910
5166
|
willSubmitForm(element, submitter) {
|
3911
|
-
return element.closest("turbo-frame") == this.element && this
|
5167
|
+
return element.closest("turbo-frame") == this.element && this.#shouldInterceptNavigation(element, submitter);
|
3912
5168
|
}
|
3913
5169
|
formSubmitted(element, submitter) {
|
3914
5170
|
if (this.formSubmission) {
|
@@ -3919,10 +5175,10 @@
|
|
3919
5175
|
this.prepareRequest(fetchRequest);
|
3920
5176
|
this.formSubmission.start();
|
3921
5177
|
}
|
5178
|
+
// Fetch request delegate
|
3922
5179
|
prepareRequest(request) {
|
3923
|
-
var _a;
|
3924
5180
|
request.headers["Turbo-Frame"] = this.id;
|
3925
|
-
if (
|
5181
|
+
if (this.currentNavigationElement?.hasAttribute("data-turbo-stream")) {
|
3926
5182
|
request.acceptResponseType(StreamMessage.contentType);
|
3927
5183
|
}
|
3928
5184
|
}
|
@@ -3930,29 +5186,30 @@
|
|
3930
5186
|
markAsBusy(this.element);
|
3931
5187
|
}
|
3932
5188
|
requestPreventedHandlingResponse(_request, _response) {
|
3933
|
-
this
|
5189
|
+
this.#resolveVisitPromise();
|
3934
5190
|
}
|
3935
5191
|
async requestSucceededWithResponse(request, response) {
|
3936
5192
|
await this.loadResponse(response);
|
3937
|
-
this
|
5193
|
+
this.#resolveVisitPromise();
|
3938
5194
|
}
|
3939
5195
|
async requestFailedWithResponse(request, response) {
|
3940
5196
|
await this.loadResponse(response);
|
3941
|
-
this
|
5197
|
+
this.#resolveVisitPromise();
|
3942
5198
|
}
|
3943
5199
|
requestErrored(request, error2) {
|
3944
5200
|
console.error(error2);
|
3945
|
-
this
|
5201
|
+
this.#resolveVisitPromise();
|
3946
5202
|
}
|
3947
5203
|
requestFinished(_request) {
|
3948
5204
|
clearBusyState(this.element);
|
3949
5205
|
}
|
5206
|
+
// Form submission delegate
|
3950
5207
|
formSubmissionStarted({ formElement }) {
|
3951
|
-
markAsBusy(formElement, this
|
5208
|
+
markAsBusy(formElement, this.#findFrameElement(formElement));
|
3952
5209
|
}
|
3953
5210
|
formSubmissionSucceededWithResponse(formSubmission, response) {
|
3954
|
-
const frame = this
|
3955
|
-
frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.
|
5211
|
+
const frame = this.#findFrameElement(formSubmission.formElement, formSubmission.submitter);
|
5212
|
+
frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(formSubmission.submitter, formSubmission.formElement, frame));
|
3956
5213
|
frame.delegate.loadResponse(response);
|
3957
5214
|
if (!formSubmission.isSafe) {
|
3958
5215
|
session.clearCache();
|
@@ -3966,31 +5223,44 @@
|
|
3966
5223
|
console.error(error2);
|
3967
5224
|
}
|
3968
5225
|
formSubmissionFinished({ formElement }) {
|
3969
|
-
clearBusyState(formElement, this
|
5226
|
+
clearBusyState(formElement, this.#findFrameElement(formElement));
|
3970
5227
|
}
|
5228
|
+
// View delegate
|
3971
5229
|
allowsImmediateRender({ element: newFrame }, options) {
|
3972
5230
|
const event = dispatch("turbo:before-frame-render", {
|
3973
5231
|
target: this.element,
|
3974
|
-
detail:
|
5232
|
+
detail: { newFrame, ...options },
|
3975
5233
|
cancelable: true
|
3976
5234
|
});
|
3977
|
-
const {
|
5235
|
+
const {
|
5236
|
+
defaultPrevented,
|
5237
|
+
detail: { render }
|
5238
|
+
} = event;
|
3978
5239
|
if (this.view.renderer && render) {
|
3979
5240
|
this.view.renderer.renderElement = render;
|
3980
5241
|
}
|
3981
5242
|
return !defaultPrevented;
|
3982
5243
|
}
|
3983
|
-
viewRenderedSnapshot(_snapshot, _isPreview) {
|
5244
|
+
viewRenderedSnapshot(_snapshot, _isPreview, _renderMethod) {
|
3984
5245
|
}
|
3985
5246
|
preloadOnLoadLinksForView(element) {
|
3986
5247
|
session.preloadOnLoadLinksForView(element);
|
3987
5248
|
}
|
3988
5249
|
viewInvalidated() {
|
3989
5250
|
}
|
5251
|
+
// Frame renderer delegate
|
3990
5252
|
willRenderFrame(currentElement, _newElement) {
|
3991
5253
|
this.previousFrameElement = currentElement.cloneNode(true);
|
3992
5254
|
}
|
3993
|
-
|
5255
|
+
visitCachedSnapshot = ({ element }) => {
|
5256
|
+
const frame = element.querySelector("#" + this.element.id);
|
5257
|
+
if (frame && this.previousFrameElement) {
|
5258
|
+
frame.replaceChildren(...this.previousFrameElement.children);
|
5259
|
+
}
|
5260
|
+
delete this.previousFrameElement;
|
5261
|
+
};
|
5262
|
+
// Private
|
5263
|
+
async #loadFrameResponse(fetchResponse, document2) {
|
3994
5264
|
const newFrameElement = await this.extractForeignFrameElement(document2.body);
|
3995
5265
|
if (newFrameElement) {
|
3996
5266
|
const snapshot = new Snapshot(newFrameElement);
|
@@ -4002,42 +5272,41 @@
|
|
4002
5272
|
this.complete = true;
|
4003
5273
|
session.frameRendered(fetchResponse, this.element);
|
4004
5274
|
session.frameLoaded(this.element);
|
4005
|
-
this.fetchResponseLoaded(fetchResponse);
|
4006
|
-
} else if (this
|
4007
|
-
this
|
5275
|
+
await this.fetchResponseLoaded(fetchResponse);
|
5276
|
+
} else if (this.#willHandleFrameMissingFromResponse(fetchResponse)) {
|
5277
|
+
this.#handleFrameMissingFromResponse(fetchResponse);
|
4008
5278
|
}
|
4009
5279
|
}
|
4010
|
-
async visit(url) {
|
4011
|
-
var _a;
|
5280
|
+
async #visit(url) {
|
4012
5281
|
const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
|
4013
|
-
|
4014
|
-
this
|
5282
|
+
this.#currentFetchRequest?.cancel();
|
5283
|
+
this.#currentFetchRequest = request;
|
4015
5284
|
return new Promise((resolve) => {
|
4016
|
-
this
|
4017
|
-
this
|
5285
|
+
this.#resolveVisitPromise = () => {
|
5286
|
+
this.#resolveVisitPromise = () => {
|
4018
5287
|
};
|
4019
|
-
this
|
5288
|
+
this.#currentFetchRequest = null;
|
4020
5289
|
resolve();
|
4021
5290
|
};
|
4022
5291
|
request.perform();
|
4023
5292
|
});
|
4024
5293
|
}
|
4025
|
-
navigateFrame(element, url, submitter) {
|
4026
|
-
const frame = this
|
4027
|
-
frame.delegate.proposeVisitIfNavigatedWithAction(frame, element,
|
4028
|
-
this
|
5294
|
+
#navigateFrame(element, url, submitter) {
|
5295
|
+
const frame = this.#findFrameElement(element, submitter);
|
5296
|
+
frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(submitter, element, frame));
|
5297
|
+
this.#withCurrentNavigationElement(element, () => {
|
4029
5298
|
frame.src = url;
|
4030
5299
|
});
|
4031
5300
|
}
|
4032
|
-
proposeVisitIfNavigatedWithAction(frame,
|
4033
|
-
this.action =
|
5301
|
+
proposeVisitIfNavigatedWithAction(frame, action = null) {
|
5302
|
+
this.action = action;
|
4034
5303
|
if (this.action) {
|
4035
5304
|
const pageSnapshot = PageSnapshot.fromElement(frame).clone();
|
4036
5305
|
const { visitCachedSnapshot } = frame.delegate;
|
4037
|
-
frame.delegate.fetchResponseLoaded = (fetchResponse) => {
|
5306
|
+
frame.delegate.fetchResponseLoaded = async (fetchResponse) => {
|
4038
5307
|
if (frame.src) {
|
4039
5308
|
const { statusCode, redirected } = fetchResponse;
|
4040
|
-
const responseHTML =
|
5309
|
+
const responseHTML = await fetchResponse.responseHTML;
|
4041
5310
|
const response = { statusCode, redirected, responseHTML };
|
4042
5311
|
const options = {
|
4043
5312
|
response,
|
@@ -4060,16 +5329,18 @@
|
|
4060
5329
|
session.history.update(method, expandURL(this.element.src || ""), this.restorationIdentifier);
|
4061
5330
|
}
|
4062
5331
|
}
|
4063
|
-
async handleUnvisitableFrameResponse(fetchResponse) {
|
4064
|
-
console.warn(
|
4065
|
-
|
5332
|
+
async #handleUnvisitableFrameResponse(fetchResponse) {
|
5333
|
+
console.warn(
|
5334
|
+
`The response (${fetchResponse.statusCode}) from <turbo-frame id="${this.element.id}"> is performing a full page visit due to turbo-visit-control.`
|
5335
|
+
);
|
5336
|
+
await this.#visitResponse(fetchResponse.response);
|
4066
5337
|
}
|
4067
|
-
willHandleFrameMissingFromResponse(fetchResponse) {
|
5338
|
+
#willHandleFrameMissingFromResponse(fetchResponse) {
|
4068
5339
|
this.element.setAttribute("complete", "");
|
4069
5340
|
const response = fetchResponse.response;
|
4070
|
-
const visit2 = async (url, options
|
5341
|
+
const visit2 = async (url, options) => {
|
4071
5342
|
if (url instanceof Response) {
|
4072
|
-
this
|
5343
|
+
this.#visitResponse(url);
|
4073
5344
|
} else {
|
4074
5345
|
session.visit(url, options);
|
4075
5346
|
}
|
@@ -4081,24 +5352,23 @@
|
|
4081
5352
|
});
|
4082
5353
|
return !event.defaultPrevented;
|
4083
5354
|
}
|
4084
|
-
handleFrameMissingFromResponse(fetchResponse) {
|
5355
|
+
#handleFrameMissingFromResponse(fetchResponse) {
|
4085
5356
|
this.view.missing();
|
4086
|
-
this
|
5357
|
+
this.#throwFrameMissingError(fetchResponse);
|
4087
5358
|
}
|
4088
|
-
throwFrameMissingError(fetchResponse) {
|
5359
|
+
#throwFrameMissingError(fetchResponse) {
|
4089
5360
|
const message = `The response (${fetchResponse.statusCode}) did not contain the expected <turbo-frame id="${this.element.id}"> and will be ignored. To perform a full page visit instead, set turbo-visit-control to reload.`;
|
4090
5361
|
throw new TurboFrameMissingError(message);
|
4091
5362
|
}
|
4092
|
-
async visitResponse(response) {
|
5363
|
+
async #visitResponse(response) {
|
4093
5364
|
const wrapped = new FetchResponse(response);
|
4094
5365
|
const responseHTML = await wrapped.responseHTML;
|
4095
5366
|
const { location: location2, redirected, statusCode } = wrapped;
|
4096
5367
|
return session.visit(location2, { response: { redirected, statusCode, responseHTML } });
|
4097
5368
|
}
|
4098
|
-
findFrameElement(element, submitter) {
|
4099
|
-
var _a;
|
5369
|
+
#findFrameElement(element, submitter) {
|
4100
5370
|
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
4101
|
-
return
|
5371
|
+
return getFrameElementById(id) ?? this.element;
|
4102
5372
|
}
|
4103
5373
|
async extractForeignFrameElement(container) {
|
4104
5374
|
let element;
|
@@ -4119,13 +5389,13 @@
|
|
4119
5389
|
}
|
4120
5390
|
return null;
|
4121
5391
|
}
|
4122
|
-
formActionIsVisitable(form, submitter) {
|
4123
|
-
const action = getAction(form, submitter);
|
5392
|
+
#formActionIsVisitable(form, submitter) {
|
5393
|
+
const action = getAction$1(form, submitter);
|
4124
5394
|
return locationIsVisitable(expandURL(action), this.rootLocation);
|
4125
5395
|
}
|
4126
|
-
shouldInterceptNavigation(element, submitter) {
|
5396
|
+
#shouldInterceptNavigation(element, submitter) {
|
4127
5397
|
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
4128
|
-
if (element instanceof HTMLFormElement && !this
|
5398
|
+
if (element instanceof HTMLFormElement && !this.#formActionIsVisitable(element, submitter)) {
|
4129
5399
|
return false;
|
4130
5400
|
}
|
4131
5401
|
if (!this.enabled || id == "_top") {
|
@@ -4145,6 +5415,7 @@
|
|
4145
5415
|
}
|
4146
5416
|
return true;
|
4147
5417
|
}
|
5418
|
+
// Computed properties
|
4148
5419
|
get id() {
|
4149
5420
|
return this.element.id;
|
4150
5421
|
}
|
@@ -4157,46 +5428,43 @@
|
|
4157
5428
|
}
|
4158
5429
|
}
|
4159
5430
|
set sourceURL(sourceURL) {
|
4160
|
-
this
|
4161
|
-
this.element.src = sourceURL
|
5431
|
+
this.#ignoringChangesToAttribute("src", () => {
|
5432
|
+
this.element.src = sourceURL ?? null;
|
4162
5433
|
});
|
4163
5434
|
}
|
4164
5435
|
get loadingStyle() {
|
4165
5436
|
return this.element.loading;
|
4166
5437
|
}
|
4167
5438
|
get isLoading() {
|
4168
|
-
return this.formSubmission !== void 0 || this
|
5439
|
+
return this.formSubmission !== void 0 || this.#resolveVisitPromise() !== void 0;
|
4169
5440
|
}
|
4170
5441
|
get complete() {
|
4171
5442
|
return this.element.hasAttribute("complete");
|
4172
5443
|
}
|
4173
5444
|
set complete(value) {
|
4174
|
-
|
4175
|
-
|
4176
|
-
|
4177
|
-
|
4178
|
-
|
4179
|
-
}
|
4180
|
-
});
|
5445
|
+
if (value) {
|
5446
|
+
this.element.setAttribute("complete", "");
|
5447
|
+
} else {
|
5448
|
+
this.element.removeAttribute("complete");
|
5449
|
+
}
|
4181
5450
|
}
|
4182
5451
|
get isActive() {
|
4183
|
-
return this.element.isActive && this
|
5452
|
+
return this.element.isActive && this.#connected;
|
4184
5453
|
}
|
4185
5454
|
get rootLocation() {
|
4186
|
-
var _a;
|
4187
5455
|
const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
4188
|
-
const root =
|
5456
|
+
const root = meta?.content ?? "/";
|
4189
5457
|
return expandURL(root);
|
4190
5458
|
}
|
4191
|
-
isIgnoringChangesTo(attributeName) {
|
4192
|
-
return this
|
5459
|
+
#isIgnoringChangesTo(attributeName) {
|
5460
|
+
return this.#ignoredAttributes.has(attributeName);
|
4193
5461
|
}
|
4194
|
-
ignoringChangesToAttribute(attributeName, callback) {
|
4195
|
-
this
|
5462
|
+
#ignoringChangesToAttribute(attributeName, callback) {
|
5463
|
+
this.#ignoredAttributes.add(attributeName);
|
4196
5464
|
callback();
|
4197
|
-
this
|
5465
|
+
this.#ignoredAttributes.delete(attributeName);
|
4198
5466
|
}
|
4199
|
-
withCurrentNavigationElement(element, callback) {
|
5467
|
+
#withCurrentNavigationElement(element, callback) {
|
4200
5468
|
this.currentNavigationElement = element;
|
4201
5469
|
callback();
|
4202
5470
|
delete this.currentNavigationElement;
|
@@ -4226,6 +5494,37 @@
|
|
4226
5494
|
}
|
4227
5495
|
}
|
4228
5496
|
}
|
5497
|
+
var StreamActions = {
|
5498
|
+
after() {
|
5499
|
+
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e.nextSibling));
|
5500
|
+
},
|
5501
|
+
append() {
|
5502
|
+
this.removeDuplicateTargetChildren();
|
5503
|
+
this.targetElements.forEach((e) => e.append(this.templateContent));
|
5504
|
+
},
|
5505
|
+
before() {
|
5506
|
+
this.targetElements.forEach((e) => e.parentElement?.insertBefore(this.templateContent, e));
|
5507
|
+
},
|
5508
|
+
prepend() {
|
5509
|
+
this.removeDuplicateTargetChildren();
|
5510
|
+
this.targetElements.forEach((e) => e.prepend(this.templateContent));
|
5511
|
+
},
|
5512
|
+
remove() {
|
5513
|
+
this.targetElements.forEach((e) => e.remove());
|
5514
|
+
},
|
5515
|
+
replace() {
|
5516
|
+
this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
|
5517
|
+
},
|
5518
|
+
update() {
|
5519
|
+
this.targetElements.forEach((targetElement) => {
|
5520
|
+
targetElement.innerHTML = "";
|
5521
|
+
targetElement.append(this.templateContent);
|
5522
|
+
});
|
5523
|
+
},
|
5524
|
+
refresh() {
|
5525
|
+
session.refresh(this.baseURI, this.requestId);
|
5526
|
+
}
|
5527
|
+
};
|
4229
5528
|
var StreamElement = class _StreamElement extends HTMLElement {
|
4230
5529
|
static async renderElement(newElement) {
|
4231
5530
|
await newElement.performAction();
|
@@ -4240,11 +5539,10 @@
|
|
4240
5539
|
}
|
4241
5540
|
}
|
4242
5541
|
async render() {
|
4243
|
-
|
4244
|
-
return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : this.renderPromise = (async () => {
|
5542
|
+
return this.renderPromise ??= (async () => {
|
4245
5543
|
const event = this.beforeRenderEvent;
|
4246
5544
|
if (this.dispatchEvent(event)) {
|
4247
|
-
await
|
5545
|
+
await nextRepaint();
|
4248
5546
|
await event.detail.render(this);
|
4249
5547
|
}
|
4250
5548
|
})();
|
@@ -4252,40 +5550,57 @@
|
|
4252
5550
|
disconnect() {
|
4253
5551
|
try {
|
4254
5552
|
this.remove();
|
4255
|
-
} catch
|
5553
|
+
} catch {
|
4256
5554
|
}
|
4257
5555
|
}
|
5556
|
+
/**
|
5557
|
+
* Removes duplicate children (by ID)
|
5558
|
+
*/
|
4258
5559
|
removeDuplicateTargetChildren() {
|
4259
5560
|
this.duplicateChildren.forEach((c) => c.remove());
|
4260
5561
|
}
|
5562
|
+
/**
|
5563
|
+
* Gets the list of duplicate children (i.e. those with the same ID)
|
5564
|
+
*/
|
4261
5565
|
get duplicateChildren() {
|
4262
|
-
var _a;
|
4263
5566
|
const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);
|
4264
|
-
const newChildrenIds = [...
|
5567
|
+
const newChildrenIds = [...this.templateContent?.children || []].filter((c) => !!c.id).map((c) => c.id);
|
4265
5568
|
return existingChildren.filter((c) => newChildrenIds.includes(c.id));
|
4266
5569
|
}
|
5570
|
+
/**
|
5571
|
+
* Gets the action function to be performed.
|
5572
|
+
*/
|
4267
5573
|
get performAction() {
|
4268
5574
|
if (this.action) {
|
4269
5575
|
const actionFunction = StreamActions[this.action];
|
4270
5576
|
if (actionFunction) {
|
4271
5577
|
return actionFunction;
|
4272
5578
|
}
|
4273
|
-
this
|
5579
|
+
this.#raise("unknown action");
|
4274
5580
|
}
|
4275
|
-
this
|
5581
|
+
this.#raise("action attribute is missing");
|
4276
5582
|
}
|
5583
|
+
/**
|
5584
|
+
* Gets the target elements which the template will be rendered to.
|
5585
|
+
*/
|
4277
5586
|
get targetElements() {
|
4278
5587
|
if (this.target) {
|
4279
5588
|
return this.targetElementsById;
|
4280
5589
|
} else if (this.targets) {
|
4281
5590
|
return this.targetElementsByQuery;
|
4282
5591
|
} else {
|
4283
|
-
this
|
5592
|
+
this.#raise("target or targets attribute is missing");
|
4284
5593
|
}
|
4285
5594
|
}
|
5595
|
+
/**
|
5596
|
+
* Gets the contents of the main `<template>`.
|
5597
|
+
*/
|
4286
5598
|
get templateContent() {
|
4287
5599
|
return this.templateElement.content.cloneNode(true);
|
4288
5600
|
}
|
5601
|
+
/**
|
5602
|
+
* Gets the main `<template>` used for rendering
|
5603
|
+
*/
|
4289
5604
|
get templateElement() {
|
4290
5605
|
if (this.firstElementChild === null) {
|
4291
5606
|
const template = this.ownerDocument.createElement("template");
|
@@ -4294,23 +5609,38 @@
|
|
4294
5609
|
} else if (this.firstElementChild instanceof HTMLTemplateElement) {
|
4295
5610
|
return this.firstElementChild;
|
4296
5611
|
}
|
4297
|
-
this
|
5612
|
+
this.#raise("first child element must be a <template> element");
|
4298
5613
|
}
|
5614
|
+
/**
|
5615
|
+
* Gets the current action.
|
5616
|
+
*/
|
4299
5617
|
get action() {
|
4300
5618
|
return this.getAttribute("action");
|
4301
5619
|
}
|
5620
|
+
/**
|
5621
|
+
* Gets the current target (an element ID) to which the result will
|
5622
|
+
* be rendered.
|
5623
|
+
*/
|
4302
5624
|
get target() {
|
4303
5625
|
return this.getAttribute("target");
|
4304
5626
|
}
|
5627
|
+
/**
|
5628
|
+
* Gets the current "targets" selector (a CSS selector)
|
5629
|
+
*/
|
4305
5630
|
get targets() {
|
4306
5631
|
return this.getAttribute("targets");
|
4307
5632
|
}
|
4308
|
-
|
5633
|
+
/**
|
5634
|
+
* Reads the request-id attribute
|
5635
|
+
*/
|
5636
|
+
get requestId() {
|
5637
|
+
return this.getAttribute("request-id");
|
5638
|
+
}
|
5639
|
+
#raise(message) {
|
4309
5640
|
throw new Error(`${this.description}: ${message}`);
|
4310
5641
|
}
|
4311
5642
|
get description() {
|
4312
|
-
|
4313
|
-
return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
|
5643
|
+
return (this.outerHTML.match(/<[^>]+>/) ?? [])[0] ?? "<turbo-stream>";
|
4314
5644
|
}
|
4315
5645
|
get beforeRenderEvent() {
|
4316
5646
|
return new CustomEvent("turbo:before-stream-render", {
|
@@ -4320,8 +5650,7 @@
|
|
4320
5650
|
});
|
4321
5651
|
}
|
4322
5652
|
get targetElementsById() {
|
4323
|
-
|
4324
|
-
const element = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.getElementById(this.target);
|
5653
|
+
const element = this.ownerDocument?.getElementById(this.target);
|
4325
5654
|
if (element !== null) {
|
4326
5655
|
return [element];
|
4327
5656
|
} else {
|
@@ -4329,8 +5658,7 @@
|
|
4329
5658
|
}
|
4330
5659
|
}
|
4331
5660
|
get targetElementsByQuery() {
|
4332
|
-
|
4333
|
-
const elements = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.querySelectorAll(this.targets);
|
5661
|
+
const elements = this.ownerDocument?.querySelectorAll(this.targets);
|
4334
5662
|
if (elements.length !== 0) {
|
4335
5663
|
return Array.prototype.slice.call(elements);
|
4336
5664
|
} else {
|
@@ -4339,16 +5667,14 @@
|
|
4339
5667
|
}
|
4340
5668
|
};
|
4341
5669
|
var StreamSourceElement = class extends HTMLElement {
|
4342
|
-
|
4343
|
-
super(...arguments);
|
4344
|
-
this.streamSource = null;
|
4345
|
-
}
|
5670
|
+
streamSource = null;
|
4346
5671
|
connectedCallback() {
|
4347
5672
|
this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
|
4348
5673
|
connectStreamSource(this.streamSource);
|
4349
5674
|
}
|
4350
5675
|
disconnectedCallback() {
|
4351
5676
|
if (this.streamSource) {
|
5677
|
+
this.streamSource.close();
|
4352
5678
|
disconnectStreamSource(this.streamSource);
|
4353
5679
|
}
|
4354
5680
|
}
|
@@ -4375,7 +5701,8 @@
|
|
4375
5701
|
element = element.parentElement;
|
4376
5702
|
while (element) {
|
4377
5703
|
if (element == document.body) {
|
4378
|
-
return console.warn(
|
5704
|
+
return console.warn(
|
5705
|
+
unindent`
|
4379
5706
|
You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
|
4380
5707
|
|
4381
5708
|
Load your application’s JavaScript bundle inside the <head> element instead. <script> elements in <body> are evaluated with each page change.
|
@@ -4384,12 +5711,14 @@
|
|
4384
5711
|
|
4385
5712
|
——
|
4386
5713
|
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
4387
|
-
`,
|
5714
|
+
`,
|
5715
|
+
element.outerHTML
|
5716
|
+
);
|
4388
5717
|
}
|
4389
5718
|
element = element.parentElement;
|
4390
5719
|
}
|
4391
5720
|
})();
|
4392
|
-
window.Turbo =
|
5721
|
+
window.Turbo = { ...Turbo2, StreamActions };
|
4393
5722
|
start();
|
4394
5723
|
|
4395
5724
|
// node_modules/@hotwired/turbo-rails/app/javascript/turbo/cable.js
|
@@ -4493,7 +5822,9 @@
|
|
4493
5822
|
}
|
4494
5823
|
function determineFormMethod(submitter) {
|
4495
5824
|
if (submitter instanceof HTMLButtonElement || submitter instanceof HTMLInputElement) {
|
4496
|
-
if (submitter.
|
5825
|
+
if (submitter.name === "_method") {
|
5826
|
+
return submitter.value;
|
5827
|
+
} else if (submitter.hasAttribute("formmethod")) {
|
4497
5828
|
return submitter.formMethod;
|
4498
5829
|
} else {
|
4499
5830
|
return null;
|
@@ -4507,6 +5838,7 @@
|
|
4507
5838
|
}
|
4508
5839
|
|
4509
5840
|
// node_modules/@hotwired/turbo-rails/app/javascript/turbo/index.js
|
5841
|
+
window.Turbo = turbo_es2017_esm_exports;
|
4510
5842
|
addEventListener("turbo:before-fetch-request", encodeMethodIntoRequestBody);
|
4511
5843
|
|
4512
5844
|
// node_modules/@hotwired/stimulus/dist/stimulus.js
|
@@ -5093,13 +6425,13 @@
|
|
5093
6425
|
}
|
5094
6426
|
};
|
5095
6427
|
function add(map, key, value) {
|
5096
|
-
|
6428
|
+
fetch(map, key).add(value);
|
5097
6429
|
}
|
5098
6430
|
function del(map, key, value) {
|
5099
|
-
|
6431
|
+
fetch(map, key).delete(value);
|
5100
6432
|
prune(map, key);
|
5101
6433
|
}
|
5102
|
-
function
|
6434
|
+
function fetch(map, key) {
|
5103
6435
|
let values = map.get(key);
|
5104
6436
|
if (!values) {
|
5105
6437
|
values = /* @__PURE__ */ new Set();
|
@@ -6959,9 +8291,79 @@
|
|
6959
8291
|
|
6960
8292
|
// app/assets/javascripts/controllers/application.js
|
6961
8293
|
var application = Application.start();
|
6962
|
-
application.debug =
|
8294
|
+
application.debug = true;
|
6963
8295
|
window.Stimulus = application;
|
6964
8296
|
|
8297
|
+
// node_modules/@stimulus-components/password-visibility/dist/stimulus-password-visibility.mjs
|
8298
|
+
var _PasswordVisibility = class _PasswordVisibility2 extends Controller {
|
8299
|
+
connect() {
|
8300
|
+
this.hidden = this.inputTarget.type === "password", this.class = this.hasHiddenClass ? this.hiddenClass : "hidden";
|
8301
|
+
}
|
8302
|
+
toggle(e) {
|
8303
|
+
e.preventDefault(), this.inputTarget.type = this.hidden ? "text" : "password", this.hidden = !this.hidden, this.iconTargets.forEach((icon) => icon.classList.toggle(this.class));
|
8304
|
+
}
|
8305
|
+
};
|
8306
|
+
_PasswordVisibility.targets = ["input", "icon"], _PasswordVisibility.classes = ["hidden"];
|
8307
|
+
var PasswordVisibility = _PasswordVisibility;
|
8308
|
+
|
8309
|
+
// node_modules/@stimulus-components/reveal/dist/stimulus-reveal-controller.mjs
|
8310
|
+
var _Reveal = class _Reveal2 extends Controller {
|
8311
|
+
connect() {
|
8312
|
+
this.class = this.hasHiddenClass ? this.hiddenClass : "hidden";
|
8313
|
+
}
|
8314
|
+
toggle() {
|
8315
|
+
this.itemTargets.forEach((item) => {
|
8316
|
+
item.classList.toggle(this.class);
|
8317
|
+
});
|
8318
|
+
}
|
8319
|
+
show() {
|
8320
|
+
this.itemTargets.forEach((item) => {
|
8321
|
+
item.classList.remove(this.class);
|
8322
|
+
});
|
8323
|
+
}
|
8324
|
+
hide() {
|
8325
|
+
this.itemTargets.forEach((item) => {
|
8326
|
+
item.classList.add(this.class);
|
8327
|
+
});
|
8328
|
+
}
|
8329
|
+
};
|
8330
|
+
_Reveal.targets = ["item"], _Reveal.classes = ["hidden"];
|
8331
|
+
var Reveal = _Reveal;
|
8332
|
+
|
8333
|
+
// node_modules/@stimulus-components/dialog/dist/stimulus-dialog.mjs
|
8334
|
+
var _Dialog = class _Dialog2 extends Controller {
|
8335
|
+
initialize() {
|
8336
|
+
this.forceClose = this.forceClose.bind(this);
|
8337
|
+
}
|
8338
|
+
connect() {
|
8339
|
+
this.openValue && this.open(), document.addEventListener("turbo:before-render", this.forceClose);
|
8340
|
+
}
|
8341
|
+
disconnect() {
|
8342
|
+
document.removeEventListener("turbo:before-render", this.forceClose);
|
8343
|
+
}
|
8344
|
+
open() {
|
8345
|
+
this.dialogTarget.showModal();
|
8346
|
+
}
|
8347
|
+
close() {
|
8348
|
+
this.dialogTarget.setAttribute("closing", ""), Promise.all(this.dialogTarget.getAnimations().map((animation) => animation.finished)).then(() => {
|
8349
|
+
this.dialogTarget.removeAttribute("closing"), this.dialogTarget.close();
|
8350
|
+
});
|
8351
|
+
}
|
8352
|
+
backdropClose(event) {
|
8353
|
+
event.target === this.dialogTarget && this.close();
|
8354
|
+
}
|
8355
|
+
forceClose() {
|
8356
|
+
this.dialogTarget.close();
|
8357
|
+
}
|
8358
|
+
};
|
8359
|
+
_Dialog.targets = ["dialog"], _Dialog.values = {
|
8360
|
+
open: {
|
8361
|
+
type: Boolean,
|
8362
|
+
default: false
|
8363
|
+
}
|
8364
|
+
};
|
8365
|
+
var Dialog = _Dialog;
|
8366
|
+
|
6965
8367
|
// app/assets/javascripts/controllers/session_controller.js
|
6966
8368
|
var session_controller_default = class extends Controller {
|
6967
8369
|
static get targets() {
|
@@ -7112,11 +8514,36 @@
|
|
7112
8514
|
}
|
7113
8515
|
};
|
7114
8516
|
|
8517
|
+
// app/assets/javascripts/controllers/table_controller.js
|
8518
|
+
var table_controller_default = class extends Controller {
|
8519
|
+
static get targets() {
|
8520
|
+
return ["url"];
|
8521
|
+
}
|
8522
|
+
get href() {
|
8523
|
+
return this.urlTarget.href;
|
8524
|
+
}
|
8525
|
+
click(e) {
|
8526
|
+
Turbo.visit(this.href);
|
8527
|
+
}
|
8528
|
+
};
|
8529
|
+
|
7115
8530
|
// app/assets/javascripts/controllers/index.js
|
7116
8531
|
application.register("session", session_controller_default);
|
7117
8532
|
application.register("recover", recover_controller_default);
|
7118
8533
|
application.register("recover-password", recover_password_controller_default);
|
7119
8534
|
application.register("emails", emails_controller_default);
|
7120
8535
|
application.register("keys", keys_controller_default);
|
8536
|
+
application.register("table", table_controller_default);
|
8537
|
+
application.register("password-visibility", PasswordVisibility);
|
8538
|
+
application.register("reveal", Reveal);
|
8539
|
+
application.register("dialog", Dialog);
|
7121
8540
|
})();
|
8541
|
+
/*! Bundled license information:
|
8542
|
+
|
8543
|
+
@hotwired/turbo/dist/turbo.es2017-esm.js:
|
8544
|
+
(*!
|
8545
|
+
Turbo 8.0.4
|
8546
|
+
Copyright © 2024 37signals LLC
|
8547
|
+
*)
|
8548
|
+
*/
|
7122
8549
|
//# sourceMappingURL=application.js.map
|