diff --git a/app/assets/builds/application.css b/app/assets/builds/application.css
index 633af5507..265209dc5 100644
--- a/app/assets/builds/application.css
+++ b/app/assets/builds/application.css
@@ -1914,6 +1914,12 @@ input:not([type=checkbox]):not([type=radio]).is-invalid + span, select.is-invali
}
}
+@media all and (min-width: 992px) {
+ .o-grid--two-col-laptop {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
@media all and (min-width: 1120px) {
.o-grid--two-col-desktop {
grid-template-columns: repeat(2, 1fr);
@@ -1930,6 +1936,20 @@ input:not([type=checkbox]):not([type=radio]).is-invalid + span, select.is-invali
row-gap: 3rem;
}
+.o-grid--wishlist {
+ row-gap: 1.5rem;
+}
+@media all and (min-width: 768px) {
+ .o-grid--wishlist {
+ row-gap: 2.5rem;
+ }
+}
+@media all and (min-width: 992px) {
+ .o-grid--wishlist {
+ row-gap: 0;
+ }
+}
+
.o-io-icon {
display: inline-block;
vertical-align: middle;
@@ -3633,6 +3653,25 @@ input:not([type=checkbox]):not([type=radio]).is-invalid + span, select.is-invali
padding: 0;
}
+.c-cta--wishlist {
+ background: #fff;
+ margin-bottom: 1.5rem;
+ padding-bottom: 60px;
+ box-shadow: 0 0 48px rgba(0, 0, 0, 0.12);
+}
+@media all and (min-width: 768px) {
+ .c-cta--wishlist {
+ margin-bottom: 2.5rem;
+ padding-bottom: 0px;
+ box-shadow: unset;
+ }
+}
+@media all and (min-width: 992px) {
+ .c-cta--wishlist {
+ margin-bottom: 3.75rem;
+ }
+}
+
.c-btn--orange {
font-weight: 500;
font-size: 1rem;
@@ -5482,6 +5521,10 @@ table .c-btn--icon {
margin: 0;
}
+.c-account--mainpage .c-account_editicons > svg:first-child {
+ display: none;
+}
+
.c-account_editicons {
gap: 8px;
position: absolute;
@@ -5501,35 +5544,17 @@ table .c-btn--icon {
opacity: 1;
transition: opacity 0.3s;
}
-.c-account_editicons > svg:not(:first-child) {
+.c-account_editicons > svg:nth-last-child(-n+2) {
display: none;
}
.c-account_editicons > svg:hover {
opacity: 0.7;
}
-.c-account_editicons.is-editable .c-account_editicons--reset {
+.c-account_editicons.is-editable > svg:nth-last-child(-n+2) {
display: inline-flex;
}
-.c-account_editicons.is-editable .c-account_editicons--reset svg {
- display: block;
-}
-.c-account_editicons.is-editable > svg:not(:first-child) {
- display: inline-flex;
-}
-.c-account_editicons.is-editable > svg:first-child {
- display: none;
-}
-
-.c-account_editicons--reset {
+.c-account_editicons.is-editable > svg:nth-child(-n+2) {
display: none;
- padding: 0;
- border: 0;
- background-color: transparent;
- opacity: 1;
- transition: opacity 0.3s;
-}
-.c-account_editicons--reset:hover {
- opacity: 0.7;
}
.c-account__input-wrapper {
@@ -5545,17 +5570,19 @@ table .c-btn--icon {
}
}
.c-account__input-wrapper .c-account__input {
- width: 50%;
+ width: 100%;
flex-shrink: 0;
}
+@media all and (min-width: 374px) {
+ .c-account__input-wrapper .c-account__input {
+ width: 50%;
+ }
+}
@media all and (min-width: 768px) {
.c-account__input-wrapper .c-account__input {
width: 131px;
}
}
-.c-account__input-wrapper .c-account__input:last-child {
- margin-bottom: 0;
-}
@media all and (min-width: 768px) {
.c-account__input-wrapper .c-account__input:last-child {
width: 165px;
@@ -5578,11 +5605,11 @@ table .c-btn--icon {
padding: 0;
}
-.c-account__input--editable input {
+.c-account__input--editable input, .c-account__input--editable select {
border-color: transparent;
transition: border 0.5s;
}
-.c-account__input--editable.is-editable input {
+.c-account__input--editable.is-editable input, .c-account__input--editable.is-editable select {
border: 1px solid #e2e2e2;
}
@@ -5600,7 +5627,7 @@ table .c-btn--icon {
line-height: 1.5rem;
}
-a.c-acount__link {
+.c-acount__link {
color: #0085ca;
font-size: 0.875rem;
font-weight: 500;
@@ -5613,7 +5640,7 @@ a.c-acount__link {
.c-acount__buttons {
gap: 5px;
}
-@media all and (min-width: 320px) {
+@media all and (min-width: 374px) {
.c-acount__buttons {
gap: 10px;
}
@@ -5627,7 +5654,7 @@ a.c-acount__link {
.c-acount__button {
font-size: 0.6875rem;
}
-@media all and (min-width: 320px) {
+@media all and (min-width: 374px) {
.c-acount__button {
font-size: 0.875rem;
}
@@ -5639,6 +5666,265 @@ a.c-acount__link {
gap: 10px;
}
+.c-wishlist__table tr th {
+ white-space: nowrap;
+}
+.c-wishlist__table tbody {
+ margin-top: 1.5rem;
+}
+@media all and (min-width: 992px) {
+ .c-wishlist__table tbody {
+ margin-top: 1.875rem;
+ }
+}
+@media all and (min-width: 992px) {
+ .c-wishlist__table tbody {
+ margin-top: 0;
+ }
+}
+.c-wishlist__table tbody tr td:nth-child(1) {
+ order: 2;
+ margin-left: auto;
+ font-weight: 800;
+}
+@media all and (min-width: 992px) {
+ .c-wishlist__table tbody tr td:nth-child(1) {
+ order: 1;
+ margin-left: 0;
+ font-weight: 500;
+ }
+}
+.c-wishlist__table tbody tr td:nth-child(2) {
+ font-weight: 800;
+ order: 1;
+ margin-left: 0;
+ max-width: 90%;
+ margin-bottom: 0.5rem;
+}
+@media all and (min-width: 992px) {
+ .c-wishlist__table tbody tr td:nth-child(2) {
+ order: 2;
+ width: 100%;
+ margin-bottom: 0;
+ }
+}
+.c-wishlist__table tbody tr td:nth-child(3) {
+ order: 3;
+ margin-bottom: 0.875rem;
+}
+@media all and (min-width: 992px) {
+ .c-wishlist__table tbody tr td:nth-child(3) {
+ margin-bottom: 0;
+ }
+}
+.c-wishlist__table tbody tr td:nth-child(4) {
+ order: 4;
+}
+
+.c-table__filters__search--whishlist {
+ margin: 0 -1rem;
+}
+@media all and (min-width: 768px) {
+ .c-table__filters__search--whishlist {
+ margin: auto;
+ }
+}
+.c-table__filters__search--whishlist .c-table__filters__search {
+ text-align: left;
+}
+.c-table__filters__search--whishlist input {
+ width: 11.25rem;
+ margin-right: 0.3125rem;
+ font-size: 0.75rem;
+}
+@media all and (min-width: 374px) {
+ .c-table__filters__search--whishlist input {
+ width: 15.9375rem;
+ margin-right: 1rem;
+ font-size: 0.875rem;
+ }
+}
+@media all and (min-width: 992px) {
+ .c-table__filters__search--whishlist input {
+ width: 550px;
+ }
+}
+
+.c-whishlist__notice {
+ font-size: 0.875rem;
+ font-weight: 500;
+ line-height: 1.5rem;
+ display: inline-block;
+ padding-top: 30px;
+}
+@media all and (min-width: 768px) {
+ .c-whishlist__notice {
+ padding-top: 40px;
+ }
+}
+@media all and (min-width: 992px) {
+ .c-whishlist__notice {
+ padding-top: 60px;
+ }
+}
+
+.c-wishlist__btn {
+ font-size: 0.875rem;
+}
+
+.c-account--adresses input {
+ max-width: 550px;
+}
+.c-account--adresses .c-account__input-title {
+ gap: 40px;
+}
+.c-account--adresses .c-account__input-title input {
+ border-radius: 0;
+}
+.c-account--adresses .c-account__input-title.is-editable input {
+ border-color: transparent;
+ border-bottom-color: #E2E2E2;
+}
+.c-account--adresses .c-account__input-wrapper {
+ max-width: 100%;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+@media all and (min-width: 768px) {
+ .c-account--adresses .c-account__input-wrapper {
+ gap: 16px;
+ }
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input input {
+ width: 100%;
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input select {
+ cursor: pointer;
+ min-width: 62px;
+ width: fit-content;
+ background-position: right 0.6rem center;
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(1) {
+ width: 100%;
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(2) {
+ width: 88px;
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(3) {
+ width: 88px;
+}
+.c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(4) {
+ width: fit-content;
+}
+@media all and (min-width: 768px) {
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(1) {
+ width: 200px;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(2) {
+ width: 130px;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(3) {
+ width: 108px;
+ }
+}
+@media all and (min-width: 1120px) {
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(1) {
+ width: 100%;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(2) {
+ width: 88px;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(3) {
+ width: 88px;
+ }
+}
+@media all and (min-width: 1480px) {
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(1) {
+ width: 200px;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(2) {
+ width: 130px;
+ }
+ .c-account--adresses .c-account__input-wrapper .c-account__input:nth-child(3) {
+ width: 108px;
+ }
+}
+
+.pagy-nav .page.prev,
+.pagy-nav .page.prev a,
+.pagy-nav .page.next,
+.pagy-nav .page.next a {
+ width: 2rem;
+ height: 2rem;
+ border-radius: 1rem !important;
+ border: 1px solid #E2E2E2 !important;
+ display: flex !important;
+ justify-content: center;
+ align-items: center;
+ padding: 0 !important;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.5rem;
+ border: none !important;
+ padding: 0.25rem 0.25rem !important;
+ width: 5rem;
+}
+
+.pagy-nav .page.active {
+ width: 2rem;
+ height: 2rem;
+ border-radius: 1rem !important;
+ border: 1px solid #E2E2E2 !important;
+ display: flex !important;
+ justify-content: center;
+ align-items: center;
+ padding: 0 !important;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.5rem;
+ background-color: #48A23F !important;
+ border-color: #48A23F !important;
+ color: #FFFFFF !important;
+}
+
+.pagy-nav .page.gap {
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.pagy-nav .page a {
+ text-decoration: none;
+ color: black !important;
+ width: 2rem;
+ height: 2rem;
+ border-radius: 1rem !important;
+ border: 1px solid #E2E2E2 !important;
+ display: flex !important;
+ justify-content: center;
+ align-items: center;
+ padding: 0 !important;
+ font-weight: 500;
+ font-size: 0.875rem;
+ line-height: 1.5rem;
+}
+
+.pagy-nav .page a:hover {
+ color: #212224 !important;
+ background: #E2E2E2 !important;
+}
+
+.pagy-nav {
+ display: flex;
+ justify-content: center;
+ width: 100%;
+ margin-top: 3rem;
+ gap: 1.5rem;
+}
+.pagy-nav span {
+ display: flex;
+ gap: 0.5rem;
+}
+
.u-clear-both {
clear: both;
}
@@ -5857,6 +6143,10 @@ a.c-acount__link {
margin-top: 3rem;
}
+.u-mt-60 {
+ margin-top: 3.75rem;
+}
+
.u-mt-8 {
margin-top: 0.5rem;
}
@@ -5867,6 +6157,10 @@ a.c-acount__link {
}
}
+.u-mb-60 {
+ margin-bottom: 3.75rem;
+}
+
.u-mb-48 {
margin-bottom: 3rem;
}
diff --git a/app/assets/builds/application.js b/app/assets/builds/application.js
index 77d78be40..4b41a674c 100644
--- a/app/assets/builds/application.js
+++ b/app/assets/builds/application.js
@@ -655,10 +655,10 @@
});
// node_modules/@hotwired/turbo-rails/node_modules/@rails/actioncable/src/subscription.js
- var extend2, Subscription;
+ var extend, Subscription;
var init_subscription = __esm({
"node_modules/@hotwired/turbo-rails/node_modules/@rails/actioncable/src/subscription.js"() {
- extend2 = function(object, properties) {
+ extend = function(object, properties) {
if (properties != null) {
for (let key in properties) {
const value = properties[key];
@@ -671,7 +671,7 @@
constructor(consumer2, params = {}, mixin) {
this.consumer = consumer2;
this.identifier = JSON.stringify(params);
- extend2(this, mixin);
+ extend(this, mixin);
}
perform(action, data = {}) {
data.action = action;
@@ -901,7002 +901,7013 @@
}
});
- // node_modules/@hotwired/stimulus/dist/stimulus.js
- var EventListener = class {
- constructor(eventTarget, eventName, eventOptions) {
- this.eventTarget = eventTarget;
- this.eventName = eventName;
- this.eventOptions = eventOptions;
- this.unorderedBindings = /* @__PURE__ */ new Set();
+ // node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
+ (function() {
+ if (window.Reflect === void 0 || window.customElements === void 0 || window.customElements.polyfillWrapFlushCallback) {
+ return;
}
- connect() {
- this.eventTarget.addEventListener(this.eventName, this, this.eventOptions);
+ const BuiltInHTMLElement = HTMLElement;
+ const wrapperForTheName = {
+ HTMLElement: function HTMLElement2() {
+ return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
+ }
+ };
+ window.HTMLElement = wrapperForTheName["HTMLElement"];
+ HTMLElement.prototype = BuiltInHTMLElement.prototype;
+ HTMLElement.prototype.constructor = HTMLElement;
+ Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
+ })();
+ (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");
}
- disconnect() {
- this.eventTarget.removeEventListener(this.eventName, this, this.eventOptions);
+ function raise(errorConstructor, message, name) {
+ throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name);
}
- bindingConnected(binding) {
- this.unorderedBindings.add(binding);
+ })(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 === null || candidate === void 0 ? void 0 : candidate.type) == "submit" ? candidate : null;
+ }
+ function clickCaptured(event) {
+ const submitter = findSubmitterFromClickTarget(event.target);
+ if (submitter && submitter.form) {
+ submittersByForm.set(submitter.form, submitter);
}
- bindingDisconnected(binding) {
- this.unorderedBindings.delete(binding);
+ }
+ (function() {
+ if ("submitter" in Event.prototype)
+ return;
+ let prototype = window.Event.prototype;
+ if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
+ prototype = window.SubmitEvent.prototype;
+ } else if ("SubmitEvent" in window) {
+ return;
}
- handleEvent(event) {
- const extendedEvent = extendEvent(event);
- for (const binding of this.bindings) {
- if (extendedEvent.immediatePropagationStopped) {
- break;
- } else {
- binding.handleEvent(extendedEvent);
+ addEventListener("click", clickCaptured, true);
+ Object.defineProperty(prototype, "submitter", {
+ get() {
+ if (this.type == "submit" && this.target instanceof HTMLFormElement) {
+ return submittersByForm.get(this.target);
}
}
+ });
+ })();
+ var FrameLoadingStyle;
+ (function(FrameLoadingStyle2) {
+ FrameLoadingStyle2["eager"] = "eager";
+ FrameLoadingStyle2["lazy"] = "lazy";
+ })(FrameLoadingStyle || (FrameLoadingStyle = {}));
+ var FrameElement = class extends HTMLElement {
+ static get observedAttributes() {
+ return ["disabled", "complete", "loading", "src"];
}
- hasBindings() {
- return this.unorderedBindings.size > 0;
- }
- get bindings() {
- return Array.from(this.unorderedBindings).sort((left, right) => {
- const leftIndex = left.index, rightIndex = right.index;
- return leftIndex < rightIndex ? -1 : leftIndex > rightIndex ? 1 : 0;
- });
+ constructor() {
+ super();
+ this.loaded = Promise.resolve();
+ this.delegate = new FrameElement.delegateConstructor(this);
}
- };
- function extendEvent(event) {
- if ("immediatePropagationStopped" in event) {
- return event;
- } else {
- const { stopImmediatePropagation } = event;
- return Object.assign(event, {
- immediatePropagationStopped: false,
- stopImmediatePropagation() {
- this.immediatePropagationStopped = true;
- stopImmediatePropagation.call(this);
- }
- });
+ connectedCallback() {
+ this.delegate.connect();
}
- }
- var Dispatcher = class {
- constructor(application2) {
- this.application = application2;
- this.eventListenerMaps = /* @__PURE__ */ new Map();
- this.started = false;
+ disconnectedCallback() {
+ this.delegate.disconnect();
}
- start() {
- if (!this.started) {
- this.started = true;
- this.eventListeners.forEach((eventListener) => eventListener.connect());
- }
+ reload() {
+ return this.delegate.sourceURLReloaded();
}
- stop() {
- if (this.started) {
- this.started = false;
- this.eventListeners.forEach((eventListener) => eventListener.disconnect());
+ attributeChangedCallback(name) {
+ if (name == "loading") {
+ this.delegate.loadingStyleChanged();
+ } else if (name == "complete") {
+ this.delegate.completeChanged();
+ } else if (name == "src") {
+ this.delegate.sourceURLChanged();
+ } else {
+ this.delegate.disabledChanged();
}
}
- get eventListeners() {
- return Array.from(this.eventListenerMaps.values()).reduce((listeners, map) => listeners.concat(Array.from(map.values())), []);
- }
- bindingConnected(binding) {
- this.fetchEventListenerForBinding(binding).bindingConnected(binding);
- }
- bindingDisconnected(binding, clearEventListeners = false) {
- this.fetchEventListenerForBinding(binding).bindingDisconnected(binding);
- if (clearEventListeners)
- this.clearEventListenersForBinding(binding);
- }
- handleError(error2, message, detail = {}) {
- this.application.handleError(error2, `Error ${message}`, detail);
+ get src() {
+ return this.getAttribute("src");
}
- clearEventListenersForBinding(binding) {
- const eventListener = this.fetchEventListenerForBinding(binding);
- if (!eventListener.hasBindings()) {
- eventListener.disconnect();
- this.removeMappedEventListenerFor(binding);
+ set src(value) {
+ if (value) {
+ this.setAttribute("src", value);
+ } else {
+ this.removeAttribute("src");
}
}
- removeMappedEventListenerFor(binding) {
- const { eventTarget, eventName, eventOptions } = binding;
- const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);
- const cacheKey = this.cacheKey(eventName, eventOptions);
- eventListenerMap.delete(cacheKey);
- if (eventListenerMap.size == 0)
- this.eventListenerMaps.delete(eventTarget);
- }
- fetchEventListenerForBinding(binding) {
- const { eventTarget, eventName, eventOptions } = binding;
- return this.fetchEventListener(eventTarget, eventName, eventOptions);
+ get loading() {
+ return frameLoadingStyleFromString(this.getAttribute("loading") || "");
}
- fetchEventListener(eventTarget, eventName, eventOptions) {
- const eventListenerMap = this.fetchEventListenerMapForEventTarget(eventTarget);
- const cacheKey = this.cacheKey(eventName, eventOptions);
- let eventListener = eventListenerMap.get(cacheKey);
- if (!eventListener) {
- eventListener = this.createEventListener(eventTarget, eventName, eventOptions);
- eventListenerMap.set(cacheKey, eventListener);
+ set loading(value) {
+ if (value) {
+ this.setAttribute("loading", value);
+ } else {
+ this.removeAttribute("loading");
}
- return eventListener;
}
- createEventListener(eventTarget, eventName, eventOptions) {
- const eventListener = new EventListener(eventTarget, eventName, eventOptions);
- if (this.started) {
- eventListener.connect();
- }
- return eventListener;
+ get disabled() {
+ return this.hasAttribute("disabled");
}
- fetchEventListenerMapForEventTarget(eventTarget) {
- let eventListenerMap = this.eventListenerMaps.get(eventTarget);
- if (!eventListenerMap) {
- eventListenerMap = /* @__PURE__ */ new Map();
- this.eventListenerMaps.set(eventTarget, eventListenerMap);
+ set disabled(value) {
+ if (value) {
+ this.setAttribute("disabled", "");
+ } else {
+ this.removeAttribute("disabled");
}
- return eventListenerMap;
}
- cacheKey(eventName, eventOptions) {
- const parts = [eventName];
- Object.keys(eventOptions).sort().forEach((key) => {
- parts.push(`${eventOptions[key] ? "" : "!"}${key}`);
- });
- return parts.join(":");
+ get autoscroll() {
+ return this.hasAttribute("autoscroll");
}
- };
- var defaultActionDescriptorFilters = {
- stop({ event, value }) {
- if (value)
- event.stopPropagation();
- return true;
- },
- prevent({ event, value }) {
- if (value)
- event.preventDefault();
- return true;
- },
- self({ event, value, element }) {
+ set autoscroll(value) {
if (value) {
- return element === event.target;
+ this.setAttribute("autoscroll", "");
} else {
- return true;
+ this.removeAttribute("autoscroll");
}
}
+ get complete() {
+ return !this.delegate.isLoading;
+ }
+ get isActive() {
+ return this.ownerDocument === document && !this.isPreview;
+ }
+ get isPreview() {
+ var _a, _b;
+ return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
+ }
};
- var descriptorPattern = /^(?:(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;
- function parseActionDescriptorString(descriptorString) {
- const source = descriptorString.trim();
- const matches = source.match(descriptorPattern) || [];
- let eventName = matches[1];
- let keyFilter = matches[2];
- if (keyFilter && !["keydown", "keyup", "keypress"].includes(eventName)) {
- eventName += `.${keyFilter}`;
- keyFilter = "";
+ function frameLoadingStyleFromString(style) {
+ switch (style.toLowerCase()) {
+ case "lazy":
+ return FrameLoadingStyle.lazy;
+ default:
+ return FrameLoadingStyle.eager;
}
- return {
- eventTarget: parseEventTarget(matches[3]),
- eventName,
- eventOptions: matches[6] ? parseEventOptions(matches[6]) : {},
- identifier: matches[4],
- methodName: matches[5],
- keyFilter
- };
}
- function parseEventTarget(eventTargetName) {
- if (eventTargetName == "window") {
- return window;
- } else if (eventTargetName == "document") {
- return document;
+ 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 parseEventOptions(eventOptions) {
- return eventOptions.split(":").reduce((options, token) => Object.assign(options, { [token.replace(/^!/, "")]: !/^!/.test(token) }), {});
+ function getAction(form, submitter) {
+ const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formaction")) || form.getAttribute("action") || form.action;
+ return expandURL(action);
}
- function stringifyEventTarget(eventTarget) {
- if (eventTarget == window) {
- return "window";
- } else if (eventTarget == document) {
- return "document";
- }
+ function getExtension(url) {
+ return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
}
- function camelize(value) {
- return value.replace(/(?:[_-])([a-z0-9])/g, (_, char) => char.toUpperCase());
+ function isHTML(url) {
+ return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml|php))$/);
}
- function namespaceCamelize(value) {
- return camelize(value.replace(/--/g, "-").replace(/__/g, "_"));
+ function isPrefixedBy(baseURL, url) {
+ const prefix = getPrefix(url);
+ return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
}
- function capitalize(value) {
- return value.charAt(0).toUpperCase() + value.slice(1);
+ function locationIsVisitable(location2, rootLocation) {
+ return isPrefixedBy(location2, rootLocation) && isHTML(location2);
}
- function dasherize(value) {
- return value.replace(/([A-Z])/g, (_, char) => `-${char.toLowerCase()}`);
+ function getRequestURL(url) {
+ const anchor = getAnchor(url);
+ return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
}
- function tokenize(value) {
- return value.match(/[^\s]+/g) || [];
+ function toCacheKey(url) {
+ return getRequestURL(url);
}
- var Action = class {
- constructor(element, index, descriptor, schema) {
- this.element = element;
- this.index = index;
- this.eventTarget = descriptor.eventTarget || element;
- this.eventName = descriptor.eventName || getDefaultEventNameForElement(element) || error("missing event name");
- this.eventOptions = descriptor.eventOptions || {};
- this.identifier = descriptor.identifier || error("missing identifier");
- this.methodName = descriptor.methodName || error("missing method name");
- this.keyFilter = descriptor.keyFilter || "";
- this.schema = schema;
- }
- static forToken(token, schema) {
- return new this(token.element, token.index, parseActionDescriptorString(token.content), schema);
- }
- toString() {
- const eventFilter = this.keyFilter ? `.${this.keyFilter}` : "";
- const eventTarget = this.eventTargetName ? `@${this.eventTargetName}` : "";
- return `${this.eventName}${eventFilter}${eventTarget}->${this.identifier}#${this.methodName}`;
- }
- isFilterTarget(event) {
- if (!this.keyFilter) {
- return false;
- }
- const filteres = this.keyFilter.split("+");
- const modifiers = ["meta", "ctrl", "alt", "shift"];
- const [meta, ctrl, alt, shift] = modifiers.map((modifier) => filteres.includes(modifier));
- if (event.metaKey !== meta || event.ctrlKey !== ctrl || event.altKey !== alt || event.shiftKey !== shift) {
- return true;
- }
- const standardFilter = filteres.filter((key) => !modifiers.includes(key))[0];
- if (!standardFilter) {
- return false;
- }
- if (!Object.prototype.hasOwnProperty.call(this.keyMappings, standardFilter)) {
- error(`contains unknown key filter: ${this.keyFilter}`);
- }
- return this.keyMappings[standardFilter].toLowerCase() !== event.key.toLowerCase();
- }
- get params() {
- const params = {};
- const pattern = new RegExp(`^data-${this.identifier}-(.+)-param$`, "i");
- for (const { name, value } of Array.from(this.element.attributes)) {
- const match = name.match(pattern);
- const key = match && match[1];
- if (key) {
- params[camelize(key)] = typecast(value);
- }
- }
- return params;
- }
- get eventTargetName() {
- return stringifyEventTarget(this.eventTarget);
- }
- get keyMappings() {
- return this.schema.keyMappings;
- }
- };
- var defaultEventNames = {
- a: () => "click",
- button: () => "click",
- form: () => "submit",
- details: () => "toggle",
- input: (e) => e.getAttribute("type") == "submit" ? "click" : "input",
- select: () => "change",
- textarea: () => "input"
- };
- function getDefaultEventNameForElement(element) {
- const tagName = element.tagName.toLowerCase();
- if (tagName in defaultEventNames) {
- return defaultEventNames[tagName](element);
- }
+ function urlsAreEqual(left, right) {
+ return expandURL(left).href == expandURL(right).href;
}
- function error(message) {
- throw new Error(message);
+ function getPathComponents(url) {
+ return url.pathname.split("/").slice(1);
}
- function typecast(value) {
- try {
- return JSON.parse(value);
- } catch (o_O) {
- return value;
- }
+ function getLastPathComponent(url) {
+ return getPathComponents(url).slice(-1)[0];
}
- var Binding = class {
- constructor(context, action) {
- this.context = context;
- this.action = action;
+ 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 index() {
- return this.action.index;
+ get succeeded() {
+ return this.response.ok;
}
- get eventTarget() {
- return this.action.eventTarget;
+ get failed() {
+ return !this.succeeded;
}
- get eventOptions() {
- return this.action.eventOptions;
+ get clientError() {
+ return this.statusCode >= 400 && this.statusCode <= 499;
}
- get identifier() {
- return this.context.identifier;
+ get serverError() {
+ return this.statusCode >= 500 && this.statusCode <= 599;
}
- handleEvent(event) {
- if (this.willBeInvokedByEvent(event) && this.applyEventModifiers(event)) {
- this.invokeWithEvent(event);
- }
+ get redirected() {
+ return this.response.redirected;
}
- get eventName() {
- return this.action.eventName;
+ get location() {
+ return expandURL(this.response.url);
}
- get method() {
- const method = this.controller[this.methodName];
- if (typeof method == "function") {
- return method;
- }
- throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`);
+ get isHTML() {
+ return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
}
- applyEventModifiers(event) {
- const { element } = this.action;
- const { actionDescriptorFilters } = this.context.application;
- let passes = true;
- for (const [name, value] of Object.entries(this.eventOptions)) {
- if (name in actionDescriptorFilters) {
- const filter = actionDescriptorFilters[name];
- passes = passes && filter({ name, value, event, element });
- } else {
- continue;
- }
- }
- return passes;
+ get statusCode() {
+ return this.response.status;
}
- invokeWithEvent(event) {
- const { target, currentTarget } = event;
- try {
- const { params } = this.action;
- const actionEvent = Object.assign(event, { params });
- this.method.call(this.controller, actionEvent);
- this.context.logDebugActivity(this.methodName, { event, target, currentTarget, action: this.methodName });
- } catch (error2) {
- const { identifier, controller, element, index } = this;
- const detail = { identifier, controller, element, index, event };
- this.context.handleError(error2, `invoking action "${this.action}"`, detail);
- }
+ get contentType() {
+ return this.header("Content-Type");
}
- willBeInvokedByEvent(event) {
- const eventTarget = event.target;
- if (event instanceof KeyboardEvent && this.action.isFilterTarget(event)) {
- return false;
- }
- if (this.element === eventTarget) {
- return true;
- } else if (eventTarget instanceof Element && this.element.contains(eventTarget)) {
- return this.scope.containsElement(eventTarget);
+ get responseText() {
+ return this.response.clone().text();
+ }
+ get responseHTML() {
+ if (this.isHTML) {
+ return this.response.clone().text();
} else {
- return this.scope.containsElement(this.action.element);
+ return Promise.resolve(void 0);
}
}
- get controller() {
- return this.context.controller;
- }
- get methodName() {
- return this.action.methodName;
- }
- get element() {
- return this.scope.element;
- }
- get scope() {
- return this.context.scope;
+ header(name) {
+ return this.response.headers.get(name);
}
};
- var ElementObserver = class {
- constructor(element, delegate) {
- this.mutationObserverInit = { attributes: true, childList: true, subtree: true };
- this.element = element;
- this.started = false;
- this.delegate = delegate;
- this.elements = /* @__PURE__ */ new Set();
- this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));
- }
- start() {
- if (!this.started) {
- this.started = true;
- this.mutationObserver.observe(this.element, this.mutationObserverInit);
- this.refresh();
- }
- }
- pause(callback) {
- if (this.started) {
- this.mutationObserver.disconnect();
- this.started = false;
- }
- callback();
- if (!this.started) {
- this.mutationObserver.observe(this.element, this.mutationObserverInit);
- this.started = true;
- }
- }
- stop() {
- if (this.started) {
- this.mutationObserver.takeRecords();
- this.mutationObserver.disconnect();
- this.started = false;
+ 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;
}
- refresh() {
- if (this.started) {
- const matches = new Set(this.matchElementsInTree());
- for (const element of Array.from(this.elements)) {
- if (!matches.has(element)) {
- this.removeElement(element);
- }
- }
- for (const element of Array.from(matches)) {
- this.addElement(element);
- }
- }
+ }
+ function copyElementAttributes(destinationElement, sourceElement) {
+ for (const { name, value } of sourceElement.attributes) {
+ destinationElement.setAttribute(name, value);
}
- processMutations(mutations) {
- if (this.started) {
- for (const mutation of mutations) {
- this.processMutation(mutation);
- }
- }
+ }
+ 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);
}
- processMutation(mutation) {
- if (mutation.type == "attributes") {
- this.processAttributeChange(mutation.target, mutation.attributeName);
- } else if (mutation.type == "childList") {
- this.processRemovedNodes(mutation.removedNodes);
- this.processAddedNodes(mutation.addedNodes);
+ return event;
+ }
+ 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 === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
+ if (typeof value == "string")
+ return value;
}
- processAttributeChange(node, attributeName) {
- const element = node;
- if (this.elements.has(element)) {
- if (this.delegate.elementAttributeChanged && this.matchElement(element)) {
- this.delegate.elementAttributeChanged(element, attributeName);
- } else {
- this.removeElement(element);
- }
- } else if (this.matchElement(element)) {
- this.addElement(element);
+ 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");
}
- processRemovedNodes(nodes) {
- for (const node of Array.from(nodes)) {
- const element = this.elementFromNode(node);
- if (element) {
- this.processTree(element, this.removeElement);
- }
+ }
+ function clearBusyState(...elements) {
+ for (const element of elements) {
+ if (element.localName == "turbo-frame") {
+ element.removeAttribute("busy");
}
+ element.removeAttribute("aria-busy");
}
- processAddedNodes(nodes) {
- for (const node of Array.from(nodes)) {
- const element = this.elementFromNode(node);
- if (element && this.elementIsActive(element)) {
- this.processTree(element, this.addElement);
- }
- }
+ }
+ 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;
}
- matchElement(element) {
- return this.delegate.matchElement(element);
+ }
+ 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);
}
- matchElementsInTree(tree = this.element) {
- return this.delegate.matchElementsInTree(tree);
+ element.setAttribute("content", content);
+ return element;
+ }
+ function findClosestRecursively(element, selector) {
+ var _a;
+ if (element instanceof Element) {
+ return element.closest(selector) || findClosestRecursively(element.assignedSlot || ((_a = element.getRootNode()) === null || _a === void 0 ? void 0 : _a.host), selector);
}
- processTree(tree, processor) {
- for (const element of this.matchElementsInTree(tree)) {
- processor.call(this, element);
- }
+ }
+ var FetchMethod;
+ (function(FetchMethod2) {
+ FetchMethod2[FetchMethod2["get"] = 0] = "get";
+ FetchMethod2[FetchMethod2["post"] = 1] = "post";
+ FetchMethod2[FetchMethod2["put"] = 2] = "put";
+ FetchMethod2[FetchMethod2["patch"] = 3] = "patch";
+ FetchMethod2[FetchMethod2["delete"] = 4] = "delete";
+ })(FetchMethod || (FetchMethod = {}));
+ 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;
}
- elementFromNode(node) {
- if (node.nodeType == Node.ELEMENT_NODE) {
- return node;
- }
+ }
+ var FetchRequest = class {
+ constructor(delegate, method, location2, body = new URLSearchParams(), target = null) {
+ this.abortController = new AbortController();
+ this.resolveRequestPromise = (_value) => {
+ };
+ this.delegate = delegate;
+ this.method = method;
+ this.headers = this.defaultHeaders;
+ this.body = body;
+ this.url = location2;
+ this.target = target;
}
- elementIsActive(element) {
- if (element.isConnected != this.element.isConnected) {
- return false;
- } else {
- return this.element.contains(element);
- }
+ get location() {
+ return this.url;
}
- addElement(element) {
- if (!this.elements.has(element)) {
- if (this.elementIsActive(element)) {
- this.elements.add(element);
- if (this.delegate.elementMatched) {
- this.delegate.elementMatched(element);
+ 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);
+ await this.allowRequestToBeIntercepted(fetchOptions);
+ try {
+ this.delegate.requestStarted(this);
+ const response = await fetch(this.url.href, fetchOptions);
+ 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);
}
}
- removeElement(element) {
- if (this.elements.has(element)) {
- this.elements.delete(element);
- if (this.delegate.elementUnmatched) {
- this.delegate.elementUnmatched(element);
- }
+ 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;
}
- };
- var AttributeObserver = class {
- constructor(element, attributeName, delegate) {
- this.attributeName = attributeName;
- this.delegate = delegate;
- this.elementObserver = new ElementObserver(element, this);
- }
- get element() {
- return this.elementObserver.element;
- }
- get selector() {
- return `[${this.attributeName}]`;
+ get fetchOptions() {
+ var _a;
+ return {
+ method: FetchMethod[this.method].toUpperCase(),
+ credentials: "same-origin",
+ headers: this.headers,
+ redirect: "follow",
+ body: this.isSafe ? null : this.body,
+ signal: this.abortSignal,
+ referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
+ };
}
- start() {
- this.elementObserver.start();
+ get defaultHeaders() {
+ return {
+ Accept: "text/html, application/xhtml+xml"
+ };
}
- pause(callback) {
- this.elementObserver.pause(callback);
+ get isSafe() {
+ return this.method === FetchMethod.get;
}
- stop() {
- this.elementObserver.stop();
+ get abortSignal() {
+ return this.abortController.signal;
}
- refresh() {
- this.elementObserver.refresh();
+ acceptResponseType(mimeType) {
+ this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
}
- get started() {
- return this.elementObserver.started;
+ 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
+ });
+ if (event.defaultPrevented)
+ await requestInterception;
}
- matchElement(element) {
- return element.hasAttribute(this.attributeName);
+ willDelegateErrorHandling(error2) {
+ const event = dispatch("turbo:fetch-request-error", {
+ target: this.target,
+ cancelable: true,
+ detail: { request: this, error: error2 }
+ });
+ return !event.defaultPrevented;
}
- matchElementsInTree(tree) {
- const match = this.matchElement(tree) ? [tree] : [];
- const matches = Array.from(tree.querySelectorAll(this.selector));
- return match.concat(matches);
+ };
+ var AppearanceObserver = class {
+ constructor(delegate, element) {
+ this.started = false;
+ this.intersect = (entries) => {
+ const lastEntry = entries.slice(-1)[0];
+ if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
+ this.delegate.elementAppearedInViewport(this.element);
+ }
+ };
+ this.delegate = delegate;
+ this.element = element;
+ this.intersectionObserver = new IntersectionObserver(this.intersect);
}
- elementMatched(element) {
- if (this.delegate.elementMatchedAttribute) {
- this.delegate.elementMatchedAttribute(element, this.attributeName);
+ start() {
+ if (!this.started) {
+ this.started = true;
+ this.intersectionObserver.observe(this.element);
}
}
- elementUnmatched(element) {
- if (this.delegate.elementUnmatchedAttribute) {
- this.delegate.elementUnmatchedAttribute(element, this.attributeName);
+ stop() {
+ if (this.started) {
+ this.started = false;
+ this.intersectionObserver.unobserve(this.element);
}
}
- elementAttributeChanged(element, attributeName) {
- if (this.delegate.elementAttributeValueChanged && this.attributeName == attributeName) {
- this.delegate.elementAttributeValueChanged(element, attributeName);
+ };
+ var StreamMessage = class {
+ static wrap(message) {
+ if (typeof message == "string") {
+ return new this(createDocumentFragment(message));
+ } else {
+ return message;
}
}
+ constructor(fragment) {
+ this.fragment = importStreamElements(fragment);
+ }
};
- function add(map, key, value) {
- fetch2(map, key).add(value);
- }
- function del(map, key, value) {
- fetch2(map, key).delete(value);
- prune(map, key);
- }
- function fetch2(map, key) {
- let values = map.get(key);
- if (!values) {
- values = /* @__PURE__ */ new Set();
- map.set(key, values);
+ StreamMessage.contentType = "text/vnd.turbo-stream.html";
+ 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 values;
+ return fragment;
}
- function prune(map, key) {
- const values = map.get(key);
- if (values != null && values.size == 0) {
- map.delete(key);
+ var FormSubmissionState;
+ (function(FormSubmissionState2) {
+ FormSubmissionState2[FormSubmissionState2["initialized"] = 0] = "initialized";
+ FormSubmissionState2[FormSubmissionState2["requesting"] = 1] = "requesting";
+ FormSubmissionState2[FormSubmissionState2["waiting"] = 2] = "waiting";
+ FormSubmissionState2[FormSubmissionState2["receiving"] = 3] = "receiving";
+ FormSubmissionState2[FormSubmissionState2["stopping"] = 4] = "stopping";
+ FormSubmissionState2[FormSubmissionState2["stopped"] = 5] = "stopped";
+ })(FormSubmissionState || (FormSubmissionState = {}));
+ var FormEnctype;
+ (function(FormEnctype2) {
+ FormEnctype2["urlEncoded"] = "application/x-www-form-urlencoded";
+ FormEnctype2["multipart"] = "multipart/form-data";
+ FormEnctype2["plain"] = "text/plain";
+ })(FormEnctype || (FormEnctype = {}));
+ function formEnctypeFromString(encoding) {
+ switch (encoding.toLowerCase()) {
+ case FormEnctype.multipart:
+ return FormEnctype.multipart;
+ case FormEnctype.plain:
+ return FormEnctype.plain;
+ default:
+ return FormEnctype.urlEncoded;
}
}
- var Multimap = class {
- constructor() {
- this.valuesByKey = /* @__PURE__ */ new Map();
+ var FormSubmission = class {
+ static confirmMethod(message, _element, _submitter) {
+ return Promise.resolve(confirm(message));
}
- get keys() {
- return Array.from(this.valuesByKey.keys());
+ constructor(delegate, formElement, submitter, mustRedirect = false) {
+ this.state = FormSubmissionState.initialized;
+ this.delegate = delegate;
+ this.formElement = formElement;
+ this.submitter = submitter;
+ this.formData = buildFormData(formElement, submitter);
+ this.location = expandURL(this.action);
+ if (this.method == FetchMethod.get) {
+ mergeFormDataEntries(this.location, [...this.body.entries()]);
+ }
+ this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
+ this.mustRedirect = mustRedirect;
}
- get values() {
- const sets = Array.from(this.valuesByKey.values());
- return sets.reduce((values, set) => values.concat(Array.from(set)), []);
+ get method() {
+ var _a;
+ const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
+ return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
}
- get size() {
- const sets = Array.from(this.valuesByKey.values());
- return sets.reduce((size, set) => size + set.size, 0);
+ get action() {
+ var _a;
+ const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
+ if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
+ return this.submitter.getAttribute("formaction") || "";
+ } else {
+ return this.formElement.getAttribute("action") || formElementAction || "";
+ }
}
- add(key, value) {
- add(this.valuesByKey, key, value);
+ get body() {
+ if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
+ return new URLSearchParams(this.stringFormData);
+ } else {
+ return this.formData;
+ }
}
- delete(key, value) {
- del(this.valuesByKey, key, value);
+ get enctype() {
+ var _a;
+ return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
}
- has(key, value) {
- const values = this.valuesByKey.get(key);
- return values != null && values.has(value);
+ get isSafe() {
+ return this.fetchRequest.isSafe;
}
- hasKey(key) {
- return this.valuesByKey.has(key);
+ get stringFormData() {
+ return [...this.formData].reduce((entries, [name, value]) => {
+ return entries.concat(typeof value == "string" ? [[name, value]] : []);
+ }, []);
}
- hasValue(value) {
- const sets = Array.from(this.valuesByKey.values());
- return sets.some((set) => set.has(value));
+ 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();
+ }
}
- getValuesForKey(key) {
- const values = this.valuesByKey.get(key);
- return values ? Array.from(values) : [];
+ stop() {
+ const { stopping, stopped } = FormSubmissionState;
+ if (this.state != stopping && this.state != stopped) {
+ this.state = stopping;
+ this.fetchRequest.cancel();
+ return true;
+ }
}
- getKeysForValue(value) {
- return Array.from(this.valuesByKey).filter(([_key, values]) => values.has(value)).map(([key, _values]) => key);
+ 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);
+ }
}
- };
- var SelectorObserver = class {
- constructor(element, selector, delegate, details = {}) {
- this.selector = selector;
- this.details = details;
- this.elementObserver = new ElementObserver(element, this);
- this.delegate = delegate;
- this.matchesByElement = new Multimap();
+ requestStarted(_request) {
+ var _a;
+ this.state = FormSubmissionState.waiting;
+ (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
+ this.setSubmitsWith();
+ dispatch("turbo:submit-start", {
+ target: this.formElement,
+ detail: { formSubmission: this }
+ });
+ this.delegate.formSubmissionStarted(this);
}
- get started() {
- return this.elementObserver.started;
+ requestPreventedHandlingResponse(request, response) {
+ this.result = { success: response.succeeded, fetchResponse: response };
}
- start() {
- this.elementObserver.start();
+ requestSucceededWithResponse(request, response) {
+ if (response.clientError || response.serverError) {
+ this.delegate.formSubmissionFailedWithResponse(this, response);
+ } else 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);
+ }
}
- pause(callback) {
- this.elementObserver.pause(callback);
+ requestFailedWithResponse(request, response) {
+ this.result = { success: false, fetchResponse: response };
+ this.delegate.formSubmissionFailedWithResponse(this, response);
}
- stop() {
- this.elementObserver.stop();
+ requestErrored(request, error2) {
+ this.result = { success: false, error: error2 };
+ this.delegate.formSubmissionErrored(this, error2);
}
- refresh() {
- this.elementObserver.refresh();
+ requestFinished(_request) {
+ var _a;
+ this.state = FormSubmissionState.stopped;
+ (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
+ this.resetSubmitterText();
+ dispatch("turbo:submit-end", {
+ target: this.formElement,
+ detail: Object.assign({ formSubmission: this }, this.result)
+ });
+ this.delegate.formSubmissionFinished(this);
}
- get element() {
- return this.elementObserver.element;
+ 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;
+ }
}
- matchElement(element) {
- const matches = element.matches(this.selector);
- if (this.delegate.selectorMatchElement) {
- return matches && this.delegate.selectorMatchElement(element, this.details);
+ 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;
}
- return matches;
}
- matchElementsInTree(tree) {
- const match = this.matchElement(tree) ? [tree] : [];
- const matches = Array.from(tree.querySelectorAll(this.selector)).filter((match2) => this.matchElement(match2));
- return match.concat(matches);
+ requestMustRedirect(request) {
+ return !request.isSafe && this.mustRedirect;
}
- elementMatched(element) {
- this.selectorMatched(element);
+ requestAcceptsTurboStreamResponse(request) {
+ return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
}
- elementUnmatched(element) {
- this.selectorUnmatched(element);
+ get submitsWith() {
+ var _a;
+ return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-submits-with");
}
- elementAttributeChanged(element, _attributeName) {
- const matches = this.matchElement(element);
- const matchedBefore = this.matchesByElement.has(this.selector, element);
- if (!matches && matchedBefore) {
- this.selectorUnmatched(element);
- }
+ };
+ function buildFormData(formElement, submitter) {
+ const formData = new FormData(formElement);
+ const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
+ const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
+ if (name) {
+ formData.append(name, value || "");
}
- selectorMatched(element) {
- if (this.delegate.selectorMatched) {
- this.delegate.selectorMatched(element, this.selector, this.details);
- this.matchesByElement.add(this.selector, element);
+ 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;
}
}
- selectorUnmatched(element) {
- this.delegate.selectorUnmatched(element, this.selector, this.details);
- this.matchesByElement.delete(this.selector, element);
+ }
+ function responseSucceededWithoutRedirect(response) {
+ return response.statusCode == 200 && !response.redirected;
+ }
+ function mergeFormDataEntries(url, entries) {
+ const searchParams = new URLSearchParams();
+ for (const [name, value] of entries) {
+ if (value instanceof File)
+ continue;
+ searchParams.append(name, value);
}
- };
- var StringMapObserver = class {
- constructor(element, delegate) {
+ url.search = searchParams.toString();
+ return url;
+ }
+ var Snapshot = class {
+ constructor(element) {
this.element = element;
- this.delegate = delegate;
- this.started = false;
- this.stringMap = /* @__PURE__ */ new Map();
- this.mutationObserver = new MutationObserver((mutations) => this.processMutations(mutations));
}
- start() {
- if (!this.started) {
- this.started = true;
- this.mutationObserver.observe(this.element, { attributes: true, attributeOldValue: true });
- this.refresh();
- }
+ get activeElement() {
+ return this.element.ownerDocument.activeElement;
}
- stop() {
- if (this.started) {
- this.mutationObserver.takeRecords();
- this.mutationObserver.disconnect();
- this.started = false;
- }
+ get children() {
+ return [...this.element.children];
}
- refresh() {
- if (this.started) {
- for (const attributeName of this.knownAttributeNames) {
- this.refreshAttribute(attributeName, null);
- }
- }
+ hasAnchor(anchor) {
+ return this.getElementForAnchor(anchor) != null;
}
- processMutations(mutations) {
- if (this.started) {
- for (const mutation of mutations) {
- this.processMutation(mutation);
- }
- }
+ getElementForAnchor(anchor) {
+ return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;
}
- processMutation(mutation) {
- const attributeName = mutation.attributeName;
- if (attributeName) {
- this.refreshAttribute(attributeName, mutation.oldValue);
- }
+ get isConnected() {
+ return this.element.isConnected;
}
- refreshAttribute(attributeName, oldValue) {
- const key = this.delegate.getStringMapKeyForAttribute(attributeName);
- if (key != null) {
- if (!this.stringMap.has(attributeName)) {
- this.stringMapKeyAdded(key, attributeName);
- }
- const value = this.element.getAttribute(attributeName);
- if (this.stringMap.get(attributeName) != value) {
- this.stringMapValueChanged(value, key, oldValue);
- }
- if (value == null) {
- const oldValue2 = this.stringMap.get(attributeName);
- this.stringMap.delete(attributeName);
- if (oldValue2)
- this.stringMapKeyRemoved(key, attributeName, oldValue2);
- } else {
- this.stringMap.set(attributeName, value);
- }
+ get firstAutofocusableElement() {
+ const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
+ for (const element of this.element.querySelectorAll("[autofocus]")) {
+ if (element.closest(inertDisabledOrHidden) == null)
+ return element;
+ else
+ continue;
}
+ return null;
}
- stringMapKeyAdded(key, attributeName) {
- if (this.delegate.stringMapKeyAdded) {
- this.delegate.stringMapKeyAdded(key, attributeName);
- }
+ get permanentElements() {
+ return queryPermanentElementsAll(this.element);
}
- stringMapValueChanged(value, key, oldValue) {
- if (this.delegate.stringMapValueChanged) {
- this.delegate.stringMapValueChanged(value, key, oldValue);
- }
+ getPermanentElementById(id) {
+ return getPermanentElementById(this.element, id);
}
- stringMapKeyRemoved(key, attributeName, oldValue) {
- if (this.delegate.stringMapKeyRemoved) {
- this.delegate.stringMapKeyRemoved(key, attributeName, oldValue);
+ getPermanentElementMapForSnapshot(snapshot) {
+ const permanentElementMap = {};
+ for (const currentPermanentElement of this.permanentElements) {
+ const { id } = currentPermanentElement;
+ const newPermanentElement = snapshot.getPermanentElementById(id);
+ if (newPermanentElement) {
+ permanentElementMap[id] = [currentPermanentElement, newPermanentElement];
+ }
}
- }
- get knownAttributeNames() {
- return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)));
- }
- get currentAttributeNames() {
- return Array.from(this.element.attributes).map((attribute) => attribute.name);
- }
- get recordedAttributeNames() {
- return Array.from(this.stringMap.keys());
+ return permanentElementMap;
}
};
- var TokenListObserver = class {
- constructor(element, attributeName, delegate) {
- this.attributeObserver = new AttributeObserver(element, attributeName, this);
+ function getPermanentElementById(node, id) {
+ return node.querySelector(`#${id}[data-turbo-permanent]`);
+ }
+ function queryPermanentElementsAll(node) {
+ return node.querySelectorAll("[id][data-turbo-permanent]");
+ }
+ var FormSubmitObserver = class {
+ constructor(delegate, eventTarget) {
+ this.started = false;
+ this.submitCaptured = () => {
+ this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
+ this.eventTarget.addEventListener("submit", this.submitBubbled, false);
+ };
+ this.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);
+ }
+ }
+ };
this.delegate = delegate;
- this.tokensByElement = new Multimap();
- }
- get started() {
- return this.attributeObserver.started;
+ this.eventTarget = eventTarget;
}
start() {
- this.attributeObserver.start();
- }
- pause(callback) {
- this.attributeObserver.pause(callback);
+ if (!this.started) {
+ this.eventTarget.addEventListener("submit", this.submitCaptured, true);
+ this.started = true;
+ }
}
stop() {
- this.attributeObserver.stop();
- }
- refresh() {
- this.attributeObserver.refresh();
+ if (this.started) {
+ this.eventTarget.removeEventListener("submit", this.submitCaptured, true);
+ this.started = false;
+ }
}
- get element() {
- return this.attributeObserver.element;
+ };
+ function submissionDoesNotDismissDialog(form, submitter) {
+ const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
+ return method != "dialog";
+ }
+ function submissionDoesNotTargetIFrame(form, submitter) {
+ if ((submitter === null || submitter === void 0 ? void 0 : submitter.hasAttribute("formtarget")) || form.hasAttribute("target")) {
+ const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
+ for (const element of document.getElementsByName(target)) {
+ if (element instanceof HTMLIFrameElement)
+ return false;
+ }
+ return true;
+ } else {
+ return true;
}
- get attributeName() {
- return this.attributeObserver.attributeName;
+ }
+ var View = class {
+ constructor(delegate, element) {
+ this.resolveRenderPromise = (_value) => {
+ };
+ this.resolveInterceptionPromise = (_value) => {
+ };
+ this.delegate = delegate;
+ this.element = element;
}
- elementMatchedAttribute(element) {
- this.tokensMatched(this.readTokensForElement(element));
+ scrollToAnchor(anchor) {
+ const element = this.snapshot.getElementForAnchor(anchor);
+ if (element) {
+ this.scrollToElement(element);
+ this.focusElement(element);
+ } else {
+ this.scrollToPosition({ x: 0, y: 0 });
+ }
}
- elementAttributeValueChanged(element) {
- const [unmatchedTokens, matchedTokens] = this.refreshTokensForElement(element);
- this.tokensUnmatched(unmatchedTokens);
- this.tokensMatched(matchedTokens);
+ scrollToAnchorFromLocation(location2) {
+ this.scrollToAnchor(getAnchor(location2));
}
- elementUnmatchedAttribute(element) {
- this.tokensUnmatched(this.tokensByElement.getValuesForKey(element));
+ scrollToElement(element) {
+ element.scrollIntoView();
}
- tokensMatched(tokens) {
- tokens.forEach((token) => this.tokenMatched(token));
+ focusElement(element) {
+ if (element instanceof HTMLElement) {
+ if (element.hasAttribute("tabindex")) {
+ element.focus();
+ } else {
+ element.setAttribute("tabindex", "-1");
+ element.focus();
+ element.removeAttribute("tabindex");
+ }
+ }
}
- tokensUnmatched(tokens) {
- tokens.forEach((token) => this.tokenUnmatched(token));
+ scrollToPosition({ x, y }) {
+ this.scrollRoot.scrollTo(x, y);
}
- tokenMatched(token) {
- this.delegate.tokenMatched(token);
- this.tokensByElement.add(token.element, token);
+ scrollToTop() {
+ this.scrollToPosition({ x: 0, y: 0 });
}
- tokenUnmatched(token) {
- this.delegate.tokenUnmatched(token);
- this.tokensByElement.delete(token.element, token);
+ get scrollRoot() {
+ return window;
}
- refreshTokensForElement(element) {
- const previousTokens = this.tokensByElement.getValuesForKey(element);
- const currentTokens = this.readTokensForElement(element);
- const firstDifferingIndex = zip(previousTokens, currentTokens).findIndex(([previousToken, currentToken]) => !tokensAreEqual(previousToken, currentToken));
- if (firstDifferingIndex == -1) {
- return [[], []];
+ async render(renderer) {
+ const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
+ 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 };
+ const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
+ if (!immediateRender)
+ await renderInterception;
+ await this.renderSnapshot(renderer);
+ this.delegate.viewRenderedSnapshot(snapshot, isPreview);
+ this.delegate.preloadOnLoadLinksForView(this.element);
+ this.finishRenderingSnapshot(renderer);
+ } finally {
+ delete this.renderer;
+ this.resolveRenderPromise(void 0);
+ delete this.renderPromise;
+ }
} else {
- return [previousTokens.slice(firstDifferingIndex), currentTokens.slice(firstDifferingIndex)];
+ this.invalidate(renderer.reloadReason);
}
}
- readTokensForElement(element) {
- const attributeName = this.attributeName;
- const tokenString = element.getAttribute(attributeName) || "";
- return parseTokenString(tokenString, element, attributeName);
+ invalidate(reason) {
+ this.delegate.viewInvalidated(reason);
}
- };
- function parseTokenString(tokenString, element, attributeName) {
- return tokenString.trim().split(/\s+/).filter((content) => content.length).map((content, index) => ({ element, attributeName, content, index }));
- }
- function zip(left, right) {
- const length = Math.max(left.length, right.length);
- return Array.from({ length }, (_, index) => [left[index], right[index]]);
- }
- function tokensAreEqual(left, right) {
- return left && right && left.index == right.index && left.content == right.content;
- }
- var ValueListObserver = class {
- constructor(element, attributeName, delegate) {
- this.tokenListObserver = new TokenListObserver(element, attributeName, this);
- this.delegate = delegate;
- this.parseResultsByToken = /* @__PURE__ */ new WeakMap();
- this.valuesByTokenByElement = /* @__PURE__ */ new WeakMap();
+ async prepareToRenderSnapshot(renderer) {
+ this.markAsPreview(renderer.isPreview);
+ await renderer.prepareToRender();
}
- get started() {
- return this.tokenListObserver.started;
+ markAsPreview(isPreview) {
+ if (isPreview) {
+ this.element.setAttribute("data-turbo-preview", "");
+ } else {
+ this.element.removeAttribute("data-turbo-preview");
+ }
}
- start() {
- this.tokenListObserver.start();
+ async renderSnapshot(renderer) {
+ await renderer.render();
}
- stop() {
- this.tokenListObserver.stop();
+ finishRenderingSnapshot(renderer) {
+ renderer.finishRendering();
}
- refresh() {
- this.tokenListObserver.refresh();
- }
- get element() {
- return this.tokenListObserver.element;
- }
- get attributeName() {
- return this.tokenListObserver.attributeName;
+ };
+ var FrameView = class extends View {
+ missing() {
+ this.element.innerHTML = `Content missing`;
}
- tokenMatched(token) {
- const { element } = token;
- const { value } = this.fetchParseResultForToken(token);
- if (value) {
- this.fetchValuesByTokenForElement(element).set(token, value);
- this.delegate.elementMatchedValue(element, value);
- }
+ get snapshot() {
+ return new Snapshot(this.element);
}
- tokenUnmatched(token) {
- const { element } = token;
- const { value } = this.fetchParseResultForToken(token);
- if (value) {
- this.fetchValuesByTokenForElement(element).delete(token);
- this.delegate.elementUnmatchedValue(element, value);
- }
+ };
+ var LinkInterceptor = class {
+ constructor(delegate, element) {
+ this.clickBubbled = (event) => {
+ if (this.respondsToEventTarget(event.target)) {
+ this.clickEvent = event;
+ } else {
+ delete this.clickEvent;
+ }
+ };
+ this.linkClicked = (event) => {
+ if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
+ 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;
+ };
+ this.willVisit = (_event) => {
+ delete this.clickEvent;
+ };
+ this.delegate = delegate;
+ this.element = element;
}
- fetchParseResultForToken(token) {
- let parseResult = this.parseResultsByToken.get(token);
- if (!parseResult) {
- parseResult = this.parseToken(token);
- this.parseResultsByToken.set(token, parseResult);
- }
- return parseResult;
+ start() {
+ this.element.addEventListener("click", this.clickBubbled);
+ document.addEventListener("turbo:click", this.linkClicked);
+ document.addEventListener("turbo:before-visit", this.willVisit);
}
- fetchValuesByTokenForElement(element) {
- let valuesByToken = this.valuesByTokenByElement.get(element);
- if (!valuesByToken) {
- valuesByToken = /* @__PURE__ */ new Map();
- this.valuesByTokenByElement.set(element, valuesByToken);
- }
- return valuesByToken;
+ stop() {
+ this.element.removeEventListener("click", this.clickBubbled);
+ document.removeEventListener("turbo:click", this.linkClicked);
+ document.removeEventListener("turbo:before-visit", this.willVisit);
}
- parseToken(token) {
- try {
- const value = this.delegate.parseValueForToken(token);
- return { value };
- } catch (error2) {
- return { error: error2 };
- }
+ respondsToEventTarget(target) {
+ const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
+ return element && element.closest("turbo-frame, html") == this.element;
}
};
- var BindingObserver = class {
- constructor(context, delegate) {
- this.context = context;
+ var LinkClickObserver = class {
+ constructor(delegate, eventTarget) {
+ this.started = false;
+ this.clickCaptured = () => {
+ this.eventTarget.removeEventListener("click", this.clickBubbled, false);
+ this.eventTarget.addEventListener("click", this.clickBubbled, false);
+ };
+ this.clickBubbled = (event) => {
+ if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
+ const target = event.composedPath && event.composedPath()[0] || event.target;
+ const link = this.findLinkFromClickTarget(target);
+ if (link && doesNotTargetIFrame(link)) {
+ const location2 = this.getLocationForLink(link);
+ if (this.delegate.willFollowLinkToLocation(link, location2, event)) {
+ event.preventDefault();
+ this.delegate.followedLinkToLocation(link, location2);
+ }
+ }
+ }
+ };
this.delegate = delegate;
- this.bindingsByAction = /* @__PURE__ */ new Map();
+ this.eventTarget = eventTarget;
}
start() {
- if (!this.valueListObserver) {
- this.valueListObserver = new ValueListObserver(this.element, this.actionAttribute, this);
- this.valueListObserver.start();
+ if (!this.started) {
+ this.eventTarget.addEventListener("click", this.clickCaptured, true);
+ this.started = true;
}
}
stop() {
- if (this.valueListObserver) {
- this.valueListObserver.stop();
- delete this.valueListObserver;
- this.disconnectAllActions();
+ if (this.started) {
+ this.eventTarget.removeEventListener("click", this.clickCaptured, true);
+ this.started = false;
}
}
- get element() {
- return this.context.element;
+ clickEventIsSignificant(event) {
+ return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey);
}
- get identifier() {
- return this.context.identifier;
+ findLinkFromClickTarget(target) {
+ return findClosestRecursively(target, "a[href]:not([target^=_]):not([download])");
}
- get actionAttribute() {
- return this.schema.actionAttribute;
+ getLocationForLink(link) {
+ return expandURL(link.getAttribute("href") || "");
}
- get schema() {
- return this.context.schema;
+ };
+ function doesNotTargetIFrame(anchor) {
+ if (anchor.hasAttribute("target")) {
+ for (const element of document.getElementsByName(anchor.target)) {
+ if (element instanceof HTMLIFrameElement)
+ return false;
+ }
+ return true;
+ } else {
+ return true;
}
- get bindings() {
- return Array.from(this.bindingsByAction.values());
+ }
+ var FormLinkClickObserver = class {
+ constructor(delegate, element) {
+ this.delegate = delegate;
+ this.linkInterceptor = new LinkClickObserver(this, element);
}
- connectAction(action) {
- const binding = new Binding(this.context, action);
- this.bindingsByAction.set(action, binding);
- this.delegate.bindingConnected(binding);
+ start() {
+ this.linkInterceptor.start();
}
- disconnectAction(action) {
- const binding = this.bindingsByAction.get(action);
- if (binding) {
- this.bindingsByAction.delete(action);
- this.delegate.bindingDisconnected(binding);
- }
+ stop() {
+ this.linkInterceptor.stop();
}
- disconnectAllActions() {
- this.bindings.forEach((binding) => this.delegate.bindingDisconnected(binding, true));
- this.bindingsByAction.clear();
+ willFollowLinkToLocation(link, location2, originalEvent) {
+ return this.delegate.willSubmitFormLinkToLocation(link, location2, originalEvent) && link.hasAttribute("data-turbo-method");
}
- parseValueForToken(token) {
- const action = Action.forToken(token, this.schema);
- if (action.identifier == this.identifier) {
- return action;
+ 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 }));
}
- }
- elementMatchedValue(element, action) {
- this.connectAction(action);
- }
- elementUnmatchedValue(element, action) {
- this.disconnectAction(action);
+ 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 ValueObserver = class {
- constructor(context, receiver) {
- this.context = context;
- this.receiver = receiver;
- this.stringMapObserver = new StringMapObserver(this.element, this);
- this.valueDescriptorMap = this.controller.valueDescriptorMap;
- }
- start() {
- this.stringMapObserver.start();
- this.invokeChangedCallbacksForDefaultValues();
- }
- stop() {
- this.stringMapObserver.stop();
- }
- get element() {
- return this.context.element;
+ var Bardo = class {
+ static async preservingPermanentElements(delegate, permanentElementMap, callback) {
+ const bardo = new this(delegate, permanentElementMap);
+ bardo.enter();
+ await callback();
+ bardo.leave();
}
- get controller() {
- return this.context.controller;
+ constructor(delegate, permanentElementMap) {
+ this.delegate = delegate;
+ this.permanentElementMap = permanentElementMap;
}
- getStringMapKeyForAttribute(attributeName) {
- if (attributeName in this.valueDescriptorMap) {
- return this.valueDescriptorMap[attributeName].name;
+ enter() {
+ for (const id in this.permanentElementMap) {
+ const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
+ this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);
+ this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);
}
}
- stringMapKeyAdded(key, attributeName) {
- const descriptor = this.valueDescriptorMap[attributeName];
- if (!this.hasValue(key)) {
- this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), descriptor.writer(descriptor.defaultValue));
+ leave() {
+ for (const id in this.permanentElementMap) {
+ const [currentPermanentElement] = this.permanentElementMap[id];
+ this.replaceCurrentPermanentElementWithClone(currentPermanentElement);
+ this.replacePlaceholderWithPermanentElement(currentPermanentElement);
+ this.delegate.leavingBardo(currentPermanentElement);
}
}
- stringMapValueChanged(value, name, oldValue) {
- const descriptor = this.valueDescriptorNameMap[name];
- if (value === null)
- return;
- if (oldValue === null) {
- oldValue = descriptor.writer(descriptor.defaultValue);
- }
- this.invokeChangedCallback(name, value, oldValue);
- }
- stringMapKeyRemoved(key, attributeName, oldValue) {
- const descriptor = this.valueDescriptorNameMap[key];
- if (this.hasValue(key)) {
- this.invokeChangedCallback(key, descriptor.writer(this.receiver[key]), oldValue);
- } else {
- this.invokeChangedCallback(key, descriptor.writer(descriptor.defaultValue), oldValue);
- }
- }
- invokeChangedCallbacksForDefaultValues() {
- for (const { key, name, defaultValue, writer } of this.valueDescriptors) {
- if (defaultValue != void 0 && !this.controller.data.has(key)) {
- this.invokeChangedCallback(name, writer(defaultValue), void 0);
- }
- }
+ replaceNewPermanentElementWithPlaceholder(permanentElement) {
+ const placeholder = createPlaceholderForPermanentElement(permanentElement);
+ permanentElement.replaceWith(placeholder);
}
- invokeChangedCallback(name, rawValue, rawOldValue) {
- const changedMethodName = `${name}Changed`;
- const changedMethod = this.receiver[changedMethodName];
- if (typeof changedMethod == "function") {
- const descriptor = this.valueDescriptorNameMap[name];
- try {
- const value = descriptor.reader(rawValue);
- let oldValue = rawOldValue;
- if (rawOldValue) {
- oldValue = descriptor.reader(rawOldValue);
- }
- changedMethod.call(this.receiver, value, oldValue);
- } catch (error2) {
- if (error2 instanceof TypeError) {
- error2.message = `Stimulus Value "${this.context.identifier}.${descriptor.name}" - ${error2.message}`;
- }
- throw error2;
- }
- }
+ replaceCurrentPermanentElementWithClone(permanentElement) {
+ const clone = permanentElement.cloneNode(true);
+ permanentElement.replaceWith(clone);
}
- get valueDescriptors() {
- const { valueDescriptorMap } = this;
- return Object.keys(valueDescriptorMap).map((key) => valueDescriptorMap[key]);
+ replacePlaceholderWithPermanentElement(permanentElement) {
+ const placeholder = this.getPlaceholderById(permanentElement.id);
+ placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);
}
- get valueDescriptorNameMap() {
- const descriptors = {};
- Object.keys(this.valueDescriptorMap).forEach((key) => {
- const descriptor = this.valueDescriptorMap[key];
- descriptors[descriptor.name] = descriptor;
- });
- return descriptors;
+ getPlaceholderById(id) {
+ return this.placeholders.find((element) => element.content == id);
}
- hasValue(attributeName) {
- const descriptor = this.valueDescriptorNameMap[attributeName];
- const hasMethodName = `has${capitalize(descriptor.name)}`;
- return this.receiver[hasMethodName];
+ get placeholders() {
+ return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")];
}
};
- var TargetObserver = class {
- constructor(context, delegate) {
- this.context = context;
- this.delegate = delegate;
- this.targetsByName = new Multimap();
+ function createPlaceholderForPermanentElement(permanentElement) {
+ const element = document.createElement("meta");
+ element.setAttribute("name", "turbo-permanent-placeholder");
+ element.setAttribute("content", permanentElement.id);
+ return element;
+ }
+ var Renderer = class {
+ constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
+ this.activeElement = null;
+ 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 });
}
- start() {
- if (!this.tokenListObserver) {
- this.tokenListObserver = new TokenListObserver(this.element, this.attributeName, this);
- this.tokenListObserver.start();
- }
+ get shouldRender() {
+ return true;
}
- stop() {
- if (this.tokenListObserver) {
- this.disconnectAllTargets();
- this.tokenListObserver.stop();
- delete this.tokenListObserver;
- }
+ get reloadReason() {
+ return;
}
- tokenMatched({ element, content: name }) {
- if (this.scope.containsElement(element)) {
- this.connectTarget(element, name);
+ prepareToRender() {
+ return;
+ }
+ finishRendering() {
+ if (this.resolvingFunctions) {
+ this.resolvingFunctions.resolve();
+ delete this.resolvingFunctions;
}
}
- tokenUnmatched({ element, content: name }) {
- this.disconnectTarget(element, name);
+ async preservingPermanentElements(callback) {
+ await Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
}
- connectTarget(element, name) {
- var _a;
- if (!this.targetsByName.has(name, element)) {
- this.targetsByName.add(name, element);
- (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetConnected(element, name));
+ focusFirstAutofocusableElement() {
+ const element = this.connectedSnapshot.firstAutofocusableElement;
+ if (elementIsFocusable(element)) {
+ element.focus();
}
}
- disconnectTarget(element, name) {
- var _a;
- if (this.targetsByName.has(name, element)) {
- this.targetsByName.delete(name, element);
- (_a = this.tokenListObserver) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.targetDisconnected(element, name));
+ enteringBardo(currentPermanentElement) {
+ if (this.activeElement)
+ return;
+ if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
+ this.activeElement = this.currentSnapshot.activeElement;
}
}
- disconnectAllTargets() {
- for (const name of this.targetsByName.keys) {
- for (const element of this.targetsByName.getValuesForKey(name)) {
- this.disconnectTarget(element, name);
- }
+ leavingBardo(currentPermanentElement) {
+ if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {
+ this.activeElement.focus();
+ this.activeElement = null;
}
}
- get attributeName() {
- return `data-${this.context.identifier}-target`;
+ get connectedSnapshot() {
+ return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;
}
- get element() {
- return this.context.element;
+ get currentElement() {
+ return this.currentSnapshot.element;
}
- get scope() {
- return this.context.scope;
+ get newElement() {
+ return this.newSnapshot.element;
+ }
+ get permanentElementMap() {
+ return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
}
};
- function readInheritableStaticArrayValues(constructor, propertyName) {
- const ancestors = getAncestorsForConstructor(constructor);
- return Array.from(ancestors.reduce((values, constructor2) => {
- getOwnStaticArrayValues(constructor2, propertyName).forEach((name) => values.add(name));
- return values;
- }, /* @__PURE__ */ new Set()));
- }
- function readInheritableStaticObjectPairs(constructor, propertyName) {
- const ancestors = getAncestorsForConstructor(constructor);
- return ancestors.reduce((pairs, constructor2) => {
- pairs.push(...getOwnStaticObjectPairs(constructor2, propertyName));
- return pairs;
- }, []);
+ function elementIsFocusable(element) {
+ return element && typeof element.focus == "function";
}
- function getAncestorsForConstructor(constructor) {
- const ancestors = [];
- while (constructor) {
- ancestors.push(constructor);
- constructor = Object.getPrototypeOf(constructor);
+ var FrameRenderer = class extends Renderer {
+ static renderElement(currentElement, newElement) {
+ var _a;
+ const destinationRange = document.createRange();
+ destinationRange.selectNodeContents(currentElement);
+ destinationRange.deleteContents();
+ const frameElement = newElement;
+ const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
+ if (sourceRange) {
+ sourceRange.selectNodeContents(frameElement);
+ currentElement.appendChild(sourceRange.extractContents());
+ }
}
- return ancestors.reverse();
- }
- function getOwnStaticArrayValues(constructor, propertyName) {
- const definition = constructor[propertyName];
- return Array.isArray(definition) ? definition : [];
- }
- function getOwnStaticObjectPairs(constructor, propertyName) {
- const definition = constructor[propertyName];
- return definition ? Object.keys(definition).map((key) => [key, definition[key]]) : [];
- }
- var OutletObserver = class {
- constructor(context, delegate) {
- this.context = context;
+ constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
+ super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
this.delegate = delegate;
- this.outletsByName = new Multimap();
- this.outletElementsByName = new Multimap();
- this.selectorObserverMap = /* @__PURE__ */ new Map();
- }
- start() {
- if (this.selectorObserverMap.size === 0) {
- this.outletDefinitions.forEach((outletName) => {
- const selector = this.selector(outletName);
- const details = { outletName };
- if (selector) {
- this.selectorObserverMap.set(outletName, new SelectorObserver(document.body, selector, this, details));
- }
- });
- this.selectorObserverMap.forEach((observer) => observer.start());
- }
- this.dependentContexts.forEach((context) => context.refresh());
}
- stop() {
- if (this.selectorObserverMap.size > 0) {
- this.disconnectAllOutlets();
- this.selectorObserverMap.forEach((observer) => observer.stop());
- this.selectorObserverMap.clear();
- }
+ get shouldRender() {
+ return true;
}
- refresh() {
- this.selectorObserverMap.forEach((observer) => observer.refresh());
+ async render() {
+ await nextAnimationFrame();
+ this.preservingPermanentElements(() => {
+ this.loadFrameElement();
+ });
+ this.scrollFrameIntoView();
+ await nextAnimationFrame();
+ this.focusFirstAutofocusableElement();
+ await nextAnimationFrame();
+ this.activateScriptElements();
}
- selectorMatched(element, _selector, { outletName }) {
- const outlet = this.getOutlet(element, outletName);
- if (outlet) {
- this.connectOutlet(outlet, element, outletName);
- }
+ loadFrameElement() {
+ this.delegate.willRenderFrame(this.currentElement, this.newElement);
+ this.renderElement(this.currentElement, this.newElement);
}
- selectorUnmatched(element, _selector, { outletName }) {
- const outlet = this.getOutletFromMap(element, outletName);
- if (outlet) {
- this.disconnectOutlet(outlet, element, outletName);
- }
- }
- selectorMatchElement(element, { outletName }) {
- return this.hasOutlet(element, outletName) && element.matches(`[${this.context.application.schema.controllerAttribute}~=${outletName}]`);
- }
- connectOutlet(outlet, element, outletName) {
- var _a;
- if (!this.outletElementsByName.has(outletName, element)) {
- this.outletsByName.add(outletName, outlet);
- this.outletElementsByName.add(outletName, element);
- (_a = this.selectorObserverMap.get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletConnected(outlet, element, outletName));
- }
- }
- disconnectOutlet(outlet, element, outletName) {
- var _a;
- if (this.outletElementsByName.has(outletName, element)) {
- this.outletsByName.delete(outletName, outlet);
- this.outletElementsByName.delete(outletName, element);
- (_a = this.selectorObserverMap.get(outletName)) === null || _a === void 0 ? void 0 : _a.pause(() => this.delegate.outletDisconnected(outlet, element, outletName));
- }
- }
- disconnectAllOutlets() {
- for (const outletName of this.outletElementsByName.keys) {
- for (const element of this.outletElementsByName.getValuesForKey(outletName)) {
- for (const outlet of this.outletsByName.getValuesForKey(outletName)) {
- this.disconnectOutlet(outlet, element, outletName);
- }
+ 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;
}
- selector(outletName) {
- return this.scope.outlets.getSelectorForOutletName(outletName);
+ activateScriptElements() {
+ for (const inertScriptElement of this.newScriptElements) {
+ const activatedScriptElement = activateScriptElement(inertScriptElement);
+ inertScriptElement.replaceWith(activatedScriptElement);
+ }
}
- get outletDependencies() {
- const dependencies = new Multimap();
- this.router.modules.forEach((module) => {
- const constructor = module.definition.controllerConstructor;
- const outlets = readInheritableStaticArrayValues(constructor, "outlets");
- outlets.forEach((outlet) => dependencies.add(outlet, module.identifier));
- });
- return dependencies;
+ get newScriptElements() {
+ return this.currentElement.querySelectorAll("script");
}
- get outletDefinitions() {
- return this.outletDependencies.getKeysForValue(this.identifier);
+ };
+ function readScrollLogicalPosition(value, defaultValue) {
+ if (value == "end" || value == "start" || value == "center" || value == "nearest") {
+ return value;
+ } else {
+ return defaultValue;
}
- get dependentControllerIdentifiers() {
- return this.outletDependencies.getValuesForKey(this.identifier);
+ }
+ function readScrollBehavior(value, defaultValue) {
+ if (value == "auto" || value == "smooth") {
+ return value;
+ } else {
+ return defaultValue;
}
- get dependentContexts() {
- const identifiers = this.dependentControllerIdentifiers;
- return this.router.contexts.filter((context) => identifiers.includes(context.identifier));
+ }
+ var ProgressBar = class {
+ 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);
+ }
+ `;
}
- hasOutlet(element, outletName) {
- return !!this.getOutlet(element, outletName) || !!this.getOutletFromMap(element, outletName);
+ constructor() {
+ this.hiding = false;
+ this.value = 0;
+ this.visible = false;
+ this.trickle = () => {
+ this.setValue(this.value + Math.random() / 100);
+ };
+ this.stylesheetElement = this.createStylesheetElement();
+ this.progressElement = this.createProgressElement();
+ this.installStylesheetElement();
+ this.setValue(0);
}
- getOutlet(element, outletName) {
- return this.application.getControllerForElementAndIdentifier(element, outletName);
+ show() {
+ if (!this.visible) {
+ this.visible = true;
+ this.installProgressElement();
+ this.startTrickling();
+ }
}
- getOutletFromMap(element, outletName) {
- return this.outletsByName.getValuesForKey(outletName).find((outlet) => outlet.element === element);
+ hide() {
+ if (this.visible && !this.hiding) {
+ this.hiding = true;
+ this.fadeProgressElement(() => {
+ this.uninstallProgressElement();
+ this.stopTrickling();
+ this.visible = false;
+ this.hiding = false;
+ });
+ }
}
- get scope() {
- return this.context.scope;
+ setValue(value) {
+ this.value = value;
+ this.refresh();
}
- get identifier() {
- return this.context.identifier;
+ installStylesheetElement() {
+ document.head.insertBefore(this.stylesheetElement, document.head.firstChild);
}
- get application() {
- return this.context.application;
+ installProgressElement() {
+ this.progressElement.style.width = "0";
+ this.progressElement.style.opacity = "1";
+ document.documentElement.insertBefore(this.progressElement, document.body);
+ this.refresh();
}
- get router() {
- return this.application.router;
+ fadeProgressElement(callback) {
+ this.progressElement.style.opacity = "0";
+ setTimeout(callback, ProgressBar.animationDuration * 1.5);
}
- };
- var Context = class {
- constructor(module, scope) {
- this.logDebugActivity = (functionName, detail = {}) => {
- const { identifier, controller, element } = this;
- detail = Object.assign({ identifier, controller, element }, detail);
- this.application.logDebugActivity(this.identifier, functionName, detail);
- };
- this.module = module;
- this.scope = scope;
- this.controller = new module.controllerConstructor(this);
- this.bindingObserver = new BindingObserver(this, this.dispatcher);
- this.valueObserver = new ValueObserver(this, this.controller);
- this.targetObserver = new TargetObserver(this, this);
- this.outletObserver = new OutletObserver(this, this);
- try {
- this.controller.initialize();
- this.logDebugActivity("initialize");
- } catch (error2) {
- this.handleError(error2, "initializing controller");
+ uninstallProgressElement() {
+ if (this.progressElement.parentNode) {
+ document.documentElement.removeChild(this.progressElement);
}
}
- connect() {
- this.bindingObserver.start();
- this.valueObserver.start();
- this.targetObserver.start();
- this.outletObserver.start();
- try {
- this.controller.connect();
- this.logDebugActivity("connect");
- } catch (error2) {
- this.handleError(error2, "connecting controller");
+ startTrickling() {
+ if (!this.trickleInterval) {
+ this.trickleInterval = window.setInterval(this.trickle, ProgressBar.animationDuration);
}
}
+ stopTrickling() {
+ window.clearInterval(this.trickleInterval);
+ delete this.trickleInterval;
+ }
refresh() {
- this.outletObserver.refresh();
+ requestAnimationFrame(() => {
+ this.progressElement.style.width = `${10 + this.value * 90}%`;
+ });
}
- disconnect() {
- try {
- this.controller.disconnect();
- this.logDebugActivity("disconnect");
- } catch (error2) {
- this.handleError(error2, "disconnecting controller");
+ createStylesheetElement() {
+ const element = document.createElement("style");
+ element.type = "text/css";
+ element.textContent = ProgressBar.defaultCSS;
+ if (this.cspNonce) {
+ element.nonce = this.cspNonce;
}
- this.outletObserver.stop();
- this.targetObserver.stop();
- this.valueObserver.stop();
- this.bindingObserver.stop();
- }
- get application() {
- return this.module.application;
- }
- get identifier() {
- return this.module.identifier;
+ return element;
}
- get schema() {
- return this.application.schema;
+ createProgressElement() {
+ const element = document.createElement("div");
+ element.className = "turbo-progress-bar";
+ return element;
}
- get dispatcher() {
- return this.application.dispatcher;
+ get cspNonce() {
+ return getMetaContent("csp-nonce");
}
- get element() {
- return this.scope.element;
+ };
+ ProgressBar.animationDuration = 300;
+ var HeadSnapshot = class extends Snapshot {
+ constructor() {
+ super(...arguments);
+ this.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 Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });
+ }, {});
}
- get parentElement() {
- return this.element.parentElement;
+ get trackedElementSignature() {
+ return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked).join("");
}
- handleError(error2, message, detail = {}) {
- const { identifier, controller, element } = this;
- detail = Object.assign({ identifier, controller, element }, detail);
- this.application.handleError(error2, `Error ${message}`, detail);
+ getScriptElementsNotInSnapshot(snapshot) {
+ return this.getElementsMatchingTypeNotInSnapshot("script", snapshot);
}
- targetConnected(element, name) {
- this.invokeControllerMethod(`${name}TargetConnected`, element);
+ getStylesheetElementsNotInSnapshot(snapshot) {
+ return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot);
}
- targetDisconnected(element, name) {
- this.invokeControllerMethod(`${name}TargetDisconnected`, element);
+ 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);
}
- outletConnected(outlet, element, name) {
- this.invokeControllerMethod(`${namespaceCamelize(name)}OutletConnected`, outlet, 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;
+ }
+ }, []);
}
- outletDisconnected(outlet, element, name) {
- this.invokeControllerMethod(`${namespaceCamelize(name)}OutletDisconnected`, outlet, element);
+ getMetaValue(name) {
+ const element = this.findMetaElementByName(name);
+ return element ? element.getAttribute("content") : null;
}
- invokeControllerMethod(methodName, ...args) {
- const controller = this.controller;
- if (typeof controller[methodName] == "function") {
- controller[methodName](...args);
- }
+ findMetaElementByName(name) {
+ return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
+ const { elements: [element] } = this.detailsByOuterHTML[outerHTML];
+ return elementIsMetaElementWithName(element, name) ? element : result;
+ }, void 0);
}
};
- function bless(constructor) {
- return shadow(constructor, getBlessedProperties(constructor));
+ function elementType(element) {
+ if (elementIsScript(element)) {
+ return "script";
+ } else if (elementIsStylesheet(element)) {
+ return "stylesheet";
+ }
}
- function shadow(constructor, properties) {
- const shadowConstructor = extend(constructor);
- const shadowProperties = getShadowProperties(constructor.prototype, properties);
- Object.defineProperties(shadowConstructor.prototype, shadowProperties);
- return shadowConstructor;
+ function elementIsTracked(element) {
+ return element.getAttribute("data-turbo-track") == "reload";
}
- function getBlessedProperties(constructor) {
- const blessings = readInheritableStaticArrayValues(constructor, "blessings");
- return blessings.reduce((blessedProperties, blessing) => {
- const properties = blessing(constructor);
- for (const key in properties) {
- const descriptor = blessedProperties[key] || {};
- blessedProperties[key] = Object.assign(descriptor, properties[key]);
- }
- return blessedProperties;
- }, {});
+ function elementIsScript(element) {
+ const tagName = element.localName;
+ return tagName == "script";
}
- function getShadowProperties(prototype, properties) {
- return getOwnKeys(properties).reduce((shadowProperties, key) => {
- const descriptor = getShadowedDescriptor(prototype, properties, key);
- if (descriptor) {
- Object.assign(shadowProperties, { [key]: descriptor });
- }
- return shadowProperties;
- }, {});
+ function elementIsNoscript(element) {
+ const tagName = element.localName;
+ return tagName == "noscript";
}
- function getShadowedDescriptor(prototype, properties, key) {
- const shadowingDescriptor = Object.getOwnPropertyDescriptor(prototype, key);
- const shadowedByValue = shadowingDescriptor && "value" in shadowingDescriptor;
- if (!shadowedByValue) {
- const descriptor = Object.getOwnPropertyDescriptor(properties, key).value;
- if (shadowingDescriptor) {
- descriptor.get = shadowingDescriptor.get || descriptor.get;
- descriptor.set = shadowingDescriptor.set || descriptor.set;
- }
- return descriptor;
- }
+ function elementIsStylesheet(element) {
+ const tagName = element.localName;
+ return tagName == "style" || tagName == "link" && element.getAttribute("rel") == "stylesheet";
}
- var getOwnKeys = (() => {
- if (typeof Object.getOwnPropertySymbols == "function") {
- return (object) => [...Object.getOwnPropertyNames(object), ...Object.getOwnPropertySymbols(object)];
- } else {
- return Object.getOwnPropertyNames;
- }
- })();
- var extend = (() => {
- function extendWithReflect(constructor) {
- function extended() {
- return Reflect.construct(constructor, arguments, new.target);
- }
- extended.prototype = Object.create(constructor.prototype, {
- constructor: { value: extended }
- });
- Reflect.setPrototypeOf(extended, constructor);
- return extended;
- }
- function testReflectExtension() {
- const a = function() {
- this.a.call(this);
- };
- const b = extendWithReflect(a);
- b.prototype.a = function() {
- };
- return new b();
- }
- try {
- testReflectExtension();
- return extendWithReflect;
- } catch (error2) {
- return (constructor) => class extended extends constructor {
- };
- }
- })();
- function blessDefinition(definition) {
- return {
- identifier: definition.identifier,
- controllerConstructor: bless(definition.controllerConstructor)
- };
+ function elementIsMetaElementWithName(element, name) {
+ const tagName = element.localName;
+ return tagName == "meta" && element.getAttribute("name") == name;
}
- var Module = class {
- constructor(application2, definition) {
- this.application = application2;
- this.definition = blessDefinition(definition);
- this.contextsByScope = /* @__PURE__ */ new WeakMap();
- this.connectedContexts = /* @__PURE__ */ new Set();
+ function elementWithoutNonce(element) {
+ if (element.hasAttribute("nonce")) {
+ element.setAttribute("nonce", "");
}
- get identifier() {
- return this.definition.identifier;
+ return element;
+ }
+ var PageSnapshot = class extends Snapshot {
+ static fromHTMLString(html = "") {
+ return this.fromDocument(parseHTMLDocument(html));
}
- get controllerConstructor() {
- return this.definition.controllerConstructor;
+ static fromElement(element) {
+ return this.fromDocument(element.ownerDocument);
}
- get contexts() {
- return Array.from(this.connectedContexts);
+ static fromDocument({ head, body }) {
+ return new this(body, new HeadSnapshot(head));
}
- connectContextForScope(scope) {
- const context = this.fetchContextForScope(scope);
- this.connectedContexts.add(context);
- context.connect();
+ constructor(element, headSnapshot) {
+ super(element);
+ this.headSnapshot = headSnapshot;
}
- disconnectContextForScope(scope) {
- const context = this.contextsByScope.get(scope);
- if (context) {
- this.connectedContexts.delete(context);
- context.disconnect();
+ 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;
}
- }
- fetchContextForScope(scope) {
- let context = this.contextsByScope.get(scope);
- if (!context) {
- context = new Context(this, scope);
- this.contextsByScope.set(scope, context);
+ for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
+ clonedPasswordInput.value = "";
}
- return context;
- }
- };
- var ClassMap = class {
- constructor(scope) {
- this.scope = scope;
- }
- has(name) {
- return this.data.has(this.getDataKey(name));
- }
- get(name) {
- return this.getAll(name)[0];
- }
- getAll(name) {
- const tokenString = this.data.get(this.getDataKey(name)) || "";
- return tokenize(tokenString);
- }
- getAttributeName(name) {
- return this.data.getAttributeNameForKey(this.getDataKey(name));
- }
- getDataKey(name) {
- return `${name}-class`;
- }
- get data() {
- return this.scope.data;
- }
- };
- var DataMap = class {
- constructor(scope) {
- this.scope = scope;
+ return new PageSnapshot(clonedElement, this.headSnapshot);
}
- get element() {
- return this.scope.element;
+ get headElement() {
+ return this.headSnapshot.element;
}
- get identifier() {
- return this.scope.identifier;
+ get rootLocation() {
+ var _a;
+ const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
+ return expandURL(root);
}
- get(key) {
- const name = this.getAttributeNameForKey(key);
- return this.element.getAttribute(name);
+ get cacheControlValue() {
+ return this.getSetting("cache-control");
}
- set(key, value) {
- const name = this.getAttributeNameForKey(key);
- this.element.setAttribute(name, value);
- return this.get(key);
+ get isPreviewable() {
+ return this.cacheControlValue != "no-preview";
}
- has(key) {
- const name = this.getAttributeNameForKey(key);
- return this.element.hasAttribute(name);
+ get isCacheable() {
+ return this.cacheControlValue != "no-cache";
}
- delete(key) {
- if (this.has(key)) {
- const name = this.getAttributeNameForKey(key);
- this.element.removeAttribute(name);
- return true;
- } else {
- return false;
- }
+ get isVisitable() {
+ return this.getSetting("visit-control") != "reload";
}
- getAttributeNameForKey(key) {
- return `data-${this.identifier}-${dasherize(key)}`;
+ getSetting(name) {
+ return this.headSnapshot.getMetaValue(`turbo-${name}`);
}
};
- var Guide = class {
- constructor(logger) {
- this.warnedKeysByObject = /* @__PURE__ */ new WeakMap();
- this.logger = logger;
- }
- warn(object, key, message) {
- let warnedKeys = this.warnedKeysByObject.get(object);
- if (!warnedKeys) {
- warnedKeys = /* @__PURE__ */ new Set();
- this.warnedKeysByObject.set(object, warnedKeys);
- }
- if (!warnedKeys.has(key)) {
- warnedKeys.add(key);
- this.logger.warn(message, object);
- }
- }
+ var TimingMetric;
+ (function(TimingMetric2) {
+ TimingMetric2["visitStart"] = "visitStart";
+ TimingMetric2["requestStart"] = "requestStart";
+ TimingMetric2["requestEnd"] = "requestEnd";
+ TimingMetric2["visitEnd"] = "visitEnd";
+ })(TimingMetric || (TimingMetric = {}));
+ var VisitState;
+ (function(VisitState2) {
+ VisitState2["initialized"] = "initialized";
+ VisitState2["started"] = "started";
+ VisitState2["canceled"] = "canceled";
+ VisitState2["failed"] = "failed";
+ VisitState2["completed"] = "completed";
+ })(VisitState || (VisitState = {}));
+ var defaultOptions = {
+ action: "advance",
+ historyChanged: false,
+ visitCachedSnapshot: () => {
+ },
+ willRender: true,
+ updateHistory: true,
+ shouldCacheSnapshot: true,
+ acceptsStreamResponse: false
};
- function attributeValueContainsToken(attributeName, token) {
- return `[${attributeName}~="${token}"]`;
- }
- var TargetSet = class {
- constructor(scope) {
- this.scope = scope;
- }
- get element() {
- return this.scope.element;
- }
- get identifier() {
- return this.scope.identifier;
- }
- get schema() {
- return this.scope.schema;
- }
- has(targetName) {
- return this.find(targetName) != null;
- }
- find(...targetNames) {
- return targetNames.reduce((target, targetName) => target || this.findTarget(targetName) || this.findLegacyTarget(targetName), void 0);
+ var SystemStatusCode;
+ (function(SystemStatusCode2) {
+ SystemStatusCode2[SystemStatusCode2["networkFailure"] = 0] = "networkFailure";
+ SystemStatusCode2[SystemStatusCode2["timeoutFailure"] = -1] = "timeoutFailure";
+ SystemStatusCode2[SystemStatusCode2["contentTypeMismatch"] = -2] = "contentTypeMismatch";
+ })(SystemStatusCode || (SystemStatusCode = {}));
+ var Visit = class {
+ constructor(delegate, location2, restorationIdentifier, options = {}) {
+ this.identifier = uuid();
+ this.timingMetrics = {};
+ this.followedRedirect = false;
+ this.historyChanged = false;
+ this.scrolled = false;
+ this.shouldCacheSnapshot = true;
+ this.acceptsStreamResponse = false;
+ this.snapshotCached = false;
+ this.state = VisitState.initialized;
+ this.delegate = delegate;
+ this.location = location2;
+ this.restorationIdentifier = restorationIdentifier || uuid();
+ const { action, historyChanged, referrer, snapshot, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse } = Object.assign(Object.assign({}, 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.visitCachedSnapshot = visitCachedSnapshot;
+ this.willRender = willRender;
+ this.updateHistory = updateHistory;
+ this.scrolled = !willRender;
+ this.shouldCacheSnapshot = shouldCacheSnapshot;
+ this.acceptsStreamResponse = acceptsStreamResponse;
}
- findAll(...targetNames) {
- return targetNames.reduce((targets, targetName) => [
- ...targets,
- ...this.findAllTargets(targetName),
- ...this.findAllLegacyTargets(targetName)
- ], []);
+ get adapter() {
+ return this.delegate.adapter;
}
- findTarget(targetName) {
- const selector = this.getSelectorForTargetName(targetName);
- return this.scope.findElement(selector);
+ get view() {
+ return this.delegate.view;
}
- findAllTargets(targetName) {
- const selector = this.getSelectorForTargetName(targetName);
- return this.scope.findAllElements(selector);
+ get history() {
+ return this.delegate.history;
}
- getSelectorForTargetName(targetName) {
- const attributeName = this.schema.targetAttributeForScope(this.identifier);
- return attributeValueContainsToken(attributeName, targetName);
+ get restorationData() {
+ return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
}
- findLegacyTarget(targetName) {
- const selector = this.getLegacySelectorForTargetName(targetName);
- return this.deprecate(this.scope.findElement(selector), targetName);
+ get silent() {
+ return this.isSamePage;
}
- findAllLegacyTargets(targetName) {
- const selector = this.getLegacySelectorForTargetName(targetName);
- return this.scope.findAllElements(selector).map((element) => this.deprecate(element, targetName));
+ start() {
+ if (this.state == VisitState.initialized) {
+ this.recordTimingMetric(TimingMetric.visitStart);
+ this.state = VisitState.started;
+ this.adapter.visitStarted(this);
+ this.delegate.visitStarted(this);
+ }
}
- getLegacySelectorForTargetName(targetName) {
- const targetDescriptor = `${this.identifier}.${targetName}`;
- return attributeValueContainsToken(this.schema.targetAttribute, targetDescriptor);
+ cancel() {
+ if (this.state == VisitState.started) {
+ if (this.request) {
+ this.request.cancel();
+ }
+ this.cancelRender();
+ this.state = VisitState.canceled;
+ }
}
- deprecate(element, targetName) {
- if (element) {
- const { identifier } = this;
- const attributeName = this.schema.targetAttribute;
- const revisedAttributeName = this.schema.targetAttributeForScope(identifier);
- this.guide.warn(element, `target:${targetName}`, `Please replace ${attributeName}="${identifier}.${targetName}" with ${revisedAttributeName}="${targetName}". The ${attributeName} attribute is deprecated and will be removed in a future version of Stimulus.`);
+ complete() {
+ if (this.state == VisitState.started) {
+ this.recordTimingMetric(TimingMetric.visitEnd);
+ this.state = VisitState.completed;
+ this.followRedirect();
+ if (!this.followedRedirect) {
+ this.adapter.visitCompleted(this);
+ this.delegate.visitCompleted(this);
+ }
}
- return element;
}
- get guide() {
- return this.scope.guide;
+ fail() {
+ if (this.state == VisitState.started) {
+ this.state = VisitState.failed;
+ this.adapter.visitFailed(this);
+ }
}
- };
- var OutletSet = class {
- constructor(scope, controllerElement) {
- this.scope = scope;
- this.controllerElement = controllerElement;
+ changeHistory() {
+ var _a;
+ if (!this.historyChanged && this.updateHistory) {
+ const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
+ const method = getHistoryMethodForAction(actionForHistory);
+ this.history.update(method, this.location, this.restorationIdentifier);
+ this.historyChanged = true;
+ }
}
- get element() {
- return this.scope.element;
+ issueRequest() {
+ if (this.hasPreloadedResponse()) {
+ this.simulateRequest();
+ } else if (this.shouldIssueRequest() && !this.request) {
+ this.request = new FetchRequest(this, FetchMethod.get, this.location);
+ this.request.perform();
+ }
}
- get identifier() {
- return this.scope.identifier;
+ simulateRequest() {
+ if (this.response) {
+ this.startRequest();
+ this.recordResponse();
+ this.finishRequest();
+ }
}
- get schema() {
- return this.scope.schema;
+ startRequest() {
+ this.recordTimingMetric(TimingMetric.requestStart);
+ this.adapter.visitRequestStarted(this);
}
- has(outletName) {
- return this.find(outletName) != null;
+ 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);
+ }
+ }
}
- find(...outletNames) {
- return outletNames.reduce((outlet, outletName) => outlet || this.findOutlet(outletName), void 0);
+ finishRequest() {
+ this.recordTimingMetric(TimingMetric.requestEnd);
+ this.adapter.visitRequestFinished(this);
}
- findAll(...outletNames) {
- return outletNames.reduce((outlets, outletName) => [...outlets, ...this.findAllOutlets(outletName)], []);
+ 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) {
+ await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);
+ this.performScroll();
+ this.adapter.visitRendered(this);
+ this.complete();
+ } else {
+ await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);
+ this.adapter.visitRendered(this);
+ this.fail();
+ }
+ });
+ }
}
- getSelectorForOutletName(outletName) {
- const attributeName = this.schema.outletAttributeForScope(this.identifier, outletName);
- return this.controllerElement.getAttribute(attributeName);
+ 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;
+ }
+ }
}
- findOutlet(outletName) {
- const selector = this.getSelectorForOutletName(outletName);
- if (selector)
- return this.findElement(selector, outletName);
+ getPreloadedSnapshot() {
+ if (this.snapshotHTML) {
+ return PageSnapshot.fromHTMLString(this.snapshotHTML);
+ }
}
- findAllOutlets(outletName) {
- const selector = this.getSelectorForOutletName(outletName);
- return selector ? this.findAllElements(selector, outletName) : [];
+ hasCachedSnapshot() {
+ return this.getCachedSnapshot() != null;
}
- findElement(selector, outletName) {
- const elements = this.scope.queryElements(selector);
- return elements.filter((element) => this.matchesElement(element, selector, outletName))[0];
+ loadCachedSnapshot() {
+ const snapshot = this.getCachedSnapshot();
+ if (snapshot) {
+ const isPreview = this.shouldIssueRequest();
+ this.render(async () => {
+ this.cacheSnapshot();
+ if (this.isSamePage) {
+ this.adapter.visitRendered(this);
+ } else {
+ if (this.view.renderPromise)
+ await this.view.renderPromise;
+ await this.view.renderPage(snapshot, isPreview, this.willRender, this);
+ this.performScroll();
+ this.adapter.visitRendered(this);
+ if (!isPreview) {
+ this.complete();
+ }
+ }
+ });
+ }
}
- findAllElements(selector, outletName) {
- const elements = this.scope.queryElements(selector);
- return elements.filter((element) => this.matchesElement(element, selector, outletName));
+ followRedirect() {
+ var _a;
+ if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
+ this.adapter.visitProposedToLocation(this.redirectedToLocation, {
+ action: "replace",
+ response: this.response,
+ shouldCacheSnapshot: false,
+ willRender: false
+ });
+ this.followedRedirect = true;
+ }
}
- matchesElement(element, selector, outletName) {
- const controllerAttribute = element.getAttribute(this.scope.schema.controllerAttribute) || "";
- return element.matches(selector) && controllerAttribute.split(" ").includes(outletName);
+ goToSamePageAnchor() {
+ if (this.isSamePage) {
+ this.render(async () => {
+ this.cacheSnapshot();
+ this.performScroll();
+ this.changeHistory();
+ this.adapter.visitRendered(this);
+ });
+ }
}
- };
- var Scope = class {
- constructor(schema, element, identifier, logger) {
- this.targets = new TargetSet(this);
- this.classes = new ClassMap(this);
- this.data = new DataMap(this);
- this.containsElement = (element2) => {
- return element2.closest(this.controllerSelector) === this.element;
- };
- this.schema = schema;
- this.element = element;
- this.identifier = identifier;
- this.guide = new Guide(logger);
- this.outlets = new OutletSet(this.documentScope, element);
+ prepareRequest(request) {
+ if (this.acceptsStreamResponse) {
+ request.acceptResponseType(StreamMessage.contentType);
+ }
}
- findElement(selector) {
- return this.element.matches(selector) ? this.element : this.queryElements(selector).find(this.containsElement);
+ requestStarted() {
+ this.startRequest();
}
- findAllElements(selector) {
- return [
- ...this.element.matches(selector) ? [this.element] : [],
- ...this.queryElements(selector).filter(this.containsElement)
- ];
+ requestPreventedHandlingResponse(_request, _response) {
}
- queryElements(selector) {
- return Array.from(this.element.querySelectorAll(selector));
+ 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 });
+ }
}
- get controllerSelector() {
- return attributeValueContainsToken(this.schema.controllerAttribute, this.identifier);
+ 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 });
+ }
}
- get isDocumentScope() {
- return this.element === document.documentElement;
+ requestErrored(_request, _error) {
+ this.recordResponse({
+ statusCode: SystemStatusCode.networkFailure,
+ redirected: false
+ });
}
- get documentScope() {
- return this.isDocumentScope ? this : new Scope(this.schema, document.documentElement, this.identifier, this.guide.logger);
+ requestFinished() {
+ this.finishRequest();
}
- };
- var ScopeObserver = class {
- constructor(element, schema, delegate) {
- this.element = element;
- this.schema = schema;
- this.delegate = delegate;
- this.valueListObserver = new ValueListObserver(this.element, this.controllerAttribute, this);
- this.scopesByIdentifierByElement = /* @__PURE__ */ new WeakMap();
- this.scopeReferenceCounts = /* @__PURE__ */ new WeakMap();
+ performScroll() {
+ if (!this.scrolled && !this.view.forceReloaded) {
+ 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;
+ }
}
- start() {
- this.valueListObserver.start();
+ scrollToRestoredPosition() {
+ const { scrollPosition } = this.restorationData;
+ if (scrollPosition) {
+ this.view.scrollToPosition(scrollPosition);
+ return true;
+ }
}
- stop() {
- this.valueListObserver.stop();
+ scrollToAnchor() {
+ const anchor = getAnchor(this.location);
+ if (anchor != null) {
+ this.view.scrollToAnchor(anchor);
+ return true;
+ }
}
- get controllerAttribute() {
- return this.schema.controllerAttribute;
+ recordTimingMetric(metric) {
+ this.timingMetrics[metric] = new Date().getTime();
}
- parseValueForToken(token) {
- const { element, content: identifier } = token;
- const scopesByIdentifier = this.fetchScopesByIdentifierForElement(element);
- let scope = scopesByIdentifier.get(identifier);
- if (!scope) {
- scope = this.delegate.createScopeForElementAndIdentifier(element, identifier);
- scopesByIdentifier.set(identifier, scope);
+ getTimingMetrics() {
+ return Object.assign({}, this.timingMetrics);
+ }
+ getHistoryMethodForAction(action) {
+ switch (action) {
+ case "replace":
+ return history.replaceState;
+ case "advance":
+ case "restore":
+ return history.pushState;
}
- return scope;
}
- elementMatchedValue(element, value) {
- const referenceCount = (this.scopeReferenceCounts.get(value) || 0) + 1;
- this.scopeReferenceCounts.set(value, referenceCount);
- if (referenceCount == 1) {
- this.delegate.scopeConnected(value);
+ hasPreloadedResponse() {
+ return typeof this.response == "object";
+ }
+ shouldIssueRequest() {
+ if (this.isSamePage) {
+ return false;
+ } else if (this.action == "restore") {
+ return !this.hasCachedSnapshot();
+ } else {
+ return this.willRender;
}
}
- elementUnmatchedValue(element, value) {
- const referenceCount = this.scopeReferenceCounts.get(value);
- if (referenceCount) {
- this.scopeReferenceCounts.set(value, referenceCount - 1);
- if (referenceCount == 1) {
- this.delegate.scopeDisconnected(value);
- }
+ cacheSnapshot() {
+ if (!this.snapshotCached) {
+ this.view.cacheSnapshot(this.snapshot).then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));
+ this.snapshotCached = true;
}
}
- fetchScopesByIdentifierForElement(element) {
- let scopesByIdentifier = this.scopesByIdentifierByElement.get(element);
- if (!scopesByIdentifier) {
- scopesByIdentifier = /* @__PURE__ */ new Map();
- this.scopesByIdentifierByElement.set(element, scopesByIdentifier);
+ async render(callback) {
+ this.cancelRender();
+ await new Promise((resolve) => {
+ this.frame = requestAnimationFrame(() => resolve());
+ });
+ await callback();
+ delete this.frame;
+ }
+ cancelRender() {
+ if (this.frame) {
+ cancelAnimationFrame(this.frame);
+ delete this.frame;
}
- return scopesByIdentifier;
}
};
- var Router = class {
- constructor(application2) {
- this.application = application2;
- this.scopeObserver = new ScopeObserver(this.element, this.schema, this);
- this.scopesByIdentifier = new Multimap();
- this.modulesByIdentifier = /* @__PURE__ */ new Map();
+ function isSuccessful(statusCode) {
+ return statusCode >= 200 && statusCode < 300;
+ }
+ var BrowserAdapter = class {
+ constructor(session2) {
+ this.progressBar = new ProgressBar();
+ this.showProgressBar = () => {
+ this.progressBar.show();
+ };
+ this.session = session2;
}
- get element() {
- return this.application.element;
+ visitProposedToLocation(location2, options) {
+ this.navigator.startVisit(location2, (options === null || options === void 0 ? void 0 : options.restorationIdentifier) || uuid(), options);
}
- get schema() {
- return this.application.schema;
+ visitStarted(visit2) {
+ this.location = visit2.location;
+ visit2.loadCachedSnapshot();
+ visit2.issueRequest();
+ visit2.goToSamePageAnchor();
}
- get logger() {
- return this.application.logger;
+ visitRequestStarted(visit2) {
+ this.progressBar.setValue(0);
+ if (visit2.hasCachedSnapshot() || visit2.action != "restore") {
+ this.showVisitProgressBarAfterDelay();
+ } else {
+ this.showProgressBar();
+ }
}
- get controllerAttribute() {
- return this.schema.controllerAttribute;
+ visitRequestCompleted(visit2) {
+ visit2.loadResponse();
}
- get modules() {
- return Array.from(this.modulesByIdentifier.values());
+ 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();
+ }
}
- get contexts() {
- return this.modules.reduce((contexts, module) => contexts.concat(module.contexts), []);
+ visitRequestFinished(_visit) {
+ this.progressBar.setValue(1);
+ this.hideVisitProgressBar();
}
- start() {
- this.scopeObserver.start();
+ visitCompleted(_visit) {
}
- stop() {
- this.scopeObserver.stop();
+ pageInvalidated(reason) {
+ this.reload(reason);
}
- loadDefinition(definition) {
- this.unloadIdentifier(definition.identifier);
- const module = new Module(this.application, definition);
- this.connectModule(module);
- const afterLoad = definition.controllerConstructor.afterLoad;
- if (afterLoad) {
- afterLoad(definition.identifier, this.application);
- }
+ visitFailed(_visit) {
}
- unloadIdentifier(identifier) {
- const module = this.modulesByIdentifier.get(identifier);
- if (module) {
- this.disconnectModule(module);
- }
+ visitRendered(_visit) {
}
- getContextForElementAndIdentifier(element, identifier) {
- const module = this.modulesByIdentifier.get(identifier);
- if (module) {
- return module.contexts.find((context) => context.element == element);
- }
+ formSubmissionStarted(_formSubmission) {
+ this.progressBar.setValue(0);
+ this.showFormProgressBarAfterDelay();
}
- handleError(error2, message, detail) {
- this.application.handleError(error2, message, detail);
+ formSubmissionFinished(_formSubmission) {
+ this.progressBar.setValue(1);
+ this.hideFormProgressBar();
}
- createScopeForElementAndIdentifier(element, identifier) {
- return new Scope(this.schema, element, identifier, this.logger);
+ showVisitProgressBarAfterDelay() {
+ this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
}
- scopeConnected(scope) {
- this.scopesByIdentifier.add(scope.identifier, scope);
- const module = this.modulesByIdentifier.get(scope.identifier);
- if (module) {
- module.connectContextForScope(scope);
+ hideVisitProgressBar() {
+ this.progressBar.hide();
+ if (this.visitProgressBarTimeout != null) {
+ window.clearTimeout(this.visitProgressBarTimeout);
+ delete this.visitProgressBarTimeout;
}
}
- scopeDisconnected(scope) {
- this.scopesByIdentifier.delete(scope.identifier, scope);
- const module = this.modulesByIdentifier.get(scope.identifier);
- if (module) {
- module.disconnectContextForScope(scope);
+ showFormProgressBarAfterDelay() {
+ if (this.formProgressBarTimeout == null) {
+ this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
}
}
- connectModule(module) {
- this.modulesByIdentifier.set(module.identifier, module);
- const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);
- scopes.forEach((scope) => module.connectContextForScope(scope));
+ hideFormProgressBar() {
+ this.progressBar.hide();
+ if (this.formProgressBarTimeout != null) {
+ window.clearTimeout(this.formProgressBarTimeout);
+ delete this.formProgressBarTimeout;
+ }
}
- disconnectModule(module) {
- this.modulesByIdentifier.delete(module.identifier);
- const scopes = this.scopesByIdentifier.getValuesForKey(module.identifier);
- scopes.forEach((scope) => module.disconnectContextForScope(scope));
+ reload(reason) {
+ var _a;
+ dispatch("turbo:reload", { detail: reason });
+ window.location.href = ((_a = this.location) === null || _a === void 0 ? void 0 : _a.toString()) || window.location.href;
+ }
+ get navigator() {
+ return this.session.navigator;
}
};
- var defaultSchema = {
- controllerAttribute: "data-controller",
- actionAttribute: "data-action",
- targetAttribute: "data-target",
- targetAttributeForScope: (identifier) => `data-${identifier}-target`,
- outletAttributeForScope: (identifier, outlet) => `data-${identifier}-${outlet}-outlet`,
- keyMappings: Object.assign(Object.assign({ enter: "Enter", tab: "Tab", esc: "Escape", space: " ", up: "ArrowUp", down: "ArrowDown", left: "ArrowLeft", right: "ArrowRight", home: "Home", end: "End" }, objectFromEntries("abcdefghijklmnopqrstuvwxyz".split("").map((c) => [c, c]))), objectFromEntries("0123456789".split("").map((n) => [n, n])))
- };
- function objectFromEntries(array) {
- return array.reduce((memo, [k, v]) => Object.assign(Object.assign({}, memo), { [k]: v }), {});
- }
- var Application = class {
- constructor(element = document.documentElement, schema = defaultSchema) {
- this.logger = console;
- this.debug = false;
- this.logDebugActivity = (identifier, functionName, detail = {}) => {
- if (this.debug) {
- this.logFormattedMessage(identifier, functionName, detail);
+ var CacheObserver = class {
+ constructor() {
+ this.selector = "[data-turbo-temporary]";
+ this.deprecatedSelector = "[data-turbo-cache=false]";
+ this.started = false;
+ this.removeTemporaryElements = (_event) => {
+ for (const element of this.temporaryElements) {
+ element.remove();
}
};
- this.element = element;
- this.schema = schema;
- this.dispatcher = new Dispatcher(this);
- this.router = new Router(this);
- this.actionDescriptorFilters = Object.assign({}, defaultActionDescriptorFilters);
- }
- static start(element, schema) {
- const application2 = new this(element, schema);
- application2.start();
- return application2;
}
- async start() {
- await domReady();
- this.logDebugActivity("application", "starting");
- this.dispatcher.start();
- this.router.start();
- this.logDebugActivity("application", "start");
+ start() {
+ if (!this.started) {
+ this.started = true;
+ addEventListener("turbo:before-cache", this.removeTemporaryElements, false);
+ }
}
stop() {
- this.logDebugActivity("application", "stopping");
- this.dispatcher.stop();
- this.router.stop();
- this.logDebugActivity("application", "stop");
+ if (this.started) {
+ this.started = false;
+ removeEventListener("turbo:before-cache", this.removeTemporaryElements, false);
+ }
}
- register(identifier, controllerConstructor) {
- this.load({ identifier, controllerConstructor });
+ get temporaryElements() {
+ return [...document.querySelectorAll(this.selector), ...this.temporaryElementsWithDeprecation];
}
- registerActionOption(name, filter) {
- this.actionDescriptorFilters[name] = filter;
+ 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];
}
- load(head, ...rest) {
- const definitions = Array.isArray(head) ? head : [head, ...rest];
- definitions.forEach((definition) => {
- if (definition.controllerConstructor.shouldLoad) {
- this.router.loadDefinition(definition);
- }
- });
+ };
+ var FrameRedirector = class {
+ constructor(session2, element) {
+ this.session = session2;
+ this.element = element;
+ this.linkInterceptor = new LinkInterceptor(this, element);
+ this.formSubmitObserver = new FormSubmitObserver(this, element);
}
- unload(head, ...rest) {
- const identifiers = Array.isArray(head) ? head : [head, ...rest];
- identifiers.forEach((identifier) => this.router.unloadIdentifier(identifier));
+ start() {
+ this.linkInterceptor.start();
+ this.formSubmitObserver.start();
}
- get controllers() {
- return this.router.contexts.map((context) => context.controller);
+ stop() {
+ this.linkInterceptor.stop();
+ this.formSubmitObserver.stop();
}
- getControllerForElementAndIdentifier(element, identifier) {
- const context = this.router.getContextForElementAndIdentifier(element, identifier);
- return context ? context.controller : null;
+ shouldInterceptLinkClick(element, _location, _event) {
+ return this.shouldRedirect(element);
}
- handleError(error2, message, detail) {
- var _a;
- this.logger.error(`%s
-
-%o
-
-%o`, message, error2, detail);
- (_a = window.onerror) === null || _a === void 0 ? void 0 : _a.call(window, message, "", 0, 0, error2);
+ linkClickIntercepted(element, url, event) {
+ const frame = this.findFrameElement(element);
+ if (frame) {
+ frame.delegate.linkClickIntercepted(element, url, event);
+ }
}
- logFormattedMessage(identifier, functionName, detail = {}) {
- detail = Object.assign({ application: this }, detail);
- this.logger.groupCollapsed(`${identifier} #${functionName}`);
- this.logger.log("details:", Object.assign({}, detail));
- this.logger.groupEnd();
+ willSubmitForm(element, submitter) {
+ return element.closest("turbo-frame") == null && this.shouldSubmit(element, submitter) && this.shouldRedirect(element, submitter);
}
- };
- function domReady() {
- return new Promise((resolve) => {
- if (document.readyState == "loading") {
- document.addEventListener("DOMContentLoaded", () => resolve());
+ formSubmitted(element, submitter) {
+ const frame = this.findFrameElement(element, submitter);
+ if (frame) {
+ frame.delegate.formSubmitted(element, submitter);
+ }
+ }
+ shouldSubmit(form, submitter) {
+ var _a;
+ const action = getAction(form, submitter);
+ const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
+ const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/");
+ 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 {
- resolve();
+ return false;
}
- });
- }
- function ClassPropertiesBlessing(constructor) {
- const classes = readInheritableStaticArrayValues(constructor, "classes");
- return classes.reduce((properties, classDefinition) => {
- return Object.assign(properties, propertiesForClassDefinition(classDefinition));
- }, {});
- }
- function propertiesForClassDefinition(key) {
- return {
- [`${key}Class`]: {
- get() {
- const { classes } = this;
- if (classes.has(key)) {
- return classes.get(key);
- } else {
- const attribute = classes.getAttributeName(key);
- throw new Error(`Missing attribute "${attribute}"`);
- }
- }
- },
- [`${key}Classes`]: {
- get() {
- return this.classes.getAll(key);
- }
- },
- [`has${capitalize(key)}Class`]: {
- get() {
- return this.classes.has(key);
+ }
+ findFrameElement(element, submitter) {
+ const id = (submitter === null || submitter === void 0 ? void 0 : 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;
}
}
- };
- }
- function OutletPropertiesBlessing(constructor) {
- const outlets = readInheritableStaticArrayValues(constructor, "outlets");
- return outlets.reduce((properties, outletDefinition) => {
- return Object.assign(properties, propertiesForOutletDefinition(outletDefinition));
- }, {});
- }
- function propertiesForOutletDefinition(name) {
- const camelizedName = namespaceCamelize(name);
- return {
- [`${camelizedName}Outlet`]: {
- get() {
- const outlet = this.outlets.find(name);
- if (outlet) {
- const outletController = this.application.getControllerForElementAndIdentifier(outlet, name);
- if (outletController) {
- return outletController;
- } else {
- throw new Error(`Missing "data-controller=${name}" attribute on outlet element for "${this.identifier}" controller`);
- }
- }
- throw new Error(`Missing outlet element "${name}" for "${this.identifier}" controller`);
- }
- },
- [`${camelizedName}Outlets`]: {
- get() {
- const outlets = this.outlets.findAll(name);
- if (outlets.length > 0) {
- return outlets.map((outlet) => {
- const controller = this.application.getControllerForElementAndIdentifier(outlet, name);
- if (controller) {
- return controller;
- } else {
- console.warn(`The provided outlet element is missing the outlet controller "${name}" for "${this.identifier}"`, outlet);
- }
- }).filter((controller) => controller);
- }
- return [];
- }
- },
- [`${camelizedName}OutletElement`]: {
- get() {
- const outlet = this.outlets.find(name);
- if (outlet) {
- return outlet;
- } else {
- throw new Error(`Missing outlet element "${name}" for "${this.identifier}" controller`);
+ }
+ };
+ var History = class {
+ constructor(delegate) {
+ this.restorationIdentifier = uuid();
+ this.restorationData = {};
+ this.started = false;
+ this.pageLoaded = false;
+ this.onPopState = (event) => {
+ if (this.shouldHandlePopState()) {
+ const { turbo } = event.state || {};
+ if (turbo) {
+ this.location = new URL(window.location.href);
+ const { restorationIdentifier } = turbo;
+ this.restorationIdentifier = restorationIdentifier;
+ this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
}
}
- },
- [`${camelizedName}OutletElements`]: {
- get() {
- return this.outlets.findAll(name);
- }
- },
- [`has${capitalize(camelizedName)}Outlet`]: {
- get() {
- return this.outlets.has(name);
- }
+ };
+ this.onPageLoad = async (_event) => {
+ await nextMicrotask();
+ this.pageLoaded = true;
+ };
+ this.delegate = delegate;
+ }
+ start() {
+ if (!this.started) {
+ addEventListener("popstate", this.onPopState, false);
+ addEventListener("load", this.onPageLoad, false);
+ this.started = true;
+ this.replace(new URL(window.location.href));
}
- };
- }
- function TargetPropertiesBlessing(constructor) {
- const targets = readInheritableStaticArrayValues(constructor, "targets");
- return targets.reduce((properties, targetDefinition) => {
- return Object.assign(properties, propertiesForTargetDefinition(targetDefinition));
- }, {});
- }
- function propertiesForTargetDefinition(name) {
- return {
- [`${name}Target`]: {
- get() {
- const target = this.targets.find(name);
- if (target) {
- return target;
- } else {
- throw new Error(`Missing target element "${name}" for "${this.identifier}" controller`);
- }
- }
- },
- [`${name}Targets`]: {
- get() {
- return this.targets.findAll(name);
- }
- },
- [`has${capitalize(name)}Target`]: {
- get() {
- return this.targets.has(name);
- }
+ }
+ stop() {
+ if (this.started) {
+ removeEventListener("popstate", this.onPopState, false);
+ removeEventListener("load", this.onPageLoad, false);
+ this.started = false;
}
- };
- }
- function ValuePropertiesBlessing(constructor) {
- const valueDefinitionPairs = readInheritableStaticObjectPairs(constructor, "values");
- const propertyDescriptorMap = {
- valueDescriptorMap: {
- get() {
- return valueDefinitionPairs.reduce((result, valueDefinitionPair) => {
- const valueDescriptor = parseValueDefinitionPair(valueDefinitionPair, this.identifier);
- const attributeName = this.data.getAttributeNameForKey(valueDescriptor.key);
- return Object.assign(result, { [attributeName]: valueDescriptor });
- }, {});
- }
+ }
+ push(location2, restorationIdentifier) {
+ this.update(history.pushState, location2, restorationIdentifier);
+ }
+ replace(location2, restorationIdentifier) {
+ this.update(history.replaceState, location2, restorationIdentifier);
+ }
+ update(method, location2, restorationIdentifier = uuid()) {
+ const state = { turbo: { restorationIdentifier } };
+ method.call(history, state, "", location2.href);
+ this.location = location2;
+ this.restorationIdentifier = restorationIdentifier;
+ }
+ getRestorationDataForIdentifier(restorationIdentifier) {
+ return this.restorationData[restorationIdentifier] || {};
+ }
+ updateRestorationData(additionalData) {
+ const { restorationIdentifier } = this;
+ const restorationData = this.restorationData[restorationIdentifier];
+ this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);
+ }
+ assumeControlOfScrollRestoration() {
+ var _a;
+ if (!this.previousScrollRestoration) {
+ this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto";
+ history.scrollRestoration = "manual";
}
- };
- return valueDefinitionPairs.reduce((properties, valueDefinitionPair) => {
- return Object.assign(properties, propertiesForValueDefinitionPair(valueDefinitionPair));
- }, propertyDescriptorMap);
- }
- function propertiesForValueDefinitionPair(valueDefinitionPair, controller) {
- const definition = parseValueDefinitionPair(valueDefinitionPair, controller);
- const { key, name, reader: read, writer: write } = definition;
- return {
- [name]: {
- get() {
- const value = this.data.get(key);
- if (value !== null) {
- return read(value);
- } else {
- return definition.defaultValue;
- }
- },
- set(value) {
- if (value === void 0) {
- this.data.delete(key);
- } else {
- this.data.set(key, write(value));
- }
- }
- },
- [`has${capitalize(name)}`]: {
- get() {
- return this.data.has(key) || definition.hasCustomDefaultValue;
- }
+ }
+ relinquishControlOfScrollRestoration() {
+ if (this.previousScrollRestoration) {
+ history.scrollRestoration = this.previousScrollRestoration;
+ delete this.previousScrollRestoration;
}
- };
- }
- function parseValueDefinitionPair([token, typeDefinition], controller) {
- return valueDescriptorForTokenAndTypeDefinition({
- controller,
- token,
- typeDefinition
- });
- }
- function parseValueTypeConstant(constant) {
- switch (constant) {
- case Array:
- return "array";
- case Boolean:
- return "boolean";
- case Number:
- return "number";
- case Object:
- return "object";
- case String:
- return "string";
}
- }
- function parseValueTypeDefault(defaultValue) {
- switch (typeof defaultValue) {
- case "boolean":
- return "boolean";
- case "number":
- return "number";
- case "string":
- return "string";
+ shouldHandlePopState() {
+ return this.pageIsLoaded();
}
- if (Array.isArray(defaultValue))
- return "array";
- if (Object.prototype.toString.call(defaultValue) === "[object Object]")
- return "object";
- }
- function parseValueTypeObject(payload) {
- const typeFromObject = parseValueTypeConstant(payload.typeObject.type);
- if (!typeFromObject)
- return;
- const defaultValueType = parseValueTypeDefault(payload.typeObject.default);
- if (typeFromObject !== defaultValueType) {
- const propertyPath = payload.controller ? `${payload.controller}.${payload.token}` : payload.token;
- throw new Error(`The specified default value for the Stimulus Value "${propertyPath}" must match the defined type "${typeFromObject}". The provided default value of "${payload.typeObject.default}" is of type "${defaultValueType}".`);
- }
- return typeFromObject;
- }
- function parseValueTypeDefinition(payload) {
- const typeFromObject = parseValueTypeObject({
- controller: payload.controller,
- token: payload.token,
- typeObject: payload.typeDefinition
- });
- const typeFromDefaultValue = parseValueTypeDefault(payload.typeDefinition);
- const typeFromConstant = parseValueTypeConstant(payload.typeDefinition);
- const type = typeFromObject || typeFromDefaultValue || typeFromConstant;
- if (type)
- return type;
- const propertyPath = payload.controller ? `${payload.controller}.${payload.typeDefinition}` : payload.token;
- throw new Error(`Unknown value type "${propertyPath}" for "${payload.token}" value`);
- }
- function defaultValueForDefinition(typeDefinition) {
- const constant = parseValueTypeConstant(typeDefinition);
- if (constant)
- return defaultValuesByType[constant];
- const defaultValue = typeDefinition.default;
- if (defaultValue !== void 0)
- return defaultValue;
- return typeDefinition;
- }
- function valueDescriptorForTokenAndTypeDefinition(payload) {
- const key = `${dasherize(payload.token)}-value`;
- const type = parseValueTypeDefinition(payload);
- return {
- type,
- key,
- name: camelize(key),
- get defaultValue() {
- return defaultValueForDefinition(payload.typeDefinition);
- },
- get hasCustomDefaultValue() {
- return parseValueTypeDefault(payload.typeDefinition) !== void 0;
- },
- reader: readers[type],
- writer: writers[type] || writers.default
- };
- }
- var defaultValuesByType = {
- get array() {
- return [];
- },
- boolean: false,
- number: 0,
- get object() {
- return {};
- },
- string: ""
- };
- var readers = {
- array(value) {
- const array = JSON.parse(value);
- if (!Array.isArray(array)) {
- throw new TypeError(`expected value of type "array" but instead got value "${value}" of type "${parseValueTypeDefault(array)}"`);
- }
- return array;
- },
- boolean(value) {
- return !(value == "0" || String(value).toLowerCase() == "false");
- },
- number(value) {
- return Number(value);
- },
- object(value) {
- const object = JSON.parse(value);
- if (object === null || typeof object != "object" || Array.isArray(object)) {
- throw new TypeError(`expected value of type "object" but instead got value "${value}" of type "${parseValueTypeDefault(object)}"`);
- }
- return object;
- },
- string(value) {
- return value;
+ pageIsLoaded() {
+ return this.pageLoaded || document.readyState == "complete";
}
};
- var writers = {
- default: writeString,
- array: writeJSON,
- object: writeJSON
- };
- function writeJSON(value) {
- return JSON.stringify(value);
- }
- function writeString(value) {
- return `${value}`;
- }
- var Controller = class {
- constructor(context) {
- this.context = context;
+ var Navigator = class {
+ constructor(delegate) {
+ this.delegate = delegate;
}
- static get shouldLoad() {
- return true;
+ proposeVisit(location2, options = {}) {
+ if (this.delegate.allowsVisitingLocationWithAction(location2, options.action)) {
+ if (locationIsVisitable(location2, this.view.snapshot.rootLocation)) {
+ this.delegate.visitProposedToLocation(location2, options);
+ } else {
+ window.location.href = location2.toString();
+ }
+ }
}
- static afterLoad(_identifier, _application) {
- return;
+ startVisit(locatable, restorationIdentifier, options = {}) {
+ this.stop();
+ this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));
+ this.currentVisit.start();
}
- get application() {
- return this.context.application;
+ submitForm(form, submitter) {
+ this.stop();
+ this.formSubmission = new FormSubmission(this, form, submitter, true);
+ this.formSubmission.start();
}
- get scope() {
- return this.context.scope;
+ stop() {
+ if (this.formSubmission) {
+ this.formSubmission.stop();
+ delete this.formSubmission;
+ }
+ if (this.currentVisit) {
+ this.currentVisit.cancel();
+ delete this.currentVisit;
+ }
}
- get element() {
- return this.scope.element;
+ get adapter() {
+ return this.delegate.adapter;
}
- get identifier() {
- return this.scope.identifier;
+ get view() {
+ return this.delegate.view;
}
- get targets() {
- return this.scope.targets;
+ get history() {
+ return this.delegate.history;
}
- get outlets() {
- return this.scope.outlets;
+ formSubmissionStarted(formSubmission) {
+ if (typeof this.adapter.formSubmissionStarted === "function") {
+ this.adapter.formSubmissionStarted(formSubmission);
+ }
}
- get classes() {
- return this.scope.classes;
+ 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);
+ const visitOptions = {
+ action,
+ shouldCacheSnapshot,
+ response: { statusCode, responseHTML, redirected }
+ };
+ this.proposeVisit(fetchResponse.location, visitOptions);
+ }
+ }
}
- get data() {
- return this.scope.data;
+ 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);
+ }
+ this.view.scrollToTop();
+ this.view.clearSnapshotCache();
+ }
}
- initialize() {
+ formSubmissionErrored(formSubmission, error2) {
+ console.error(error2);
}
- connect() {
+ formSubmissionFinished(formSubmission) {
+ if (typeof this.adapter.formSubmissionFinished === "function") {
+ this.adapter.formSubmissionFinished(formSubmission);
+ }
}
- disconnect() {
+ visitStarted(visit2) {
+ this.delegate.visitStarted(visit2);
}
- dispatch(eventName, { target = this.element, detail = {}, prefix = this.identifier, bubbles = true, cancelable = true } = {}) {
- const type = prefix ? `${prefix}:${eventName}` : eventName;
- const event = new CustomEvent(type, { detail, bubbles, cancelable });
- target.dispatchEvent(event);
- return event;
+ visitCompleted(visit2) {
+ this.delegate.visitCompleted(visit2);
}
- };
- Controller.blessings = [
- ClassPropertiesBlessing,
- TargetPropertiesBlessing,
- ValuePropertiesBlessing,
- OutletPropertiesBlessing
- ];
- Controller.targets = [];
- Controller.outlets = [];
- Controller.values = {};
-
- // app/javascript/controllers/application.js
- var application = Application.start();
- application.debug = document.documentElement.classList.contains("debug");
- window.Stimulus = application;
-
- // app/javascript/controllers/modals/offer_modal_controller.js
- var offer_modal_controller_default = class extends Controller {
- connect() {
- const modal = document.querySelector(`.${this.classNameAttrValue}`);
- modal.classList.toggle("is-open");
- document.querySelector(".js-close-modal").addEventListener("click", function() {
- modal.classList.toggle("is-open");
- });
+ 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);
}
- };
- __publicField(offer_modal_controller_default, "values", {
- classNameAttr: String
- });
-
- // app/javascript/controllers/modals/modal_controller.js
- var modal_controller_default = class extends Controller {
- connect() {
- console.log("Modal connected");
+ visitScrolledToSamePageLocation(oldURL, newURL) {
+ this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
}
- open(event) {
- event.preventDefault();
- this.modalTarget.showModal();
- this.modalTarget.addEventListener("click", (e) => this.backdropClick(e));
- console.log("Modal opened");
+ get location() {
+ return this.history.location;
}
- close(event) {
- event.preventDefault();
- this.modalTarget.close();
- console.log("Modal close");
+ get restorationIdentifier() {
+ return this.history.restorationIdentifier;
}
- backdropClick(event) {
- event.target === this.modalTarget && this.close(event);
- console.log("Modal close");
+ getActionForFormSubmission({ submitter, formElement }) {
+ return getVisitAction(submitter, formElement) || "advance";
}
};
- __publicField(modal_controller_default, "targets", ["modal"]);
-
- // app/javascript/controllers/form/debounce_controller.js
- var debounce_controller_default = class extends Controller {
- connect() {
- }
- search() {
- clearTimeout(this.timeout);
- this.timeout = setTimeout(() => {
- this.formTarget.requestSubmit();
- }, 300);
- }
- };
- __publicField(debounce_controller_default, "targets", ["form"]);
-
- // app/javascript/controllers/form/filter_controller.js
- var filter_controller_default = class extends Controller {
- click(event) {
- const label = event.currentTarget;
- this.resetAll();
- label.classList.add("is-active");
- }
- resetAll() {
- this.buttonTargets.forEach((r) => r.checked = false);
- this.labelTargets.forEach((l) => l.classList.remove("is-active"));
- }
- };
- __publicField(filter_controller_default, "targets", ["button", "label"]);
-
- // app/javascript/controllers/form/autobider_submit_controller.js
- var autobider_submit_controller_default = class extends Controller {
- connect() {
- this.validatingInputPrice();
+ var PageStage;
+ (function(PageStage2) {
+ PageStage2[PageStage2["initial"] = 0] = "initial";
+ PageStage2[PageStage2["loading"] = 1] = "loading";
+ PageStage2[PageStage2["interactive"] = 2] = "interactive";
+ PageStage2[PageStage2["complete"] = 3] = "complete";
+ })(PageStage || (PageStage = {}));
+ var PageObserver = class {
+ constructor(delegate) {
+ this.stage = PageStage.initial;
+ this.started = false;
+ this.interpretReadyState = () => {
+ const { readyState } = this;
+ if (readyState == "interactive") {
+ this.pageIsInteractive();
+ } else if (readyState == "complete") {
+ this.pageIsComplete();
+ }
+ };
+ this.pageWillUnload = () => {
+ this.delegate.pageWillUnload();
+ };
+ this.delegate = delegate;
}
- disconnect() {
- if (this.timeout) {
- clearTimeout(this.timeout);
+ 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;
}
}
- submitAutobider() {
- clearTimeout(this.timeout);
- if (parseFloat(this.priceTarget.value) <= 5) {
- return;
+ stop() {
+ if (this.started) {
+ document.removeEventListener("readystatechange", this.interpretReadyState, false);
+ removeEventListener("pagehide", this.pageWillUnload, false);
+ this.started = false;
}
- this.timeout = setTimeout(() => {
- this.formTarget.requestSubmit();
- }, 300);
}
- validatePrice(event) {
- const char = event.key;
- const value = this.priceTarget.value;
- if (![".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Backspace", "Delete", "Tab", "Enter", "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"].includes(char) || char == "." && value.includes(".")) {
- event.preventDefault();
+ pageIsInteractive() {
+ if (this.stage == PageStage.loading) {
+ this.stage = PageStage.interactive;
+ this.delegate.pageBecameInteractive();
}
}
- validatingInputPrice() {
- if (parseFloat(this.priceTarget.value) <= 5) {
- this.checkboxTarget.disabled = true;
- } else {
- this.checkboxTarget.disabled = false;
+ pageIsComplete() {
+ this.pageIsInteractive();
+ if (this.stage == PageStage.interactive) {
+ this.stage = PageStage.complete;
+ this.delegate.pageLoaded();
}
}
- };
- __publicField(autobider_submit_controller_default, "targets", ["form", "price", "checkbox"]);
-
- // app/javascript/controllers/form/bundle_checkbox_controller.js
- var bundle_checkbox_controller_default = class extends Controller {
- collect_ids() {
- if (this.hasCheckboxesTarget == false)
- return;
- const regx = /\d+/;
- this.hiddenFieldTarget.value = "";
- this.checkboxesTargets.forEach((el) => {
- if (el.checked == false)
- return;
- const element_id = el.id;
- this.hiddenFieldTarget.value += ` ${element_id.match(regx)}`;
- });
+ get readyState() {
+ return document.readyState;
}
};
- __publicField(bundle_checkbox_controller_default, "targets", ["hiddenField", "checkboxes"]);
-
- // app/javascript/controllers/form/checkbox_toggle_controller.js
- var checkbox_toggle_controller_default = class extends Controller {
- connect() {
- this.enableDepositTarget.addEventListener("click", (source) => {
- this.disableDepositTarget.checked = false;
- });
- this.disableDepositTarget.addEventListener("click", (source) => {
- this.enableDepositTarget.checked = false;
- });
+ var ScrollObserver = class {
+ constructor(delegate) {
+ this.started = false;
+ this.onScroll = () => {
+ this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
+ };
+ this.delegate = delegate;
}
- };
- __publicField(checkbox_toggle_controller_default, "targets", ["enableDeposit", "disableDeposit"]);
-
- // node_modules/@rails/request.js/src/fetch_response.js
- var FetchResponse = class {
- constructor(response) {
- this.response = response;
+ start() {
+ if (!this.started) {
+ addEventListener("scroll", this.onScroll, false);
+ this.onScroll();
+ this.started = true;
+ }
}
- get statusCode() {
- return this.response.status;
+ stop() {
+ if (this.started) {
+ removeEventListener("scroll", this.onScroll, false);
+ this.started = false;
+ }
}
- get redirected() {
- return this.response.redirected;
+ updatePosition(position) {
+ this.delegate.scrollPositionChanged(position);
}
- get ok() {
- return this.response.ok;
+ };
+ var StreamMessageRenderer = class {
+ render({ fragment }) {
+ Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => document.documentElement.appendChild(fragment));
}
- get unauthenticated() {
- return this.statusCode === 401;
+ enteringBardo(currentPermanentElement, newPermanentElement) {
+ newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
}
- get unprocessableEntity() {
- return this.statusCode === 422;
+ leavingBardo() {
}
- get authenticationURL() {
- return this.response.headers.get("WWW-Authenticate");
+ };
+ 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];
+ }
+ }
}
- get contentType() {
- const contentType = this.response.headers.get("Content-Type") || "";
- return contentType.replace(/;.*$/, "");
+ return permanentElementMap;
+ }
+ var StreamObserver = class {
+ constructor(delegate) {
+ this.sources = /* @__PURE__ */ new Set();
+ this.started = false;
+ this.inspectFetchResponse = (event) => {
+ const response = fetchResponseFromEvent(event);
+ if (response && fetchResponseIsStream(response)) {
+ event.preventDefault();
+ this.receiveMessageResponse(response);
+ }
+ };
+ this.receiveMessageEvent = (event) => {
+ if (this.started && typeof event.data == "string") {
+ this.receiveMessageHTML(event.data);
+ }
+ };
+ this.delegate = delegate;
}
- get headers() {
- return this.response.headers;
+ start() {
+ if (!this.started) {
+ this.started = true;
+ addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
+ }
}
- get html() {
- if (this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)) {
- return this.text;
+ stop() {
+ if (this.started) {
+ this.started = false;
+ removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
}
- return Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`));
}
- get json() {
- if (this.contentType.match(/^application\/.*json$/)) {
- return this.responseJson || (this.responseJson = this.response.json());
+ connectStreamSource(source) {
+ if (!this.streamSourceIsConnected(source)) {
+ this.sources.add(source);
+ source.addEventListener("message", this.receiveMessageEvent, false);
}
- return Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`));
}
- get text() {
- return this.responseText || (this.responseText = this.response.text());
+ disconnectStreamSource(source) {
+ if (this.streamSourceIsConnected(source)) {
+ this.sources.delete(source);
+ source.removeEventListener("message", this.receiveMessageEvent, false);
+ }
}
- get isTurboStream() {
- return this.contentType.match(/^text\/vnd\.turbo-stream\.html/);
+ streamSourceIsConnected(source) {
+ return this.sources.has(source);
}
- async renderTurboStream() {
- if (this.isTurboStream) {
- if (window.Turbo) {
- await window.Turbo.renderStreamMessage(await this.text);
- } else {
- console.warn("You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js");
- }
- } else {
- return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`));
+ async receiveMessageResponse(response) {
+ const html = await response.responseHTML;
+ if (html) {
+ this.receiveMessageHTML(html);
}
}
- };
-
- // node_modules/@rails/request.js/src/request_interceptor.js
- var RequestInterceptor = class {
- static register(interceptor) {
- this.interceptor = interceptor;
- }
- static get() {
- return this.interceptor;
- }
- static reset() {
- this.interceptor = void 0;
+ receiveMessageHTML(html) {
+ this.delegate.receivedMessageFromStream(StreamMessage.wrap(html));
}
};
-
- // node_modules/@rails/request.js/src/lib/utils.js
- function getCookie(name) {
- const cookies = document.cookie ? document.cookie.split("; ") : [];
- const prefix = `${encodeURIComponent(name)}=`;
- const cookie = cookies.find((cookie2) => cookie2.startsWith(prefix));
- if (cookie) {
- const value = cookie.split("=").slice(1).join("=");
- if (value) {
- return decodeURIComponent(value);
- }
- }
- }
- function compact(object) {
- const result = {};
- for (const key in object) {
- const value = object[key];
- if (value !== void 0) {
- result[key] = value;
- }
+ function fetchResponseFromEvent(event) {
+ var _a;
+ const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;
+ if (fetchResponse instanceof FetchResponse) {
+ return fetchResponse;
}
- return result;
- }
- function metaContent(name) {
- const element = document.head.querySelector(`meta[name="${name}"]`);
- return element && element.content;
}
- function stringEntriesFromFormData(formData) {
- return [...formData].reduce((entries, [name, value]) => {
- return entries.concat(typeof value === "string" ? [[name, value]] : []);
- }, []);
+ function fetchResponseIsStream(response) {
+ var _a;
+ const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
+ return contentType.startsWith(StreamMessage.contentType);
}
- function mergeEntries(searchParams, entries) {
- for (const [name, value] of entries) {
- if (value instanceof window.File)
- continue;
- if (searchParams.has(name) && !name.includes("[]")) {
- searchParams.delete(name);
- searchParams.set(name, value);
- } else {
- searchParams.append(name, value);
- }
+ var ErrorRenderer = class extends Renderer {
+ static renderElement(currentElement, newElement) {
+ const { documentElement, body } = document;
+ documentElement.replaceChild(newElement, body);
}
- }
-
- // node_modules/@rails/request.js/src/fetch_request.js
- var FetchRequest = class {
- constructor(method, url, options = {}) {
- this.method = method;
- this.options = options;
- this.originalUrl = url.toString();
+ async render() {
+ this.replaceHeadAndBody();
+ this.activateScriptElements();
}
- async perform() {
- try {
- const requestInterceptor = RequestInterceptor.get();
- if (requestInterceptor) {
- await requestInterceptor(this);
+ 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);
}
- } catch (error2) {
- console.error(error2);
- }
- const response = new FetchResponse(await window.fetch(this.url, this.fetchOptions));
- if (response.unauthenticated && response.authenticationURL) {
- return Promise.reject(window.location.href = response.authenticationURL);
- }
- if (response.ok && response.isTurboStream) {
- await response.renderTurboStream();
}
- return response;
- }
- addHeader(key, value) {
- const headers = this.additionalHeaders;
- headers[key] = value;
- this.options.headers = headers;
}
- sameHostname() {
- if (!this.originalUrl.startsWith("http:")) {
- return true;
- }
- try {
- return new URL(this.originalUrl).hostname === window.location.hostname;
- } catch (_) {
- return true;
- }
+ get newHead() {
+ return this.newSnapshot.headSnapshot.element;
}
- get fetchOptions() {
- return {
- method: this.method.toUpperCase(),
- headers: this.headers,
- body: this.formattedBody,
- signal: this.signal,
- credentials: "same-origin",
- redirect: this.redirect
- };
+ get scriptElements() {
+ return document.documentElement.querySelectorAll("script");
}
- get headers() {
- const baseHeaders = {
- "X-Requested-With": "XMLHttpRequest",
- "Content-Type": this.contentType,
- Accept: this.accept
- };
- if (this.sameHostname()) {
- baseHeaders["X-CSRF-Token"] = this.csrfToken;
+ };
+ var PageRenderer = class extends Renderer {
+ static renderElement(currentElement, newElement) {
+ if (document.body && newElement instanceof HTMLBodyElement) {
+ document.body.replaceWith(newElement);
+ } else {
+ document.documentElement.appendChild(newElement);
}
- return compact(
- Object.assign(baseHeaders, this.additionalHeaders)
- );
}
- get csrfToken() {
- return getCookie(metaContent("csrf-param")) || metaContent("csrf-token");
+ get shouldRender() {
+ return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
}
- get contentType() {
- if (this.options.contentType) {
- return this.options.contentType;
- } else if (this.body == null || this.body instanceof window.FormData) {
- return void 0;
- } else if (this.body instanceof window.File) {
- return this.body.type;
+ get reloadReason() {
+ if (!this.newSnapshot.isVisitable) {
+ return {
+ reason: "turbo_visit_control_is_reload"
+ };
}
- return "application/json";
- }
- get accept() {
- switch (this.responseKind) {
- case "html":
- return "text/html, application/xhtml+xml";
- case "turbo-stream":
- return "text/vnd.turbo-stream.html, text/html, application/xhtml+xml";
- case "json":
- return "application/json, application/vnd.api+json";
- default:
- return "*/*";
+ if (!this.trackedElementsAreIdentical) {
+ return {
+ reason: "tracked_element_mismatch"
+ };
}
}
- get body() {
- return this.options.body;
+ async prepareToRender() {
+ await this.mergeHead();
}
- get query() {
- const originalQuery = (this.originalUrl.split("?")[1] || "").split("#")[0];
- const params = new URLSearchParams(originalQuery);
- let requestQuery = this.options.query;
- if (requestQuery instanceof window.FormData) {
- requestQuery = stringEntriesFromFormData(requestQuery);
- } else if (requestQuery instanceof window.URLSearchParams) {
- requestQuery = requestQuery.entries();
- } else {
- requestQuery = Object.entries(requestQuery || {});
+ async render() {
+ if (this.willRender) {
+ await this.replaceBody();
}
- mergeEntries(params, requestQuery);
- const query = params.toString();
- return query.length > 0 ? `?${query}` : "";
}
- get url() {
- return this.originalUrl.split("?")[0].split("#")[0] + this.query;
+ finishRendering() {
+ super.finishRendering();
+ if (!this.isPreview) {
+ this.focusFirstAutofocusableElement();
+ }
}
- get responseKind() {
- return this.options.responseKind || "html";
+ get currentHeadSnapshot() {
+ return this.currentSnapshot.headSnapshot;
}
- get signal() {
- return this.options.signal;
+ get newHeadSnapshot() {
+ return this.newSnapshot.headSnapshot;
}
- get redirect() {
- return this.options.redirect || "follow";
+ get newElement() {
+ return this.newSnapshot.element;
}
- get additionalHeaders() {
- return this.options.headers || {};
+ async mergeHead() {
+ const mergedHeadElements = this.mergeProvisionalElements();
+ const newStylesheetElements = this.copyNewHeadStylesheetElements();
+ this.copyNewHeadScriptElements();
+ await mergedHeadElements;
+ await newStylesheetElements;
}
- get formattedBody() {
- const bodyIsAString = Object.prototype.toString.call(this.body) === "[object String]";
- const contentTypeIsJson = this.headers["Content-Type"] === "application/json";
- if (contentTypeIsJson && !bodyIsAString) {
- return JSON.stringify(this.body);
- }
- return this.body;
+ async replaceBody() {
+ await this.preservingPermanentElements(async () => {
+ this.activateNewBody();
+ await this.assignNewBody();
+ });
}
- };
-
- // app/javascript/controllers/form/checkbox_autosubmit_controller.js
- var checkbox_autosubmit_controller_default = class extends Controller {
- submit() {
- clearTimeout(this.timeout);
- this.timeout = setTimeout(() => {
- this.performRequest();
- }, 300);
+ get trackedElementsAreIdentical() {
+ return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;
}
- disconnect() {
- if (this.timeout) {
- clearTimeout(this.timeout);
+ async copyNewHeadStylesheetElements() {
+ const loadingElements = [];
+ for (const element of this.newHeadStylesheetElements) {
+ loadingElements.push(waitForLoad(element));
+ document.head.appendChild(element);
}
+ await Promise.all(loadingElements);
}
- performRequest() {
- const originalState = this.checkboxTarget.checked;
- const request = new FetchRequest("PATCH", this.urlValue, {
- headers: { responseKind: "turbo-stream", accept: "text/vnd.turbo-stream.html" },
- body: new FormData(this.checkboxTarget.form)
- });
- const response = request.perform();
- if (!response.ok) {
- this.checkboxTarget.checked = !originalState;
- console.error("Failed to update user profile", response);
+ copyNewHeadScriptElements() {
+ for (const element of this.newHeadScriptElements) {
+ document.head.appendChild(activateScriptElement(element));
}
}
- };
- __publicField(checkbox_autosubmit_controller_default, "targets", ["checkbox"]);
- __publicField(checkbox_autosubmit_controller_default, "values", { url: String });
-
- // app/javascript/controllers/form/autosave_controller.js
- var autosave_controller_default = class extends Controller {
- connect() {
- this.selectValue = this.selectTarget.value;
- }
- save() {
- if (confirm("Are you sure?") == true) {
- this.formTarget.requestSubmit();
- } else {
- this.selectTarget.value = this.selectValue;
+ async mergeProvisionalElements() {
+ const newHeadElements = [...this.newHeadProvisionalElements];
+ for (const element of this.currentHeadProvisionalElements) {
+ if (!this.isCurrentElementInElementList(element, newHeadElements)) {
+ document.head.removeChild(element);
+ }
+ }
+ for (const element of newHeadElements) {
+ document.head.appendChild(element);
}
}
- };
- __publicField(autosave_controller_default, "targets", ["form", "select"]);
- __publicField(autosave_controller_default, "values", {
- select: String
- });
-
- // app/javascript/controllers/table/ordeable_controller.js
- var ordeable_controller_default = class extends Controller {
- initialize() {
- this.classHandle = this.classHandle.bind(this);
+ isCurrentElementInElementList(element, elementList) {
+ for (const [index, newElement] of elementList.entries()) {
+ if (element.tagName == "TITLE") {
+ if (newElement.tagName != "TITLE") {
+ continue;
+ }
+ if (element.innerHTML == newElement.innerHTML) {
+ elementList.splice(index, 1);
+ return true;
+ }
+ }
+ if (newElement.isEqualNode(element)) {
+ elementList.splice(index, 1);
+ return true;
+ }
+ }
+ return false;
}
- resortTable(_event) {
- Turbo.visit("?sort_by=" + this.columnValue + "&sort_direction=" + this.directionValue, { frame: this.frameNameValue });
+ removeCurrentHeadProvisionalElements() {
+ for (const element of this.currentHeadProvisionalElements) {
+ document.head.removeChild(element);
+ }
}
- directionValueChanged() {
- this.classHandle();
+ copyNewHeadProvisionalElements() {
+ for (const element of this.newHeadProvisionalElements) {
+ document.head.appendChild(element);
+ }
}
- columnValueChanged() {
- this.classHandle();
+ activateNewBody() {
+ document.adoptNode(this.newElement);
+ this.activateNewBodyScriptElements();
}
- classHandle() {
- if (this.directionValue == "asc") {
- this.thTarget.classList.remove(this.ascClass);
- this.thTarget.classList.add(this.descClass);
- } else if (this.directionValue == "desc") {
- this.thTarget.classList.add(this.ascClass);
- this.thTarget.classList.remove(this.descClass);
- } else {
- this.thTarget.classList.remove(this.ascClass);
- this.thTarget.classList.remove(this.descClass);
+ activateNewBodyScriptElements() {
+ for (const inertScriptElement of this.newBodyScriptElements) {
+ const activatedScriptElement = activateScriptElement(inertScriptElement);
+ inertScriptElement.replaceWith(activatedScriptElement);
}
}
- };
- __publicField(ordeable_controller_default, "values", { direction: String, column: String, frameName: String });
- __publicField(ordeable_controller_default, "targets", ["th"]);
- __publicField(ordeable_controller_default, "classes", ["asc", "desc"]);
-
- // app/javascript/controllers/table/tab_controller.js
- var tab_controller_default = class extends Controller {
- initialize() {
- this.showTab = this.showTab.bind(this);
+ async assignNewBody() {
+ await this.renderElement(this.currentElement, this.newElement);
}
- showTab(event) {
- const index = event.params.index;
- this.tabTargets.forEach((tab) => {
- tab.classList.remove(this.activeClass);
- });
- this.contentTargets.forEach((content) => {
- content.classList.remove(this.activeClass);
- });
- this.tabTargets[index].classList.add(this.activeClass);
- this.contentTargets[index].classList.add(this.activeClass);
+ get newHeadStylesheetElements() {
+ return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
}
- };
- __publicField(tab_controller_default, "targets", ["tab", "content"]);
- __publicField(tab_controller_default, "classes", ["active"]);
-
- // app/javascript/controllers/autotax_counter_controller.js
- var autotax_counter_controller_default = class extends Controller {
- connect() {
- this.updateTax();
+ get newHeadScriptElements() {
+ return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot);
}
- count(event) {
- const value = parseFloat(event.target.value);
- const result = this.resultTarget;
- if (!isNaN(value) && value > 0) {
- const tax = parseFloat(this.taxValue) || 0;
- const taxAmount = value * tax;
- const totalAmount = value + taxAmount;
- result.innerHTML = this.templateValue.replace("{price}", totalAmount.toFixed(2)).replace("{tax}", (tax * 100).toFixed(2));
- } else {
- result.innerHTML = this.defaulttemplateValue;
- }
+ get currentHeadProvisionalElements() {
+ return this.currentHeadSnapshot.provisionalElements;
}
- updateTax(event) {
- let selectElement = this.element.querySelector("select");
- this.taxValue = selectElement.options[selectElement.selectedIndex].dataset.vatRate || 0;
- const priceElement = this.element.querySelector('[name="offer[price]"]');
- this.count({ target: priceElement });
+ get newHeadProvisionalElements() {
+ return this.newHeadSnapshot.provisionalElements;
}
- };
- __publicField(autotax_counter_controller_default, "targets", ["result"]);
- __publicField(autotax_counter_controller_default, "values", {
- tax: String,
- template: String,
- defaulttemplate: String
- });
-
- // app/javascript/controllers/english_offers_controller.js
- var english_offers_controller_default = class extends Controller {
- beforeStreamRender(e) {
- var content = e.target.templateElement.content;
- var currentPrice = content.querySelector(".current_price");
- var auctionRow = content.querySelector(".auctions-table-row");
- if (currentPrice) {
- let offerUserId = currentPrice.dataset.userId;
- let you = currentPrice.dataset.you;
- if (this.values.userId === offerUserId) {
- currentPrice.style.color = "green";
- var currentPriceWrapper = document.getElementById("current_price_wrapper");
- currentPriceWrapper.style.color = "green";
- currentPriceWrapper.className = "";
- currentPrice.querySelector(".bidder").textContent = "(" + you + ")";
- } else {
- currentPrice.style.color = "red";
- var currentPriceWrapper = document.getElementById("current_price_wrapper");
- currentPriceWrapper.style.color = "red";
- currentPriceWrapper.className = "";
- }
- }
- if (auctionRow) {
- let platform = auctionRow.dataset.platform;
- auctionRow.querySelector(".bid_button").textContent = this.values.bidText;
- auctionRow.querySelector(".auction_platform").textContent = this.values[platform + "Text"];
- }
+ get newBodyScriptElements() {
+ return this.newElement.querySelectorAll("script");
}
};
- __publicField(english_offers_controller_default, "values", {
- userId: String,
- decimalMark: String,
- bidText: String,
- participateText: String,
- englishText: String,
- blindText: String
- });
-
- // app/javascript/controllers/countdown_controller.js
- var countdown_controller_default = class extends Controller {
- connect() {
- if (this.dateValue) {
- this.endTime = new Date(this.dateValue).getTime();
- this.update();
- this.timer = setInterval(() => {
- this.update();
- }, this.refreshIntervalValue);
- } else {
- console.log("Missing data-countdown-date-value attribute", this.element);
- }
+ var SnapshotCache = class {
+ constructor(size) {
+ this.keys = [];
+ this.snapshots = {};
+ this.size = size;
}
- disconnect() {
- this.stopTimer();
+ has(location2) {
+ return toCacheKey(location2) in this.snapshots;
}
- stopTimer() {
- if (this.timer) {
- clearInterval(this.timer);
+ get(location2) {
+ if (this.has(location2)) {
+ const snapshot = this.read(location2);
+ this.touch(location2);
+ return snapshot;
}
}
- update() {
- let difference = this.timeDifference();
- if (difference < 0) {
- var expiredMsg = $("#timer_message").data("expiredMessage");
- $("#timer_message").html(expiredMsg);
- this.stopTimer();
- return;
- }
- let days = Math.floor(difference / (1e3 * 60 * 60 * 24));
- let hours = Math.floor(difference % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
- let minutes = Math.floor(difference % (1e3 * 60 * 60) / (1e3 * 60));
- let seconds = Math.floor(difference % (1e3 * 60) / 1e3);
- this.element.innerHTML = this.messageTimerValue.replace("${days}", days).replace("${hours}", hours).replace("${minutes}", minutes).replace("${seconds}", seconds);
+ put(location2, snapshot) {
+ this.write(location2, snapshot);
+ this.touch(location2);
+ return snapshot;
}
- timeDifference() {
- return this.endTime - new Date().getTime();
+ clear() {
+ this.snapshots = {};
}
- };
- __publicField(countdown_controller_default, "values", {
- date: String,
- refreshInterval: { type: Number, default: 1e3 },
- messageTimer: { type: String, default: "${days}d ${hours}h ${minutes}m ${seconds}s" }
- });
-
- // app/javascript/controllers/profile_webpush_controller.js
- var profile_webpush_controller_default = class extends Controller {
- connect() {
- console.log("webpush connected!");
- if ("serviceWorker" in navigator && "PushManager" in window) {
- navigator.serviceWorker.ready.then(
- (registration) => {
- registration.pushManager.getSubscription().then(
- (subscription) => {
- if (subscription) {
- this.checkboxTarget.style.disabled = true;
- this.checkboxTarget.classList.add("disabled");
- }
- }
- );
- }
- );
- }
+ read(location2) {
+ return this.snapshots[toCacheKey(location2)];
}
- setupPushNotifications() {
- console.log("webpush action!");
- const applicationServerKey2 = this.urlBase64ToUint8Array(this.vapidPublicValue);
- navigator.serviceWorker.register("/service-worker.js", { scope: "./" }).then((registration) => {
- registration.pushManager.subscribe({
- userVisibleOnly: true,
- applicationServerKey: applicationServerKey2
- }).then((subscription) => {
- const endpoint = subscription.endpoint;
- const p256dh = btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey("p256dh"))));
- const auth = btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey("auth"))));
- fetch("/push_subscriptions", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').getAttribute("content")
- },
- body: JSON.stringify({
- subscription: {
- endpoint,
- p256dh,
- auth
- }
- })
- });
- localStorage.setItem("block-webpush-modal", "true");
- document.querySelector(".webpush-modal").style.display = "none";
- this.checkboxTarget.style.disabled = true;
- this.checkboxTarget.classList.add("disabled");
- });
- });
+ write(location2, snapshot) {
+ this.snapshots[toCacheKey(location2)] = snapshot;
}
- };
- __publicField(profile_webpush_controller_default, "values", {
- vapidPublic: String
- });
- __publicField(profile_webpush_controller_default, "targets", ["checkbox"]);
-
- // app/javascript/controllers/push_notification_controller.js
- var push_notification_controller_default = class extends Controller {
- connect() {
- if (!this.userLoginValue)
- return;
- let subscribed = localStorage.getItem("block-webpush-modal");
- if (subscribed === "true") {
- document.querySelector(".webpush-modal").style.display = "none";
- }
- if ("serviceWorker" in navigator && "PushManager" in window) {
- navigator.serviceWorker.ready.then(
- (registration) => {
- registration.pushManager.getSubscription().then(
- (subscription) => {
- if (!subscription) {
- if (Notification.permission === "granted") {
- this.setupPushNotifications();
- } else {
- this.requestPermission();
- }
- }
- }
- );
- }
- );
+ touch(location2) {
+ const key = toCacheKey(location2);
+ const index = this.keys.indexOf(key);
+ if (index > -1)
+ this.keys.splice(index, 1);
+ this.keys.unshift(key);
+ this.trim();
+ }
+ trim() {
+ for (const key of this.keys.splice(this.size)) {
+ delete this.snapshots[key];
}
}
- requestPermission() {
- window.addEventListener("load", () => {
- Notification.requestPermission().then((permission) => {
- if (permission === "granted") {
- this.setupPushNotifications(applicationServerKey);
- }
- });
- });
+ };
+ var PageView = class extends View {
+ constructor() {
+ super(...arguments);
+ this.snapshotCache = new SnapshotCache(10);
+ this.lastRenderedLocation = new URL(location.href);
+ this.forceReloaded = false;
}
- setupPushNotifications() {
- const applicationServerKey2 = this.urlBase64ToUint8Array(this.vapidPublicValue);
- console.log(this.vapidPublicValue);
- navigator.serviceWorker.register("/service-worker.js", { scope: "./" }).then((registration) => {
- console.log("Service Worker registered successfully:", registration);
- registration.pushManager.subscribe({
- userVisibleOnly: true,
- applicationServerKey: applicationServerKey2
- }).then((subscription) => {
- const endpoint = subscription.endpoint;
- const p256dh = btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey("p256dh"))));
- const auth = btoa(String.fromCharCode.apply(null, new Uint8Array(subscription.getKey("auth"))));
- fetch("/push_subscriptions", {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- "X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').getAttribute("content")
- },
- body: JSON.stringify({
- subscription: {
- endpoint,
- p256dh,
- auth
- }
- })
- });
- localStorage.setItem("block-webpush-modal", "true");
- document.querySelector(".webpush-modal").style.display = "none";
- });
- }).catch((err) => {
- console.log("Service Worker registration failed:", err);
- });
- ;
+ renderPage(snapshot, isPreview = false, willRender = true, visit2) {
+ const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
+ if (!renderer.shouldRender) {
+ this.forceReloaded = true;
+ } else {
+ visit2 === null || visit2 === void 0 ? void 0 : visit2.changeHistory();
+ }
+ return this.render(renderer);
}
- close() {
- document.querySelector(".webpush-modal").style.display = "none";
+ renderError(snapshot, visit2) {
+ visit2 === null || visit2 === void 0 ? void 0 : visit2.changeHistory();
+ const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
+ return this.render(renderer);
}
- decline() {
- localStorage.setItem("block-webpush-modal", "true");
- document.querySelector(".webpush-modal").style.display = "none";
+ clearSnapshotCache() {
+ this.snapshotCache.clear();
}
- urlBase64ToUint8Array(base64String) {
- var padding = "=".repeat((4 - base64String.length % 4) % 4);
- var base64 = (base64String + padding).replace(/\-/g, "+").replace(/_/g, "/");
- var rawData = window.atob(base64);
- var outputArray = new Uint8Array(rawData.length);
- for (var i = 0; i < rawData.length; ++i) {
- outputArray[i] = rawData.charCodeAt(i);
+ async cacheSnapshot(snapshot = this.snapshot) {
+ if (snapshot.isCacheable) {
+ this.delegate.viewWillCacheSnapshot();
+ const { lastRenderedLocation: location2 } = this;
+ await nextEventLoopTick();
+ const cachedSnapshot = snapshot.clone();
+ this.snapshotCache.put(location2, cachedSnapshot);
+ return cachedSnapshot;
}
- return outputArray;
+ }
+ getCachedSnapshotForLocation(location2) {
+ return this.snapshotCache.get(location2);
+ }
+ get snapshot() {
+ return PageSnapshot.fromElement(this.element);
}
};
- __publicField(push_notification_controller_default, "values", {
- vapidPublic: String,
- userLogin: Boolean
- });
-
- // app/javascript/controllers/index.js
- application.register("modals--offer-modal", offer_modal_controller_default);
- application.register("modals--modal", modal_controller_default);
- application.register("form--debounce", debounce_controller_default);
- application.register("form--filter", filter_controller_default);
- application.register("form--autobider-submit", autobider_submit_controller_default);
- application.register("form--bundle-checkbox", bundle_checkbox_controller_default);
- application.register("form--checkbox-toggle", checkbox_toggle_controller_default);
- application.register("form--checkbox-autosubmit", checkbox_autosubmit_controller_default);
- application.register("form--autosave", autosave_controller_default);
- application.register("table--ordeable", ordeable_controller_default);
- application.register("table--tab", tab_controller_default);
- application.register("autotax-counter", autotax_counter_controller_default);
- application.register("english-offer", english_offers_controller_default);
- application.register("countdown", countdown_controller_default);
- application.register("profile-webpush", profile_webpush_controller_default);
- application.register("push-notification", push_notification_controller_default);
-
- // node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js
- (function() {
- if (window.Reflect === void 0 || window.customElements === void 0 || window.customElements.polyfillWrapFlushCallback) {
- return;
+ var Preloader = class {
+ constructor(delegate) {
+ this.selector = "a[data-turbo-preload]";
+ this.delegate = delegate;
}
- const BuiltInHTMLElement = HTMLElement;
- const wrapperForTheName = {
- HTMLElement: function HTMLElement2() {
- return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
- }
- };
- window.HTMLElement = wrapperForTheName["HTMLElement"];
- HTMLElement.prototype = BuiltInHTMLElement.prototype;
- HTMLElement.prototype.constructor = HTMLElement;
- Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
- })();
- (function(prototype) {
- if (typeof prototype.requestSubmit == "function")
- return;
- prototype.requestSubmit = function(submitter) {
- if (submitter) {
- validateSubmitter(submitter, this);
- submitter.click();
+ get snapshotCache() {
+ return this.delegate.navigator.view.snapshotCache;
+ }
+ start() {
+ if (document.readyState === "loading") {
+ return document.addEventListener("DOMContentLoaded", () => {
+ this.preloadOnLoadLinksForView(document.body);
+ });
} else {
- submitter = document.createElement("input");
- submitter.type = "submit";
- submitter.hidden = true;
- this.appendChild(submitter);
- submitter.click();
- this.removeChild(submitter);
+ this.preloadOnLoadLinksForView(document.body);
}
- };
- 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);
+ preloadOnLoadLinksForView(element) {
+ for (const link of element.querySelectorAll(this.selector)) {
+ this.preloadURL(link);
+ }
}
- })(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 === null || candidate === void 0 ? void 0 : 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 && /Apple Computer/.test(navigator.vendor)) {
- prototype = window.SubmitEvent.prototype;
- } else if ("SubmitEvent" in window) {
- return;
- }
- addEventListener("click", clickCaptured, true);
- Object.defineProperty(prototype, "submitter", {
- get() {
- if (this.type == "submit" && this.target instanceof HTMLFormElement) {
- return submittersByForm.get(this.target);
- }
+ async preloadURL(link) {
+ const location2 = new URL(link.href);
+ if (this.snapshotCache.has(location2)) {
+ return;
+ }
+ try {
+ const response = await fetch(location2.toString(), { headers: { "VND.PREFETCH": "true", Accept: "text/html" } });
+ const responseText = await response.text();
+ const snapshot = PageSnapshot.fromHTMLString(responseText);
+ this.snapshotCache.put(location2, snapshot);
+ } catch (_) {
}
- });
- })();
- var FrameLoadingStyle;
- (function(FrameLoadingStyle2) {
- FrameLoadingStyle2["eager"] = "eager";
- FrameLoadingStyle2["lazy"] = "lazy";
- })(FrameLoadingStyle || (FrameLoadingStyle = {}));
- var FrameElement = class extends HTMLElement {
- static get observedAttributes() {
- return ["disabled", "complete", "loading", "src"];
}
+ };
+ var Session = class {
constructor() {
- super();
- this.loaded = Promise.resolve();
- this.delegate = new FrameElement.delegateConstructor(this);
- }
- connectedCallback() {
- this.delegate.connect();
+ this.navigator = new Navigator(this);
+ this.history = new History(this);
+ this.preloader = new Preloader(this);
+ this.view = new PageView(this, document.documentElement);
+ this.adapter = new BrowserAdapter(this);
+ this.pageObserver = new PageObserver(this);
+ this.cacheObserver = new CacheObserver();
+ this.linkClickObserver = new LinkClickObserver(this, window);
+ this.formSubmitObserver = new FormSubmitObserver(this, document);
+ this.scrollObserver = new ScrollObserver(this);
+ this.streamObserver = new StreamObserver(this);
+ this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
+ this.frameRedirector = new FrameRedirector(this, document.documentElement);
+ this.streamMessageRenderer = new StreamMessageRenderer();
+ this.drive = true;
+ this.enabled = true;
+ this.progressBarDelay = 500;
+ this.started = false;
+ this.formMode = "on";
}
- disconnectedCallback() {
- this.delegate.disconnect();
+ start() {
+ if (!this.started) {
+ this.pageObserver.start();
+ this.cacheObserver.start();
+ this.formLinkClickObserver.start();
+ this.linkClickObserver.start();
+ this.formSubmitObserver.start();
+ this.scrollObserver.start();
+ this.streamObserver.start();
+ this.frameRedirector.start();
+ this.history.start();
+ this.preloader.start();
+ this.started = true;
+ this.enabled = true;
+ }
}
- reload() {
- return this.delegate.sourceURLReloaded();
+ disable() {
+ this.enabled = false;
}
- attributeChangedCallback(name) {
- if (name == "loading") {
- this.delegate.loadingStyleChanged();
- } else if (name == "complete") {
- this.delegate.completeChanged();
- } else if (name == "src") {
- this.delegate.sourceURLChanged();
- } else {
- this.delegate.disabledChanged();
+ stop() {
+ if (this.started) {
+ this.pageObserver.stop();
+ this.cacheObserver.stop();
+ this.formLinkClickObserver.stop();
+ this.linkClickObserver.stop();
+ this.formSubmitObserver.stop();
+ this.scrollObserver.stop();
+ this.streamObserver.stop();
+ this.frameRedirector.stop();
+ this.history.stop();
+ this.started = false;
}
}
- get src() {
- return this.getAttribute("src");
+ registerAdapter(adapter) {
+ this.adapter = adapter;
}
- set src(value) {
- if (value) {
- this.setAttribute("src", value);
+ visit(location2, options = {}) {
+ const frameElement = options.frame ? document.getElementById(options.frame) : null;
+ if (frameElement instanceof FrameElement) {
+ frameElement.src = location2.toString();
+ frameElement.loaded;
} else {
- this.removeAttribute("src");
+ this.navigator.proposeVisit(expandURL(location2), options);
}
}
- get loading() {
- return frameLoadingStyleFromString(this.getAttribute("loading") || "");
+ connectStreamSource(source) {
+ this.streamObserver.connectStreamSource(source);
}
- set loading(value) {
- if (value) {
- this.setAttribute("loading", value);
- } else {
- this.removeAttribute("loading");
- }
+ disconnectStreamSource(source) {
+ this.streamObserver.disconnectStreamSource(source);
}
- get disabled() {
- return this.hasAttribute("disabled");
+ renderStreamMessage(message) {
+ this.streamMessageRenderer.render(StreamMessage.wrap(message));
}
- set disabled(value) {
- if (value) {
- this.setAttribute("disabled", "");
+ clearCache() {
+ this.view.clearSnapshotCache();
+ }
+ setProgressBarDelay(delay) {
+ this.progressBarDelay = delay;
+ }
+ setFormMode(mode) {
+ this.formMode = mode;
+ }
+ get location() {
+ return this.history.location;
+ }
+ get restorationIdentifier() {
+ return this.history.restorationIdentifier;
+ }
+ historyPoppedToLocationWithRestorationIdentifier(location2, restorationIdentifier) {
+ if (this.enabled) {
+ this.navigator.startVisit(location2, restorationIdentifier, {
+ action: "restore",
+ historyChanged: true
+ });
} else {
- this.removeAttribute("disabled");
+ this.adapter.pageInvalidated({
+ reason: "turbo_disabled"
+ });
}
}
- get autoscroll() {
- return this.hasAttribute("autoscroll");
+ scrollPositionChanged(position) {
+ this.history.updateRestorationData({ scrollPosition: position });
}
- set autoscroll(value) {
- if (value) {
- this.setAttribute("autoscroll", "");
- } else {
- this.removeAttribute("autoscroll");
+ willSubmitFormLinkToLocation(link, location2) {
+ return this.elementIsNavigatable(link) && locationIsVisitable(location2, this.snapshot.rootLocation);
+ }
+ submittedFormLinkToLocation() {
+ }
+ willFollowLinkToLocation(link, location2, event) {
+ return this.elementIsNavigatable(link) && locationIsVisitable(location2, this.snapshot.rootLocation) && this.applicationAllowsFollowingLinkToLocation(link, location2, event);
+ }
+ followedLinkToLocation(link, location2) {
+ const action = this.getActionForLink(link);
+ const acceptsStreamResponse = link.hasAttribute("data-turbo-stream");
+ this.visit(location2.href, { action, acceptsStreamResponse });
+ }
+ allowsVisitingLocationWithAction(location2, action) {
+ return this.locationWithActionIsSamePage(location2, action) || this.applicationAllowsVisitingLocation(location2);
+ }
+ visitProposedToLocation(location2, options) {
+ extendURLWithDeprecatedProperties(location2);
+ this.adapter.visitProposedToLocation(location2, options);
+ }
+ visitStarted(visit2) {
+ if (!visit2.acceptsStreamResponse) {
+ markAsBusy(document.documentElement);
+ }
+ extendURLWithDeprecatedProperties(visit2.location);
+ if (!visit2.silent) {
+ this.notifyApplicationAfterVisitingLocation(visit2.location, visit2.action);
}
}
- get complete() {
- return !this.delegate.isLoading;
+ visitCompleted(visit2) {
+ clearBusyState(document.documentElement);
+ this.notifyApplicationAfterPageLoad(visit2.getTimingMetrics());
}
- get isActive() {
- return this.ownerDocument === document && !this.isPreview;
+ locationWithActionIsSamePage(location2, action) {
+ return this.navigator.locationWithActionIsSamePage(location2, action);
}
- get isPreview() {
- var _a, _b;
- return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
+ visitScrolledToSamePageLocation(oldURL, newURL) {
+ this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
}
- };
- function frameLoadingStyleFromString(style) {
- switch (style.toLowerCase()) {
- case "lazy":
- return FrameLoadingStyle.lazy;
- default:
- return FrameLoadingStyle.eager;
+ willSubmitForm(form, submitter) {
+ const action = getAction(form, submitter);
+ return this.submissionIsNavigatable(form, submitter) && locationIsVisitable(expandURL(action), this.snapshot.rootLocation);
}
- }
- 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];
+ formSubmitted(form, submitter) {
+ this.navigator.submitForm(form, submitter);
}
- }
- function getAction(form, submitter) {
- const action = (submitter === null || submitter === void 0 ? void 0 : 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 FetchResponse2 = class {
- constructor(response) {
- this.response = response;
+ pageBecameInteractive() {
+ this.view.lastRenderedLocation = this.location;
+ this.notifyApplicationAfterPageLoad();
}
- get succeeded() {
- return this.response.ok;
+ pageLoaded() {
+ this.history.assumeControlOfScrollRestoration();
}
- get failed() {
- return !this.succeeded;
+ pageWillUnload() {
+ this.history.relinquishControlOfScrollRestoration();
}
- get clientError() {
- return this.statusCode >= 400 && this.statusCode <= 499;
+ receivedMessageFromStream(message) {
+ this.renderStreamMessage(message);
}
- get serverError() {
- return this.statusCode >= 500 && this.statusCode <= 599;
+ viewWillCacheSnapshot() {
+ var _a;
+ if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {
+ this.notifyApplicationBeforeCachingSnapshot();
+ }
}
- get redirected() {
- return this.response.redirected;
+ allowsImmediateRender({ element }, options) {
+ const event = this.notifyApplicationBeforeRender(element, options);
+ const { defaultPrevented, detail: { render } } = event;
+ if (this.view.renderer && render) {
+ this.view.renderer.renderElement = render;
+ }
+ return !defaultPrevented;
}
- get location() {
- return expandURL(this.response.url);
+ viewRenderedSnapshot(_snapshot, _isPreview) {
+ this.view.lastRenderedLocation = this.history.location;
+ this.notifyApplicationAfterRender();
}
- get isHTML() {
- return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
+ preloadOnLoadLinksForView(element) {
+ this.preloader.preloadOnLoadLinksForView(element);
}
- get statusCode() {
- return this.response.status;
+ viewInvalidated(reason) {
+ this.adapter.pageInvalidated(reason);
}
- get contentType() {
- return this.header("Content-Type");
+ frameLoaded(frame) {
+ this.notifyApplicationAfterFrameLoad(frame);
}
- get responseText() {
- return this.response.clone().text();
+ frameRendered(fetchResponse, frame) {
+ this.notifyApplicationAfterFrameRender(fetchResponse, frame);
}
- get responseHTML() {
- if (this.isHTML) {
- return this.response.clone().text();
- } else {
- return Promise.resolve(void 0);
- }
+ applicationAllowsFollowingLinkToLocation(link, location2, ev) {
+ const event = this.notifyApplicationAfterClickingLinkToLocation(link, location2, ev);
+ return !event.defaultPrevented;
}
- header(name) {
- return this.response.headers.get(name);
+ applicationAllowsVisitingLocation(location2) {
+ const event = this.notifyApplicationBeforeVisitingLocation(location2);
+ return !event.defaultPrevented;
}
- };
- 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;
+ notifyApplicationAfterClickingLinkToLocation(link, location2, event) {
+ return dispatch("turbo:click", {
+ target: link,
+ detail: { url: location2.href, originalEvent: event },
+ cancelable: true
+ });
}
- }
- function copyElementAttributes(destinationElement, sourceElement) {
- for (const { name, value } of sourceElement.attributes) {
- destinationElement.setAttribute(name, value);
+ notifyApplicationBeforeVisitingLocation(location2) {
+ return dispatch("turbo:before-visit", {
+ detail: { url: location2.href },
+ cancelable: true
+ });
}
- }
- 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);
+ notifyApplicationAfterVisitingLocation(location2, action) {
+ return dispatch("turbo:visit", { detail: { url: location2.href, action } });
}
- return event;
- }
- 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);
+ notifyApplicationBeforeCachingSnapshot() {
+ return dispatch("turbo:before-cache");
+ }
+ notifyApplicationBeforeRender(newBody, options) {
+ return dispatch("turbo:before-render", {
+ detail: Object.assign({ newBody }, options),
+ cancelable: true
+ });
+ }
+ notifyApplicationAfterRender() {
+ return dispatch("turbo:render");
+ }
+ notifyApplicationAfterPageLoad(timing = {}) {
+ return dispatch("turbo:load", {
+ detail: { url: this.location.href, timing }
+ });
+ }
+ notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
+ dispatchEvent(new HashChangeEvent("hashchange", {
+ oldURL: oldURL.toString(),
+ newURL: newURL.toString()
+ }));
+ }
+ notifyApplicationAfterFrameLoad(frame) {
+ return dispatch("turbo:frame-load", { target: frame });
+ }
+ notifyApplicationAfterFrameRender(fetchResponse, frame) {
+ return dispatch("turbo:frame-render", {
+ detail: { fetchResponse },
+ target: frame,
+ cancelable: true
+ });
+ }
+ submissionIsNavigatable(form, submitter) {
+ if (this.formMode == "off") {
+ return false;
} else {
- return Math.floor(Math.random() * 15).toString(16);
+ const submitterIsNavigatable = submitter ? this.elementIsNavigatable(submitter) : true;
+ if (this.formMode == "optin") {
+ return submitterIsNavigatable && form.closest('[data-turbo="true"]') != null;
+ } else {
+ return submitterIsNavigatable && this.elementIsNavigatable(form);
+ }
}
- }).join("");
- }
- function getAttribute(attributeName, ...elements) {
- for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : 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", "");
+ elementIsNavigatable(element) {
+ const container = findClosestRecursively(element, "[data-turbo]");
+ const withinFrame = findClosestRecursively(element, "turbo-frame");
+ if (this.drive || withinFrame) {
+ if (container) {
+ return container.getAttribute("data-turbo") != "false";
+ } else {
+ return true;
+ }
+ } else {
+ if (container) {
+ return container.getAttribute("data-turbo") == "true";
+ } else {
+ return false;
+ }
}
- element.setAttribute("aria-busy", "true");
}
- }
- function clearBusyState(...elements) {
- for (const element of elements) {
- if (element.localName == "turbo-frame") {
- element.removeAttribute("busy");
+ getActionForLink(link) {
+ return getVisitAction(link) || "advance";
+ }
+ get snapshot() {
+ return this.view.snapshot;
+ }
+ };
+ function extendURLWithDeprecatedProperties(url) {
+ Object.defineProperties(url, deprecatedLocationPropertyDescriptors);
+ }
+ var deprecatedLocationPropertyDescriptors = {
+ absoluteURL: {
+ get() {
+ return this.toString();
}
- element.removeAttribute("aria-busy");
}
+ };
+ var Cache = class {
+ constructor(session2) {
+ this.session = session2;
+ }
+ clear() {
+ this.session.clearCache();
+ }
+ resetCacheControl() {
+ this.setCacheControl("");
+ }
+ exemptPageFromCache() {
+ this.setCacheControl("no-cache");
+ }
+ exemptPageFromPreview() {
+ this.setCacheControl("no-preview");
+ }
+ setCacheControl(value) {
+ setMetaContent("turbo-cache-control", value);
+ }
+ };
+ var StreamActions = {
+ after() {
+ this.targetElements.forEach((e) => {
+ var _a;
+ return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling);
+ });
+ },
+ append() {
+ this.removeDuplicateTargetChildren();
+ this.targetElements.forEach((e) => e.append(this.templateContent));
+ },
+ before() {
+ this.targetElements.forEach((e) => {
+ var _a;
+ return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e);
+ });
+ },
+ prepend() {
+ this.removeDuplicateTargetChildren();
+ this.targetElements.forEach((e) => e.prepend(this.templateContent));
+ },
+ remove() {
+ this.targetElements.forEach((e) => e.remove());
+ },
+ replace() {
+ this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
+ },
+ update() {
+ this.targetElements.forEach((targetElement) => {
+ targetElement.innerHTML = "";
+ targetElement.append(this.templateContent);
+ });
+ }
+ };
+ var session = new Session();
+ var cache = new Cache(session);
+ var { navigator: navigator$1 } = session;
+ function start() {
+ session.start();
}
- 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 registerAdapter(adapter) {
+ session.registerAdapter(adapter);
}
- function getHistoryMethodForAction(action) {
- switch (action) {
- case "replace":
- return history.replaceState;
- case "advance":
- case "restore":
- return history.pushState;
- }
+ function visit(location2, options) {
+ session.visit(location2, options);
}
- function isAction(action) {
- return action == "advance" || action == "replace" || action == "restore";
+ function connectStreamSource(source) {
+ session.connectStreamSource(source);
}
- function getVisitAction(...elements) {
- const action = getAttribute("data-turbo-action", ...elements);
- return isAction(action) ? action : null;
+ function disconnectStreamSource(source) {
+ session.disconnectStreamSource(source);
}
- function getMetaElement(name) {
- return document.querySelector(`meta[name="${name}"]`);
+ function renderStreamMessage(message) {
+ session.renderStreamMessage(message);
}
- function getMetaContent(name) {
- const element = getMetaElement(name);
- return element && element.content;
+ function clearCache() {
+ console.warn("Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`");
+ session.clearCache();
}
- 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 setProgressBarDelay(delay) {
+ session.setProgressBarDelay(delay);
}
- function findClosestRecursively(element, selector) {
- var _a;
- if (element instanceof Element) {
- return element.closest(selector) || findClosestRecursively(element.assignedSlot || ((_a = element.getRootNode()) === null || _a === void 0 ? void 0 : _a.host), selector);
- }
+ function setConfirmMethod(confirmMethod) {
+ FormSubmission.confirmMethod = confirmMethod;
}
- var FetchMethod;
- (function(FetchMethod2) {
- FetchMethod2[FetchMethod2["get"] = 0] = "get";
- FetchMethod2[FetchMethod2["post"] = 1] = "post";
- FetchMethod2[FetchMethod2["put"] = 2] = "put";
- FetchMethod2[FetchMethod2["patch"] = 3] = "patch";
- FetchMethod2[FetchMethod2["delete"] = 4] = "delete";
- })(FetchMethod || (FetchMethod = {}));
- 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;
- }
+ function setFormMode(mode) {
+ session.setFormMode(mode);
}
- var FetchRequest2 = class {
- constructor(delegate, method, location2, body = new URLSearchParams(), target = null) {
- this.abortController = new AbortController();
- this.resolveRequestPromise = (_value) => {
+ var Turbo2 = /* @__PURE__ */ Object.freeze({
+ __proto__: null,
+ navigator: navigator$1,
+ session,
+ cache,
+ PageRenderer,
+ PageSnapshot,
+ FrameRenderer,
+ start,
+ registerAdapter,
+ visit,
+ connectStreamSource,
+ disconnectStreamSource,
+ renderStreamMessage,
+ clearCache,
+ setProgressBarDelay,
+ setConfirmMethod,
+ setFormMode,
+ StreamActions
+ });
+ var TurboFrameMissingError = class extends Error {
+ };
+ var FrameController = class {
+ constructor(element) {
+ this.fetchResponseLoaded = (_fetchResponse) => {
};
- this.delegate = delegate;
- this.method = method;
- this.headers = this.defaultHeaders;
- this.body = body;
- this.url = location2;
- this.target = target;
+ this.currentFetchRequest = null;
+ this.resolveVisitPromise = () => {
+ };
+ this.connected = false;
+ this.hasBeenLoaded = false;
+ this.ignoredAttributes = /* @__PURE__ */ new Set();
+ this.action = null;
+ this.visitCachedSnapshot = ({ element: element2 }) => {
+ const frame = element2.querySelector("#" + this.element.id);
+ if (frame && this.previousFrameElement) {
+ frame.replaceChildren(...this.previousFrameElement.children);
+ }
+ delete this.previousFrameElement;
+ };
+ this.element = element;
+ this.view = new FrameView(this, this.element);
+ this.appearanceObserver = new AppearanceObserver(this, this.element);
+ this.formLinkClickObserver = new FormLinkClickObserver(this, this.element);
+ this.linkInterceptor = new LinkInterceptor(this, this.element);
+ this.restorationIdentifier = uuid();
+ this.formSubmitObserver = new FormSubmitObserver(this, this.element);
}
- get location() {
- return this.url;
+ connect() {
+ if (!this.connected) {
+ this.connected = true;
+ if (this.loadingStyle == FrameLoadingStyle.lazy) {
+ this.appearanceObserver.start();
+ } else {
+ this.loadSourceURL();
+ }
+ this.formLinkClickObserver.start();
+ this.linkInterceptor.start();
+ this.formSubmitObserver.start();
+ }
}
- get params() {
- return this.url.searchParams;
+ disconnect() {
+ if (this.connected) {
+ this.connected = false;
+ this.appearanceObserver.stop();
+ this.formLinkClickObserver.stop();
+ this.linkInterceptor.stop();
+ this.formSubmitObserver.stop();
+ }
}
- get entries() {
- return this.body ? Array.from(this.body.entries()) : [];
+ disabledChanged() {
+ if (this.loadingStyle == FrameLoadingStyle.eager) {
+ this.loadSourceURL();
+ }
}
- cancel() {
- this.abortController.abort();
+ sourceURLChanged() {
+ if (this.isIgnoringChangesTo("src"))
+ return;
+ if (this.element.isConnected) {
+ this.complete = false;
+ }
+ if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
+ this.loadSourceURL();
+ }
}
- async perform() {
- const { fetchOptions } = this;
- this.delegate.prepareRequest(this);
- await this.allowRequestToBeIntercepted(fetchOptions);
+ sourceURLReloaded() {
+ const { src } = this.element;
+ this.ignoringChangesToAttribute("complete", () => {
+ this.element.removeAttribute("complete");
+ });
+ this.element.src = null;
+ this.element.src = src;
+ return this.element.loaded;
+ }
+ completeChanged() {
+ if (this.isIgnoringChangesTo("complete"))
+ return;
+ this.loadSourceURL();
+ }
+ loadingStyleChanged() {
+ if (this.loadingStyle == FrameLoadingStyle.lazy) {
+ this.appearanceObserver.start();
+ } else {
+ this.appearanceObserver.stop();
+ this.loadSourceURL();
+ }
+ }
+ async loadSourceURL() {
+ if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
+ this.element.loaded = this.visit(expandURL(this.sourceURL));
+ this.appearanceObserver.stop();
+ await this.element.loaded;
+ this.hasBeenLoaded = true;
+ }
+ }
+ async loadResponse(fetchResponse) {
+ if (fetchResponse.redirected || fetchResponse.succeeded && fetchResponse.isHTML) {
+ this.sourceURL = fetchResponse.response.url;
+ }
try {
- this.delegate.requestStarted(this);
- const response = await fetch(this.url.href, fetchOptions);
- return await this.receive(response);
- } catch (error2) {
- if (error2.name !== "AbortError") {
- if (this.willDelegateErrorHandling(error2)) {
- this.delegate.requestErrored(this, error2);
+ const html = await fetchResponse.responseHTML;
+ if (html) {
+ const document2 = parseHTMLDocument(html);
+ const pageSnapshot = PageSnapshot.fromDocument(document2);
+ if (pageSnapshot.isVisitable) {
+ await this.loadFrameResponse(fetchResponse, document2);
+ } else {
+ await this.handleUnvisitableFrameResponse(fetchResponse);
}
- throw error2;
}
} finally {
- this.delegate.requestFinished(this);
+ this.fetchResponseLoaded = () => {
+ };
}
}
- async receive(response) {
- const fetchResponse = new FetchResponse2(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);
+ elementAppearedInViewport(element) {
+ this.proposeVisitIfNavigatedWithAction(element, element);
+ this.loadSourceURL();
+ }
+ willSubmitFormLinkToLocation(link) {
+ return this.shouldInterceptNavigation(link);
+ }
+ submittedFormLinkToLocation(link, _location, form) {
+ const frame = this.findFrameElement(link);
+ if (frame)
+ form.setAttribute("data-turbo-frame", frame.id);
+ }
+ shouldInterceptLinkClick(element, _location, _event) {
+ return this.shouldInterceptNavigation(element);
+ }
+ linkClickIntercepted(element, location2) {
+ this.navigateFrame(element, location2);
+ }
+ willSubmitForm(element, submitter) {
+ return element.closest("turbo-frame") == this.element && this.shouldInterceptNavigation(element, submitter);
+ }
+ formSubmitted(element, submitter) {
+ if (this.formSubmission) {
+ this.formSubmission.stop();
}
- return fetchResponse;
+ this.formSubmission = new FormSubmission(this, element, submitter);
+ const { fetchRequest } = this.formSubmission;
+ this.prepareRequest(fetchRequest);
+ this.formSubmission.start();
}
- get fetchOptions() {
+ prepareRequest(request) {
var _a;
- return {
- method: FetchMethod[this.method].toUpperCase(),
- credentials: "same-origin",
- headers: this.headers,
- redirect: "follow",
- body: this.isSafe ? null : this.body,
- signal: this.abortSignal,
- referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
- };
+ request.headers["Turbo-Frame"] = this.id;
+ if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute("data-turbo-stream")) {
+ request.acceptResponseType(StreamMessage.contentType);
+ }
}
- get defaultHeaders() {
- return {
- Accept: "text/html, application/xhtml+xml"
- };
+ requestStarted(_request) {
+ markAsBusy(this.element);
}
- get isSafe() {
- return this.method === FetchMethod.get;
+ requestPreventedHandlingResponse(_request, _response) {
+ this.resolveVisitPromise();
}
- get abortSignal() {
- return this.abortController.signal;
+ async requestSucceededWithResponse(request, response) {
+ await this.loadResponse(response);
+ this.resolveVisitPromise();
}
- acceptResponseType(mimeType) {
- this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
+ async requestFailedWithResponse(request, response) {
+ await this.loadResponse(response);
+ this.resolveVisitPromise();
}
- 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
- });
- if (event.defaultPrevented)
- await requestInterception;
+ requestErrored(request, error2) {
+ console.error(error2);
+ this.resolveVisitPromise();
}
- willDelegateErrorHandling(error2) {
- const event = dispatch("turbo:fetch-request-error", {
- target: this.target,
- cancelable: true,
- detail: { request: this, error: error2 }
- });
- return !event.defaultPrevented;
+ requestFinished(_request) {
+ clearBusyState(this.element);
}
- };
- var AppearanceObserver = class {
- constructor(delegate, element) {
- this.started = false;
- this.intersect = (entries) => {
- const lastEntry = entries.slice(-1)[0];
- if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
- this.delegate.elementAppearedInViewport(this.element);
- }
- };
- this.delegate = delegate;
- this.element = element;
- this.intersectionObserver = new IntersectionObserver(this.intersect);
+ formSubmissionStarted({ formElement }) {
+ markAsBusy(formElement, this.findFrameElement(formElement));
}
- start() {
- if (!this.started) {
- this.started = true;
- this.intersectionObserver.observe(this.element);
+ formSubmissionSucceededWithResponse(formSubmission, response) {
+ const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
+ frame.delegate.loadResponse(response);
+ if (!formSubmission.isSafe) {
+ session.clearCache();
}
}
- stop() {
- if (this.started) {
- this.started = false;
- this.intersectionObserver.unobserve(this.element);
- }
+ formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
+ this.element.delegate.loadResponse(fetchResponse);
+ session.clearCache();
}
- };
- var StreamMessage = class {
- static wrap(message) {
- if (typeof message == "string") {
- return new this(createDocumentFragment(message));
- } else {
- return message;
- }
+ formSubmissionErrored(formSubmission, error2) {
+ console.error(error2);
}
- constructor(fragment) {
- this.fragment = importStreamElements(fragment);
+ formSubmissionFinished({ formElement }) {
+ clearBusyState(formElement, this.findFrameElement(formElement));
}
- };
- StreamMessage.contentType = "text/vnd.turbo-stream.html";
- 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));
+ allowsImmediateRender({ element: newFrame }, options) {
+ const event = dispatch("turbo:before-frame-render", {
+ target: this.element,
+ detail: Object.assign({ newFrame }, options),
+ cancelable: true
+ });
+ const { defaultPrevented, detail: { render } } = event;
+ if (this.view.renderer && render) {
+ this.view.renderer.renderElement = render;
}
- element.replaceWith(streamElement);
+ return !defaultPrevented;
}
- return fragment;
- }
- var FormSubmissionState;
- (function(FormSubmissionState2) {
- FormSubmissionState2[FormSubmissionState2["initialized"] = 0] = "initialized";
- FormSubmissionState2[FormSubmissionState2["requesting"] = 1] = "requesting";
- FormSubmissionState2[FormSubmissionState2["waiting"] = 2] = "waiting";
- FormSubmissionState2[FormSubmissionState2["receiving"] = 3] = "receiving";
- FormSubmissionState2[FormSubmissionState2["stopping"] = 4] = "stopping";
- FormSubmissionState2[FormSubmissionState2["stopped"] = 5] = "stopped";
- })(FormSubmissionState || (FormSubmissionState = {}));
- var FormEnctype;
- (function(FormEnctype2) {
- FormEnctype2["urlEncoded"] = "application/x-www-form-urlencoded";
- FormEnctype2["multipart"] = "multipart/form-data";
- FormEnctype2["plain"] = "text/plain";
- })(FormEnctype || (FormEnctype = {}));
- function formEnctypeFromString(encoding) {
- switch (encoding.toLowerCase()) {
- case FormEnctype.multipart:
- return FormEnctype.multipart;
- case FormEnctype.plain:
- return FormEnctype.plain;
- default:
- return FormEnctype.urlEncoded;
+ viewRenderedSnapshot(_snapshot, _isPreview) {
}
- }
- var FormSubmission = class {
- static confirmMethod(message, _element, _submitter) {
- return Promise.resolve(confirm(message));
+ preloadOnLoadLinksForView(element) {
+ session.preloadOnLoadLinksForView(element);
}
- constructor(delegate, formElement, submitter, mustRedirect = false) {
- this.state = FormSubmissionState.initialized;
- this.delegate = delegate;
- this.formElement = formElement;
- this.submitter = submitter;
- this.formData = buildFormData(formElement, submitter);
- this.location = expandURL(this.action);
- if (this.method == FetchMethod.get) {
- mergeFormDataEntries(this.location, [...this.body.entries()]);
+ viewInvalidated() {
+ }
+ willRenderFrame(currentElement, _newElement) {
+ this.previousFrameElement = currentElement.cloneNode(true);
+ }
+ async loadFrameResponse(fetchResponse, document2) {
+ const newFrameElement = await this.extractForeignFrameElement(document2.body);
+ if (newFrameElement) {
+ const snapshot = new Snapshot(newFrameElement);
+ const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
+ if (this.view.renderPromise)
+ await this.view.renderPromise;
+ this.changeHistory();
+ await this.view.render(renderer);
+ this.complete = true;
+ session.frameRendered(fetchResponse, this.element);
+ session.frameLoaded(this.element);
+ this.fetchResponseLoaded(fetchResponse);
+ } else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
+ this.handleFrameMissingFromResponse(fetchResponse);
}
- this.fetchRequest = new FetchRequest2(this, this.method, this.location, this.body, this.formElement);
- this.mustRedirect = mustRedirect;
}
- get method() {
+ async visit(url) {
var _a;
- const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
- return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
+ const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
+ (_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
+ this.currentFetchRequest = request;
+ return new Promise((resolve) => {
+ this.resolveVisitPromise = () => {
+ this.resolveVisitPromise = () => {
+ };
+ this.currentFetchRequest = null;
+ resolve();
+ };
+ request.perform();
+ });
}
- get action() {
- var _a;
- const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
- if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
- return this.submitter.getAttribute("formaction") || "";
- } else {
- return this.formElement.getAttribute("action") || formElementAction || "";
+ navigateFrame(element, url, submitter) {
+ const frame = this.findFrameElement(element, submitter);
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
+ this.withCurrentNavigationElement(element, () => {
+ frame.src = url;
+ });
+ }
+ proposeVisitIfNavigatedWithAction(frame, element, submitter) {
+ this.action = getVisitAction(submitter, element, frame);
+ if (this.action) {
+ const pageSnapshot = PageSnapshot.fromElement(frame).clone();
+ const { visitCachedSnapshot } = frame.delegate;
+ frame.delegate.fetchResponseLoaded = (fetchResponse) => {
+ if (frame.src) {
+ const { statusCode, redirected } = fetchResponse;
+ const responseHTML = frame.ownerDocument.documentElement.outerHTML;
+ const response = { statusCode, redirected, responseHTML };
+ const options = {
+ response,
+ visitCachedSnapshot,
+ willRender: false,
+ updateHistory: false,
+ restorationIdentifier: this.restorationIdentifier,
+ snapshot: pageSnapshot
+ };
+ if (this.action)
+ options.action = this.action;
+ session.visit(frame.src, options);
+ }
+ };
}
}
- get body() {
- if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
- return new URLSearchParams(this.stringFormData);
- } else {
- return this.formData;
+ changeHistory() {
+ if (this.action) {
+ const method = getHistoryMethodForAction(this.action);
+ session.history.update(method, expandURL(this.element.src || ""), this.restorationIdentifier);
}
}
- get enctype() {
- var _a;
- return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
+ async handleUnvisitableFrameResponse(fetchResponse) {
+ console.warn(`The response (${fetchResponse.statusCode}) from is performing a full page visit due to turbo-visit-control.`);
+ await this.visitResponse(fetchResponse.response);
}
- get isSafe() {
- return this.fetchRequest.isSafe;
+ willHandleFrameMissingFromResponse(fetchResponse) {
+ this.element.setAttribute("complete", "");
+ const response = fetchResponse.response;
+ const visit2 = async (url, options = {}) => {
+ if (url instanceof Response) {
+ this.visitResponse(url);
+ } else {
+ session.visit(url, options);
+ }
+ };
+ const event = dispatch("turbo:frame-missing", {
+ target: this.element,
+ detail: { response, visit: visit2 },
+ cancelable: true
+ });
+ return !event.defaultPrevented;
}
- get stringFormData() {
- return [...this.formData].reduce((entries, [name, value]) => {
- return entries.concat(typeof value == "string" ? [[name, value]] : []);
- }, []);
+ handleFrameMissingFromResponse(fetchResponse) {
+ this.view.missing();
+ this.throwFrameMissingError(fetchResponse);
}
- 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;
+ throwFrameMissingError(fetchResponse) {
+ const message = `The response (${fetchResponse.statusCode}) did not contain the expected and will be ignored. To perform a full page visit instead, set turbo-visit-control to reload.`;
+ throw new TurboFrameMissingError(message);
+ }
+ async visitResponse(response) {
+ const wrapped = new FetchResponse(response);
+ const responseHTML = await wrapped.responseHTML;
+ const { location: location2, redirected, statusCode } = wrapped;
+ return session.visit(location2, { response: { redirected, statusCode, responseHTML } });
+ }
+ findFrameElement(element, submitter) {
+ var _a;
+ const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
+ return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
+ }
+ async extractForeignFrameElement(container) {
+ let element;
+ const id = CSS.escape(this.id);
+ try {
+ element = activateElement(container.querySelector(`turbo-frame#${id}`), this.sourceURL);
+ if (element) {
+ return element;
}
+ element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.sourceURL);
+ if (element) {
+ await element.loaded;
+ return await this.extractForeignFrameElement(element);
+ }
+ } catch (error2) {
+ console.error(error2);
+ return new FrameElement();
}
- if (this.state == initialized) {
- this.state = requesting;
- return this.fetchRequest.perform();
- }
+ return null;
}
- stop() {
- const { stopping, stopped } = FormSubmissionState;
- if (this.state != stopping && this.state != stopped) {
- this.state = stopping;
- this.fetchRequest.cancel();
- return true;
- }
+ formActionIsVisitable(form, submitter) {
+ const action = getAction(form, submitter);
+ return locationIsVisitable(expandURL(action), this.rootLocation);
}
- prepareRequest(request) {
- if (!request.isSafe) {
- const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
- if (token) {
- request.headers["X-CSRF-Token"] = token;
+ shouldInterceptNavigation(element, submitter) {
+ const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
+ if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) {
+ return false;
+ }
+ if (!this.enabled || id == "_top") {
+ return false;
+ }
+ if (id) {
+ const frameElement = getFrameElementById(id);
+ if (frameElement) {
+ return !frameElement.disabled;
}
}
- if (this.requestAcceptsTurboStreamResponse(request)) {
- request.acceptResponseType(StreamMessage.contentType);
+ if (!session.elementIsNavigatable(element)) {
+ return false;
+ }
+ if (submitter && !session.elementIsNavigatable(submitter)) {
+ return false;
}
+ return true;
}
- requestStarted(_request) {
- var _a;
- this.state = FormSubmissionState.waiting;
- (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
- this.setSubmitsWith();
- dispatch("turbo:submit-start", {
- target: this.formElement,
- detail: { formSubmission: this }
- });
- this.delegate.formSubmissionStarted(this);
+ get id() {
+ return this.element.id;
}
- requestPreventedHandlingResponse(request, response) {
- this.result = { success: response.succeeded, fetchResponse: response };
+ get enabled() {
+ return !this.element.disabled;
}
- requestSucceededWithResponse(request, response) {
- if (response.clientError || response.serverError) {
- this.delegate.formSubmissionFailedWithResponse(this, response);
- } else 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);
+ get sourceURL() {
+ if (this.element.src) {
+ return this.element.src;
}
}
- requestFailedWithResponse(request, response) {
- this.result = { success: false, fetchResponse: response };
- this.delegate.formSubmissionFailedWithResponse(this, response);
+ set sourceURL(sourceURL) {
+ this.ignoringChangesToAttribute("src", () => {
+ this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
+ });
}
- requestErrored(request, error2) {
- this.result = { success: false, error: error2 };
- this.delegate.formSubmissionErrored(this, error2);
+ get loadingStyle() {
+ return this.element.loading;
}
- requestFinished(_request) {
- var _a;
- this.state = FormSubmissionState.stopped;
- (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
- this.resetSubmitterText();
- dispatch("turbo:submit-end", {
- target: this.formElement,
- detail: Object.assign({ formSubmission: this }, this.result)
- });
- this.delegate.formSubmissionFinished(this);
+ get isLoading() {
+ return this.formSubmission !== void 0 || this.resolveVisitPromise() !== void 0;
}
- 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;
- }
+ get complete() {
+ return this.element.hasAttribute("complete");
}
- requestMustRedirect(request) {
- return !request.isSafe && this.mustRedirect;
+ set complete(value) {
+ this.ignoringChangesToAttribute("complete", () => {
+ if (value) {
+ this.element.setAttribute("complete", "");
+ } else {
+ this.element.removeAttribute("complete");
+ }
+ });
}
- requestAcceptsTurboStreamResponse(request) {
- return !request.isSafe || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
+ get isActive() {
+ return this.element.isActive && this.connected;
}
- get submitsWith() {
+ get rootLocation() {
var _a;
- return (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-submits-with");
+ const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
+ const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
+ return expandURL(root);
}
- };
- function buildFormData(formElement, submitter) {
- const formData = new FormData(formElement);
- const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
- const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
- if (name) {
- formData.append(name, value || "");
+ isIgnoringChangesTo(attributeName) {
+ return this.ignoredAttributes.has(attributeName);
}
- 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;
+ ignoringChangesToAttribute(attributeName, callback) {
+ this.ignoredAttributes.add(attributeName);
+ callback();
+ this.ignoredAttributes.delete(attributeName);
+ }
+ withCurrentNavigationElement(element, callback) {
+ this.currentNavigationElement = element;
+ callback();
+ delete this.currentNavigationElement;
+ }
+ };
+ function getFrameElementById(id) {
+ if (id != null) {
+ const element = document.getElementById(id);
+ if (element instanceof FrameElement) {
+ return element;
}
}
}
- function responseSucceededWithoutRedirect(response) {
- return response.statusCode == 200 && !response.redirected;
- }
- function mergeFormDataEntries(url, entries) {
- const searchParams = new URLSearchParams();
- for (const [name, value] of entries) {
- if (value instanceof File)
- continue;
- searchParams.append(name, value);
+ function activateElement(element, currentURL) {
+ if (element) {
+ const src = element.getAttribute("src");
+ if (src != null && currentURL != null && urlsAreEqual(src, currentURL)) {
+ throw new Error(`Matching element has a source URL which references itself`);
+ }
+ if (element.ownerDocument !== document) {
+ element = document.importNode(element, true);
+ }
+ if (element instanceof FrameElement) {
+ element.connectedCallback();
+ element.disconnectedCallback();
+ return element;
+ }
}
- url.search = searchParams.toString();
- return url;
}
- 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;
+ var StreamElement = class extends HTMLElement {
+ static async renderElement(newElement) {
+ await newElement.performAction();
}
- getElementForAnchor(anchor) {
- return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;
+ async connectedCallback() {
+ try {
+ await this.render();
+ } catch (error2) {
+ console.error(error2);
+ } finally {
+ this.disconnect();
+ }
}
- get isConnected() {
- return this.element.isConnected;
+ async render() {
+ var _a;
+ return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : this.renderPromise = (async () => {
+ const event = this.beforeRenderEvent;
+ if (this.dispatchEvent(event)) {
+ await nextAnimationFrame();
+ await event.detail.render(this);
+ }
+ })();
}
- get firstAutofocusableElement() {
- const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
- for (const element of this.element.querySelectorAll("[autofocus]")) {
- if (element.closest(inertDisabledOrHidden) == null)
- return element;
- else
- continue;
+ disconnect() {
+ try {
+ this.remove();
+ } catch (_a) {
}
- return null;
}
- get permanentElements() {
- return queryPermanentElementsAll(this.element);
+ removeDuplicateTargetChildren() {
+ this.duplicateChildren.forEach((c) => c.remove());
}
- getPermanentElementById(id) {
- return getPermanentElementById(this.element, id);
+ get duplicateChildren() {
+ var _a;
+ const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);
+ const newChildrenIds = [...((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || []].filter((c) => !!c.id).map((c) => c.id);
+ return existingChildren.filter((c) => newChildrenIds.includes(c.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];
+ get performAction() {
+ if (this.action) {
+ const actionFunction = StreamActions[this.action];
+ if (actionFunction) {
+ return actionFunction;
}
+ this.raise("unknown action");
}
- 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 {
- constructor(delegate, eventTarget) {
- this.started = false;
- this.submitCaptured = () => {
- this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
- this.eventTarget.addEventListener("submit", this.submitBubbled, false);
- };
- this.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);
- }
- }
- };
- this.delegate = delegate;
- this.eventTarget = eventTarget;
+ this.raise("action attribute is missing");
}
- start() {
- if (!this.started) {
- this.eventTarget.addEventListener("submit", this.submitCaptured, true);
- this.started = true;
+ get targetElements() {
+ if (this.target) {
+ return this.targetElementsById;
+ } else if (this.targets) {
+ return this.targetElementsByQuery;
+ } else {
+ this.raise("target or targets attribute is missing");
}
}
- stop() {
- if (this.started) {
- this.eventTarget.removeEventListener("submit", this.submitCaptured, true);
- this.started = false;
- }
+ get templateContent() {
+ return this.templateElement.content.cloneNode(true);
}
- };
- function submissionDoesNotDismissDialog(form, submitter) {
- const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
- return method != "dialog";
- }
- function submissionDoesNotTargetIFrame(form, submitter) {
- if ((submitter === null || submitter === void 0 ? void 0 : submitter.hasAttribute("formtarget")) || form.hasAttribute("target")) {
- const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
- for (const element of document.getElementsByName(target)) {
- if (element instanceof HTMLIFrameElement)
- return false;
+ get templateElement() {
+ if (this.firstElementChild === null) {
+ const template = this.ownerDocument.createElement("template");
+ this.appendChild(template);
+ return template;
+ } else if (this.firstElementChild instanceof HTMLTemplateElement) {
+ return this.firstElementChild;
}
- return true;
- } else {
- return true;
+ this.raise("first child element must be a element");
}
- }
- var View = class {
- constructor(delegate, element) {
- this.resolveRenderPromise = (_value) => {
- };
- this.resolveInterceptionPromise = (_value) => {
- };
- this.delegate = delegate;
- this.element = element;
+ get action() {
+ return this.getAttribute("action");
}
- 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();
+ get target() {
+ return this.getAttribute("target");
}
- focusElement(element) {
- if (element instanceof HTMLElement) {
- if (element.hasAttribute("tabindex")) {
- element.focus();
- } else {
- element.setAttribute("tabindex", "-1");
- element.focus();
- element.removeAttribute("tabindex");
- }
- }
+ get targets() {
+ return this.getAttribute("targets");
}
- scrollToPosition({ x, y }) {
- this.scrollRoot.scrollTo(x, y);
+ raise(message) {
+ throw new Error(`${this.description}: ${message}`);
}
- scrollToTop() {
- this.scrollToPosition({ x: 0, y: 0 });
+ get description() {
+ var _a, _b;
+ return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "";
}
- get scrollRoot() {
- return window;
+ get beforeRenderEvent() {
+ return new CustomEvent("turbo:before-stream-render", {
+ bubbles: true,
+ cancelable: true,
+ detail: { newStream: this, render: StreamElement.renderElement }
+ });
}
- async render(renderer) {
- const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
- 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 };
- const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
- if (!immediateRender)
- await renderInterception;
- await this.renderSnapshot(renderer);
- this.delegate.viewRenderedSnapshot(snapshot, isPreview);
- this.delegate.preloadOnLoadLinksForView(this.element);
- this.finishRenderingSnapshot(renderer);
- } finally {
- delete this.renderer;
- this.resolveRenderPromise(void 0);
- delete this.renderPromise;
- }
+ get targetElementsById() {
+ var _a;
+ const element = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.getElementById(this.target);
+ if (element !== null) {
+ return [element];
} else {
- this.invalidate(renderer.reloadReason);
+ return [];
}
}
- 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", "");
+ get targetElementsByQuery() {
+ var _a;
+ const elements = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.querySelectorAll(this.targets);
+ if (elements.length !== 0) {
+ return Array.prototype.slice.call(elements);
} else {
- this.element.removeAttribute("data-turbo-preview");
+ return [];
}
}
- 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.clickBubbled = (event) => {
- if (this.respondsToEventTarget(event.target)) {
- this.clickEvent = event;
- } else {
- delete this.clickEvent;
- }
- };
- this.linkClicked = (event) => {
- if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
- 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;
- };
- this.willVisit = (_event) => {
- delete this.clickEvent;
- };
- this.delegate = delegate;
- this.element = element;
+ var StreamSourceElement = class extends HTMLElement {
+ constructor() {
+ super(...arguments);
+ this.streamSource = null;
}
- start() {
- this.element.addEventListener("click", this.clickBubbled);
- document.addEventListener("turbo:click", this.linkClicked);
- document.addEventListener("turbo:before-visit", this.willVisit);
+ connectedCallback() {
+ this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
+ connectStreamSource(this.streamSource);
}
- stop() {
- this.element.removeEventListener("click", this.clickBubbled);
- document.removeEventListener("turbo:click", this.linkClicked);
- document.removeEventListener("turbo:before-visit", this.willVisit);
+ disconnectedCallback() {
+ if (this.streamSource) {
+ disconnectStreamSource(this.streamSource);
+ }
}
- respondsToEventTarget(target) {
- const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
- return element && element.closest("turbo-frame, html") == this.element;
+ get src() {
+ return this.getAttribute("src") || "";
}
};
- var LinkClickObserver = class {
- constructor(delegate, eventTarget) {
- this.started = false;
- this.clickCaptured = () => {
- this.eventTarget.removeEventListener("click", this.clickBubbled, false);
- this.eventTarget.addEventListener("click", this.clickBubbled, false);
- };
- this.clickBubbled = (event) => {
- if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
- const target = event.composedPath && event.composedPath()[0] || event.target;
- const link = this.findLinkFromClickTarget(target);
- if (link && doesNotTargetIFrame(link)) {
- const location2 = this.getLocationForLink(link);
- if (this.delegate.willFollowLinkToLocation(link, location2, event)) {
- event.preventDefault();
- this.delegate.followedLinkToLocation(link, location2);
- }
- }
- }
- };
- this.delegate = delegate;
- this.eventTarget = eventTarget;
- }
- start() {
- if (!this.started) {
- this.eventTarget.addEventListener("click", this.clickCaptured, true);
- this.started = true;
+ FrameElement.delegateConstructor = FrameController;
+ if (customElements.get("turbo-frame") === void 0) {
+ customElements.define("turbo-frame", FrameElement);
+ }
+ if (customElements.get("turbo-stream") === void 0) {
+ customElements.define("turbo-stream", StreamElement);
+ }
+ if (customElements.get("turbo-stream-source") === void 0) {
+ customElements.define("turbo-stream-source", StreamSourceElement);
+ }
+ (() => {
+ let element = document.currentScript;
+ if (!element)
+ return;
+ if (element.hasAttribute("data-turbo-suppress-warning"))
+ return;
+ element = element.parentElement;
+ while (element) {
+ if (element == document.body) {
+ return console.warn(unindent`
+ You are loading Turbo from a