turbo-rails 1.5.0 → 2.0.0.pre.beta.1

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.
@@ -1,19 +1,7 @@
1
- (function() {
2
- if (window.Reflect === undefined || window.customElements === undefined || window.customElements.polyfillWrapFlushCallback) {
3
- return;
4
- }
5
- const BuiltInHTMLElement = HTMLElement;
6
- const wrapperForTheName = {
7
- HTMLElement: function HTMLElement() {
8
- return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
9
- }
10
- };
11
- window.HTMLElement = wrapperForTheName["HTMLElement"];
12
- HTMLElement.prototype = BuiltInHTMLElement.prototype;
13
- HTMLElement.prototype.constructor = HTMLElement;
14
- Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
15
- })();
16
-
1
+ /*!
2
+ Turbo 8.0.0-beta.1
3
+ Copyright © 2023 37signals LLC
4
+ */
17
5
  (function(prototype) {
18
6
  if (typeof prototype.requestSubmit == "function") return;
19
7
  prototype.requestSubmit = function(submitter) {
@@ -44,7 +32,7 @@ const submittersByForm = new WeakMap;
44
32
  function findSubmitterFromClickTarget(target) {
45
33
  const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
46
34
  const candidate = element ? element.closest("input, button") : null;
47
- return (candidate === null || candidate === void 0 ? void 0 : candidate.type) == "submit" ? candidate : null;
35
+ return candidate?.type == "submit" ? candidate : null;
48
36
  }
49
37
 
50
38
  function clickCaptured(event) {
@@ -57,10 +45,13 @@ function clickCaptured(event) {
57
45
  (function() {
58
46
  if ("submitter" in Event.prototype) return;
59
47
  let prototype = window.Event.prototype;
60
- if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
61
- prototype = window.SubmitEvent.prototype;
62
- } else if ("SubmitEvent" in window) {
63
- return;
48
+ if ("SubmitEvent" in window) {
49
+ const prototypeOfSubmitEvent = window.SubmitEvent.prototype;
50
+ if (/Apple Computer/.test(navigator.vendor) && !("submitter" in prototypeOfSubmitEvent)) {
51
+ prototype = prototypeOfSubmitEvent;
52
+ } else {
53
+ return;
54
+ }
64
55
  }
65
56
  addEventListener("click", clickCaptured, true);
66
57
  Object.defineProperty(prototype, "submitter", {
@@ -72,20 +63,19 @@ function clickCaptured(event) {
72
63
  });
73
64
  })();
74
65
 
75
- var FrameLoadingStyle;
76
-
77
- (function(FrameLoadingStyle) {
78
- FrameLoadingStyle["eager"] = "eager";
79
- FrameLoadingStyle["lazy"] = "lazy";
80
- })(FrameLoadingStyle || (FrameLoadingStyle = {}));
66
+ const FrameLoadingStyle = {
67
+ eager: "eager",
68
+ lazy: "lazy"
69
+ };
81
70
 
82
71
  class FrameElement extends HTMLElement {
72
+ static delegateConstructor=undefined;
73
+ loaded=Promise.resolve();
83
74
  static get observedAttributes() {
84
75
  return [ "disabled", "complete", "loading", "src" ];
85
76
  }
86
77
  constructor() {
87
78
  super();
88
- this.loaded = Promise.resolve();
89
79
  this.delegate = new FrameElement.delegateConstructor(this);
90
80
  }
91
81
  connectedCallback() {
@@ -118,6 +108,16 @@ class FrameElement extends HTMLElement {
118
108
  this.removeAttribute("src");
119
109
  }
120
110
  }
111
+ get refresh() {
112
+ return this.getAttribute("refresh");
113
+ }
114
+ set refresh(value) {
115
+ if (value) {
116
+ this.setAttribute("refresh", value);
117
+ } else {
118
+ this.removeAttribute("refresh");
119
+ }
120
+ }
121
121
  get loading() {
122
122
  return frameLoadingStyleFromString(this.getAttribute("loading") || "");
123
123
  }
@@ -155,8 +155,7 @@ class FrameElement extends HTMLElement {
155
155
  return this.ownerDocument === document && !this.isPreview;
156
156
  }
157
157
  get isPreview() {
158
- var _a, _b;
159
- return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
158
+ return this.ownerDocument?.documentElement?.hasAttribute("data-turbo-preview");
160
159
  }
161
160
  }
162
161
 
@@ -183,8 +182,8 @@ function getAnchor(url) {
183
182
  }
184
183
  }
185
184
 
186
- function getAction(form, submitter) {
187
- const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formaction")) || form.getAttribute("action") || form.action;
185
+ function getAction$1(form, submitter) {
186
+ const action = submitter?.getAttribute("formaction") || form.getAttribute("action") || form.action;
188
187
  return expandURL(action);
189
188
  }
190
189
 
@@ -323,6 +322,14 @@ function dispatch(eventName, {target: target, cancelable: cancelable, detail: de
323
322
  return event;
324
323
  }
325
324
 
325
+ function nextRepaint() {
326
+ if (document.visibilityState === "hidden") {
327
+ return nextEventLoopTick();
328
+ } else {
329
+ return nextAnimationFrame();
330
+ }
331
+ }
332
+
326
333
  function nextAnimationFrame() {
327
334
  return new Promise((resolve => requestAnimationFrame((() => resolve()))));
328
335
  }
@@ -370,7 +377,7 @@ function uuid() {
370
377
  }
371
378
 
372
379
  function getAttribute(attributeName, ...elements) {
373
- for (const value of elements.map((element => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName)))) {
380
+ for (const value of elements.map((element => element?.getAttribute(attributeName)))) {
374
381
  if (typeof value == "string") return value;
375
382
  }
376
383
  return null;
@@ -456,21 +463,38 @@ function setMetaContent(name, content) {
456
463
  }
457
464
 
458
465
  function findClosestRecursively(element, selector) {
459
- var _a;
460
466
  if (element instanceof Element) {
461
- return element.closest(selector) || findClosestRecursively(element.assignedSlot || ((_a = element.getRootNode()) === null || _a === void 0 ? void 0 : _a.host), selector);
467
+ return element.closest(selector) || findClosestRecursively(element.assignedSlot || element.getRootNode()?.host, selector);
462
468
  }
463
469
  }
464
470
 
465
- var FetchMethod;
471
+ function elementIsFocusable(element) {
472
+ const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
473
+ return !!element && element.closest(inertDisabledOrHidden) == null && typeof element.focus == "function";
474
+ }
475
+
476
+ function queryAutofocusableElement(elementOrDocumentFragment) {
477
+ return Array.from(elementOrDocumentFragment.querySelectorAll("[autofocus]")).find(elementIsFocusable);
478
+ }
479
+
480
+ async function around(callback, reader) {
481
+ const before = reader();
482
+ callback();
483
+ await nextAnimationFrame();
484
+ const after = reader();
485
+ return [ before, after ];
486
+ }
466
487
 
467
- (function(FetchMethod) {
468
- FetchMethod[FetchMethod["get"] = 0] = "get";
469
- FetchMethod[FetchMethod["post"] = 1] = "post";
470
- FetchMethod[FetchMethod["put"] = 2] = "put";
471
- FetchMethod[FetchMethod["patch"] = 3] = "patch";
472
- FetchMethod[FetchMethod["delete"] = 4] = "delete";
473
- })(FetchMethod || (FetchMethod = {}));
488
+ function fetch(url, options = {}) {
489
+ const modifiedHeaders = new Headers(options.headers || {});
490
+ const requestUID = uuid();
491
+ window.Turbo.session.recentRequests.add(requestUID);
492
+ modifiedHeaders.append("X-Turbo-Request-Id", requestUID);
493
+ return window.fetch(url, {
494
+ ...options,
495
+ headers: modifiedHeaders
496
+ });
497
+ }
474
498
 
475
499
  function fetchMethodFromString(method) {
476
500
  switch (method.toLowerCase()) {
@@ -491,16 +515,81 @@ function fetchMethodFromString(method) {
491
515
  }
492
516
  }
493
517
 
518
+ const FetchMethod = {
519
+ get: "get",
520
+ post: "post",
521
+ put: "put",
522
+ patch: "patch",
523
+ delete: "delete"
524
+ };
525
+
526
+ function fetchEnctypeFromString(encoding) {
527
+ switch (encoding.toLowerCase()) {
528
+ case FetchEnctype.multipart:
529
+ return FetchEnctype.multipart;
530
+
531
+ case FetchEnctype.plain:
532
+ return FetchEnctype.plain;
533
+
534
+ default:
535
+ return FetchEnctype.urlEncoded;
536
+ }
537
+ }
538
+
539
+ const FetchEnctype = {
540
+ urlEncoded: "application/x-www-form-urlencoded",
541
+ multipart: "multipart/form-data",
542
+ plain: "text/plain"
543
+ };
544
+
494
545
  class FetchRequest {
495
- constructor(delegate, method, location, body = new URLSearchParams, target = null) {
496
- this.abortController = new AbortController;
497
- this.resolveRequestPromise = _value => {};
546
+ abortController=new AbortController;
547
+ #resolveRequestPromise=_value => {};
548
+ constructor(delegate, method, location, requestBody = new URLSearchParams, target = null, enctype = FetchEnctype.urlEncoded) {
549
+ const [url, body] = buildResourceAndBody(expandURL(location), method, requestBody, enctype);
498
550
  this.delegate = delegate;
499
- this.method = method;
500
- this.headers = this.defaultHeaders;
501
- this.body = body;
502
- this.url = location;
551
+ this.url = url;
503
552
  this.target = target;
553
+ this.fetchOptions = {
554
+ credentials: "same-origin",
555
+ redirect: "follow",
556
+ method: method,
557
+ headers: {
558
+ ...this.defaultHeaders
559
+ },
560
+ body: body,
561
+ signal: this.abortSignal,
562
+ referrer: this.delegate.referrer?.href
563
+ };
564
+ this.enctype = enctype;
565
+ }
566
+ get method() {
567
+ return this.fetchOptions.method;
568
+ }
569
+ set method(value) {
570
+ const fetchBody = this.isSafe ? this.url.searchParams : this.fetchOptions.body || new FormData;
571
+ const fetchMethod = fetchMethodFromString(value) || FetchMethod.get;
572
+ this.url.search = "";
573
+ const [url, body] = buildResourceAndBody(this.url, fetchMethod, fetchBody, this.enctype);
574
+ this.url = url;
575
+ this.fetchOptions.body = body;
576
+ this.fetchOptions.method = fetchMethod;
577
+ }
578
+ get headers() {
579
+ return this.fetchOptions.headers;
580
+ }
581
+ set headers(value) {
582
+ this.fetchOptions.headers = value;
583
+ }
584
+ get body() {
585
+ if (this.isSafe) {
586
+ return this.url.searchParams;
587
+ } else {
588
+ return this.fetchOptions.body;
589
+ }
590
+ }
591
+ set body(value) {
592
+ this.fetchOptions.body = value;
504
593
  }
505
594
  get location() {
506
595
  return this.url;
@@ -517,14 +606,14 @@ class FetchRequest {
517
606
  async perform() {
518
607
  const {fetchOptions: fetchOptions} = this;
519
608
  this.delegate.prepareRequest(this);
520
- await this.allowRequestToBeIntercepted(fetchOptions);
609
+ await this.#allowRequestToBeIntercepted(fetchOptions);
521
610
  try {
522
611
  this.delegate.requestStarted(this);
523
612
  const response = await fetch(this.url.href, fetchOptions);
524
613
  return await this.receive(response);
525
614
  } catch (error) {
526
615
  if (error.name !== "AbortError") {
527
- if (this.willDelegateErrorHandling(error)) {
616
+ if (this.#willDelegateErrorHandling(error)) {
528
617
  this.delegate.requestErrored(this, error);
529
618
  }
530
619
  throw error;
@@ -551,25 +640,13 @@ class FetchRequest {
551
640
  }
552
641
  return fetchResponse;
553
642
  }
554
- get fetchOptions() {
555
- var _a;
556
- return {
557
- method: FetchMethod[this.method].toUpperCase(),
558
- credentials: "same-origin",
559
- headers: this.headers,
560
- redirect: "follow",
561
- body: this.isSafe ? null : this.body,
562
- signal: this.abortSignal,
563
- referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
564
- };
565
- }
566
643
  get defaultHeaders() {
567
644
  return {
568
645
  Accept: "text/html, application/xhtml+xml"
569
646
  };
570
647
  }
571
648
  get isSafe() {
572
- return this.method === FetchMethod.get;
649
+ return isSafe(this.method);
573
650
  }
574
651
  get abortSignal() {
575
652
  return this.abortController.signal;
@@ -577,20 +654,21 @@ class FetchRequest {
577
654
  acceptResponseType(mimeType) {
578
655
  this.headers["Accept"] = [ mimeType, this.headers["Accept"] ].join(", ");
579
656
  }
580
- async allowRequestToBeIntercepted(fetchOptions) {
581
- const requestInterception = new Promise((resolve => this.resolveRequestPromise = resolve));
657
+ async #allowRequestToBeIntercepted(fetchOptions) {
658
+ const requestInterception = new Promise((resolve => this.#resolveRequestPromise = resolve));
582
659
  const event = dispatch("turbo:before-fetch-request", {
583
660
  cancelable: true,
584
661
  detail: {
585
662
  fetchOptions: fetchOptions,
586
663
  url: this.url,
587
- resume: this.resolveRequestPromise
664
+ resume: this.#resolveRequestPromise
588
665
  },
589
666
  target: this.target
590
667
  });
668
+ this.url = event.detail.url;
591
669
  if (event.defaultPrevented) await requestInterception;
592
670
  }
593
- willDelegateErrorHandling(error) {
671
+ #willDelegateErrorHandling(error) {
594
672
  const event = dispatch("turbo:fetch-request-error", {
595
673
  target: this.target,
596
674
  cancelable: true,
@@ -603,15 +681,38 @@ class FetchRequest {
603
681
  }
604
682
  }
605
683
 
684
+ function isSafe(fetchMethod) {
685
+ return fetchMethodFromString(fetchMethod) == FetchMethod.get;
686
+ }
687
+
688
+ function buildResourceAndBody(resource, method, requestBody, enctype) {
689
+ const searchParams = Array.from(requestBody).length > 0 ? new URLSearchParams(entriesExcludingFiles(requestBody)) : resource.searchParams;
690
+ if (isSafe(method)) {
691
+ return [ mergeIntoURLSearchParams(resource, searchParams), null ];
692
+ } else if (enctype == FetchEnctype.urlEncoded) {
693
+ return [ resource, searchParams ];
694
+ } else {
695
+ return [ resource, requestBody ];
696
+ }
697
+ }
698
+
699
+ function entriesExcludingFiles(requestBody) {
700
+ const entries = [];
701
+ for (const [name, value] of requestBody) {
702
+ if (value instanceof File) continue; else entries.push([ name, value ]);
703
+ }
704
+ return entries;
705
+ }
706
+
707
+ function mergeIntoURLSearchParams(url, requestBody) {
708
+ const searchParams = new URLSearchParams(entriesExcludingFiles(requestBody));
709
+ url.search = searchParams.toString();
710
+ return url;
711
+ }
712
+
606
713
  class AppearanceObserver {
714
+ started=false;
607
715
  constructor(delegate, element) {
608
- this.started = false;
609
- this.intersect = entries => {
610
- const lastEntry = entries.slice(-1)[0];
611
- if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
612
- this.delegate.elementAppearedInViewport(this.element);
613
- }
614
- };
615
716
  this.delegate = delegate;
616
717
  this.element = element;
617
718
  this.intersectionObserver = new IntersectionObserver(this.intersect);
@@ -628,9 +729,16 @@ class AppearanceObserver {
628
729
  this.intersectionObserver.unobserve(this.element);
629
730
  }
630
731
  }
732
+ intersect=entries => {
733
+ const lastEntry = entries.slice(-1)[0];
734
+ if (lastEntry?.isIntersecting) {
735
+ this.delegate.elementAppearedInViewport(this.element);
736
+ }
737
+ };
631
738
  }
632
739
 
633
740
  class StreamMessage {
741
+ static contentType="text/vnd.turbo-stream.html";
634
742
  static wrap(message) {
635
743
  if (typeof message == "string") {
636
744
  return new this(createDocumentFragment(message));
@@ -643,8 +751,6 @@ class StreamMessage {
643
751
  }
644
752
  }
645
753
 
646
- StreamMessage.contentType = "text/vnd.turbo-stream.html";
647
-
648
754
  function importStreamElements(fragment) {
649
755
  for (const element of fragment.querySelectorAll("turbo-stream")) {
650
756
  const streamElement = document.importNode(element, true);
@@ -656,85 +762,54 @@ function importStreamElements(fragment) {
656
762
  return fragment;
657
763
  }
658
764
 
659
- var FormSubmissionState;
660
-
661
- (function(FormSubmissionState) {
662
- FormSubmissionState[FormSubmissionState["initialized"] = 0] = "initialized";
663
- FormSubmissionState[FormSubmissionState["requesting"] = 1] = "requesting";
664
- FormSubmissionState[FormSubmissionState["waiting"] = 2] = "waiting";
665
- FormSubmissionState[FormSubmissionState["receiving"] = 3] = "receiving";
666
- FormSubmissionState[FormSubmissionState["stopping"] = 4] = "stopping";
667
- FormSubmissionState[FormSubmissionState["stopped"] = 5] = "stopped";
668
- })(FormSubmissionState || (FormSubmissionState = {}));
669
-
670
- var FormEnctype;
671
-
672
- (function(FormEnctype) {
673
- FormEnctype["urlEncoded"] = "application/x-www-form-urlencoded";
674
- FormEnctype["multipart"] = "multipart/form-data";
675
- FormEnctype["plain"] = "text/plain";
676
- })(FormEnctype || (FormEnctype = {}));
677
-
678
- function formEnctypeFromString(encoding) {
679
- switch (encoding.toLowerCase()) {
680
- case FormEnctype.multipart:
681
- return FormEnctype.multipart;
682
-
683
- case FormEnctype.plain:
684
- return FormEnctype.plain;
685
-
686
- default:
687
- return FormEnctype.urlEncoded;
688
- }
689
- }
765
+ const FormSubmissionState = {
766
+ initialized: "initialized",
767
+ requesting: "requesting",
768
+ waiting: "waiting",
769
+ receiving: "receiving",
770
+ stopping: "stopping",
771
+ stopped: "stopped"
772
+ };
690
773
 
691
774
  class FormSubmission {
775
+ state=FormSubmissionState.initialized;
692
776
  static confirmMethod(message, _element, _submitter) {
693
777
  return Promise.resolve(confirm(message));
694
778
  }
695
779
  constructor(delegate, formElement, submitter, mustRedirect = false) {
696
- this.state = FormSubmissionState.initialized;
780
+ const method = getMethod(formElement, submitter);
781
+ const action = getAction(getFormAction(formElement, submitter), method);
782
+ const body = buildFormData(formElement, submitter);
783
+ const enctype = getEnctype(formElement, submitter);
697
784
  this.delegate = delegate;
698
785
  this.formElement = formElement;
699
786
  this.submitter = submitter;
700
- this.formData = buildFormData(formElement, submitter);
701
- this.location = expandURL(this.action);
702
- if (this.method == FetchMethod.get) {
703
- mergeFormDataEntries(this.location, [ ...this.body.entries() ]);
704
- }
705
- this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
787
+ this.fetchRequest = new FetchRequest(this, method, action, body, formElement, enctype);
706
788
  this.mustRedirect = mustRedirect;
707
789
  }
708
790
  get method() {
709
- var _a;
710
- const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
711
- return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
791
+ return this.fetchRequest.method;
792
+ }
793
+ set method(value) {
794
+ this.fetchRequest.method = value;
712
795
  }
713
796
  get action() {
714
- var _a;
715
- const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
716
- if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
717
- return this.submitter.getAttribute("formaction") || "";
718
- } else {
719
- return this.formElement.getAttribute("action") || formElementAction || "";
720
- }
797
+ return this.fetchRequest.url.toString();
798
+ }
799
+ set action(value) {
800
+ this.fetchRequest.url = expandURL(value);
721
801
  }
722
802
  get body() {
723
- if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
724
- return new URLSearchParams(this.stringFormData);
725
- } else {
726
- return this.formData;
727
- }
803
+ return this.fetchRequest.body;
728
804
  }
729
805
  get enctype() {
730
- var _a;
731
- return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
806
+ return this.fetchRequest.enctype;
732
807
  }
733
808
  get isSafe() {
734
809
  return this.fetchRequest.isSafe;
735
810
  }
736
- get stringFormData() {
737
- return [ ...this.formData ].reduce(((entries, [name, value]) => entries.concat(typeof value == "string" ? [ [ name, value ] ] : [])), []);
811
+ get location() {
812
+ return this.fetchRequest.url;
738
813
  }
739
814
  async start() {
740
815
  const {initialized: initialized, requesting: requesting} = FormSubmissionState;
@@ -770,9 +845,8 @@ class FormSubmission {
770
845
  }
771
846
  }
772
847
  requestStarted(_request) {
773
- var _a;
774
848
  this.state = FormSubmissionState.waiting;
775
- (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
849
+ this.submitter?.setAttribute("disabled", "");
776
850
  this.setSubmitsWith();
777
851
  dispatch("turbo:submit-start", {
778
852
  target: this.formElement,
@@ -818,15 +892,15 @@ class FormSubmission {
818
892
  this.delegate.formSubmissionErrored(this, error);
819
893
  }
820
894
  requestFinished(_request) {
821
- var _a;
822
895
  this.state = FormSubmissionState.stopped;
823
- (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
896
+ this.submitter?.removeAttribute("disabled");
824
897
  this.resetSubmitterText();
825
898
  dispatch("turbo:submit-end", {
826
899
  target: this.formElement,
827
- detail: Object.assign({
828
- formSubmission: this
829
- }, this.result)
900
+ detail: {
901
+ formSubmission: this,
902
+ ...this.result
903
+ }
830
904
  });
831
905
  this.delegate.formSubmissionFinished(this);
832
906
  }
@@ -857,15 +931,14 @@ class FormSubmission {
857
931
  return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
858
932
  }
859
933
  get submitsWith() {
860
- var _a;
861
- return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-submits-with");
934
+ return this.submitter?.getAttribute("data-turbo-submits-with");
862
935
  }
863
936
  }
864
937
 
865
938
  function buildFormData(formElement, submitter) {
866
939
  const formData = new FormData(formElement);
867
- const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
868
- const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
940
+ const name = submitter?.getAttribute("name");
941
+ const value = submitter?.getAttribute("value");
869
942
  if (name) {
870
943
  formData.append(name, value || "");
871
944
  }
@@ -887,14 +960,30 @@ function responseSucceededWithoutRedirect(response) {
887
960
  return response.statusCode == 200 && !response.redirected;
888
961
  }
889
962
 
890
- function mergeFormDataEntries(url, entries) {
891
- const searchParams = new URLSearchParams;
892
- for (const [name, value] of entries) {
893
- if (value instanceof File) continue;
894
- searchParams.append(name, value);
963
+ function getFormAction(formElement, submitter) {
964
+ const formElementAction = typeof formElement.action === "string" ? formElement.action : null;
965
+ if (submitter?.hasAttribute("formaction")) {
966
+ return submitter.getAttribute("formaction") || "";
967
+ } else {
968
+ return formElement.getAttribute("action") || formElementAction || "";
895
969
  }
896
- url.search = searchParams.toString();
897
- return url;
970
+ }
971
+
972
+ function getAction(formAction, fetchMethod) {
973
+ const action = expandURL(formAction);
974
+ if (isSafe(fetchMethod)) {
975
+ action.search = "";
976
+ }
977
+ return action;
978
+ }
979
+
980
+ function getMethod(formElement, submitter) {
981
+ const method = submitter?.getAttribute("formmethod") || formElement.getAttribute("method") || "";
982
+ return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
983
+ }
984
+
985
+ function getEnctype(formElement, submitter) {
986
+ return fetchEnctypeFromString(submitter?.getAttribute("formenctype") || formElement.enctype);
898
987
  }
899
988
 
900
989
  class Snapshot {
@@ -917,11 +1006,7 @@ class Snapshot {
917
1006
  return this.element.isConnected;
918
1007
  }
919
1008
  get firstAutofocusableElement() {
920
- const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
921
- for (const element of this.element.querySelectorAll("[autofocus]")) {
922
- if (element.closest(inertDisabledOrHidden) == null) return element; else continue;
923
- }
924
- return null;
1009
+ return queryAutofocusableElement(this.element);
925
1010
  }
926
1011
  get permanentElements() {
927
1012
  return queryPermanentElementsAll(this.element);
@@ -951,23 +1036,8 @@ function queryPermanentElementsAll(node) {
951
1036
  }
952
1037
 
953
1038
  class FormSubmitObserver {
1039
+ started=false;
954
1040
  constructor(delegate, eventTarget) {
955
- this.started = false;
956
- this.submitCaptured = () => {
957
- this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
958
- this.eventTarget.addEventListener("submit", this.submitBubbled, false);
959
- };
960
- this.submitBubbled = event => {
961
- if (!event.defaultPrevented) {
962
- const form = event.target instanceof HTMLFormElement ? event.target : undefined;
963
- const submitter = event.submitter || undefined;
964
- if (form && submissionDoesNotDismissDialog(form, submitter) && submissionDoesNotTargetIFrame(form, submitter) && this.delegate.willSubmitForm(form, submitter)) {
965
- event.preventDefault();
966
- event.stopImmediatePropagation();
967
- this.delegate.formSubmitted(form, submitter);
968
- }
969
- }
970
- };
971
1041
  this.delegate = delegate;
972
1042
  this.eventTarget = eventTarget;
973
1043
  }
@@ -983,16 +1053,31 @@ class FormSubmitObserver {
983
1053
  this.started = false;
984
1054
  }
985
1055
  }
1056
+ submitCaptured=() => {
1057
+ this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
1058
+ this.eventTarget.addEventListener("submit", this.submitBubbled, false);
1059
+ };
1060
+ submitBubbled=event => {
1061
+ if (!event.defaultPrevented) {
1062
+ const form = event.target instanceof HTMLFormElement ? event.target : undefined;
1063
+ const submitter = event.submitter || undefined;
1064
+ if (form && submissionDoesNotDismissDialog(form, submitter) && submissionDoesNotTargetIFrame(form, submitter) && this.delegate.willSubmitForm(form, submitter)) {
1065
+ event.preventDefault();
1066
+ event.stopImmediatePropagation();
1067
+ this.delegate.formSubmitted(form, submitter);
1068
+ }
1069
+ }
1070
+ };
986
1071
  }
987
1072
 
988
1073
  function submissionDoesNotDismissDialog(form, submitter) {
989
- const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
1074
+ const method = submitter?.getAttribute("formmethod") || form.getAttribute("method");
990
1075
  return method != "dialog";
991
1076
  }
992
1077
 
993
1078
  function submissionDoesNotTargetIFrame(form, submitter) {
994
- if ((submitter === null || submitter === void 0 ? void 0 : submitter.hasAttribute("formtarget")) || form.hasAttribute("target")) {
995
- const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
1079
+ if (submitter?.hasAttribute("formtarget") || form.hasAttribute("target")) {
1080
+ const target = submitter?.getAttribute("formtarget") || form.target;
996
1081
  for (const element of document.getElementsByName(target)) {
997
1082
  if (element instanceof HTMLIFrameElement) return false;
998
1083
  }
@@ -1003,9 +1088,9 @@ function submissionDoesNotTargetIFrame(form, submitter) {
1003
1088
  }
1004
1089
 
1005
1090
  class View {
1091
+ #resolveRenderPromise=_value => {};
1092
+ #resolveInterceptionPromise=_value => {};
1006
1093
  constructor(delegate, element) {
1007
- this.resolveRenderPromise = _value => {};
1008
- this.resolveInterceptionPromise = _value => {};
1009
1094
  this.delegate = delegate;
1010
1095
  this.element = element;
1011
1096
  }
@@ -1054,23 +1139,23 @@ class View {
1054
1139
  const {isPreview: isPreview, shouldRender: shouldRender, newSnapshot: snapshot} = renderer;
1055
1140
  if (shouldRender) {
1056
1141
  try {
1057
- this.renderPromise = new Promise((resolve => this.resolveRenderPromise = resolve));
1142
+ this.renderPromise = new Promise((resolve => this.#resolveRenderPromise = resolve));
1058
1143
  this.renderer = renderer;
1059
1144
  await this.prepareToRenderSnapshot(renderer);
1060
- const renderInterception = new Promise((resolve => this.resolveInterceptionPromise = resolve));
1145
+ const renderInterception = new Promise((resolve => this.#resolveInterceptionPromise = resolve));
1061
1146
  const options = {
1062
- resume: this.resolveInterceptionPromise,
1147
+ resume: this.#resolveInterceptionPromise,
1063
1148
  render: this.renderer.renderElement
1064
1149
  };
1065
- const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
1150
+ const immediateRender = this.delegate.allowsImmediateRender(snapshot, isPreview, options);
1066
1151
  if (!immediateRender) await renderInterception;
1067
1152
  await this.renderSnapshot(renderer);
1068
- this.delegate.viewRenderedSnapshot(snapshot, isPreview);
1153
+ this.delegate.viewRenderedSnapshot(snapshot, isPreview, this.renderer.renderMethod);
1069
1154
  this.delegate.preloadOnLoadLinksForView(this.element);
1070
1155
  this.finishRenderingSnapshot(renderer);
1071
1156
  } finally {
1072
1157
  delete this.renderer;
1073
- this.resolveRenderPromise(undefined);
1158
+ this.#resolveRenderPromise(undefined);
1074
1159
  delete this.renderPromise;
1075
1160
  }
1076
1161
  } else {
@@ -1110,26 +1195,6 @@ class FrameView extends View {
1110
1195
 
1111
1196
  class LinkInterceptor {
1112
1197
  constructor(delegate, element) {
1113
- this.clickBubbled = event => {
1114
- if (this.respondsToEventTarget(event.target)) {
1115
- this.clickEvent = event;
1116
- } else {
1117
- delete this.clickEvent;
1118
- }
1119
- };
1120
- this.linkClicked = event => {
1121
- if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
1122
- if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
1123
- this.clickEvent.preventDefault();
1124
- event.preventDefault();
1125
- this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
1126
- }
1127
- }
1128
- delete this.clickEvent;
1129
- };
1130
- this.willVisit = _event => {
1131
- delete this.clickEvent;
1132
- };
1133
1198
  this.delegate = delegate;
1134
1199
  this.element = element;
1135
1200
  }
@@ -1143,6 +1208,26 @@ class LinkInterceptor {
1143
1208
  document.removeEventListener("turbo:click", this.linkClicked);
1144
1209
  document.removeEventListener("turbo:before-visit", this.willVisit);
1145
1210
  }
1211
+ clickBubbled=event => {
1212
+ if (this.respondsToEventTarget(event.target)) {
1213
+ this.clickEvent = event;
1214
+ } else {
1215
+ delete this.clickEvent;
1216
+ }
1217
+ };
1218
+ linkClicked=event => {
1219
+ if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
1220
+ if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
1221
+ this.clickEvent.preventDefault();
1222
+ event.preventDefault();
1223
+ this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
1224
+ }
1225
+ }
1226
+ delete this.clickEvent;
1227
+ };
1228
+ willVisit=_event => {
1229
+ delete this.clickEvent;
1230
+ };
1146
1231
  respondsToEventTarget(target) {
1147
1232
  const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
1148
1233
  return element && element.closest("turbo-frame, html") == this.element;
@@ -1150,25 +1235,8 @@ class LinkInterceptor {
1150
1235
  }
1151
1236
 
1152
1237
  class LinkClickObserver {
1238
+ started=false;
1153
1239
  constructor(delegate, eventTarget) {
1154
- this.started = false;
1155
- this.clickCaptured = () => {
1156
- this.eventTarget.removeEventListener("click", this.clickBubbled, false);
1157
- this.eventTarget.addEventListener("click", this.clickBubbled, false);
1158
- };
1159
- this.clickBubbled = event => {
1160
- if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
1161
- const target = event.composedPath && event.composedPath()[0] || event.target;
1162
- const link = this.findLinkFromClickTarget(target);
1163
- if (link && doesNotTargetIFrame(link)) {
1164
- const location = this.getLocationForLink(link);
1165
- if (this.delegate.willFollowLinkToLocation(link, location, event)) {
1166
- event.preventDefault();
1167
- this.delegate.followedLinkToLocation(link, location);
1168
- }
1169
- }
1170
- }
1171
- };
1172
1240
  this.delegate = delegate;
1173
1241
  this.eventTarget = eventTarget;
1174
1242
  }
@@ -1184,6 +1252,23 @@ class LinkClickObserver {
1184
1252
  this.started = false;
1185
1253
  }
1186
1254
  }
1255
+ clickCaptured=() => {
1256
+ this.eventTarget.removeEventListener("click", this.clickBubbled, false);
1257
+ this.eventTarget.addEventListener("click", this.clickBubbled, false);
1258
+ };
1259
+ clickBubbled=event => {
1260
+ if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
1261
+ const target = event.composedPath && event.composedPath()[0] || event.target;
1262
+ const link = this.findLinkFromClickTarget(target);
1263
+ if (link && doesNotTargetIFrame(link)) {
1264
+ const location = this.getLocationForLink(link);
1265
+ if (this.delegate.willFollowLinkToLocation(link, location, event)) {
1266
+ event.preventDefault();
1267
+ this.delegate.followedLinkToLocation(link, location);
1268
+ }
1269
+ }
1270
+ }
1271
+ };
1187
1272
  clickEventIsSignificant(event) {
1188
1273
  return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
1189
1274
  }
@@ -1218,7 +1303,7 @@ class FormLinkClickObserver {
1218
1303
  this.linkInterceptor.stop();
1219
1304
  }
1220
1305
  willFollowLinkToLocation(link, location, originalEvent) {
1221
- return this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) && link.hasAttribute("data-turbo-method");
1306
+ return this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) && (link.hasAttribute("data-turbo-method") || link.hasAttribute("data-turbo-stream"));
1222
1307
  }
1223
1308
  followedLinkToLocation(link, location) {
1224
1309
  const form = document.createElement("form");
@@ -1291,7 +1376,7 @@ class Bardo {
1291
1376
  }
1292
1377
  replacePlaceholderWithPermanentElement(permanentElement) {
1293
1378
  const placeholder = this.getPlaceholderById(permanentElement.id);
1294
- placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);
1379
+ placeholder?.replaceWith(permanentElement);
1295
1380
  }
1296
1381
  getPlaceholderById(id) {
1297
1382
  return this.placeholders.find((element => element.content == id));
@@ -1309,8 +1394,8 @@ function createPlaceholderForPermanentElement(permanentElement) {
1309
1394
  }
1310
1395
 
1311
1396
  class Renderer {
1397
+ #activeElement=null;
1312
1398
  constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
1313
- this.activeElement = null;
1314
1399
  this.currentSnapshot = currentSnapshot;
1315
1400
  this.newSnapshot = newSnapshot;
1316
1401
  this.isPreview = isPreview;
@@ -1330,6 +1415,7 @@ class Renderer {
1330
1415
  prepareToRender() {
1331
1416
  return;
1332
1417
  }
1418
+ render() {}
1333
1419
  finishRendering() {
1334
1420
  if (this.resolvingFunctions) {
1335
1421
  this.resolvingFunctions.resolve();
@@ -1341,20 +1427,20 @@ class Renderer {
1341
1427
  }
1342
1428
  focusFirstAutofocusableElement() {
1343
1429
  const element = this.connectedSnapshot.firstAutofocusableElement;
1344
- if (elementIsFocusable(element)) {
1430
+ if (element) {
1345
1431
  element.focus();
1346
1432
  }
1347
1433
  }
1348
1434
  enteringBardo(currentPermanentElement) {
1349
- if (this.activeElement) return;
1435
+ if (this.#activeElement) return;
1350
1436
  if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
1351
- this.activeElement = this.currentSnapshot.activeElement;
1437
+ this.#activeElement = this.currentSnapshot.activeElement;
1352
1438
  }
1353
1439
  }
1354
1440
  leavingBardo(currentPermanentElement) {
1355
- if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {
1356
- this.activeElement.focus();
1357
- this.activeElement = null;
1441
+ if (currentPermanentElement.contains(this.#activeElement) && this.#activeElement instanceof HTMLElement) {
1442
+ this.#activeElement.focus();
1443
+ this.#activeElement = null;
1358
1444
  }
1359
1445
  }
1360
1446
  get connectedSnapshot() {
@@ -1369,20 +1455,18 @@ class Renderer {
1369
1455
  get permanentElementMap() {
1370
1456
  return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
1371
1457
  }
1372
- }
1373
-
1374
- function elementIsFocusable(element) {
1375
- return element && typeof element.focus == "function";
1458
+ get renderMethod() {
1459
+ return "replace";
1460
+ }
1376
1461
  }
1377
1462
 
1378
1463
  class FrameRenderer extends Renderer {
1379
1464
  static renderElement(currentElement, newElement) {
1380
- var _a;
1381
1465
  const destinationRange = document.createRange();
1382
1466
  destinationRange.selectNodeContents(currentElement);
1383
1467
  destinationRange.deleteContents();
1384
1468
  const frameElement = newElement;
1385
- const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
1469
+ const sourceRange = frameElement.ownerDocument?.createRange();
1386
1470
  if (sourceRange) {
1387
1471
  sourceRange.selectNodeContents(frameElement);
1388
1472
  currentElement.appendChild(sourceRange.extractContents());
@@ -1453,6 +1537,7 @@ function readScrollBehavior(value, defaultValue) {
1453
1537
  }
1454
1538
 
1455
1539
  class ProgressBar {
1540
+ static animationDuration=300;
1456
1541
  static get defaultCSS() {
1457
1542
  return unindent`
1458
1543
  .turbo-progress-bar {
@@ -1470,13 +1555,10 @@ class ProgressBar {
1470
1555
  }
1471
1556
  `;
1472
1557
  }
1558
+ hiding=false;
1559
+ value=0;
1560
+ visible=false;
1473
1561
  constructor() {
1474
- this.hiding = false;
1475
- this.value = 0;
1476
- this.visible = false;
1477
- this.trickle = () => {
1478
- this.setValue(this.value + Math.random() / 100);
1479
- };
1480
1562
  this.stylesheetElement = this.createStylesheetElement();
1481
1563
  this.progressElement = this.createProgressElement();
1482
1564
  this.installStylesheetElement();
@@ -1531,6 +1613,9 @@ class ProgressBar {
1531
1613
  window.clearInterval(this.trickleInterval);
1532
1614
  delete this.trickleInterval;
1533
1615
  }
1616
+ trickle=() => {
1617
+ this.setValue(this.value + Math.random() / 100);
1618
+ };
1534
1619
  refresh() {
1535
1620
  requestAnimationFrame((() => {
1536
1621
  this.progressElement.style.width = `${10 + this.value * 90}%`;
@@ -1555,25 +1640,22 @@ class ProgressBar {
1555
1640
  }
1556
1641
  }
1557
1642
 
1558
- ProgressBar.animationDuration = 300;
1559
-
1560
1643
  class HeadSnapshot extends Snapshot {
1561
- constructor() {
1562
- super(...arguments);
1563
- this.detailsByOuterHTML = this.children.filter((element => !elementIsNoscript(element))).map((element => elementWithoutNonce(element))).reduce(((result, element) => {
1564
- const {outerHTML: outerHTML} = element;
1565
- const details = outerHTML in result ? result[outerHTML] : {
1566
- type: elementType(element),
1567
- tracked: elementIsTracked(element),
1568
- elements: []
1569
- };
1570
- return Object.assign(Object.assign({}, result), {
1571
- [outerHTML]: Object.assign(Object.assign({}, details), {
1572
- elements: [ ...details.elements, element ]
1573
- })
1574
- });
1575
- }), {});
1576
- }
1644
+ detailsByOuterHTML=this.children.filter((element => !elementIsNoscript(element))).map((element => elementWithoutNonce(element))).reduce(((result, element) => {
1645
+ const {outerHTML: outerHTML} = element;
1646
+ const details = outerHTML in result ? result[outerHTML] : {
1647
+ type: elementType(element),
1648
+ tracked: elementIsTracked(element),
1649
+ elements: []
1650
+ };
1651
+ return {
1652
+ ...result,
1653
+ [outerHTML]: {
1654
+ ...details,
1655
+ elements: [ ...details.elements, element ]
1656
+ }
1657
+ };
1658
+ }), {});
1577
1659
  get trackedElementSignature() {
1578
1660
  return Object.keys(this.detailsByOuterHTML).filter((outerHTML => this.detailsByOuterHTML[outerHTML].tracked)).join("");
1579
1661
  }
@@ -1606,7 +1688,7 @@ class HeadSnapshot extends Snapshot {
1606
1688
  return Object.keys(this.detailsByOuterHTML).reduce(((result, outerHTML) => {
1607
1689
  const {elements: [element]} = this.detailsByOuterHTML[outerHTML];
1608
1690
  return elementIsMetaElementWithName(element, name) ? element : result;
1609
- }), undefined);
1691
+ }), undefined | undefined);
1610
1692
  }
1611
1693
  }
1612
1694
 
@@ -1656,11 +1738,12 @@ class PageSnapshot extends Snapshot {
1656
1738
  static fromElement(element) {
1657
1739
  return this.fromDocument(element.ownerDocument);
1658
1740
  }
1659
- static fromDocument({head: head, body: body}) {
1660
- return new this(body, new HeadSnapshot(head));
1741
+ static fromDocument({documentElement: documentElement, body: body, head: head}) {
1742
+ return new this(documentElement, body, new HeadSnapshot(head));
1661
1743
  }
1662
- constructor(element, headSnapshot) {
1663
- super(element);
1744
+ constructor(documentElement, body, headSnapshot) {
1745
+ super(body);
1746
+ this.documentElement = documentElement;
1664
1747
  this.headSnapshot = headSnapshot;
1665
1748
  }
1666
1749
  clone() {
@@ -1675,14 +1758,16 @@ class PageSnapshot extends Snapshot {
1675
1758
  for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
1676
1759
  clonedPasswordInput.value = "";
1677
1760
  }
1678
- return new PageSnapshot(clonedElement, this.headSnapshot);
1761
+ return new PageSnapshot(this.documentElement, clonedElement, this.headSnapshot);
1762
+ }
1763
+ get lang() {
1764
+ return this.documentElement.getAttribute("lang");
1679
1765
  }
1680
1766
  get headElement() {
1681
1767
  return this.headSnapshot.element;
1682
1768
  }
1683
1769
  get rootLocation() {
1684
- var _a;
1685
- const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
1770
+ const root = this.getSetting("root") ?? "/";
1686
1771
  return expandURL(root);
1687
1772
  }
1688
1773
  get cacheControlValue() {
@@ -1697,29 +1782,38 @@ class PageSnapshot extends Snapshot {
1697
1782
  get isVisitable() {
1698
1783
  return this.getSetting("visit-control") != "reload";
1699
1784
  }
1785
+ get prefersViewTransitions() {
1786
+ return this.headSnapshot.getMetaValue("view-transition") === "same-origin";
1787
+ }
1788
+ get shouldMorphPage() {
1789
+ return this.getSetting("refresh-method") === "morph";
1790
+ }
1791
+ get shouldPreserveScrollPosition() {
1792
+ return this.getSetting("refresh-scroll") === "preserve";
1793
+ }
1700
1794
  getSetting(name) {
1701
1795
  return this.headSnapshot.getMetaValue(`turbo-${name}`);
1702
1796
  }
1703
1797
  }
1704
1798
 
1705
- var TimingMetric;
1706
-
1707
- (function(TimingMetric) {
1708
- TimingMetric["visitStart"] = "visitStart";
1709
- TimingMetric["requestStart"] = "requestStart";
1710
- TimingMetric["requestEnd"] = "requestEnd";
1711
- TimingMetric["visitEnd"] = "visitEnd";
1712
- })(TimingMetric || (TimingMetric = {}));
1713
-
1714
- var VisitState;
1715
-
1716
- (function(VisitState) {
1717
- VisitState["initialized"] = "initialized";
1718
- VisitState["started"] = "started";
1719
- VisitState["canceled"] = "canceled";
1720
- VisitState["failed"] = "failed";
1721
- VisitState["completed"] = "completed";
1722
- })(VisitState || (VisitState = {}));
1799
+ class ViewTransitioner {
1800
+ #viewTransitionStarted=false;
1801
+ #lastOperation=Promise.resolve();
1802
+ renderChange(useViewTransition, render) {
1803
+ if (useViewTransition && this.viewTransitionsAvailable && !this.#viewTransitionStarted) {
1804
+ this.#viewTransitionStarted = true;
1805
+ this.#lastOperation = this.#lastOperation.then((async () => {
1806
+ await document.startViewTransition(render).finished;
1807
+ }));
1808
+ } else {
1809
+ this.#lastOperation = this.#lastOperation.then(render);
1810
+ }
1811
+ return this.#lastOperation;
1812
+ }
1813
+ get viewTransitionsAvailable() {
1814
+ return document.startViewTransition;
1815
+ }
1816
+ }
1723
1817
 
1724
1818
  const defaultOptions = {
1725
1819
  action: "advance",
@@ -1731,29 +1825,46 @@ const defaultOptions = {
1731
1825
  acceptsStreamResponse: false
1732
1826
  };
1733
1827
 
1734
- var SystemStatusCode;
1828
+ const TimingMetric = {
1829
+ visitStart: "visitStart",
1830
+ requestStart: "requestStart",
1831
+ requestEnd: "requestEnd",
1832
+ visitEnd: "visitEnd"
1833
+ };
1834
+
1835
+ const VisitState = {
1836
+ initialized: "initialized",
1837
+ started: "started",
1838
+ canceled: "canceled",
1839
+ failed: "failed",
1840
+ completed: "completed"
1841
+ };
1735
1842
 
1736
- (function(SystemStatusCode) {
1737
- SystemStatusCode[SystemStatusCode["networkFailure"] = 0] = "networkFailure";
1738
- SystemStatusCode[SystemStatusCode["timeoutFailure"] = -1] = "timeoutFailure";
1739
- SystemStatusCode[SystemStatusCode["contentTypeMismatch"] = -2] = "contentTypeMismatch";
1740
- })(SystemStatusCode || (SystemStatusCode = {}));
1843
+ const SystemStatusCode = {
1844
+ networkFailure: 0,
1845
+ timeoutFailure: -1,
1846
+ contentTypeMismatch: -2
1847
+ };
1741
1848
 
1742
1849
  class Visit {
1850
+ identifier=uuid();
1851
+ timingMetrics={};
1852
+ followedRedirect=false;
1853
+ historyChanged=false;
1854
+ scrolled=false;
1855
+ shouldCacheSnapshot=true;
1856
+ acceptsStreamResponse=false;
1857
+ snapshotCached=false;
1858
+ state=VisitState.initialized;
1859
+ viewTransitioner=new ViewTransitioner;
1743
1860
  constructor(delegate, location, restorationIdentifier, options = {}) {
1744
- this.identifier = uuid();
1745
- this.timingMetrics = {};
1746
- this.followedRedirect = false;
1747
- this.historyChanged = false;
1748
- this.scrolled = false;
1749
- this.shouldCacheSnapshot = true;
1750
- this.acceptsStreamResponse = false;
1751
- this.snapshotCached = false;
1752
- this.state = VisitState.initialized;
1753
1861
  this.delegate = delegate;
1754
1862
  this.location = location;
1755
1863
  this.restorationIdentifier = restorationIdentifier || uuid();
1756
- const {action: action, historyChanged: historyChanged, referrer: referrer, snapshot: snapshot, snapshotHTML: snapshotHTML, response: response, visitCachedSnapshot: visitCachedSnapshot, willRender: willRender, updateHistory: updateHistory, shouldCacheSnapshot: shouldCacheSnapshot, acceptsStreamResponse: acceptsStreamResponse} = Object.assign(Object.assign({}, defaultOptions), options);
1864
+ const {action: action, historyChanged: historyChanged, referrer: referrer, snapshot: snapshot, snapshotHTML: snapshotHTML, response: response, visitCachedSnapshot: visitCachedSnapshot, willRender: willRender, updateHistory: updateHistory, shouldCacheSnapshot: shouldCacheSnapshot, acceptsStreamResponse: acceptsStreamResponse} = {
1865
+ ...defaultOptions,
1866
+ ...options
1867
+ };
1757
1868
  this.action = action;
1758
1869
  this.historyChanged = historyChanged;
1759
1870
  this.referrer = referrer;
@@ -1815,12 +1926,12 @@ class Visit {
1815
1926
  if (this.state == VisitState.started) {
1816
1927
  this.state = VisitState.failed;
1817
1928
  this.adapter.visitFailed(this);
1929
+ this.delegate.visitCompleted(this);
1818
1930
  }
1819
1931
  }
1820
1932
  changeHistory() {
1821
- var _a;
1822
1933
  if (!this.historyChanged && this.updateHistory) {
1823
- const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
1934
+ const actionForHistory = this.location.href === this.referrer?.href ? "replace" : this.action;
1824
1935
  const method = getHistoryMethodForAction(actionForHistory);
1825
1936
  this.history.update(method, this.location, this.restorationIdentifier);
1826
1937
  this.historyChanged = true;
@@ -1867,8 +1978,8 @@ class Visit {
1867
1978
  if (this.shouldCacheSnapshot) this.cacheSnapshot();
1868
1979
  if (this.view.renderPromise) await this.view.renderPromise;
1869
1980
  if (isSuccessful(statusCode) && responseHTML != null) {
1870
- await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);
1871
- this.performScroll();
1981
+ const snapshot = PageSnapshot.fromHTMLString(responseHTML);
1982
+ await this.renderPageSnapshot(snapshot, false);
1872
1983
  this.adapter.visitRendered(this);
1873
1984
  this.complete();
1874
1985
  } else {
@@ -1905,8 +2016,7 @@ class Visit {
1905
2016
  this.adapter.visitRendered(this);
1906
2017
  } else {
1907
2018
  if (this.view.renderPromise) await this.view.renderPromise;
1908
- await this.view.renderPage(snapshot, isPreview, this.willRender, this);
1909
- this.performScroll();
2019
+ await this.renderPageSnapshot(snapshot, isPreview);
1910
2020
  this.adapter.visitRendered(this);
1911
2021
  if (!isPreview) {
1912
2022
  this.complete();
@@ -1916,8 +2026,7 @@ class Visit {
1916
2026
  }
1917
2027
  }
1918
2028
  followRedirect() {
1919
- var _a;
1920
- if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
2029
+ if (this.redirectedToLocation && !this.followedRedirect && this.response?.redirected) {
1921
2030
  this.adapter.visitProposedToLocation(this.redirectedToLocation, {
1922
2031
  action: "replace",
1923
2032
  response: this.response,
@@ -1989,7 +2098,7 @@ class Visit {
1989
2098
  this.finishRequest();
1990
2099
  }
1991
2100
  performScroll() {
1992
- if (!this.scrolled && !this.view.forceReloaded) {
2101
+ if (!this.scrolled && !this.view.forceReloaded && !this.view.snapshot.shouldPreserveScrollPosition) {
1993
2102
  if (this.action == "restore") {
1994
2103
  this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
1995
2104
  } else {
@@ -2019,7 +2128,9 @@ class Visit {
2019
2128
  this.timingMetrics[metric] = (new Date).getTime();
2020
2129
  }
2021
2130
  getTimingMetrics() {
2022
- return Object.assign({}, this.timingMetrics);
2131
+ return {
2132
+ ...this.timingMetrics
2133
+ };
2023
2134
  }
2024
2135
  getHistoryMethodForAction(action) {
2025
2136
  switch (action) {
@@ -2057,6 +2168,12 @@ class Visit {
2057
2168
  await callback();
2058
2169
  delete this.frame;
2059
2170
  }
2171
+ async renderPageSnapshot(snapshot, isPreview) {
2172
+ await this.viewTransitioner.renderChange(this.view.shouldTransitionTo(snapshot), (async () => {
2173
+ await this.view.renderPage(snapshot, isPreview, this.willRender, this);
2174
+ this.performScroll();
2175
+ }));
2176
+ }
2060
2177
  cancelRender() {
2061
2178
  if (this.frame) {
2062
2179
  cancelAnimationFrame(this.frame);
@@ -2070,15 +2187,16 @@ function isSuccessful(statusCode) {
2070
2187
  }
2071
2188
 
2072
2189
  class BrowserAdapter {
2190
+ progressBar=new ProgressBar;
2073
2191
  constructor(session) {
2074
- this.progressBar = new ProgressBar;
2075
- this.showProgressBar = () => {
2076
- this.progressBar.show();
2077
- };
2078
2192
  this.session = session;
2079
2193
  }
2080
2194
  visitProposedToLocation(location, options) {
2081
- this.navigator.startVisit(location, (options === null || options === void 0 ? void 0 : options.restorationIdentifier) || uuid(), options);
2195
+ if (locationIsVisitable(location, this.navigator.rootLocation)) {
2196
+ this.navigator.startVisit(location, options?.restorationIdentifier || uuid(), options);
2197
+ } else {
2198
+ window.location.href = location.toString();
2199
+ }
2082
2200
  }
2083
2201
  visitStarted(visit) {
2084
2202
  this.location = visit.location;
@@ -2113,15 +2231,18 @@ class BrowserAdapter {
2113
2231
  return visit.loadResponse();
2114
2232
  }
2115
2233
  }
2116
- visitRequestFinished(_visit) {
2234
+ visitRequestFinished(_visit) {}
2235
+ visitCompleted(_visit) {
2117
2236
  this.progressBar.setValue(1);
2118
2237
  this.hideVisitProgressBar();
2119
2238
  }
2120
- visitCompleted(_visit) {}
2121
2239
  pageInvalidated(reason) {
2122
2240
  this.reload(reason);
2123
2241
  }
2124
- visitFailed(_visit) {}
2242
+ visitFailed(_visit) {
2243
+ this.progressBar.setValue(1);
2244
+ this.hideVisitProgressBar();
2245
+ }
2125
2246
  visitRendered(_visit) {}
2126
2247
  formSubmissionStarted(_formSubmission) {
2127
2248
  this.progressBar.setValue(0);
@@ -2153,12 +2274,14 @@ class BrowserAdapter {
2153
2274
  delete this.formProgressBarTimeout;
2154
2275
  }
2155
2276
  }
2277
+ showProgressBar=() => {
2278
+ this.progressBar.show();
2279
+ };
2156
2280
  reload(reason) {
2157
- var _a;
2158
2281
  dispatch("turbo:reload", {
2159
2282
  detail: reason
2160
2283
  });
2161
- window.location.href = ((_a = this.location) === null || _a === void 0 ? void 0 : _a.toString()) || window.location.href;
2284
+ window.location.href = this.location?.toString() || window.location.href;
2162
2285
  }
2163
2286
  get navigator() {
2164
2287
  return this.session.navigator;
@@ -2166,16 +2289,9 @@ class BrowserAdapter {
2166
2289
  }
2167
2290
 
2168
2291
  class CacheObserver {
2169
- constructor() {
2170
- this.selector = "[data-turbo-temporary]";
2171
- this.deprecatedSelector = "[data-turbo-cache=false]";
2172
- this.started = false;
2173
- this.removeTemporaryElements = _event => {
2174
- for (const element of this.temporaryElements) {
2175
- element.remove();
2176
- }
2177
- };
2178
- }
2292
+ selector="[data-turbo-temporary]";
2293
+ deprecatedSelector="[data-turbo-cache=false]";
2294
+ started=false;
2179
2295
  start() {
2180
2296
  if (!this.started) {
2181
2297
  this.started = true;
@@ -2188,6 +2304,11 @@ class CacheObserver {
2188
2304
  removeEventListener("turbo:before-cache", this.removeTemporaryElements, false);
2189
2305
  }
2190
2306
  }
2307
+ removeTemporaryElements=_event => {
2308
+ for (const element of this.temporaryElements) {
2309
+ element.remove();
2310
+ }
2311
+ };
2191
2312
  get temporaryElements() {
2192
2313
  return [ ...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation ];
2193
2314
  }
@@ -2216,41 +2337,40 @@ class FrameRedirector {
2216
2337
  this.formSubmitObserver.stop();
2217
2338
  }
2218
2339
  shouldInterceptLinkClick(element, _location, _event) {
2219
- return this.shouldRedirect(element);
2340
+ return this.#shouldRedirect(element);
2220
2341
  }
2221
2342
  linkClickIntercepted(element, url, event) {
2222
- const frame = this.findFrameElement(element);
2343
+ const frame = this.#findFrameElement(element);
2223
2344
  if (frame) {
2224
2345
  frame.delegate.linkClickIntercepted(element, url, event);
2225
2346
  }
2226
2347
  }
2227
2348
  willSubmitForm(element, submitter) {
2228
- return element.closest("turbo-frame") == null && this.shouldSubmit(element, submitter) && this.shouldRedirect(element, submitter);
2349
+ return element.closest("turbo-frame") == null && this.#shouldSubmit(element, submitter) && this.#shouldRedirect(element, submitter);
2229
2350
  }
2230
2351
  formSubmitted(element, submitter) {
2231
- const frame = this.findFrameElement(element, submitter);
2352
+ const frame = this.#findFrameElement(element, submitter);
2232
2353
  if (frame) {
2233
2354
  frame.delegate.formSubmitted(element, submitter);
2234
2355
  }
2235
2356
  }
2236
- shouldSubmit(form, submitter) {
2237
- var _a;
2238
- const action = getAction(form, submitter);
2357
+ #shouldSubmit(form, submitter) {
2358
+ const action = getAction$1(form, submitter);
2239
2359
  const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
2240
- const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/");
2241
- return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
2360
+ const rootLocation = expandURL(meta?.content ?? "/");
2361
+ return this.#shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
2242
2362
  }
2243
- shouldRedirect(element, submitter) {
2363
+ #shouldRedirect(element, submitter) {
2244
2364
  const isNavigatable = element instanceof HTMLFormElement ? this.session.submissionIsNavigatable(element, submitter) : this.session.elementIsNavigatable(element);
2245
2365
  if (isNavigatable) {
2246
- const frame = this.findFrameElement(element, submitter);
2366
+ const frame = this.#findFrameElement(element, submitter);
2247
2367
  return frame ? frame != element.closest("turbo-frame") : false;
2248
2368
  } else {
2249
2369
  return false;
2250
2370
  }
2251
2371
  }
2252
- findFrameElement(element, submitter) {
2253
- const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame");
2372
+ #findFrameElement(element, submitter) {
2373
+ const id = submitter?.getAttribute("data-turbo-frame") || element.getAttribute("data-turbo-frame");
2254
2374
  if (id && id != "_top") {
2255
2375
  const frame = this.element.querySelector(`#${id}:not([disabled])`);
2256
2376
  if (frame instanceof FrameElement) {
@@ -2261,26 +2381,12 @@ class FrameRedirector {
2261
2381
  }
2262
2382
 
2263
2383
  class History {
2384
+ location;
2385
+ restorationIdentifier=uuid();
2386
+ restorationData={};
2387
+ started=false;
2388
+ pageLoaded=false;
2264
2389
  constructor(delegate) {
2265
- this.restorationIdentifier = uuid();
2266
- this.restorationData = {};
2267
- this.started = false;
2268
- this.pageLoaded = false;
2269
- this.onPopState = event => {
2270
- if (this.shouldHandlePopState()) {
2271
- const {turbo: turbo} = event.state || {};
2272
- if (turbo) {
2273
- this.location = new URL(window.location.href);
2274
- const {restorationIdentifier: restorationIdentifier} = turbo;
2275
- this.restorationIdentifier = restorationIdentifier;
2276
- this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
2277
- }
2278
- }
2279
- };
2280
- this.onPageLoad = async _event => {
2281
- await nextMicrotask();
2282
- this.pageLoaded = true;
2283
- };
2284
2390
  this.delegate = delegate;
2285
2391
  }
2286
2392
  start() {
@@ -2320,12 +2426,14 @@ class History {
2320
2426
  updateRestorationData(additionalData) {
2321
2427
  const {restorationIdentifier: restorationIdentifier} = this;
2322
2428
  const restorationData = this.restorationData[restorationIdentifier];
2323
- this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);
2429
+ this.restorationData[restorationIdentifier] = {
2430
+ ...restorationData,
2431
+ ...additionalData
2432
+ };
2324
2433
  }
2325
2434
  assumeControlOfScrollRestoration() {
2326
- var _a;
2327
2435
  if (!this.previousScrollRestoration) {
2328
- this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto";
2436
+ this.previousScrollRestoration = history.scrollRestoration ?? "auto";
2329
2437
  history.scrollRestoration = "manual";
2330
2438
  }
2331
2439
  }
@@ -2335,6 +2443,21 @@ class History {
2335
2443
  delete this.previousScrollRestoration;
2336
2444
  }
2337
2445
  }
2446
+ onPopState=event => {
2447
+ if (this.shouldHandlePopState()) {
2448
+ const {turbo: turbo} = event.state || {};
2449
+ if (turbo) {
2450
+ this.location = new URL(window.location.href);
2451
+ const {restorationIdentifier: restorationIdentifier} = turbo;
2452
+ this.restorationIdentifier = restorationIdentifier;
2453
+ this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
2454
+ }
2455
+ }
2456
+ };
2457
+ onPageLoad=async _event => {
2458
+ await nextMicrotask();
2459
+ this.pageLoaded = true;
2460
+ };
2338
2461
  shouldHandlePopState() {
2339
2462
  return this.pageIsLoaded();
2340
2463
  }
@@ -2349,18 +2472,15 @@ class Navigator {
2349
2472
  }
2350
2473
  proposeVisit(location, options = {}) {
2351
2474
  if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {
2352
- if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {
2353
- this.delegate.visitProposedToLocation(location, options);
2354
- } else {
2355
- window.location.href = location.toString();
2356
- }
2475
+ this.delegate.visitProposedToLocation(location, options);
2357
2476
  }
2358
2477
  }
2359
2478
  startVisit(locatable, restorationIdentifier, options = {}) {
2360
2479
  this.stop();
2361
- this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({
2362
- referrer: this.location
2363
- }, options));
2480
+ this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, {
2481
+ referrer: this.location,
2482
+ ...options
2483
+ });
2364
2484
  this.currentVisit.start();
2365
2485
  }
2366
2486
  submitForm(form, submitter) {
@@ -2384,6 +2504,9 @@ class Navigator {
2384
2504
  get view() {
2385
2505
  return this.delegate.view;
2386
2506
  }
2507
+ get rootLocation() {
2508
+ return this.view.snapshot.rootLocation;
2509
+ }
2387
2510
  get history() {
2388
2511
  return this.delegate.history;
2389
2512
  }
@@ -2401,7 +2524,7 @@ class Navigator {
2401
2524
  this.view.clearSnapshotCache();
2402
2525
  }
2403
2526
  const {statusCode: statusCode, redirected: redirected} = fetchResponse;
2404
- const action = this.getActionForFormSubmission(formSubmission);
2527
+ const action = this.#getActionForFormSubmission(formSubmission, fetchResponse);
2405
2528
  const visitOptions = {
2406
2529
  action: action,
2407
2530
  shouldCacheSnapshot: shouldCacheSnapshot,
@@ -2424,7 +2547,9 @@ class Navigator {
2424
2547
  } else {
2425
2548
  await this.view.renderPage(snapshot, false, true, this.currentVisit);
2426
2549
  }
2427
- this.view.scrollToTop();
2550
+ if (!snapshot.shouldPreserveScrollPosition) {
2551
+ this.view.scrollToTop();
2552
+ }
2428
2553
  this.view.clearSnapshotCache();
2429
2554
  }
2430
2555
  }
@@ -2457,35 +2582,27 @@ class Navigator {
2457
2582
  get restorationIdentifier() {
2458
2583
  return this.history.restorationIdentifier;
2459
2584
  }
2460
- getActionForFormSubmission({submitter: submitter, formElement: formElement}) {
2461
- return getVisitAction(submitter, formElement) || "advance";
2585
+ #getActionForFormSubmission(formSubmission, fetchResponse) {
2586
+ const {submitter: submitter, formElement: formElement} = formSubmission;
2587
+ return getVisitAction(submitter, formElement) || this.#getDefaultAction(fetchResponse);
2588
+ }
2589
+ #getDefaultAction(fetchResponse) {
2590
+ const sameLocationRedirect = fetchResponse.redirected && fetchResponse.location.href === this.location?.href;
2591
+ return sameLocationRedirect ? "replace" : "advance";
2462
2592
  }
2463
2593
  }
2464
2594
 
2465
- var PageStage;
2466
-
2467
- (function(PageStage) {
2468
- PageStage[PageStage["initial"] = 0] = "initial";
2469
- PageStage[PageStage["loading"] = 1] = "loading";
2470
- PageStage[PageStage["interactive"] = 2] = "interactive";
2471
- PageStage[PageStage["complete"] = 3] = "complete";
2472
- })(PageStage || (PageStage = {}));
2595
+ const PageStage = {
2596
+ initial: 0,
2597
+ loading: 1,
2598
+ interactive: 2,
2599
+ complete: 3
2600
+ };
2473
2601
 
2474
2602
  class PageObserver {
2603
+ stage=PageStage.initial;
2604
+ started=false;
2475
2605
  constructor(delegate) {
2476
- this.stage = PageStage.initial;
2477
- this.started = false;
2478
- this.interpretReadyState = () => {
2479
- const {readyState: readyState} = this;
2480
- if (readyState == "interactive") {
2481
- this.pageIsInteractive();
2482
- } else if (readyState == "complete") {
2483
- this.pageIsComplete();
2484
- }
2485
- };
2486
- this.pageWillUnload = () => {
2487
- this.delegate.pageWillUnload();
2488
- };
2489
2606
  this.delegate = delegate;
2490
2607
  }
2491
2608
  start() {
@@ -2505,6 +2622,14 @@ class PageObserver {
2505
2622
  this.started = false;
2506
2623
  }
2507
2624
  }
2625
+ interpretReadyState=() => {
2626
+ const {readyState: readyState} = this;
2627
+ if (readyState == "interactive") {
2628
+ this.pageIsInteractive();
2629
+ } else if (readyState == "complete") {
2630
+ this.pageIsComplete();
2631
+ }
2632
+ };
2508
2633
  pageIsInteractive() {
2509
2634
  if (this.stage == PageStage.loading) {
2510
2635
  this.stage = PageStage.interactive;
@@ -2518,20 +2643,17 @@ class PageObserver {
2518
2643
  this.delegate.pageLoaded();
2519
2644
  }
2520
2645
  }
2646
+ pageWillUnload=() => {
2647
+ this.delegate.pageWillUnload();
2648
+ };
2521
2649
  get readyState() {
2522
2650
  return document.readyState;
2523
2651
  }
2524
2652
  }
2525
2653
 
2526
2654
  class ScrollObserver {
2655
+ started=false;
2527
2656
  constructor(delegate) {
2528
- this.started = false;
2529
- this.onScroll = () => {
2530
- this.updatePosition({
2531
- x: window.pageXOffset,
2532
- y: window.pageYOffset
2533
- });
2534
- };
2535
2657
  this.delegate = delegate;
2536
2658
  }
2537
2659
  start() {
@@ -2547,6 +2669,12 @@ class ScrollObserver {
2547
2669
  this.started = false;
2548
2670
  }
2549
2671
  }
2672
+ onScroll=() => {
2673
+ this.updatePosition({
2674
+ x: window.pageXOffset,
2675
+ y: window.pageYOffset
2676
+ });
2677
+ };
2550
2678
  updatePosition(position) {
2551
2679
  this.delegate.scrollPositionChanged(position);
2552
2680
  }
@@ -2554,7 +2682,13 @@ class ScrollObserver {
2554
2682
 
2555
2683
  class StreamMessageRenderer {
2556
2684
  render({fragment: fragment}) {
2557
- Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), (() => document.documentElement.appendChild(fragment)));
2685
+ Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), (() => {
2686
+ withAutofocusFromFragment(fragment, (() => {
2687
+ withPreservedFocus((() => {
2688
+ document.documentElement.appendChild(fragment);
2689
+ }));
2690
+ }));
2691
+ }));
2558
2692
  }
2559
2693
  enteringBardo(currentPermanentElement, newPermanentElement) {
2560
2694
  newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
@@ -2577,34 +2711,68 @@ function getPermanentElementMapForFragment(fragment) {
2577
2711
  return permanentElementMap;
2578
2712
  }
2579
2713
 
2580
- class StreamObserver {
2581
- constructor(delegate) {
2582
- this.sources = new Set;
2583
- this.started = false;
2584
- this.inspectFetchResponse = event => {
2585
- const response = fetchResponseFromEvent(event);
2586
- if (response && fetchResponseIsStream(response)) {
2587
- event.preventDefault();
2588
- this.receiveMessageResponse(response);
2589
- }
2590
- };
2591
- this.receiveMessageEvent = event => {
2592
- if (this.started && typeof event.data == "string") {
2593
- this.receiveMessageHTML(event.data);
2594
- }
2595
- };
2596
- this.delegate = delegate;
2597
- }
2598
- start() {
2599
- if (!this.started) {
2600
- this.started = true;
2601
- addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
2714
+ async function withAutofocusFromFragment(fragment, callback) {
2715
+ const generatedID = `turbo-stream-autofocus-${uuid()}`;
2716
+ const turboStreams = fragment.querySelectorAll("turbo-stream");
2717
+ const elementWithAutofocus = firstAutofocusableElementInStreams(turboStreams);
2718
+ let willAutofocusId = null;
2719
+ if (elementWithAutofocus) {
2720
+ if (elementWithAutofocus.id) {
2721
+ willAutofocusId = elementWithAutofocus.id;
2722
+ } else {
2723
+ willAutofocusId = generatedID;
2602
2724
  }
2725
+ elementWithAutofocus.id = willAutofocusId;
2603
2726
  }
2604
- stop() {
2605
- if (this.started) {
2606
- this.started = false;
2607
- removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
2727
+ callback();
2728
+ await nextAnimationFrame();
2729
+ const hasNoActiveElement = document.activeElement == null || document.activeElement == document.body;
2730
+ if (hasNoActiveElement && willAutofocusId) {
2731
+ const elementToAutofocus = document.getElementById(willAutofocusId);
2732
+ if (elementIsFocusable(elementToAutofocus)) {
2733
+ elementToAutofocus.focus();
2734
+ }
2735
+ if (elementToAutofocus && elementToAutofocus.id == generatedID) {
2736
+ elementToAutofocus.removeAttribute("id");
2737
+ }
2738
+ }
2739
+ }
2740
+
2741
+ async function withPreservedFocus(callback) {
2742
+ const [activeElementBeforeRender, activeElementAfterRender] = await around(callback, (() => document.activeElement));
2743
+ const restoreFocusTo = activeElementBeforeRender && activeElementBeforeRender.id;
2744
+ if (restoreFocusTo) {
2745
+ const elementToFocus = document.getElementById(restoreFocusTo);
2746
+ if (elementIsFocusable(elementToFocus) && elementToFocus != activeElementAfterRender) {
2747
+ elementToFocus.focus();
2748
+ }
2749
+ }
2750
+ }
2751
+
2752
+ function firstAutofocusableElementInStreams(nodeListOfStreamElements) {
2753
+ for (const streamElement of nodeListOfStreamElements) {
2754
+ const elementWithAutofocus = queryAutofocusableElement(streamElement.templateElement.content);
2755
+ if (elementWithAutofocus) return elementWithAutofocus;
2756
+ }
2757
+ return null;
2758
+ }
2759
+
2760
+ class StreamObserver {
2761
+ sources=new Set;
2762
+ #started=false;
2763
+ constructor(delegate) {
2764
+ this.delegate = delegate;
2765
+ }
2766
+ start() {
2767
+ if (!this.#started) {
2768
+ this.#started = true;
2769
+ addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
2770
+ }
2771
+ }
2772
+ stop() {
2773
+ if (this.#started) {
2774
+ this.#started = false;
2775
+ removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
2608
2776
  }
2609
2777
  }
2610
2778
  connectStreamSource(source) {
@@ -2622,6 +2790,18 @@ class StreamObserver {
2622
2790
  streamSourceIsConnected(source) {
2623
2791
  return this.sources.has(source);
2624
2792
  }
2793
+ inspectFetchResponse=event => {
2794
+ const response = fetchResponseFromEvent(event);
2795
+ if (response && fetchResponseIsStream(response)) {
2796
+ event.preventDefault();
2797
+ this.receiveMessageResponse(response);
2798
+ }
2799
+ };
2800
+ receiveMessageEvent=event => {
2801
+ if (this.#started && typeof event.data == "string") {
2802
+ this.receiveMessageHTML(event.data);
2803
+ }
2804
+ };
2625
2805
  async receiveMessageResponse(response) {
2626
2806
  const html = await response.responseHTML;
2627
2807
  if (html) {
@@ -2634,16 +2814,14 @@ class StreamObserver {
2634
2814
  }
2635
2815
 
2636
2816
  function fetchResponseFromEvent(event) {
2637
- var _a;
2638
- const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;
2817
+ const fetchResponse = event.detail?.fetchResponse;
2639
2818
  if (fetchResponse instanceof FetchResponse) {
2640
2819
  return fetchResponse;
2641
2820
  }
2642
2821
  }
2643
2822
 
2644
2823
  function fetchResponseIsStream(response) {
2645
- var _a;
2646
- const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
2824
+ const contentType = response.contentType ?? "";
2647
2825
  return contentType.startsWith(StreamMessage.contentType);
2648
2826
  }
2649
2827
 
@@ -2678,6 +2856,575 @@ class ErrorRenderer extends Renderer {
2678
2856
  }
2679
2857
  }
2680
2858
 
2859
+ let EMPTY_SET = new Set;
2860
+
2861
+ function morph(oldNode, newContent, config = {}) {
2862
+ if (oldNode instanceof Document) {
2863
+ oldNode = oldNode.documentElement;
2864
+ }
2865
+ if (typeof newContent === "string") {
2866
+ newContent = parseContent(newContent);
2867
+ }
2868
+ let normalizedContent = normalizeContent(newContent);
2869
+ let ctx = createMorphContext(oldNode, normalizedContent, config);
2870
+ return morphNormalizedContent(oldNode, normalizedContent, ctx);
2871
+ }
2872
+
2873
+ function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {
2874
+ if (ctx.head.block) {
2875
+ let oldHead = oldNode.querySelector("head");
2876
+ let newHead = normalizedNewContent.querySelector("head");
2877
+ if (oldHead && newHead) {
2878
+ let promises = handleHeadElement(newHead, oldHead, ctx);
2879
+ Promise.all(promises).then((function() {
2880
+ morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {
2881
+ head: {
2882
+ block: false,
2883
+ ignore: true
2884
+ }
2885
+ }));
2886
+ }));
2887
+ return;
2888
+ }
2889
+ }
2890
+ if (ctx.morphStyle === "innerHTML") {
2891
+ morphChildren(normalizedNewContent, oldNode, ctx);
2892
+ return oldNode.children;
2893
+ } else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) {
2894
+ let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);
2895
+ let previousSibling = bestMatch?.previousSibling;
2896
+ let nextSibling = bestMatch?.nextSibling;
2897
+ let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);
2898
+ if (bestMatch) {
2899
+ return insertSiblings(previousSibling, morphedNode, nextSibling);
2900
+ } else {
2901
+ return [];
2902
+ }
2903
+ } else {
2904
+ throw "Do not understand how to morph style " + ctx.morphStyle;
2905
+ }
2906
+ }
2907
+
2908
+ function morphOldNodeTo(oldNode, newContent, ctx) {
2909
+ if (ctx.ignoreActive && oldNode === document.activeElement) ; else if (newContent == null) {
2910
+ if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return;
2911
+ oldNode.remove();
2912
+ ctx.callbacks.afterNodeRemoved(oldNode);
2913
+ return null;
2914
+ } else if (!isSoftMatch(oldNode, newContent)) {
2915
+ if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return;
2916
+ if (ctx.callbacks.beforeNodeAdded(newContent) === false) return;
2917
+ oldNode.parentElement.replaceChild(newContent, oldNode);
2918
+ ctx.callbacks.afterNodeAdded(newContent);
2919
+ ctx.callbacks.afterNodeRemoved(oldNode);
2920
+ return newContent;
2921
+ } else {
2922
+ if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return;
2923
+ if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) ; else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") {
2924
+ handleHeadElement(newContent, oldNode, ctx);
2925
+ } else {
2926
+ syncNodeFrom(newContent, oldNode);
2927
+ morphChildren(newContent, oldNode, ctx);
2928
+ }
2929
+ ctx.callbacks.afterNodeMorphed(oldNode, newContent);
2930
+ return oldNode;
2931
+ }
2932
+ }
2933
+
2934
+ function morphChildren(newParent, oldParent, ctx) {
2935
+ let nextNewChild = newParent.firstChild;
2936
+ let insertionPoint = oldParent.firstChild;
2937
+ let newChild;
2938
+ while (nextNewChild) {
2939
+ newChild = nextNewChild;
2940
+ nextNewChild = newChild.nextSibling;
2941
+ if (insertionPoint == null) {
2942
+ if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
2943
+ oldParent.appendChild(newChild);
2944
+ ctx.callbacks.afterNodeAdded(newChild);
2945
+ removeIdsFromConsideration(ctx, newChild);
2946
+ continue;
2947
+ }
2948
+ if (isIdSetMatch(newChild, insertionPoint, ctx)) {
2949
+ morphOldNodeTo(insertionPoint, newChild, ctx);
2950
+ insertionPoint = insertionPoint.nextSibling;
2951
+ removeIdsFromConsideration(ctx, newChild);
2952
+ continue;
2953
+ }
2954
+ let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);
2955
+ if (idSetMatch) {
2956
+ insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);
2957
+ morphOldNodeTo(idSetMatch, newChild, ctx);
2958
+ removeIdsFromConsideration(ctx, newChild);
2959
+ continue;
2960
+ }
2961
+ let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);
2962
+ if (softMatch) {
2963
+ insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);
2964
+ morphOldNodeTo(softMatch, newChild, ctx);
2965
+ removeIdsFromConsideration(ctx, newChild);
2966
+ continue;
2967
+ }
2968
+ if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
2969
+ oldParent.insertBefore(newChild, insertionPoint);
2970
+ ctx.callbacks.afterNodeAdded(newChild);
2971
+ removeIdsFromConsideration(ctx, newChild);
2972
+ }
2973
+ while (insertionPoint !== null) {
2974
+ let tempNode = insertionPoint;
2975
+ insertionPoint = insertionPoint.nextSibling;
2976
+ removeNode(tempNode, ctx);
2977
+ }
2978
+ }
2979
+
2980
+ function syncNodeFrom(from, to) {
2981
+ let type = from.nodeType;
2982
+ if (type === 1) {
2983
+ const fromAttributes = from.attributes;
2984
+ const toAttributes = to.attributes;
2985
+ for (const fromAttribute of fromAttributes) {
2986
+ if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {
2987
+ to.setAttribute(fromAttribute.name, fromAttribute.value);
2988
+ }
2989
+ }
2990
+ for (const toAttribute of toAttributes) {
2991
+ if (!from.hasAttribute(toAttribute.name)) {
2992
+ to.removeAttribute(toAttribute.name);
2993
+ }
2994
+ }
2995
+ }
2996
+ if (type === 8 || type === 3) {
2997
+ if (to.nodeValue !== from.nodeValue) {
2998
+ to.nodeValue = from.nodeValue;
2999
+ }
3000
+ }
3001
+ if (from instanceof HTMLInputElement && to instanceof HTMLInputElement && from.type !== "file") {
3002
+ to.value = from.value || "";
3003
+ syncAttribute(from, to, "value");
3004
+ syncAttribute(from, to, "checked");
3005
+ syncAttribute(from, to, "disabled");
3006
+ } else if (from instanceof HTMLOptionElement) {
3007
+ syncAttribute(from, to, "selected");
3008
+ } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {
3009
+ let fromValue = from.value;
3010
+ let toValue = to.value;
3011
+ if (fromValue !== toValue) {
3012
+ to.value = fromValue;
3013
+ }
3014
+ if (to.firstChild && to.firstChild.nodeValue !== fromValue) {
3015
+ to.firstChild.nodeValue = fromValue;
3016
+ }
3017
+ }
3018
+ }
3019
+
3020
+ function syncAttribute(from, to, attributeName) {
3021
+ if (from[attributeName] !== to[attributeName]) {
3022
+ if (from[attributeName]) {
3023
+ to.setAttribute(attributeName, from[attributeName]);
3024
+ } else {
3025
+ to.removeAttribute(attributeName);
3026
+ }
3027
+ }
3028
+ }
3029
+
3030
+ function handleHeadElement(newHeadTag, currentHead, ctx) {
3031
+ let added = [];
3032
+ let removed = [];
3033
+ let preserved = [];
3034
+ let nodesToAppend = [];
3035
+ let headMergeStyle = ctx.head.style;
3036
+ let srcToNewHeadNodes = new Map;
3037
+ for (const newHeadChild of newHeadTag.children) {
3038
+ srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
3039
+ }
3040
+ for (const currentHeadElt of currentHead.children) {
3041
+ let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
3042
+ let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
3043
+ let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
3044
+ if (inNewContent || isPreserved) {
3045
+ if (isReAppended) {
3046
+ removed.push(currentHeadElt);
3047
+ } else {
3048
+ srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
3049
+ preserved.push(currentHeadElt);
3050
+ }
3051
+ } else {
3052
+ if (headMergeStyle === "append") {
3053
+ if (isReAppended) {
3054
+ removed.push(currentHeadElt);
3055
+ nodesToAppend.push(currentHeadElt);
3056
+ }
3057
+ } else {
3058
+ if (ctx.head.shouldRemove(currentHeadElt) !== false) {
3059
+ removed.push(currentHeadElt);
3060
+ }
3061
+ }
3062
+ }
3063
+ }
3064
+ nodesToAppend.push(...srcToNewHeadNodes.values());
3065
+ let promises = [];
3066
+ for (const newNode of nodesToAppend) {
3067
+ let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;
3068
+ if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {
3069
+ if (newElt.href || newElt.src) {
3070
+ let resolve = null;
3071
+ let promise = new Promise((function(_resolve) {
3072
+ resolve = _resolve;
3073
+ }));
3074
+ newElt.addEventListener("load", (function() {
3075
+ resolve();
3076
+ }));
3077
+ promises.push(promise);
3078
+ }
3079
+ currentHead.appendChild(newElt);
3080
+ ctx.callbacks.afterNodeAdded(newElt);
3081
+ added.push(newElt);
3082
+ }
3083
+ }
3084
+ for (const removedElement of removed) {
3085
+ if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
3086
+ currentHead.removeChild(removedElement);
3087
+ ctx.callbacks.afterNodeRemoved(removedElement);
3088
+ }
3089
+ }
3090
+ ctx.head.afterHeadMorphed(currentHead, {
3091
+ added: added,
3092
+ kept: preserved,
3093
+ removed: removed
3094
+ });
3095
+ return promises;
3096
+ }
3097
+
3098
+ function noOp() {}
3099
+
3100
+ function createMorphContext(oldNode, newContent, config) {
3101
+ return {
3102
+ target: oldNode,
3103
+ newContent: newContent,
3104
+ config: config,
3105
+ morphStyle: config.morphStyle,
3106
+ ignoreActive: config.ignoreActive,
3107
+ idMap: createIdMap(oldNode, newContent),
3108
+ deadIds: new Set,
3109
+ callbacks: Object.assign({
3110
+ beforeNodeAdded: noOp,
3111
+ afterNodeAdded: noOp,
3112
+ beforeNodeMorphed: noOp,
3113
+ afterNodeMorphed: noOp,
3114
+ beforeNodeRemoved: noOp,
3115
+ afterNodeRemoved: noOp
3116
+ }, config.callbacks),
3117
+ head: Object.assign({
3118
+ style: "merge",
3119
+ shouldPreserve: function(elt) {
3120
+ return elt.getAttribute("im-preserve") === "true";
3121
+ },
3122
+ shouldReAppend: function(elt) {
3123
+ return elt.getAttribute("im-re-append") === "true";
3124
+ },
3125
+ shouldRemove: noOp,
3126
+ afterHeadMorphed: noOp
3127
+ }, config.head)
3128
+ };
3129
+ }
3130
+
3131
+ function isIdSetMatch(node1, node2, ctx) {
3132
+ if (node1 == null || node2 == null) {
3133
+ return false;
3134
+ }
3135
+ if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {
3136
+ if (node1.id !== "" && node1.id === node2.id) {
3137
+ return true;
3138
+ } else {
3139
+ return getIdIntersectionCount(ctx, node1, node2) > 0;
3140
+ }
3141
+ }
3142
+ return false;
3143
+ }
3144
+
3145
+ function isSoftMatch(node1, node2) {
3146
+ if (node1 == null || node2 == null) {
3147
+ return false;
3148
+ }
3149
+ return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName;
3150
+ }
3151
+
3152
+ function removeNodesBetween(startInclusive, endExclusive, ctx) {
3153
+ while (startInclusive !== endExclusive) {
3154
+ let tempNode = startInclusive;
3155
+ startInclusive = startInclusive.nextSibling;
3156
+ removeNode(tempNode, ctx);
3157
+ }
3158
+ removeIdsFromConsideration(ctx, endExclusive);
3159
+ return endExclusive.nextSibling;
3160
+ }
3161
+
3162
+ function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
3163
+ let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);
3164
+ let potentialMatch = null;
3165
+ if (newChildPotentialIdCount > 0) {
3166
+ let potentialMatch = insertionPoint;
3167
+ let otherMatchCount = 0;
3168
+ while (potentialMatch != null) {
3169
+ if (isIdSetMatch(newChild, potentialMatch, ctx)) {
3170
+ return potentialMatch;
3171
+ }
3172
+ otherMatchCount += getIdIntersectionCount(ctx, potentialMatch, newContent);
3173
+ if (otherMatchCount > newChildPotentialIdCount) {
3174
+ return null;
3175
+ }
3176
+ potentialMatch = potentialMatch.nextSibling;
3177
+ }
3178
+ }
3179
+ return potentialMatch;
3180
+ }
3181
+
3182
+ function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
3183
+ let potentialSoftMatch = insertionPoint;
3184
+ let nextSibling = newChild.nextSibling;
3185
+ let siblingSoftMatchCount = 0;
3186
+ while (potentialSoftMatch != null) {
3187
+ if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {
3188
+ return null;
3189
+ }
3190
+ if (isSoftMatch(newChild, potentialSoftMatch)) {
3191
+ return potentialSoftMatch;
3192
+ }
3193
+ if (isSoftMatch(nextSibling, potentialSoftMatch)) {
3194
+ siblingSoftMatchCount++;
3195
+ nextSibling = nextSibling.nextSibling;
3196
+ if (siblingSoftMatchCount >= 2) {
3197
+ return null;
3198
+ }
3199
+ }
3200
+ potentialSoftMatch = potentialSoftMatch.nextSibling;
3201
+ }
3202
+ return potentialSoftMatch;
3203
+ }
3204
+
3205
+ function parseContent(newContent) {
3206
+ let parser = new DOMParser;
3207
+ let contentWithSvgsRemoved = newContent.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim, "");
3208
+ if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
3209
+ let content = parser.parseFromString(newContent, "text/html");
3210
+ if (contentWithSvgsRemoved.match(/<\/html>/)) {
3211
+ content.generatedByIdiomorph = true;
3212
+ return content;
3213
+ } else {
3214
+ let htmlElement = content.firstChild;
3215
+ if (htmlElement) {
3216
+ htmlElement.generatedByIdiomorph = true;
3217
+ return htmlElement;
3218
+ } else {
3219
+ return null;
3220
+ }
3221
+ }
3222
+ } else {
3223
+ let responseDoc = parser.parseFromString("<body><template>" + newContent + "</template></body>", "text/html");
3224
+ let content = responseDoc.body.querySelector("template").content;
3225
+ content.generatedByIdiomorph = true;
3226
+ return content;
3227
+ }
3228
+ }
3229
+
3230
+ function normalizeContent(newContent) {
3231
+ if (newContent == null) {
3232
+ const dummyParent = document.createElement("div");
3233
+ return dummyParent;
3234
+ } else if (newContent.generatedByIdiomorph) {
3235
+ return newContent;
3236
+ } else if (newContent instanceof Node) {
3237
+ const dummyParent = document.createElement("div");
3238
+ dummyParent.append(newContent);
3239
+ return dummyParent;
3240
+ } else {
3241
+ const dummyParent = document.createElement("div");
3242
+ for (const elt of [ ...newContent ]) {
3243
+ dummyParent.append(elt);
3244
+ }
3245
+ return dummyParent;
3246
+ }
3247
+ }
3248
+
3249
+ function insertSiblings(previousSibling, morphedNode, nextSibling) {
3250
+ let stack = [];
3251
+ let added = [];
3252
+ while (previousSibling != null) {
3253
+ stack.push(previousSibling);
3254
+ previousSibling = previousSibling.previousSibling;
3255
+ }
3256
+ while (stack.length > 0) {
3257
+ let node = stack.pop();
3258
+ added.push(node);
3259
+ morphedNode.parentElement.insertBefore(node, morphedNode);
3260
+ }
3261
+ added.push(morphedNode);
3262
+ while (nextSibling != null) {
3263
+ stack.push(nextSibling);
3264
+ added.push(nextSibling);
3265
+ nextSibling = nextSibling.nextSibling;
3266
+ }
3267
+ while (stack.length > 0) {
3268
+ morphedNode.parentElement.insertBefore(stack.pop(), morphedNode.nextSibling);
3269
+ }
3270
+ return added;
3271
+ }
3272
+
3273
+ function findBestNodeMatch(newContent, oldNode, ctx) {
3274
+ let currentElement;
3275
+ currentElement = newContent.firstChild;
3276
+ let bestElement = currentElement;
3277
+ let score = 0;
3278
+ while (currentElement) {
3279
+ let newScore = scoreElement(currentElement, oldNode, ctx);
3280
+ if (newScore > score) {
3281
+ bestElement = currentElement;
3282
+ score = newScore;
3283
+ }
3284
+ currentElement = currentElement.nextSibling;
3285
+ }
3286
+ return bestElement;
3287
+ }
3288
+
3289
+ function scoreElement(node1, node2, ctx) {
3290
+ if (isSoftMatch(node1, node2)) {
3291
+ return .5 + getIdIntersectionCount(ctx, node1, node2);
3292
+ }
3293
+ return 0;
3294
+ }
3295
+
3296
+ function removeNode(tempNode, ctx) {
3297
+ removeIdsFromConsideration(ctx, tempNode);
3298
+ if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;
3299
+ tempNode.remove();
3300
+ ctx.callbacks.afterNodeRemoved(tempNode);
3301
+ }
3302
+
3303
+ function isIdInConsideration(ctx, id) {
3304
+ return !ctx.deadIds.has(id);
3305
+ }
3306
+
3307
+ function idIsWithinNode(ctx, id, targetNode) {
3308
+ let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;
3309
+ return idSet.has(id);
3310
+ }
3311
+
3312
+ function removeIdsFromConsideration(ctx, node) {
3313
+ let idSet = ctx.idMap.get(node) || EMPTY_SET;
3314
+ for (const id of idSet) {
3315
+ ctx.deadIds.add(id);
3316
+ }
3317
+ }
3318
+
3319
+ function getIdIntersectionCount(ctx, node1, node2) {
3320
+ let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;
3321
+ let matchCount = 0;
3322
+ for (const id of sourceSet) {
3323
+ if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {
3324
+ ++matchCount;
3325
+ }
3326
+ }
3327
+ return matchCount;
3328
+ }
3329
+
3330
+ function populateIdMapForNode(node, idMap) {
3331
+ let nodeParent = node.parentElement;
3332
+ let idElements = node.querySelectorAll("[id]");
3333
+ for (const elt of idElements) {
3334
+ let current = elt;
3335
+ while (current !== nodeParent && current != null) {
3336
+ let idSet = idMap.get(current);
3337
+ if (idSet == null) {
3338
+ idSet = new Set;
3339
+ idMap.set(current, idSet);
3340
+ }
3341
+ idSet.add(elt.id);
3342
+ current = current.parentElement;
3343
+ }
3344
+ }
3345
+ }
3346
+
3347
+ function createIdMap(oldContent, newContent) {
3348
+ let idMap = new Map;
3349
+ populateIdMapForNode(oldContent, idMap);
3350
+ populateIdMapForNode(newContent, idMap);
3351
+ return idMap;
3352
+ }
3353
+
3354
+ var idiomorph = {
3355
+ morph: morph
3356
+ };
3357
+
3358
+ class MorphRenderer extends Renderer {
3359
+ async render() {
3360
+ if (this.willRender) await this.#morphBody();
3361
+ }
3362
+ get renderMethod() {
3363
+ return "morph";
3364
+ }
3365
+ async #morphBody() {
3366
+ this.#morphElements(this.currentElement, this.newElement);
3367
+ this.#reloadRemoteFrames();
3368
+ dispatch("turbo:morph", {
3369
+ detail: {
3370
+ currentElement: this.currentElement,
3371
+ newElement: this.newElement
3372
+ }
3373
+ });
3374
+ }
3375
+ #morphElements(currentElement, newElement, morphStyle = "outerHTML") {
3376
+ this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
3377
+ idiomorph.morph(currentElement, newElement, {
3378
+ morphStyle: morphStyle,
3379
+ callbacks: {
3380
+ beforeNodeAdded: this.#shouldAddElement,
3381
+ beforeNodeMorphed: this.#shouldMorphElement,
3382
+ beforeNodeRemoved: this.#shouldRemoveElement
3383
+ }
3384
+ });
3385
+ }
3386
+ #shouldAddElement=node => !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id));
3387
+ #shouldMorphElement=(oldNode, newNode) => {
3388
+ if (oldNode instanceof HTMLElement) {
3389
+ return !oldNode.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(oldNode));
3390
+ } else {
3391
+ return true;
3392
+ }
3393
+ };
3394
+ #shouldRemoveElement=node => this.#shouldMorphElement(node);
3395
+ #reloadRemoteFrames() {
3396
+ this.#remoteFrames().forEach((frame => {
3397
+ if (this.#isFrameReloadedWithMorph(frame)) {
3398
+ this.#renderFrameWithMorph(frame);
3399
+ frame.reload();
3400
+ }
3401
+ }));
3402
+ }
3403
+ #renderFrameWithMorph(frame) {
3404
+ frame.addEventListener("turbo:before-frame-render", (event => {
3405
+ event.detail.render = this.#morphFrameUpdate;
3406
+ }), {
3407
+ once: true
3408
+ });
3409
+ }
3410
+ #morphFrameUpdate=(currentElement, newElement) => {
3411
+ dispatch("turbo:before-frame-morph", {
3412
+ target: currentElement,
3413
+ detail: {
3414
+ currentElement: currentElement,
3415
+ newElement: newElement
3416
+ }
3417
+ });
3418
+ this.#morphElements(currentElement, newElement.children, "innerHTML");
3419
+ };
3420
+ #isFrameReloadedWithMorph(element) {
3421
+ return element.src && element.refresh === "morph";
3422
+ }
3423
+ #remoteFrames() {
3424
+ return Array.from(document.querySelectorAll("turbo-frame[src]")).filter((frame => !frame.closest("[data-turbo-permanent]")));
3425
+ }
3426
+ }
3427
+
2681
3428
  class PageRenderer extends Renderer {
2682
3429
  static renderElement(currentElement, newElement) {
2683
3430
  if (document.body && newElement instanceof HTMLBodyElement) {
@@ -2702,6 +3449,7 @@ class PageRenderer extends Renderer {
2702
3449
  }
2703
3450
  }
2704
3451
  async prepareToRender() {
3452
+ this.#setLanguage();
2705
3453
  await this.mergeHead();
2706
3454
  }
2707
3455
  async render() {
@@ -2724,6 +3472,15 @@ class PageRenderer extends Renderer {
2724
3472
  get newElement() {
2725
3473
  return this.newSnapshot.element;
2726
3474
  }
3475
+ #setLanguage() {
3476
+ const {documentElement: documentElement} = this.currentSnapshot;
3477
+ const {lang: lang} = this.newSnapshot;
3478
+ if (lang) {
3479
+ documentElement.setAttribute("lang", lang);
3480
+ } else {
3481
+ documentElement.removeAttribute("lang");
3482
+ }
3483
+ }
2727
3484
  async mergeHead() {
2728
3485
  const mergedHeadElements = this.mergeProvisionalElements();
2729
3486
  const newStylesheetElements = this.copyNewHeadStylesheetElements();
@@ -2823,9 +3580,9 @@ class PageRenderer extends Renderer {
2823
3580
  }
2824
3581
 
2825
3582
  class SnapshotCache {
3583
+ keys=[];
3584
+ snapshots={};
2826
3585
  constructor(size) {
2827
- this.keys = [];
2828
- this.snapshots = {};
2829
3586
  this.size = size;
2830
3587
  }
2831
3588
  has(location) {
@@ -2867,23 +3624,25 @@ class SnapshotCache {
2867
3624
  }
2868
3625
 
2869
3626
  class PageView extends View {
2870
- constructor() {
2871
- super(...arguments);
2872
- this.snapshotCache = new SnapshotCache(10);
2873
- this.lastRenderedLocation = new URL(location.href);
2874
- this.forceReloaded = false;
3627
+ snapshotCache=new SnapshotCache(10);
3628
+ lastRenderedLocation=new URL(location.href);
3629
+ forceReloaded=false;
3630
+ shouldTransitionTo(newSnapshot) {
3631
+ return this.snapshot.prefersViewTransitions && newSnapshot.prefersViewTransitions;
2875
3632
  }
2876
3633
  renderPage(snapshot, isPreview = false, willRender = true, visit) {
2877
- const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
3634
+ const shouldMorphPage = this.isPageRefresh(visit) && this.snapshot.shouldMorphPage;
3635
+ const rendererClass = shouldMorphPage ? MorphRenderer : PageRenderer;
3636
+ const renderer = new rendererClass(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
2878
3637
  if (!renderer.shouldRender) {
2879
3638
  this.forceReloaded = true;
2880
3639
  } else {
2881
- visit === null || visit === void 0 ? void 0 : visit.changeHistory();
3640
+ visit?.changeHistory();
2882
3641
  }
2883
3642
  return this.render(renderer);
2884
3643
  }
2885
3644
  renderError(snapshot, visit) {
2886
- visit === null || visit === void 0 ? void 0 : visit.changeHistory();
3645
+ visit?.changeHistory();
2887
3646
  const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
2888
3647
  return this.render(renderer);
2889
3648
  }
@@ -2903,14 +3662,17 @@ class PageView extends View {
2903
3662
  getCachedSnapshotForLocation(location) {
2904
3663
  return this.snapshotCache.get(location);
2905
3664
  }
3665
+ isPageRefresh(visit) {
3666
+ return !visit || this.lastRenderedLocation.href === visit.location.href && visit.action === "replace";
3667
+ }
2906
3668
  get snapshot() {
2907
3669
  return PageSnapshot.fromElement(this.element);
2908
3670
  }
2909
3671
  }
2910
3672
 
2911
3673
  class Preloader {
3674
+ selector="a[data-turbo-preload]";
2912
3675
  constructor(delegate) {
2913
- this.selector = "a[data-turbo-preload]";
2914
3676
  this.delegate = delegate;
2915
3677
  }
2916
3678
  get snapshotCache() {
@@ -2938,7 +3700,7 @@ class Preloader {
2938
3700
  try {
2939
3701
  const response = await fetch(location.toString(), {
2940
3702
  headers: {
2941
- "VND.PREFETCH": "true",
3703
+ "Sec-Purpose": "prefetch",
2942
3704
  Accept: "text/html"
2943
3705
  }
2944
3706
  });
@@ -2949,28 +3711,64 @@ class Preloader {
2949
3711
  }
2950
3712
  }
2951
3713
 
2952
- class Session {
2953
- constructor() {
2954
- this.navigator = new Navigator(this);
2955
- this.history = new History(this);
2956
- this.preloader = new Preloader(this);
2957
- this.view = new PageView(this, document.documentElement);
2958
- this.adapter = new BrowserAdapter(this);
2959
- this.pageObserver = new PageObserver(this);
2960
- this.cacheObserver = new CacheObserver;
2961
- this.linkClickObserver = new LinkClickObserver(this, window);
2962
- this.formSubmitObserver = new FormSubmitObserver(this, document);
2963
- this.scrollObserver = new ScrollObserver(this);
2964
- this.streamObserver = new StreamObserver(this);
2965
- this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
2966
- this.frameRedirector = new FrameRedirector(this, document.documentElement);
2967
- this.streamMessageRenderer = new StreamMessageRenderer;
2968
- this.drive = true;
2969
- this.enabled = true;
2970
- this.progressBarDelay = 500;
2971
- this.started = false;
2972
- this.formMode = "on";
3714
+ class LimitedSet extends Set {
3715
+ constructor(maxSize) {
3716
+ super();
3717
+ this.maxSize = maxSize;
3718
+ }
3719
+ add(value) {
3720
+ if (this.size >= this.maxSize) {
3721
+ const iterator = this.values();
3722
+ const oldestValue = iterator.next().value;
3723
+ this.delete(oldestValue);
3724
+ }
3725
+ super.add(value);
3726
+ }
3727
+ }
3728
+
3729
+ class Cache {
3730
+ constructor(session) {
3731
+ this.session = session;
2973
3732
  }
3733
+ clear() {
3734
+ this.session.clearCache();
3735
+ }
3736
+ resetCacheControl() {
3737
+ this.#setCacheControl("");
3738
+ }
3739
+ exemptPageFromCache() {
3740
+ this.#setCacheControl("no-cache");
3741
+ }
3742
+ exemptPageFromPreview() {
3743
+ this.#setCacheControl("no-preview");
3744
+ }
3745
+ #setCacheControl(value) {
3746
+ setMetaContent("turbo-cache-control", value);
3747
+ }
3748
+ }
3749
+
3750
+ class Session {
3751
+ navigator=new Navigator(this);
3752
+ history=new History(this);
3753
+ preloader=new Preloader(this);
3754
+ view=new PageView(this, document.documentElement);
3755
+ adapter=new BrowserAdapter(this);
3756
+ pageObserver=new PageObserver(this);
3757
+ cacheObserver=new CacheObserver;
3758
+ linkClickObserver=new LinkClickObserver(this, window);
3759
+ formSubmitObserver=new FormSubmitObserver(this, document);
3760
+ scrollObserver=new ScrollObserver(this);
3761
+ streamObserver=new StreamObserver(this);
3762
+ formLinkClickObserver=new FormLinkClickObserver(this, document.documentElement);
3763
+ frameRedirector=new FrameRedirector(this, document.documentElement);
3764
+ streamMessageRenderer=new StreamMessageRenderer;
3765
+ cache=new Cache(this);
3766
+ recentRequests=new LimitedSet(20);
3767
+ drive=true;
3768
+ enabled=true;
3769
+ progressBarDelay=500;
3770
+ started=false;
3771
+ formMode="on";
2974
3772
  start() {
2975
3773
  if (!this.started) {
2976
3774
  this.pageObserver.start();
@@ -3016,6 +3814,15 @@ class Session {
3016
3814
  this.navigator.proposeVisit(expandURL(location), options);
3017
3815
  }
3018
3816
  }
3817
+ refresh(url, requestId) {
3818
+ const isRecentRequest = requestId && this.recentRequests.has(requestId);
3819
+ if (!isRecentRequest) {
3820
+ this.cache.exemptPageFromPreview();
3821
+ this.visit(url, {
3822
+ action: "replace"
3823
+ });
3824
+ }
3825
+ }
3019
3826
  connectStreamSource(source) {
3020
3827
  this.streamObserver.connectStreamSource(source);
3021
3828
  }
@@ -3099,7 +3906,7 @@ class Session {
3099
3906
  this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
3100
3907
  }
3101
3908
  willSubmitForm(form, submitter) {
3102
- const action = getAction(form, submitter);
3909
+ const action = getAction$1(form, submitter);
3103
3910
  return this.submissionIsNavigatable(form, submitter) && locationIsVisitable(expandURL(action), this.snapshot.rootLocation);
3104
3911
  }
3105
3912
  formSubmitted(form, submitter) {
@@ -3119,22 +3926,21 @@ class Session {
3119
3926
  this.renderStreamMessage(message);
3120
3927
  }
3121
3928
  viewWillCacheSnapshot() {
3122
- var _a;
3123
- if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {
3929
+ if (!this.navigator.currentVisit?.silent) {
3124
3930
  this.notifyApplicationBeforeCachingSnapshot();
3125
3931
  }
3126
3932
  }
3127
- allowsImmediateRender({element: element}, options) {
3128
- const event = this.notifyApplicationBeforeRender(element, options);
3933
+ allowsImmediateRender({element: element}, isPreview, options) {
3934
+ const event = this.notifyApplicationBeforeRender(element, isPreview, options);
3129
3935
  const {defaultPrevented: defaultPrevented, detail: {render: render}} = event;
3130
3936
  if (this.view.renderer && render) {
3131
3937
  this.view.renderer.renderElement = render;
3132
3938
  }
3133
3939
  return !defaultPrevented;
3134
3940
  }
3135
- viewRenderedSnapshot(_snapshot, _isPreview) {
3941
+ viewRenderedSnapshot(_snapshot, isPreview, renderMethod) {
3136
3942
  this.view.lastRenderedLocation = this.history.location;
3137
- this.notifyApplicationAfterRender();
3943
+ this.notifyApplicationAfterRender(isPreview, renderMethod);
3138
3944
  }
3139
3945
  preloadOnLoadLinksForView(element) {
3140
3946
  this.preloader.preloadOnLoadLinksForView(element);
@@ -3185,16 +3991,23 @@ class Session {
3185
3991
  notifyApplicationBeforeCachingSnapshot() {
3186
3992
  return dispatch("turbo:before-cache");
3187
3993
  }
3188
- notifyApplicationBeforeRender(newBody, options) {
3994
+ notifyApplicationBeforeRender(newBody, isPreview, options) {
3189
3995
  return dispatch("turbo:before-render", {
3190
- detail: Object.assign({
3191
- newBody: newBody
3192
- }, options),
3996
+ detail: {
3997
+ newBody: newBody,
3998
+ isPreview: isPreview,
3999
+ ...options
4000
+ },
3193
4001
  cancelable: true
3194
4002
  });
3195
4003
  }
3196
- notifyApplicationAfterRender() {
3197
- return dispatch("turbo:render");
4004
+ notifyApplicationAfterRender(isPreview, renderMethod) {
4005
+ return dispatch("turbo:render", {
4006
+ detail: {
4007
+ isPreview: isPreview,
4008
+ renderMethod: renderMethod
4009
+ }
4010
+ });
3198
4011
  }
3199
4012
  notifyApplicationAfterPageLoad(timing = {}) {
3200
4013
  return dispatch("turbo:load", {
@@ -3273,67 +4086,9 @@ const deprecatedLocationPropertyDescriptors = {
3273
4086
  }
3274
4087
  };
3275
4088
 
3276
- class Cache {
3277
- constructor(session) {
3278
- this.session = session;
3279
- }
3280
- clear() {
3281
- this.session.clearCache();
3282
- }
3283
- resetCacheControl() {
3284
- this.setCacheControl("");
3285
- }
3286
- exemptPageFromCache() {
3287
- this.setCacheControl("no-cache");
3288
- }
3289
- exemptPageFromPreview() {
3290
- this.setCacheControl("no-preview");
3291
- }
3292
- setCacheControl(value) {
3293
- setMetaContent("turbo-cache-control", value);
3294
- }
3295
- }
3296
-
3297
- const StreamActions = {
3298
- after() {
3299
- this.targetElements.forEach((e => {
3300
- var _a;
3301
- return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling);
3302
- }));
3303
- },
3304
- append() {
3305
- this.removeDuplicateTargetChildren();
3306
- this.targetElements.forEach((e => e.append(this.templateContent)));
3307
- },
3308
- before() {
3309
- this.targetElements.forEach((e => {
3310
- var _a;
3311
- return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e);
3312
- }));
3313
- },
3314
- prepend() {
3315
- this.removeDuplicateTargetChildren();
3316
- this.targetElements.forEach((e => e.prepend(this.templateContent)));
3317
- },
3318
- remove() {
3319
- this.targetElements.forEach((e => e.remove()));
3320
- },
3321
- replace() {
3322
- this.targetElements.forEach((e => e.replaceWith(this.templateContent)));
3323
- },
3324
- update() {
3325
- this.targetElements.forEach((targetElement => {
3326
- targetElement.innerHTML = "";
3327
- targetElement.append(this.templateContent);
3328
- }));
3329
- }
3330
- };
3331
-
3332
4089
  const session = new Session;
3333
4090
 
3334
- const cache = new Cache(session);
3335
-
3336
- const {navigator: navigator$1} = session;
4091
+ const {cache: cache, navigator: navigator$1} = session;
3337
4092
 
3338
4093
  function start() {
3339
4094
  session.start();
@@ -3384,6 +4139,7 @@ var Turbo = Object.freeze({
3384
4139
  PageRenderer: PageRenderer,
3385
4140
  PageSnapshot: PageSnapshot,
3386
4141
  FrameRenderer: FrameRenderer,
4142
+ fetch: fetch,
3387
4143
  start: start,
3388
4144
  registerAdapter: registerAdapter,
3389
4145
  visit: visit,
@@ -3393,28 +4149,20 @@ var Turbo = Object.freeze({
3393
4149
  clearCache: clearCache,
3394
4150
  setProgressBarDelay: setProgressBarDelay,
3395
4151
  setConfirmMethod: setConfirmMethod,
3396
- setFormMode: setFormMode,
3397
- StreamActions: StreamActions
4152
+ setFormMode: setFormMode
3398
4153
  });
3399
4154
 
3400
4155
  class TurboFrameMissingError extends Error {}
3401
4156
 
3402
4157
  class FrameController {
4158
+ fetchResponseLoaded=_fetchResponse => Promise.resolve();
4159
+ #currentFetchRequest=null;
4160
+ #resolveVisitPromise=() => {};
4161
+ #connected=false;
4162
+ #hasBeenLoaded=false;
4163
+ #ignoredAttributes=new Set;
4164
+ action=null;
3403
4165
  constructor(element) {
3404
- this.fetchResponseLoaded = _fetchResponse => {};
3405
- this.currentFetchRequest = null;
3406
- this.resolveVisitPromise = () => {};
3407
- this.connected = false;
3408
- this.hasBeenLoaded = false;
3409
- this.ignoredAttributes = new Set;
3410
- this.action = null;
3411
- this.visitCachedSnapshot = ({element: element}) => {
3412
- const frame = element.querySelector("#" + this.element.id);
3413
- if (frame && this.previousFrameElement) {
3414
- frame.replaceChildren(...this.previousFrameElement.children);
3415
- }
3416
- delete this.previousFrameElement;
3417
- };
3418
4166
  this.element = element;
3419
4167
  this.view = new FrameView(this, this.element);
3420
4168
  this.appearanceObserver = new AppearanceObserver(this, this.element);
@@ -3424,12 +4172,12 @@ class FrameController {
3424
4172
  this.formSubmitObserver = new FormSubmitObserver(this, this.element);
3425
4173
  }
3426
4174
  connect() {
3427
- if (!this.connected) {
3428
- this.connected = true;
4175
+ if (!this.#connected) {
4176
+ this.#connected = true;
3429
4177
  if (this.loadingStyle == FrameLoadingStyle.lazy) {
3430
4178
  this.appearanceObserver.start();
3431
4179
  } else {
3432
- this.loadSourceURL();
4180
+ this.#loadSourceURL();
3433
4181
  }
3434
4182
  this.formLinkClickObserver.start();
3435
4183
  this.linkInterceptor.start();
@@ -3437,8 +4185,8 @@ class FrameController {
3437
4185
  }
3438
4186
  }
3439
4187
  disconnect() {
3440
- if (this.connected) {
3441
- this.connected = false;
4188
+ if (this.#connected) {
4189
+ this.#connected = false;
3442
4190
  this.appearanceObserver.stop();
3443
4191
  this.formLinkClickObserver.stop();
3444
4192
  this.linkInterceptor.stop();
@@ -3447,21 +4195,21 @@ class FrameController {
3447
4195
  }
3448
4196
  disabledChanged() {
3449
4197
  if (this.loadingStyle == FrameLoadingStyle.eager) {
3450
- this.loadSourceURL();
4198
+ this.#loadSourceURL();
3451
4199
  }
3452
4200
  }
3453
4201
  sourceURLChanged() {
3454
- if (this.isIgnoringChangesTo("src")) return;
4202
+ if (this.#isIgnoringChangesTo("src")) return;
3455
4203
  if (this.element.isConnected) {
3456
4204
  this.complete = false;
3457
4205
  }
3458
- if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
3459
- this.loadSourceURL();
4206
+ if (this.loadingStyle == FrameLoadingStyle.eager || this.#hasBeenLoaded) {
4207
+ this.#loadSourceURL();
3460
4208
  }
3461
4209
  }
3462
4210
  sourceURLReloaded() {
3463
4211
  const {src: src} = this.element;
3464
- this.ignoringChangesToAttribute("complete", (() => {
4212
+ this.#ignoringChangesToAttribute("complete", (() => {
3465
4213
  this.element.removeAttribute("complete");
3466
4214
  }));
3467
4215
  this.element.src = null;
@@ -3469,23 +4217,23 @@ class FrameController {
3469
4217
  return this.element.loaded;
3470
4218
  }
3471
4219
  completeChanged() {
3472
- if (this.isIgnoringChangesTo("complete")) return;
3473
- this.loadSourceURL();
4220
+ if (this.#isIgnoringChangesTo("complete")) return;
4221
+ this.#loadSourceURL();
3474
4222
  }
3475
4223
  loadingStyleChanged() {
3476
4224
  if (this.loadingStyle == FrameLoadingStyle.lazy) {
3477
4225
  this.appearanceObserver.start();
3478
4226
  } else {
3479
4227
  this.appearanceObserver.stop();
3480
- this.loadSourceURL();
4228
+ this.#loadSourceURL();
3481
4229
  }
3482
4230
  }
3483
- async loadSourceURL() {
4231
+ async #loadSourceURL() {
3484
4232
  if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
3485
- this.element.loaded = this.visit(expandURL(this.sourceURL));
4233
+ this.element.loaded = this.#visit(expandURL(this.sourceURL));
3486
4234
  this.appearanceObserver.stop();
3487
4235
  await this.element.loaded;
3488
- this.hasBeenLoaded = true;
4236
+ this.#hasBeenLoaded = true;
3489
4237
  }
3490
4238
  }
3491
4239
  async loadResponse(fetchResponse) {
@@ -3498,34 +4246,34 @@ class FrameController {
3498
4246
  const document = parseHTMLDocument(html);
3499
4247
  const pageSnapshot = PageSnapshot.fromDocument(document);
3500
4248
  if (pageSnapshot.isVisitable) {
3501
- await this.loadFrameResponse(fetchResponse, document);
4249
+ await this.#loadFrameResponse(fetchResponse, document);
3502
4250
  } else {
3503
- await this.handleUnvisitableFrameResponse(fetchResponse);
4251
+ await this.#handleUnvisitableFrameResponse(fetchResponse);
3504
4252
  }
3505
4253
  }
3506
4254
  } finally {
3507
- this.fetchResponseLoaded = () => {};
4255
+ this.fetchResponseLoaded = () => Promise.resolve();
3508
4256
  }
3509
4257
  }
3510
4258
  elementAppearedInViewport(element) {
3511
4259
  this.proposeVisitIfNavigatedWithAction(element, element);
3512
- this.loadSourceURL();
4260
+ this.#loadSourceURL();
3513
4261
  }
3514
4262
  willSubmitFormLinkToLocation(link) {
3515
- return this.shouldInterceptNavigation(link);
4263
+ return this.#shouldInterceptNavigation(link);
3516
4264
  }
3517
4265
  submittedFormLinkToLocation(link, _location, form) {
3518
- const frame = this.findFrameElement(link);
4266
+ const frame = this.#findFrameElement(link);
3519
4267
  if (frame) form.setAttribute("data-turbo-frame", frame.id);
3520
4268
  }
3521
4269
  shouldInterceptLinkClick(element, _location, _event) {
3522
- return this.shouldInterceptNavigation(element);
4270
+ return this.#shouldInterceptNavigation(element);
3523
4271
  }
3524
4272
  linkClickIntercepted(element, location) {
3525
- this.navigateFrame(element, location);
4273
+ this.#navigateFrame(element, location);
3526
4274
  }
3527
4275
  willSubmitForm(element, submitter) {
3528
- return element.closest("turbo-frame") == this.element && this.shouldInterceptNavigation(element, submitter);
4276
+ return element.closest("turbo-frame") == this.element && this.#shouldInterceptNavigation(element, submitter);
3529
4277
  }
3530
4278
  formSubmitted(element, submitter) {
3531
4279
  if (this.formSubmission) {
@@ -3537,9 +4285,8 @@ class FrameController {
3537
4285
  this.formSubmission.start();
3538
4286
  }
3539
4287
  prepareRequest(request) {
3540
- var _a;
3541
4288
  request.headers["Turbo-Frame"] = this.id;
3542
- if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute("data-turbo-stream")) {
4289
+ if (this.currentNavigationElement?.hasAttribute("data-turbo-stream")) {
3543
4290
  request.acceptResponseType(StreamMessage.contentType);
3544
4291
  }
3545
4292
  }
@@ -3547,28 +4294,28 @@ class FrameController {
3547
4294
  markAsBusy(this.element);
3548
4295
  }
3549
4296
  requestPreventedHandlingResponse(_request, _response) {
3550
- this.resolveVisitPromise();
4297
+ this.#resolveVisitPromise();
3551
4298
  }
3552
4299
  async requestSucceededWithResponse(request, response) {
3553
4300
  await this.loadResponse(response);
3554
- this.resolveVisitPromise();
4301
+ this.#resolveVisitPromise();
3555
4302
  }
3556
4303
  async requestFailedWithResponse(request, response) {
3557
4304
  await this.loadResponse(response);
3558
- this.resolveVisitPromise();
4305
+ this.#resolveVisitPromise();
3559
4306
  }
3560
4307
  requestErrored(request, error) {
3561
4308
  console.error(error);
3562
- this.resolveVisitPromise();
4309
+ this.#resolveVisitPromise();
3563
4310
  }
3564
4311
  requestFinished(_request) {
3565
4312
  clearBusyState(this.element);
3566
4313
  }
3567
4314
  formSubmissionStarted({formElement: formElement}) {
3568
- markAsBusy(formElement, this.findFrameElement(formElement));
4315
+ markAsBusy(formElement, this.#findFrameElement(formElement));
3569
4316
  }
3570
4317
  formSubmissionSucceededWithResponse(formSubmission, response) {
3571
- const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
4318
+ const frame = this.#findFrameElement(formSubmission.formElement, formSubmission.submitter);
3572
4319
  frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
3573
4320
  frame.delegate.loadResponse(response);
3574
4321
  if (!formSubmission.isSafe) {
@@ -3583,14 +4330,15 @@ class FrameController {
3583
4330
  console.error(error);
3584
4331
  }
3585
4332
  formSubmissionFinished({formElement: formElement}) {
3586
- clearBusyState(formElement, this.findFrameElement(formElement));
4333
+ clearBusyState(formElement, this.#findFrameElement(formElement));
3587
4334
  }
3588
- allowsImmediateRender({element: newFrame}, options) {
4335
+ allowsImmediateRender({element: newFrame}, _isPreview, options) {
3589
4336
  const event = dispatch("turbo:before-frame-render", {
3590
4337
  target: this.element,
3591
- detail: Object.assign({
3592
- newFrame: newFrame
3593
- }, options),
4338
+ detail: {
4339
+ newFrame: newFrame,
4340
+ ...options
4341
+ },
3594
4342
  cancelable: true
3595
4343
  });
3596
4344
  const {defaultPrevented: defaultPrevented, detail: {render: render}} = event;
@@ -3599,7 +4347,7 @@ class FrameController {
3599
4347
  }
3600
4348
  return !defaultPrevented;
3601
4349
  }
3602
- viewRenderedSnapshot(_snapshot, _isPreview) {}
4350
+ viewRenderedSnapshot(_snapshot, _isPreview, _renderMethod) {}
3603
4351
  preloadOnLoadLinksForView(element) {
3604
4352
  session.preloadOnLoadLinksForView(element);
3605
4353
  }
@@ -3607,7 +4355,14 @@ class FrameController {
3607
4355
  willRenderFrame(currentElement, _newElement) {
3608
4356
  this.previousFrameElement = currentElement.cloneNode(true);
3609
4357
  }
3610
- async loadFrameResponse(fetchResponse, document) {
4358
+ visitCachedSnapshot=({element: element}) => {
4359
+ const frame = element.querySelector("#" + this.element.id);
4360
+ if (frame && this.previousFrameElement) {
4361
+ frame.replaceChildren(...this.previousFrameElement.children);
4362
+ }
4363
+ delete this.previousFrameElement;
4364
+ };
4365
+ async #loadFrameResponse(fetchResponse, document) {
3611
4366
  const newFrameElement = await this.extractForeignFrameElement(document.body);
3612
4367
  if (newFrameElement) {
3613
4368
  const snapshot = new Snapshot(newFrameElement);
@@ -3618,29 +4373,28 @@ class FrameController {
3618
4373
  this.complete = true;
3619
4374
  session.frameRendered(fetchResponse, this.element);
3620
4375
  session.frameLoaded(this.element);
3621
- this.fetchResponseLoaded(fetchResponse);
3622
- } else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
3623
- this.handleFrameMissingFromResponse(fetchResponse);
4376
+ await this.fetchResponseLoaded(fetchResponse);
4377
+ } else if (this.#willHandleFrameMissingFromResponse(fetchResponse)) {
4378
+ this.#handleFrameMissingFromResponse(fetchResponse);
3624
4379
  }
3625
4380
  }
3626
- async visit(url) {
3627
- var _a;
4381
+ async #visit(url) {
3628
4382
  const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams, this.element);
3629
- (_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
3630
- this.currentFetchRequest = request;
4383
+ this.#currentFetchRequest?.cancel();
4384
+ this.#currentFetchRequest = request;
3631
4385
  return new Promise((resolve => {
3632
- this.resolveVisitPromise = () => {
3633
- this.resolveVisitPromise = () => {};
3634
- this.currentFetchRequest = null;
4386
+ this.#resolveVisitPromise = () => {
4387
+ this.#resolveVisitPromise = () => {};
4388
+ this.#currentFetchRequest = null;
3635
4389
  resolve();
3636
4390
  };
3637
4391
  request.perform();
3638
4392
  }));
3639
4393
  }
3640
- navigateFrame(element, url, submitter) {
3641
- const frame = this.findFrameElement(element, submitter);
4394
+ #navigateFrame(element, url, submitter) {
4395
+ const frame = this.#findFrameElement(element, submitter);
3642
4396
  frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
3643
- this.withCurrentNavigationElement(element, (() => {
4397
+ this.#withCurrentNavigationElement(element, (() => {
3644
4398
  frame.src = url;
3645
4399
  }));
3646
4400
  }
@@ -3649,10 +4403,10 @@ class FrameController {
3649
4403
  if (this.action) {
3650
4404
  const pageSnapshot = PageSnapshot.fromElement(frame).clone();
3651
4405
  const {visitCachedSnapshot: visitCachedSnapshot} = frame.delegate;
3652
- frame.delegate.fetchResponseLoaded = fetchResponse => {
4406
+ frame.delegate.fetchResponseLoaded = async fetchResponse => {
3653
4407
  if (frame.src) {
3654
4408
  const {statusCode: statusCode, redirected: redirected} = fetchResponse;
3655
- const responseHTML = frame.ownerDocument.documentElement.outerHTML;
4409
+ const responseHTML = await fetchResponse.responseHTML;
3656
4410
  const response = {
3657
4411
  statusCode: statusCode,
3658
4412
  redirected: redirected,
@@ -3678,16 +4432,16 @@ class FrameController {
3678
4432
  session.history.update(method, expandURL(this.element.src || ""), this.restorationIdentifier);
3679
4433
  }
3680
4434
  }
3681
- async handleUnvisitableFrameResponse(fetchResponse) {
4435
+ async #handleUnvisitableFrameResponse(fetchResponse) {
3682
4436
  console.warn(`The response (${fetchResponse.statusCode}) from <turbo-frame id="${this.element.id}"> is performing a full page visit due to turbo-visit-control.`);
3683
- await this.visitResponse(fetchResponse.response);
4437
+ await this.#visitResponse(fetchResponse.response);
3684
4438
  }
3685
- willHandleFrameMissingFromResponse(fetchResponse) {
4439
+ #willHandleFrameMissingFromResponse(fetchResponse) {
3686
4440
  this.element.setAttribute("complete", "");
3687
4441
  const response = fetchResponse.response;
3688
- const visit = async (url, options = {}) => {
4442
+ const visit = async (url, options) => {
3689
4443
  if (url instanceof Response) {
3690
- this.visitResponse(url);
4444
+ this.#visitResponse(url);
3691
4445
  } else {
3692
4446
  session.visit(url, options);
3693
4447
  }
@@ -3702,15 +4456,15 @@ class FrameController {
3702
4456
  });
3703
4457
  return !event.defaultPrevented;
3704
4458
  }
3705
- handleFrameMissingFromResponse(fetchResponse) {
4459
+ #handleFrameMissingFromResponse(fetchResponse) {
3706
4460
  this.view.missing();
3707
- this.throwFrameMissingError(fetchResponse);
4461
+ this.#throwFrameMissingError(fetchResponse);
3708
4462
  }
3709
- throwFrameMissingError(fetchResponse) {
4463
+ #throwFrameMissingError(fetchResponse) {
3710
4464
  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.`;
3711
4465
  throw new TurboFrameMissingError(message);
3712
4466
  }
3713
- async visitResponse(response) {
4467
+ async #visitResponse(response) {
3714
4468
  const wrapped = new FetchResponse(response);
3715
4469
  const responseHTML = await wrapped.responseHTML;
3716
4470
  const {location: location, redirected: redirected, statusCode: statusCode} = wrapped;
@@ -3722,10 +4476,9 @@ class FrameController {
3722
4476
  }
3723
4477
  });
3724
4478
  }
3725
- findFrameElement(element, submitter) {
3726
- var _a;
4479
+ #findFrameElement(element, submitter) {
3727
4480
  const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
3728
- return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
4481
+ return getFrameElementById(id) ?? this.element;
3729
4482
  }
3730
4483
  async extractForeignFrameElement(container) {
3731
4484
  let element;
@@ -3746,13 +4499,13 @@ class FrameController {
3746
4499
  }
3747
4500
  return null;
3748
4501
  }
3749
- formActionIsVisitable(form, submitter) {
3750
- const action = getAction(form, submitter);
4502
+ #formActionIsVisitable(form, submitter) {
4503
+ const action = getAction$1(form, submitter);
3751
4504
  return locationIsVisitable(expandURL(action), this.rootLocation);
3752
4505
  }
3753
- shouldInterceptNavigation(element, submitter) {
4506
+ #shouldInterceptNavigation(element, submitter) {
3754
4507
  const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
3755
- if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) {
4508
+ if (element instanceof HTMLFormElement && !this.#formActionIsVisitable(element, submitter)) {
3756
4509
  return false;
3757
4510
  }
3758
4511
  if (!this.enabled || id == "_top") {
@@ -3784,21 +4537,21 @@ class FrameController {
3784
4537
  }
3785
4538
  }
3786
4539
  set sourceURL(sourceURL) {
3787
- this.ignoringChangesToAttribute("src", (() => {
3788
- this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
4540
+ this.#ignoringChangesToAttribute("src", (() => {
4541
+ this.element.src = sourceURL ?? null;
3789
4542
  }));
3790
4543
  }
3791
4544
  get loadingStyle() {
3792
4545
  return this.element.loading;
3793
4546
  }
3794
4547
  get isLoading() {
3795
- return this.formSubmission !== undefined || this.resolveVisitPromise() !== undefined;
4548
+ return this.formSubmission !== undefined || this.#resolveVisitPromise() !== undefined;
3796
4549
  }
3797
4550
  get complete() {
3798
4551
  return this.element.hasAttribute("complete");
3799
4552
  }
3800
4553
  set complete(value) {
3801
- this.ignoringChangesToAttribute("complete", (() => {
4554
+ this.#ignoringChangesToAttribute("complete", (() => {
3802
4555
  if (value) {
3803
4556
  this.element.setAttribute("complete", "");
3804
4557
  } else {
@@ -3807,23 +4560,22 @@ class FrameController {
3807
4560
  }));
3808
4561
  }
3809
4562
  get isActive() {
3810
- return this.element.isActive && this.connected;
4563
+ return this.element.isActive && this.#connected;
3811
4564
  }
3812
4565
  get rootLocation() {
3813
- var _a;
3814
4566
  const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
3815
- const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
4567
+ const root = meta?.content ?? "/";
3816
4568
  return expandURL(root);
3817
4569
  }
3818
- isIgnoringChangesTo(attributeName) {
3819
- return this.ignoredAttributes.has(attributeName);
4570
+ #isIgnoringChangesTo(attributeName) {
4571
+ return this.#ignoredAttributes.has(attributeName);
3820
4572
  }
3821
- ignoringChangesToAttribute(attributeName, callback) {
3822
- this.ignoredAttributes.add(attributeName);
4573
+ #ignoringChangesToAttribute(attributeName, callback) {
4574
+ this.#ignoredAttributes.add(attributeName);
3823
4575
  callback();
3824
- this.ignoredAttributes.delete(attributeName);
4576
+ this.#ignoredAttributes.delete(attributeName);
3825
4577
  }
3826
- withCurrentNavigationElement(element, callback) {
4578
+ #withCurrentNavigationElement(element, callback) {
3827
4579
  this.currentNavigationElement = element;
3828
4580
  callback();
3829
4581
  delete this.currentNavigationElement;
@@ -3856,6 +4608,38 @@ function activateElement(element, currentURL) {
3856
4608
  }
3857
4609
  }
3858
4610
 
4611
+ const StreamActions = {
4612
+ after() {
4613
+ this.targetElements.forEach((e => e.parentElement?.insertBefore(this.templateContent, e.nextSibling)));
4614
+ },
4615
+ append() {
4616
+ this.removeDuplicateTargetChildren();
4617
+ this.targetElements.forEach((e => e.append(this.templateContent)));
4618
+ },
4619
+ before() {
4620
+ this.targetElements.forEach((e => e.parentElement?.insertBefore(this.templateContent, e)));
4621
+ },
4622
+ prepend() {
4623
+ this.removeDuplicateTargetChildren();
4624
+ this.targetElements.forEach((e => e.prepend(this.templateContent)));
4625
+ },
4626
+ remove() {
4627
+ this.targetElements.forEach((e => e.remove()));
4628
+ },
4629
+ replace() {
4630
+ this.targetElements.forEach((e => e.replaceWith(this.templateContent)));
4631
+ },
4632
+ update() {
4633
+ this.targetElements.forEach((targetElement => {
4634
+ targetElement.innerHTML = "";
4635
+ targetElement.append(this.templateContent);
4636
+ }));
4637
+ },
4638
+ refresh() {
4639
+ session.refresh(this.baseURI, this.requestId);
4640
+ }
4641
+ };
4642
+
3859
4643
  class StreamElement extends HTMLElement {
3860
4644
  static async renderElement(newElement) {
3861
4645
  await newElement.performAction();
@@ -3870,11 +4654,10 @@ class StreamElement extends HTMLElement {
3870
4654
  }
3871
4655
  }
3872
4656
  async render() {
3873
- var _a;
3874
- return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : this.renderPromise = (async () => {
4657
+ return this.renderPromise ??= (async () => {
3875
4658
  const event = this.beforeRenderEvent;
3876
4659
  if (this.dispatchEvent(event)) {
3877
- await nextAnimationFrame();
4660
+ await nextRepaint();
3878
4661
  await event.detail.render(this);
3879
4662
  }
3880
4663
  })();
@@ -3882,15 +4665,14 @@ class StreamElement extends HTMLElement {
3882
4665
  disconnect() {
3883
4666
  try {
3884
4667
  this.remove();
3885
- } catch (_a) {}
4668
+ } catch {}
3886
4669
  }
3887
4670
  removeDuplicateTargetChildren() {
3888
4671
  this.duplicateChildren.forEach((c => c.remove()));
3889
4672
  }
3890
4673
  get duplicateChildren() {
3891
- var _a;
3892
4674
  const existingChildren = this.targetElements.flatMap((e => [ ...e.children ])).filter((c => !!c.id));
3893
- const newChildrenIds = [ ...((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || [] ].filter((c => !!c.id)).map((c => c.id));
4675
+ const newChildrenIds = [ ...this.templateContent?.children || [] ].filter((c => !!c.id)).map((c => c.id));
3894
4676
  return existingChildren.filter((c => newChildrenIds.includes(c.id)));
3895
4677
  }
3896
4678
  get performAction() {
@@ -3899,9 +4681,9 @@ class StreamElement extends HTMLElement {
3899
4681
  if (actionFunction) {
3900
4682
  return actionFunction;
3901
4683
  }
3902
- this.raise("unknown action");
4684
+ this.#raise("unknown action");
3903
4685
  }
3904
- this.raise("action attribute is missing");
4686
+ this.#raise("action attribute is missing");
3905
4687
  }
3906
4688
  get targetElements() {
3907
4689
  if (this.target) {
@@ -3909,7 +4691,7 @@ class StreamElement extends HTMLElement {
3909
4691
  } else if (this.targets) {
3910
4692
  return this.targetElementsByQuery;
3911
4693
  } else {
3912
- this.raise("target or targets attribute is missing");
4694
+ this.#raise("target or targets attribute is missing");
3913
4695
  }
3914
4696
  }
3915
4697
  get templateContent() {
@@ -3923,7 +4705,7 @@ class StreamElement extends HTMLElement {
3923
4705
  } else if (this.firstElementChild instanceof HTMLTemplateElement) {
3924
4706
  return this.firstElementChild;
3925
4707
  }
3926
- this.raise("first child element must be a <template> element");
4708
+ this.#raise("first child element must be a <template> element");
3927
4709
  }
3928
4710
  get action() {
3929
4711
  return this.getAttribute("action");
@@ -3934,12 +4716,14 @@ class StreamElement extends HTMLElement {
3934
4716
  get targets() {
3935
4717
  return this.getAttribute("targets");
3936
4718
  }
3937
- raise(message) {
4719
+ get requestId() {
4720
+ return this.getAttribute("request-id");
4721
+ }
4722
+ #raise(message) {
3938
4723
  throw new Error(`${this.description}: ${message}`);
3939
4724
  }
3940
4725
  get description() {
3941
- var _a, _b;
3942
- return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
4726
+ return (this.outerHTML.match(/<[^>]+>/) ?? [])[0] ?? "<turbo-stream>";
3943
4727
  }
3944
4728
  get beforeRenderEvent() {
3945
4729
  return new CustomEvent("turbo:before-stream-render", {
@@ -3952,8 +4736,7 @@ class StreamElement extends HTMLElement {
3952
4736
  });
3953
4737
  }
3954
4738
  get targetElementsById() {
3955
- var _a;
3956
- const element = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.getElementById(this.target);
4739
+ const element = this.ownerDocument?.getElementById(this.target);
3957
4740
  if (element !== null) {
3958
4741
  return [ element ];
3959
4742
  } else {
@@ -3961,8 +4744,7 @@ class StreamElement extends HTMLElement {
3961
4744
  }
3962
4745
  }
3963
4746
  get targetElementsByQuery() {
3964
- var _a;
3965
- const elements = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.querySelectorAll(this.targets);
4747
+ const elements = this.ownerDocument?.querySelectorAll(this.targets);
3966
4748
  if (elements.length !== 0) {
3967
4749
  return Array.prototype.slice.call(elements);
3968
4750
  } else {
@@ -3972,16 +4754,14 @@ class StreamElement extends HTMLElement {
3972
4754
  }
3973
4755
 
3974
4756
  class StreamSourceElement extends HTMLElement {
3975
- constructor() {
3976
- super(...arguments);
3977
- this.streamSource = null;
3978
- }
4757
+ streamSource=null;
3979
4758
  connectedCallback() {
3980
4759
  this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
3981
4760
  connectStreamSource(this.streamSource);
3982
4761
  }
3983
4762
  disconnectedCallback() {
3984
4763
  if (this.streamSource) {
4764
+ this.streamSource.close();
3985
4765
  disconnectStreamSource(this.streamSource);
3986
4766
  }
3987
4767
  }
@@ -4032,10 +4812,12 @@ start();
4032
4812
 
4033
4813
  var turbo_es2017Esm = Object.freeze({
4034
4814
  __proto__: null,
4815
+ FetchEnctype: FetchEnctype,
4816
+ FetchMethod: FetchMethod,
4817
+ FetchRequest: FetchRequest,
4818
+ FetchResponse: FetchResponse,
4035
4819
  FrameElement: FrameElement,
4036
- get FrameLoadingStyle() {
4037
- return FrameLoadingStyle;
4038
- },
4820
+ FrameLoadingStyle: FrameLoadingStyle,
4039
4821
  FrameRenderer: FrameRenderer,
4040
4822
  PageRenderer: PageRenderer,
4041
4823
  PageSnapshot: PageSnapshot,
@@ -4046,6 +4828,10 @@ var turbo_es2017Esm = Object.freeze({
4046
4828
  clearCache: clearCache,
4047
4829
  connectStreamSource: connectStreamSource,
4048
4830
  disconnectStreamSource: disconnectStreamSource,
4831
+ fetch: fetch,
4832
+ fetchEnctypeFromString: fetchEnctypeFromString,
4833
+ fetchMethodFromString: fetchMethodFromString,
4834
+ isSafe: isSafe,
4049
4835
  navigator: navigator$1,
4050
4836
  registerAdapter: registerAdapter,
4051
4837
  renderStreamMessage: renderStreamMessage,
@@ -4060,14 +4846,14 @@ var turbo_es2017Esm = Object.freeze({
4060
4846
  let consumer;
4061
4847
 
4062
4848
  async function getConsumer() {
4063
- return consumer || setConsumer(createConsumer().then(setConsumer));
4849
+ return consumer || setConsumer(createConsumer$1().then(setConsumer));
4064
4850
  }
4065
4851
 
4066
4852
  function setConsumer(newConsumer) {
4067
4853
  return consumer = newConsumer;
4068
4854
  }
4069
4855
 
4070
- async function createConsumer() {
4856
+ async function createConsumer$1() {
4071
4857
  const {createConsumer: createConsumer} = await Promise.resolve().then((function() {
4072
4858
  return index;
4073
4859
  }));
@@ -4083,7 +4869,7 @@ var cable = Object.freeze({
4083
4869
  __proto__: null,
4084
4870
  getConsumer: getConsumer,
4085
4871
  setConsumer: setConsumer,
4086
- createConsumer: createConsumer,
4872
+ createConsumer: createConsumer$1,
4087
4873
  subscribeTo: subscribeTo
4088
4874
  });
4089
4875
 
@@ -4309,6 +5095,8 @@ ConnectionMonitor.staleThreshold = 6;
4309
5095
 
4310
5096
  ConnectionMonitor.reconnectionBackoffRate = .15;
4311
5097
 
5098
+ var ConnectionMonitor$1 = ConnectionMonitor;
5099
+
4312
5100
  var INTERNAL = {
4313
5101
  message_types: {
4314
5102
  welcome: "welcome",
@@ -4320,7 +5108,8 @@ var INTERNAL = {
4320
5108
  disconnect_reasons: {
4321
5109
  unauthorized: "unauthorized",
4322
5110
  invalid_request: "invalid_request",
4323
- server_restart: "server_restart"
5111
+ server_restart: "server_restart",
5112
+ remote: "remote"
4324
5113
  },
4325
5114
  default_mount_path: "/cable",
4326
5115
  protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
@@ -4337,7 +5126,7 @@ class Connection {
4337
5126
  this.open = this.open.bind(this);
4338
5127
  this.consumer = consumer;
4339
5128
  this.subscriptions = this.consumer.subscriptions;
4340
- this.monitor = new ConnectionMonitor(this);
5129
+ this.monitor = new ConnectionMonitor$1(this);
4341
5130
  this.disconnected = true;
4342
5131
  }
4343
5132
  send(data) {
@@ -4353,11 +5142,12 @@ class Connection {
4353
5142
  logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
4354
5143
  return false;
4355
5144
  } else {
4356
- logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
5145
+ const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];
5146
+ logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);
4357
5147
  if (this.webSocket) {
4358
5148
  this.uninstallEventHandlers();
4359
5149
  }
4360
- this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
5150
+ this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);
4361
5151
  this.installEventHandlers();
4362
5152
  this.monitor.start();
4363
5153
  return true;
@@ -4369,7 +5159,7 @@ class Connection {
4369
5159
  if (!allowReconnect) {
4370
5160
  this.monitor.stop();
4371
5161
  }
4372
- if (this.isActive()) {
5162
+ if (this.isOpen()) {
4373
5163
  return this.webSocket.close();
4374
5164
  }
4375
5165
  }
@@ -4399,6 +5189,9 @@ class Connection {
4399
5189
  isActive() {
4400
5190
  return this.isState("open", "connecting");
4401
5191
  }
5192
+ triedToReconnect() {
5193
+ return this.monitor.reconnectAttempts > 0;
5194
+ }
4402
5195
  isProtocolSupported() {
4403
5196
  return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
4404
5197
  }
@@ -4438,6 +5231,9 @@ Connection.prototype.events = {
4438
5231
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
4439
5232
  switch (type) {
4440
5233
  case message_types.welcome:
5234
+ if (this.triedToReconnect()) {
5235
+ this.reconnectAttempted = true;
5236
+ }
4441
5237
  this.monitor.recordConnect();
4442
5238
  return this.subscriptions.reload();
4443
5239
 
@@ -4452,7 +5248,16 @@ Connection.prototype.events = {
4452
5248
 
4453
5249
  case message_types.confirmation:
4454
5250
  this.subscriptions.confirmSubscription(identifier);
4455
- return this.subscriptions.notify(identifier, "connected");
5251
+ if (this.reconnectAttempted) {
5252
+ this.reconnectAttempted = false;
5253
+ return this.subscriptions.notify(identifier, "connected", {
5254
+ reconnected: true
5255
+ });
5256
+ } else {
5257
+ return this.subscriptions.notify(identifier, "connected", {
5258
+ reconnected: false
5259
+ });
5260
+ }
4456
5261
 
4457
5262
  case message_types.rejection:
4458
5263
  return this.subscriptions.reject(identifier);
@@ -4487,6 +5292,8 @@ Connection.prototype.events = {
4487
5292
  }
4488
5293
  };
4489
5294
 
5295
+ var Connection$1 = Connection;
5296
+
4490
5297
  const extend = function(object, properties) {
4491
5298
  if (properties != null) {
4492
5299
  for (let key in properties) {
@@ -4556,10 +5363,12 @@ class SubscriptionGuarantor {
4556
5363
  }
4557
5364
  }
4558
5365
 
5366
+ var SubscriptionGuarantor$1 = SubscriptionGuarantor;
5367
+
4559
5368
  class Subscriptions {
4560
5369
  constructor(consumer) {
4561
5370
  this.consumer = consumer;
4562
- this.guarantor = new SubscriptionGuarantor(this);
5371
+ this.guarantor = new SubscriptionGuarantor$1(this);
4563
5372
  this.subscriptions = [];
4564
5373
  }
4565
5374
  create(channelName, mixin) {
@@ -4636,7 +5445,8 @@ class Consumer {
4636
5445
  constructor(url) {
4637
5446
  this._url = url;
4638
5447
  this.subscriptions = new Subscriptions(this);
4639
- this.connection = new Connection(this);
5448
+ this.connection = new Connection$1(this);
5449
+ this.subprotocols = [];
4640
5450
  }
4641
5451
  get url() {
4642
5452
  return createWebSocketURL(this._url);
@@ -4657,6 +5467,9 @@ class Consumer {
4657
5467
  return this.connection.open();
4658
5468
  }
4659
5469
  }
5470
+ addSubProtocol(subprotocol) {
5471
+ this.subprotocols = [ ...this.subprotocols, subprotocol ];
5472
+ }
4660
5473
  }
4661
5474
 
4662
5475
  function createWebSocketURL(url) {
@@ -4674,7 +5487,7 @@ function createWebSocketURL(url) {
4674
5487
  }
4675
5488
  }
4676
5489
 
4677
- function createConsumer$1(url = getConfig("url") || INTERNAL.default_mount_path) {
5490
+ function createConsumer(url = getConfig("url") || INTERNAL.default_mount_path) {
4678
5491
  return new Consumer(url);
4679
5492
  }
4680
5493
 
@@ -4687,17 +5500,17 @@ function getConfig(name) {
4687
5500
 
4688
5501
  var index = Object.freeze({
4689
5502
  __proto__: null,
4690
- Connection: Connection,
4691
- ConnectionMonitor: ConnectionMonitor,
5503
+ Connection: Connection$1,
5504
+ ConnectionMonitor: ConnectionMonitor$1,
4692
5505
  Consumer: Consumer,
4693
5506
  INTERNAL: INTERNAL,
4694
5507
  Subscription: Subscription,
4695
5508
  Subscriptions: Subscriptions,
4696
- SubscriptionGuarantor: SubscriptionGuarantor,
5509
+ SubscriptionGuarantor: SubscriptionGuarantor$1,
4697
5510
  adapters: adapters,
4698
5511
  createWebSocketURL: createWebSocketURL,
4699
5512
  logger: logger,
4700
- createConsumer: createConsumer$1,
5513
+ createConsumer: createConsumer,
4701
5514
  getConfig: getConfig
4702
5515
  });
4703
5516