1 |
|
2 |
|
3 |
|
4 |
|
5 | (function () {
|
6 | if (window.Reflect === undefined ||
|
7 | window.customElements === undefined ||
|
8 | window.customElements.polyfillWrapFlushCallback) {
|
9 | return;
|
10 | }
|
11 | const BuiltInHTMLElement = HTMLElement;
|
12 | const wrapperForTheName = {
|
13 | HTMLElement: function HTMLElement() {
|
14 | return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
|
15 | },
|
16 | };
|
17 | window.HTMLElement = wrapperForTheName["HTMLElement"];
|
18 | HTMLElement.prototype = BuiltInHTMLElement.prototype;
|
19 | HTMLElement.prototype.constructor = HTMLElement;
|
20 | Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
|
21 | })();
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 | (function(prototype) {
|
48 | if (typeof prototype.requestSubmit == "function") return
|
49 |
|
50 | prototype.requestSubmit = function(submitter) {
|
51 | if (submitter) {
|
52 | validateSubmitter(submitter, this);
|
53 | submitter.click();
|
54 | } else {
|
55 | submitter = document.createElement("input");
|
56 | submitter.type = "submit";
|
57 | submitter.hidden = true;
|
58 | this.appendChild(submitter);
|
59 | submitter.click();
|
60 | this.removeChild(submitter);
|
61 | }
|
62 | };
|
63 |
|
64 | function validateSubmitter(submitter, form) {
|
65 | submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'");
|
66 | submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button");
|
67 | submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError");
|
68 | }
|
69 |
|
70 | function raise(errorConstructor, message, name) {
|
71 | throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name)
|
72 | }
|
73 | })(HTMLFormElement.prototype);
|
74 |
|
75 | const submittersByForm = new WeakMap();
|
76 | function findSubmitterFromClickTarget(target) {
|
77 | const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
78 | const candidate = element ? element.closest("input, button") : null;
|
79 | return (candidate === null || candidate === void 0 ? void 0 : candidate.type) == "submit" ? candidate : null;
|
80 | }
|
81 | function clickCaptured(event) {
|
82 | const submitter = findSubmitterFromClickTarget(event.target);
|
83 | if (submitter && submitter.form) {
|
84 | submittersByForm.set(submitter.form, submitter);
|
85 | }
|
86 | }
|
87 | (function () {
|
88 | if ("submitter" in Event.prototype)
|
89 | return;
|
90 | let prototype;
|
91 | if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
|
92 | prototype = window.SubmitEvent.prototype;
|
93 | }
|
94 | else if ("SubmitEvent" in window) {
|
95 | return;
|
96 | }
|
97 | else {
|
98 | prototype = window.Event.prototype;
|
99 | }
|
100 | addEventListener("click", clickCaptured, true);
|
101 | Object.defineProperty(prototype, "submitter", {
|
102 | get() {
|
103 | if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
104 | return submittersByForm.get(this.target);
|
105 | }
|
106 | },
|
107 | });
|
108 | })();
|
109 |
|
110 | var FrameLoadingStyle;
|
111 | (function (FrameLoadingStyle) {
|
112 | FrameLoadingStyle["eager"] = "eager";
|
113 | FrameLoadingStyle["lazy"] = "lazy";
|
114 | })(FrameLoadingStyle || (FrameLoadingStyle = {}));
|
115 | class FrameElement extends HTMLElement {
|
116 | constructor() {
|
117 | super();
|
118 | this.loaded = Promise.resolve();
|
119 | this.delegate = new FrameElement.delegateConstructor(this);
|
120 | }
|
121 | static get observedAttributes() {
|
122 | return ["disabled", "complete", "loading", "src"];
|
123 | }
|
124 | connectedCallback() {
|
125 | this.delegate.connect();
|
126 | }
|
127 | disconnectedCallback() {
|
128 | this.delegate.disconnect();
|
129 | }
|
130 | reload() {
|
131 | return this.delegate.sourceURLReloaded();
|
132 | }
|
133 | attributeChangedCallback(name) {
|
134 | if (name == "loading") {
|
135 | this.delegate.loadingStyleChanged();
|
136 | }
|
137 | else if (name == "complete") {
|
138 | this.delegate.completeChanged();
|
139 | }
|
140 | else if (name == "src") {
|
141 | this.delegate.sourceURLChanged();
|
142 | }
|
143 | else {
|
144 | this.delegate.disabledChanged();
|
145 | }
|
146 | }
|
147 | get src() {
|
148 | return this.getAttribute("src");
|
149 | }
|
150 | set src(value) {
|
151 | if (value) {
|
152 | this.setAttribute("src", value);
|
153 | }
|
154 | else {
|
155 | this.removeAttribute("src");
|
156 | }
|
157 | }
|
158 | get loading() {
|
159 | return frameLoadingStyleFromString(this.getAttribute("loading") || "");
|
160 | }
|
161 | set loading(value) {
|
162 | if (value) {
|
163 | this.setAttribute("loading", value);
|
164 | }
|
165 | else {
|
166 | this.removeAttribute("loading");
|
167 | }
|
168 | }
|
169 | get disabled() {
|
170 | return this.hasAttribute("disabled");
|
171 | }
|
172 | set disabled(value) {
|
173 | if (value) {
|
174 | this.setAttribute("disabled", "");
|
175 | }
|
176 | else {
|
177 | this.removeAttribute("disabled");
|
178 | }
|
179 | }
|
180 | get autoscroll() {
|
181 | return this.hasAttribute("autoscroll");
|
182 | }
|
183 | set autoscroll(value) {
|
184 | if (value) {
|
185 | this.setAttribute("autoscroll", "");
|
186 | }
|
187 | else {
|
188 | this.removeAttribute("autoscroll");
|
189 | }
|
190 | }
|
191 | get complete() {
|
192 | return !this.delegate.isLoading;
|
193 | }
|
194 | get isActive() {
|
195 | return this.ownerDocument === document && !this.isPreview;
|
196 | }
|
197 | get isPreview() {
|
198 | var _a, _b;
|
199 | return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
|
200 | }
|
201 | }
|
202 | function frameLoadingStyleFromString(style) {
|
203 | switch (style.toLowerCase()) {
|
204 | case "lazy":
|
205 | return FrameLoadingStyle.lazy;
|
206 | default:
|
207 | return FrameLoadingStyle.eager;
|
208 | }
|
209 | }
|
210 |
|
211 | function expandURL(locatable) {
|
212 | return new URL(locatable.toString(), document.baseURI);
|
213 | }
|
214 | function getAnchor(url) {
|
215 | let anchorMatch;
|
216 | if (url.hash) {
|
217 | return url.hash.slice(1);
|
218 | }
|
219 | else if ((anchorMatch = url.href.match(/#(.*)$/))) {
|
220 | return anchorMatch[1];
|
221 | }
|
222 | }
|
223 | function getAction(form, submitter) {
|
224 | const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formaction")) || form.getAttribute("action") || form.action;
|
225 | return expandURL(action);
|
226 | }
|
227 | function getExtension(url) {
|
228 | return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
229 | }
|
230 | function isHTML(url) {
|
231 | return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml|php))$/);
|
232 | }
|
233 | function isPrefixedBy(baseURL, url) {
|
234 | const prefix = getPrefix(url);
|
235 | return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
|
236 | }
|
237 | function locationIsVisitable(location, rootLocation) {
|
238 | return isPrefixedBy(location, rootLocation) && isHTML(location);
|
239 | }
|
240 | function getRequestURL(url) {
|
241 | const anchor = getAnchor(url);
|
242 | return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
|
243 | }
|
244 | function toCacheKey(url) {
|
245 | return getRequestURL(url);
|
246 | }
|
247 | function urlsAreEqual(left, right) {
|
248 | return expandURL(left).href == expandURL(right).href;
|
249 | }
|
250 | function getPathComponents(url) {
|
251 | return url.pathname.split("/").slice(1);
|
252 | }
|
253 | function getLastPathComponent(url) {
|
254 | return getPathComponents(url).slice(-1)[0];
|
255 | }
|
256 | function getPrefix(url) {
|
257 | return addTrailingSlash(url.origin + url.pathname);
|
258 | }
|
259 | function addTrailingSlash(value) {
|
260 | return value.endsWith("/") ? value : value + "/";
|
261 | }
|
262 |
|
263 | class FetchResponse {
|
264 | constructor(response) {
|
265 | this.response = response;
|
266 | }
|
267 | get succeeded() {
|
268 | return this.response.ok;
|
269 | }
|
270 | get failed() {
|
271 | return !this.succeeded;
|
272 | }
|
273 | get clientError() {
|
274 | return this.statusCode >= 400 && this.statusCode <= 499;
|
275 | }
|
276 | get serverError() {
|
277 | return this.statusCode >= 500 && this.statusCode <= 599;
|
278 | }
|
279 | get redirected() {
|
280 | return this.response.redirected;
|
281 | }
|
282 | get location() {
|
283 | return expandURL(this.response.url);
|
284 | }
|
285 | get isHTML() {
|
286 | return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
|
287 | }
|
288 | get statusCode() {
|
289 | return this.response.status;
|
290 | }
|
291 | get contentType() {
|
292 | return this.header("Content-Type");
|
293 | }
|
294 | get responseText() {
|
295 | return this.response.clone().text();
|
296 | }
|
297 | get responseHTML() {
|
298 | if (this.isHTML) {
|
299 | return this.response.clone().text();
|
300 | }
|
301 | else {
|
302 | return Promise.resolve(undefined);
|
303 | }
|
304 | }
|
305 | header(name) {
|
306 | return this.response.headers.get(name);
|
307 | }
|
308 | }
|
309 |
|
310 | function isAction(action) {
|
311 | return action == "advance" || action == "replace" || action == "restore";
|
312 | }
|
313 |
|
314 | function activateScriptElement(element) {
|
315 | if (element.getAttribute("data-turbo-eval") == "false") {
|
316 | return element;
|
317 | }
|
318 | else {
|
319 | const createdScriptElement = document.createElement("script");
|
320 | const cspNonce = getMetaContent("csp-nonce");
|
321 | if (cspNonce) {
|
322 | createdScriptElement.nonce = cspNonce;
|
323 | }
|
324 | createdScriptElement.textContent = element.textContent;
|
325 | createdScriptElement.async = false;
|
326 | copyElementAttributes(createdScriptElement, element);
|
327 | return createdScriptElement;
|
328 | }
|
329 | }
|
330 | function copyElementAttributes(destinationElement, sourceElement) {
|
331 | for (const { name, value } of sourceElement.attributes) {
|
332 | destinationElement.setAttribute(name, value);
|
333 | }
|
334 | }
|
335 | function createDocumentFragment(html) {
|
336 | const template = document.createElement("template");
|
337 | template.innerHTML = html;
|
338 | return template.content;
|
339 | }
|
340 | function dispatch(eventName, { target, cancelable, detail } = {}) {
|
341 | const event = new CustomEvent(eventName, {
|
342 | cancelable,
|
343 | bubbles: true,
|
344 | detail,
|
345 | });
|
346 | if (target && target.isConnected) {
|
347 | target.dispatchEvent(event);
|
348 | }
|
349 | else {
|
350 | document.documentElement.dispatchEvent(event);
|
351 | }
|
352 | return event;
|
353 | }
|
354 | function nextAnimationFrame() {
|
355 | return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
356 | }
|
357 | function nextEventLoopTick() {
|
358 | return new Promise((resolve) => setTimeout(() => resolve(), 0));
|
359 | }
|
360 | function nextMicrotask() {
|
361 | return Promise.resolve();
|
362 | }
|
363 | function parseHTMLDocument(html = "") {
|
364 | return new DOMParser().parseFromString(html, "text/html");
|
365 | }
|
366 | function unindent(strings, ...values) {
|
367 | const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
|
368 | const match = lines[0].match(/^\s+/);
|
369 | const indent = match ? match[0].length : 0;
|
370 | return lines.map((line) => line.slice(indent)).join("\n");
|
371 | }
|
372 | function interpolate(strings, values) {
|
373 | return strings.reduce((result, string, i) => {
|
374 | const value = values[i] == undefined ? "" : values[i];
|
375 | return result + string + value;
|
376 | }, "");
|
377 | }
|
378 | function uuid() {
|
379 | return Array.from({ length: 36 })
|
380 | .map((_, i) => {
|
381 | if (i == 8 || i == 13 || i == 18 || i == 23) {
|
382 | return "-";
|
383 | }
|
384 | else if (i == 14) {
|
385 | return "4";
|
386 | }
|
387 | else if (i == 19) {
|
388 | return (Math.floor(Math.random() * 4) + 8).toString(16);
|
389 | }
|
390 | else {
|
391 | return Math.floor(Math.random() * 15).toString(16);
|
392 | }
|
393 | })
|
394 | .join("");
|
395 | }
|
396 | function getAttribute(attributeName, ...elements) {
|
397 | for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
398 | if (typeof value == "string")
|
399 | return value;
|
400 | }
|
401 | return null;
|
402 | }
|
403 | function hasAttribute(attributeName, ...elements) {
|
404 | return elements.some((element) => element && element.hasAttribute(attributeName));
|
405 | }
|
406 | function markAsBusy(...elements) {
|
407 | for (const element of elements) {
|
408 | if (element.localName == "turbo-frame") {
|
409 | element.setAttribute("busy", "");
|
410 | }
|
411 | element.setAttribute("aria-busy", "true");
|
412 | }
|
413 | }
|
414 | function clearBusyState(...elements) {
|
415 | for (const element of elements) {
|
416 | if (element.localName == "turbo-frame") {
|
417 | element.removeAttribute("busy");
|
418 | }
|
419 | element.removeAttribute("aria-busy");
|
420 | }
|
421 | }
|
422 | function waitForLoad(element, timeoutInMilliseconds = 2000) {
|
423 | return new Promise((resolve) => {
|
424 | const onComplete = () => {
|
425 | element.removeEventListener("error", onComplete);
|
426 | element.removeEventListener("load", onComplete);
|
427 | resolve();
|
428 | };
|
429 | element.addEventListener("load", onComplete, { once: true });
|
430 | element.addEventListener("error", onComplete, { once: true });
|
431 | setTimeout(resolve, timeoutInMilliseconds);
|
432 | });
|
433 | }
|
434 | function getHistoryMethodForAction(action) {
|
435 | switch (action) {
|
436 | case "replace":
|
437 | return history.replaceState;
|
438 | case "advance":
|
439 | case "restore":
|
440 | return history.pushState;
|
441 | }
|
442 | }
|
443 | function getVisitAction(...elements) {
|
444 | const action = getAttribute("data-turbo-action", ...elements);
|
445 | return isAction(action) ? action : null;
|
446 | }
|
447 | function getMetaElement(name) {
|
448 | return document.querySelector(`meta[name="${name}"]`);
|
449 | }
|
450 | function getMetaContent(name) {
|
451 | const element = getMetaElement(name);
|
452 | return element && element.content;
|
453 | }
|
454 | function setMetaContent(name, content) {
|
455 | let element = getMetaElement(name);
|
456 | if (!element) {
|
457 | element = document.createElement("meta");
|
458 | element.setAttribute("name", name);
|
459 | document.head.appendChild(element);
|
460 | }
|
461 | element.setAttribute("content", content);
|
462 | return element;
|
463 | }
|
464 |
|
465 | var FetchMethod;
|
466 | (function (FetchMethod) {
|
467 | FetchMethod[FetchMethod["get"] = 0] = "get";
|
468 | FetchMethod[FetchMethod["post"] = 1] = "post";
|
469 | FetchMethod[FetchMethod["put"] = 2] = "put";
|
470 | FetchMethod[FetchMethod["patch"] = 3] = "patch";
|
471 | FetchMethod[FetchMethod["delete"] = 4] = "delete";
|
472 | })(FetchMethod || (FetchMethod = {}));
|
473 | function fetchMethodFromString(method) {
|
474 | switch (method.toLowerCase()) {
|
475 | case "get":
|
476 | return FetchMethod.get;
|
477 | case "post":
|
478 | return FetchMethod.post;
|
479 | case "put":
|
480 | return FetchMethod.put;
|
481 | case "patch":
|
482 | return FetchMethod.patch;
|
483 | case "delete":
|
484 | return FetchMethod.delete;
|
485 | }
|
486 | }
|
487 | class FetchRequest {
|
488 | constructor(delegate, method, location, body = new URLSearchParams(), target = null) {
|
489 | this.abortController = new AbortController();
|
490 | this.resolveRequestPromise = (_value) => { };
|
491 | this.delegate = delegate;
|
492 | this.method = method;
|
493 | this.headers = this.defaultHeaders;
|
494 | this.body = body;
|
495 | this.url = location;
|
496 | this.target = target;
|
497 | }
|
498 | get location() {
|
499 | return this.url;
|
500 | }
|
501 | get params() {
|
502 | return this.url.searchParams;
|
503 | }
|
504 | get entries() {
|
505 | return this.body ? Array.from(this.body.entries()) : [];
|
506 | }
|
507 | cancel() {
|
508 | this.abortController.abort();
|
509 | }
|
510 | async perform() {
|
511 | var _a, _b;
|
512 | const { fetchOptions } = this;
|
513 | (_b = (_a = this.delegate).prepareHeadersForRequest) === null || _b === void 0 ? void 0 : _b.call(_a, this.headers, this);
|
514 | await this.allowRequestToBeIntercepted(fetchOptions);
|
515 | try {
|
516 | this.delegate.requestStarted(this);
|
517 | const response = await fetch(this.url.href, fetchOptions);
|
518 | return await this.receive(response);
|
519 | }
|
520 | catch (error) {
|
521 | if (error.name !== "AbortError") {
|
522 | if (this.willDelegateErrorHandling(error)) {
|
523 | this.delegate.requestErrored(this, error);
|
524 | }
|
525 | throw error;
|
526 | }
|
527 | }
|
528 | finally {
|
529 | this.delegate.requestFinished(this);
|
530 | }
|
531 | }
|
532 | async receive(response) {
|
533 | const fetchResponse = new FetchResponse(response);
|
534 | const event = dispatch("turbo:before-fetch-response", {
|
535 | cancelable: true,
|
536 | detail: { fetchResponse },
|
537 | target: this.target,
|
538 | });
|
539 | if (event.defaultPrevented) {
|
540 | this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
|
541 | }
|
542 | else if (fetchResponse.succeeded) {
|
543 | this.delegate.requestSucceededWithResponse(this, fetchResponse);
|
544 | }
|
545 | else {
|
546 | this.delegate.requestFailedWithResponse(this, fetchResponse);
|
547 | }
|
548 | return fetchResponse;
|
549 | }
|
550 | get fetchOptions() {
|
551 | var _a;
|
552 | return {
|
553 | method: FetchMethod[this.method].toUpperCase(),
|
554 | credentials: "same-origin",
|
555 | headers: this.headers,
|
556 | redirect: "follow",
|
557 | body: this.isIdempotent ? null : this.body,
|
558 | signal: this.abortSignal,
|
559 | referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href,
|
560 | };
|
561 | }
|
562 | get defaultHeaders() {
|
563 | return {
|
564 | Accept: "text/html, application/xhtml+xml",
|
565 | };
|
566 | }
|
567 | get isIdempotent() {
|
568 | return this.method == FetchMethod.get;
|
569 | }
|
570 | get abortSignal() {
|
571 | return this.abortController.signal;
|
572 | }
|
573 | acceptResponseType(mimeType) {
|
574 | this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
|
575 | }
|
576 | async allowRequestToBeIntercepted(fetchOptions) {
|
577 | const requestInterception = new Promise((resolve) => (this.resolveRequestPromise = resolve));
|
578 | const event = dispatch("turbo:before-fetch-request", {
|
579 | cancelable: true,
|
580 | detail: {
|
581 | fetchOptions,
|
582 | url: this.url,
|
583 | resume: this.resolveRequestPromise,
|
584 | },
|
585 | target: this.target,
|
586 | });
|
587 | if (event.defaultPrevented)
|
588 | await requestInterception;
|
589 | }
|
590 | willDelegateErrorHandling(error) {
|
591 | const event = dispatch("turbo:fetch-request-error", {
|
592 | target: this.target,
|
593 | cancelable: true,
|
594 | detail: { request: this, error: error },
|
595 | });
|
596 | return !event.defaultPrevented;
|
597 | }
|
598 | }
|
599 |
|
600 | class AppearanceObserver {
|
601 | constructor(delegate, element) {
|
602 | this.started = false;
|
603 | this.intersect = (entries) => {
|
604 | const lastEntry = entries.slice(-1)[0];
|
605 | if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
606 | this.delegate.elementAppearedInViewport(this.element);
|
607 | }
|
608 | };
|
609 | this.delegate = delegate;
|
610 | this.element = element;
|
611 | this.intersectionObserver = new IntersectionObserver(this.intersect);
|
612 | }
|
613 | start() {
|
614 | if (!this.started) {
|
615 | this.started = true;
|
616 | this.intersectionObserver.observe(this.element);
|
617 | }
|
618 | }
|
619 | stop() {
|
620 | if (this.started) {
|
621 | this.started = false;
|
622 | this.intersectionObserver.unobserve(this.element);
|
623 | }
|
624 | }
|
625 | }
|
626 |
|
627 | class StreamMessage {
|
628 | constructor(fragment) {
|
629 | this.fragment = importStreamElements(fragment);
|
630 | }
|
631 | static wrap(message) {
|
632 | if (typeof message == "string") {
|
633 | return new this(createDocumentFragment(message));
|
634 | }
|
635 | else {
|
636 | return message;
|
637 | }
|
638 | }
|
639 | }
|
640 | StreamMessage.contentType = "text/vnd.turbo-stream.html";
|
641 | function importStreamElements(fragment) {
|
642 | for (const element of fragment.querySelectorAll("turbo-stream")) {
|
643 | const streamElement = document.importNode(element, true);
|
644 | for (const inertScriptElement of streamElement.templateElement.content.querySelectorAll("script")) {
|
645 | inertScriptElement.replaceWith(activateScriptElement(inertScriptElement));
|
646 | }
|
647 | element.replaceWith(streamElement);
|
648 | }
|
649 | return fragment;
|
650 | }
|
651 |
|
652 | var FormSubmissionState;
|
653 | (function (FormSubmissionState) {
|
654 | FormSubmissionState[FormSubmissionState["initialized"] = 0] = "initialized";
|
655 | FormSubmissionState[FormSubmissionState["requesting"] = 1] = "requesting";
|
656 | FormSubmissionState[FormSubmissionState["waiting"] = 2] = "waiting";
|
657 | FormSubmissionState[FormSubmissionState["receiving"] = 3] = "receiving";
|
658 | FormSubmissionState[FormSubmissionState["stopping"] = 4] = "stopping";
|
659 | FormSubmissionState[FormSubmissionState["stopped"] = 5] = "stopped";
|
660 | })(FormSubmissionState || (FormSubmissionState = {}));
|
661 | var FormEnctype;
|
662 | (function (FormEnctype) {
|
663 | FormEnctype["urlEncoded"] = "application/x-www-form-urlencoded";
|
664 | FormEnctype["multipart"] = "multipart/form-data";
|
665 | FormEnctype["plain"] = "text/plain";
|
666 | })(FormEnctype || (FormEnctype = {}));
|
667 | function formEnctypeFromString(encoding) {
|
668 | switch (encoding.toLowerCase()) {
|
669 | case FormEnctype.multipart:
|
670 | return FormEnctype.multipart;
|
671 | case FormEnctype.plain:
|
672 | return FormEnctype.plain;
|
673 | default:
|
674 | return FormEnctype.urlEncoded;
|
675 | }
|
676 | }
|
677 | class FormSubmission {
|
678 | constructor(delegate, formElement, submitter, mustRedirect = false) {
|
679 | this.state = FormSubmissionState.initialized;
|
680 | this.delegate = delegate;
|
681 | this.formElement = formElement;
|
682 | this.submitter = submitter;
|
683 | this.formData = buildFormData(formElement, submitter);
|
684 | this.location = expandURL(this.action);
|
685 | if (this.method == FetchMethod.get) {
|
686 | mergeFormDataEntries(this.location, [...this.body.entries()]);
|
687 | }
|
688 | this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
689 | this.mustRedirect = mustRedirect;
|
690 | }
|
691 | static confirmMethod(message, _element, _submitter) {
|
692 | return Promise.resolve(confirm(message));
|
693 | }
|
694 | get method() {
|
695 | var _a;
|
696 | const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || "";
|
697 | return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get;
|
698 | }
|
699 | get action() {
|
700 | var _a;
|
701 | const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
|
702 | if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
|
703 | return this.submitter.getAttribute("formaction") || "";
|
704 | }
|
705 | else {
|
706 | return this.formElement.getAttribute("action") || formElementAction || "";
|
707 | }
|
708 | }
|
709 | get body() {
|
710 | if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
|
711 | return new URLSearchParams(this.stringFormData);
|
712 | }
|
713 | else {
|
714 | return this.formData;
|
715 | }
|
716 | }
|
717 | get enctype() {
|
718 | var _a;
|
719 | return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
|
720 | }
|
721 | get isIdempotent() {
|
722 | return this.fetchRequest.isIdempotent;
|
723 | }
|
724 | get stringFormData() {
|
725 | return [...this.formData].reduce((entries, [name, value]) => {
|
726 | return entries.concat(typeof value == "string" ? [[name, value]] : []);
|
727 | }, []);
|
728 | }
|
729 | async start() {
|
730 | const { initialized, requesting } = FormSubmissionState;
|
731 | const confirmationMessage = getAttribute("data-turbo-confirm", this.submitter, this.formElement);
|
732 | if (typeof confirmationMessage === "string") {
|
733 | const answer = await FormSubmission.confirmMethod(confirmationMessage, this.formElement, this.submitter);
|
734 | if (!answer) {
|
735 | return;
|
736 | }
|
737 | }
|
738 | if (this.state == initialized) {
|
739 | this.state = requesting;
|
740 | return this.fetchRequest.perform();
|
741 | }
|
742 | }
|
743 | stop() {
|
744 | const { stopping, stopped } = FormSubmissionState;
|
745 | if (this.state != stopping && this.state != stopped) {
|
746 | this.state = stopping;
|
747 | this.fetchRequest.cancel();
|
748 | return true;
|
749 | }
|
750 | }
|
751 | prepareHeadersForRequest(headers, request) {
|
752 | if (!request.isIdempotent) {
|
753 | const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
|
754 | if (token) {
|
755 | headers["X-CSRF-Token"] = token;
|
756 | }
|
757 | }
|
758 | if (this.requestAcceptsTurboStreamResponse(request)) {
|
759 | request.acceptResponseType(StreamMessage.contentType);
|
760 | }
|
761 | }
|
762 | requestStarted(_request) {
|
763 | var _a;
|
764 | this.state = FormSubmissionState.waiting;
|
765 | (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
|
766 | dispatch("turbo:submit-start", {
|
767 | target: this.formElement,
|
768 | detail: { formSubmission: this },
|
769 | });
|
770 | this.delegate.formSubmissionStarted(this);
|
771 | }
|
772 | requestPreventedHandlingResponse(request, response) {
|
773 | this.result = { success: response.succeeded, fetchResponse: response };
|
774 | }
|
775 | requestSucceededWithResponse(request, response) {
|
776 | if (response.clientError || response.serverError) {
|
777 | this.delegate.formSubmissionFailedWithResponse(this, response);
|
778 | }
|
779 | else if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {
|
780 | const error = new Error("Form responses must redirect to another location");
|
781 | this.delegate.formSubmissionErrored(this, error);
|
782 | }
|
783 | else {
|
784 | this.state = FormSubmissionState.receiving;
|
785 | this.result = { success: true, fetchResponse: response };
|
786 | this.delegate.formSubmissionSucceededWithResponse(this, response);
|
787 | }
|
788 | }
|
789 | requestFailedWithResponse(request, response) {
|
790 | this.result = { success: false, fetchResponse: response };
|
791 | this.delegate.formSubmissionFailedWithResponse(this, response);
|
792 | }
|
793 | requestErrored(request, error) {
|
794 | this.result = { success: false, error };
|
795 | this.delegate.formSubmissionErrored(this, error);
|
796 | }
|
797 | requestFinished(_request) {
|
798 | var _a;
|
799 | this.state = FormSubmissionState.stopped;
|
800 | (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
|
801 | dispatch("turbo:submit-end", {
|
802 | target: this.formElement,
|
803 | detail: Object.assign({ formSubmission: this }, this.result),
|
804 | });
|
805 | this.delegate.formSubmissionFinished(this);
|
806 | }
|
807 | requestMustRedirect(request) {
|
808 | return !request.isIdempotent && this.mustRedirect;
|
809 | }
|
810 | requestAcceptsTurboStreamResponse(request) {
|
811 | return !request.isIdempotent || hasAttribute("data-turbo-stream", this.submitter, this.formElement);
|
812 | }
|
813 | }
|
814 | function buildFormData(formElement, submitter) {
|
815 | const formData = new FormData(formElement);
|
816 | const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
|
817 | const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
|
818 | if (name) {
|
819 | formData.append(name, value || "");
|
820 | }
|
821 | return formData;
|
822 | }
|
823 | function getCookieValue(cookieName) {
|
824 | if (cookieName != null) {
|
825 | const cookies = document.cookie ? document.cookie.split("; ") : [];
|
826 | const cookie = cookies.find((cookie) => cookie.startsWith(cookieName));
|
827 | if (cookie) {
|
828 | const value = cookie.split("=").slice(1).join("=");
|
829 | return value ? decodeURIComponent(value) : undefined;
|
830 | }
|
831 | }
|
832 | }
|
833 | function responseSucceededWithoutRedirect(response) {
|
834 | return response.statusCode == 200 && !response.redirected;
|
835 | }
|
836 | function mergeFormDataEntries(url, entries) {
|
837 | const searchParams = new URLSearchParams();
|
838 | for (const [name, value] of entries) {
|
839 | if (value instanceof File)
|
840 | continue;
|
841 | searchParams.append(name, value);
|
842 | }
|
843 | url.search = searchParams.toString();
|
844 | return url;
|
845 | }
|
846 |
|
847 | class Snapshot {
|
848 | constructor(element) {
|
849 | this.element = element;
|
850 | }
|
851 | get activeElement() {
|
852 | return this.element.ownerDocument.activeElement;
|
853 | }
|
854 | get children() {
|
855 | return [...this.element.children];
|
856 | }
|
857 | hasAnchor(anchor) {
|
858 | return this.getElementForAnchor(anchor) != null;
|
859 | }
|
860 | getElementForAnchor(anchor) {
|
861 | return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null;
|
862 | }
|
863 | get isConnected() {
|
864 | return this.element.isConnected;
|
865 | }
|
866 | get firstAutofocusableElement() {
|
867 | const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
|
868 | for (const element of this.element.querySelectorAll("[autofocus]")) {
|
869 | if (element.closest(inertDisabledOrHidden) == null)
|
870 | return element;
|
871 | else
|
872 | continue;
|
873 | }
|
874 | return null;
|
875 | }
|
876 | get permanentElements() {
|
877 | return queryPermanentElementsAll(this.element);
|
878 | }
|
879 | getPermanentElementById(id) {
|
880 | return getPermanentElementById(this.element, id);
|
881 | }
|
882 | getPermanentElementMapForSnapshot(snapshot) {
|
883 | const permanentElementMap = {};
|
884 | for (const currentPermanentElement of this.permanentElements) {
|
885 | const { id } = currentPermanentElement;
|
886 | const newPermanentElement = snapshot.getPermanentElementById(id);
|
887 | if (newPermanentElement) {
|
888 | permanentElementMap[id] = [currentPermanentElement, newPermanentElement];
|
889 | }
|
890 | }
|
891 | return permanentElementMap;
|
892 | }
|
893 | }
|
894 | function getPermanentElementById(node, id) {
|
895 | return node.querySelector(`#${id}[data-turbo-permanent]`);
|
896 | }
|
897 | function queryPermanentElementsAll(node) {
|
898 | return node.querySelectorAll("[id][data-turbo-permanent]");
|
899 | }
|
900 |
|
901 | class FormSubmitObserver {
|
902 | constructor(delegate, eventTarget) {
|
903 | this.started = false;
|
904 | this.submitCaptured = () => {
|
905 | this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
|
906 | this.eventTarget.addEventListener("submit", this.submitBubbled, false);
|
907 | };
|
908 | this.submitBubbled = ((event) => {
|
909 | if (!event.defaultPrevented) {
|
910 | const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
911 | const submitter = event.submitter || undefined;
|
912 | if (form &&
|
913 | submissionDoesNotDismissDialog(form, submitter) &&
|
914 | submissionDoesNotTargetIFrame(form, submitter) &&
|
915 | this.delegate.willSubmitForm(form, submitter)) {
|
916 | event.preventDefault();
|
917 | event.stopImmediatePropagation();
|
918 | this.delegate.formSubmitted(form, submitter);
|
919 | }
|
920 | }
|
921 | });
|
922 | this.delegate = delegate;
|
923 | this.eventTarget = eventTarget;
|
924 | }
|
925 | start() {
|
926 | if (!this.started) {
|
927 | this.eventTarget.addEventListener("submit", this.submitCaptured, true);
|
928 | this.started = true;
|
929 | }
|
930 | }
|
931 | stop() {
|
932 | if (this.started) {
|
933 | this.eventTarget.removeEventListener("submit", this.submitCaptured, true);
|
934 | this.started = false;
|
935 | }
|
936 | }
|
937 | }
|
938 | function submissionDoesNotDismissDialog(form, submitter) {
|
939 | const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
|
940 | return method != "dialog";
|
941 | }
|
942 | function submissionDoesNotTargetIFrame(form, submitter) {
|
943 | const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
|
944 | for (const element of document.getElementsByName(target)) {
|
945 | if (element instanceof HTMLIFrameElement)
|
946 | return false;
|
947 | }
|
948 | return true;
|
949 | }
|
950 |
|
951 | class View {
|
952 | constructor(delegate, element) {
|
953 | this.resolveRenderPromise = (_value) => { };
|
954 | this.resolveInterceptionPromise = (_value) => { };
|
955 | this.delegate = delegate;
|
956 | this.element = element;
|
957 | }
|
958 | scrollToAnchor(anchor) {
|
959 | const element = this.snapshot.getElementForAnchor(anchor);
|
960 | if (element) {
|
961 | this.scrollToElement(element);
|
962 | this.focusElement(element);
|
963 | }
|
964 | else {
|
965 | this.scrollToPosition({ x: 0, y: 0 });
|
966 | }
|
967 | }
|
968 | scrollToAnchorFromLocation(location) {
|
969 | this.scrollToAnchor(getAnchor(location));
|
970 | }
|
971 | scrollToElement(element) {
|
972 | element.scrollIntoView();
|
973 | }
|
974 | focusElement(element) {
|
975 | if (element instanceof HTMLElement) {
|
976 | if (element.hasAttribute("tabindex")) {
|
977 | element.focus();
|
978 | }
|
979 | else {
|
980 | element.setAttribute("tabindex", "-1");
|
981 | element.focus();
|
982 | element.removeAttribute("tabindex");
|
983 | }
|
984 | }
|
985 | }
|
986 | scrollToPosition({ x, y }) {
|
987 | this.scrollRoot.scrollTo(x, y);
|
988 | }
|
989 | scrollToTop() {
|
990 | this.scrollToPosition({ x: 0, y: 0 });
|
991 | }
|
992 | get scrollRoot() {
|
993 | return window;
|
994 | }
|
995 | async render(renderer) {
|
996 | const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
|
997 | if (shouldRender) {
|
998 | try {
|
999 | this.renderPromise = new Promise((resolve) => (this.resolveRenderPromise = resolve));
|
1000 | this.renderer = renderer;
|
1001 | await this.prepareToRenderSnapshot(renderer);
|
1002 | const renderInterception = new Promise((resolve) => (this.resolveInterceptionPromise = resolve));
|
1003 | const options = { resume: this.resolveInterceptionPromise, render: this.renderer.renderElement };
|
1004 | const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
|
1005 | if (!immediateRender)
|
1006 | await renderInterception;
|
1007 | await this.renderSnapshot(renderer);
|
1008 | this.delegate.viewRenderedSnapshot(snapshot, isPreview);
|
1009 | this.delegate.preloadOnLoadLinksForView(this.element);
|
1010 | this.finishRenderingSnapshot(renderer);
|
1011 | }
|
1012 | finally {
|
1013 | delete this.renderer;
|
1014 | this.resolveRenderPromise(undefined);
|
1015 | delete this.renderPromise;
|
1016 | }
|
1017 | }
|
1018 | else {
|
1019 | this.invalidate(renderer.reloadReason);
|
1020 | }
|
1021 | }
|
1022 | invalidate(reason) {
|
1023 | this.delegate.viewInvalidated(reason);
|
1024 | }
|
1025 | async prepareToRenderSnapshot(renderer) {
|
1026 | this.markAsPreview(renderer.isPreview);
|
1027 | await renderer.prepareToRender();
|
1028 | }
|
1029 | markAsPreview(isPreview) {
|
1030 | if (isPreview) {
|
1031 | this.element.setAttribute("data-turbo-preview", "");
|
1032 | }
|
1033 | else {
|
1034 | this.element.removeAttribute("data-turbo-preview");
|
1035 | }
|
1036 | }
|
1037 | async renderSnapshot(renderer) {
|
1038 | await renderer.render();
|
1039 | }
|
1040 | finishRenderingSnapshot(renderer) {
|
1041 | renderer.finishRendering();
|
1042 | }
|
1043 | }
|
1044 |
|
1045 | class FrameView extends View {
|
1046 | invalidate() {
|
1047 | this.element.innerHTML = "";
|
1048 | }
|
1049 | get snapshot() {
|
1050 | return new Snapshot(this.element);
|
1051 | }
|
1052 | }
|
1053 |
|
1054 | class LinkInterceptor {
|
1055 | constructor(delegate, element) {
|
1056 | this.clickBubbled = (event) => {
|
1057 | if (this.respondsToEventTarget(event.target)) {
|
1058 | this.clickEvent = event;
|
1059 | }
|
1060 | else {
|
1061 | delete this.clickEvent;
|
1062 | }
|
1063 | };
|
1064 | this.linkClicked = ((event) => {
|
1065 | if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) {
|
1066 | if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url, event.detail.originalEvent)) {
|
1067 | this.clickEvent.preventDefault();
|
1068 | event.preventDefault();
|
1069 | this.delegate.linkClickIntercepted(event.target, event.detail.url, event.detail.originalEvent);
|
1070 | }
|
1071 | }
|
1072 | delete this.clickEvent;
|
1073 | });
|
1074 | this.willVisit = ((_event) => {
|
1075 | delete this.clickEvent;
|
1076 | });
|
1077 | this.delegate = delegate;
|
1078 | this.element = element;
|
1079 | }
|
1080 | start() {
|
1081 | this.element.addEventListener("click", this.clickBubbled);
|
1082 | document.addEventListener("turbo:click", this.linkClicked);
|
1083 | document.addEventListener("turbo:before-visit", this.willVisit);
|
1084 | }
|
1085 | stop() {
|
1086 | this.element.removeEventListener("click", this.clickBubbled);
|
1087 | document.removeEventListener("turbo:click", this.linkClicked);
|
1088 | document.removeEventListener("turbo:before-visit", this.willVisit);
|
1089 | }
|
1090 | respondsToEventTarget(target) {
|
1091 | const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
1092 | return element && element.closest("turbo-frame, html") == this.element;
|
1093 | }
|
1094 | }
|
1095 |
|
1096 | class LinkClickObserver {
|
1097 | constructor(delegate, eventTarget) {
|
1098 | this.started = false;
|
1099 | this.clickCaptured = () => {
|
1100 | this.eventTarget.removeEventListener("click", this.clickBubbled, false);
|
1101 | this.eventTarget.addEventListener("click", this.clickBubbled, false);
|
1102 | };
|
1103 | this.clickBubbled = (event) => {
|
1104 | if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
|
1105 | const target = (event.composedPath && event.composedPath()[0]) || event.target;
|
1106 | const link = this.findLinkFromClickTarget(target);
|
1107 | if (link && doesNotTargetIFrame(link)) {
|
1108 | const location = this.getLocationForLink(link);
|
1109 | if (this.delegate.willFollowLinkToLocation(link, location, event)) {
|
1110 | event.preventDefault();
|
1111 | this.delegate.followedLinkToLocation(link, location);
|
1112 | }
|
1113 | }
|
1114 | }
|
1115 | };
|
1116 | this.delegate = delegate;
|
1117 | this.eventTarget = eventTarget;
|
1118 | }
|
1119 | start() {
|
1120 | if (!this.started) {
|
1121 | this.eventTarget.addEventListener("click", this.clickCaptured, true);
|
1122 | this.started = true;
|
1123 | }
|
1124 | }
|
1125 | stop() {
|
1126 | if (this.started) {
|
1127 | this.eventTarget.removeEventListener("click", this.clickCaptured, true);
|
1128 | this.started = false;
|
1129 | }
|
1130 | }
|
1131 | clickEventIsSignificant(event) {
|
1132 | return !((event.target && event.target.isContentEditable) ||
|
1133 | event.defaultPrevented ||
|
1134 | event.which > 1 ||
|
1135 | event.altKey ||
|
1136 | event.ctrlKey ||
|
1137 | event.metaKey ||
|
1138 | event.shiftKey);
|
1139 | }
|
1140 | findLinkFromClickTarget(target) {
|
1141 | if (target instanceof Element) {
|
1142 | return target.closest("a[href]:not([target^=_]):not([download])");
|
1143 | }
|
1144 | }
|
1145 | getLocationForLink(link) {
|
1146 | return expandURL(link.getAttribute("href") || "");
|
1147 | }
|
1148 | }
|
1149 | function doesNotTargetIFrame(anchor) {
|
1150 | for (const element of document.getElementsByName(anchor.target)) {
|
1151 | if (element instanceof HTMLIFrameElement)
|
1152 | return false;
|
1153 | }
|
1154 | return true;
|
1155 | }
|
1156 |
|
1157 | class FormLinkClickObserver {
|
1158 | constructor(delegate, element) {
|
1159 | this.delegate = delegate;
|
1160 | this.linkInterceptor = new LinkClickObserver(this, element);
|
1161 | }
|
1162 | start() {
|
1163 | this.linkInterceptor.start();
|
1164 | }
|
1165 | stop() {
|
1166 | this.linkInterceptor.stop();
|
1167 | }
|
1168 | willFollowLinkToLocation(link, location, originalEvent) {
|
1169 | return (this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) &&
|
1170 | link.hasAttribute("data-turbo-method"));
|
1171 | }
|
1172 | followedLinkToLocation(link, location) {
|
1173 | const action = location.href;
|
1174 | const form = document.createElement("form");
|
1175 | form.setAttribute("data-turbo", "true");
|
1176 | form.setAttribute("action", action);
|
1177 | form.setAttribute("hidden", "");
|
1178 | const method = link.getAttribute("data-turbo-method");
|
1179 | if (method)
|
1180 | form.setAttribute("method", method);
|
1181 | const turboFrame = link.getAttribute("data-turbo-frame");
|
1182 | if (turboFrame)
|
1183 | form.setAttribute("data-turbo-frame", turboFrame);
|
1184 | const turboAction = link.getAttribute("data-turbo-action");
|
1185 | if (turboAction)
|
1186 | form.setAttribute("data-turbo-action", turboAction);
|
1187 | const turboConfirm = link.getAttribute("data-turbo-confirm");
|
1188 | if (turboConfirm)
|
1189 | form.setAttribute("data-turbo-confirm", turboConfirm);
|
1190 | const turboStream = link.hasAttribute("data-turbo-stream");
|
1191 | if (turboStream)
|
1192 | form.setAttribute("data-turbo-stream", "");
|
1193 | this.delegate.submittedFormLinkToLocation(link, location, form);
|
1194 | document.body.appendChild(form);
|
1195 | form.addEventListener("turbo:submit-end", () => form.remove(), { once: true });
|
1196 | requestAnimationFrame(() => form.requestSubmit());
|
1197 | }
|
1198 | }
|
1199 |
|
1200 | class Bardo {
|
1201 | constructor(delegate, permanentElementMap) {
|
1202 | this.delegate = delegate;
|
1203 | this.permanentElementMap = permanentElementMap;
|
1204 | }
|
1205 | static preservingPermanentElements(delegate, permanentElementMap, callback) {
|
1206 | const bardo = new this(delegate, permanentElementMap);
|
1207 | bardo.enter();
|
1208 | callback();
|
1209 | bardo.leave();
|
1210 | }
|
1211 | enter() {
|
1212 | for (const id in this.permanentElementMap) {
|
1213 | const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
|
1214 | this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);
|
1215 | this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);
|
1216 | }
|
1217 | }
|
1218 | leave() {
|
1219 | for (const id in this.permanentElementMap) {
|
1220 | const [currentPermanentElement] = this.permanentElementMap[id];
|
1221 | this.replaceCurrentPermanentElementWithClone(currentPermanentElement);
|
1222 | this.replacePlaceholderWithPermanentElement(currentPermanentElement);
|
1223 | this.delegate.leavingBardo(currentPermanentElement);
|
1224 | }
|
1225 | }
|
1226 | replaceNewPermanentElementWithPlaceholder(permanentElement) {
|
1227 | const placeholder = createPlaceholderForPermanentElement(permanentElement);
|
1228 | permanentElement.replaceWith(placeholder);
|
1229 | }
|
1230 | replaceCurrentPermanentElementWithClone(permanentElement) {
|
1231 | const clone = permanentElement.cloneNode(true);
|
1232 | permanentElement.replaceWith(clone);
|
1233 | }
|
1234 | replacePlaceholderWithPermanentElement(permanentElement) {
|
1235 | const placeholder = this.getPlaceholderById(permanentElement.id);
|
1236 | placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);
|
1237 | }
|
1238 | getPlaceholderById(id) {
|
1239 | return this.placeholders.find((element) => element.content == id);
|
1240 | }
|
1241 | get placeholders() {
|
1242 | return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")];
|
1243 | }
|
1244 | }
|
1245 | function createPlaceholderForPermanentElement(permanentElement) {
|
1246 | const element = document.createElement("meta");
|
1247 | element.setAttribute("name", "turbo-permanent-placeholder");
|
1248 | element.setAttribute("content", permanentElement.id);
|
1249 | return element;
|
1250 | }
|
1251 |
|
1252 | class Renderer {
|
1253 | constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
1254 | this.activeElement = null;
|
1255 | this.currentSnapshot = currentSnapshot;
|
1256 | this.newSnapshot = newSnapshot;
|
1257 | this.isPreview = isPreview;
|
1258 | this.willRender = willRender;
|
1259 | this.renderElement = renderElement;
|
1260 | this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));
|
1261 | }
|
1262 | get shouldRender() {
|
1263 | return true;
|
1264 | }
|
1265 | get reloadReason() {
|
1266 | return;
|
1267 | }
|
1268 | prepareToRender() {
|
1269 | return;
|
1270 | }
|
1271 | finishRendering() {
|
1272 | if (this.resolvingFunctions) {
|
1273 | this.resolvingFunctions.resolve();
|
1274 | delete this.resolvingFunctions;
|
1275 | }
|
1276 | }
|
1277 | preservingPermanentElements(callback) {
|
1278 | Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
|
1279 | }
|
1280 | focusFirstAutofocusableElement() {
|
1281 | const element = this.connectedSnapshot.firstAutofocusableElement;
|
1282 | if (elementIsFocusable(element)) {
|
1283 | element.focus();
|
1284 | }
|
1285 | }
|
1286 | enteringBardo(currentPermanentElement) {
|
1287 | if (this.activeElement)
|
1288 | return;
|
1289 | if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
|
1290 | this.activeElement = this.currentSnapshot.activeElement;
|
1291 | }
|
1292 | }
|
1293 | leavingBardo(currentPermanentElement) {
|
1294 | if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {
|
1295 | this.activeElement.focus();
|
1296 | this.activeElement = null;
|
1297 | }
|
1298 | }
|
1299 | get connectedSnapshot() {
|
1300 | return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;
|
1301 | }
|
1302 | get currentElement() {
|
1303 | return this.currentSnapshot.element;
|
1304 | }
|
1305 | get newElement() {
|
1306 | return this.newSnapshot.element;
|
1307 | }
|
1308 | get permanentElementMap() {
|
1309 | return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
|
1310 | }
|
1311 | }
|
1312 | function elementIsFocusable(element) {
|
1313 | return element && typeof element.focus == "function";
|
1314 | }
|
1315 |
|
1316 | class FrameRenderer extends Renderer {
|
1317 | constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
1318 | super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
|
1319 | this.delegate = delegate;
|
1320 | }
|
1321 | static renderElement(currentElement, newElement) {
|
1322 | var _a;
|
1323 | const destinationRange = document.createRange();
|
1324 | destinationRange.selectNodeContents(currentElement);
|
1325 | destinationRange.deleteContents();
|
1326 | const frameElement = newElement;
|
1327 | const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
1328 | if (sourceRange) {
|
1329 | sourceRange.selectNodeContents(frameElement);
|
1330 | currentElement.appendChild(sourceRange.extractContents());
|
1331 | }
|
1332 | }
|
1333 | get shouldRender() {
|
1334 | return true;
|
1335 | }
|
1336 | async render() {
|
1337 | await nextAnimationFrame();
|
1338 | this.preservingPermanentElements(() => {
|
1339 | this.loadFrameElement();
|
1340 | });
|
1341 | this.scrollFrameIntoView();
|
1342 | await nextAnimationFrame();
|
1343 | this.focusFirstAutofocusableElement();
|
1344 | await nextAnimationFrame();
|
1345 | this.activateScriptElements();
|
1346 | }
|
1347 | loadFrameElement() {
|
1348 | this.delegate.willRenderFrame(this.currentElement, this.newElement);
|
1349 | this.renderElement(this.currentElement, this.newElement);
|
1350 | }
|
1351 | scrollFrameIntoView() {
|
1352 | if (this.currentElement.autoscroll || this.newElement.autoscroll) {
|
1353 | const element = this.currentElement.firstElementChild;
|
1354 | const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
|
1355 | const behavior = readScrollBehavior(this.currentElement.getAttribute("data-autoscroll-behavior"), "auto");
|
1356 | if (element) {
|
1357 | element.scrollIntoView({ block, behavior });
|
1358 | return true;
|
1359 | }
|
1360 | }
|
1361 | return false;
|
1362 | }
|
1363 | activateScriptElements() {
|
1364 | for (const inertScriptElement of this.newScriptElements) {
|
1365 | const activatedScriptElement = activateScriptElement(inertScriptElement);
|
1366 | inertScriptElement.replaceWith(activatedScriptElement);
|
1367 | }
|
1368 | }
|
1369 | get newScriptElements() {
|
1370 | return this.currentElement.querySelectorAll("script");
|
1371 | }
|
1372 | }
|
1373 | function readScrollLogicalPosition(value, defaultValue) {
|
1374 | if (value == "end" || value == "start" || value == "center" || value == "nearest") {
|
1375 | return value;
|
1376 | }
|
1377 | else {
|
1378 | return defaultValue;
|
1379 | }
|
1380 | }
|
1381 | function readScrollBehavior(value, defaultValue) {
|
1382 | if (value == "auto" || value == "smooth") {
|
1383 | return value;
|
1384 | }
|
1385 | else {
|
1386 | return defaultValue;
|
1387 | }
|
1388 | }
|
1389 |
|
1390 | class ProgressBar {
|
1391 | constructor() {
|
1392 | this.hiding = false;
|
1393 | this.value = 0;
|
1394 | this.visible = false;
|
1395 | this.trickle = () => {
|
1396 | this.setValue(this.value + Math.random() / 100);
|
1397 | };
|
1398 | this.stylesheetElement = this.createStylesheetElement();
|
1399 | this.progressElement = this.createProgressElement();
|
1400 | this.installStylesheetElement();
|
1401 | this.setValue(0);
|
1402 | }
|
1403 | static get defaultCSS() {
|
1404 | return unindent `
|
1405 | .turbo-progress-bar {
|
1406 | position: fixed;
|
1407 | display: block;
|
1408 | top: 0;
|
1409 | left: 0;
|
1410 | height: 3px;
|
1411 | background: #0076ff;
|
1412 | z-index: 2147483647;
|
1413 | transition:
|
1414 | width ${ProgressBar.animationDuration}ms ease-out,
|
1415 | opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in;
|
1416 | transform: translate3d(0, 0, 0);
|
1417 | }
|
1418 | `;
|
1419 | }
|
1420 | show() {
|
1421 | if (!this.visible) {
|
1422 | this.visible = true;
|
1423 | this.installProgressElement();
|
1424 | this.startTrickling();
|
1425 | }
|
1426 | }
|
1427 | hide() {
|
1428 | if (this.visible && !this.hiding) {
|
1429 | this.hiding = true;
|
1430 | this.fadeProgressElement(() => {
|
1431 | this.uninstallProgressElement();
|
1432 | this.stopTrickling();
|
1433 | this.visible = false;
|
1434 | this.hiding = false;
|
1435 | });
|
1436 | }
|
1437 | }
|
1438 | setValue(value) {
|
1439 | this.value = value;
|
1440 | this.refresh();
|
1441 | }
|
1442 | installStylesheetElement() {
|
1443 | document.head.insertBefore(this.stylesheetElement, document.head.firstChild);
|
1444 | }
|
1445 | installProgressElement() {
|
1446 | this.progressElement.style.width = "0";
|
1447 | this.progressElement.style.opacity = "1";
|
1448 | document.documentElement.insertBefore(this.progressElement, document.body);
|
1449 | this.refresh();
|
1450 | }
|
1451 | fadeProgressElement(callback) {
|
1452 | this.progressElement.style.opacity = "0";
|
1453 | setTimeout(callback, ProgressBar.animationDuration * 1.5);
|
1454 | }
|
1455 | uninstallProgressElement() {
|
1456 | if (this.progressElement.parentNode) {
|
1457 | document.documentElement.removeChild(this.progressElement);
|
1458 | }
|
1459 | }
|
1460 | startTrickling() {
|
1461 | if (!this.trickleInterval) {
|
1462 | this.trickleInterval = window.setInterval(this.trickle, ProgressBar.animationDuration);
|
1463 | }
|
1464 | }
|
1465 | stopTrickling() {
|
1466 | window.clearInterval(this.trickleInterval);
|
1467 | delete this.trickleInterval;
|
1468 | }
|
1469 | refresh() {
|
1470 | requestAnimationFrame(() => {
|
1471 | this.progressElement.style.width = `${10 + this.value * 90}%`;
|
1472 | });
|
1473 | }
|
1474 | createStylesheetElement() {
|
1475 | const element = document.createElement("style");
|
1476 | element.type = "text/css";
|
1477 | element.textContent = ProgressBar.defaultCSS;
|
1478 | if (this.cspNonce) {
|
1479 | element.nonce = this.cspNonce;
|
1480 | }
|
1481 | return element;
|
1482 | }
|
1483 | createProgressElement() {
|
1484 | const element = document.createElement("div");
|
1485 | element.className = "turbo-progress-bar";
|
1486 | return element;
|
1487 | }
|
1488 | get cspNonce() {
|
1489 | return getMetaContent("csp-nonce");
|
1490 | }
|
1491 | }
|
1492 | ProgressBar.animationDuration = 300;
|
1493 |
|
1494 | class HeadSnapshot extends Snapshot {
|
1495 | constructor() {
|
1496 | super(...arguments);
|
1497 | this.detailsByOuterHTML = this.children
|
1498 | .filter((element) => !elementIsNoscript(element))
|
1499 | .map((element) => elementWithoutNonce(element))
|
1500 | .reduce((result, element) => {
|
1501 | const { outerHTML } = element;
|
1502 | const details = outerHTML in result
|
1503 | ? result[outerHTML]
|
1504 | : {
|
1505 | type: elementType(element),
|
1506 | tracked: elementIsTracked(element),
|
1507 | elements: [],
|
1508 | };
|
1509 | return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });
|
1510 | }, {});
|
1511 | }
|
1512 | get trackedElementSignature() {
|
1513 | return Object.keys(this.detailsByOuterHTML)
|
1514 | .filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked)
|
1515 | .join("");
|
1516 | }
|
1517 | getScriptElementsNotInSnapshot(snapshot) {
|
1518 | return this.getElementsMatchingTypeNotInSnapshot("script", snapshot);
|
1519 | }
|
1520 | getStylesheetElementsNotInSnapshot(snapshot) {
|
1521 | return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot);
|
1522 | }
|
1523 | getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
|
1524 | return Object.keys(this.detailsByOuterHTML)
|
1525 | .filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML))
|
1526 | .map((outerHTML) => this.detailsByOuterHTML[outerHTML])
|
1527 | .filter(({ type }) => type == matchedType)
|
1528 | .map(({ elements: [element] }) => element);
|
1529 | }
|
1530 | get provisionalElements() {
|
1531 | return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
1532 | const { type, tracked, elements } = this.detailsByOuterHTML[outerHTML];
|
1533 | if (type == null && !tracked) {
|
1534 | return [...result, ...elements];
|
1535 | }
|
1536 | else if (elements.length > 1) {
|
1537 | return [...result, ...elements.slice(1)];
|
1538 | }
|
1539 | else {
|
1540 | return result;
|
1541 | }
|
1542 | }, []);
|
1543 | }
|
1544 | getMetaValue(name) {
|
1545 | const element = this.findMetaElementByName(name);
|
1546 | return element ? element.getAttribute("content") : null;
|
1547 | }
|
1548 | findMetaElementByName(name) {
|
1549 | return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
1550 | const { elements: [element], } = this.detailsByOuterHTML[outerHTML];
|
1551 | return elementIsMetaElementWithName(element, name) ? element : result;
|
1552 | }, undefined);
|
1553 | }
|
1554 | }
|
1555 | function elementType(element) {
|
1556 | if (elementIsScript(element)) {
|
1557 | return "script";
|
1558 | }
|
1559 | else if (elementIsStylesheet(element)) {
|
1560 | return "stylesheet";
|
1561 | }
|
1562 | }
|
1563 | function elementIsTracked(element) {
|
1564 | return element.getAttribute("data-turbo-track") == "reload";
|
1565 | }
|
1566 | function elementIsScript(element) {
|
1567 | const tagName = element.localName;
|
1568 | return tagName == "script";
|
1569 | }
|
1570 | function elementIsNoscript(element) {
|
1571 | const tagName = element.localName;
|
1572 | return tagName == "noscript";
|
1573 | }
|
1574 | function elementIsStylesheet(element) {
|
1575 | const tagName = element.localName;
|
1576 | return tagName == "style" || (tagName == "link" && element.getAttribute("rel") == "stylesheet");
|
1577 | }
|
1578 | function elementIsMetaElementWithName(element, name) {
|
1579 | const tagName = element.localName;
|
1580 | return tagName == "meta" && element.getAttribute("name") == name;
|
1581 | }
|
1582 | function elementWithoutNonce(element) {
|
1583 | if (element.hasAttribute("nonce")) {
|
1584 | element.setAttribute("nonce", "");
|
1585 | }
|
1586 | return element;
|
1587 | }
|
1588 |
|
1589 | class PageSnapshot extends Snapshot {
|
1590 | constructor(element, headSnapshot) {
|
1591 | super(element);
|
1592 | this.headSnapshot = headSnapshot;
|
1593 | }
|
1594 | static fromHTMLString(html = "") {
|
1595 | return this.fromDocument(parseHTMLDocument(html));
|
1596 | }
|
1597 | static fromElement(element) {
|
1598 | return this.fromDocument(element.ownerDocument);
|
1599 | }
|
1600 | static fromDocument({ head, body }) {
|
1601 | return new this(body, new HeadSnapshot(head));
|
1602 | }
|
1603 | clone() {
|
1604 | const clonedElement = this.element.cloneNode(true);
|
1605 | const selectElements = this.element.querySelectorAll("select");
|
1606 | const clonedSelectElements = clonedElement.querySelectorAll("select");
|
1607 | for (const [index, source] of selectElements.entries()) {
|
1608 | const clone = clonedSelectElements[index];
|
1609 | for (const option of clone.selectedOptions)
|
1610 | option.selected = false;
|
1611 | for (const option of source.selectedOptions)
|
1612 | clone.options[option.index].selected = true;
|
1613 | }
|
1614 | for (const clonedPasswordInput of clonedElement.querySelectorAll('input[type="password"]')) {
|
1615 | clonedPasswordInput.value = "";
|
1616 | }
|
1617 | return new PageSnapshot(clonedElement, this.headSnapshot);
|
1618 | }
|
1619 | get headElement() {
|
1620 | return this.headSnapshot.element;
|
1621 | }
|
1622 | get rootLocation() {
|
1623 | var _a;
|
1624 | const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
|
1625 | return expandURL(root);
|
1626 | }
|
1627 | get cacheControlValue() {
|
1628 | return this.getSetting("cache-control");
|
1629 | }
|
1630 | get isPreviewable() {
|
1631 | return this.cacheControlValue != "no-preview";
|
1632 | }
|
1633 | get isCacheable() {
|
1634 | return this.cacheControlValue != "no-cache";
|
1635 | }
|
1636 | get isVisitable() {
|
1637 | return this.getSetting("visit-control") != "reload";
|
1638 | }
|
1639 | getSetting(name) {
|
1640 | return this.headSnapshot.getMetaValue(`turbo-${name}`);
|
1641 | }
|
1642 | }
|
1643 |
|
1644 | var TimingMetric;
|
1645 | (function (TimingMetric) {
|
1646 | TimingMetric["visitStart"] = "visitStart";
|
1647 | TimingMetric["requestStart"] = "requestStart";
|
1648 | TimingMetric["requestEnd"] = "requestEnd";
|
1649 | TimingMetric["visitEnd"] = "visitEnd";
|
1650 | })(TimingMetric || (TimingMetric = {}));
|
1651 | var VisitState;
|
1652 | (function (VisitState) {
|
1653 | VisitState["initialized"] = "initialized";
|
1654 | VisitState["started"] = "started";
|
1655 | VisitState["canceled"] = "canceled";
|
1656 | VisitState["failed"] = "failed";
|
1657 | VisitState["completed"] = "completed";
|
1658 | })(VisitState || (VisitState = {}));
|
1659 | const defaultOptions = {
|
1660 | action: "advance",
|
1661 | historyChanged: false,
|
1662 | visitCachedSnapshot: () => { },
|
1663 | willRender: true,
|
1664 | updateHistory: true,
|
1665 | shouldCacheSnapshot: true,
|
1666 | acceptsStreamResponse: false,
|
1667 | };
|
1668 | var SystemStatusCode;
|
1669 | (function (SystemStatusCode) {
|
1670 | SystemStatusCode[SystemStatusCode["networkFailure"] = 0] = "networkFailure";
|
1671 | SystemStatusCode[SystemStatusCode["timeoutFailure"] = -1] = "timeoutFailure";
|
1672 | SystemStatusCode[SystemStatusCode["contentTypeMismatch"] = -2] = "contentTypeMismatch";
|
1673 | })(SystemStatusCode || (SystemStatusCode = {}));
|
1674 | class Visit {
|
1675 | constructor(delegate, location, restorationIdentifier, options = {}) {
|
1676 | this.identifier = uuid();
|
1677 | this.timingMetrics = {};
|
1678 | this.followedRedirect = false;
|
1679 | this.historyChanged = false;
|
1680 | this.scrolled = false;
|
1681 | this.shouldCacheSnapshot = true;
|
1682 | this.acceptsStreamResponse = false;
|
1683 | this.snapshotCached = false;
|
1684 | this.state = VisitState.initialized;
|
1685 | this.delegate = delegate;
|
1686 | this.location = location;
|
1687 | this.restorationIdentifier = restorationIdentifier || uuid();
|
1688 | const { action, historyChanged, referrer, snapshot, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse, } = Object.assign(Object.assign({}, defaultOptions), options);
|
1689 | this.action = action;
|
1690 | this.historyChanged = historyChanged;
|
1691 | this.referrer = referrer;
|
1692 | this.snapshot = snapshot;
|
1693 | this.snapshotHTML = snapshotHTML;
|
1694 | this.response = response;
|
1695 | this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
1696 | this.visitCachedSnapshot = visitCachedSnapshot;
|
1697 | this.willRender = willRender;
|
1698 | this.updateHistory = updateHistory;
|
1699 | this.scrolled = !willRender;
|
1700 | this.shouldCacheSnapshot = shouldCacheSnapshot;
|
1701 | this.acceptsStreamResponse = acceptsStreamResponse;
|
1702 | }
|
1703 | get adapter() {
|
1704 | return this.delegate.adapter;
|
1705 | }
|
1706 | get view() {
|
1707 | return this.delegate.view;
|
1708 | }
|
1709 | get history() {
|
1710 | return this.delegate.history;
|
1711 | }
|
1712 | get restorationData() {
|
1713 | return this.history.getRestorationDataForIdentifier(this.restorationIdentifier);
|
1714 | }
|
1715 | get silent() {
|
1716 | return this.isSamePage;
|
1717 | }
|
1718 | start() {
|
1719 | if (this.state == VisitState.initialized) {
|
1720 | this.recordTimingMetric(TimingMetric.visitStart);
|
1721 | this.state = VisitState.started;
|
1722 | this.adapter.visitStarted(this);
|
1723 | this.delegate.visitStarted(this);
|
1724 | }
|
1725 | }
|
1726 | cancel() {
|
1727 | if (this.state == VisitState.started) {
|
1728 | if (this.request) {
|
1729 | this.request.cancel();
|
1730 | }
|
1731 | this.cancelRender();
|
1732 | this.state = VisitState.canceled;
|
1733 | }
|
1734 | }
|
1735 | complete() {
|
1736 | if (this.state == VisitState.started) {
|
1737 | this.recordTimingMetric(TimingMetric.visitEnd);
|
1738 | this.state = VisitState.completed;
|
1739 | this.followRedirect();
|
1740 | if (!this.followedRedirect) {
|
1741 | this.adapter.visitCompleted(this);
|
1742 | this.delegate.visitCompleted(this);
|
1743 | }
|
1744 | }
|
1745 | }
|
1746 | fail() {
|
1747 | if (this.state == VisitState.started) {
|
1748 | this.state = VisitState.failed;
|
1749 | this.adapter.visitFailed(this);
|
1750 | }
|
1751 | }
|
1752 | changeHistory() {
|
1753 | var _a;
|
1754 | if (!this.historyChanged && this.updateHistory) {
|
1755 | const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
|
1756 | const method = getHistoryMethodForAction(actionForHistory);
|
1757 | this.history.update(method, this.location, this.restorationIdentifier);
|
1758 | this.historyChanged = true;
|
1759 | }
|
1760 | }
|
1761 | issueRequest() {
|
1762 | if (this.hasPreloadedResponse()) {
|
1763 | this.simulateRequest();
|
1764 | }
|
1765 | else if (this.shouldIssueRequest() && !this.request) {
|
1766 | this.request = new FetchRequest(this, FetchMethod.get, this.location);
|
1767 | this.request.perform();
|
1768 | }
|
1769 | }
|
1770 | simulateRequest() {
|
1771 | if (this.response) {
|
1772 | this.startRequest();
|
1773 | this.recordResponse();
|
1774 | this.finishRequest();
|
1775 | }
|
1776 | }
|
1777 | startRequest() {
|
1778 | this.recordTimingMetric(TimingMetric.requestStart);
|
1779 | this.adapter.visitRequestStarted(this);
|
1780 | }
|
1781 | recordResponse(response = this.response) {
|
1782 | this.response = response;
|
1783 | if (response) {
|
1784 | const { statusCode } = response;
|
1785 | if (isSuccessful(statusCode)) {
|
1786 | this.adapter.visitRequestCompleted(this);
|
1787 | }
|
1788 | else {
|
1789 | this.adapter.visitRequestFailedWithStatusCode(this, statusCode);
|
1790 | }
|
1791 | }
|
1792 | }
|
1793 | finishRequest() {
|
1794 | this.recordTimingMetric(TimingMetric.requestEnd);
|
1795 | this.adapter.visitRequestFinished(this);
|
1796 | }
|
1797 | loadResponse() {
|
1798 | if (this.response) {
|
1799 | const { statusCode, responseHTML } = this.response;
|
1800 | this.render(async () => {
|
1801 | if (this.shouldCacheSnapshot)
|
1802 | this.cacheSnapshot();
|
1803 | if (this.view.renderPromise)
|
1804 | await this.view.renderPromise;
|
1805 | if (isSuccessful(statusCode) && responseHTML != null) {
|
1806 | await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);
|
1807 | this.performScroll();
|
1808 | this.adapter.visitRendered(this);
|
1809 | this.complete();
|
1810 | }
|
1811 | else {
|
1812 | await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);
|
1813 | this.adapter.visitRendered(this);
|
1814 | this.fail();
|
1815 | }
|
1816 | });
|
1817 | }
|
1818 | }
|
1819 | getCachedSnapshot() {
|
1820 | const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot();
|
1821 | if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) {
|
1822 | if (this.action == "restore" || snapshot.isPreviewable) {
|
1823 | return snapshot;
|
1824 | }
|
1825 | }
|
1826 | }
|
1827 | getPreloadedSnapshot() {
|
1828 | if (this.snapshotHTML) {
|
1829 | return PageSnapshot.fromHTMLString(this.snapshotHTML);
|
1830 | }
|
1831 | }
|
1832 | hasCachedSnapshot() {
|
1833 | return this.getCachedSnapshot() != null;
|
1834 | }
|
1835 | loadCachedSnapshot() {
|
1836 | const snapshot = this.getCachedSnapshot();
|
1837 | if (snapshot) {
|
1838 | const isPreview = this.shouldIssueRequest();
|
1839 | this.render(async () => {
|
1840 | this.cacheSnapshot();
|
1841 | if (this.isSamePage) {
|
1842 | this.adapter.visitRendered(this);
|
1843 | }
|
1844 | else {
|
1845 | if (this.view.renderPromise)
|
1846 | await this.view.renderPromise;
|
1847 | await this.view.renderPage(snapshot, isPreview, this.willRender, this);
|
1848 | this.performScroll();
|
1849 | this.adapter.visitRendered(this);
|
1850 | if (!isPreview) {
|
1851 | this.complete();
|
1852 | }
|
1853 | }
|
1854 | });
|
1855 | }
|
1856 | }
|
1857 | followRedirect() {
|
1858 | var _a;
|
1859 | if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
1860 | this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
1861 | action: "replace",
|
1862 | response: this.response,
|
1863 | });
|
1864 | this.followedRedirect = true;
|
1865 | }
|
1866 | }
|
1867 | goToSamePageAnchor() {
|
1868 | if (this.isSamePage) {
|
1869 | this.render(async () => {
|
1870 | this.cacheSnapshot();
|
1871 | this.performScroll();
|
1872 | this.changeHistory();
|
1873 | this.adapter.visitRendered(this);
|
1874 | });
|
1875 | }
|
1876 | }
|
1877 | prepareHeadersForRequest(headers, request) {
|
1878 | if (this.acceptsStreamResponse) {
|
1879 | request.acceptResponseType(StreamMessage.contentType);
|
1880 | }
|
1881 | }
|
1882 | requestStarted() {
|
1883 | this.startRequest();
|
1884 | }
|
1885 | requestPreventedHandlingResponse(_request, _response) { }
|
1886 | async requestSucceededWithResponse(request, response) {
|
1887 | const responseHTML = await response.responseHTML;
|
1888 | const { redirected, statusCode } = response;
|
1889 | if (responseHTML == undefined) {
|
1890 | this.recordResponse({
|
1891 | statusCode: SystemStatusCode.contentTypeMismatch,
|
1892 | redirected,
|
1893 | });
|
1894 | }
|
1895 | else {
|
1896 | this.redirectedToLocation = response.redirected ? response.location : undefined;
|
1897 | this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
1898 | }
|
1899 | }
|
1900 | async requestFailedWithResponse(request, response) {
|
1901 | const responseHTML = await response.responseHTML;
|
1902 | const { redirected, statusCode } = response;
|
1903 | if (responseHTML == undefined) {
|
1904 | this.recordResponse({
|
1905 | statusCode: SystemStatusCode.contentTypeMismatch,
|
1906 | redirected,
|
1907 | });
|
1908 | }
|
1909 | else {
|
1910 | this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
1911 | }
|
1912 | }
|
1913 | requestErrored(_request, _error) {
|
1914 | this.recordResponse({
|
1915 | statusCode: SystemStatusCode.networkFailure,
|
1916 | redirected: false,
|
1917 | });
|
1918 | }
|
1919 | requestFinished() {
|
1920 | this.finishRequest();
|
1921 | }
|
1922 | performScroll() {
|
1923 | if (!this.scrolled && !this.view.forceReloaded) {
|
1924 | if (this.action == "restore") {
|
1925 | this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
|
1926 | }
|
1927 | else {
|
1928 | this.scrollToAnchor() || this.view.scrollToTop();
|
1929 | }
|
1930 | if (this.isSamePage) {
|
1931 | this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location);
|
1932 | }
|
1933 | this.scrolled = true;
|
1934 | }
|
1935 | }
|
1936 | scrollToRestoredPosition() {
|
1937 | const { scrollPosition } = this.restorationData;
|
1938 | if (scrollPosition) {
|
1939 | this.view.scrollToPosition(scrollPosition);
|
1940 | return true;
|
1941 | }
|
1942 | }
|
1943 | scrollToAnchor() {
|
1944 | const anchor = getAnchor(this.location);
|
1945 | if (anchor != null) {
|
1946 | this.view.scrollToAnchor(anchor);
|
1947 | return true;
|
1948 | }
|
1949 | }
|
1950 | recordTimingMetric(metric) {
|
1951 | this.timingMetrics[metric] = new Date().getTime();
|
1952 | }
|
1953 | getTimingMetrics() {
|
1954 | return Object.assign({}, this.timingMetrics);
|
1955 | }
|
1956 | getHistoryMethodForAction(action) {
|
1957 | switch (action) {
|
1958 | case "replace":
|
1959 | return history.replaceState;
|
1960 | case "advance":
|
1961 | case "restore":
|
1962 | return history.pushState;
|
1963 | }
|
1964 | }
|
1965 | hasPreloadedResponse() {
|
1966 | return typeof this.response == "object";
|
1967 | }
|
1968 | shouldIssueRequest() {
|
1969 | if (this.isSamePage) {
|
1970 | return false;
|
1971 | }
|
1972 | else if (this.action == "restore") {
|
1973 | return !this.hasCachedSnapshot();
|
1974 | }
|
1975 | else {
|
1976 | return this.willRender;
|
1977 | }
|
1978 | }
|
1979 | cacheSnapshot() {
|
1980 | if (!this.snapshotCached) {
|
1981 | this.view.cacheSnapshot(this.snapshot).then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));
|
1982 | this.snapshotCached = true;
|
1983 | }
|
1984 | }
|
1985 | async render(callback) {
|
1986 | this.cancelRender();
|
1987 | await new Promise((resolve) => {
|
1988 | this.frame = requestAnimationFrame(() => resolve());
|
1989 | });
|
1990 | await callback();
|
1991 | delete this.frame;
|
1992 | }
|
1993 | cancelRender() {
|
1994 | if (this.frame) {
|
1995 | cancelAnimationFrame(this.frame);
|
1996 | delete this.frame;
|
1997 | }
|
1998 | }
|
1999 | }
|
2000 | function isSuccessful(statusCode) {
|
2001 | return statusCode >= 200 && statusCode < 300;
|
2002 | }
|
2003 |
|
2004 | class BrowserAdapter {
|
2005 | constructor(session) {
|
2006 | this.progressBar = new ProgressBar();
|
2007 | this.showProgressBar = () => {
|
2008 | this.progressBar.show();
|
2009 | };
|
2010 | this.session = session;
|
2011 | }
|
2012 | visitProposedToLocation(location, options) {
|
2013 | this.navigator.startVisit(location, (options === null || options === void 0 ? void 0 : options.restorationIdentifier) || uuid(), options);
|
2014 | }
|
2015 | visitStarted(visit) {
|
2016 | this.location = visit.location;
|
2017 | visit.loadCachedSnapshot();
|
2018 | visit.issueRequest();
|
2019 | visit.goToSamePageAnchor();
|
2020 | }
|
2021 | visitRequestStarted(visit) {
|
2022 | this.progressBar.setValue(0);
|
2023 | if (visit.hasCachedSnapshot() || visit.action != "restore") {
|
2024 | this.showVisitProgressBarAfterDelay();
|
2025 | }
|
2026 | else {
|
2027 | this.showProgressBar();
|
2028 | }
|
2029 | }
|
2030 | visitRequestCompleted(visit) {
|
2031 | visit.loadResponse();
|
2032 | }
|
2033 | visitRequestFailedWithStatusCode(visit, statusCode) {
|
2034 | switch (statusCode) {
|
2035 | case SystemStatusCode.networkFailure:
|
2036 | case SystemStatusCode.timeoutFailure:
|
2037 | case SystemStatusCode.contentTypeMismatch:
|
2038 | return this.reload({
|
2039 | reason: "request_failed",
|
2040 | context: {
|
2041 | statusCode,
|
2042 | },
|
2043 | });
|
2044 | default:
|
2045 | return visit.loadResponse();
|
2046 | }
|
2047 | }
|
2048 | visitRequestFinished(_visit) {
|
2049 | this.progressBar.setValue(1);
|
2050 | this.hideVisitProgressBar();
|
2051 | }
|
2052 | visitCompleted(_visit) { }
|
2053 | pageInvalidated(reason) {
|
2054 | this.reload(reason);
|
2055 | }
|
2056 | visitFailed(_visit) { }
|
2057 | visitRendered(_visit) { }
|
2058 | formSubmissionStarted(_formSubmission) {
|
2059 | this.progressBar.setValue(0);
|
2060 | this.showFormProgressBarAfterDelay();
|
2061 | }
|
2062 | formSubmissionFinished(_formSubmission) {
|
2063 | this.progressBar.setValue(1);
|
2064 | this.hideFormProgressBar();
|
2065 | }
|
2066 | showVisitProgressBarAfterDelay() {
|
2067 | this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
|
2068 | }
|
2069 | hideVisitProgressBar() {
|
2070 | this.progressBar.hide();
|
2071 | if (this.visitProgressBarTimeout != null) {
|
2072 | window.clearTimeout(this.visitProgressBarTimeout);
|
2073 | delete this.visitProgressBarTimeout;
|
2074 | }
|
2075 | }
|
2076 | showFormProgressBarAfterDelay() {
|
2077 | if (this.formProgressBarTimeout == null) {
|
2078 | this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay);
|
2079 | }
|
2080 | }
|
2081 | hideFormProgressBar() {
|
2082 | this.progressBar.hide();
|
2083 | if (this.formProgressBarTimeout != null) {
|
2084 | window.clearTimeout(this.formProgressBarTimeout);
|
2085 | delete this.formProgressBarTimeout;
|
2086 | }
|
2087 | }
|
2088 | reload(reason) {
|
2089 | var _a;
|
2090 | dispatch("turbo:reload", { detail: reason });
|
2091 | window.location.href = ((_a = this.location) === null || _a === void 0 ? void 0 : _a.toString()) || window.location.href;
|
2092 | }
|
2093 | get navigator() {
|
2094 | return this.session.navigator;
|
2095 | }
|
2096 | }
|
2097 |
|
2098 | class CacheObserver {
|
2099 | constructor() {
|
2100 | this.started = false;
|
2101 | this.removeStaleElements = ((_event) => {
|
2102 | const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
|
2103 | for (const element of staleElements) {
|
2104 | element.remove();
|
2105 | }
|
2106 | });
|
2107 | }
|
2108 | start() {
|
2109 | if (!this.started) {
|
2110 | this.started = true;
|
2111 | addEventListener("turbo:before-cache", this.removeStaleElements, false);
|
2112 | }
|
2113 | }
|
2114 | stop() {
|
2115 | if (this.started) {
|
2116 | this.started = false;
|
2117 | removeEventListener("turbo:before-cache", this.removeStaleElements, false);
|
2118 | }
|
2119 | }
|
2120 | }
|
2121 |
|
2122 | class FrameRedirector {
|
2123 | constructor(session, element) {
|
2124 | this.session = session;
|
2125 | this.element = element;
|
2126 | this.linkInterceptor = new LinkInterceptor(this, element);
|
2127 | this.formSubmitObserver = new FormSubmitObserver(this, element);
|
2128 | }
|
2129 | start() {
|
2130 | this.linkInterceptor.start();
|
2131 | this.formSubmitObserver.start();
|
2132 | }
|
2133 | stop() {
|
2134 | this.linkInterceptor.stop();
|
2135 | this.formSubmitObserver.stop();
|
2136 | }
|
2137 | shouldInterceptLinkClick(element, _location, _event) {
|
2138 | return this.shouldRedirect(element);
|
2139 | }
|
2140 | linkClickIntercepted(element, url, event) {
|
2141 | const frame = this.findFrameElement(element);
|
2142 | if (frame) {
|
2143 | frame.delegate.linkClickIntercepted(element, url, event);
|
2144 | }
|
2145 | }
|
2146 | willSubmitForm(element, submitter) {
|
2147 | return (element.closest("turbo-frame") == null &&
|
2148 | this.shouldSubmit(element, submitter) &&
|
2149 | this.shouldRedirect(element, submitter));
|
2150 | }
|
2151 | formSubmitted(element, submitter) {
|
2152 | const frame = this.findFrameElement(element, submitter);
|
2153 | if (frame) {
|
2154 | frame.delegate.formSubmitted(element, submitter);
|
2155 | }
|
2156 | }
|
2157 | shouldSubmit(form, submitter) {
|
2158 | var _a;
|
2159 | const action = getAction(form, submitter);
|
2160 | const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
2161 | const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/");
|
2162 | return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
|
2163 | }
|
2164 | shouldRedirect(element, submitter) {
|
2165 | const isNavigatable = element instanceof HTMLFormElement
|
2166 | ? this.session.submissionIsNavigatable(element, submitter)
|
2167 | : this.session.elementIsNavigatable(element);
|
2168 | if (isNavigatable) {
|
2169 | const frame = this.findFrameElement(element, submitter);
|
2170 | return frame ? frame != element.closest("turbo-frame") : false;
|
2171 | }
|
2172 | else {
|
2173 | return false;
|
2174 | }
|
2175 | }
|
2176 | findFrameElement(element, submitter) {
|
2177 | const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame");
|
2178 | if (id && id != "_top") {
|
2179 | const frame = this.element.querySelector(`#${id}:not([disabled])`);
|
2180 | if (frame instanceof FrameElement) {
|
2181 | return frame;
|
2182 | }
|
2183 | }
|
2184 | }
|
2185 | }
|
2186 |
|
2187 | class History {
|
2188 | constructor(delegate) {
|
2189 | this.restorationIdentifier = uuid();
|
2190 | this.restorationData = {};
|
2191 | this.started = false;
|
2192 | this.pageLoaded = false;
|
2193 | this.onPopState = (event) => {
|
2194 | if (this.shouldHandlePopState()) {
|
2195 | const { turbo } = event.state || {};
|
2196 | if (turbo) {
|
2197 | this.location = new URL(window.location.href);
|
2198 | const { restorationIdentifier } = turbo;
|
2199 | this.restorationIdentifier = restorationIdentifier;
|
2200 | this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
|
2201 | }
|
2202 | }
|
2203 | };
|
2204 | this.onPageLoad = async (_event) => {
|
2205 | await nextMicrotask();
|
2206 | this.pageLoaded = true;
|
2207 | };
|
2208 | this.delegate = delegate;
|
2209 | }
|
2210 | start() {
|
2211 | if (!this.started) {
|
2212 | addEventListener("popstate", this.onPopState, false);
|
2213 | addEventListener("load", this.onPageLoad, false);
|
2214 | this.started = true;
|
2215 | this.replace(new URL(window.location.href));
|
2216 | }
|
2217 | }
|
2218 | stop() {
|
2219 | if (this.started) {
|
2220 | removeEventListener("popstate", this.onPopState, false);
|
2221 | removeEventListener("load", this.onPageLoad, false);
|
2222 | this.started = false;
|
2223 | }
|
2224 | }
|
2225 | push(location, restorationIdentifier) {
|
2226 | this.update(history.pushState, location, restorationIdentifier);
|
2227 | }
|
2228 | replace(location, restorationIdentifier) {
|
2229 | this.update(history.replaceState, location, restorationIdentifier);
|
2230 | }
|
2231 | update(method, location, restorationIdentifier = uuid()) {
|
2232 | const state = { turbo: { restorationIdentifier } };
|
2233 | method.call(history, state, "", location.href);
|
2234 | this.location = location;
|
2235 | this.restorationIdentifier = restorationIdentifier;
|
2236 | }
|
2237 | getRestorationDataForIdentifier(restorationIdentifier) {
|
2238 | return this.restorationData[restorationIdentifier] || {};
|
2239 | }
|
2240 | updateRestorationData(additionalData) {
|
2241 | const { restorationIdentifier } = this;
|
2242 | const restorationData = this.restorationData[restorationIdentifier];
|
2243 | this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);
|
2244 | }
|
2245 | assumeControlOfScrollRestoration() {
|
2246 | var _a;
|
2247 | if (!this.previousScrollRestoration) {
|
2248 | this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto";
|
2249 | history.scrollRestoration = "manual";
|
2250 | }
|
2251 | }
|
2252 | relinquishControlOfScrollRestoration() {
|
2253 | if (this.previousScrollRestoration) {
|
2254 | history.scrollRestoration = this.previousScrollRestoration;
|
2255 | delete this.previousScrollRestoration;
|
2256 | }
|
2257 | }
|
2258 | shouldHandlePopState() {
|
2259 | return this.pageIsLoaded();
|
2260 | }
|
2261 | pageIsLoaded() {
|
2262 | return this.pageLoaded || document.readyState == "complete";
|
2263 | }
|
2264 | }
|
2265 |
|
2266 | class Navigator {
|
2267 | constructor(delegate) {
|
2268 | this.delegate = delegate;
|
2269 | }
|
2270 | proposeVisit(location, options = {}) {
|
2271 | if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {
|
2272 | if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {
|
2273 | this.delegate.visitProposedToLocation(location, options);
|
2274 | }
|
2275 | else {
|
2276 | window.location.href = location.toString();
|
2277 | }
|
2278 | }
|
2279 | }
|
2280 | startVisit(locatable, restorationIdentifier, options = {}) {
|
2281 | this.stop();
|
2282 | this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));
|
2283 | this.currentVisit.start();
|
2284 | }
|
2285 | submitForm(form, submitter) {
|
2286 | this.stop();
|
2287 | this.formSubmission = new FormSubmission(this, form, submitter, true);
|
2288 | this.formSubmission.start();
|
2289 | }
|
2290 | stop() {
|
2291 | if (this.formSubmission) {
|
2292 | this.formSubmission.stop();
|
2293 | delete this.formSubmission;
|
2294 | }
|
2295 | if (this.currentVisit) {
|
2296 | this.currentVisit.cancel();
|
2297 | delete this.currentVisit;
|
2298 | }
|
2299 | }
|
2300 | get adapter() {
|
2301 | return this.delegate.adapter;
|
2302 | }
|
2303 | get view() {
|
2304 | return this.delegate.view;
|
2305 | }
|
2306 | get history() {
|
2307 | return this.delegate.history;
|
2308 | }
|
2309 | formSubmissionStarted(formSubmission) {
|
2310 | if (typeof this.adapter.formSubmissionStarted === "function") {
|
2311 | this.adapter.formSubmissionStarted(formSubmission);
|
2312 | }
|
2313 | }
|
2314 | async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) {
|
2315 | if (formSubmission == this.formSubmission) {
|
2316 | const responseHTML = await fetchResponse.responseHTML;
|
2317 | if (responseHTML) {
|
2318 | const shouldCacheSnapshot = formSubmission.method == FetchMethod.get;
|
2319 | if (!shouldCacheSnapshot) {
|
2320 | this.view.clearSnapshotCache();
|
2321 | }
|
2322 | const { statusCode, redirected } = fetchResponse;
|
2323 | const action = this.getActionForFormSubmission(formSubmission);
|
2324 | const visitOptions = {
|
2325 | action,
|
2326 | shouldCacheSnapshot,
|
2327 | response: { statusCode, responseHTML, redirected },
|
2328 | };
|
2329 | this.proposeVisit(fetchResponse.location, visitOptions);
|
2330 | }
|
2331 | }
|
2332 | }
|
2333 | async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
2334 | const responseHTML = await fetchResponse.responseHTML;
|
2335 | if (responseHTML) {
|
2336 | const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
2337 | if (fetchResponse.serverError) {
|
2338 | await this.view.renderError(snapshot, this.currentVisit);
|
2339 | }
|
2340 | else {
|
2341 | await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
2342 | }
|
2343 | this.view.scrollToTop();
|
2344 | this.view.clearSnapshotCache();
|
2345 | }
|
2346 | }
|
2347 | formSubmissionErrored(formSubmission, error) {
|
2348 | console.error(error);
|
2349 | }
|
2350 | formSubmissionFinished(formSubmission) {
|
2351 | if (typeof this.adapter.formSubmissionFinished === "function") {
|
2352 | this.adapter.formSubmissionFinished(formSubmission);
|
2353 | }
|
2354 | }
|
2355 | visitStarted(visit) {
|
2356 | this.delegate.visitStarted(visit);
|
2357 | }
|
2358 | visitCompleted(visit) {
|
2359 | this.delegate.visitCompleted(visit);
|
2360 | }
|
2361 | locationWithActionIsSamePage(location, action) {
|
2362 | const anchor = getAnchor(location);
|
2363 | const currentAnchor = getAnchor(this.view.lastRenderedLocation);
|
2364 | const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
2365 | return (action !== "replace" &&
|
2366 | getRequestURL(location) === getRequestURL(this.view.lastRenderedLocation) &&
|
2367 | (isRestorationToTop || (anchor != null && anchor !== currentAnchor)));
|
2368 | }
|
2369 | visitScrolledToSamePageLocation(oldURL, newURL) {
|
2370 | this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
2371 | }
|
2372 | get location() {
|
2373 | return this.history.location;
|
2374 | }
|
2375 | get restorationIdentifier() {
|
2376 | return this.history.restorationIdentifier;
|
2377 | }
|
2378 | getActionForFormSubmission(formSubmission) {
|
2379 | const { formElement, submitter } = formSubmission;
|
2380 | const action = getAttribute("data-turbo-action", submitter, formElement);
|
2381 | return isAction(action) ? action : "advance";
|
2382 | }
|
2383 | }
|
2384 |
|
2385 | var PageStage;
|
2386 | (function (PageStage) {
|
2387 | PageStage[PageStage["initial"] = 0] = "initial";
|
2388 | PageStage[PageStage["loading"] = 1] = "loading";
|
2389 | PageStage[PageStage["interactive"] = 2] = "interactive";
|
2390 | PageStage[PageStage["complete"] = 3] = "complete";
|
2391 | })(PageStage || (PageStage = {}));
|
2392 | class PageObserver {
|
2393 | constructor(delegate) {
|
2394 | this.stage = PageStage.initial;
|
2395 | this.started = false;
|
2396 | this.interpretReadyState = () => {
|
2397 | const { readyState } = this;
|
2398 | if (readyState == "interactive") {
|
2399 | this.pageIsInteractive();
|
2400 | }
|
2401 | else if (readyState == "complete") {
|
2402 | this.pageIsComplete();
|
2403 | }
|
2404 | };
|
2405 | this.pageWillUnload = () => {
|
2406 | this.delegate.pageWillUnload();
|
2407 | };
|
2408 | this.delegate = delegate;
|
2409 | }
|
2410 | start() {
|
2411 | if (!this.started) {
|
2412 | if (this.stage == PageStage.initial) {
|
2413 | this.stage = PageStage.loading;
|
2414 | }
|
2415 | document.addEventListener("readystatechange", this.interpretReadyState, false);
|
2416 | addEventListener("pagehide", this.pageWillUnload, false);
|
2417 | this.started = true;
|
2418 | }
|
2419 | }
|
2420 | stop() {
|
2421 | if (this.started) {
|
2422 | document.removeEventListener("readystatechange", this.interpretReadyState, false);
|
2423 | removeEventListener("pagehide", this.pageWillUnload, false);
|
2424 | this.started = false;
|
2425 | }
|
2426 | }
|
2427 | pageIsInteractive() {
|
2428 | if (this.stage == PageStage.loading) {
|
2429 | this.stage = PageStage.interactive;
|
2430 | this.delegate.pageBecameInteractive();
|
2431 | }
|
2432 | }
|
2433 | pageIsComplete() {
|
2434 | this.pageIsInteractive();
|
2435 | if (this.stage == PageStage.interactive) {
|
2436 | this.stage = PageStage.complete;
|
2437 | this.delegate.pageLoaded();
|
2438 | }
|
2439 | }
|
2440 | get readyState() {
|
2441 | return document.readyState;
|
2442 | }
|
2443 | }
|
2444 |
|
2445 | class ScrollObserver {
|
2446 | constructor(delegate) {
|
2447 | this.started = false;
|
2448 | this.onScroll = () => {
|
2449 | this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset });
|
2450 | };
|
2451 | this.delegate = delegate;
|
2452 | }
|
2453 | start() {
|
2454 | if (!this.started) {
|
2455 | addEventListener("scroll", this.onScroll, false);
|
2456 | this.onScroll();
|
2457 | this.started = true;
|
2458 | }
|
2459 | }
|
2460 | stop() {
|
2461 | if (this.started) {
|
2462 | removeEventListener("scroll", this.onScroll, false);
|
2463 | this.started = false;
|
2464 | }
|
2465 | }
|
2466 | updatePosition(position) {
|
2467 | this.delegate.scrollPositionChanged(position);
|
2468 | }
|
2469 | }
|
2470 |
|
2471 | class StreamMessageRenderer {
|
2472 | render({ fragment }) {
|
2473 | Bardo.preservingPermanentElements(this, getPermanentElementMapForFragment(fragment), () => document.documentElement.appendChild(fragment));
|
2474 | }
|
2475 | enteringBardo(currentPermanentElement, newPermanentElement) {
|
2476 | newPermanentElement.replaceWith(currentPermanentElement.cloneNode(true));
|
2477 | }
|
2478 | leavingBardo() { }
|
2479 | }
|
2480 | function getPermanentElementMapForFragment(fragment) {
|
2481 | const permanentElementsInDocument = queryPermanentElementsAll(document.documentElement);
|
2482 | const permanentElementMap = {};
|
2483 | for (const permanentElementInDocument of permanentElementsInDocument) {
|
2484 | const { id } = permanentElementInDocument;
|
2485 | for (const streamElement of fragment.querySelectorAll("turbo-stream")) {
|
2486 | const elementInStream = getPermanentElementById(streamElement.templateElement.content, id);
|
2487 | if (elementInStream) {
|
2488 | permanentElementMap[id] = [permanentElementInDocument, elementInStream];
|
2489 | }
|
2490 | }
|
2491 | }
|
2492 | return permanentElementMap;
|
2493 | }
|
2494 |
|
2495 | class StreamObserver {
|
2496 | constructor(delegate) {
|
2497 | this.sources = new Set();
|
2498 | this.started = false;
|
2499 | this.inspectFetchResponse = ((event) => {
|
2500 | const response = fetchResponseFromEvent(event);
|
2501 | if (response && fetchResponseIsStream(response)) {
|
2502 | event.preventDefault();
|
2503 | this.receiveMessageResponse(response);
|
2504 | }
|
2505 | });
|
2506 | this.receiveMessageEvent = (event) => {
|
2507 | if (this.started && typeof event.data == "string") {
|
2508 | this.receiveMessageHTML(event.data);
|
2509 | }
|
2510 | };
|
2511 | this.delegate = delegate;
|
2512 | }
|
2513 | start() {
|
2514 | if (!this.started) {
|
2515 | this.started = true;
|
2516 | addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
2517 | }
|
2518 | }
|
2519 | stop() {
|
2520 | if (this.started) {
|
2521 | this.started = false;
|
2522 | removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
|
2523 | }
|
2524 | }
|
2525 | connectStreamSource(source) {
|
2526 | if (!this.streamSourceIsConnected(source)) {
|
2527 | this.sources.add(source);
|
2528 | source.addEventListener("message", this.receiveMessageEvent, false);
|
2529 | }
|
2530 | }
|
2531 | disconnectStreamSource(source) {
|
2532 | if (this.streamSourceIsConnected(source)) {
|
2533 | this.sources.delete(source);
|
2534 | source.removeEventListener("message", this.receiveMessageEvent, false);
|
2535 | }
|
2536 | }
|
2537 | streamSourceIsConnected(source) {
|
2538 | return this.sources.has(source);
|
2539 | }
|
2540 | async receiveMessageResponse(response) {
|
2541 | const html = await response.responseHTML;
|
2542 | if (html) {
|
2543 | this.receiveMessageHTML(html);
|
2544 | }
|
2545 | }
|
2546 | receiveMessageHTML(html) {
|
2547 | this.delegate.receivedMessageFromStream(StreamMessage.wrap(html));
|
2548 | }
|
2549 | }
|
2550 | function fetchResponseFromEvent(event) {
|
2551 | var _a;
|
2552 | const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse;
|
2553 | if (fetchResponse instanceof FetchResponse) {
|
2554 | return fetchResponse;
|
2555 | }
|
2556 | }
|
2557 | function fetchResponseIsStream(response) {
|
2558 | var _a;
|
2559 | const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
|
2560 | return contentType.startsWith(StreamMessage.contentType);
|
2561 | }
|
2562 |
|
2563 | class ErrorRenderer extends Renderer {
|
2564 | static renderElement(currentElement, newElement) {
|
2565 | const { documentElement, body } = document;
|
2566 | documentElement.replaceChild(newElement, body);
|
2567 | }
|
2568 | async render() {
|
2569 | this.replaceHeadAndBody();
|
2570 | this.activateScriptElements();
|
2571 | }
|
2572 | replaceHeadAndBody() {
|
2573 | const { documentElement, head } = document;
|
2574 | documentElement.replaceChild(this.newHead, head);
|
2575 | this.renderElement(this.currentElement, this.newElement);
|
2576 | }
|
2577 | activateScriptElements() {
|
2578 | for (const replaceableElement of this.scriptElements) {
|
2579 | const parentNode = replaceableElement.parentNode;
|
2580 | if (parentNode) {
|
2581 | const element = activateScriptElement(replaceableElement);
|
2582 | parentNode.replaceChild(element, replaceableElement);
|
2583 | }
|
2584 | }
|
2585 | }
|
2586 | get newHead() {
|
2587 | return this.newSnapshot.headSnapshot.element;
|
2588 | }
|
2589 | get scriptElements() {
|
2590 | return document.documentElement.querySelectorAll("script");
|
2591 | }
|
2592 | }
|
2593 |
|
2594 | class PageRenderer extends Renderer {
|
2595 | static renderElement(currentElement, newElement) {
|
2596 | if (document.body && newElement instanceof HTMLBodyElement) {
|
2597 | document.body.replaceWith(newElement);
|
2598 | }
|
2599 | else {
|
2600 | document.documentElement.appendChild(newElement);
|
2601 | }
|
2602 | }
|
2603 | get shouldRender() {
|
2604 | return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
|
2605 | }
|
2606 | get reloadReason() {
|
2607 | if (!this.newSnapshot.isVisitable) {
|
2608 | return {
|
2609 | reason: "turbo_visit_control_is_reload",
|
2610 | };
|
2611 | }
|
2612 | if (!this.trackedElementsAreIdentical) {
|
2613 | return {
|
2614 | reason: "tracked_element_mismatch",
|
2615 | };
|
2616 | }
|
2617 | }
|
2618 | async prepareToRender() {
|
2619 | await this.mergeHead();
|
2620 | }
|
2621 | async render() {
|
2622 | if (this.willRender) {
|
2623 | this.replaceBody();
|
2624 | }
|
2625 | }
|
2626 | finishRendering() {
|
2627 | super.finishRendering();
|
2628 | if (!this.isPreview) {
|
2629 | this.focusFirstAutofocusableElement();
|
2630 | }
|
2631 | }
|
2632 | get currentHeadSnapshot() {
|
2633 | return this.currentSnapshot.headSnapshot;
|
2634 | }
|
2635 | get newHeadSnapshot() {
|
2636 | return this.newSnapshot.headSnapshot;
|
2637 | }
|
2638 | get newElement() {
|
2639 | return this.newSnapshot.element;
|
2640 | }
|
2641 | async mergeHead() {
|
2642 | const newStylesheetElements = this.copyNewHeadStylesheetElements();
|
2643 | this.copyNewHeadScriptElements();
|
2644 | this.removeCurrentHeadProvisionalElements();
|
2645 | this.copyNewHeadProvisionalElements();
|
2646 | await newStylesheetElements;
|
2647 | }
|
2648 | replaceBody() {
|
2649 | this.preservingPermanentElements(() => {
|
2650 | this.activateNewBody();
|
2651 | this.assignNewBody();
|
2652 | });
|
2653 | }
|
2654 | get trackedElementsAreIdentical() {
|
2655 | return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;
|
2656 | }
|
2657 | async copyNewHeadStylesheetElements() {
|
2658 | const loadingElements = [];
|
2659 | for (const element of this.newHeadStylesheetElements) {
|
2660 | loadingElements.push(waitForLoad(element));
|
2661 | document.head.appendChild(element);
|
2662 | }
|
2663 | await Promise.all(loadingElements);
|
2664 | }
|
2665 | copyNewHeadScriptElements() {
|
2666 | for (const element of this.newHeadScriptElements) {
|
2667 | document.head.appendChild(activateScriptElement(element));
|
2668 | }
|
2669 | }
|
2670 | removeCurrentHeadProvisionalElements() {
|
2671 | for (const element of this.currentHeadProvisionalElements) {
|
2672 | document.head.removeChild(element);
|
2673 | }
|
2674 | }
|
2675 | copyNewHeadProvisionalElements() {
|
2676 | for (const element of this.newHeadProvisionalElements) {
|
2677 | document.head.appendChild(element);
|
2678 | }
|
2679 | }
|
2680 | activateNewBody() {
|
2681 | document.adoptNode(this.newElement);
|
2682 | this.activateNewBodyScriptElements();
|
2683 | }
|
2684 | activateNewBodyScriptElements() {
|
2685 | for (const inertScriptElement of this.newBodyScriptElements) {
|
2686 | const activatedScriptElement = activateScriptElement(inertScriptElement);
|
2687 | inertScriptElement.replaceWith(activatedScriptElement);
|
2688 | }
|
2689 | }
|
2690 | assignNewBody() {
|
2691 | this.renderElement(this.currentElement, this.newElement);
|
2692 | }
|
2693 | get newHeadStylesheetElements() {
|
2694 | return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
2695 | }
|
2696 | get newHeadScriptElements() {
|
2697 | return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot);
|
2698 | }
|
2699 | get currentHeadProvisionalElements() {
|
2700 | return this.currentHeadSnapshot.provisionalElements;
|
2701 | }
|
2702 | get newHeadProvisionalElements() {
|
2703 | return this.newHeadSnapshot.provisionalElements;
|
2704 | }
|
2705 | get newBodyScriptElements() {
|
2706 | return this.newElement.querySelectorAll("script");
|
2707 | }
|
2708 | }
|
2709 |
|
2710 | class SnapshotCache {
|
2711 | constructor(size) {
|
2712 | this.keys = [];
|
2713 | this.snapshots = {};
|
2714 | this.size = size;
|
2715 | }
|
2716 | has(location) {
|
2717 | return toCacheKey(location) in this.snapshots;
|
2718 | }
|
2719 | get(location) {
|
2720 | if (this.has(location)) {
|
2721 | const snapshot = this.read(location);
|
2722 | this.touch(location);
|
2723 | return snapshot;
|
2724 | }
|
2725 | }
|
2726 | put(location, snapshot) {
|
2727 | this.write(location, snapshot);
|
2728 | this.touch(location);
|
2729 | return snapshot;
|
2730 | }
|
2731 | clear() {
|
2732 | this.snapshots = {};
|
2733 | }
|
2734 | read(location) {
|
2735 | return this.snapshots[toCacheKey(location)];
|
2736 | }
|
2737 | write(location, snapshot) {
|
2738 | this.snapshots[toCacheKey(location)] = snapshot;
|
2739 | }
|
2740 | touch(location) {
|
2741 | const key = toCacheKey(location);
|
2742 | const index = this.keys.indexOf(key);
|
2743 | if (index > -1)
|
2744 | this.keys.splice(index, 1);
|
2745 | this.keys.unshift(key);
|
2746 | this.trim();
|
2747 | }
|
2748 | trim() {
|
2749 | for (const key of this.keys.splice(this.size)) {
|
2750 | delete this.snapshots[key];
|
2751 | }
|
2752 | }
|
2753 | }
|
2754 |
|
2755 | class PageView extends View {
|
2756 | constructor() {
|
2757 | super(...arguments);
|
2758 | this.snapshotCache = new SnapshotCache(10);
|
2759 | this.lastRenderedLocation = new URL(location.href);
|
2760 | this.forceReloaded = false;
|
2761 | }
|
2762 | renderPage(snapshot, isPreview = false, willRender = true, visit) {
|
2763 | const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
|
2764 | if (!renderer.shouldRender) {
|
2765 | this.forceReloaded = true;
|
2766 | }
|
2767 | else {
|
2768 | visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
2769 | }
|
2770 | return this.render(renderer);
|
2771 | }
|
2772 | renderError(snapshot, visit) {
|
2773 | visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
2774 | const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
|
2775 | return this.render(renderer);
|
2776 | }
|
2777 | clearSnapshotCache() {
|
2778 | this.snapshotCache.clear();
|
2779 | }
|
2780 | async cacheSnapshot(snapshot = this.snapshot) {
|
2781 | if (snapshot.isCacheable) {
|
2782 | this.delegate.viewWillCacheSnapshot();
|
2783 | const { lastRenderedLocation: location } = this;
|
2784 | await nextEventLoopTick();
|
2785 | const cachedSnapshot = snapshot.clone();
|
2786 | this.snapshotCache.put(location, cachedSnapshot);
|
2787 | return cachedSnapshot;
|
2788 | }
|
2789 | }
|
2790 | getCachedSnapshotForLocation(location) {
|
2791 | return this.snapshotCache.get(location);
|
2792 | }
|
2793 | get snapshot() {
|
2794 | return PageSnapshot.fromElement(this.element);
|
2795 | }
|
2796 | }
|
2797 |
|
2798 | class Preloader {
|
2799 | constructor(delegate) {
|
2800 | this.selector = "a[data-turbo-preload]";
|
2801 | this.delegate = delegate;
|
2802 | }
|
2803 | get snapshotCache() {
|
2804 | return this.delegate.navigator.view.snapshotCache;
|
2805 | }
|
2806 | start() {
|
2807 | if (document.readyState === "loading") {
|
2808 | return document.addEventListener("DOMContentLoaded", () => {
|
2809 | this.preloadOnLoadLinksForView(document.body);
|
2810 | });
|
2811 | }
|
2812 | else {
|
2813 | this.preloadOnLoadLinksForView(document.body);
|
2814 | }
|
2815 | }
|
2816 | preloadOnLoadLinksForView(element) {
|
2817 | for (const link of element.querySelectorAll(this.selector)) {
|
2818 | this.preloadURL(link);
|
2819 | }
|
2820 | }
|
2821 | async preloadURL(link) {
|
2822 | const location = new URL(link.href);
|
2823 | if (this.snapshotCache.has(location)) {
|
2824 | return;
|
2825 | }
|
2826 | try {
|
2827 | const response = await fetch(location.toString(), { headers: { "VND.PREFETCH": "true", Accept: "text/html" } });
|
2828 | const responseText = await response.text();
|
2829 | const snapshot = PageSnapshot.fromHTMLString(responseText);
|
2830 | this.snapshotCache.put(location, snapshot);
|
2831 | }
|
2832 | catch (_) {
|
2833 | }
|
2834 | }
|
2835 | }
|
2836 |
|
2837 | class Session {
|
2838 | constructor() {
|
2839 | this.navigator = new Navigator(this);
|
2840 | this.history = new History(this);
|
2841 | this.preloader = new Preloader(this);
|
2842 | this.view = new PageView(this, document.documentElement);
|
2843 | this.adapter = new BrowserAdapter(this);
|
2844 | this.pageObserver = new PageObserver(this);
|
2845 | this.cacheObserver = new CacheObserver();
|
2846 | this.linkClickObserver = new LinkClickObserver(this, window);
|
2847 | this.formSubmitObserver = new FormSubmitObserver(this, document);
|
2848 | this.scrollObserver = new ScrollObserver(this);
|
2849 | this.streamObserver = new StreamObserver(this);
|
2850 | this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
|
2851 | this.frameRedirector = new FrameRedirector(this, document.documentElement);
|
2852 | this.streamMessageRenderer = new StreamMessageRenderer();
|
2853 | this.drive = true;
|
2854 | this.enabled = true;
|
2855 | this.progressBarDelay = 500;
|
2856 | this.started = false;
|
2857 | this.formMode = "on";
|
2858 | }
|
2859 | start() {
|
2860 | if (!this.started) {
|
2861 | this.pageObserver.start();
|
2862 | this.cacheObserver.start();
|
2863 | this.formLinkClickObserver.start();
|
2864 | this.linkClickObserver.start();
|
2865 | this.formSubmitObserver.start();
|
2866 | this.scrollObserver.start();
|
2867 | this.streamObserver.start();
|
2868 | this.frameRedirector.start();
|
2869 | this.history.start();
|
2870 | this.preloader.start();
|
2871 | this.started = true;
|
2872 | this.enabled = true;
|
2873 | }
|
2874 | }
|
2875 | disable() {
|
2876 | this.enabled = false;
|
2877 | }
|
2878 | stop() {
|
2879 | if (this.started) {
|
2880 | this.pageObserver.stop();
|
2881 | this.cacheObserver.stop();
|
2882 | this.formLinkClickObserver.stop();
|
2883 | this.linkClickObserver.stop();
|
2884 | this.formSubmitObserver.stop();
|
2885 | this.scrollObserver.stop();
|
2886 | this.streamObserver.stop();
|
2887 | this.frameRedirector.stop();
|
2888 | this.history.stop();
|
2889 | this.started = false;
|
2890 | }
|
2891 | }
|
2892 | registerAdapter(adapter) {
|
2893 | this.adapter = adapter;
|
2894 | }
|
2895 | visit(location, options = {}) {
|
2896 | const frameElement = options.frame ? document.getElementById(options.frame) : null;
|
2897 | if (frameElement instanceof FrameElement) {
|
2898 | frameElement.src = location.toString();
|
2899 | frameElement.loaded;
|
2900 | }
|
2901 | else {
|
2902 | this.navigator.proposeVisit(expandURL(location), options);
|
2903 | }
|
2904 | }
|
2905 | connectStreamSource(source) {
|
2906 | this.streamObserver.connectStreamSource(source);
|
2907 | }
|
2908 | disconnectStreamSource(source) {
|
2909 | this.streamObserver.disconnectStreamSource(source);
|
2910 | }
|
2911 | renderStreamMessage(message) {
|
2912 | this.streamMessageRenderer.render(StreamMessage.wrap(message));
|
2913 | }
|
2914 | clearCache() {
|
2915 | this.view.clearSnapshotCache();
|
2916 | }
|
2917 | setProgressBarDelay(delay) {
|
2918 | this.progressBarDelay = delay;
|
2919 | }
|
2920 | setFormMode(mode) {
|
2921 | this.formMode = mode;
|
2922 | }
|
2923 | get location() {
|
2924 | return this.history.location;
|
2925 | }
|
2926 | get restorationIdentifier() {
|
2927 | return this.history.restorationIdentifier;
|
2928 | }
|
2929 | historyPoppedToLocationWithRestorationIdentifier(location, restorationIdentifier) {
|
2930 | if (this.enabled) {
|
2931 | this.navigator.startVisit(location, restorationIdentifier, {
|
2932 | action: "restore",
|
2933 | historyChanged: true,
|
2934 | });
|
2935 | }
|
2936 | else {
|
2937 | this.adapter.pageInvalidated({
|
2938 | reason: "turbo_disabled",
|
2939 | });
|
2940 | }
|
2941 | }
|
2942 | scrollPositionChanged(position) {
|
2943 | this.history.updateRestorationData({ scrollPosition: position });
|
2944 | }
|
2945 | willSubmitFormLinkToLocation(link, location) {
|
2946 | return this.elementIsNavigatable(link) && locationIsVisitable(location, this.snapshot.rootLocation);
|
2947 | }
|
2948 | submittedFormLinkToLocation() { }
|
2949 | willFollowLinkToLocation(link, location, event) {
|
2950 | return (this.elementIsNavigatable(link) &&
|
2951 | locationIsVisitable(location, this.snapshot.rootLocation) &&
|
2952 | this.applicationAllowsFollowingLinkToLocation(link, location, event));
|
2953 | }
|
2954 | followedLinkToLocation(link, location) {
|
2955 | const action = this.getActionForLink(link);
|
2956 | const acceptsStreamResponse = link.hasAttribute("data-turbo-stream");
|
2957 | this.visit(location.href, { action, acceptsStreamResponse });
|
2958 | }
|
2959 | allowsVisitingLocationWithAction(location, action) {
|
2960 | return this.locationWithActionIsSamePage(location, action) || this.applicationAllowsVisitingLocation(location);
|
2961 | }
|
2962 | visitProposedToLocation(location, options) {
|
2963 | extendURLWithDeprecatedProperties(location);
|
2964 | this.adapter.visitProposedToLocation(location, options);
|
2965 | }
|
2966 | visitStarted(visit) {
|
2967 | if (!visit.acceptsStreamResponse) {
|
2968 | markAsBusy(document.documentElement);
|
2969 | }
|
2970 | extendURLWithDeprecatedProperties(visit.location);
|
2971 | if (!visit.silent) {
|
2972 | this.notifyApplicationAfterVisitingLocation(visit.location, visit.action);
|
2973 | }
|
2974 | }
|
2975 | visitCompleted(visit) {
|
2976 | clearBusyState(document.documentElement);
|
2977 | this.notifyApplicationAfterPageLoad(visit.getTimingMetrics());
|
2978 | }
|
2979 | locationWithActionIsSamePage(location, action) {
|
2980 | return this.navigator.locationWithActionIsSamePage(location, action);
|
2981 | }
|
2982 | visitScrolledToSamePageLocation(oldURL, newURL) {
|
2983 | this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
2984 | }
|
2985 | willSubmitForm(form, submitter) {
|
2986 | const action = getAction(form, submitter);
|
2987 | return (this.submissionIsNavigatable(form, submitter) &&
|
2988 | locationIsVisitable(expandURL(action), this.snapshot.rootLocation));
|
2989 | }
|
2990 | formSubmitted(form, submitter) {
|
2991 | this.navigator.submitForm(form, submitter);
|
2992 | }
|
2993 | pageBecameInteractive() {
|
2994 | this.view.lastRenderedLocation = this.location;
|
2995 | this.notifyApplicationAfterPageLoad();
|
2996 | }
|
2997 | pageLoaded() {
|
2998 | this.history.assumeControlOfScrollRestoration();
|
2999 | }
|
3000 | pageWillUnload() {
|
3001 | this.history.relinquishControlOfScrollRestoration();
|
3002 | }
|
3003 | receivedMessageFromStream(message) {
|
3004 | this.renderStreamMessage(message);
|
3005 | }
|
3006 | viewWillCacheSnapshot() {
|
3007 | var _a;
|
3008 | if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) {
|
3009 | this.notifyApplicationBeforeCachingSnapshot();
|
3010 | }
|
3011 | }
|
3012 | allowsImmediateRender({ element }, options) {
|
3013 | const event = this.notifyApplicationBeforeRender(element, options);
|
3014 | const { defaultPrevented, detail: { render }, } = event;
|
3015 | if (this.view.renderer && render) {
|
3016 | this.view.renderer.renderElement = render;
|
3017 | }
|
3018 | return !defaultPrevented;
|
3019 | }
|
3020 | viewRenderedSnapshot(_snapshot, _isPreview) {
|
3021 | this.view.lastRenderedLocation = this.history.location;
|
3022 | this.notifyApplicationAfterRender();
|
3023 | }
|
3024 | preloadOnLoadLinksForView(element) {
|
3025 | this.preloader.preloadOnLoadLinksForView(element);
|
3026 | }
|
3027 | viewInvalidated(reason) {
|
3028 | this.adapter.pageInvalidated(reason);
|
3029 | }
|
3030 | frameLoaded(frame) {
|
3031 | this.notifyApplicationAfterFrameLoad(frame);
|
3032 | }
|
3033 | frameRendered(fetchResponse, frame) {
|
3034 | this.notifyApplicationAfterFrameRender(fetchResponse, frame);
|
3035 | }
|
3036 | applicationAllowsFollowingLinkToLocation(link, location, ev) {
|
3037 | const event = this.notifyApplicationAfterClickingLinkToLocation(link, location, ev);
|
3038 | return !event.defaultPrevented;
|
3039 | }
|
3040 | applicationAllowsVisitingLocation(location) {
|
3041 | const event = this.notifyApplicationBeforeVisitingLocation(location);
|
3042 | return !event.defaultPrevented;
|
3043 | }
|
3044 | notifyApplicationAfterClickingLinkToLocation(link, location, event) {
|
3045 | return dispatch("turbo:click", {
|
3046 | target: link,
|
3047 | detail: { url: location.href, originalEvent: event },
|
3048 | cancelable: true,
|
3049 | });
|
3050 | }
|
3051 | notifyApplicationBeforeVisitingLocation(location) {
|
3052 | return dispatch("turbo:before-visit", {
|
3053 | detail: { url: location.href },
|
3054 | cancelable: true,
|
3055 | });
|
3056 | }
|
3057 | notifyApplicationAfterVisitingLocation(location, action) {
|
3058 | return dispatch("turbo:visit", { detail: { url: location.href, action } });
|
3059 | }
|
3060 | notifyApplicationBeforeCachingSnapshot() {
|
3061 | return dispatch("turbo:before-cache");
|
3062 | }
|
3063 | notifyApplicationBeforeRender(newBody, options) {
|
3064 | return dispatch("turbo:before-render", {
|
3065 | detail: Object.assign({ newBody }, options),
|
3066 | cancelable: true,
|
3067 | });
|
3068 | }
|
3069 | notifyApplicationAfterRender() {
|
3070 | return dispatch("turbo:render");
|
3071 | }
|
3072 | notifyApplicationAfterPageLoad(timing = {}) {
|
3073 | return dispatch("turbo:load", {
|
3074 | detail: { url: this.location.href, timing },
|
3075 | });
|
3076 | }
|
3077 | notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
3078 | dispatchEvent(new HashChangeEvent("hashchange", {
|
3079 | oldURL: oldURL.toString(),
|
3080 | newURL: newURL.toString(),
|
3081 | }));
|
3082 | }
|
3083 | notifyApplicationAfterFrameLoad(frame) {
|
3084 | return dispatch("turbo:frame-load", { target: frame });
|
3085 | }
|
3086 | notifyApplicationAfterFrameRender(fetchResponse, frame) {
|
3087 | return dispatch("turbo:frame-render", {
|
3088 | detail: { fetchResponse },
|
3089 | target: frame,
|
3090 | cancelable: true,
|
3091 | });
|
3092 | }
|
3093 | submissionIsNavigatable(form, submitter) {
|
3094 | if (this.formMode == "off") {
|
3095 | return false;
|
3096 | }
|
3097 | else {
|
3098 | const submitterIsNavigatable = submitter ? this.elementIsNavigatable(submitter) : true;
|
3099 | if (this.formMode == "optin") {
|
3100 | return submitterIsNavigatable && form.closest('[data-turbo="true"]') != null;
|
3101 | }
|
3102 | else {
|
3103 | return submitterIsNavigatable && this.elementIsNavigatable(form);
|
3104 | }
|
3105 | }
|
3106 | }
|
3107 | elementIsNavigatable(element) {
|
3108 | const container = element.closest("[data-turbo]");
|
3109 | const withinFrame = element.closest("turbo-frame");
|
3110 | if (this.drive || withinFrame) {
|
3111 | if (container) {
|
3112 | return container.getAttribute("data-turbo") != "false";
|
3113 | }
|
3114 | else {
|
3115 | return true;
|
3116 | }
|
3117 | }
|
3118 | else {
|
3119 | if (container) {
|
3120 | return container.getAttribute("data-turbo") == "true";
|
3121 | }
|
3122 | else {
|
3123 | return false;
|
3124 | }
|
3125 | }
|
3126 | }
|
3127 | getActionForLink(link) {
|
3128 | const action = link.getAttribute("data-turbo-action");
|
3129 | return isAction(action) ? action : "advance";
|
3130 | }
|
3131 | get snapshot() {
|
3132 | return this.view.snapshot;
|
3133 | }
|
3134 | }
|
3135 | function extendURLWithDeprecatedProperties(url) {
|
3136 | Object.defineProperties(url, deprecatedLocationPropertyDescriptors);
|
3137 | }
|
3138 | const deprecatedLocationPropertyDescriptors = {
|
3139 | absoluteURL: {
|
3140 | get() {
|
3141 | return this.toString();
|
3142 | },
|
3143 | },
|
3144 | };
|
3145 |
|
3146 | class Cache {
|
3147 | constructor(session) {
|
3148 | this.session = session;
|
3149 | }
|
3150 | clear() {
|
3151 | this.session.clearCache();
|
3152 | }
|
3153 | resetCacheControl() {
|
3154 | this.setCacheControl("");
|
3155 | }
|
3156 | exemptPageFromCache() {
|
3157 | this.setCacheControl("no-cache");
|
3158 | }
|
3159 | exemptPageFromPreview() {
|
3160 | this.setCacheControl("no-preview");
|
3161 | }
|
3162 | setCacheControl(value) {
|
3163 | setMetaContent("turbo-cache-control", value);
|
3164 | }
|
3165 | }
|
3166 |
|
3167 | const StreamActions = {
|
3168 | after() {
|
3169 | this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });
|
3170 | },
|
3171 | append() {
|
3172 | this.removeDuplicateTargetChildren();
|
3173 | this.targetElements.forEach((e) => e.append(this.templateContent));
|
3174 | },
|
3175 | before() {
|
3176 | this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });
|
3177 | },
|
3178 | prepend() {
|
3179 | this.removeDuplicateTargetChildren();
|
3180 | this.targetElements.forEach((e) => e.prepend(this.templateContent));
|
3181 | },
|
3182 | remove() {
|
3183 | this.targetElements.forEach((e) => e.remove());
|
3184 | },
|
3185 | replace() {
|
3186 | this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
|
3187 | },
|
3188 | update() {
|
3189 | this.targetElements.forEach((e) => e.replaceChildren(this.templateContent));
|
3190 | },
|
3191 | };
|
3192 |
|
3193 | const session = new Session();
|
3194 | const cache = new Cache(session);
|
3195 | const { navigator: navigator$1 } = session;
|
3196 | function start() {
|
3197 | session.start();
|
3198 | }
|
3199 | function registerAdapter(adapter) {
|
3200 | session.registerAdapter(adapter);
|
3201 | }
|
3202 | function visit(location, options) {
|
3203 | session.visit(location, options);
|
3204 | }
|
3205 | function connectStreamSource(source) {
|
3206 | session.connectStreamSource(source);
|
3207 | }
|
3208 | function disconnectStreamSource(source) {
|
3209 | session.disconnectStreamSource(source);
|
3210 | }
|
3211 | function renderStreamMessage(message) {
|
3212 | session.renderStreamMessage(message);
|
3213 | }
|
3214 | function clearCache() {
|
3215 | 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.`");
|
3216 | session.clearCache();
|
3217 | }
|
3218 | function setProgressBarDelay(delay) {
|
3219 | session.setProgressBarDelay(delay);
|
3220 | }
|
3221 | function setConfirmMethod(confirmMethod) {
|
3222 | FormSubmission.confirmMethod = confirmMethod;
|
3223 | }
|
3224 | function setFormMode(mode) {
|
3225 | session.setFormMode(mode);
|
3226 | }
|
3227 |
|
3228 | var Turbo = Object.freeze({
|
3229 | __proto__: null,
|
3230 | navigator: navigator$1,
|
3231 | session: session,
|
3232 | cache: cache,
|
3233 | PageRenderer: PageRenderer,
|
3234 | PageSnapshot: PageSnapshot,
|
3235 | FrameRenderer: FrameRenderer,
|
3236 | start: start,
|
3237 | registerAdapter: registerAdapter,
|
3238 | visit: visit,
|
3239 | connectStreamSource: connectStreamSource,
|
3240 | disconnectStreamSource: disconnectStreamSource,
|
3241 | renderStreamMessage: renderStreamMessage,
|
3242 | clearCache: clearCache,
|
3243 | setProgressBarDelay: setProgressBarDelay,
|
3244 | setConfirmMethod: setConfirmMethod,
|
3245 | setFormMode: setFormMode,
|
3246 | StreamActions: StreamActions
|
3247 | });
|
3248 |
|
3249 | class FrameController {
|
3250 | constructor(element) {
|
3251 | this.fetchResponseLoaded = (_fetchResponse) => { };
|
3252 | this.currentFetchRequest = null;
|
3253 | this.resolveVisitPromise = () => { };
|
3254 | this.connected = false;
|
3255 | this.hasBeenLoaded = false;
|
3256 | this.ignoredAttributes = new Set();
|
3257 | this.action = null;
|
3258 | this.visitCachedSnapshot = ({ element }) => {
|
3259 | const frame = element.querySelector("#" + this.element.id);
|
3260 | if (frame && this.previousFrameElement) {
|
3261 | frame.replaceChildren(...this.previousFrameElement.children);
|
3262 | }
|
3263 | delete this.previousFrameElement;
|
3264 | };
|
3265 | this.element = element;
|
3266 | this.view = new FrameView(this, this.element);
|
3267 | this.appearanceObserver = new AppearanceObserver(this, this.element);
|
3268 | this.formLinkClickObserver = new FormLinkClickObserver(this, this.element);
|
3269 | this.linkInterceptor = new LinkInterceptor(this, this.element);
|
3270 | this.restorationIdentifier = uuid();
|
3271 | this.formSubmitObserver = new FormSubmitObserver(this, this.element);
|
3272 | }
|
3273 | connect() {
|
3274 | if (!this.connected) {
|
3275 | this.connected = true;
|
3276 | if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
3277 | this.appearanceObserver.start();
|
3278 | }
|
3279 | else {
|
3280 | this.loadSourceURL();
|
3281 | }
|
3282 | this.formLinkClickObserver.start();
|
3283 | this.linkInterceptor.start();
|
3284 | this.formSubmitObserver.start();
|
3285 | }
|
3286 | }
|
3287 | disconnect() {
|
3288 | if (this.connected) {
|
3289 | this.connected = false;
|
3290 | this.appearanceObserver.stop();
|
3291 | this.formLinkClickObserver.stop();
|
3292 | this.linkInterceptor.stop();
|
3293 | this.formSubmitObserver.stop();
|
3294 | }
|
3295 | }
|
3296 | disabledChanged() {
|
3297 | if (this.loadingStyle == FrameLoadingStyle.eager) {
|
3298 | this.loadSourceURL();
|
3299 | }
|
3300 | }
|
3301 | sourceURLChanged() {
|
3302 | if (this.isIgnoringChangesTo("src"))
|
3303 | return;
|
3304 | if (this.element.isConnected) {
|
3305 | this.complete = false;
|
3306 | }
|
3307 | if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
|
3308 | this.loadSourceURL();
|
3309 | }
|
3310 | }
|
3311 | sourceURLReloaded() {
|
3312 | const { src } = this.element;
|
3313 | this.ignoringChangesToAttribute("complete", () => {
|
3314 | this.element.removeAttribute("complete");
|
3315 | });
|
3316 | this.element.src = null;
|
3317 | this.element.src = src;
|
3318 | return this.element.loaded;
|
3319 | }
|
3320 | completeChanged() {
|
3321 | if (this.isIgnoringChangesTo("complete"))
|
3322 | return;
|
3323 | this.loadSourceURL();
|
3324 | }
|
3325 | loadingStyleChanged() {
|
3326 | if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
3327 | this.appearanceObserver.start();
|
3328 | }
|
3329 | else {
|
3330 | this.appearanceObserver.stop();
|
3331 | this.loadSourceURL();
|
3332 | }
|
3333 | }
|
3334 | async loadSourceURL() {
|
3335 | if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
|
3336 | this.element.loaded = this.visit(expandURL(this.sourceURL));
|
3337 | this.appearanceObserver.stop();
|
3338 | await this.element.loaded;
|
3339 | this.hasBeenLoaded = true;
|
3340 | }
|
3341 | }
|
3342 | async loadResponse(fetchResponse) {
|
3343 | if (fetchResponse.redirected || (fetchResponse.succeeded && fetchResponse.isHTML)) {
|
3344 | this.sourceURL = fetchResponse.response.url;
|
3345 | }
|
3346 | try {
|
3347 | const html = await fetchResponse.responseHTML;
|
3348 | if (html) {
|
3349 | const { body } = parseHTMLDocument(html);
|
3350 | const newFrameElement = await this.extractForeignFrameElement(body);
|
3351 | if (newFrameElement) {
|
3352 | const snapshot = new Snapshot(newFrameElement);
|
3353 | const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
|
3354 | if (this.view.renderPromise)
|
3355 | await this.view.renderPromise;
|
3356 | this.changeHistory();
|
3357 | await this.view.render(renderer);
|
3358 | this.complete = true;
|
3359 | session.frameRendered(fetchResponse, this.element);
|
3360 | session.frameLoaded(this.element);
|
3361 | this.fetchResponseLoaded(fetchResponse);
|
3362 | }
|
3363 | else if (this.willHandleFrameMissingFromResponse(fetchResponse)) {
|
3364 | console.warn(`A matching frame for #${this.element.id} was missing from the response, transforming into full-page Visit.`);
|
3365 | this.visitResponse(fetchResponse.response);
|
3366 | }
|
3367 | }
|
3368 | }
|
3369 | catch (error) {
|
3370 | console.error(error);
|
3371 | this.view.invalidate();
|
3372 | }
|
3373 | finally {
|
3374 | this.fetchResponseLoaded = () => { };
|
3375 | }
|
3376 | }
|
3377 | elementAppearedInViewport(_element) {
|
3378 | this.loadSourceURL();
|
3379 | }
|
3380 | willSubmitFormLinkToLocation(link) {
|
3381 | return this.shouldInterceptNavigation(link);
|
3382 | }
|
3383 | submittedFormLinkToLocation(link, _location, form) {
|
3384 | const frame = this.findFrameElement(link);
|
3385 | if (frame)
|
3386 | form.setAttribute("data-turbo-frame", frame.id);
|
3387 | }
|
3388 | shouldInterceptLinkClick(element, _location, _event) {
|
3389 | return this.shouldInterceptNavigation(element);
|
3390 | }
|
3391 | linkClickIntercepted(element, location) {
|
3392 | this.navigateFrame(element, location);
|
3393 | }
|
3394 | willSubmitForm(element, submitter) {
|
3395 | return element.closest("turbo-frame") == this.element && this.shouldInterceptNavigation(element, submitter);
|
3396 | }
|
3397 | formSubmitted(element, submitter) {
|
3398 | if (this.formSubmission) {
|
3399 | this.formSubmission.stop();
|
3400 | }
|
3401 | this.formSubmission = new FormSubmission(this, element, submitter);
|
3402 | const { fetchRequest } = this.formSubmission;
|
3403 | this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest);
|
3404 | this.formSubmission.start();
|
3405 | }
|
3406 | prepareHeadersForRequest(headers, request) {
|
3407 | var _a;
|
3408 | headers["Turbo-Frame"] = this.id;
|
3409 | if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute("data-turbo-stream")) {
|
3410 | request.acceptResponseType(StreamMessage.contentType);
|
3411 | }
|
3412 | }
|
3413 | requestStarted(_request) {
|
3414 | markAsBusy(this.element);
|
3415 | }
|
3416 | requestPreventedHandlingResponse(_request, _response) {
|
3417 | this.resolveVisitPromise();
|
3418 | }
|
3419 | async requestSucceededWithResponse(request, response) {
|
3420 | await this.loadResponse(response);
|
3421 | this.resolveVisitPromise();
|
3422 | }
|
3423 | async requestFailedWithResponse(request, response) {
|
3424 | console.error(response);
|
3425 | await this.loadResponse(response);
|
3426 | this.resolveVisitPromise();
|
3427 | }
|
3428 | requestErrored(request, error) {
|
3429 | console.error(error);
|
3430 | this.resolveVisitPromise();
|
3431 | }
|
3432 | requestFinished(_request) {
|
3433 | clearBusyState(this.element);
|
3434 | }
|
3435 | formSubmissionStarted({ formElement }) {
|
3436 | markAsBusy(formElement, this.findFrameElement(formElement));
|
3437 | }
|
3438 | formSubmissionSucceededWithResponse(formSubmission, response) {
|
3439 | const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
|
3440 | frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
|
3441 | frame.delegate.loadResponse(response);
|
3442 | }
|
3443 | formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
3444 | this.element.delegate.loadResponse(fetchResponse);
|
3445 | }
|
3446 | formSubmissionErrored(formSubmission, error) {
|
3447 | console.error(error);
|
3448 | }
|
3449 | formSubmissionFinished({ formElement }) {
|
3450 | clearBusyState(formElement, this.findFrameElement(formElement));
|
3451 | }
|
3452 | allowsImmediateRender({ element: newFrame }, options) {
|
3453 | const event = dispatch("turbo:before-frame-render", {
|
3454 | target: this.element,
|
3455 | detail: Object.assign({ newFrame }, options),
|
3456 | cancelable: true,
|
3457 | });
|
3458 | const { defaultPrevented, detail: { render }, } = event;
|
3459 | if (this.view.renderer && render) {
|
3460 | this.view.renderer.renderElement = render;
|
3461 | }
|
3462 | return !defaultPrevented;
|
3463 | }
|
3464 | viewRenderedSnapshot(_snapshot, _isPreview) { }
|
3465 | preloadOnLoadLinksForView(element) {
|
3466 | session.preloadOnLoadLinksForView(element);
|
3467 | }
|
3468 | viewInvalidated() { }
|
3469 | willRenderFrame(currentElement, _newElement) {
|
3470 | this.previousFrameElement = currentElement.cloneNode(true);
|
3471 | }
|
3472 | async visit(url) {
|
3473 | var _a;
|
3474 | const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
|
3475 | (_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
|
3476 | this.currentFetchRequest = request;
|
3477 | return new Promise((resolve) => {
|
3478 | this.resolveVisitPromise = () => {
|
3479 | this.resolveVisitPromise = () => { };
|
3480 | this.currentFetchRequest = null;
|
3481 | resolve();
|
3482 | };
|
3483 | request.perform();
|
3484 | });
|
3485 | }
|
3486 | navigateFrame(element, url, submitter) {
|
3487 | const frame = this.findFrameElement(element, submitter);
|
3488 | this.pageSnapshot = PageSnapshot.fromElement(frame).clone();
|
3489 | frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
|
3490 | this.withCurrentNavigationElement(element, () => {
|
3491 | frame.src = url;
|
3492 | });
|
3493 | }
|
3494 | proposeVisitIfNavigatedWithAction(frame, element, submitter) {
|
3495 | this.action = getVisitAction(submitter, element, frame);
|
3496 | if (isAction(this.action)) {
|
3497 | const { visitCachedSnapshot } = frame.delegate;
|
3498 | frame.delegate.fetchResponseLoaded = (fetchResponse) => {
|
3499 | if (frame.src) {
|
3500 | const { statusCode, redirected } = fetchResponse;
|
3501 | const responseHTML = frame.ownerDocument.documentElement.outerHTML;
|
3502 | const response = { statusCode, redirected, responseHTML };
|
3503 | const options = {
|
3504 | response,
|
3505 | visitCachedSnapshot,
|
3506 | willRender: false,
|
3507 | updateHistory: false,
|
3508 | restorationIdentifier: this.restorationIdentifier,
|
3509 | snapshot: this.pageSnapshot,
|
3510 | };
|
3511 | if (this.action)
|
3512 | options.action = this.action;
|
3513 | session.visit(frame.src, options);
|
3514 | }
|
3515 | };
|
3516 | }
|
3517 | }
|
3518 | changeHistory() {
|
3519 | if (this.action) {
|
3520 | const method = getHistoryMethodForAction(this.action);
|
3521 | session.history.update(method, expandURL(this.element.src || ""), this.restorationIdentifier);
|
3522 | }
|
3523 | }
|
3524 | willHandleFrameMissingFromResponse(fetchResponse) {
|
3525 | this.element.setAttribute("complete", "");
|
3526 | const response = fetchResponse.response;
|
3527 | const visit = async (url, options = {}) => {
|
3528 | if (url instanceof Response) {
|
3529 | this.visitResponse(url);
|
3530 | }
|
3531 | else {
|
3532 | session.visit(url, options);
|
3533 | }
|
3534 | };
|
3535 | const event = dispatch("turbo:frame-missing", {
|
3536 | target: this.element,
|
3537 | detail: { response, visit },
|
3538 | cancelable: true,
|
3539 | });
|
3540 | return !event.defaultPrevented;
|
3541 | }
|
3542 | async visitResponse(response) {
|
3543 | const wrapped = new FetchResponse(response);
|
3544 | const responseHTML = await wrapped.responseHTML;
|
3545 | const { location, redirected, statusCode } = wrapped;
|
3546 | return session.visit(location, { response: { redirected, statusCode, responseHTML } });
|
3547 | }
|
3548 | findFrameElement(element, submitter) {
|
3549 | var _a;
|
3550 | const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
3551 | return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
|
3552 | }
|
3553 | async extractForeignFrameElement(container) {
|
3554 | let element;
|
3555 | const id = CSS.escape(this.id);
|
3556 | try {
|
3557 | element = activateElement(container.querySelector(`turbo-frame#${id}`), this.sourceURL);
|
3558 | if (element) {
|
3559 | return element;
|
3560 | }
|
3561 | element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.sourceURL);
|
3562 | if (element) {
|
3563 | await element.loaded;
|
3564 | return await this.extractForeignFrameElement(element);
|
3565 | }
|
3566 | }
|
3567 | catch (error) {
|
3568 | console.error(error);
|
3569 | return new FrameElement();
|
3570 | }
|
3571 | return null;
|
3572 | }
|
3573 | formActionIsVisitable(form, submitter) {
|
3574 | const action = getAction(form, submitter);
|
3575 | return locationIsVisitable(expandURL(action), this.rootLocation);
|
3576 | }
|
3577 | shouldInterceptNavigation(element, submitter) {
|
3578 | const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
3579 | if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) {
|
3580 | return false;
|
3581 | }
|
3582 | if (!this.enabled || id == "_top") {
|
3583 | return false;
|
3584 | }
|
3585 | if (id) {
|
3586 | const frameElement = getFrameElementById(id);
|
3587 | if (frameElement) {
|
3588 | return !frameElement.disabled;
|
3589 | }
|
3590 | }
|
3591 | if (!session.elementIsNavigatable(element)) {
|
3592 | return false;
|
3593 | }
|
3594 | if (submitter && !session.elementIsNavigatable(submitter)) {
|
3595 | return false;
|
3596 | }
|
3597 | return true;
|
3598 | }
|
3599 | get id() {
|
3600 | return this.element.id;
|
3601 | }
|
3602 | get enabled() {
|
3603 | return !this.element.disabled;
|
3604 | }
|
3605 | get sourceURL() {
|
3606 | if (this.element.src) {
|
3607 | return this.element.src;
|
3608 | }
|
3609 | }
|
3610 | set sourceURL(sourceURL) {
|
3611 | this.ignoringChangesToAttribute("src", () => {
|
3612 | this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
|
3613 | });
|
3614 | }
|
3615 | get loadingStyle() {
|
3616 | return this.element.loading;
|
3617 | }
|
3618 | get isLoading() {
|
3619 | return this.formSubmission !== undefined || this.resolveVisitPromise() !== undefined;
|
3620 | }
|
3621 | get complete() {
|
3622 | return this.element.hasAttribute("complete");
|
3623 | }
|
3624 | set complete(value) {
|
3625 | this.ignoringChangesToAttribute("complete", () => {
|
3626 | if (value) {
|
3627 | this.element.setAttribute("complete", "");
|
3628 | }
|
3629 | else {
|
3630 | this.element.removeAttribute("complete");
|
3631 | }
|
3632 | });
|
3633 | }
|
3634 | get isActive() {
|
3635 | return this.element.isActive && this.connected;
|
3636 | }
|
3637 | get rootLocation() {
|
3638 | var _a;
|
3639 | const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`);
|
3640 | const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
|
3641 | return expandURL(root);
|
3642 | }
|
3643 | isIgnoringChangesTo(attributeName) {
|
3644 | return this.ignoredAttributes.has(attributeName);
|
3645 | }
|
3646 | ignoringChangesToAttribute(attributeName, callback) {
|
3647 | this.ignoredAttributes.add(attributeName);
|
3648 | callback();
|
3649 | this.ignoredAttributes.delete(attributeName);
|
3650 | }
|
3651 | withCurrentNavigationElement(element, callback) {
|
3652 | this.currentNavigationElement = element;
|
3653 | callback();
|
3654 | delete this.currentNavigationElement;
|
3655 | }
|
3656 | }
|
3657 | function getFrameElementById(id) {
|
3658 | if (id != null) {
|
3659 | const element = document.getElementById(id);
|
3660 | if (element instanceof FrameElement) {
|
3661 | return element;
|
3662 | }
|
3663 | }
|
3664 | }
|
3665 | function activateElement(element, currentURL) {
|
3666 | if (element) {
|
3667 | const src = element.getAttribute("src");
|
3668 | if (src != null && currentURL != null && urlsAreEqual(src, currentURL)) {
|
3669 | throw new Error(`Matching <turbo-frame id="${element.id}"> element has a source URL which references itself`);
|
3670 | }
|
3671 | if (element.ownerDocument !== document) {
|
3672 | element = document.importNode(element, true);
|
3673 | }
|
3674 | if (element instanceof FrameElement) {
|
3675 | element.connectedCallback();
|
3676 | element.disconnectedCallback();
|
3677 | return element;
|
3678 | }
|
3679 | }
|
3680 | }
|
3681 |
|
3682 | class StreamElement extends HTMLElement {
|
3683 | static async renderElement(newElement) {
|
3684 | await newElement.performAction();
|
3685 | }
|
3686 | async connectedCallback() {
|
3687 | try {
|
3688 | await this.render();
|
3689 | }
|
3690 | catch (error) {
|
3691 | console.error(error);
|
3692 | }
|
3693 | finally {
|
3694 | this.disconnect();
|
3695 | }
|
3696 | }
|
3697 | async render() {
|
3698 | var _a;
|
3699 | return ((_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
3700 | const event = this.beforeRenderEvent;
|
3701 | if (this.dispatchEvent(event)) {
|
3702 | await nextAnimationFrame();
|
3703 | await event.detail.render(this);
|
3704 | }
|
3705 | })()));
|
3706 | }
|
3707 | disconnect() {
|
3708 | try {
|
3709 | this.remove();
|
3710 | }
|
3711 | catch (_a) { }
|
3712 | }
|
3713 | removeDuplicateTargetChildren() {
|
3714 | this.duplicateChildren.forEach((c) => c.remove());
|
3715 | }
|
3716 | get duplicateChildren() {
|
3717 | var _a;
|
3718 | const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);
|
3719 | const newChildrenIds = [...(((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || [])].filter((c) => !!c.id).map((c) => c.id);
|
3720 | return existingChildren.filter((c) => newChildrenIds.includes(c.id));
|
3721 | }
|
3722 | get performAction() {
|
3723 | if (this.action) {
|
3724 | const actionFunction = StreamActions[this.action];
|
3725 | if (actionFunction) {
|
3726 | return actionFunction;
|
3727 | }
|
3728 | this.raise("unknown action");
|
3729 | }
|
3730 | this.raise("action attribute is missing");
|
3731 | }
|
3732 | get targetElements() {
|
3733 | if (this.target) {
|
3734 | return this.targetElementsById;
|
3735 | }
|
3736 | else if (this.targets) {
|
3737 | return this.targetElementsByQuery;
|
3738 | }
|
3739 | else {
|
3740 | this.raise("target or targets attribute is missing");
|
3741 | }
|
3742 | }
|
3743 | get templateContent() {
|
3744 | return this.templateElement.content.cloneNode(true);
|
3745 | }
|
3746 | get templateElement() {
|
3747 | if (this.firstElementChild === null) {
|
3748 | const template = this.ownerDocument.createElement("template");
|
3749 | this.appendChild(template);
|
3750 | return template;
|
3751 | }
|
3752 | else if (this.firstElementChild instanceof HTMLTemplateElement) {
|
3753 | return this.firstElementChild;
|
3754 | }
|
3755 | this.raise("first child element must be a <template> element");
|
3756 | }
|
3757 | get action() {
|
3758 | return this.getAttribute("action");
|
3759 | }
|
3760 | get target() {
|
3761 | return this.getAttribute("target");
|
3762 | }
|
3763 | get targets() {
|
3764 | return this.getAttribute("targets");
|
3765 | }
|
3766 | raise(message) {
|
3767 | throw new Error(`${this.description}: ${message}`);
|
3768 | }
|
3769 | get description() {
|
3770 | var _a, _b;
|
3771 | return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
|
3772 | }
|
3773 | get beforeRenderEvent() {
|
3774 | return new CustomEvent("turbo:before-stream-render", {
|
3775 | bubbles: true,
|
3776 | cancelable: true,
|
3777 | detail: { newStream: this, render: StreamElement.renderElement },
|
3778 | });
|
3779 | }
|
3780 | get targetElementsById() {
|
3781 | var _a;
|
3782 | const element = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.getElementById(this.target);
|
3783 | if (element !== null) {
|
3784 | return [element];
|
3785 | }
|
3786 | else {
|
3787 | return [];
|
3788 | }
|
3789 | }
|
3790 | get targetElementsByQuery() {
|
3791 | var _a;
|
3792 | const elements = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.querySelectorAll(this.targets);
|
3793 | if (elements.length !== 0) {
|
3794 | return Array.prototype.slice.call(elements);
|
3795 | }
|
3796 | else {
|
3797 | return [];
|
3798 | }
|
3799 | }
|
3800 | }
|
3801 |
|
3802 | class StreamSourceElement extends HTMLElement {
|
3803 | constructor() {
|
3804 | super(...arguments);
|
3805 | this.streamSource = null;
|
3806 | }
|
3807 | connectedCallback() {
|
3808 | this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
|
3809 | connectStreamSource(this.streamSource);
|
3810 | }
|
3811 | disconnectedCallback() {
|
3812 | if (this.streamSource) {
|
3813 | disconnectStreamSource(this.streamSource);
|
3814 | }
|
3815 | }
|
3816 | get src() {
|
3817 | return this.getAttribute("src") || "";
|
3818 | }
|
3819 | }
|
3820 |
|
3821 | FrameElement.delegateConstructor = FrameController;
|
3822 | if (customElements.get("turbo-frame") === undefined) {
|
3823 | customElements.define("turbo-frame", FrameElement);
|
3824 | }
|
3825 | if (customElements.get("turbo-stream") === undefined) {
|
3826 | customElements.define("turbo-stream", StreamElement);
|
3827 | }
|
3828 | if (customElements.get("turbo-stream-source") === undefined) {
|
3829 | customElements.define("turbo-stream-source", StreamSourceElement);
|
3830 | }
|
3831 |
|
3832 | (() => {
|
3833 | let element = document.currentScript;
|
3834 | if (!element)
|
3835 | return;
|
3836 | if (element.hasAttribute("data-turbo-suppress-warning"))
|
3837 | return;
|
3838 | element = element.parentElement;
|
3839 | while (element) {
|
3840 | if (element == document.body) {
|
3841 | return console.warn(unindent `
|
3842 | You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
|
3843 |
|
3844 | Load your application’s JavaScript bundle inside the <head> element instead. <script> elements in <body> are evaluated with each page change.
|
3845 |
|
3846 | For more information, see: https://turbo.hotwired.dev/handbook/building#working-with-script-elements
|
3847 |
|
3848 | ——
|
3849 | Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
3850 | `, element.outerHTML);
|
3851 | }
|
3852 | element = element.parentElement;
|
3853 | }
|
3854 | })();
|
3855 |
|
3856 | window.Turbo = Turbo;
|
3857 | start();
|
3858 |
|
3859 | export { FrameElement, FrameLoadingStyle, FrameRenderer, PageRenderer, PageSnapshot, StreamActions, StreamElement, StreamSourceElement, cache, clearCache, connectStreamSource, disconnectStreamSource, navigator$1 as navigator, registerAdapter, renderStreamMessage, session, setConfirmMethod, setFormMode, setProgressBarDelay, start, visit };
|