diff --git a/app/assets/builds/rosetta/application.css b/app/assets/builds/rosetta/application.css
index 6684207..becea92 100644
--- a/app/assets/builds/rosetta/application.css
+++ b/app/assets/builds/rosetta/application.css
@@ -1,560 +1 @@
-/*
-! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com
-*/
-
-/*
-1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
-2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
-*/
-
-*,
-::before,
-::after {
- box-sizing: border-box;
- /* 1 */
- border-width: 0;
- /* 2 */
- border-style: solid;
- /* 2 */
- border-color: #e5e7eb;
- /* 2 */
-}
-
-::before,
-::after {
- --tw-content: '';
-}
-
-/*
-1. Use a consistent sensible line-height in all browsers.
-2. Prevent adjustments of font size after orientation changes in iOS.
-3. Use a more readable tab size.
-4. Use the user's configured `sans` font-family by default.
-5. Use the user's configured `sans` font-feature-settings by default.
-6. Use the user's configured `sans` font-variation-settings by default.
-7. Disable tap highlights on iOS
-*/
-
-html,
-:host {
- line-height: 1.5;
- /* 1 */
- -webkit-text-size-adjust: 100%;
- /* 2 */
- -moz-tab-size: 4;
- /* 3 */
- -o-tab-size: 4;
- tab-size: 4;
- /* 3 */
- font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
- /* 4 */
- font-feature-settings: normal;
- /* 5 */
- font-variation-settings: normal;
- /* 6 */
- -webkit-tap-highlight-color: transparent;
- /* 7 */
-}
-
-/*
-1. Remove the margin in all browsers.
-2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
-*/
-
-body {
- margin: 0;
- /* 1 */
- line-height: inherit;
- /* 2 */
-}
-
-/*
-1. Add the correct height in Firefox.
-2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
-3. Ensure horizontal rules are visible by default.
-*/
-
-hr {
- height: 0;
- /* 1 */
- color: inherit;
- /* 2 */
- border-top-width: 1px;
- /* 3 */
-}
-
-/*
-Add the correct text decoration in Chrome, Edge, and Safari.
-*/
-
-abbr:where([title]) {
- -webkit-text-decoration: underline dotted;
- text-decoration: underline dotted;
-}
-
-/*
-Remove the default font size and weight for headings.
-*/
-
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- font-size: inherit;
- font-weight: inherit;
-}
-
-/*
-Reset links to optimize for opt-in styling instead of opt-out.
-*/
-
-a {
- color: inherit;
- text-decoration: inherit;
-}
-
-/*
-Add the correct font weight in Edge and Safari.
-*/
-
-b,
-strong {
- font-weight: bolder;
-}
-
-/*
-1. Use the user's configured `mono` font-family by default.
-2. Use the user's configured `mono` font-feature-settings by default.
-3. Use the user's configured `mono` font-variation-settings by default.
-4. Correct the odd `em` font sizing in all browsers.
-*/
-
-code,
-kbd,
-samp,
-pre {
- font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
- /* 1 */
- font-feature-settings: normal;
- /* 2 */
- font-variation-settings: normal;
- /* 3 */
- font-size: 1em;
- /* 4 */
-}
-
-/*
-Add the correct font size in all browsers.
-*/
-
-small {
- font-size: 80%;
-}
-
-/*
-Prevent `sub` and `sup` elements from affecting the line height in all browsers.
-*/
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-sup {
- top: -0.5em;
-}
-
-/*
-1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
-2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
-3. Remove gaps between table borders by default.
-*/
-
-table {
- text-indent: 0;
- /* 1 */
- border-color: inherit;
- /* 2 */
- border-collapse: collapse;
- /* 3 */
-}
-
-/*
-1. Change the font styles in all browsers.
-2. Remove the margin in Firefox and Safari.
-3. Remove default padding in all browsers.
-*/
-
-button,
-input,
-optgroup,
-select,
-textarea {
- font-family: inherit;
- /* 1 */
- font-feature-settings: inherit;
- /* 1 */
- font-variation-settings: inherit;
- /* 1 */
- font-size: 100%;
- /* 1 */
- font-weight: inherit;
- /* 1 */
- line-height: inherit;
- /* 1 */
- letter-spacing: inherit;
- /* 1 */
- color: inherit;
- /* 1 */
- margin: 0;
- /* 2 */
- padding: 0;
- /* 3 */
-}
-
-/*
-Remove the inheritance of text transform in Edge and Firefox.
-*/
-
-button,
-select {
- text-transform: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Remove default button styles.
-*/
-
-button,
-input:where([type='button']),
-input:where([type='reset']),
-input:where([type='submit']) {
- -webkit-appearance: button;
- /* 1 */
- background-color: transparent;
- /* 2 */
- background-image: none;
- /* 2 */
-}
-
-/*
-Use the modern Firefox focus style for all focusable elements.
-*/
-
-:-moz-focusring {
- outline: auto;
-}
-
-/*
-Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
-*/
-
-:-moz-ui-invalid {
- box-shadow: none;
-}
-
-/*
-Add the correct vertical alignment in Chrome and Firefox.
-*/
-
-progress {
- vertical-align: baseline;
-}
-
-/*
-Correct the cursor style of increment and decrement buttons in Safari.
-*/
-
-::-webkit-inner-spin-button,
-::-webkit-outer-spin-button {
- height: auto;
-}
-
-/*
-1. Correct the odd appearance in Chrome and Safari.
-2. Correct the outline style in Safari.
-*/
-
-[type='search'] {
- -webkit-appearance: textfield;
- /* 1 */
- outline-offset: -2px;
- /* 2 */
-}
-
-/*
-Remove the inner padding in Chrome and Safari on macOS.
-*/
-
-::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/*
-1. Correct the inability to style clickable types in iOS and Safari.
-2. Change font properties to `inherit` in Safari.
-*/
-
-::-webkit-file-upload-button {
- -webkit-appearance: button;
- /* 1 */
- font: inherit;
- /* 2 */
-}
-
-/*
-Add the correct display in Chrome and Safari.
-*/
-
-summary {
- display: list-item;
-}
-
-/*
-Removes the default spacing and border for appropriate elements.
-*/
-
-blockquote,
-dl,
-dd,
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-hr,
-figure,
-p,
-pre {
- margin: 0;
-}
-
-fieldset {
- margin: 0;
- padding: 0;
-}
-
-legend {
- padding: 0;
-}
-
-ol,
-ul,
-menu {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-/*
-Reset default styling for dialogs.
-*/
-
-dialog {
- padding: 0;
-}
-
-/*
-Prevent resizing textareas horizontally by default.
-*/
-
-textarea {
- resize: vertical;
-}
-
-/*
-1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
-2. Set the default placeholder color to the user's configured gray 400 color.
-*/
-
-input::-moz-placeholder, textarea::-moz-placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-input::placeholder,
-textarea::placeholder {
- opacity: 1;
- /* 1 */
- color: #9ca3af;
- /* 2 */
-}
-
-/*
-Set the default cursor for buttons.
-*/
-
-button,
-[role="button"] {
- cursor: pointer;
-}
-
-/*
-Make sure disabled buttons don't get the pointer cursor.
-*/
-
-:disabled {
- cursor: default;
-}
-
-/*
-1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
-2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
- This can trigger a poorly considered lint error in some tools but is included by design.
-*/
-
-img,
-svg,
-video,
-canvas,
-audio,
-iframe,
-embed,
-object {
- display: block;
- /* 1 */
- vertical-align: middle;
- /* 2 */
-}
-
-/*
-Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
-*/
-
-img,
-video {
- max-width: 100%;
- height: auto;
-}
-
-/* Make elements with the HTML hidden attribute stay hidden by default */
-
-[hidden] {
- display: none;
-}
-
-*, ::before, ::after {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
- --tw-contain-size: ;
- --tw-contain-layout: ;
- --tw-contain-paint: ;
- --tw-contain-style: ;
-}
-
-::backdrop {
- --tw-border-spacing-x: 0;
- --tw-border-spacing-y: 0;
- --tw-translate-x: 0;
- --tw-translate-y: 0;
- --tw-rotate: 0;
- --tw-skew-x: 0;
- --tw-skew-y: 0;
- --tw-scale-x: 1;
- --tw-scale-y: 1;
- --tw-pan-x: ;
- --tw-pan-y: ;
- --tw-pinch-zoom: ;
- --tw-scroll-snap-strictness: proximity;
- --tw-gradient-from-position: ;
- --tw-gradient-via-position: ;
- --tw-gradient-to-position: ;
- --tw-ordinal: ;
- --tw-slashed-zero: ;
- --tw-numeric-figure: ;
- --tw-numeric-spacing: ;
- --tw-numeric-fraction: ;
- --tw-ring-inset: ;
- --tw-ring-offset-width: 0px;
- --tw-ring-offset-color: #fff;
- --tw-ring-color: rgb(59 130 246 / 0.5);
- --tw-ring-offset-shadow: 0 0 #0000;
- --tw-ring-shadow: 0 0 #0000;
- --tw-shadow: 0 0 #0000;
- --tw-shadow-colored: 0 0 #0000;
- --tw-blur: ;
- --tw-brightness: ;
- --tw-contrast: ;
- --tw-grayscale: ;
- --tw-hue-rotate: ;
- --tw-invert: ;
- --tw-saturate: ;
- --tw-sepia: ;
- --tw-drop-shadow: ;
- --tw-backdrop-blur: ;
- --tw-backdrop-brightness: ;
- --tw-backdrop-contrast: ;
- --tw-backdrop-grayscale: ;
- --tw-backdrop-hue-rotate: ;
- --tw-backdrop-invert: ;
- --tw-backdrop-opacity: ;
- --tw-backdrop-saturate: ;
- --tw-backdrop-sepia: ;
- --tw-contain-size: ;
- --tw-contain-layout: ;
- --tw-contain-paint: ;
- --tw-contain-style: ;
-}
-
-.text-3xl {
- font-size: 1.875rem;
- line-height: 2.25rem;
-}
+/*! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[multiple],[type=date],[type=datetime-local],[type=email],[type=month],[type=number],[type=password],[type=search],[type=tel],[type=text],[type=time],[type=url],[type=week],input:where(:not([type])),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#6b7280;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow:0 0 #0000}[multiple]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=email]:focus,[type=month]:focus,[type=number]:focus,[type=password]:focus,[type=search]:focus,[type=tel]:focus,[type=text]:focus,[type=time]:focus,[type=url]:focus,[type=week]:focus,input:where(:not([type])):focus,select:focus,textarea:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#6b7280;opacity:1}input::placeholder,textarea::placeholder{color:#6b7280;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='m6 8 4 4 4-4'/%3E%3C/svg%3E");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple],[size]:where(select:not([size="1"])){background-image:none;background-position:0 0;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#6b7280;border-width:1px;--tw-shadow:0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:#2563eb;--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M12.207 4.793a1 1 0 0 1 0 1.414l-5 5a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L6.5 9.086l4.293-4.293a1 1 0 0 1 1.414 0'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=checkbox]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=radio]:checked{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='3'/%3E%3C/svg%3E")}@media (forced-colors:active) {[type=radio]:checked{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:checked:focus,[type=checkbox]:checked:hover,[type=radio]:checked:focus,[type=radio]:checked:hover{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3E%3Cpath stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3E%3C/svg%3E");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:50%;background-repeat:no-repeat}@media (forced-colors:active) {[type=checkbox]:indeterminate{-webkit-appearance:auto;-moz-appearance:auto;appearance:auto}}[type=checkbox]:indeterminate:focus,[type=checkbox]:indeterminate:hover{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.btn{border-radius:.375rem;padding:.5rem .75rem;font-size:.875rem;line-height:1.25rem;font-weight:600;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.btn:focus-visible{outline-style:solid;outline-width:2px;outline-offset:2px}.btn-primary{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.btn-primary:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.btn-primary:focus-visible{outline-color:#4f46e5}.label{font-size:.875rem;font-weight:500;line-height:1.5rem}.input,.label{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.input{display:block;width:100%;border-radius:.375rem;border-width:0;padding-top:.375rem;padding-bottom:.375rem;--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-inset:inset;--tw-ring-opacity:1;--tw-ring-color:rgb(209 213 219/var(--tw-ring-opacity))}.input::-moz-placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.input::placeholder{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.input:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-inset:inset;--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}@media (min-width:640px){.input{font-size:.875rem;line-height:1.5rem}}.badge{display:inline-flex;align-items:center;border-radius:.375rem;--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity));padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500;--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity));--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000);--tw-ring-inset:inset;--tw-ring-color:hsla(220,9%,46%,.1)}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.absolute{position:absolute}.relative{position:relative}.left-0{left:0}.top-4{top:1rem}.m-0{margin:0}.mx-auto{margin-left:auto;margin-right:auto}.ml-3{margin-left:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-full{height:100%}.min-h-full{min-height:100%}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-full{width:100%}.min-w-full{min-width:100%}.max-w-24{max-width:6rem}.max-w-4xl{max-width:56rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-shrink-0{flex-shrink:0}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-2{gap:.5rem}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-gray-200>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(229 231 235/var(--tw-divide-opacity))}.divide-gray-300>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(209 213 219/var(--tw-divide-opacity))}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border-b{border-bottom-width:1px}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.p-12{padding:3rem}.p-4{padding:1rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.text-left{text-align:left}.text-right{text-align:right}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.leading-6{line-height:1.5rem}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-red-400{--tw-text-opacity:1;color:rgb(248 113 113/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.hover\:text-gray-500:hover{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.hover\:text-indigo-900:hover{--tw-text-opacity:1;color:rgb(49 46 129/var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}@media (min-width:640px){.sm\:ml-16{margin-left:4rem}.sm\:mt-0{margin-top:0}.sm\:flex{display:flex}.sm\:flex-auto{flex:1 1 auto}.sm\:flex-none{flex:none}.sm\:items-center{align-items:center}.sm\:rounded-lg{border-radius:.5rem}.sm\:px-6{padding-right:1.5rem}.sm\:pl-6,.sm\:px-6{padding-left:1.5rem}.sm\:pr-6{padding-right:1.5rem}}@media (min-width:1024px){.lg\:px-8{padding-left:2rem;padding-right:2rem}}
\ No newline at end of file
diff --git a/app/assets/builds/rosetta/application.js b/app/assets/builds/rosetta/application.js
index dff84fd..7017457 100644
--- a/app/assets/builds/rosetta/application.js
+++ b/app/assets/builds/rosetta/application.js
@@ -1,5794 +1,8283 @@
-var __defProp = Object.defineProperty;
-var __getOwnPropNames = Object.getOwnPropertyNames;
-var __esm = (fn, res) => function __init() {
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
-};
-var __export = (target, all) => {
- for (var name in all)
- __defProp(target, name, { get: all[name], enumerable: true });
-};
+(() => {
+ var __defProp = Object.defineProperty;
+ var __getOwnPropNames = Object.getOwnPropertyNames;
+ var __esm = (fn, res) => function __init() {
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
+ };
+ var __export = (target, all) => {
+ for (var name in all)
+ __defProp(target, name, { get: all[name], enumerable: true });
+ };
+
+ // node_modules/@rails/actioncable/src/adapters.js
+ var adapters_default;
+ var init_adapters = __esm({
+ "node_modules/@rails/actioncable/src/adapters.js"() {
+ adapters_default = {
+ logger: typeof console !== "undefined" ? console : void 0,
+ WebSocket: typeof WebSocket !== "undefined" ? WebSocket : void 0
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/logger.js
+ var logger_default;
+ var init_logger = __esm({
+ "node_modules/@rails/actioncable/src/logger.js"() {
+ init_adapters();
+ logger_default = {
+ log(...messages) {
+ if (this.enabled) {
+ messages.push(Date.now());
+ adapters_default.logger.log("[ActionCable]", ...messages);
+ }
+ }
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/connection_monitor.js
+ var now, secondsSince, ConnectionMonitor, connection_monitor_default;
+ var init_connection_monitor = __esm({
+ "node_modules/@rails/actioncable/src/connection_monitor.js"() {
+ init_logger();
+ now = () => (/* @__PURE__ */ new Date()).getTime();
+ secondsSince = (time) => (now() - time) / 1e3;
+ ConnectionMonitor = class {
+ constructor(connection) {
+ this.visibilityDidChange = this.visibilityDidChange.bind(this);
+ this.connection = connection;
+ this.reconnectAttempts = 0;
+ }
+ start() {
+ if (!this.isRunning()) {
+ this.startedAt = now();
+ delete this.stoppedAt;
+ this.startPolling();
+ addEventListener("visibilitychange", this.visibilityDidChange);
+ logger_default.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`);
+ }
+ }
+ stop() {
+ if (this.isRunning()) {
+ this.stoppedAt = now();
+ this.stopPolling();
+ removeEventListener("visibilitychange", this.visibilityDidChange);
+ logger_default.log("ConnectionMonitor stopped");
+ }
+ }
+ isRunning() {
+ return this.startedAt && !this.stoppedAt;
+ }
+ recordMessage() {
+ this.pingedAt = now();
+ }
+ recordConnect() {
+ this.reconnectAttempts = 0;
+ delete this.disconnectedAt;
+ logger_default.log("ConnectionMonitor recorded connect");
+ }
+ recordDisconnect() {
+ this.disconnectedAt = now();
+ logger_default.log("ConnectionMonitor recorded disconnect");
+ }
+ // Private
+ startPolling() {
+ this.stopPolling();
+ this.poll();
+ }
+ stopPolling() {
+ clearTimeout(this.pollTimeout);
+ }
+ poll() {
+ this.pollTimeout = setTimeout(
+ () => {
+ this.reconnectIfStale();
+ this.poll();
+ },
+ this.getPollInterval()
+ );
+ }
+ getPollInterval() {
+ const { staleThreshold, reconnectionBackoffRate } = this.constructor;
+ const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10));
+ const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate;
+ const jitter = jitterMax * Math.random();
+ return staleThreshold * 1e3 * backoff * (1 + jitter);
+ }
+ reconnectIfStale() {
+ if (this.connectionIsStale()) {
+ logger_default.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`);
+ this.reconnectAttempts++;
+ if (this.disconnectedRecently()) {
+ logger_default.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`);
+ } else {
+ logger_default.log("ConnectionMonitor reopening");
+ this.connection.reopen();
+ }
+ }
+ }
+ get refreshedAt() {
+ return this.pingedAt ? this.pingedAt : this.startedAt;
+ }
+ connectionIsStale() {
+ return secondsSince(this.refreshedAt) > this.constructor.staleThreshold;
+ }
+ disconnectedRecently() {
+ return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold;
+ }
+ visibilityDidChange() {
+ if (document.visibilityState === "visible") {
+ setTimeout(
+ () => {
+ if (this.connectionIsStale() || !this.connection.isOpen()) {
+ logger_default.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`);
+ this.connection.reopen();
+ }
+ },
+ 200
+ );
+ }
+ }
+ };
+ ConnectionMonitor.staleThreshold = 6;
+ ConnectionMonitor.reconnectionBackoffRate = 0.15;
+ connection_monitor_default = ConnectionMonitor;
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/internal.js
+ var internal_default;
+ var init_internal = __esm({
+ "node_modules/@rails/actioncable/src/internal.js"() {
+ internal_default = {
+ "message_types": {
+ "welcome": "welcome",
+ "disconnect": "disconnect",
+ "ping": "ping",
+ "confirmation": "confirm_subscription",
+ "rejection": "reject_subscription"
+ },
+ "disconnect_reasons": {
+ "unauthorized": "unauthorized",
+ "invalid_request": "invalid_request",
+ "server_restart": "server_restart",
+ "remote": "remote"
+ },
+ "default_mount_path": "/cable",
+ "protocols": [
+ "actioncable-v1-json",
+ "actioncable-unsupported"
+ ]
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/connection.js
+ var message_types, protocols, supportedProtocols, indexOf, Connection, connection_default;
+ var init_connection = __esm({
+ "node_modules/@rails/actioncable/src/connection.js"() {
+ init_adapters();
+ init_connection_monitor();
+ init_internal();
+ init_logger();
+ ({ message_types, protocols } = internal_default);
+ supportedProtocols = protocols.slice(0, protocols.length - 1);
+ indexOf = [].indexOf;
+ Connection = class {
+ constructor(consumer2) {
+ this.open = this.open.bind(this);
+ this.consumer = consumer2;
+ this.subscriptions = this.consumer.subscriptions;
+ this.monitor = new connection_monitor_default(this);
+ this.disconnected = true;
+ }
+ send(data) {
+ if (this.isOpen()) {
+ this.webSocket.send(JSON.stringify(data));
+ return true;
+ } else {
+ return false;
+ }
+ }
+ open() {
+ if (this.isActive()) {
+ logger_default.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
+ return false;
+ } else {
+ const socketProtocols = [...protocols, ...this.consumer.subprotocols || []];
+ logger_default.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);
+ if (this.webSocket) {
+ this.uninstallEventHandlers();
+ }
+ this.webSocket = new adapters_default.WebSocket(this.consumer.url, socketProtocols);
+ this.installEventHandlers();
+ this.monitor.start();
+ return true;
+ }
+ }
+ close({ allowReconnect } = { allowReconnect: true }) {
+ if (!allowReconnect) {
+ this.monitor.stop();
+ }
+ if (this.isOpen()) {
+ return this.webSocket.close();
+ }
+ }
+ reopen() {
+ logger_default.log(`Reopening WebSocket, current state is ${this.getState()}`);
+ if (this.isActive()) {
+ try {
+ return this.close();
+ } catch (error2) {
+ logger_default.log("Failed to reopen WebSocket", error2);
+ } finally {
+ logger_default.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`);
+ setTimeout(this.open, this.constructor.reopenDelay);
+ }
+ } else {
+ return this.open();
+ }
+ }
+ getProtocol() {
+ if (this.webSocket) {
+ return this.webSocket.protocol;
+ }
+ }
+ isOpen() {
+ return this.isState("open");
+ }
+ isActive() {
+ return this.isState("open", "connecting");
+ }
+ triedToReconnect() {
+ return this.monitor.reconnectAttempts > 0;
+ }
+ // Private
+ isProtocolSupported() {
+ return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
+ }
+ isState(...states) {
+ return indexOf.call(states, this.getState()) >= 0;
+ }
+ getState() {
+ if (this.webSocket) {
+ for (let state in adapters_default.WebSocket) {
+ if (adapters_default.WebSocket[state] === this.webSocket.readyState) {
+ return state.toLowerCase();
+ }
+ }
+ }
+ return null;
+ }
+ installEventHandlers() {
+ for (let eventName in this.events) {
+ const handler = this.events[eventName].bind(this);
+ this.webSocket[`on${eventName}`] = handler;
+ }
+ }
+ uninstallEventHandlers() {
+ for (let eventName in this.events) {
+ this.webSocket[`on${eventName}`] = function() {
+ };
+ }
+ }
+ };
+ Connection.reopenDelay = 500;
+ Connection.prototype.events = {
+ message(event) {
+ if (!this.isProtocolSupported()) {
+ return;
+ }
+ const { identifier, message, reason, reconnect, type } = JSON.parse(event.data);
+ this.monitor.recordMessage();
+ switch (type) {
+ case message_types.welcome:
+ if (this.triedToReconnect()) {
+ this.reconnectAttempted = true;
+ }
+ this.monitor.recordConnect();
+ return this.subscriptions.reload();
+ case message_types.disconnect:
+ logger_default.log(`Disconnecting. Reason: ${reason}`);
+ return this.close({ allowReconnect: reconnect });
+ case message_types.ping:
+ return null;
+ case message_types.confirmation:
+ this.subscriptions.confirmSubscription(identifier);
+ if (this.reconnectAttempted) {
+ this.reconnectAttempted = false;
+ return this.subscriptions.notify(identifier, "connected", { reconnected: true });
+ } else {
+ return this.subscriptions.notify(identifier, "connected", { reconnected: false });
+ }
+ case message_types.rejection:
+ return this.subscriptions.reject(identifier);
+ default:
+ return this.subscriptions.notify(identifier, "received", message);
+ }
+ },
+ open() {
+ logger_default.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`);
+ this.disconnected = false;
+ if (!this.isProtocolSupported()) {
+ logger_default.log("Protocol is unsupported. Stopping monitor and disconnecting.");
+ return this.close({ allowReconnect: false });
+ }
+ },
+ close(event) {
+ logger_default.log("WebSocket onclose event");
+ if (this.disconnected) {
+ return;
+ }
+ this.disconnected = true;
+ this.monitor.recordDisconnect();
+ return this.subscriptions.notifyAll("disconnected", { willAttemptReconnect: this.monitor.isRunning() });
+ },
+ error() {
+ logger_default.log("WebSocket onerror event");
+ }
+ };
+ connection_default = Connection;
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/subscription.js
+ var extend, Subscription;
+ var init_subscription = __esm({
+ "node_modules/@rails/actioncable/src/subscription.js"() {
+ extend = function(object, properties) {
+ if (properties != null) {
+ for (let key in properties) {
+ const value = properties[key];
+ object[key] = value;
+ }
+ }
+ return object;
+ };
+ Subscription = class {
+ constructor(consumer2, params = {}, mixin) {
+ this.consumer = consumer2;
+ this.identifier = JSON.stringify(params);
+ extend(this, mixin);
+ }
+ // Perform a channel action with the optional data passed as an attribute
+ perform(action, data = {}) {
+ data.action = action;
+ return this.send(data);
+ }
+ send(data) {
+ return this.consumer.send({ command: "message", identifier: this.identifier, data: JSON.stringify(data) });
+ }
+ unsubscribe() {
+ return this.consumer.subscriptions.remove(this);
+ }
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/subscription_guarantor.js
+ var SubscriptionGuarantor, subscription_guarantor_default;
+ var init_subscription_guarantor = __esm({
+ "node_modules/@rails/actioncable/src/subscription_guarantor.js"() {
+ init_logger();
+ SubscriptionGuarantor = class {
+ constructor(subscriptions) {
+ this.subscriptions = subscriptions;
+ this.pendingSubscriptions = [];
+ }
+ guarantee(subscription) {
+ if (this.pendingSubscriptions.indexOf(subscription) == -1) {
+ logger_default.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`);
+ this.pendingSubscriptions.push(subscription);
+ } else {
+ logger_default.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`);
+ }
+ this.startGuaranteeing();
+ }
+ forget(subscription) {
+ logger_default.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`);
+ this.pendingSubscriptions = this.pendingSubscriptions.filter((s) => s !== subscription);
+ }
+ startGuaranteeing() {
+ this.stopGuaranteeing();
+ this.retrySubscribing();
+ }
+ stopGuaranteeing() {
+ clearTimeout(this.retryTimeout);
+ }
+ retrySubscribing() {
+ this.retryTimeout = setTimeout(
+ () => {
+ if (this.subscriptions && typeof this.subscriptions.subscribe === "function") {
+ this.pendingSubscriptions.map((subscription) => {
+ logger_default.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`);
+ this.subscriptions.subscribe(subscription);
+ });
+ }
+ },
+ 500
+ );
+ }
+ };
+ subscription_guarantor_default = SubscriptionGuarantor;
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/subscriptions.js
+ var Subscriptions;
+ var init_subscriptions = __esm({
+ "node_modules/@rails/actioncable/src/subscriptions.js"() {
+ init_subscription();
+ init_subscription_guarantor();
+ init_logger();
+ Subscriptions = class {
+ constructor(consumer2) {
+ this.consumer = consumer2;
+ this.guarantor = new subscription_guarantor_default(this);
+ this.subscriptions = [];
+ }
+ create(channelName, mixin) {
+ const channel = channelName;
+ const params = typeof channel === "object" ? channel : { channel };
+ const subscription = new Subscription(this.consumer, params, mixin);
+ return this.add(subscription);
+ }
+ // Private
+ add(subscription) {
+ this.subscriptions.push(subscription);
+ this.consumer.ensureActiveConnection();
+ this.notify(subscription, "initialized");
+ this.subscribe(subscription);
+ return subscription;
+ }
+ remove(subscription) {
+ this.forget(subscription);
+ if (!this.findAll(subscription.identifier).length) {
+ this.sendCommand(subscription, "unsubscribe");
+ }
+ return subscription;
+ }
+ reject(identifier) {
+ return this.findAll(identifier).map((subscription) => {
+ this.forget(subscription);
+ this.notify(subscription, "rejected");
+ return subscription;
+ });
+ }
+ forget(subscription) {
+ this.guarantor.forget(subscription);
+ this.subscriptions = this.subscriptions.filter((s) => s !== subscription);
+ return subscription;
+ }
+ findAll(identifier) {
+ return this.subscriptions.filter((s) => s.identifier === identifier);
+ }
+ reload() {
+ return this.subscriptions.map((subscription) => this.subscribe(subscription));
+ }
+ notifyAll(callbackName, ...args) {
+ return this.subscriptions.map((subscription) => this.notify(subscription, callbackName, ...args));
+ }
+ notify(subscription, callbackName, ...args) {
+ let subscriptions;
+ if (typeof subscription === "string") {
+ subscriptions = this.findAll(subscription);
+ } else {
+ subscriptions = [subscription];
+ }
+ return subscriptions.map((subscription2) => typeof subscription2[callbackName] === "function" ? subscription2[callbackName](...args) : void 0);
+ }
+ subscribe(subscription) {
+ if (this.sendCommand(subscription, "subscribe")) {
+ this.guarantor.guarantee(subscription);
+ }
+ }
+ confirmSubscription(identifier) {
+ logger_default.log(`Subscription confirmed ${identifier}`);
+ this.findAll(identifier).map((subscription) => this.guarantor.forget(subscription));
+ }
+ sendCommand(subscription, command) {
+ const { identifier } = subscription;
+ return this.consumer.send({ command, identifier });
+ }
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/consumer.js
+ function createWebSocketURL(url) {
+ if (typeof url === "function") {
+ url = url();
+ }
+ if (url && !/^wss?:/i.test(url)) {
+ const a = document.createElement("a");
+ a.href = url;
+ a.href = a.href;
+ a.protocol = a.protocol.replace("http", "ws");
+ return a.href;
+ } else {
+ return url;
+ }
+ }
+ var Consumer;
+ var init_consumer = __esm({
+ "node_modules/@rails/actioncable/src/consumer.js"() {
+ init_connection();
+ init_subscriptions();
+ Consumer = class {
+ constructor(url) {
+ this._url = url;
+ this.subscriptions = new Subscriptions(this);
+ this.connection = new connection_default(this);
+ this.subprotocols = [];
+ }
+ get url() {
+ return createWebSocketURL(this._url);
+ }
+ send(data) {
+ return this.connection.send(data);
+ }
+ connect() {
+ return this.connection.open();
+ }
+ disconnect() {
+ return this.connection.close({ allowReconnect: false });
+ }
+ ensureActiveConnection() {
+ if (!this.connection.isActive()) {
+ return this.connection.open();
+ }
+ }
+ addSubProtocol(subprotocol) {
+ this.subprotocols = [...this.subprotocols, subprotocol];
+ }
+ };
+ }
+ });
+
+ // node_modules/@rails/actioncable/src/index.js
+ var src_exports = {};
+ __export(src_exports, {
+ Connection: () => connection_default,
+ ConnectionMonitor: () => connection_monitor_default,
+ Consumer: () => Consumer,
+ INTERNAL: () => internal_default,
+ Subscription: () => Subscription,
+ SubscriptionGuarantor: () => subscription_guarantor_default,
+ Subscriptions: () => Subscriptions,
+ adapters: () => adapters_default,
+ createConsumer: () => createConsumer,
+ createWebSocketURL: () => createWebSocketURL,
+ getConfig: () => getConfig,
+ logger: () => logger_default
+ });
+ function createConsumer(url = getConfig("url") || internal_default.default_mount_path) {
+ return new Consumer(url);
+ }
+ function getConfig(name) {
+ const element = document.head.querySelector(`meta[name='action-cable-${name}']`);
+ if (element) {
+ return element.getAttribute("content");
+ }
+ }
+ var init_src = __esm({
+ "node_modules/@rails/actioncable/src/index.js"() {
+ init_connection();
+ init_connection_monitor();
+ init_consumer();
+ init_internal();
+ init_subscription();
+ init_subscriptions();
+ init_subscription_guarantor();
+ init_adapters();
+ init_logger();
+ }
+ });
-// node_modules/@rails/actioncable/src/adapters.js
-var adapters_default;
-var init_adapters = __esm({
- "node_modules/@rails/actioncable/src/adapters.js"() {
- adapters_default = {
- logger: typeof console !== "undefined" ? console : void 0,
- WebSocket: typeof WebSocket !== "undefined" ? WebSocket : void 0
+ // node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
+ var turbo_es2017_esm_exports = {};
+ __export(turbo_es2017_esm_exports, {
+ FetchEnctype: () => FetchEnctype,
+ FetchMethod: () => FetchMethod,
+ FetchRequest: () => FetchRequest,
+ FetchResponse: () => FetchResponse,
+ FrameElement: () => FrameElement,
+ FrameLoadingStyle: () => FrameLoadingStyle,
+ FrameRenderer: () => FrameRenderer,
+ PageRenderer: () => PageRenderer,
+ PageSnapshot: () => PageSnapshot,
+ StreamActions: () => StreamActions,
+ StreamElement: () => StreamElement,
+ StreamSourceElement: () => StreamSourceElement,
+ cache: () => cache,
+ clearCache: () => clearCache,
+ connectStreamSource: () => connectStreamSource,
+ disconnectStreamSource: () => disconnectStreamSource,
+ fetch: () => fetchWithTurboHeaders,
+ fetchEnctypeFromString: () => fetchEnctypeFromString,
+ fetchMethodFromString: () => fetchMethodFromString,
+ isSafe: () => isSafe,
+ navigator: () => navigator$1,
+ registerAdapter: () => registerAdapter,
+ renderStreamMessage: () => renderStreamMessage,
+ session: () => session,
+ setConfirmMethod: () => setConfirmMethod,
+ setFormMode: () => setFormMode,
+ setProgressBarDelay: () => setProgressBarDelay,
+ start: () => start,
+ visit: () => visit
+ });
+ (function(prototype) {
+ if (typeof prototype.requestSubmit == "function") return;
+ prototype.requestSubmit = function(submitter) {
+ if (submitter) {
+ validateSubmitter(submitter, this);
+ submitter.click();
+ } else {
+ submitter = document.createElement("input");
+ submitter.type = "submit";
+ submitter.hidden = true;
+ this.appendChild(submitter);
+ submitter.click();
+ this.removeChild(submitter);
+ }
+ };
+ function validateSubmitter(submitter, form) {
+ submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
+ submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
+ submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
+ }
+ function raise(errorConstructor, message, name) {
+ throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name);
+ }
+ })(HTMLFormElement.prototype);
+ var submittersByForm = /* @__PURE__ */ new WeakMap();
+ function findSubmitterFromClickTarget(target) {
+ const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
+ const candidate = element ? element.closest("input, button") : null;
+ return candidate?.type == "submit" ? candidate : null;
+ }
+ function clickCaptured(event) {
+ const submitter = findSubmitterFromClickTarget(event.target);
+ if (submitter && submitter.form) {
+ submittersByForm.set(submitter.form, submitter);
+ }
+ }
+ (function() {
+ if ("submitter" in Event.prototype) return;
+ let prototype = window.Event.prototype;
+ if ("SubmitEvent" in window) {
+ const prototypeOfSubmitEvent = window.SubmitEvent.prototype;
+ if (/Apple Computer/.test(navigator.vendor) && !("submitter" in prototypeOfSubmitEvent)) {
+ prototype = prototypeOfSubmitEvent;
+ } else {
+ return;
+ }
+ }
+ addEventListener("click", clickCaptured, true);
+ Object.defineProperty(prototype, "submitter", {
+ get() {
+ if (this.type == "submit" && this.target instanceof HTMLFormElement) {
+ return submittersByForm.get(this.target);
+ }
+ }
+ });
+ })();
+ var FrameLoadingStyle = {
+ eager: "eager",
+ lazy: "lazy"
+ };
+ var FrameElement = class _FrameElement extends HTMLElement {
+ static delegateConstructor = void 0;
+ loaded = Promise.resolve();
+ static get observedAttributes() {
+ return ["disabled", "loading", "src"];
+ }
+ constructor() {
+ super();
+ this.delegate = new _FrameElement.delegateConstructor(this);
+ }
+ connectedCallback() {
+ this.delegate.connect();
+ }
+ disconnectedCallback() {
+ this.delegate.disconnect();
+ }
+ reload() {
+ return this.delegate.sourceURLReloaded();
+ }
+ attributeChangedCallback(name) {
+ if (name == "loading") {
+ this.delegate.loadingStyleChanged();
+ } else if (name == "src") {
+ this.delegate.sourceURLChanged();
+ } else if (name == "disabled") {
+ this.delegate.disabledChanged();
+ }
+ }
+ /**
+ * Gets the URL to lazily load source HTML from
+ */
+ get src() {
+ return this.getAttribute("src");
+ }
+ /**
+ * Sets the URL to lazily load source HTML from
+ */
+ set src(value) {
+ if (value) {
+ this.setAttribute("src", value);
+ } else {
+ this.removeAttribute("src");
+ }
+ }
+ /**
+ * Gets the refresh mode for the frame.
+ */
+ get refresh() {
+ return this.getAttribute("refresh");
+ }
+ /**
+ * Sets the refresh mode for the frame.
+ */
+ set refresh(value) {
+ if (value) {
+ this.setAttribute("refresh", value);
+ } else {
+ this.removeAttribute("refresh");
+ }
+ }
+ /**
+ * Determines if the element is loading
+ */
+ get loading() {
+ return frameLoadingStyleFromString(this.getAttribute("loading") || "");
+ }
+ /**
+ * Sets the value of if the element is loading
+ */
+ set loading(value) {
+ if (value) {
+ this.setAttribute("loading", value);
+ } else {
+ this.removeAttribute("loading");
+ }
+ }
+ /**
+ * Gets the disabled state of the frame.
+ *
+ * If disabled, no requests will be intercepted by the frame.
+ */
+ get disabled() {
+ return this.hasAttribute("disabled");
+ }
+ /**
+ * Sets the disabled state of the frame.
+ *
+ * If disabled, no requests will be intercepted by the frame.
+ */
+ set disabled(value) {
+ if (value) {
+ this.setAttribute("disabled", "");
+ } else {
+ this.removeAttribute("disabled");
+ }
+ }
+ /**
+ * Gets the autoscroll state of the frame.
+ *
+ * If true, the frame will be scrolled into view automatically on update.
+ */
+ get autoscroll() {
+ return this.hasAttribute("autoscroll");
+ }
+ /**
+ * Sets the autoscroll state of the frame.
+ *
+ * If true, the frame will be scrolled into view automatically on update.
+ */
+ set autoscroll(value) {
+ if (value) {
+ this.setAttribute("autoscroll", "");
+ } else {
+ this.removeAttribute("autoscroll");
+ }
+ }
+ /**
+ * Determines if the element has finished loading
+ */
+ get complete() {
+ return !this.delegate.isLoading;
+ }
+ /**
+ * Gets the active state of the frame.
+ *
+ * If inactive, source changes will not be observed.
+ */
+ get isActive() {
+ return this.ownerDocument === document && !this.isPreview;
+ }
+ /**
+ * Sets the active state of the frame.
+ *
+ * If inactive, source changes will not be observed.
+ */
+ get isPreview() {
+ return this.ownerDocument?.documentElement?.hasAttribute("data-turbo-preview");
+ }
+ };
+ function frameLoadingStyleFromString(style) {
+ switch (style.toLowerCase()) {
+ case "lazy":
+ return FrameLoadingStyle.lazy;
+ default:
+ return FrameLoadingStyle.eager;
+ }
+ }
+ function expandURL(locatable) {
+ return new URL(locatable.toString(), document.baseURI);
+ }
+ function getAnchor(url) {
+ let anchorMatch;
+ if (url.hash) {
+ return url.hash.slice(1);
+ } else if (anchorMatch = url.href.match(/#(.*)$/)) {
+ return anchorMatch[1];
+ }
+ }
+ function getAction$1(form, submitter) {
+ const action = submitter?.getAttribute("formaction") || form.getAttribute("action") || form.action;
+ return expandURL(action);
+ }
+ function getExtension(url) {
+ return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
+ }
+ function isHTML(url) {
+ return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml|php))$/);
+ }
+ function isPrefixedBy(baseURL, url) {
+ const prefix = getPrefix(url);
+ return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
+ }
+ function locationIsVisitable(location2, rootLocation) {
+ return isPrefixedBy(location2, rootLocation) && isHTML(location2);
+ }
+ function getRequestURL(url) {
+ const anchor = getAnchor(url);
+ return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
+ }
+ function toCacheKey(url) {
+ return getRequestURL(url);
+ }
+ function urlsAreEqual(left, right) {
+ return expandURL(left).href == expandURL(right).href;
+ }
+ function getPathComponents(url) {
+ return url.pathname.split("/").slice(1);
+ }
+ function getLastPathComponent(url) {
+ return getPathComponents(url).slice(-1)[0];
+ }
+ function getPrefix(url) {
+ return addTrailingSlash(url.origin + url.pathname);
+ }
+ function addTrailingSlash(value) {
+ return value.endsWith("/") ? value : value + "/";
+ }
+ var FetchResponse = class {
+ constructor(response) {
+ this.response = response;
+ }
+ get succeeded() {
+ return this.response.ok;
+ }
+ get failed() {
+ return !this.succeeded;
+ }
+ get clientError() {
+ return this.statusCode >= 400 && this.statusCode <= 499;
+ }
+ get serverError() {
+ return this.statusCode >= 500 && this.statusCode <= 599;
+ }
+ get redirected() {
+ return this.response.redirected;
+ }
+ get location() {
+ return expandURL(this.response.url);
+ }
+ get isHTML() {
+ return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
+ }
+ get statusCode() {
+ return this.response.status;
+ }
+ get contentType() {
+ return this.header("Content-Type");
+ }
+ get responseText() {
+ return this.response.clone().text();
+ }
+ get responseHTML() {
+ if (this.isHTML) {
+ return this.response.clone().text();
+ } else {
+ return Promise.resolve(void 0);
+ }
+ }
+ header(name) {
+ return this.response.headers.get(name);
+ }
+ };
+ function activateScriptElement(element) {
+ if (element.getAttribute("data-turbo-eval") == "false") {
+ return element;
+ } else {
+ const createdScriptElement = document.createElement("script");
+ const cspNonce = getMetaContent("csp-nonce");
+ if (cspNonce) {
+ createdScriptElement.nonce = cspNonce;
+ }
+ createdScriptElement.textContent = element.textContent;
+ createdScriptElement.async = false;
+ copyElementAttributes(createdScriptElement, element);
+ return createdScriptElement;
+ }
+ }
+ function copyElementAttributes(destinationElement, sourceElement) {
+ for (const { name, value } of sourceElement.attributes) {
+ destinationElement.setAttribute(name, value);
+ }
+ }
+ function createDocumentFragment(html) {
+ const template = document.createElement("template");
+ template.innerHTML = html;
+ return template.content;
+ }
+ function dispatch(eventName, { target, cancelable, detail } = {}) {
+ const event = new CustomEvent(eventName, {
+ cancelable,
+ bubbles: true,
+ composed: true,
+ detail
+ });
+ if (target && target.isConnected) {
+ target.dispatchEvent(event);
+ } else {
+ document.documentElement.dispatchEvent(event);
+ }
+ return event;
+ }
+ function nextRepaint() {
+ if (document.visibilityState === "hidden") {
+ return nextEventLoopTick();
+ } else {
+ return nextAnimationFrame();
+ }
+ }
+ function nextAnimationFrame() {
+ return new Promise((resolve) => requestAnimationFrame(() => resolve()));
+ }
+ function nextEventLoopTick() {
+ return new Promise((resolve) => setTimeout(() => resolve(), 0));
+ }
+ function nextMicrotask() {
+ return Promise.resolve();
+ }
+ function parseHTMLDocument(html = "") {
+ return new DOMParser().parseFromString(html, "text/html");
+ }
+ function unindent(strings, ...values) {
+ const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
+ const match = lines[0].match(/^\s+/);
+ const indent = match ? match[0].length : 0;
+ return lines.map((line) => line.slice(indent)).join("\n");
+ }
+ function interpolate(strings, values) {
+ return strings.reduce((result, string, i) => {
+ const value = values[i] == void 0 ? "" : values[i];
+ return result + string + value;
+ }, "");
+ }
+ function uuid() {
+ return Array.from({ length: 36 }).map((_, i) => {
+ if (i == 8 || i == 13 || i == 18 || i == 23) {
+ return "-";
+ } else if (i == 14) {
+ return "4";
+ } else if (i == 19) {
+ return (Math.floor(Math.random() * 4) + 8).toString(16);
+ } else {
+ return Math.floor(Math.random() * 15).toString(16);
+ }
+ }).join("");
+ }
+ function getAttribute(attributeName, ...elements) {
+ for (const value of elements.map((element) => element?.getAttribute(attributeName))) {
+ if (typeof value == "string") return value;
+ }
+ return null;
+ }
+ function hasAttribute(attributeName, ...elements) {
+ return elements.some((element) => element && element.hasAttribute(attributeName));
+ }
+ function markAsBusy(...elements) {
+ for (const element of elements) {
+ if (element.localName == "turbo-frame") {
+ element.setAttribute("busy", "");
+ }
+ element.setAttribute("aria-busy", "true");
+ }
+ }
+ function clearBusyState(...elements) {
+ for (const element of elements) {
+ if (element.localName == "turbo-frame") {
+ element.removeAttribute("busy");
+ }
+ element.removeAttribute("aria-busy");
+ }
+ }
+ function waitForLoad(element, timeoutInMilliseconds = 2e3) {
+ return new Promise((resolve) => {
+ const onComplete = () => {
+ element.removeEventListener("error", onComplete);
+ element.removeEventListener("load", onComplete);
+ resolve();
+ };
+ element.addEventListener("load", onComplete, { once: true });
+ element.addEventListener("error", onComplete, { once: true });
+ setTimeout(resolve, timeoutInMilliseconds);
+ });
+ }
+ function getHistoryMethodForAction(action) {
+ switch (action) {
+ case "replace":
+ return history.replaceState;
+ case "advance":
+ case "restore":
+ return history.pushState;
+ }
+ }
+ function isAction(action) {
+ return action == "advance" || action == "replace" || action == "restore";
+ }
+ function getVisitAction(...elements) {
+ const action = getAttribute("data-turbo-action", ...elements);
+ return isAction(action) ? action : null;
+ }
+ function getMetaElement(name) {
+ return document.querySelector(`meta[name="${name}"]`);
+ }
+ function getMetaContent(name) {
+ const element = getMetaElement(name);
+ return element && element.content;
+ }
+ function setMetaContent(name, content) {
+ let element = getMetaElement(name);
+ if (!element) {
+ element = document.createElement("meta");
+ element.setAttribute("name", name);
+ document.head.appendChild(element);
+ }
+ element.setAttribute("content", content);
+ return element;
+ }
+ function findClosestRecursively(element, selector) {
+ if (element instanceof Element) {
+ return element.closest(selector) || findClosestRecursively(element.assignedSlot || element.getRootNode()?.host, selector);
+ }
+ }
+ function elementIsFocusable(element) {
+ const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
+ return !!element && element.closest(inertDisabledOrHidden) == null && typeof element.focus == "function";
+ }
+ function queryAutofocusableElement(elementOrDocumentFragment) {
+ return Array.from(elementOrDocumentFragment.querySelectorAll("[autofocus]")).find(elementIsFocusable);
+ }
+ async function around(callback, reader) {
+ const before = reader();
+ callback();
+ await nextAnimationFrame();
+ const after = reader();
+ return [before, after];
+ }
+ function doesNotTargetIFrame(name) {
+ if (name === "_blank") {
+ return false;
+ } else if (name) {
+ for (const element of document.getElementsByName(name)) {
+ if (element instanceof HTMLIFrameElement) return false;
+ }
+ return true;
+ } else {
+ return true;
+ }
+ }
+ function findLinkFromClickTarget(target) {
+ return findClosestRecursively(target, "a[href]:not([target^=_]):not([download])");
+ }
+ function getLocationForLink(link) {
+ return expandURL(link.getAttribute("href") || "");
+ }
+ function debounce(fn, delay) {
+ let timeoutId = null;
+ return (...args) => {
+ const callback = () => fn.apply(this, args);
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(callback, delay);
+ };
+ }
+ var LimitedSet = class extends Set {
+ constructor(maxSize) {
+ super();
+ this.maxSize = maxSize;
+ }
+ add(value) {
+ if (this.size >= this.maxSize) {
+ const iterator = this.values();
+ const oldestValue = iterator.next().value;
+ this.delete(oldestValue);
+ }
+ super.add(value);
+ }
+ };
+ var recentRequests = new LimitedSet(20);
+ var nativeFetch = window.fetch;
+ function fetchWithTurboHeaders(url, options = {}) {
+ const modifiedHeaders = new Headers(options.headers || {});
+ const requestUID = uuid();
+ recentRequests.add(requestUID);
+ modifiedHeaders.append("X-Turbo-Request-Id", requestUID);
+ return nativeFetch(url, {
+ ...options,
+ headers: modifiedHeaders
+ });
+ }
+ function fetchMethodFromString(method) {
+ switch (method.toLowerCase()) {
+ case "get":
+ return FetchMethod.get;
+ case "post":
+ return FetchMethod.post;
+ case "put":
+ return FetchMethod.put;
+ case "patch":
+ return FetchMethod.patch;
+ case "delete":
+ return FetchMethod.delete;
+ }
+ }
+ var FetchMethod = {
+ get: "get",
+ post: "post",
+ put: "put",
+ patch: "patch",
+ delete: "delete"
+ };
+ function fetchEnctypeFromString(encoding) {
+ switch (encoding.toLowerCase()) {
+ case FetchEnctype.multipart:
+ return FetchEnctype.multipart;
+ case FetchEnctype.plain:
+ return FetchEnctype.plain;
+ default:
+ return FetchEnctype.urlEncoded;
+ }
+ }
+ var FetchEnctype = {
+ urlEncoded: "application/x-www-form-urlencoded",
+ multipart: "multipart/form-data",
+ plain: "text/plain"
+ };
+ var FetchRequest = class {
+ abortController = new AbortController();
+ #resolveRequestPromise = (_value) => {
+ };
+ constructor(delegate, method, location2, requestBody = new URLSearchParams(), target = null, enctype = FetchEnctype.urlEncoded) {
+ const [url, body] = buildResourceAndBody(expandURL(location2), method, requestBody, enctype);
+ this.delegate = delegate;
+ this.url = url;
+ this.target = target;
+ this.fetchOptions = {
+ credentials: "same-origin",
+ redirect: "follow",
+ method: method.toUpperCase(),
+ headers: { ...this.defaultHeaders },
+ body,
+ signal: this.abortSignal,
+ referrer: this.delegate.referrer?.href
+ };
+ this.enctype = enctype;
+ }
+ get method() {
+ return this.fetchOptions.method;
+ }
+ set method(value) {
+ const fetchBody = this.isSafe ? this.url.searchParams : this.fetchOptions.body || new FormData();
+ const fetchMethod = fetchMethodFromString(value) || FetchMethod.get;
+ this.url.search = "";
+ const [url, body] = buildResourceAndBody(this.url, fetchMethod, fetchBody, this.enctype);
+ this.url = url;
+ this.fetchOptions.body = body;
+ this.fetchOptions.method = fetchMethod.toUpperCase();
+ }
+ get headers() {
+ return this.fetchOptions.headers;
+ }
+ set headers(value) {
+ this.fetchOptions.headers = value;
+ }
+ get body() {
+ if (this.isSafe) {
+ return this.url.searchParams;
+ } else {
+ return this.fetchOptions.body;
+ }
+ }
+ set body(value) {
+ this.fetchOptions.body = value;
+ }
+ get location() {
+ return this.url;
+ }
+ get params() {
+ return this.url.searchParams;
+ }
+ get entries() {
+ return this.body ? Array.from(this.body.entries()) : [];
+ }
+ cancel() {
+ this.abortController.abort();
+ }
+ async perform() {
+ const { fetchOptions } = this;
+ this.delegate.prepareRequest(this);
+ const event = await this.#allowRequestToBeIntercepted(fetchOptions);
+ try {
+ this.delegate.requestStarted(this);
+ if (event.detail.fetchRequest) {
+ this.response = event.detail.fetchRequest.response;
+ } else {
+ this.response = fetchWithTurboHeaders(this.url.href, fetchOptions);
+ }
+ const response = await this.response;
+ return await this.receive(response);
+ } catch (error2) {
+ if (error2.name !== "AbortError") {
+ if (this.#willDelegateErrorHandling(error2)) {
+ this.delegate.requestErrored(this, error2);
+ }
+ throw error2;
+ }
+ } finally {
+ this.delegate.requestFinished(this);
+ }
+ }
+ async receive(response) {
+ const fetchResponse = new FetchResponse(response);
+ const event = dispatch("turbo:before-fetch-response", {
+ cancelable: true,
+ detail: { fetchResponse },
+ target: this.target
+ });
+ if (event.defaultPrevented) {
+ this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
+ } else if (fetchResponse.succeeded) {
+ this.delegate.requestSucceededWithResponse(this, fetchResponse);
+ } else {
+ this.delegate.requestFailedWithResponse(this, fetchResponse);
+ }
+ return fetchResponse;
+ }
+ get defaultHeaders() {
+ return {
+ Accept: "text/html, application/xhtml+xml"
+ };
+ }
+ get isSafe() {
+ return isSafe(this.method);
+ }
+ get abortSignal() {
+ return this.abortController.signal;
+ }
+ acceptResponseType(mimeType) {
+ this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
+ }
+ async #allowRequestToBeIntercepted(fetchOptions) {
+ const requestInterception = new Promise((resolve) => this.#resolveRequestPromise = resolve);
+ const event = dispatch("turbo:before-fetch-request", {
+ cancelable: true,
+ detail: {
+ fetchOptions,
+ url: this.url,
+ resume: this.#resolveRequestPromise
+ },
+ target: this.target
+ });
+ this.url = event.detail.url;
+ if (event.defaultPrevented) await requestInterception;
+ return event;
+ }
+ #willDelegateErrorHandling(error2) {
+ const event = dispatch("turbo:fetch-request-error", {
+ target: this.target,
+ cancelable: true,
+ detail: { request: this, error: error2 }
+ });
+ return !event.defaultPrevented;
+ }
+ };
+ function isSafe(fetchMethod) {
+ return fetchMethodFromString(fetchMethod) == FetchMethod.get;
+ }
+ function buildResourceAndBody(resource, method, requestBody, enctype) {
+ const searchParams = Array.from(requestBody).length > 0 ? new URLSearchParams(entriesExcludingFiles(requestBody)) : resource.searchParams;
+ if (isSafe(method)) {
+ return [mergeIntoURLSearchParams(resource, searchParams), null];
+ } else if (enctype == FetchEnctype.urlEncoded) {
+ return [resource, searchParams];
+ } else {
+ return [resource, requestBody];
+ }
+ }
+ function entriesExcludingFiles(requestBody) {
+ const entries = [];
+ for (const [name, value] of requestBody) {
+ if (value instanceof File) continue;
+ else entries.push([name, value]);
+ }
+ return entries;
+ }
+ function mergeIntoURLSearchParams(url, requestBody) {
+ const searchParams = new URLSearchParams(entriesExcludingFiles(requestBody));
+ url.search = searchParams.toString();
+ return url;
+ }
+ var AppearanceObserver = class {
+ started = false;
+ constructor(delegate, element) {
+ this.delegate = delegate;
+ this.element = element;
+ this.intersectionObserver = new IntersectionObserver(this.intersect);
+ }
+ start() {
+ if (!this.started) {
+ this.started = true;
+ this.intersectionObserver.observe(this.element);
+ }
+ }
+ stop() {
+ if (this.started) {
+ this.started = false;
+ this.intersectionObserver.unobserve(this.element);
+ }
+ }
+ intersect = (entries) => {
+ const lastEntry = entries.slice(-1)[0];
+ if (lastEntry?.isIntersecting) {
+ this.delegate.elementAppearedInViewport(this.element);
+ }
+ };
+ };
+ var StreamMessage = class {
+ static contentType = "text/vnd.turbo-stream.html";
+ static wrap(message) {
+ if (typeof message == "string") {
+ return new this(createDocumentFragment(message));
+ } else {
+ return message;
+ }
+ }
+ constructor(fragment) {
+ this.fragment = importStreamElements(fragment);
+ }
+ };
+ function importStreamElements(fragment) {
+ for (const element of fragment.querySelectorAll("turbo-stream")) {
+ const streamElement = document.importNode(element, true);
+ for (const inertScriptElement of streamElement.templateElement.content.querySelectorAll("script")) {
+ inertScriptElement.replaceWith(activateScriptElement(inertScriptElement));
+ }
+ element.replaceWith(streamElement);
+ }
+ return fragment;
+ }
+ var PREFETCH_DELAY = 100;
+ var PrefetchCache = class {
+ #prefetchTimeout = null;
+ #prefetched = null;
+ get(url) {
+ if (this.#prefetched && this.#prefetched.url === url && this.#prefetched.expire > Date.now()) {
+ return this.#prefetched.request;
+ }
+ }
+ setLater(url, request, ttl) {
+ this.clear();
+ this.#prefetchTimeout = setTimeout(() => {
+ request.perform();
+ this.set(url, request, ttl);
+ this.#prefetchTimeout = null;
+ }, PREFETCH_DELAY);
+ }
+ set(url, request, ttl) {
+ this.#prefetched = { url, request, expire: new Date((/* @__PURE__ */ new Date()).getTime() + ttl) };
+ }
+ clear() {
+ if (this.#prefetchTimeout) clearTimeout(this.#prefetchTimeout);
+ this.#prefetched = null;
+ }
+ };
+ var cacheTtl = 10 * 1e3;
+ var prefetchCache = new PrefetchCache();
+ var FormSubmissionState = {
+ initialized: "initialized",
+ requesting: "requesting",
+ waiting: "waiting",
+ receiving: "receiving",
+ stopping: "stopping",
+ stopped: "stopped"
+ };
+ var FormSubmission = class _FormSubmission {
+ state = FormSubmissionState.initialized;
+ static confirmMethod(message, _element, _submitter) {
+ return Promise.resolve(confirm(message));
+ }
+ constructor(delegate, formElement, submitter, mustRedirect = false) {
+ const method = getMethod(formElement, submitter);
+ const action = getAction(getFormAction(formElement, submitter), method);
+ const body = buildFormData(formElement, submitter);
+ const enctype = getEnctype(formElement, submitter);
+ this.delegate = delegate;
+ this.formElement = formElement;
+ this.submitter = submitter;
+ this.fetchRequest = new FetchRequest(this, method, action, body, formElement, enctype);
+ this.mustRedirect = mustRedirect;
+ }
+ get method() {
+ return this.fetchRequest.method;
+ }
+ set method(value) {
+ this.fetchRequest.method = value;
+ }
+ get action() {
+ return this.fetchRequest.url.toString();
+ }
+ set action(value) {
+ this.fetchRequest.url = expandURL(value);
+ }
+ get body() {
+ return this.fetchRequest.body;
+ }
+ get enctype() {
+ return this.fetchRequest.enctype;
+ }
+ get isSafe() {
+ return this.fetchRequest.isSafe;
+ }
+ get location() {
+ return this.fetchRequest.url;
+ }
+ // The submission process
+ async start() {
+ const { initialized, requesting } = FormSubmissionState;
+ const confirmationMessage = getAttribute("data-turbo-confirm", this.submitter, this.formElement);
+ if (typeof confirmationMessage === "string") {
+ const answer = await _FormSubmission.confirmMethod(confirmationMessage, this.formElement, this.submitter);
+ if (!answer) {
+ return;
+ }
+ }
+ if (this.state == initialized) {
+ this.state = requesting;
+ return this.fetchRequest.perform();
+ }
+ }
+ stop() {
+ const { stopping, stopped } = FormSubmissionState;
+ if (this.state != stopping && this.state != stopped) {
+ this.state = stopping;
+ this.fetchRequest.cancel();
+ return true;
+ }
+ }
+ // Fetch request delegate
+ prepareRequest(request) {
+ if (!request.isSafe) {
+ const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
+ if (token) {
+ request.headers["X-CSRF-Token"] = token;
+ }
+ }
+ if (this.requestAcceptsTurboStreamResponse(request)) {
+ request.acceptResponseType(StreamMessage.contentType);
+ }
+ }
+ requestStarted(_request) {
+ this.state = FormSubmissionState.waiting;
+ this.submitter?.setAttribute("disabled", "");
+ this.setSubmitsWith();
+ markAsBusy(this.formElement);
+ dispatch("turbo:submit-start", {
+ target: this.formElement,
+ detail: { formSubmission: this }
+ });
+ this.delegate.formSubmissionStarted(this);
+ }
+ requestPreventedHandlingResponse(request, response) {
+ prefetchCache.clear();
+ this.result = { success: response.succeeded, fetchResponse: response };
+ }
+ requestSucceededWithResponse(request, response) {
+ if (response.clientError || response.serverError) {
+ this.delegate.formSubmissionFailedWithResponse(this, response);
+ return;
+ }
+ prefetchCache.clear();
+ if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {
+ const error2 = new Error("Form responses must redirect to another location");
+ this.delegate.formSubmissionErrored(this, error2);
+ } else {
+ this.state = FormSubmissionState.receiving;
+ this.result = { success: true, fetchResponse: response };
+ this.delegate.formSubmissionSucceededWithResponse(this, response);
+ }
+ }
+ requestFailedWithResponse(request, response) {
+ this.result = { success: false, fetchResponse: response };
+ this.delegate.formSubmissionFailedWithResponse(this, response);
+ }
+ requestErrored(request, error2) {
+ this.result = { success: false, error: error2 };
+ this.delegate.formSubmissionErrored(this, error2);
+ }
+ requestFinished(_request) {
+ this.state = FormSubmissionState.stopped;
+ this.submitter?.removeAttribute("disabled");
+ this.resetSubmitterText();
+ clearBusyState(this.formElement);
+ dispatch("turbo:submit-end", {
+ target: this.formElement,
+ detail: { formSubmission: this, ...this.result }
+ });
+ this.delegate.formSubmissionFinished(this);
+ }
+ // Private
+ setSubmitsWith() {
+ if (!this.submitter || !this.submitsWith) return;
+ if (this.submitter.matches("button")) {
+ this.originalSubmitText = this.submitter.innerHTML;
+ this.submitter.innerHTML = this.submitsWith;
+ } else if (this.submitter.matches("input")) {
+ const input = this.submitter;
+ this.originalSubmitText = input.value;
+ input.value = this.submitsWith;
+ }
+ }
+ resetSubmitterText() {
+ if (!this.submitter || !this.originalSubmitText) return;
+ if (this.submitter.matches("button")) {
+ this.submitter.innerHTML = this.originalSubmitText;
+ } else if (this.submitter.matches("input")) {
+ const input = this.submitter;
+ input.value = this.originalSubmitText;
+ }
+ }
+ requestMustRedirect(request) {
+ return !request.isSafe && this.mustRedirect;
+ }
+ requestAcceptsTurboStreamResponse(request) {
+ return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
+ }
+ get submitsWith() {
+ return this.submitter?.getAttribute("data-turbo-submits-with");
+ }
+ };
+ function buildFormData(formElement, submitter) {
+ const formData = new FormData(formElement);
+ const name = submitter?.getAttribute("name");
+ const value = submitter?.getAttribute("value");
+ if (name) {
+ formData.append(name, value || "");
+ }
+ return formData;
+ }
+ function getCookieValue(cookieName) {
+ if (cookieName != null) {
+ const cookies = document.cookie ? document.cookie.split("; ") : [];
+ const cookie = cookies.find((cookie2) => cookie2.startsWith(cookieName));
+ if (cookie) {
+ const value = cookie.split("=").slice(1).join("=");
+ return value ? decodeURIComponent(value) : void 0;
+ }
+ }
+ }
+ function responseSucceededWithoutRedirect(response) {
+ return response.statusCode == 200 && !response.redirected;
+ }
+ function getFormAction(formElement, submitter) {
+ const formElementAction = typeof formElement.action === "string" ? formElement.action : null;
+ if (submitter?.hasAttribute("formaction")) {
+ return submitter.getAttribute("formaction") || "";
+ } else {
+ return formElement.getAttribute("action") || formElementAction || "";
+ }
+ }
+ function getAction(formAction, fetchMethod) {
+ const action = expandURL(formAction);
+ if (isSafe(fetchMethod)) {
+ action.search = "";
+ }
+ return action;
+ }
+ function getMethod(formElement, submitter) {
+ const method = submitter?.getAttribute("formmethod") || formElement.getAttribute("method") || "";
+ return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
+ }
+ function getEnctype(formElement, submitter) {
+ return fetchEnctypeFromString(submitter?.getAttribute("formenctype") || formElement.enctype);
+ }
+ var Snapshot = class {
+ constructor(element) {
+ this.element = element;
+ }
+ get activeElement() {
+ return this.element.ownerDocument.activeElement;
+ }
+ get children() {
+ return [...this.element.children];
+ }
+ hasAnchor(anchor) {
+ return this.getElementForAnchor(anchor) != null;
+ }
+ getElementForAnchor(anchor) {
+ return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;
+ }
+ get isConnected() {
+ return this.element.isConnected;
+ }
+ get firstAutofocusableElement() {
+ return queryAutofocusableElement(this.element);
+ }
+ get permanentElements() {
+ return queryPermanentElementsAll(this.element);
+ }
+ getPermanentElementById(id) {
+ return getPermanentElementById(this.element, id);
+ }
+ getPermanentElementMapForSnapshot(snapshot) {
+ const permanentElementMap = {};
+ for (const currentPermanentElement of this.permanentElements) {
+ const { id } = currentPermanentElement;
+ const newPermanentElement = snapshot.getPermanentElementById(id);
+ if (newPermanentElement) {
+ permanentElementMap[id] = [currentPermanentElement, newPermanentElement];
+ }
+ }
+ return permanentElementMap;
+ }
+ };
+ function getPermanentElementById(node, id) {
+ return node.querySelector(`#${id}[data-turbo-permanent]`);
+ }
+ function queryPermanentElementsAll(node) {
+ return node.querySelectorAll("[id][data-turbo-permanent]");
+ }
+ var FormSubmitObserver = class {
+ started = false;
+ constructor(delegate, eventTarget) {
+ this.delegate = delegate;
+ this.eventTarget = eventTarget;
+ }
+ start() {
+ if (!this.started) {
+ this.eventTarget.addEventListener("submit", this.submitCaptured, true);
+ this.started = true;
+ }
+ }
+ stop() {
+ if (this.started) {
+ this.eventTarget.removeEventListener("submit", this.submitCaptured, true);
+ this.started = false;
+ }
+ }
+ submitCaptured = () => {
+ this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
+ this.eventTarget.addEventListener("submit", this.submitBubbled, false);
+ };
+ submitBubbled = (event) => {
+ if (!event.defaultPrevented) {
+ const form = event.target instanceof HTMLFormElement ? event.target : void 0;
+ const submitter = event.submitter || void 0;
+ if (form && submissionDoesNotDismissDialog(form, submitter) && submissionDoesNotTargetIFrame(form, submitter) && this.delegate.willSubmitForm(form, submitter)) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ this.delegate.formSubmitted(form, submitter);
+ }
+ }
+ };
+ };
+ function submissionDoesNotDismissDialog(form, submitter) {
+ const method = submitter?.getAttribute("formmethod") || form.getAttribute("method");
+ return method != "dialog";
+ }
+ function submissionDoesNotTargetIFrame(form, submitter) {
+ const target = submitter?.getAttribute("formtarget") || form.getAttribute("target");
+ return doesNotTargetIFrame(target);
+ }
+ var View = class {
+ #resolveRenderPromise = (_value) => {
+ };
+ #resolveInterceptionPromise = (_value) => {
+ };
+ constructor(delegate, element) {
+ this.delegate = delegate;
+ this.element = element;
+ }
+ // Scrolling
+ scrollToAnchor(anchor) {
+ const element = this.snapshot.getElementForAnchor(anchor);
+ if (element) {
+ this.scrollToElement(element);
+ this.focusElement(element);
+ } else {
+ this.scrollToPosition({ x: 0, y: 0 });
+ }
+ }
+ scrollToAnchorFromLocation(location2) {
+ this.scrollToAnchor(getAnchor(location2));
+ }
+ scrollToElement(element) {
+ element.scrollIntoView();
+ }
+ focusElement(element) {
+ if (element instanceof HTMLElement) {
+ if (element.hasAttribute("tabindex")) {
+ element.focus();
+ } else {
+ element.setAttribute("tabindex", "-1");
+ element.focus();
+ element.removeAttribute("tabindex");
+ }
+ }
+ }
+ scrollToPosition({ x, y }) {
+ this.scrollRoot.scrollTo(x, y);
+ }
+ scrollToTop() {
+ this.scrollToPosition({ x: 0, y: 0 });
+ }
+ get scrollRoot() {
+ return window;
+ }
+ // Rendering
+ async render(renderer) {
+ const { isPreview, shouldRender, willRender, newSnapshot: snapshot } = renderer;
+ const shouldInvalidate = willRender;
+ if (shouldRender) {
+ try {
+ this.renderPromise = new Promise((resolve) => this.#resolveRenderPromise = resolve);
+ this.renderer = renderer;
+ await this.prepareToRenderSnapshot(renderer);
+ const renderInterception = new Promise((resolve) => this.#resolveInterceptionPromise = resolve);
+ const options = { resume: this.#resolveInterceptionPromise, render: this.renderer.renderElement, renderMethod: this.renderer.renderMethod };
+ const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
+ if (!immediateRender) await renderInterception;
+ await this.renderSnapshot(renderer);
+ this.delegate.viewRenderedSnapshot(snapshot, isPreview, this.renderer.renderMethod);
+ this.delegate.preloadOnLoadLinksForView(this.element);
+ this.finishRenderingSnapshot(renderer);
+ } finally {
+ delete this.renderer;
+ this.#resolveRenderPromise(void 0);
+ delete this.renderPromise;
+ }
+ } else if (shouldInvalidate) {
+ this.invalidate(renderer.reloadReason);
+ }
+ }
+ invalidate(reason) {
+ this.delegate.viewInvalidated(reason);
+ }
+ async prepareToRenderSnapshot(renderer) {
+ this.markAsPreview(renderer.isPreview);
+ await renderer.prepareToRender();
+ }
+ markAsPreview(isPreview) {
+ if (isPreview) {
+ this.element.setAttribute("data-turbo-preview", "");
+ } else {
+ this.element.removeAttribute("data-turbo-preview");
+ }
+ }
+ markVisitDirection(direction) {
+ this.element.setAttribute("data-turbo-visit-direction", direction);
+ }
+ unmarkVisitDirection() {
+ this.element.removeAttribute("data-turbo-visit-direction");
+ }
+ async renderSnapshot(renderer) {
+ await renderer.render();
+ }
+ finishRenderingSnapshot(renderer) {
+ renderer.finishRendering();
+ }
+ };
+ var FrameView = class extends View {
+ missing() {
+ this.element.innerHTML = `Content missing`;
+ }
+ get snapshot() {
+ return new Snapshot(this.element);
+ }
+ };
+ var LinkInterceptor = class {
+ constructor(delegate, element) {
+ this.delegate = delegate;
+ this.element = element;
+ }
+ start() {
+ this.element.addEventListener("click", this.clickBubbled);
+ document.addEventListener("turbo:click", this.linkClicked);
+ document.addEventListener("turbo:before-visit", this.willVisit);
+ }
+ stop() {
+ this.element.removeEventListener("click", this.clickBubbled);
+ document.removeEventListener("turbo:click", this.linkClicked);
+ document.removeEventListener("turbo:before-visit", this.willVisit);
+ }
+ clickBubbled = (event) => {
+ if (this.clickEventIsSignificant(event)) {
+ this.clickEvent = event;
+ } else {
+ delete this.clickEvent;
+ }
+ };
+ linkClicked = (event) => {
+ if (this.clickEvent && this.clickEventIsSignificant(event)) {
+ if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
+ this.clickEvent.preventDefault();
+ event.preventDefault();
+ this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
+ }
+ }
+ delete this.clickEvent;
+ };
+ willVisit = (_event) => {
+ delete this.clickEvent;
+ };
+ clickEventIsSignificant(event) {
+ const target = event.composed ? event.target?.parentElement : event.target;
+ const element = findLinkFromClickTarget(target) || target;
+ return element instanceof Element && element.closest("turbo-frame, html") == this.element;
+ }
+ };
+ var LinkClickObserver = class {
+ started = false;
+ constructor(delegate, eventTarget) {
+ this.delegate = delegate;
+ this.eventTarget = eventTarget;
+ }
+ start() {
+ if (!this.started) {
+ this.eventTarget.addEventListener("click", this.clickCaptured, true);
+ this.started = true;
+ }
+ }
+ stop() {
+ if (this.started) {
+ this.eventTarget.removeEventListener("click", this.clickCaptured, true);
+ this.started = false;
+ }
+ }
+ clickCaptured = () => {
+ this.eventTarget.removeEventListener("click", this.clickBubbled, false);
+ this.eventTarget.addEventListener("click", this.clickBubbled, false);
+ };
+ clickBubbled = (event) => {
+ if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
+ const target = event.composedPath && event.composedPath()[0] || event.target;
+ const link = findLinkFromClickTarget(target);
+ if (link && doesNotTargetIFrame(link.target)) {
+ const location2 = getLocationForLink(link);
+ if (this.delegate.willFollowLinkToLocation(link, location2, event)) {
+ event.preventDefault();
+ this.delegate.followedLinkToLocation(link, location2);
+ }
+ }
+ }
+ };
+ clickEventIsSignificant(event) {
+ return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
+ }
+ };
+ var FormLinkClickObserver = class {
+ constructor(delegate, element) {
+ this.delegate = delegate;
+ this.linkInterceptor = new LinkClickObserver(this, element);
+ }
+ start() {
+ this.linkInterceptor.start();
+ }
+ stop() {
+ this.linkInterceptor.stop();
+ }
+ // Link hover observer delegate
+ canPrefetchRequestToLocation(link, location2) {
+ return false;
+ }
+ prefetchAndCacheRequestToLocation(link, location2) {
+ return;
+ }
+ // Link click observer delegate
+ willFollowLinkToLocation(link, location2, originalEvent) {
+ return this.delegate.willSubmitFormLinkToLocation(link, location2, originalEvent) && (link.hasAttribute("data-turbo-method") || link.hasAttribute("data-turbo-stream"));
+ }
+ followedLinkToLocation(link, location2) {
+ const form = document.createElement("form");
+ const type = "hidden";
+ for (const [name, value] of location2.searchParams) {
+ form.append(Object.assign(document.createElement("input"), { type, name, value }));
+ }
+ const action = Object.assign(location2, { search: "" });
+ form.setAttribute("data-turbo", "true");
+ form.setAttribute("action", action.href);
+ form.setAttribute("hidden", "");
+ const method = link.getAttribute("data-turbo-method");
+ if (method) form.setAttribute("method", method);
+ const turboFrame = link.getAttribute("data-turbo-frame");
+ if (turboFrame) form.setAttribute("data-turbo-frame", turboFrame);
+ const turboAction = getVisitAction(link);
+ if (turboAction) form.setAttribute("data-turbo-action", turboAction);
+ const turboConfirm = link.getAttribute("data-turbo-confirm");
+ if (turboConfirm) form.setAttribute("data-turbo-confirm", turboConfirm);
+ const turboStream = link.hasAttribute("data-turbo-stream");
+ if (turboStream) form.setAttribute("data-turbo-stream", "");
+ this.delegate.submittedFormLinkToLocation(link, location2, form);
+ document.body.appendChild(form);
+ form.addEventListener("turbo:submit-end", () => form.remove(), { once: true });
+ requestAnimationFrame(() => form.requestSubmit());
+ }
+ };
+ var Bardo = class {
+ static async preservingPermanentElements(delegate, permanentElementMap, callback) {
+ const bardo = new this(delegate, permanentElementMap);
+ bardo.enter();
+ await callback();
+ bardo.leave();
+ }
+ constructor(delegate, permanentElementMap) {
+ this.delegate = delegate;
+ this.permanentElementMap = permanentElementMap;
+ }
+ enter() {
+ for (const id in this.permanentElementMap) {
+ const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
+ this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);
+ this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);
+ }
+ }
+ leave() {
+ for (const id in this.permanentElementMap) {
+ const [currentPermanentElement] = this.permanentElementMap[id];
+ this.replaceCurrentPermanentElementWithClone(currentPermanentElement);
+ this.replacePlaceholderWithPermanentElement(currentPermanentElement);
+ this.delegate.leavingBardo(currentPermanentElement);
+ }
+ }
+ replaceNewPermanentElementWithPlaceholder(permanentElement) {
+ const placeholder = createPlaceholderForPermanentElement(permanentElement);
+ permanentElement.replaceWith(placeholder);
+ }
+ replaceCurrentPermanentElementWithClone(permanentElement) {
+ const clone = permanentElement.cloneNode(true);
+ permanentElement.replaceWith(clone);
+ }
+ replacePlaceholderWithPermanentElement(permanentElement) {
+ const placeholder = this.getPlaceholderById(permanentElement.id);
+ placeholder?.replaceWith(permanentElement);
+ }
+ getPlaceholderById(id) {
+ return this.placeholders.find((element) => element.content == id);
+ }
+ get placeholders() {
+ return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")];
+ }
+ };
+ function createPlaceholderForPermanentElement(permanentElement) {
+ const element = document.createElement("meta");
+ element.setAttribute("name", "turbo-permanent-placeholder");
+ element.setAttribute("content", permanentElement.id);
+ return element;
+ }
+ var Renderer = class {
+ #activeElement = null;
+ constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
+ this.currentSnapshot = currentSnapshot;
+ this.newSnapshot = newSnapshot;
+ this.isPreview = isPreview;
+ this.willRender = willRender;
+ this.renderElement = renderElement;
+ this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject });
+ }
+ get shouldRender() {
+ return true;
+ }
+ get shouldAutofocus() {
+ return true;
+ }
+ get reloadReason() {
+ return;
+ }
+ prepareToRender() {
+ return;
+ }
+ render() {
+ }
+ finishRendering() {
+ if (this.resolvingFunctions) {
+ this.resolvingFunctions.resolve();
+ delete this.resolvingFunctions;
+ }
+ }
+ async preservingPermanentElements(callback) {
+ await Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
+ }
+ focusFirstAutofocusableElement() {
+ if (this.shouldAutofocus) {
+ const element = this.connectedSnapshot.firstAutofocusableElement;
+ if (element) {
+ element.focus();
+ }
+ }
+ }
+ // Bardo delegate
+ enteringBardo(currentPermanentElement) {
+ if (this.#activeElement) return;
+ if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
+ this.#activeElement = this.currentSnapshot.activeElement;
+ }
+ }
+ leavingBardo(currentPermanentElement) {
+ if (currentPermanentElement.contains(this.#activeElement) && this.#activeElement instanceof HTMLElement) {
+ this.#activeElement.focus();
+ this.#activeElement = null;
+ }
+ }
+ get connectedSnapshot() {
+ return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;
+ }
+ get currentElement() {
+ return this.currentSnapshot.element;
+ }
+ get newElement() {
+ return this.newSnapshot.element;
+ }
+ get permanentElementMap() {
+ return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
+ }
+ get renderMethod() {
+ return "replace";
+ }
+ };
+ var FrameRenderer = class extends Renderer {
+ static renderElement(currentElement, newElement) {
+ const destinationRange = document.createRange();
+ destinationRange.selectNodeContents(currentElement);
+ destinationRange.deleteContents();
+ const frameElement = newElement;
+ const sourceRange = frameElement.ownerDocument?.createRange();
+ if (sourceRange) {
+ sourceRange.selectNodeContents(frameElement);
+ currentElement.appendChild(sourceRange.extractContents());
+ }
+ }
+ constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
+ super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
+ this.delegate = delegate;
+ }
+ get shouldRender() {
+ return true;
+ }
+ async render() {
+ await nextRepaint();
+ this.preservingPermanentElements(() => {
+ this.loadFrameElement();
+ });
+ this.scrollFrameIntoView();
+ await nextRepaint();
+ this.focusFirstAutofocusableElement();
+ await nextRepaint();
+ this.activateScriptElements();
+ }
+ loadFrameElement() {
+ this.delegate.willRenderFrame(this.currentElement, this.newElement);
+ this.renderElement(this.currentElement, this.newElement);
+ }
+ scrollFrameIntoView() {
+ if (this.currentElement.autoscroll || this.newElement.autoscroll) {
+ const element = this.currentElement.firstElementChild;
+ const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
+ const behavior = readScrollBehavior(this.currentElement.getAttribute("data-autoscroll-behavior"), "auto");
+ if (element) {
+ element.scrollIntoView({ block, behavior });
+ return true;
+ }
+ }
+ return false;
+ }
+ activateScriptElements() {
+ for (const inertScriptElement of this.newScriptElements) {
+ const activatedScriptElement = activateScriptElement(inertScriptElement);
+ inertScriptElement.replaceWith(activatedScriptElement);
+ }
+ }
+ get newScriptElements() {
+ return this.currentElement.querySelectorAll("script");
+ }
+ };
+ function readScrollLogicalPosition(value, defaultValue) {
+ if (value == "end" || value == "start" || value == "center" || value == "nearest") {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+ function readScrollBehavior(value, defaultValue) {
+ if (value == "auto" || value == "smooth") {
+ return value;
+ } else {
+ return defaultValue;
+ }
+ }
+ var ProgressBar = class _ProgressBar {
+ static animationDuration = 300;
+ /*ms*/
+ static get defaultCSS() {
+ return unindent`
+ .turbo-progress-bar {
+ position: fixed;
+ display: block;
+ top: 0;
+ left: 0;
+ height: 3px;
+ background: #0076ff;
+ z-index: 2147483647;
+ transition:
+ width ${_ProgressBar.animationDuration}ms ease-out,
+ opacity ${_ProgressBar.animationDuration / 2}ms ${_ProgressBar.animationDuration / 2}ms ease-in;
+ transform: translate3d(0, 0, 0);
+ }
+ `;
+ }
+ hiding = false;
+ value = 0;
+ visible = false;
+ constructor() {
+ this.stylesheetElement = this.createStylesheetElement();
+ this.progressElement = this.createProgressElement();
+ this.installStylesheetElement();
+ this.setValue(0);
+ }
+ show() {
+ if (!this.visible) {
+ this.visible = true;
+ this.installProgressElement();
+ this.startTrickling();
+ }
+ }
+ hide() {
+ if (this.visible && !this.hiding) {
+ this.hiding = true;
+ this.fadeProgressElement(() => {
+ this.uninstallProgressElement();
+ this.stopTrickling();
+ this.visible = false;
+ this.hiding = false;
+ });
+ }
+ }
+ setValue(value) {
+ this.value = value;
+ this.refresh();
+ }
+ // Private
+ installStylesheetElement() {
+ document.head.insertBefore(this.stylesheetElement, document.head.firstChild);
+ }
+ installProgressElement() {
+ this.progressElement.style.width = "0";
+ this.progressElement.style.opacity = "1";
+ document.documentElement.insertBefore(this.progressElement, document.body);
+ this.refresh();
+ }
+ fadeProgressElement(callback) {
+ this.progressElement.style.opacity = "0";
+ setTimeout(callback, _ProgressBar.animationDuration * 1.5);
+ }
+ uninstallProgressElement() {
+ if (this.progressElement.parentNode) {
+ document.documentElement.removeChild(this.progressElement);
+ }
+ }
+ startTrickling() {
+ if (!this.trickleInterval) {
+ this.trickleInterval = window.setInterval(this.trickle, _ProgressBar.animationDuration);
+ }
+ }
+ stopTrickling() {
+ window.clearInterval(this.trickleInterval);
+ delete this.trickleInterval;
+ }
+ trickle = () => {
+ this.setValue(this.value + Math.random() / 100);
+ };
+ refresh() {
+ requestAnimationFrame(() => {
+ this.progressElement.style.width = `${10 + this.value * 90}%`;
+ });
+ }
+ createStylesheetElement() {
+ const element = document.createElement("style");
+ element.type = "text/css";
+ element.textContent = _ProgressBar.defaultCSS;
+ if (this.cspNonce) {
+ element.nonce = this.cspNonce;
+ }
+ return element;
+ }
+ createProgressElement() {
+ const element = document.createElement("div");
+ element.className = "turbo-progress-bar";
+ return element;
+ }
+ get cspNonce() {
+ return getMetaContent("csp-nonce");
+ }
+ };
+ var HeadSnapshot = class extends Snapshot {
+ detailsByOuterHTML = this.children.filter((element) => !elementIsNoscript(element)).map((element) => elementWithoutNonce(element)).reduce((result, element) => {
+ const { outerHTML } = element;
+ const details = outerHTML in result ? result[outerHTML] : {
+ type: elementType(element),
+ tracked: elementIsTracked(element),
+ elements: []
+ };
+ return {
+ ...result,
+ [outerHTML]: {
+ ...details,
+ elements: [...details.elements, element]
+ }
+ };
+ }, {});
+ get trackedElementSignature() {
+ return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked).join("");
+ }
+ getScriptElementsNotInSnapshot(snapshot) {
+ return this.getElementsMatchingTypeNotInSnapshot("script", snapshot);
+ }
+ getStylesheetElementsNotInSnapshot(snapshot) {
+ return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot);
+ }
+ getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
+ return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML)).map((outerHTML) => this.detailsByOuterHTML[outerHTML]).filter(({ type }) => type == matchedType).map(({ elements: [element] }) => element);
+ }
+ get provisionalElements() {
+ return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
+ const { type, tracked, elements } = this.detailsByOuterHTML[outerHTML];
+ if (type == null && !tracked) {
+ return [...result, ...elements];
+ } else if (elements.length > 1) {
+ return [...result, ...elements.slice(1)];
+ } else {
+ return result;
+ }
+ }, []);
+ }
+ getMetaValue(name) {
+ const element = this.findMetaElementByName(name);
+ return element ? element.getAttribute("content") : null;
+ }
+ findMetaElementByName(name) {
+ return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
+ const {
+ elements: [element]
+ } = this.detailsByOuterHTML[outerHTML];
+ return elementIsMetaElementWithName(element, name) ? element : result;
+ }, void 0 | void 0);
+ }
+ };
+ function elementType(element) {
+ if (elementIsScript(element)) {
+ return "script";
+ } else if (elementIsStylesheet(element)) {
+ return "stylesheet";
+ }
+ }
+ function elementIsTracked(element) {
+ return element.getAttribute("data-turbo-track") == "reload";
+ }
+ function elementIsScript(element) {
+ const tagName = element.localName;
+ return tagName == "script";
+ }
+ function elementIsNoscript(element) {
+ const tagName = element.localName;
+ return tagName == "noscript";
+ }
+ function elementIsStylesheet(element) {
+ const tagName = element.localName;
+ return tagName == "style" || tagName == "link" && element.getAttribute("rel") == "stylesheet";
+ }
+ function elementIsMetaElementWithName(element, name) {
+ const tagName = element.localName;
+ return tagName == "meta" && element.getAttribute("name") == name;
+ }
+ function elementWithoutNonce(element) {
+ if (element.hasAttribute("nonce")) {
+ element.setAttribute("nonce", "");
+ }
+ return element;
+ }
+ var PageSnapshot = class _PageSnapshot extends Snapshot {
+ static fromHTMLString(html = "") {
+ return this.fromDocument(parseHTMLDocument(html));
+ }
+ static fromElement(element) {
+ return this.fromDocument(element.ownerDocument);
+ }
+ static fromDocument({ documentElement, body, head }) {
+ return new this(documentElement, body, new HeadSnapshot(head));
+ }
+ constructor(documentElement, body, headSnapshot) {
+ super(body);
+ this.documentElement = documentElement;
+ this.headSnapshot = headSnapshot;
+ }
+ clone() {
+ const clonedElement = this.element.cloneNode(true);
+ const selectElements = this.element.querySelectorAll("select");
+ const clonedSelectElements = clonedElement.querySelectorAll("select");
+ for (const [index, source] of selectElements.entries()) {
+ const clone = clonedSelectElements[index];
+ for (const option of clone.selectedOptions) option.selected = false;
+ for (const option of source.selectedOptions) clone.options[option.index].selected = true;
+ }
+ for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
+ clonedPasswordInput.value = "";
+ }
+ return new _PageSnapshot(this.documentElement, clonedElement, this.headSnapshot);
+ }
+ get lang() {
+ return this.documentElement.getAttribute("lang");
+ }
+ get headElement() {
+ return this.headSnapshot.element;
+ }
+ get rootLocation() {
+ const root = this.getSetting("root") ?? "/";
+ return expandURL(root);
+ }
+ get cacheControlValue() {
+ return this.getSetting("cache-control");
+ }
+ get isPreviewable() {
+ return this.cacheControlValue != "no-preview";
+ }
+ get isCacheable() {
+ return this.cacheControlValue != "no-cache";
+ }
+ get isVisitable() {
+ return this.getSetting("visit-control") != "reload";
+ }
+ get prefersViewTransitions() {
+ return this.headSnapshot.getMetaValue("view-transition") === "same-origin";
+ }
+ get shouldMorphPage() {
+ return this.getSetting("refresh-method") === "morph";
+ }
+ get shouldPreserveScrollPosition() {
+ return this.getSetting("refresh-scroll") === "preserve";
+ }
+ // Private
+ getSetting(name) {
+ return this.headSnapshot.getMetaValue(`turbo-${name}`);
+ }
+ };
+ var ViewTransitioner = class {
+ #viewTransitionStarted = false;
+ #lastOperation = Promise.resolve();
+ renderChange(useViewTransition, render) {
+ if (useViewTransition && this.viewTransitionsAvailable && !this.#viewTransitionStarted) {
+ this.#viewTransitionStarted = true;
+ this.#lastOperation = this.#lastOperation.then(async () => {
+ await document.startViewTransition(render).finished;
+ });
+ } else {
+ this.#lastOperation = this.#lastOperation.then(render);
+ }
+ return this.#lastOperation;
+ }
+ get viewTransitionsAvailable() {
+ return document.startViewTransition;
+ }
+ };
+ var defaultOptions = {
+ action: "advance",
+ historyChanged: false,
+ visitCachedSnapshot: () => {
+ },
+ willRender: true,
+ updateHistory: true,
+ shouldCacheSnapshot: true,
+ acceptsStreamResponse: false
+ };
+ var TimingMetric = {
+ visitStart: "visitStart",
+ requestStart: "requestStart",
+ requestEnd: "requestEnd",
+ visitEnd: "visitEnd"
+ };
+ var VisitState = {
+ initialized: "initialized",
+ started: "started",
+ canceled: "canceled",
+ failed: "failed",
+ completed: "completed"
+ };
+ var SystemStatusCode = {
+ networkFailure: 0,
+ timeoutFailure: -1,
+ contentTypeMismatch: -2
+ };
+ var Direction = {
+ advance: "forward",
+ restore: "back",
+ replace: "none"
+ };
+ var Visit = class {
+ identifier = uuid();
+ // Required by turbo-ios
+ timingMetrics = {};
+ followedRedirect = false;
+ historyChanged = false;
+ scrolled = false;
+ shouldCacheSnapshot = true;
+ acceptsStreamResponse = false;
+ snapshotCached = false;
+ state = VisitState.initialized;
+ viewTransitioner = new ViewTransitioner();
+ constructor(delegate, location2, restorationIdentifier, options = {}) {
+ this.delegate = delegate;
+ this.location = location2;
+ this.restorationIdentifier = restorationIdentifier || uuid();
+ const {
+ action,
+ historyChanged,
+ referrer,
+ snapshot,
+ snapshotHTML,
+ response,
+ visitCachedSnapshot,
+ willRender,
+ updateHistory,
+ shouldCacheSnapshot,
+ acceptsStreamResponse,
+ direction
+ } = {
+ ...defaultOptions,
+ ...options
+ };
+ this.action = action;
+ this.historyChanged = historyChanged;
+ this.referrer = referrer;
+ this.snapshot = snapshot;
+ this.snapshotHTML = snapshotHTML;
+ this.response = response;
+ this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
+ this.isPageRefresh = this.view.isPageRefresh(this);
+ this.visitCachedSnapshot = visitCachedSnapshot;
+ this.willRender = willRender;
+ this.updateHistory = updateHistory;
+ this.scrolled = !willRender;
+ this.shouldCacheSnapshot = shouldCacheSnapshot;
+ this.acceptsStreamResponse = acceptsStreamResponse;
+ this.direction = direction || Direction[action];
+ }
+ get adapter() {
+ return this.delegate.adapter;
+ }
+ get view() {
+ return this.delegate.view;
+ }
+ get history() {
+ return this.delegate.history;
+ }
+ get restorationData() {
+ return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
+ }
+ get silent() {
+ return this.isSamePage;
+ }
+ start() {
+ if (this.state == VisitState.initialized) {
+ this.recordTimingMetric(TimingMetric.visitStart);
+ this.state = VisitState.started;
+ this.adapter.visitStarted(this);
+ this.delegate.visitStarted(this);
+ }
+ }
+ cancel() {
+ if (this.state == VisitState.started) {
+ if (this.request) {
+ this.request.cancel();
+ }
+ this.cancelRender();
+ this.state = VisitState.canceled;
+ }
+ }
+ complete() {
+ if (this.state == VisitState.started) {
+ this.recordTimingMetric(TimingMetric.visitEnd);
+ this.adapter.visitCompleted(this);
+ this.state = VisitState.completed;
+ this.followRedirect();
+ if (!this.followedRedirect) {
+ this.delegate.visitCompleted(this);
+ }
+ }
+ }
+ fail() {
+ if (this.state == VisitState.started) {
+ this.state = VisitState.failed;
+ this.adapter.visitFailed(this);
+ this.delegate.visitCompleted(this);
+ }
+ }
+ changeHistory() {
+ if (!this.historyChanged && this.updateHistory) {
+ const actionForHistory = this.location.href === this.referrer?.href ? "replace" : this.action;
+ const method = getHistoryMethodForAction(actionForHistory);
+ this.history.update(method, this.location, this.restorationIdentifier);
+ this.historyChanged = true;
+ }
+ }
+ issueRequest() {
+ if (this.hasPreloadedResponse()) {
+ this.simulateRequest();
+ } else if (this.shouldIssueRequest() && !this.request) {
+ this.request = new FetchRequest(this, FetchMethod.get, this.location);
+ this.request.perform();
+ }
+ }
+ simulateRequest() {
+ if (this.response) {
+ this.startRequest();
+ this.recordResponse();
+ this.finishRequest();
+ }
+ }
+ startRequest() {
+ this.recordTimingMetric(TimingMetric.requestStart);
+ this.adapter.visitRequestStarted(this);
+ }
+ recordResponse(response = this.response) {
+ this.response = response;
+ if (response) {
+ const { statusCode } = response;
+ if (isSuccessful(statusCode)) {
+ this.adapter.visitRequestCompleted(this);
+ } else {
+ this.adapter.visitRequestFailedWithStatusCode(this, statusCode);
+ }
+ }
+ }
+ finishRequest() {
+ this.recordTimingMetric(TimingMetric.requestEnd);
+ this.adapter.visitRequestFinished(this);
+ }
+ loadResponse() {
+ if (this.response) {
+ const { statusCode, responseHTML } = this.response;
+ this.render(async () => {
+ if (this.shouldCacheSnapshot) this.cacheSnapshot();
+ if (this.view.renderPromise) await this.view.renderPromise;
+ if (isSuccessful(statusCode) && responseHTML != null) {
+ const snapshot = PageSnapshot.fromHTMLString(responseHTML);
+ await this.renderPageSnapshot(snapshot, false);
+ this.adapter.visitRendered(this);
+ this.complete();
+ } else {
+ await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);
+ this.adapter.visitRendered(this);
+ this.fail();
+ }
+ });
+ }
+ }
+ getCachedSnapshot() {
+ const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot();
+ if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) {
+ if (this.action == "restore" || snapshot.isPreviewable) {
+ return snapshot;
+ }
+ }
+ }
+ getPreloadedSnapshot() {
+ if (this.snapshotHTML) {
+ return PageSnapshot.fromHTMLString(this.snapshotHTML);
+ }
+ }
+ hasCachedSnapshot() {
+ return this.getCachedSnapshot() != null;
+ }
+ loadCachedSnapshot() {
+ const snapshot = this.getCachedSnapshot();
+ if (snapshot) {
+ const isPreview = this.shouldIssueRequest();
+ this.render(async () => {
+ this.cacheSnapshot();
+ if (this.isSamePage || this.isPageRefresh) {
+ this.adapter.visitRendered(this);
+ } else {
+ if (this.view.renderPromise) await this.view.renderPromise;
+ await this.renderPageSnapshot(snapshot, isPreview);
+ this.adapter.visitRendered(this);
+ if (!isPreview) {
+ this.complete();
+ }
+ }
+ });
+ }
+ }
+ followRedirect() {
+ if (this.redirectedToLocation && !this.followedRedirect && this.response?.redirected) {
+ this.adapter.visitProposedToLocation(this.redirectedToLocation, {
+ action: "replace",
+ response: this.response,
+ shouldCacheSnapshot: false,
+ willRender: false
+ });
+ this.followedRedirect = true;
+ }
+ }
+ goToSamePageAnchor() {
+ if (this.isSamePage) {
+ this.render(async () => {
+ this.cacheSnapshot();
+ this.performScroll();
+ this.changeHistory();
+ this.adapter.visitRendered(this);
+ });
+ }
+ }
+ // Fetch request delegate
+ prepareRequest(request) {
+ if (this.acceptsStreamResponse) {
+ request.acceptResponseType(StreamMessage.contentType);
+ }
+ }
+ requestStarted() {
+ this.startRequest();
+ }
+ requestPreventedHandlingResponse(_request, _response) {
+ }
+ async requestSucceededWithResponse(request, response) {
+ const responseHTML = await response.responseHTML;
+ const { redirected, statusCode } = response;
+ if (responseHTML == void 0) {
+ this.recordResponse({
+ statusCode: SystemStatusCode.contentTypeMismatch,
+ redirected
+ });
+ } else {
+ this.redirectedToLocation = response.redirected ? response.location : void 0;
+ this.recordResponse({ statusCode, responseHTML, redirected });
+ }
+ }
+ async requestFailedWithResponse(request, response) {
+ const responseHTML = await response.responseHTML;
+ const { redirected, statusCode } = response;
+ if (responseHTML == void 0) {
+ this.recordResponse({
+ statusCode: SystemStatusCode.contentTypeMismatch,
+ redirected
+ });
+ } else {
+ this.recordResponse({ statusCode, responseHTML, redirected });
+ }
+ }
+ requestErrored(_request, _error) {
+ this.recordResponse({
+ statusCode: SystemStatusCode.networkFailure,
+ redirected: false
+ });
+ }
+ requestFinished() {
+ this.finishRequest();
+ }
+ // Scrolling
+ performScroll() {
+ if (!this.scrolled && !this.view.forceReloaded && !this.view.shouldPreserveScrollPosition(this)) {
+ if (this.action == "restore") {
+ this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
+ } else {
+ this.scrollToAnchor() || this.view.scrollToTop();
+ }
+ if (this.isSamePage) {
+ this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);
+ }
+ this.scrolled = true;
+ }
+ }
+ scrollToRestoredPosition() {
+ const { scrollPosition } = this.restorationData;
+ if (scrollPosition) {
+ this.view.scrollToPosition(scrollPosition);
+ return true;
+ }
+ }
+ scrollToAnchor() {
+ const anchor = getAnchor(this.location);
+ if (anchor != null) {
+ this.view.scrollToAnchor(anchor);
+ return true;
+ }
+ }
+ // Instrumentation
+ recordTimingMetric(metric) {
+ this.timingMetrics[metric] = (/* @__PURE__ */ new Date()).getTime();
+ }
+ getTimingMetrics() {
+ return { ...this.timingMetrics };
+ }
+ // Private
+ getHistoryMethodForAction(action) {
+ switch (action) {
+ case "replace":
+ return history.replaceState;
+ case "advance":
+ case "restore":
+ return history.pushState;
+ }
+ }
+ hasPreloadedResponse() {
+ return typeof this.response == "object";
+ }
+ shouldIssueRequest() {
+ if (this.isSamePage) {
+ return false;
+ } else if (this.action == "restore") {
+ return !this.hasCachedSnapshot();
+ } else {
+ return this.willRender;
+ }
+ }
+ cacheSnapshot() {
+ if (!this.snapshotCached) {
+ this.view.cacheSnapshot(this.snapshot).then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));
+ this.snapshotCached = true;
+ }
+ }
+ async render(callback) {
+ this.cancelRender();
+ this.frame = await nextRepaint();
+ await callback();
+ delete this.frame;
+ }
+ async renderPageSnapshot(snapshot, isPreview) {
+ await this.viewTransitioner.renderChange(this.view.shouldTransitionTo(snapshot), async () => {
+ await this.view.renderPage(snapshot, isPreview, this.willRender, this);
+ this.performScroll();
+ });
+ }
+ cancelRender() {
+ if (this.frame) {
+ cancelAnimationFrame(this.frame);
+ delete this.frame;
+ }
+ }
+ };
+ function isSuccessful(statusCode) {
+ return statusCode >= 200 && statusCode < 300;
+ }
+ var BrowserAdapter = class {
+ progressBar = new ProgressBar();
+ constructor(session2) {
+ this.session = session2;
+ }
+ visitProposedToLocation(location2, options) {
+ if (locationIsVisitable(location2, this.navigator.rootLocation)) {
+ this.navigator.startVisit(location2, options?.restorationIdentifier || uuid(), options);
+ } else {
+ window.location.href = location2.toString();
+ }
+ }
+ visitStarted(visit2) {
+ this.location = visit2.location;
+ visit2.loadCachedSnapshot();
+ visit2.issueRequest();
+ visit2.goToSamePageAnchor();
+ }
+ visitRequestStarted(visit2) {
+ this.progressBar.setValue(0);
+ if (visit2.hasCachedSnapshot() || visit2.action != "restore") {
+ this.showVisitProgressBarAfterDelay();
+ } else {
+ this.showProgressBar();
+ }
+ }
+ visitRequestCompleted(visit2) {
+ visit2.loadResponse();
+ }
+ visitRequestFailedWithStatusCode(visit2, statusCode) {
+ switch (statusCode) {
+ case SystemStatusCode.networkFailure:
+ case SystemStatusCode.timeoutFailure:
+ case SystemStatusCode.contentTypeMismatch:
+ return this.reload({
+ reason: "request_failed",
+ context: {
+ statusCode
+ }
+ });
+ default:
+ return visit2.loadResponse();
+ }
+ }
+ visitRequestFinished(_visit) {
+ }
+ visitCompleted(_visit) {
+ this.progressBar.setValue(1);
+ this.hideVisitProgressBar();
+ }
+ pageInvalidated(reason) {
+ this.reload(reason);
+ }
+ visitFailed(_visit) {
+ this.progressBar.setValue(1);
+ this.hideVisitProgressBar();
+ }
+ visitRendered(_visit) {
+ }
+ // Form Submission Delegate
+ formSubmissionStarted(_formSubmission) {
+ this.progressBar.setValue(0);
+ this.showFormProgressBarAfterDelay();
+ }
+ formSubmissionFinished(_formSubmission) {
+ this.progressBar.setValue(1);
+ this.hideFormProgressBar();
+ }
+ // Private
+ showVisitProgressBarAfterDelay() {
+ this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
+ }
+ hideVisitProgressBar() {
+ this.progressBar.hide();
+ if (this.visitProgressBarTimeout != null) {
+ window.clearTimeout(this.visitProgressBarTimeout);
+ delete this.visitProgressBarTimeout;
+ }
+ }
+ showFormProgressBarAfterDelay() {
+ if (this.formProgressBarTimeout == null) {
+ this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
+ }
+ }
+ hideFormProgressBar() {
+ this.progressBar.hide();
+ if (this.formProgressBarTimeout != null) {
+ window.clearTimeout(this.formProgressBarTimeout);
+ delete this.formProgressBarTimeout;
+ }
+ }
+ showProgressBar = () => {
+ this.progressBar.show();
+ };
+ reload(reason) {
+ dispatch("turbo:reload", { detail: reason });
+ window.location.href = this.location?.toString() || window.location.href;
+ }
+ get navigator() {
+ return this.session.navigator;
+ }
+ };
+ var CacheObserver = class {
+ selector = "[data-turbo-temporary]";
+ deprecatedSelector = "[data-turbo-cache=false]";
+ started = false;
+ start() {
+ if (!this.started) {
+ this.started = true;
+ addEventListener("turbo:before-cache", this.removeTemporaryElements, false);
+ }
+ }
+ stop() {
+ if (this.started) {
+ this.started = false;
+ removeEventListener("turbo:before-cache", this.removeTemporaryElements, false);
+ }
+ }
+ removeTemporaryElements = (_event) => {
+ for (const element of this.temporaryElements) {
+ element.remove();
+ }
+ };
+ get temporaryElements() {
+ return [...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation];
+ }
+ get temporaryElementsWithDeprecation() {
+ const elements = document.querySelectorAll(this.deprecatedSelector);
+ if (elements.length) {
+ console.warn(
+ `The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`
+ );
+ }
+ return [...elements];
+ }
+ };
+ var FrameRedirector = class {
+ constructor(session2, element) {
+ this.session = session2;
+ this.element = element;
+ this.linkInterceptor = new LinkInterceptor(this, element);
+ this.formSubmitObserver = new FormSubmitObserver(this, element);
+ }
+ start() {
+ this.linkInterceptor.start();
+ this.formSubmitObserver.start();
+ }
+ stop() {
+ this.linkInterceptor.stop();
+ this.formSubmitObserver.stop();
+ }
+ // Link interceptor delegate
+ shouldInterceptLinkClick(element, _location, _event) {
+ return this.#shouldRedirect(element);
+ }
+ linkClickIntercepted(element, url, event) {
+ const frame = this.#findFrameElement(element);
+ if (frame) {
+ frame.delegate.linkClickIntercepted(element, url, event);
+ }
+ }
+ // Form submit observer delegate
+ willSubmitForm(element, submitter) {
+ return element.closest("turbo-frame") == null && this.#shouldSubmit(element, submitter) && this.#shouldRedirect(element, submitter);
+ }
+ formSubmitted(element, submitter) {
+ const frame = this.#findFrameElement(element, submitter);
+ if (frame) {
+ frame.delegate.formSubmitted(element, submitter);
+ }
+ }
+ #shouldSubmit(form, submitter) {
+ const action = getAction$1(form, submitter);
+ const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
+ const rootLocation = expandURL(meta?.content ?? "/");
+ return this.#shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
+ }
+ #shouldRedirect(element, submitter) {
+ const isNavigatable = element instanceof HTMLFormElement ? this.session.submissionIsNavigatable(element, submitter) : this.session.elementIsNavigatable(element);
+ if (isNavigatable) {
+ const frame = this.#findFrameElement(element, submitter);
+ return frame ? frame != element.closest("turbo-frame") : false;
+ } else {
+ return false;
+ }
+ }
+ #findFrameElement(element, submitter) {
+ const id = submitter?.getAttribute("data-turbo-frame") || element.getAttribute("data-turbo-frame");
+ if (id && id != "_top") {
+ const frame = this.element.querySelector(`#${id}:not([disabled])`);
+ if (frame instanceof FrameElement) {
+ return frame;
+ }
+ }
+ }
+ };
+ var History = class {
+ location;
+ restorationIdentifier = uuid();
+ restorationData = {};
+ started = false;
+ pageLoaded = false;
+ currentIndex = 0;
+ constructor(delegate) {
+ this.delegate = delegate;
+ }
+ start() {
+ if (!this.started) {
+ addEventListener("popstate", this.onPopState, false);
+ addEventListener("load", this.onPageLoad, false);
+ this.currentIndex = history.state?.turbo?.restorationIndex || 0;
+ this.started = true;
+ this.replace(new URL(window.location.href));
+ }
+ }
+ stop() {
+ if (this.started) {
+ removeEventListener("popstate", this.onPopState, false);
+ removeEventListener("load", this.onPageLoad, false);
+ this.started = false;
+ }
+ }
+ push(location2, restorationIdentifier) {
+ this.update(history.pushState, location2, restorationIdentifier);
+ }
+ replace(location2, restorationIdentifier) {
+ this.update(history.replaceState, location2, restorationIdentifier);
+ }
+ update(method, location2, restorationIdentifier = uuid()) {
+ if (method === history.pushState) ++this.currentIndex;
+ const state = { turbo: { restorationIdentifier, restorationIndex: this.currentIndex } };
+ method.call(history, state, "", location2.href);
+ this.location = location2;
+ this.restorationIdentifier = restorationIdentifier;
+ }
+ // Restoration data
+ getRestorationDataForIdentifier(restorationIdentifier) {
+ return this.restorationData[restorationIdentifier] || {};
+ }
+ updateRestorationData(additionalData) {
+ const { restorationIdentifier } = this;
+ const restorationData = this.restorationData[restorationIdentifier];
+ this.restorationData[restorationIdentifier] = {
+ ...restorationData,
+ ...additionalData
+ };
+ }
+ // Scroll restoration
+ assumeControlOfScrollRestoration() {
+ if (!this.previousScrollRestoration) {
+ this.previousScrollRestoration = history.scrollRestoration ?? "auto";
+ history.scrollRestoration = "manual";
+ }
+ }
+ relinquishControlOfScrollRestoration() {
+ if (this.previousScrollRestoration) {
+ history.scrollRestoration = this.previousScrollRestoration;
+ delete this.previousScrollRestoration;
+ }
+ }
+ // Event handlers
+ onPopState = (event) => {
+ if (this.shouldHandlePopState()) {
+ const { turbo } = event.state || {};
+ if (turbo) {
+ this.location = new URL(window.location.href);
+ const { restorationIdentifier, restorationIndex } = turbo;
+ this.restorationIdentifier = restorationIdentifier;
+ const direction = restorationIndex > this.currentIndex ? "forward" : "back";
+ this.delegate.historyPoppedToLocationWithRestorationIdentifierAndDirection(this.location, restorationIdentifier, direction);
+ this.currentIndex = restorationIndex;
+ }
+ }
+ };
+ onPageLoad = async (_event) => {
+ await nextMicrotask();
+ this.pageLoaded = true;
+ };
+ // Private
+ shouldHandlePopState() {
+ return this.pageIsLoaded();
+ }
+ pageIsLoaded() {
+ return this.pageLoaded || document.readyState == "complete";
+ }
+ };
+ var LinkPrefetchObserver = class {
+ started = false;
+ #prefetchedLink = null;
+ constructor(delegate, eventTarget) {
+ this.delegate = delegate;
+ this.eventTarget = eventTarget;
+ }
+ start() {
+ if (this.started) return;
+ if (this.eventTarget.readyState === "loading") {
+ this.eventTarget.addEventListener("DOMContentLoaded", this.#enable, { once: true });
+ } else {
+ this.#enable();
+ }
+ }
+ stop() {
+ if (!this.started) return;
+ this.eventTarget.removeEventListener("mouseenter", this.#tryToPrefetchRequest, {
+ capture: true,
+ passive: true
+ });
+ this.eventTarget.removeEventListener("mouseleave", this.#cancelRequestIfObsolete, {
+ capture: true,
+ passive: true
+ });
+ this.eventTarget.removeEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true);
+ this.started = false;
+ }
+ #enable = () => {
+ this.eventTarget.addEventListener("mouseenter", this.#tryToPrefetchRequest, {
+ capture: true,
+ passive: true
+ });
+ this.eventTarget.addEventListener("mouseleave", this.#cancelRequestIfObsolete, {
+ capture: true,
+ passive: true
+ });
+ this.eventTarget.addEventListener("turbo:before-fetch-request", this.#tryToUsePrefetchedRequest, true);
+ this.started = true;
+ };
+ #tryToPrefetchRequest = (event) => {
+ if (getMetaContent("turbo-prefetch") === "false") return;
+ const target = event.target;
+ const isLink = target.matches && target.matches("a[href]:not([target^=_]):not([download])");
+ if (isLink && this.#isPrefetchable(target)) {
+ const link = target;
+ const location2 = getLocationForLink(link);
+ if (this.delegate.canPrefetchRequestToLocation(link, location2)) {
+ this.#prefetchedLink = link;
+ const fetchRequest = new FetchRequest(
+ this,
+ FetchMethod.get,
+ location2,
+ new URLSearchParams(),
+ target
+ );
+ prefetchCache.setLater(location2.toString(), fetchRequest, this.#cacheTtl);
+ }
+ }
+ };
+ #cancelRequestIfObsolete = (event) => {
+ if (event.target === this.#prefetchedLink) this.#cancelPrefetchRequest();
+ };
+ #cancelPrefetchRequest = () => {
+ prefetchCache.clear();
+ this.#prefetchedLink = null;
+ };
+ #tryToUsePrefetchedRequest = (event) => {
+ if (event.target.tagName !== "FORM" && event.detail.fetchOptions.method === "GET") {
+ const cached = prefetchCache.get(event.detail.url.toString());
+ if (cached) {
+ event.detail.fetchRequest = cached;
+ }
+ prefetchCache.clear();
+ }
+ };
+ prepareRequest(request) {
+ const link = request.target;
+ request.headers["X-Sec-Purpose"] = "prefetch";
+ const turboFrame = link.closest("turbo-frame");
+ const turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id;
+ if (turboFrameTarget && turboFrameTarget !== "_top") {
+ request.headers["Turbo-Frame"] = turboFrameTarget;
+ }
+ }
+ // Fetch request interface
+ requestSucceededWithResponse() {
+ }
+ requestStarted(fetchRequest) {
+ }
+ requestErrored(fetchRequest) {
+ }
+ requestFinished(fetchRequest) {
+ }
+ requestPreventedHandlingResponse(fetchRequest, fetchResponse) {
+ }
+ requestFailedWithResponse(fetchRequest, fetchResponse) {
+ }
+ get #cacheTtl() {
+ return Number(getMetaContent("turbo-prefetch-cache-time")) || cacheTtl;
+ }
+ #isPrefetchable(link) {
+ const href = link.getAttribute("href");
+ if (!href) return false;
+ if (unfetchableLink(link)) return false;
+ if (linkToTheSamePage(link)) return false;
+ if (linkOptsOut(link)) return false;
+ if (nonSafeLink(link)) return false;
+ if (eventPrevented(link)) return false;
+ return true;
+ }
+ };
+ var unfetchableLink = (link) => {
+ return link.origin !== document.location.origin || !["http:", "https:"].includes(link.protocol) || link.hasAttribute("target");
+ };
+ var linkToTheSamePage = (link) => {
+ return link.pathname + link.search === document.location.pathname + document.location.search || link.href.startsWith("#");
+ };
+ var linkOptsOut = (link) => {
+ if (link.getAttribute("data-turbo-prefetch") === "false") return true;
+ if (link.getAttribute("data-turbo") === "false") return true;
+ const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
+ if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false") return true;
+ return false;
+ };
+ var nonSafeLink = (link) => {
+ const turboMethod = link.getAttribute("data-turbo-method");
+ if (turboMethod && turboMethod.toLowerCase() !== "get") return true;
+ if (isUJS(link)) return true;
+ if (link.hasAttribute("data-turbo-confirm")) return true;
+ if (link.hasAttribute("data-turbo-stream")) return true;
+ return false;
+ };
+ var isUJS = (link) => {
+ return link.hasAttribute("data-remote") || link.hasAttribute("data-behavior") || link.hasAttribute("data-confirm") || link.hasAttribute("data-method");
+ };
+ var eventPrevented = (link) => {
+ const event = dispatch("turbo:before-prefetch", { target: link, cancelable: true });
+ return event.defaultPrevented;
+ };
+ var Navigator = class {
+ constructor(delegate) {
+ this.delegate = delegate;
+ }
+ proposeVisit(location2, options = {}) {
+ if (this.delegate.allowsVisitingLocationWithAction(location2, options.action)) {
+ this.delegate.visitProposedToLocation(location2, options);
+ }
+ }
+ startVisit(locatable, restorationIdentifier, options = {}) {
+ this.stop();
+ this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, {
+ referrer: this.location,
+ ...options
+ });
+ this.currentVisit.start();
+ }
+ submitForm(form, submitter) {
+ this.stop();
+ this.formSubmission = new FormSubmission(this, form, submitter, true);
+ this.formSubmission.start();
+ }
+ stop() {
+ if (this.formSubmission) {
+ this.formSubmission.stop();
+ delete this.formSubmission;
+ }
+ if (this.currentVisit) {
+ this.currentVisit.cancel();
+ delete this.currentVisit;
+ }
+ }
+ get adapter() {
+ return this.delegate.adapter;
+ }
+ get view() {
+ return this.delegate.view;
+ }
+ get rootLocation() {
+ return this.view.snapshot.rootLocation;
+ }
+ get history() {
+ return this.delegate.history;
+ }
+ // Form submission delegate
+ formSubmissionStarted(formSubmission) {
+ if (typeof this.adapter.formSubmissionStarted === "function") {
+ this.adapter.formSubmissionStarted(formSubmission);
+ }
+ }
+ async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {
+ if (formSubmission == this.formSubmission) {
+ const responseHTML = await fetchResponse.responseHTML;
+ if (responseHTML) {
+ const shouldCacheSnapshot = formSubmission.isSafe;
+ if (!shouldCacheSnapshot) {
+ this.view.clearSnapshotCache();
+ }
+ const { statusCode, redirected } = fetchResponse;
+ const action = this.#getActionForFormSubmission(formSubmission, fetchResponse);
+ const visitOptions = {
+ action,
+ shouldCacheSnapshot,
+ response: { statusCode, responseHTML, redirected }
+ };
+ this.proposeVisit(fetchResponse.location, visitOptions);
+ }
+ }
+ }
+ async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
+ const responseHTML = await fetchResponse.responseHTML;
+ if (responseHTML) {
+ const snapshot = PageSnapshot.fromHTMLString(responseHTML);
+ if (fetchResponse.serverError) {
+ await this.view.renderError(snapshot, this.currentVisit);
+ } else {
+ await this.view.renderPage(snapshot, false, true, this.currentVisit);
+ }
+ if (!snapshot.shouldPreserveScrollPosition) {
+ this.view.scrollToTop();
+ }
+ this.view.clearSnapshotCache();
+ }
+ }
+ formSubmissionErrored(formSubmission, error2) {
+ console.error(error2);
+ }
+ formSubmissionFinished(formSubmission) {
+ if (typeof this.adapter.formSubmissionFinished === "function") {
+ this.adapter.formSubmissionFinished(formSubmission);
+ }
+ }
+ // Visit delegate
+ visitStarted(visit2) {
+ this.delegate.visitStarted(visit2);
+ }
+ visitCompleted(visit2) {
+ this.delegate.visitCompleted(visit2);
+ delete this.currentVisit;
+ }
+ locationWithActionIsSamePage(location2, action) {
+ const anchor = getAnchor(location2);
+ const currentAnchor = getAnchor(this.view.lastRenderedLocation);
+ const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
+ return action !== "replace" && getRequestURL(location2) === getRequestURL(this.view.lastRenderedLocation) && (isRestorationToTop || anchor != null && anchor !== currentAnchor);
+ }
+ visitScrolledToSamePageLocation(oldURL, newURL) {
+ this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
+ }
+ // Visits
+ get location() {
+ return this.history.location;
+ }
+ get restorationIdentifier() {
+ return this.history.restorationIdentifier;
+ }
+ #getActionForFormSubmission(formSubmission, fetchResponse) {
+ const { submitter, formElement } = formSubmission;
+ return getVisitAction(submitter, formElement) || this.#getDefaultAction(fetchResponse);
+ }
+ #getDefaultAction(fetchResponse) {
+ const sameLocationRedirect = fetchResponse.redirected && fetchResponse.location.href === this.location?.href;
+ return sameLocationRedirect ? "replace" : "advance";
+ }
+ };
+ var PageStage = {
+ initial: 0,
+ loading: 1,
+ interactive: 2,
+ complete: 3
+ };
+ var PageObserver = class {
+ stage = PageStage.initial;
+ started = false;
+ constructor(delegate) {
+ this.delegate = delegate;
+ }
+ start() {
+ if (!this.started) {
+ if (this.stage == PageStage.initial) {
+ this.stage = PageStage.loading;
+ }
+ document.addEventListener("readystatechange", this.interpretReadyState, false);
+ addEventListener("pagehide", this.pageWillUnload, false);
+ this.started = true;
+ }
+ }
+ stop() {
+ if (this.started) {
+ document.removeEventListener("readystatechange", this.interpretReadyState, false);
+ removeEventListener("pagehide", this.pageWillUnload, false);
+ this.started = false;
+ }
+ }
+ interpretReadyState = () => {
+ const { readyState } = this;
+ if (readyState == "interactive") {
+ this.pageIsInteractive();
+ } else if (readyState == "complete") {
+ this.pageIsComplete();
+ }
+ };
+ pageIsInteractive() {
+ if (this.stage == PageStage.loading) {
+ this.stage = PageStage.interactive;
+ this.delegate.pageBecameInteractive();
+ }
+ }
+ pageIsComplete() {
+ this.pageIsInteractive();
+ if (this.stage == PageStage.interactive) {
+ this.stage = PageStage.complete;
+ this.delegate.pageLoaded();
+ }
+ }
+ pageWillUnload = () => {
+ this.delegate.pageWillUnload();
+ };
+ get readyState() {
+ return document.readyState;
+ }
+ };
+ var ScrollObserver = class {
+ started = false;
+ constructor(delegate) {
+ this.delegate = delegate;
+ }
+ start() {
+ if (!this.started) {
+ addEventListener("scroll", this.onScroll, false);
+ this.onScroll();
+ this.started = true;
+ }
+ }
+ stop() {
+ if (this.started) {
+ removeEventListener("scroll", this.onScroll, false);
+ this.started = false;
+ }
+ }
+ onScroll = () => {
+ this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
+ };
+ // Private
+ updatePosition(position) {
+ this.delegate.scrollPositionChanged(position);
+ }
+ };
+ var StreamMessageRenderer = class {
+ render({ fragment }) {
+ Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => {
+ withAutofocusFromFragment(fragment, () => {
+ withPreservedFocus(() => {
+ document.documentElement.appendChild(fragment);
+ });
+ });
+ });
+ }
+ // Bardo delegate
+ enteringBardo(currentPermanentElement, newPermanentElement) {
+ newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
+ }
+ leavingBardo() {
+ }
+ };
+ function getPermanentElementMapForFragment(fragment) {
+ const permanentElementsInDocument = queryPermanentElementsAll(document.documentElement);
+ const permanentElementMap = {};
+ for (const permanentElementInDocument of permanentElementsInDocument) {
+ const { id } = permanentElementInDocument;
+ for (const streamElement of fragment.querySelectorAll("turbo-stream")) {
+ const elementInStream = getPermanentElementById(streamElement.templateElement.content, id);
+ if (elementInStream) {
+ permanentElementMap[id] = [permanentElementInDocument, elementInStream];
+ }
+ }
+ }
+ return permanentElementMap;
+ }
+ async function withAutofocusFromFragment(fragment, callback) {
+ const generatedID = `turbo-stream-autofocus-${uuid()}`;
+ const turboStreams = fragment.querySelectorAll("turbo-stream");
+ const elementWithAutofocus = firstAutofocusableElementInStreams(turboStreams);
+ let willAutofocusId = null;
+ if (elementWithAutofocus) {
+ if (elementWithAutofocus.id) {
+ willAutofocusId = elementWithAutofocus.id;
+ } else {
+ willAutofocusId = generatedID;
+ }
+ elementWithAutofocus.id = willAutofocusId;
+ }
+ callback();
+ await nextRepaint();
+ const hasNoActiveElement = document.activeElement == null || document.activeElement == document.body;
+ if (hasNoActiveElement && willAutofocusId) {
+ const elementToAutofocus = document.getElementById(willAutofocusId);
+ if (elementIsFocusable(elementToAutofocus)) {
+ elementToAutofocus.focus();
+ }
+ if (elementToAutofocus && elementToAutofocus.id == generatedID) {
+ elementToAutofocus.removeAttribute("id");
+ }
+ }
+ }
+ async function withPreservedFocus(callback) {
+ const [activeElementBeforeRender, activeElementAfterRender] = await around(callback, () => document.activeElement);
+ const restoreFocusTo = activeElementBeforeRender && activeElementBeforeRender.id;
+ if (restoreFocusTo) {
+ const elementToFocus = document.getElementById(restoreFocusTo);
+ if (elementIsFocusable(elementToFocus) && elementToFocus != activeElementAfterRender) {
+ elementToFocus.focus();
+ }
+ }
+ }
+ function firstAutofocusableElementInStreams(nodeListOfStreamElements) {
+ for (const streamElement of nodeListOfStreamElements) {
+ const elementWithAutofocus = queryAutofocusableElement(streamElement.templateElement.content);
+ if (elementWithAutofocus) return elementWithAutofocus;
+ }
+ return null;
+ }
+ var StreamObserver = class {
+ sources = /* @__PURE__ */ new Set();
+ #started = false;
+ constructor(delegate) {
+ this.delegate = delegate;
+ }
+ start() {
+ if (!this.#started) {
+ this.#started = true;
+ addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
+ }
+ }
+ stop() {
+ if (this.#started) {
+ this.#started = false;
+ removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
+ }
+ }
+ connectStreamSource(source) {
+ if (!this.streamSourceIsConnected(source)) {
+ this.sources.add(source);
+ source.addEventListener("message", this.receiveMessageEvent, false);
+ }
+ }
+ disconnectStreamSource(source) {
+ if (this.streamSourceIsConnected(source)) {
+ this.sources.delete(source);
+ source.removeEventListener("message", this.receiveMessageEvent, false);
+ }
+ }
+ streamSourceIsConnected(source) {
+ return this.sources.has(source);
+ }
+ inspectFetchResponse = (event) => {
+ const response = fetchResponseFromEvent(event);
+ if (response && fetchResponseIsStream(response)) {
+ event.preventDefault();
+ this.receiveMessageResponse(response);
+ }
+ };
+ receiveMessageEvent = (event) => {
+ if (this.#started && typeof event.data == "string") {
+ this.receiveMessageHTML(event.data);
+ }
+ };
+ async receiveMessageResponse(response) {
+ const html = await response.responseHTML;
+ if (html) {
+ this.receiveMessageHTML(html);
+ }
+ }
+ receiveMessageHTML(html) {
+ this.delegate.receivedMessageFromStream(StreamMessage.wrap(html));
+ }
+ };
+ function fetchResponseFromEvent(event) {
+ const fetchResponse = event.detail?.fetchResponse;
+ if (fetchResponse instanceof FetchResponse) {
+ return fetchResponse;
+ }
+ }
+ function fetchResponseIsStream(response) {
+ const contentType = response.contentType ?? "";
+ return contentType.startsWith(StreamMessage.contentType);
+ }
+ var ErrorRenderer = class extends Renderer {
+ static renderElement(currentElement, newElement) {
+ const { documentElement, body } = document;
+ documentElement.replaceChild(newElement, body);
+ }
+ async render() {
+ this.replaceHeadAndBody();
+ this.activateScriptElements();
+ }
+ replaceHeadAndBody() {
+ const { documentElement, head } = document;
+ documentElement.replaceChild(this.newHead, head);
+ this.renderElement(this.currentElement, this.newElement);
+ }
+ activateScriptElements() {
+ for (const replaceableElement of this.scriptElements) {
+ const parentNode = replaceableElement.parentNode;
+ if (parentNode) {
+ const element = activateScriptElement(replaceableElement);
+ parentNode.replaceChild(element, replaceableElement);
+ }
+ }
+ }
+ get newHead() {
+ return this.newSnapshot.headSnapshot.element;
+ }
+ get scriptElements() {
+ return document.documentElement.querySelectorAll("script");
+ }
+ };
+ var Idiomorph = /* @__PURE__ */ function() {
+ let EMPTY_SET = /* @__PURE__ */ new Set();
+ let defaults = {
+ morphStyle: "outerHTML",
+ callbacks: {
+ beforeNodeAdded: noOp,
+ afterNodeAdded: noOp,
+ beforeNodeMorphed: noOp,
+ afterNodeMorphed: noOp,
+ beforeNodeRemoved: noOp,
+ afterNodeRemoved: noOp,
+ beforeAttributeUpdated: noOp
+ },
+ head: {
+ style: "merge",
+ shouldPreserve: function(elt) {
+ return elt.getAttribute("im-preserve") === "true";
+ },
+ shouldReAppend: function(elt) {
+ return elt.getAttribute("im-re-append") === "true";
+ },
+ shouldRemove: noOp,
+ afterHeadMorphed: noOp
+ }
+ };
+ function morph(oldNode, newContent, config = {}) {
+ if (oldNode instanceof Document) {
+ oldNode = oldNode.documentElement;
+ }
+ if (typeof newContent === "string") {
+ newContent = parseContent(newContent);
+ }
+ let normalizedContent = normalizeContent(newContent);
+ let ctx = createMorphContext(oldNode, normalizedContent, config);
+ return morphNormalizedContent(oldNode, normalizedContent, ctx);
+ }
+ function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {
+ if (ctx.head.block) {
+ let oldHead = oldNode.querySelector("head");
+ let newHead = normalizedNewContent.querySelector("head");
+ if (oldHead && newHead) {
+ let promises = handleHeadElement(newHead, oldHead, ctx);
+ Promise.all(promises).then(function() {
+ morphNormalizedContent(oldNode, normalizedNewContent, Object.assign(ctx, {
+ head: {
+ block: false,
+ ignore: true
+ }
+ }));
+ });
+ return;
+ }
+ }
+ if (ctx.morphStyle === "innerHTML") {
+ morphChildren2(normalizedNewContent, oldNode, ctx);
+ return oldNode.children;
+ } else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) {
+ let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);
+ let previousSibling = bestMatch?.previousSibling;
+ let nextSibling = bestMatch?.nextSibling;
+ let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);
+ if (bestMatch) {
+ return insertSiblings(previousSibling, morphedNode, nextSibling);
+ } else {
+ return [];
+ }
+ } else {
+ throw "Do not understand how to morph style " + ctx.morphStyle;
+ }
+ }
+ function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
+ return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
+ }
+ function morphOldNodeTo(oldNode, newContent, ctx) {
+ if (ctx.ignoreActive && oldNode === document.activeElement) ;
+ else if (newContent == null) {
+ if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
+ oldNode.remove();
+ ctx.callbacks.afterNodeRemoved(oldNode);
+ return null;
+ } else if (!isSoftMatch(oldNode, newContent)) {
+ if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
+ if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;
+ oldNode.parentElement.replaceChild(newContent, oldNode);
+ ctx.callbacks.afterNodeAdded(newContent);
+ ctx.callbacks.afterNodeRemoved(oldNode);
+ return newContent;
+ } else {
+ if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) return oldNode;
+ if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) ;
+ else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") {
+ handleHeadElement(newContent, oldNode, ctx);
+ } else {
+ syncNodeFrom(newContent, oldNode, ctx);
+ if (!ignoreValueOfActiveElement(oldNode, ctx)) {
+ morphChildren2(newContent, oldNode, ctx);
+ }
+ }
+ ctx.callbacks.afterNodeMorphed(oldNode, newContent);
+ return oldNode;
+ }
+ }
+ function morphChildren2(newParent, oldParent, ctx) {
+ let nextNewChild = newParent.firstChild;
+ let insertionPoint = oldParent.firstChild;
+ let newChild;
+ while (nextNewChild) {
+ newChild = nextNewChild;
+ nextNewChild = newChild.nextSibling;
+ if (insertionPoint == null) {
+ if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
+ oldParent.appendChild(newChild);
+ ctx.callbacks.afterNodeAdded(newChild);
+ removeIdsFromConsideration(ctx, newChild);
+ continue;
+ }
+ if (isIdSetMatch(newChild, insertionPoint, ctx)) {
+ morphOldNodeTo(insertionPoint, newChild, ctx);
+ insertionPoint = insertionPoint.nextSibling;
+ removeIdsFromConsideration(ctx, newChild);
+ continue;
+ }
+ let idSetMatch = findIdSetMatch(newParent, oldParent, newChild, insertionPoint, ctx);
+ if (idSetMatch) {
+ insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);
+ morphOldNodeTo(idSetMatch, newChild, ctx);
+ removeIdsFromConsideration(ctx, newChild);
+ continue;
+ }
+ let softMatch = findSoftMatch(newParent, oldParent, newChild, insertionPoint, ctx);
+ if (softMatch) {
+ insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);
+ morphOldNodeTo(softMatch, newChild, ctx);
+ removeIdsFromConsideration(ctx, newChild);
+ continue;
+ }
+ if (ctx.callbacks.beforeNodeAdded(newChild) === false) return;
+ oldParent.insertBefore(newChild, insertionPoint);
+ ctx.callbacks.afterNodeAdded(newChild);
+ removeIdsFromConsideration(ctx, newChild);
+ }
+ while (insertionPoint !== null) {
+ let tempNode = insertionPoint;
+ insertionPoint = insertionPoint.nextSibling;
+ removeNode(tempNode, ctx);
+ }
+ }
+ function ignoreAttribute(attr, to, updateType, ctx) {
+ if (attr === "value" && ctx.ignoreActiveValue && to === document.activeElement) {
+ return true;
+ }
+ return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;
+ }
+ function syncNodeFrom(from, to, ctx) {
+ let type = from.nodeType;
+ if (type === 1) {
+ const fromAttributes = from.attributes;
+ const toAttributes = to.attributes;
+ for (const fromAttribute of fromAttributes) {
+ if (ignoreAttribute(fromAttribute.name, to, "update", ctx)) {
+ continue;
+ }
+ if (to.getAttribute(fromAttribute.name) !== fromAttribute.value) {
+ to.setAttribute(fromAttribute.name, fromAttribute.value);
+ }
+ }
+ for (let i = toAttributes.length - 1; 0 <= i; i--) {
+ const toAttribute = toAttributes[i];
+ if (ignoreAttribute(toAttribute.name, to, "remove", ctx)) {
+ continue;
+ }
+ if (!from.hasAttribute(toAttribute.name)) {
+ to.removeAttribute(toAttribute.name);
+ }
+ }
+ }
+ if (type === 8 || type === 3) {
+ if (to.nodeValue !== from.nodeValue) {
+ to.nodeValue = from.nodeValue;
+ }
+ }
+ if (!ignoreValueOfActiveElement(to, ctx)) {
+ syncInputValue(from, to, ctx);
+ }
+ }
+ function syncBooleanAttribute(from, to, attributeName, ctx) {
+ if (from[attributeName] !== to[attributeName]) {
+ let ignoreUpdate = ignoreAttribute(attributeName, to, "update", ctx);
+ if (!ignoreUpdate) {
+ to[attributeName] = from[attributeName];
+ }
+ if (from[attributeName]) {
+ if (!ignoreUpdate) {
+ to.setAttribute(attributeName, from[attributeName]);
+ }
+ } else {
+ if (!ignoreAttribute(attributeName, to, "remove", ctx)) {
+ to.removeAttribute(attributeName);
+ }
+ }
+ }
+ }
+ function syncInputValue(from, to, ctx) {
+ if (from instanceof HTMLInputElement && to instanceof HTMLInputElement && from.type !== "file") {
+ let fromValue = from.value;
+ let toValue = to.value;
+ syncBooleanAttribute(from, to, "checked", ctx);
+ syncBooleanAttribute(from, to, "disabled", ctx);
+ if (!from.hasAttribute("value")) {
+ if (!ignoreAttribute("value", to, "remove", ctx)) {
+ to.value = "";
+ to.removeAttribute("value");
+ }
+ } else if (fromValue !== toValue) {
+ if (!ignoreAttribute("value", to, "update", ctx)) {
+ to.setAttribute("value", fromValue);
+ to.value = fromValue;
+ }
+ }
+ } else if (from instanceof HTMLOptionElement) {
+ syncBooleanAttribute(from, to, "selected", ctx);
+ } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {
+ let fromValue = from.value;
+ let toValue = to.value;
+ if (ignoreAttribute("value", to, "update", ctx)) {
+ return;
+ }
+ if (fromValue !== toValue) {
+ to.value = fromValue;
+ }
+ if (to.firstChild && to.firstChild.nodeValue !== fromValue) {
+ to.firstChild.nodeValue = fromValue;
+ }
+ }
+ }
+ function handleHeadElement(newHeadTag, currentHead, ctx) {
+ let added = [];
+ let removed = [];
+ let preserved = [];
+ let nodesToAppend = [];
+ let headMergeStyle = ctx.head.style;
+ let srcToNewHeadNodes = /* @__PURE__ */ new Map();
+ for (const newHeadChild of newHeadTag.children) {
+ srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
+ }
+ for (const currentHeadElt of currentHead.children) {
+ let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
+ let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
+ let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
+ if (inNewContent || isPreserved) {
+ if (isReAppended) {
+ removed.push(currentHeadElt);
+ } else {
+ srcToNewHeadNodes.delete(currentHeadElt.outerHTML);
+ preserved.push(currentHeadElt);
+ }
+ } else {
+ if (headMergeStyle === "append") {
+ if (isReAppended) {
+ removed.push(currentHeadElt);
+ nodesToAppend.push(currentHeadElt);
+ }
+ } else {
+ if (ctx.head.shouldRemove(currentHeadElt) !== false) {
+ removed.push(currentHeadElt);
+ }
+ }
+ }
+ }
+ nodesToAppend.push(...srcToNewHeadNodes.values());
+ let promises = [];
+ for (const newNode of nodesToAppend) {
+ let newElt = document.createRange().createContextualFragment(newNode.outerHTML).firstChild;
+ if (ctx.callbacks.beforeNodeAdded(newElt) !== false) {
+ if (newElt.href || newElt.src) {
+ let resolve = null;
+ let promise = new Promise(function(_resolve) {
+ resolve = _resolve;
+ });
+ newElt.addEventListener("load", function() {
+ resolve();
+ });
+ promises.push(promise);
+ }
+ currentHead.appendChild(newElt);
+ ctx.callbacks.afterNodeAdded(newElt);
+ added.push(newElt);
+ }
+ }
+ for (const removedElement of removed) {
+ if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
+ currentHead.removeChild(removedElement);
+ ctx.callbacks.afterNodeRemoved(removedElement);
+ }
+ }
+ ctx.head.afterHeadMorphed(currentHead, { added, kept: preserved, removed });
+ return promises;
+ }
+ function noOp() {
+ }
+ function mergeDefaults(config) {
+ let finalConfig = {};
+ Object.assign(finalConfig, defaults);
+ Object.assign(finalConfig, config);
+ finalConfig.callbacks = {};
+ Object.assign(finalConfig.callbacks, defaults.callbacks);
+ Object.assign(finalConfig.callbacks, config.callbacks);
+ finalConfig.head = {};
+ Object.assign(finalConfig.head, defaults.head);
+ Object.assign(finalConfig.head, config.head);
+ return finalConfig;
+ }
+ function createMorphContext(oldNode, newContent, config) {
+ config = mergeDefaults(config);
+ return {
+ target: oldNode,
+ newContent,
+ config,
+ morphStyle: config.morphStyle,
+ ignoreActive: config.ignoreActive,
+ ignoreActiveValue: config.ignoreActiveValue,
+ idMap: createIdMap(oldNode, newContent),
+ deadIds: /* @__PURE__ */ new Set(),
+ callbacks: config.callbacks,
+ head: config.head
+ };
+ }
+ function isIdSetMatch(node1, node2, ctx) {
+ if (node1 == null || node2 == null) {
+ return false;
+ }
+ if (node1.nodeType === node2.nodeType && node1.tagName === node2.tagName) {
+ if (node1.id !== "" && node1.id === node2.id) {
+ return true;
+ } else {
+ return getIdIntersectionCount(ctx, node1, node2) > 0;
+ }
+ }
+ return false;
+ }
+ function isSoftMatch(node1, node2) {
+ if (node1 == null || node2 == null) {
+ return false;
+ }
+ return node1.nodeType === node2.nodeType && node1.tagName === node2.tagName;
+ }
+ function removeNodesBetween(startInclusive, endExclusive, ctx) {
+ while (startInclusive !== endExclusive) {
+ let tempNode = startInclusive;
+ startInclusive = startInclusive.nextSibling;
+ removeNode(tempNode, ctx);
+ }
+ removeIdsFromConsideration(ctx, endExclusive);
+ return endExclusive.nextSibling;
+ }
+ function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
+ let newChildPotentialIdCount = getIdIntersectionCount(ctx, newChild, oldParent);
+ let potentialMatch = null;
+ if (newChildPotentialIdCount > 0) {
+ let potentialMatch2 = insertionPoint;
+ let otherMatchCount = 0;
+ while (potentialMatch2 != null) {
+ if (isIdSetMatch(newChild, potentialMatch2, ctx)) {
+ return potentialMatch2;
+ }
+ otherMatchCount += getIdIntersectionCount(ctx, potentialMatch2, newContent);
+ if (otherMatchCount > newChildPotentialIdCount) {
+ return null;
+ }
+ potentialMatch2 = potentialMatch2.nextSibling;
+ }
+ }
+ return potentialMatch;
+ }
+ function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
+ let potentialSoftMatch = insertionPoint;
+ let nextSibling = newChild.nextSibling;
+ let siblingSoftMatchCount = 0;
+ while (potentialSoftMatch != null) {
+ if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {
+ return null;
+ }
+ if (isSoftMatch(newChild, potentialSoftMatch)) {
+ return potentialSoftMatch;
+ }
+ if (isSoftMatch(nextSibling, potentialSoftMatch)) {
+ siblingSoftMatchCount++;
+ nextSibling = nextSibling.nextSibling;
+ if (siblingSoftMatchCount >= 2) {
+ return null;
+ }
+ }
+ potentialSoftMatch = potentialSoftMatch.nextSibling;
+ }
+ return potentialSoftMatch;
+ }
+ function parseContent(newContent) {
+ let parser = new DOMParser();
+ let contentWithSvgsRemoved = newContent.replace(/