turbo-rails 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/turbo.js +660 -585
- data/app/helpers/turbo/streams/action_helper.rb +2 -7
- data/app/models/turbo/streams/tag_builder.rb +2 -1
- data/lib/turbo/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 025ba92afa27783a938ec698ff465685559d71698ab3023b091a54d14f0d6dd1
         | 
| 4 | 
            +
              data.tar.gz: ae377ccfdb57c9f9f2f862dc81e5863a5bc614002bbdfe39547cb1ede2aa797a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a7f03c2b76b07d65f64b3170b9f9ed6c1a9c4429c9f7eee3abf8bffbdbed8a320806f239df725c5aad37c826d2171ec2abc0c7787d42f929e2741584fc4d84e3
         | 
| 7 | 
            +
              data.tar.gz: b2566bd6203b982d5b3cad1c852517a41b3a11ca8c8f097cac3cf7ff45f8d83db3eab3337807a80299cf61fc21f58990275f2e5dc92af75b03b167bf04f05ecc
         | 
| @@ -132,82 +132,59 @@ function frameLoadingStyleFromString(style) { | |
| 132 132 | 
             
              }
         | 
| 133 133 | 
             
            }
         | 
| 134 134 |  | 
| 135 | 
            -
             | 
| 136 | 
            -
               | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 144 | 
            -
             | 
| 145 | 
            -
             | 
| 146 | 
            -
                 | 
| 147 | 
            -
              }
         | 
| 148 | 
            -
             | 
| 149 | 
            -
                return this.wrap(window.location.toString());
         | 
| 150 | 
            -
              }
         | 
| 151 | 
            -
              static wrap(locatable) {
         | 
| 152 | 
            -
                if (typeof locatable == "string") {
         | 
| 153 | 
            -
                  return new this(locatable);
         | 
| 154 | 
            -
                } else if (locatable != null) {
         | 
| 155 | 
            -
                  return locatable;
         | 
| 156 | 
            -
                }
         | 
| 157 | 
            -
              }
         | 
| 158 | 
            -
              getOrigin() {
         | 
| 159 | 
            -
                return this.absoluteURL.split("/", 3).join("/");
         | 
| 160 | 
            -
              }
         | 
| 161 | 
            -
              getPath() {
         | 
| 162 | 
            -
                return (this.requestURL.match(/\/\/[^/]*(\/[^?;]*)/) || [])[1] || "/";
         | 
| 163 | 
            -
              }
         | 
| 164 | 
            -
              getPathComponents() {
         | 
| 165 | 
            -
                return this.getPath().split("/").slice(1);
         | 
| 166 | 
            -
              }
         | 
| 167 | 
            -
              getLastPathComponent() {
         | 
| 168 | 
            -
                return this.getPathComponents().slice(-1)[0];
         | 
| 169 | 
            -
              }
         | 
| 170 | 
            -
              getExtension() {
         | 
| 171 | 
            -
                return (this.getLastPathComponent().match(/\.[^.]*$/) || [])[0] || "";
         | 
| 172 | 
            -
              }
         | 
| 173 | 
            -
              isHTML() {
         | 
| 174 | 
            -
                return !!this.getExtension().match(/^(?:|\.(?:htm|html|xhtml))$/);
         | 
| 175 | 
            -
              }
         | 
| 176 | 
            -
              isPrefixedBy(location) {
         | 
| 177 | 
            -
                const prefixURL = getPrefixURL(location);
         | 
| 178 | 
            -
                return this.isEqualTo(location) || stringStartsWith(this.absoluteURL, prefixURL);
         | 
| 179 | 
            -
              }
         | 
| 180 | 
            -
              isEqualTo(location) {
         | 
| 181 | 
            -
                return location && this.absoluteURL === location.absoluteURL;
         | 
| 182 | 
            -
              }
         | 
| 183 | 
            -
              toCacheKey() {
         | 
| 184 | 
            -
                return this.requestURL;
         | 
| 185 | 
            -
              }
         | 
| 186 | 
            -
              toJSON() {
         | 
| 187 | 
            -
                return this.absoluteURL;
         | 
| 188 | 
            -
              }
         | 
| 189 | 
            -
              toString() {
         | 
| 190 | 
            -
                return this.absoluteURL;
         | 
| 135 | 
            +
            function expandURL(locatable) {
         | 
| 136 | 
            +
              const anchor = document.createElement("a");
         | 
| 137 | 
            +
              anchor.href = locatable.toString();
         | 
| 138 | 
            +
              return new URL(anchor.href);
         | 
| 139 | 
            +
            }
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            function getAnchor(url) {
         | 
| 142 | 
            +
              let anchorMatch;
         | 
| 143 | 
            +
              if (url.hash) {
         | 
| 144 | 
            +
                return url.hash.slice(1);
         | 
| 145 | 
            +
              } else if (anchorMatch = url.href.match(/#(.*)$/)) {
         | 
| 146 | 
            +
                return anchorMatch[1];
         | 
| 147 | 
            +
              } else {
         | 
| 148 | 
            +
                return "";
         | 
| 191 149 | 
             
              }
         | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 150 | 
            +
            }
         | 
| 151 | 
            +
             | 
| 152 | 
            +
            function getExtension(url) {
         | 
| 153 | 
            +
              return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
         | 
| 154 | 
            +
            }
         | 
| 155 | 
            +
             | 
| 156 | 
            +
            function isHTML(url) {
         | 
| 157 | 
            +
              return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml))$/);
         | 
| 158 | 
            +
            }
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            function isPrefixedBy(baseURL, url) {
         | 
| 161 | 
            +
              const prefix = getPrefix(url);
         | 
| 162 | 
            +
              return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix);
         | 
| 163 | 
            +
            }
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            function toCacheKey(url) {
         | 
| 166 | 
            +
              const anchorLength = url.hash.length;
         | 
| 167 | 
            +
              if (anchorLength < 2) {
         | 
| 168 | 
            +
                return url.href;
         | 
| 169 | 
            +
              } else {
         | 
| 170 | 
            +
                return url.href.slice(0, -anchorLength);
         | 
| 194 171 | 
             
              }
         | 
| 195 172 | 
             
            }
         | 
| 196 173 |  | 
| 197 | 
            -
            function  | 
| 198 | 
            -
              return  | 
| 174 | 
            +
            function getPathComponents(url) {
         | 
| 175 | 
            +
              return url.pathname.split("/").slice(1);
         | 
| 199 176 | 
             
            }
         | 
| 200 177 |  | 
| 201 | 
            -
            function  | 
| 202 | 
            -
              return  | 
| 178 | 
            +
            function getLastPathComponent(url) {
         | 
| 179 | 
            +
              return getPathComponents(url).slice(-1)[0];
         | 
| 203 180 | 
             
            }
         | 
| 204 181 |  | 
| 205 | 
            -
            function  | 
| 206 | 
            -
              return  | 
| 182 | 
            +
            function getPrefix(url) {
         | 
| 183 | 
            +
              return addTrailingSlash(url.origin + url.pathname);
         | 
| 207 184 | 
             
            }
         | 
| 208 185 |  | 
| 209 | 
            -
            function  | 
| 210 | 
            -
              return  | 
| 186 | 
            +
            function addTrailingSlash(value) {
         | 
| 187 | 
            +
              return value.endsWith("/") ? value : value + "/";
         | 
| 211 188 | 
             
            }
         | 
| 212 189 |  | 
| 213 190 | 
             
            class FetchResponse {
         | 
| @@ -230,7 +207,7 @@ class FetchResponse { | |
| 230 207 | 
             
                return this.response.redirected;
         | 
| 231 208 | 
             
              }
         | 
| 232 209 | 
             
              get location() {
         | 
| 233 | 
            -
                return  | 
| 210 | 
            +
                return expandURL(this.response.url);
         | 
| 234 211 | 
             
              }
         | 
| 235 212 | 
             
              get isHTML() {
         | 
| 236 213 | 
             
                return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
         | 
| @@ -270,10 +247,18 @@ function nextAnimationFrame() { | |
| 270 247 | 
             
              return new Promise((resolve => requestAnimationFrame((() => resolve()))));
         | 
| 271 248 | 
             
            }
         | 
| 272 249 |  | 
| 250 | 
            +
            function nextEventLoopTick() {
         | 
| 251 | 
            +
              return new Promise((resolve => setTimeout((() => resolve()), 0)));
         | 
| 252 | 
            +
            }
         | 
| 253 | 
            +
             | 
| 273 254 | 
             
            function nextMicrotask() {
         | 
| 274 255 | 
             
              return Promise.resolve();
         | 
| 275 256 | 
             
            }
         | 
| 276 257 |  | 
| 258 | 
            +
            function parseHTMLDocument(html = "") {
         | 
| 259 | 
            +
              return (new DOMParser).parseFromString(html, "text/html");
         | 
| 260 | 
            +
            }
         | 
| 261 | 
            +
             | 
| 277 262 | 
             
            function unindent(strings, ...values) {
         | 
| 278 263 | 
             
              const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
         | 
| 279 264 | 
             
              const match = lines[0].match(/^\s+/);
         | 
| @@ -334,27 +319,22 @@ function fetchMethodFromString(method) { | |
| 334 319 | 
             
            }
         | 
| 335 320 |  | 
| 336 321 | 
             
            class FetchRequest {
         | 
| 337 | 
            -
              constructor(delegate, method, location, body) {
         | 
| 322 | 
            +
              constructor(delegate, method, location, body = new URLSearchParams) {
         | 
| 338 323 | 
             
                this.abortController = new AbortController;
         | 
| 339 324 | 
             
                this.delegate = delegate;
         | 
| 340 325 | 
             
                this.method = method;
         | 
| 341 | 
            -
                this. | 
| 342 | 
            -
             | 
| 343 | 
            -
              }
         | 
| 344 | 
            -
              get url() {
         | 
| 345 | 
            -
                const url = this.location.absoluteURL;
         | 
| 346 | 
            -
                const query = this.params.toString();
         | 
| 347 | 
            -
                if (this.isIdempotent && query.length) {
         | 
| 348 | 
            -
                  return [ url, query ].join(url.includes("?") ? "&" : "?");
         | 
| 326 | 
            +
                if (this.isIdempotent) {
         | 
| 327 | 
            +
                  this.url = mergeFormDataEntries(location, [ ...body.entries() ]);
         | 
| 349 328 | 
             
                } else {
         | 
| 350 | 
            -
                   | 
| 329 | 
            +
                  this.body = body;
         | 
| 330 | 
            +
                  this.url = location;
         | 
| 351 331 | 
             
                }
         | 
| 352 332 | 
             
              }
         | 
| 333 | 
            +
              get location() {
         | 
| 334 | 
            +
                return this.url;
         | 
| 335 | 
            +
              }
         | 
| 353 336 | 
             
              get params() {
         | 
| 354 | 
            -
                return this. | 
| 355 | 
            -
                  params.append(name, value.toString());
         | 
| 356 | 
            -
                  return params;
         | 
| 357 | 
            -
                }), new URLSearchParams);
         | 
| 337 | 
            +
                return this.url.searchParams;
         | 
| 358 338 | 
             
              }
         | 
| 359 339 | 
             
              get entries() {
         | 
| 360 340 | 
             
                return this.body ? Array.from(this.body.entries()) : [];
         | 
| @@ -371,7 +351,7 @@ class FetchRequest { | |
| 371 351 | 
             
                });
         | 
| 372 352 | 
             
                try {
         | 
| 373 353 | 
             
                  this.delegate.requestStarted(this);
         | 
| 374 | 
            -
                  const response = await fetch(this.url, fetchOptions);
         | 
| 354 | 
            +
                  const response = await fetch(this.url.href, fetchOptions);
         | 
| 375 355 | 
             
                  return await this.receive(response);
         | 
| 376 356 | 
             
                } catch (error) {
         | 
| 377 357 | 
             
                  this.delegate.requestErrored(this, error);
         | 
| @@ -403,7 +383,7 @@ class FetchRequest { | |
| 403 383 | 
             
                  credentials: "same-origin",
         | 
| 404 384 | 
             
                  headers: this.headers,
         | 
| 405 385 | 
             
                  redirect: "follow",
         | 
| 406 | 
            -
                  body: this. | 
| 386 | 
            +
                  body: this.body,
         | 
| 407 387 | 
             
                  signal: this.abortSignal
         | 
| 408 388 | 
             
                };
         | 
| 409 389 | 
             
              }
         | 
| @@ -411,20 +391,34 @@ class FetchRequest { | |
| 411 391 | 
             
                return this.method == FetchMethod.get;
         | 
| 412 392 | 
             
              }
         | 
| 413 393 | 
             
              get headers() {
         | 
| 414 | 
            -
                 | 
| 415 | 
            -
             | 
| 416 | 
            -
             | 
| 417 | 
            -
              }
         | 
| 418 | 
            -
              get additionalHeaders() {
         | 
| 419 | 
            -
                if (typeof this.delegate.additionalHeadersForRequest == "function") {
         | 
| 420 | 
            -
                  return this.delegate.additionalHeadersForRequest(this);
         | 
| 421 | 
            -
                } else {
         | 
| 422 | 
            -
                  return {};
         | 
| 394 | 
            +
                const headers = Object.assign({}, this.defaultHeaders);
         | 
| 395 | 
            +
                if (typeof this.delegate.prepareHeadersForRequest == "function") {
         | 
| 396 | 
            +
                  this.delegate.prepareHeadersForRequest(headers, this);
         | 
| 423 397 | 
             
                }
         | 
| 398 | 
            +
                return headers;
         | 
| 424 399 | 
             
              }
         | 
| 425 400 | 
             
              get abortSignal() {
         | 
| 426 401 | 
             
                return this.abortController.signal;
         | 
| 427 402 | 
             
              }
         | 
| 403 | 
            +
              get defaultHeaders() {
         | 
| 404 | 
            +
                return {
         | 
| 405 | 
            +
                  Accept: "text/html, application/xhtml+xml"
         | 
| 406 | 
            +
                };
         | 
| 407 | 
            +
              }
         | 
| 408 | 
            +
            }
         | 
| 409 | 
            +
             | 
| 410 | 
            +
            function mergeFormDataEntries(url, entries) {
         | 
| 411 | 
            +
              const currentSearchParams = new URLSearchParams(url.search);
         | 
| 412 | 
            +
              for (const [name, value] of entries) {
         | 
| 413 | 
            +
                if (value instanceof File) continue;
         | 
| 414 | 
            +
                if (currentSearchParams.has(name)) {
         | 
| 415 | 
            +
                  currentSearchParams.delete(name);
         | 
| 416 | 
            +
                  url.searchParams.set(name, value);
         | 
| 417 | 
            +
                } else {
         | 
| 418 | 
            +
                  url.searchParams.append(name, value);
         | 
| 419 | 
            +
                }
         | 
| 420 | 
            +
              }
         | 
| 421 | 
            +
              return url;
         | 
| 428 422 | 
             
            }
         | 
| 429 423 |  | 
| 430 424 | 
             
            class AppearanceObserver {
         | 
| @@ -454,6 +448,41 @@ class AppearanceObserver { | |
| 454 448 | 
             
              }
         | 
| 455 449 | 
             
            }
         | 
| 456 450 |  | 
| 451 | 
            +
            class StreamMessage {
         | 
| 452 | 
            +
              constructor(html) {
         | 
| 453 | 
            +
                this.templateElement = document.createElement("template");
         | 
| 454 | 
            +
                this.templateElement.innerHTML = html;
         | 
| 455 | 
            +
              }
         | 
| 456 | 
            +
              static wrap(message) {
         | 
| 457 | 
            +
                if (typeof message == "string") {
         | 
| 458 | 
            +
                  return new this(message);
         | 
| 459 | 
            +
                } else {
         | 
| 460 | 
            +
                  return message;
         | 
| 461 | 
            +
                }
         | 
| 462 | 
            +
              }
         | 
| 463 | 
            +
              get fragment() {
         | 
| 464 | 
            +
                const fragment = document.createDocumentFragment();
         | 
| 465 | 
            +
                for (const element of this.foreignElements) {
         | 
| 466 | 
            +
                  fragment.appendChild(document.importNode(element, true));
         | 
| 467 | 
            +
                }
         | 
| 468 | 
            +
                return fragment;
         | 
| 469 | 
            +
              }
         | 
| 470 | 
            +
              get foreignElements() {
         | 
| 471 | 
            +
                return this.templateChildren.reduce(((streamElements, child) => {
         | 
| 472 | 
            +
                  if (child.tagName.toLowerCase() == "turbo-stream") {
         | 
| 473 | 
            +
                    return [ ...streamElements, child ];
         | 
| 474 | 
            +
                  } else {
         | 
| 475 | 
            +
                    return streamElements;
         | 
| 476 | 
            +
                  }
         | 
| 477 | 
            +
                }), []);
         | 
| 478 | 
            +
              }
         | 
| 479 | 
            +
              get templateChildren() {
         | 
| 480 | 
            +
                return Array.from(this.templateElement.content.children);
         | 
| 481 | 
            +
              }
         | 
| 482 | 
            +
            }
         | 
| 483 | 
            +
             | 
| 484 | 
            +
            StreamMessage.contentType = "text/vnd.turbo-stream.html";
         | 
| 485 | 
            +
             | 
| 457 486 | 
             
            var FormSubmissionState;
         | 
| 458 487 |  | 
| 459 488 | 
             
            (function(FormSubmissionState) {
         | 
| @@ -465,14 +494,35 @@ var FormSubmissionState; | |
| 465 494 | 
             
              FormSubmissionState[FormSubmissionState["stopped"] = 5] = "stopped";
         | 
| 466 495 | 
             
            })(FormSubmissionState || (FormSubmissionState = {}));
         | 
| 467 496 |  | 
| 497 | 
            +
            var FormEnctype;
         | 
| 498 | 
            +
             | 
| 499 | 
            +
            (function(FormEnctype) {
         | 
| 500 | 
            +
              FormEnctype["urlEncoded"] = "application/x-www-form-urlencoded";
         | 
| 501 | 
            +
              FormEnctype["multipart"] = "multipart/form-data";
         | 
| 502 | 
            +
              FormEnctype["plain"] = "text/plain";
         | 
| 503 | 
            +
            })(FormEnctype || (FormEnctype = {}));
         | 
| 504 | 
            +
             | 
| 505 | 
            +
            function formEnctypeFromString(encoding) {
         | 
| 506 | 
            +
              switch (encoding.toLowerCase()) {
         | 
| 507 | 
            +
               case FormEnctype.multipart:
         | 
| 508 | 
            +
                return FormEnctype.multipart;
         | 
| 509 | 
            +
             | 
| 510 | 
            +
               case FormEnctype.plain:
         | 
| 511 | 
            +
                return FormEnctype.plain;
         | 
| 512 | 
            +
             | 
| 513 | 
            +
               default:
         | 
| 514 | 
            +
                return FormEnctype.urlEncoded;
         | 
| 515 | 
            +
              }
         | 
| 516 | 
            +
            }
         | 
| 517 | 
            +
             | 
| 468 518 | 
             
            class FormSubmission {
         | 
| 469 519 | 
             
              constructor(delegate, formElement, submitter, mustRedirect = false) {
         | 
| 470 520 | 
             
                this.state = FormSubmissionState.initialized;
         | 
| 471 521 | 
             
                this.delegate = delegate;
         | 
| 472 522 | 
             
                this.formElement = formElement;
         | 
| 473 | 
            -
                this.formData = buildFormData(formElement, submitter);
         | 
| 474 523 | 
             
                this.submitter = submitter;
         | 
| 475 | 
            -
                this. | 
| 524 | 
            +
                this.formData = buildFormData(formElement, submitter);
         | 
| 525 | 
            +
                this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body);
         | 
| 476 526 | 
             
                this.mustRedirect = mustRedirect;
         | 
| 477 527 | 
             
              }
         | 
| 478 528 | 
             
              get method() {
         | 
| @@ -485,7 +535,21 @@ class FormSubmission { | |
| 485 535 | 
             
                return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formaction")) || this.formElement.action;
         | 
| 486 536 | 
             
              }
         | 
| 487 537 | 
             
              get location() {
         | 
| 488 | 
            -
                return  | 
| 538 | 
            +
                return expandURL(this.action);
         | 
| 539 | 
            +
              }
         | 
| 540 | 
            +
              get body() {
         | 
| 541 | 
            +
                if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
         | 
| 542 | 
            +
                  return new URLSearchParams(this.stringFormData);
         | 
| 543 | 
            +
                } else {
         | 
| 544 | 
            +
                  return this.formData;
         | 
| 545 | 
            +
                }
         | 
| 546 | 
            +
              }
         | 
| 547 | 
            +
              get enctype() {
         | 
| 548 | 
            +
                var _a;
         | 
| 549 | 
            +
                return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype);
         | 
| 550 | 
            +
              }
         | 
| 551 | 
            +
              get stringFormData() {
         | 
| 552 | 
            +
                return [ ...this.formData ].reduce(((entries, [name, value]) => entries.concat(typeof value == "string" ? [ [ name, value ] ] : [])), []);
         | 
| 489 553 | 
             
              }
         | 
| 490 554 | 
             
              async start() {
         | 
| 491 555 | 
             
                const {initialized: initialized, requesting: requesting} = FormSubmissionState;
         | 
| @@ -502,15 +566,14 @@ class FormSubmission { | |
| 502 566 | 
             
                  return true;
         | 
| 503 567 | 
             
                }
         | 
| 504 568 | 
             
              }
         | 
| 505 | 
            -
               | 
| 506 | 
            -
                 | 
| 507 | 
            -
                if (this.method != FetchMethod.get) {
         | 
| 569 | 
            +
              prepareHeadersForRequest(headers, request) {
         | 
| 570 | 
            +
                if (!request.isIdempotent) {
         | 
| 508 571 | 
             
                  const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token");
         | 
| 509 572 | 
             
                  if (token) {
         | 
| 510 573 | 
             
                    headers["X-CSRF-Token"] = token;
         | 
| 511 574 | 
             
                  }
         | 
| 575 | 
            +
                  headers["Accept"] = [ StreamMessage.contentType, headers["Accept"] ].join(", ");
         | 
| 512 576 | 
             
                }
         | 
| 513 | 
            -
                return headers;
         | 
| 514 577 | 
             
              }
         | 
| 515 578 | 
             
              requestStarted(request) {
         | 
| 516 579 | 
             
                this.state = FormSubmissionState.waiting;
         | 
| @@ -602,6 +665,37 @@ function responseSucceededWithoutRedirect(response) { | |
| 602 665 | 
             
              return response.statusCode == 200 && !response.redirected;
         | 
| 603 666 | 
             
            }
         | 
| 604 667 |  | 
| 668 | 
            +
            class Snapshot {
         | 
| 669 | 
            +
              constructor(element) {
         | 
| 670 | 
            +
                this.element = element;
         | 
| 671 | 
            +
              }
         | 
| 672 | 
            +
              get children() {
         | 
| 673 | 
            +
                return [ ...this.element.children ];
         | 
| 674 | 
            +
              }
         | 
| 675 | 
            +
              hasAnchor(anchor) {
         | 
| 676 | 
            +
                return this.getElementForAnchor(anchor) != null;
         | 
| 677 | 
            +
              }
         | 
| 678 | 
            +
              getElementForAnchor(anchor) {
         | 
| 679 | 
            +
                try {
         | 
| 680 | 
            +
                  return this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`);
         | 
| 681 | 
            +
                } catch (_a) {
         | 
| 682 | 
            +
                  return null;
         | 
| 683 | 
            +
                }
         | 
| 684 | 
            +
              }
         | 
| 685 | 
            +
              get firstAutofocusableElement() {
         | 
| 686 | 
            +
                return this.element.querySelector("[autofocus]");
         | 
| 687 | 
            +
              }
         | 
| 688 | 
            +
              get permanentElements() {
         | 
| 689 | 
            +
                return [ ...this.element.querySelectorAll("[id][data-turbo-permanent]") ];
         | 
| 690 | 
            +
              }
         | 
| 691 | 
            +
              getPermanentElementById(id) {
         | 
| 692 | 
            +
                return this.element.querySelector(`#${id}[data-turbo-permanent]`);
         | 
| 693 | 
            +
              }
         | 
| 694 | 
            +
              getPermanentElementsPresentInSnapshot(snapshot) {
         | 
| 695 | 
            +
                return this.permanentElements.filter((({id: id}) => snapshot.getPermanentElementById(id)));
         | 
| 696 | 
            +
              }
         | 
| 697 | 
            +
            }
         | 
| 698 | 
            +
             | 
| 605 699 | 
             
            class FormInterceptor {
         | 
| 606 700 | 
             
              constructor(delegate, element) {
         | 
| 607 701 | 
             
                this.submitBubbled = event => {
         | 
| @@ -626,6 +720,82 @@ class FormInterceptor { | |
| 626 720 | 
             
              }
         | 
| 627 721 | 
             
            }
         | 
| 628 722 |  | 
| 723 | 
            +
            class View {
         | 
| 724 | 
            +
              constructor(delegate, element) {
         | 
| 725 | 
            +
                this.delegate = delegate;
         | 
| 726 | 
            +
                this.element = element;
         | 
| 727 | 
            +
              }
         | 
| 728 | 
            +
              scrollToAnchor(anchor) {
         | 
| 729 | 
            +
                const element = this.snapshot.getElementForAnchor(anchor);
         | 
| 730 | 
            +
                if (element) {
         | 
| 731 | 
            +
                  this.scrollToElement(element);
         | 
| 732 | 
            +
                } else {
         | 
| 733 | 
            +
                  this.scrollToPosition({
         | 
| 734 | 
            +
                    x: 0,
         | 
| 735 | 
            +
                    y: 0
         | 
| 736 | 
            +
                  });
         | 
| 737 | 
            +
                }
         | 
| 738 | 
            +
              }
         | 
| 739 | 
            +
              scrollToElement(element) {
         | 
| 740 | 
            +
                element.scrollIntoView();
         | 
| 741 | 
            +
              }
         | 
| 742 | 
            +
              scrollToPosition({x: x, y: y}) {
         | 
| 743 | 
            +
                this.scrollRoot.scrollTo(x, y);
         | 
| 744 | 
            +
              }
         | 
| 745 | 
            +
              get scrollRoot() {
         | 
| 746 | 
            +
                return window;
         | 
| 747 | 
            +
              }
         | 
| 748 | 
            +
              async render(renderer) {
         | 
| 749 | 
            +
                if (this.renderer) {
         | 
| 750 | 
            +
                  throw new Error("rendering is already in progress");
         | 
| 751 | 
            +
                }
         | 
| 752 | 
            +
                const {isPreview: isPreview, shouldRender: shouldRender, newSnapshot: snapshot} = renderer;
         | 
| 753 | 
            +
                if (shouldRender) {
         | 
| 754 | 
            +
                  try {
         | 
| 755 | 
            +
                    this.renderer = renderer;
         | 
| 756 | 
            +
                    this.prepareToRenderSnapshot(renderer);
         | 
| 757 | 
            +
                    this.delegate.viewWillRenderSnapshot(snapshot, isPreview);
         | 
| 758 | 
            +
                    await this.renderSnapshot(renderer);
         | 
| 759 | 
            +
                    this.delegate.viewRenderedSnapshot(snapshot, isPreview);
         | 
| 760 | 
            +
                    this.finishRenderingSnapshot(renderer);
         | 
| 761 | 
            +
                  } finally {
         | 
| 762 | 
            +
                    delete this.renderer;
         | 
| 763 | 
            +
                  }
         | 
| 764 | 
            +
                } else {
         | 
| 765 | 
            +
                  this.invalidate();
         | 
| 766 | 
            +
                }
         | 
| 767 | 
            +
              }
         | 
| 768 | 
            +
              invalidate() {
         | 
| 769 | 
            +
                this.delegate.viewInvalidated();
         | 
| 770 | 
            +
              }
         | 
| 771 | 
            +
              prepareToRenderSnapshot(renderer) {
         | 
| 772 | 
            +
                this.markAsPreview(renderer.isPreview);
         | 
| 773 | 
            +
                renderer.prepareToRender();
         | 
| 774 | 
            +
              }
         | 
| 775 | 
            +
              markAsPreview(isPreview) {
         | 
| 776 | 
            +
                if (isPreview) {
         | 
| 777 | 
            +
                  this.element.setAttribute("data-turbo-preview", "");
         | 
| 778 | 
            +
                } else {
         | 
| 779 | 
            +
                  this.element.removeAttribute("data-turbo-preview");
         | 
| 780 | 
            +
                }
         | 
| 781 | 
            +
              }
         | 
| 782 | 
            +
              async renderSnapshot(renderer) {
         | 
| 783 | 
            +
                await renderer.render();
         | 
| 784 | 
            +
              }
         | 
| 785 | 
            +
              finishRenderingSnapshot(renderer) {
         | 
| 786 | 
            +
                renderer.finishRendering();
         | 
| 787 | 
            +
              }
         | 
| 788 | 
            +
            }
         | 
| 789 | 
            +
             | 
| 790 | 
            +
            class FrameView extends View {
         | 
| 791 | 
            +
              invalidate() {
         | 
| 792 | 
            +
                this.element.innerHTML = "";
         | 
| 793 | 
            +
              }
         | 
| 794 | 
            +
              get snapshot() {
         | 
| 795 | 
            +
                return new Snapshot(this.element);
         | 
| 796 | 
            +
              }
         | 
| 797 | 
            +
            }
         | 
| 798 | 
            +
             | 
| 629 799 | 
             
            class LinkInterceptor {
         | 
| 630 800 | 
             
              constructor(delegate, element) {
         | 
| 631 801 | 
             
                this.clickBubbled = event => {
         | 
| @@ -667,10 +837,159 @@ class LinkInterceptor { | |
| 667 837 | 
             
              }
         | 
| 668 838 | 
             
            }
         | 
| 669 839 |  | 
| 840 | 
            +
            class Renderer {
         | 
| 841 | 
            +
              constructor(currentSnapshot, newSnapshot, isPreview) {
         | 
| 842 | 
            +
                this.currentSnapshot = currentSnapshot;
         | 
| 843 | 
            +
                this.newSnapshot = newSnapshot;
         | 
| 844 | 
            +
                this.isPreview = isPreview;
         | 
| 845 | 
            +
                this.promise = new Promise(((resolve, reject) => this.resolvingFunctions = {
         | 
| 846 | 
            +
                  resolve: resolve,
         | 
| 847 | 
            +
                  reject: reject
         | 
| 848 | 
            +
                }));
         | 
| 849 | 
            +
              }
         | 
| 850 | 
            +
              get shouldRender() {
         | 
| 851 | 
            +
                return true;
         | 
| 852 | 
            +
              }
         | 
| 853 | 
            +
              prepareToRender() {
         | 
| 854 | 
            +
                return;
         | 
| 855 | 
            +
              }
         | 
| 856 | 
            +
              finishRendering() {
         | 
| 857 | 
            +
                if (this.resolvingFunctions) {
         | 
| 858 | 
            +
                  this.resolvingFunctions.resolve();
         | 
| 859 | 
            +
                  delete this.resolvingFunctions;
         | 
| 860 | 
            +
                }
         | 
| 861 | 
            +
              }
         | 
| 862 | 
            +
              createScriptElement(element) {
         | 
| 863 | 
            +
                if (element.getAttribute("data-turbo-eval") == "false") {
         | 
| 864 | 
            +
                  return element;
         | 
| 865 | 
            +
                } else {
         | 
| 866 | 
            +
                  const createdScriptElement = document.createElement("script");
         | 
| 867 | 
            +
                  createdScriptElement.textContent = element.textContent;
         | 
| 868 | 
            +
                  createdScriptElement.async = false;
         | 
| 869 | 
            +
                  copyElementAttributes(createdScriptElement, element);
         | 
| 870 | 
            +
                  return createdScriptElement;
         | 
| 871 | 
            +
                }
         | 
| 872 | 
            +
              }
         | 
| 873 | 
            +
              preservingPermanentElements(callback) {
         | 
| 874 | 
            +
                const placeholders = relocatePermanentElements(this.currentSnapshot, this.newSnapshot);
         | 
| 875 | 
            +
                callback();
         | 
| 876 | 
            +
                replacePlaceholderElementsWithClonedPermanentElements(placeholders);
         | 
| 877 | 
            +
              }
         | 
| 878 | 
            +
              focusFirstAutofocusableElement() {
         | 
| 879 | 
            +
                const element = this.newSnapshot.firstAutofocusableElement;
         | 
| 880 | 
            +
                if (elementIsFocusable(element)) {
         | 
| 881 | 
            +
                  element.focus();
         | 
| 882 | 
            +
                }
         | 
| 883 | 
            +
              }
         | 
| 884 | 
            +
              get currentElement() {
         | 
| 885 | 
            +
                return this.currentSnapshot.element;
         | 
| 886 | 
            +
              }
         | 
| 887 | 
            +
              get newElement() {
         | 
| 888 | 
            +
                return this.newSnapshot.element;
         | 
| 889 | 
            +
              }
         | 
| 890 | 
            +
            }
         | 
| 891 | 
            +
             | 
| 892 | 
            +
            function replaceElementWithElement(fromElement, toElement) {
         | 
| 893 | 
            +
              const parentElement = fromElement.parentElement;
         | 
| 894 | 
            +
              if (parentElement) {
         | 
| 895 | 
            +
                return parentElement.replaceChild(toElement, fromElement);
         | 
| 896 | 
            +
              }
         | 
| 897 | 
            +
            }
         | 
| 898 | 
            +
             | 
| 899 | 
            +
            function copyElementAttributes(destinationElement, sourceElement) {
         | 
| 900 | 
            +
              for (const {name: name, value: value} of [ ...sourceElement.attributes ]) {
         | 
| 901 | 
            +
                destinationElement.setAttribute(name, value);
         | 
| 902 | 
            +
              }
         | 
| 903 | 
            +
            }
         | 
| 904 | 
            +
             | 
| 905 | 
            +
            function createPlaceholderForPermanentElement(permanentElement) {
         | 
| 906 | 
            +
              const element = document.createElement("meta");
         | 
| 907 | 
            +
              element.setAttribute("name", "turbo-permanent-placeholder");
         | 
| 908 | 
            +
              element.setAttribute("content", permanentElement.id);
         | 
| 909 | 
            +
              return {
         | 
| 910 | 
            +
                element: element,
         | 
| 911 | 
            +
                permanentElement: permanentElement
         | 
| 912 | 
            +
              };
         | 
| 913 | 
            +
            }
         | 
| 914 | 
            +
             | 
| 915 | 
            +
            function replacePlaceholderElementsWithClonedPermanentElements(placeholders) {
         | 
| 916 | 
            +
              for (const {element: element, permanentElement: permanentElement} of placeholders) {
         | 
| 917 | 
            +
                const clonedElement = permanentElement.cloneNode(true);
         | 
| 918 | 
            +
                replaceElementWithElement(element, clonedElement);
         | 
| 919 | 
            +
              }
         | 
| 920 | 
            +
            }
         | 
| 921 | 
            +
             | 
| 922 | 
            +
            function relocatePermanentElements(currentSnapshot, newSnapshot) {
         | 
| 923 | 
            +
              return currentSnapshot.getPermanentElementsPresentInSnapshot(newSnapshot).reduce(((placeholders, permanentElement) => {
         | 
| 924 | 
            +
                const newElement = newSnapshot.getPermanentElementById(permanentElement.id);
         | 
| 925 | 
            +
                if (newElement) {
         | 
| 926 | 
            +
                  const placeholder = createPlaceholderForPermanentElement(permanentElement);
         | 
| 927 | 
            +
                  replaceElementWithElement(permanentElement, placeholder.element);
         | 
| 928 | 
            +
                  replaceElementWithElement(newElement, permanentElement);
         | 
| 929 | 
            +
                  return [ ...placeholders, placeholder ];
         | 
| 930 | 
            +
                } else {
         | 
| 931 | 
            +
                  return placeholders;
         | 
| 932 | 
            +
                }
         | 
| 933 | 
            +
              }), []);
         | 
| 934 | 
            +
            }
         | 
| 935 | 
            +
             | 
| 936 | 
            +
            function elementIsFocusable(element) {
         | 
| 937 | 
            +
              return element && typeof element.focus == "function";
         | 
| 938 | 
            +
            }
         | 
| 939 | 
            +
             | 
| 940 | 
            +
            class FrameRenderer extends Renderer {
         | 
| 941 | 
            +
              get shouldRender() {
         | 
| 942 | 
            +
                return true;
         | 
| 943 | 
            +
              }
         | 
| 944 | 
            +
              async render() {
         | 
| 945 | 
            +
                await nextAnimationFrame();
         | 
| 946 | 
            +
                this.preservingPermanentElements((() => {
         | 
| 947 | 
            +
                  this.loadFrameElement();
         | 
| 948 | 
            +
                }));
         | 
| 949 | 
            +
                this.scrollFrameIntoView();
         | 
| 950 | 
            +
                await nextAnimationFrame();
         | 
| 951 | 
            +
                this.focusFirstAutofocusableElement();
         | 
| 952 | 
            +
              }
         | 
| 953 | 
            +
              loadFrameElement() {
         | 
| 954 | 
            +
                var _a;
         | 
| 955 | 
            +
                const destinationRange = document.createRange();
         | 
| 956 | 
            +
                destinationRange.selectNodeContents(this.currentElement);
         | 
| 957 | 
            +
                destinationRange.deleteContents();
         | 
| 958 | 
            +
                const frameElement = this.newElement;
         | 
| 959 | 
            +
                const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
         | 
| 960 | 
            +
                if (sourceRange) {
         | 
| 961 | 
            +
                  sourceRange.selectNodeContents(frameElement);
         | 
| 962 | 
            +
                  this.currentElement.appendChild(sourceRange.extractContents());
         | 
| 963 | 
            +
                }
         | 
| 964 | 
            +
              }
         | 
| 965 | 
            +
              scrollFrameIntoView() {
         | 
| 966 | 
            +
                if (this.currentElement.autoscroll || this.newElement.autoscroll) {
         | 
| 967 | 
            +
                  const element = this.currentElement.firstElementChild;
         | 
| 968 | 
            +
                  const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
         | 
| 969 | 
            +
                  if (element) {
         | 
| 970 | 
            +
                    element.scrollIntoView({
         | 
| 971 | 
            +
                      block: block
         | 
| 972 | 
            +
                    });
         | 
| 973 | 
            +
                    return true;
         | 
| 974 | 
            +
                  }
         | 
| 975 | 
            +
                }
         | 
| 976 | 
            +
                return false;
         | 
| 977 | 
            +
              }
         | 
| 978 | 
            +
            }
         | 
| 979 | 
            +
             | 
| 980 | 
            +
            function readScrollLogicalPosition(value, defaultValue) {
         | 
| 981 | 
            +
              if (value == "end" || value == "start" || value == "center" || value == "nearest") {
         | 
| 982 | 
            +
                return value;
         | 
| 983 | 
            +
              } else {
         | 
| 984 | 
            +
                return defaultValue;
         | 
| 985 | 
            +
              }
         | 
| 986 | 
            +
            }
         | 
| 987 | 
            +
             | 
| 670 988 | 
             
            class FrameController {
         | 
| 671 989 | 
             
              constructor(element) {
         | 
| 672 990 | 
             
                this.resolveVisitPromise = () => {};
         | 
| 673 991 | 
             
                this.element = element;
         | 
| 992 | 
            +
                this.view = new FrameView(this, this.element);
         | 
| 674 993 | 
             
                this.appearanceObserver = new AppearanceObserver(this, this.element);
         | 
| 675 994 | 
             
                this.linkInterceptor = new LinkInterceptor(this, this.element);
         | 
| 676 995 | 
             
                this.formInterceptor = new FormInterceptor(this, this.element);
         | 
| @@ -713,14 +1032,17 @@ class FrameController { | |
| 713 1032 | 
             
                }
         | 
| 714 1033 | 
             
              }
         | 
| 715 1034 | 
             
              async loadResponse(response) {
         | 
| 716 | 
            -
                 | 
| 717 | 
            -
             | 
| 718 | 
            -
                   | 
| 719 | 
            -
             | 
| 720 | 
            -
             | 
| 721 | 
            -
             | 
| 722 | 
            -
             | 
| 723 | 
            -
                   | 
| 1035 | 
            +
                try {
         | 
| 1036 | 
            +
                  const html = await response.responseHTML;
         | 
| 1037 | 
            +
                  if (html) {
         | 
| 1038 | 
            +
                    const {body: body} = parseHTMLDocument(html);
         | 
| 1039 | 
            +
                    const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
         | 
| 1040 | 
            +
                    const renderer = new FrameRenderer(this.view.snapshot, snapshot, false);
         | 
| 1041 | 
            +
                    await this.view.render(renderer);
         | 
| 1042 | 
            +
                  }
         | 
| 1043 | 
            +
                } catch (error) {
         | 
| 1044 | 
            +
                  console.error(error);
         | 
| 1045 | 
            +
                  this.view.invalidate();
         | 
| 724 1046 | 
             
                }
         | 
| 725 1047 | 
             
              }
         | 
| 726 1048 | 
             
              elementAppearedInViewport(element) {
         | 
| @@ -741,15 +1063,13 @@ class FrameController { | |
| 741 1063 | 
             
                }
         | 
| 742 1064 | 
             
                this.formSubmission = new FormSubmission(this, element, submitter);
         | 
| 743 1065 | 
             
                if (this.formSubmission.fetchRequest.isIdempotent) {
         | 
| 744 | 
            -
                  this.navigateFrame(element, this.formSubmission.fetchRequest.url);
         | 
| 1066 | 
            +
                  this.navigateFrame(element, this.formSubmission.fetchRequest.url.href);
         | 
| 745 1067 | 
             
                } else {
         | 
| 746 1068 | 
             
                  this.formSubmission.start();
         | 
| 747 1069 | 
             
                }
         | 
| 748 1070 | 
             
              }
         | 
| 749 | 
            -
               | 
| 750 | 
            -
                 | 
| 751 | 
            -
                  "Turbo-Frame": this.id
         | 
| 752 | 
            -
                };
         | 
| 1071 | 
            +
              prepareHeadersForRequest(headers, request) {
         | 
| 1072 | 
            +
                headers["Turbo-Frame"] = this.id;
         | 
| 753 1073 | 
             
              }
         | 
| 754 1074 | 
             
              requestStarted(request) {
         | 
| 755 1075 | 
             
                this.element.setAttribute("busy", "");
         | 
| @@ -782,9 +1102,11 @@ class FrameController { | |
| 782 1102 | 
             
              }
         | 
| 783 1103 | 
             
              formSubmissionErrored(formSubmission, error) {}
         | 
| 784 1104 | 
             
              formSubmissionFinished(formSubmission) {}
         | 
| 1105 | 
            +
              viewWillRenderSnapshot(snapshot, isPreview) {}
         | 
| 1106 | 
            +
              viewRenderedSnapshot(snapshot, isPreview) {}
         | 
| 1107 | 
            +
              viewInvalidated() {}
         | 
| 785 1108 | 
             
              async visit(url) {
         | 
| 786 | 
            -
                const  | 
| 787 | 
            -
                const request = new FetchRequest(this, FetchMethod.get, location);
         | 
| 1109 | 
            +
                const request = new FetchRequest(this, FetchMethod.get, expandURL(url));
         | 
| 788 1110 | 
             
                return new Promise((resolve => {
         | 
| 789 1111 | 
             
                  this.resolveVisitPromise = () => {
         | 
| 790 1112 | 
             
                    this.resolveVisitPromise = () => {};
         | 
| @@ -799,7 +1121,7 @@ class FrameController { | |
| 799 1121 | 
             
              }
         | 
| 800 1122 | 
             
              findFrameElement(element) {
         | 
| 801 1123 | 
             
                var _a;
         | 
| 802 | 
            -
                const id = element.getAttribute("data-turbo-frame");
         | 
| 1124 | 
            +
                const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
         | 
| 803 1125 | 
             
                return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
         | 
| 804 1126 | 
             
              }
         | 
| 805 1127 | 
             
              async extractForeignFrameElement(container) {
         | 
| @@ -815,38 +1137,6 @@ class FrameController { | |
| 815 1137 | 
             
                console.error(`Response has no matching <turbo-frame id="${id}"> element`);
         | 
| 816 1138 | 
             
                return new FrameElement;
         | 
| 817 1139 | 
             
              }
         | 
| 818 | 
            -
              loadFrameElement(frameElement) {
         | 
| 819 | 
            -
                var _a;
         | 
| 820 | 
            -
                const destinationRange = document.createRange();
         | 
| 821 | 
            -
                destinationRange.selectNodeContents(this.element);
         | 
| 822 | 
            -
                destinationRange.deleteContents();
         | 
| 823 | 
            -
                const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
         | 
| 824 | 
            -
                if (sourceRange) {
         | 
| 825 | 
            -
                  sourceRange.selectNodeContents(frameElement);
         | 
| 826 | 
            -
                  this.element.appendChild(sourceRange.extractContents());
         | 
| 827 | 
            -
                }
         | 
| 828 | 
            -
              }
         | 
| 829 | 
            -
              focusFirstAutofocusableElement() {
         | 
| 830 | 
            -
                const element = this.firstAutofocusableElement;
         | 
| 831 | 
            -
                if (element) {
         | 
| 832 | 
            -
                  element.focus();
         | 
| 833 | 
            -
                  return true;
         | 
| 834 | 
            -
                }
         | 
| 835 | 
            -
                return false;
         | 
| 836 | 
            -
              }
         | 
| 837 | 
            -
              scrollFrameIntoView(frame) {
         | 
| 838 | 
            -
                if (this.element.autoscroll || frame.autoscroll) {
         | 
| 839 | 
            -
                  const element = this.element.firstElementChild;
         | 
| 840 | 
            -
                  const block = readScrollLogicalPosition(this.element.getAttribute("data-autoscroll-block"), "end");
         | 
| 841 | 
            -
                  if (element) {
         | 
| 842 | 
            -
                    element.scrollIntoView({
         | 
| 843 | 
            -
                      block: block
         | 
| 844 | 
            -
                    });
         | 
| 845 | 
            -
                    return true;
         | 
| 846 | 
            -
                  }
         | 
| 847 | 
            -
                }
         | 
| 848 | 
            -
                return false;
         | 
| 849 | 
            -
              }
         | 
| 850 1140 | 
             
              shouldInterceptNavigation(element) {
         | 
| 851 1141 | 
             
                const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
         | 
| 852 1142 | 
             
                if (!this.enabled || id == "_top") {
         | 
| @@ -860,10 +1150,6 @@ class FrameController { | |
| 860 1150 | 
             
                }
         | 
| 861 1151 | 
             
                return true;
         | 
| 862 1152 | 
             
              }
         | 
| 863 | 
            -
              get firstAutofocusableElement() {
         | 
| 864 | 
            -
                const element = this.element.querySelector("[autofocus]");
         | 
| 865 | 
            -
                return element instanceof HTMLElement ? element : null;
         | 
| 866 | 
            -
              }
         | 
| 867 1153 | 
             
              get id() {
         | 
| 868 1154 | 
             
                return this.element.id;
         | 
| 869 1155 | 
             
              }
         | 
| @@ -893,21 +1179,6 @@ function getFrameElementById(id) { | |
| 893 1179 | 
             
              }
         | 
| 894 1180 | 
             
            }
         | 
| 895 1181 |  | 
| 896 | 
            -
            function readScrollLogicalPosition(value, defaultValue) {
         | 
| 897 | 
            -
              if (value == "end" || value == "start" || value == "center" || value == "nearest") {
         | 
| 898 | 
            -
                return value;
         | 
| 899 | 
            -
              } else {
         | 
| 900 | 
            -
                return defaultValue;
         | 
| 901 | 
            -
              }
         | 
| 902 | 
            -
            }
         | 
| 903 | 
            -
             | 
| 904 | 
            -
            function fragmentFromHTML(html) {
         | 
| 905 | 
            -
              if (html) {
         | 
| 906 | 
            -
                const foreignDocument = document.implementation.createHTMLDocument();
         | 
| 907 | 
            -
                return foreignDocument.createRange().createContextualFragment(html);
         | 
| 908 | 
            -
              }
         | 
| 909 | 
            -
            }
         | 
| 910 | 
            -
             | 
| 911 1182 | 
             
            function activateElement(element) {
         | 
| 912 1183 | 
             
              if (element && element.ownerDocument !== document) {
         | 
| 913 1184 | 
             
                element = document.importNode(element, true);
         | 
| @@ -1138,9 +1409,10 @@ class ProgressBar { | |
| 1138 1409 |  | 
| 1139 1410 | 
             
            ProgressBar.animationDuration = 300;
         | 
| 1140 1411 |  | 
| 1141 | 
            -
            class  | 
| 1142 | 
            -
              constructor( | 
| 1143 | 
            -
                 | 
| 1412 | 
            +
            class HeadSnapshot extends Snapshot {
         | 
| 1413 | 
            +
              constructor() {
         | 
| 1414 | 
            +
                super(...arguments);
         | 
| 1415 | 
            +
                this.detailsByOuterHTML = this.children.reduce(((result, element) => {
         | 
| 1144 1416 | 
             
                  const {outerHTML: outerHTML} = element;
         | 
| 1145 1417 | 
             
                  const details = outerHTML in result ? result[outerHTML] : {
         | 
| 1146 1418 | 
             
                    type: elementType(element),
         | 
| @@ -1154,23 +1426,19 @@ class HeadDetails { | |
| 1154 1426 | 
             
                  });
         | 
| 1155 1427 | 
             
                }), {});
         | 
| 1156 1428 | 
             
              }
         | 
| 1157 | 
            -
               | 
| 1158 | 
            -
                const children = headElement ? [ ...headElement.children ] : [];
         | 
| 1159 | 
            -
                return new this(children);
         | 
| 1160 | 
            -
              }
         | 
| 1161 | 
            -
              getTrackedElementSignature() {
         | 
| 1429 | 
            +
              get trackedElementSignature() {
         | 
| 1162 1430 | 
             
                return Object.keys(this.detailsByOuterHTML).filter((outerHTML => this.detailsByOuterHTML[outerHTML].tracked)).join("");
         | 
| 1163 1431 | 
             
              }
         | 
| 1164 | 
            -
               | 
| 1165 | 
            -
                return this. | 
| 1432 | 
            +
              getScriptElementsNotInSnapshot(snapshot) {
         | 
| 1433 | 
            +
                return this.getElementsMatchingTypeNotInSnapshot("script", snapshot);
         | 
| 1166 1434 | 
             
              }
         | 
| 1167 | 
            -
               | 
| 1168 | 
            -
                return this. | 
| 1435 | 
            +
              getStylesheetElementsNotInSnapshot(snapshot) {
         | 
| 1436 | 
            +
                return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot);
         | 
| 1169 1437 | 
             
              }
         | 
| 1170 | 
            -
               | 
| 1171 | 
            -
                return Object.keys(this.detailsByOuterHTML).filter((outerHTML => !(outerHTML in  | 
| 1438 | 
            +
              getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
         | 
| 1439 | 
            +
                return Object.keys(this.detailsByOuterHTML).filter((outerHTML => !(outerHTML in snapshot.detailsByOuterHTML))).map((outerHTML => this.detailsByOuterHTML[outerHTML])).filter((({type: type}) => type == matchedType)).map((({elements: [element]}) => element));
         | 
| 1172 1440 | 
             
              }
         | 
| 1173 | 
            -
               | 
| 1441 | 
            +
              get provisionalElements() {
         | 
| 1174 1442 | 
             
                return Object.keys(this.detailsByOuterHTML).reduce(((result, outerHTML) => {
         | 
| 1175 1443 | 
             
                  const {type: type, tracked: tracked, elements: elements} = this.detailsByOuterHTML[outerHTML];
         | 
| 1176 1444 | 
             
                  if (type == null && !tracked) {
         | 
| @@ -1221,75 +1489,45 @@ function elementIsMetaElementWithName(element, name) { | |
| 1221 1489 | 
             
              return tagName == "meta" && element.getAttribute("name") == name;
         | 
| 1222 1490 | 
             
            }
         | 
| 1223 1491 |  | 
| 1224 | 
            -
            class Snapshot {
         | 
| 1225 | 
            -
              constructor( | 
| 1226 | 
            -
                 | 
| 1227 | 
            -
                this. | 
| 1228 | 
            -
              }
         | 
| 1229 | 
            -
              static wrap(value) {
         | 
| 1230 | 
            -
                if (value instanceof this) {
         | 
| 1231 | 
            -
                  return value;
         | 
| 1232 | 
            -
                } else if (typeof value == "string") {
         | 
| 1233 | 
            -
                  return this.fromHTMLString(value);
         | 
| 1234 | 
            -
                } else {
         | 
| 1235 | 
            -
                  return this.fromHTMLElement(value);
         | 
| 1236 | 
            -
                }
         | 
| 1237 | 
            -
              }
         | 
| 1238 | 
            -
              static fromHTMLString(html) {
         | 
| 1239 | 
            -
                const {documentElement: documentElement} = (new DOMParser).parseFromString(html, "text/html");
         | 
| 1240 | 
            -
                return this.fromHTMLElement(documentElement);
         | 
| 1241 | 
            -
              }
         | 
| 1242 | 
            -
              static fromHTMLElement(htmlElement) {
         | 
| 1243 | 
            -
                const headElement = htmlElement.querySelector("head");
         | 
| 1244 | 
            -
                const bodyElement = htmlElement.querySelector("body") || document.createElement("body");
         | 
| 1245 | 
            -
                const headDetails = HeadDetails.fromHeadElement(headElement);
         | 
| 1246 | 
            -
                return new this(headDetails, bodyElement);
         | 
| 1247 | 
            -
              }
         | 
| 1248 | 
            -
              clone() {
         | 
| 1249 | 
            -
                const {bodyElement: bodyElement} = Snapshot.fromHTMLString(this.bodyElement.outerHTML);
         | 
| 1250 | 
            -
                return new Snapshot(this.headDetails, bodyElement);
         | 
| 1251 | 
            -
              }
         | 
| 1252 | 
            -
              getRootLocation() {
         | 
| 1253 | 
            -
                const root = this.getSetting("root", "/");
         | 
| 1254 | 
            -
                return new Location(root);
         | 
| 1492 | 
            +
            class PageSnapshot extends Snapshot {
         | 
| 1493 | 
            +
              constructor(element, headSnapshot) {
         | 
| 1494 | 
            +
                super(element);
         | 
| 1495 | 
            +
                this.headSnapshot = headSnapshot;
         | 
| 1255 1496 | 
             
              }
         | 
| 1256 | 
            -
               | 
| 1257 | 
            -
                return this. | 
| 1497 | 
            +
              static fromHTMLString(html = "") {
         | 
| 1498 | 
            +
                return this.fromDocument(parseHTMLDocument(html));
         | 
| 1258 1499 | 
             
              }
         | 
| 1259 | 
            -
               | 
| 1260 | 
            -
                 | 
| 1261 | 
            -
                  return this.bodyElement.querySelector(`[id='${anchor}'], a[name='${anchor}']`);
         | 
| 1262 | 
            -
                } catch (_a) {
         | 
| 1263 | 
            -
                  return null;
         | 
| 1264 | 
            -
                }
         | 
| 1500 | 
            +
              static fromElement(element) {
         | 
| 1501 | 
            +
                return this.fromDocument(element.ownerDocument);
         | 
| 1265 1502 | 
             
              }
         | 
| 1266 | 
            -
               | 
| 1267 | 
            -
                return  | 
| 1503 | 
            +
              static fromDocument({head: head, body: body}) {
         | 
| 1504 | 
            +
                return new this(body, new HeadSnapshot(head));
         | 
| 1268 1505 | 
             
              }
         | 
| 1269 | 
            -
               | 
| 1270 | 
            -
                return this. | 
| 1506 | 
            +
              clone() {
         | 
| 1507 | 
            +
                return new PageSnapshot(this.element.cloneNode(true), this.headSnapshot);
         | 
| 1271 1508 | 
             
              }
         | 
| 1272 | 
            -
               | 
| 1273 | 
            -
                return this. | 
| 1509 | 
            +
              get headElement() {
         | 
| 1510 | 
            +
                return this.headSnapshot.element;
         | 
| 1274 1511 | 
             
              }
         | 
| 1275 | 
            -
               | 
| 1276 | 
            -
                 | 
| 1512 | 
            +
              get rootLocation() {
         | 
| 1513 | 
            +
                var _a;
         | 
| 1514 | 
            +
                const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/";
         | 
| 1515 | 
            +
                return expandURL(root);
         | 
| 1277 1516 | 
             
              }
         | 
| 1278 | 
            -
               | 
| 1279 | 
            -
                return this. | 
| 1517 | 
            +
              get cacheControlValue() {
         | 
| 1518 | 
            +
                return this.getSetting("cache-control");
         | 
| 1280 1519 | 
             
              }
         | 
| 1281 | 
            -
              isPreviewable() {
         | 
| 1282 | 
            -
                return this. | 
| 1520 | 
            +
              get isPreviewable() {
         | 
| 1521 | 
            +
                return this.cacheControlValue != "no-preview";
         | 
| 1283 1522 | 
             
              }
         | 
| 1284 | 
            -
              isCacheable() {
         | 
| 1285 | 
            -
                return this. | 
| 1523 | 
            +
              get isCacheable() {
         | 
| 1524 | 
            +
                return this.cacheControlValue != "no-cache";
         | 
| 1286 1525 | 
             
              }
         | 
| 1287 | 
            -
              isVisitable() {
         | 
| 1526 | 
            +
              get isVisitable() {
         | 
| 1288 1527 | 
             
                return this.getSetting("visit-control") != "reload";
         | 
| 1289 1528 | 
             
              }
         | 
| 1290 | 
            -
              getSetting(name | 
| 1291 | 
            -
                 | 
| 1292 | 
            -
                return value == null ? defaultValue : value;
         | 
| 1529 | 
            +
              getSetting(name) {
         | 
| 1530 | 
            +
                return this.headSnapshot.getMetaValue(`turbo-${name}`);
         | 
| 1293 1531 | 
             
              }
         | 
| 1294 1532 | 
             
            }
         | 
| 1295 1533 |  | 
| @@ -1334,16 +1572,6 @@ class Visit { | |
| 1334 1572 | 
             
                this.scrolled = false;
         | 
| 1335 1573 | 
             
                this.snapshotCached = false;
         | 
| 1336 1574 | 
             
                this.state = VisitState.initialized;
         | 
| 1337 | 
            -
                this.performScroll = () => {
         | 
| 1338 | 
            -
                  if (!this.scrolled) {
         | 
| 1339 | 
            -
                    if (this.action == "restore") {
         | 
| 1340 | 
            -
                      this.scrollToRestoredPosition() || this.scrollToTop();
         | 
| 1341 | 
            -
                    } else {
         | 
| 1342 | 
            -
                      this.scrollToAnchor() || this.scrollToTop();
         | 
| 1343 | 
            -
                    }
         | 
| 1344 | 
            -
                    this.scrolled = true;
         | 
| 1345 | 
            -
                  }
         | 
| 1346 | 
            -
                };
         | 
| 1347 1575 | 
             
                this.delegate = delegate;
         | 
| 1348 1576 | 
             
                this.location = location;
         | 
| 1349 1577 | 
             
                this.restorationIdentifier = restorationIdentifier || uuid();
         | 
| @@ -1398,8 +1626,9 @@ class Visit { | |
| 1398 1626 | 
             
                }
         | 
| 1399 1627 | 
             
              }
         | 
| 1400 1628 | 
             
              changeHistory() {
         | 
| 1629 | 
            +
                var _a;
         | 
| 1401 1630 | 
             
                if (!this.historyChanged) {
         | 
| 1402 | 
            -
                  const actionForHistory = this.location. | 
| 1631 | 
            +
                  const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
         | 
| 1403 1632 | 
             
                  const method = this.getHistoryMethodForAction(actionForHistory);
         | 
| 1404 1633 | 
             
                  this.history.update(method, this.location, this.restorationIdentifier);
         | 
| 1405 1634 | 
             
                  this.historyChanged = true;
         | 
| @@ -1442,18 +1671,14 @@ class Visit { | |
| 1442 1671 | 
             
              loadResponse() {
         | 
| 1443 1672 | 
             
                if (this.response) {
         | 
| 1444 1673 | 
             
                  const {statusCode: statusCode, responseHTML: responseHTML} = this.response;
         | 
| 1445 | 
            -
                  this.render((() => {
         | 
| 1674 | 
            +
                  this.render((async () => {
         | 
| 1446 1675 | 
             
                    this.cacheSnapshot();
         | 
| 1447 1676 | 
             
                    if (isSuccessful(statusCode) && responseHTML != null) {
         | 
| 1448 | 
            -
                      this.view. | 
| 1449 | 
            -
                        snapshot: Snapshot.fromHTMLString(responseHTML)
         | 
| 1450 | 
            -
                      }, this.performScroll);
         | 
| 1677 | 
            +
                      await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML));
         | 
| 1451 1678 | 
             
                      this.adapter.visitRendered(this);
         | 
| 1452 1679 | 
             
                      this.complete();
         | 
| 1453 1680 | 
             
                    } else {
         | 
| 1454 | 
            -
                      this.view. | 
| 1455 | 
            -
                        error: responseHTML
         | 
| 1456 | 
            -
                      }, this.performScroll);
         | 
| 1681 | 
            +
                      await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML));
         | 
| 1457 1682 | 
             
                      this.adapter.visitRendered(this);
         | 
| 1458 1683 | 
             
                      this.fail();
         | 
| 1459 1684 | 
             
                    }
         | 
| @@ -1462,15 +1687,15 @@ class Visit { | |
| 1462 1687 | 
             
              }
         | 
| 1463 1688 | 
             
              getCachedSnapshot() {
         | 
| 1464 1689 | 
             
                const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot();
         | 
| 1465 | 
            -
                if (snapshot && (!this.location | 
| 1466 | 
            -
                  if (this.action == "restore" || snapshot.isPreviewable | 
| 1690 | 
            +
                if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) {
         | 
| 1691 | 
            +
                  if (this.action == "restore" || snapshot.isPreviewable) {
         | 
| 1467 1692 | 
             
                    return snapshot;
         | 
| 1468 1693 | 
             
                  }
         | 
| 1469 1694 | 
             
                }
         | 
| 1470 1695 | 
             
              }
         | 
| 1471 1696 | 
             
              getPreloadedSnapshot() {
         | 
| 1472 1697 | 
             
                if (this.snapshotHTML) {
         | 
| 1473 | 
            -
                  return  | 
| 1698 | 
            +
                  return PageSnapshot.fromHTMLString(this.snapshotHTML);
         | 
| 1474 1699 | 
             
                }
         | 
| 1475 1700 | 
             
              }
         | 
| 1476 1701 | 
             
              hasCachedSnapshot() {
         | 
| @@ -1480,12 +1705,9 @@ class Visit { | |
| 1480 1705 | 
             
                const snapshot = this.getCachedSnapshot();
         | 
| 1481 1706 | 
             
                if (snapshot) {
         | 
| 1482 1707 | 
             
                  const isPreview = this.shouldIssueRequest();
         | 
| 1483 | 
            -
                  this.render((() => {
         | 
| 1708 | 
            +
                  this.render((async () => {
         | 
| 1484 1709 | 
             
                    this.cacheSnapshot();
         | 
| 1485 | 
            -
                    this.view. | 
| 1486 | 
            -
                      snapshot: snapshot,
         | 
| 1487 | 
            -
                      isPreview: isPreview
         | 
| 1488 | 
            -
                    }, this.performScroll);
         | 
| 1710 | 
            +
                    await this.view.renderPage(snapshot);
         | 
| 1489 1711 | 
             
                    this.adapter.visitRendered(this);
         | 
| 1490 1712 | 
             
                    if (!isPreview) {
         | 
| 1491 1713 | 
             
                      this.complete();
         | 
| @@ -1539,6 +1761,16 @@ class Visit { | |
| 1539 1761 | 
             
              requestFinished() {
         | 
| 1540 1762 | 
             
                this.finishRequest();
         | 
| 1541 1763 | 
             
              }
         | 
| 1764 | 
            +
              performScroll() {
         | 
| 1765 | 
            +
                if (!this.scrolled) {
         | 
| 1766 | 
            +
                  if (this.action == "restore") {
         | 
| 1767 | 
            +
                    this.scrollToRestoredPosition() || this.scrollToTop();
         | 
| 1768 | 
            +
                  } else {
         | 
| 1769 | 
            +
                    this.scrollToAnchor() || this.scrollToTop();
         | 
| 1770 | 
            +
                  }
         | 
| 1771 | 
            +
                  this.scrolled = true;
         | 
| 1772 | 
            +
                }
         | 
| 1773 | 
            +
              }
         | 
| 1542 1774 | 
             
              scrollToRestoredPosition() {
         | 
| 1543 1775 | 
             
                const {scrollPosition: scrollPosition} = this.restorationData;
         | 
| 1544 1776 | 
             
                if (scrollPosition) {
         | 
| @@ -1547,8 +1779,8 @@ class Visit { | |
| 1547 1779 | 
             
                }
         | 
| 1548 1780 | 
             
              }
         | 
| 1549 1781 | 
             
              scrollToAnchor() {
         | 
| 1550 | 
            -
                if (this.location | 
| 1551 | 
            -
                  this.view.scrollToAnchor(this.location | 
| 1782 | 
            +
                if (getAnchor(this.location) != null) {
         | 
| 1783 | 
            +
                  this.view.scrollToAnchor(getAnchor(this.location));
         | 
| 1552 1784 | 
             
                  return true;
         | 
| 1553 1785 | 
             
                }
         | 
| 1554 1786 | 
             
              }
         | 
| @@ -1586,12 +1818,14 @@ class Visit { | |
| 1586 1818 | 
             
                  this.snapshotCached = true;
         | 
| 1587 1819 | 
             
                }
         | 
| 1588 1820 | 
             
              }
         | 
| 1589 | 
            -
              render(callback) {
         | 
| 1821 | 
            +
              async render(callback) {
         | 
| 1590 1822 | 
             
                this.cancelRender();
         | 
| 1591 | 
            -
                 | 
| 1592 | 
            -
                   | 
| 1593 | 
            -
                  callback.call(this);
         | 
| 1823 | 
            +
                await new Promise((resolve => {
         | 
| 1824 | 
            +
                  this.frame = requestAnimationFrame((() => resolve()));
         | 
| 1594 1825 | 
             
                }));
         | 
| 1826 | 
            +
                callback();
         | 
| 1827 | 
            +
                delete this.frame;
         | 
| 1828 | 
            +
                this.performScroll();
         | 
| 1595 1829 | 
             
              }
         | 
| 1596 1830 | 
             
              cancelRender() {
         | 
| 1597 1831 | 
             
                if (this.frame) {
         | 
| @@ -1766,11 +2000,10 @@ class History { | |
| 1766 2000 | 
             
                  if (this.shouldHandlePopState()) {
         | 
| 1767 2001 | 
             
                    const {turbo: turbo} = event.state || {};
         | 
| 1768 2002 | 
             
                    if (turbo) {
         | 
| 1769 | 
            -
                       | 
| 1770 | 
            -
                      this.location = location;
         | 
| 2003 | 
            +
                      this.location = new URL(window.location.href);
         | 
| 1771 2004 | 
             
                      const {restorationIdentifier: restorationIdentifier} = turbo;
         | 
| 1772 2005 | 
             
                      this.restorationIdentifier = restorationIdentifier;
         | 
| 1773 | 
            -
                      this.delegate.historyPoppedToLocationWithRestorationIdentifier(location, restorationIdentifier);
         | 
| 2006 | 
            +
                      this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier);
         | 
| 1774 2007 | 
             
                    }
         | 
| 1775 2008 | 
             
                  }
         | 
| 1776 2009 | 
             
                };
         | 
| @@ -1785,7 +2018,7 @@ class History { | |
| 1785 2018 | 
             
                  addEventListener("popstate", this.onPopState, false);
         | 
| 1786 2019 | 
             
                  addEventListener("load", this.onPageLoad, false);
         | 
| 1787 2020 | 
             
                  this.started = true;
         | 
| 1788 | 
            -
                  this.replace( | 
| 2021 | 
            +
                  this.replace(new URL(window.location.href));
         | 
| 1789 2022 | 
             
                }
         | 
| 1790 2023 | 
             
              }
         | 
| 1791 2024 | 
             
              stop() {
         | 
| @@ -1807,7 +2040,7 @@ class History { | |
| 1807 2040 | 
             
                    restorationIdentifier: restorationIdentifier
         | 
| 1808 2041 | 
             
                  }
         | 
| 1809 2042 | 
             
                };
         | 
| 1810 | 
            -
                method.call(history, state, "", location. | 
| 2043 | 
            +
                method.call(history, state, "", location.href);
         | 
| 1811 2044 | 
             
                this.location = location;
         | 
| 1812 2045 | 
             
                this.restorationIdentifier = restorationIdentifier;
         | 
| 1813 2046 | 
             
              }
         | 
| @@ -1882,7 +2115,7 @@ class LinkClickObserver { | |
| 1882 2115 | 
             
                }
         | 
| 1883 2116 | 
             
              }
         | 
| 1884 2117 | 
             
              getLocationForLink(link) {
         | 
| 1885 | 
            -
                return  | 
| 2118 | 
            +
                return expandURL(link.getAttribute("href") || "");
         | 
| 1886 2119 | 
             
              }
         | 
| 1887 2120 | 
             
            }
         | 
| 1888 2121 |  | 
| @@ -1895,9 +2128,9 @@ class Navigator { | |
| 1895 2128 | 
             
                  this.delegate.visitProposedToLocation(location, options);
         | 
| 1896 2129 | 
             
                }
         | 
| 1897 2130 | 
             
              }
         | 
| 1898 | 
            -
              startVisit( | 
| 2131 | 
            +
              startVisit(locatable, restorationIdentifier, options = {}) {
         | 
| 1899 2132 | 
             
                this.stop();
         | 
| 1900 | 
            -
                this.currentVisit = new Visit(this,  | 
| 2133 | 
            +
                this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({
         | 
| 1901 2134 | 
             
                  referrer: this.location
         | 
| 1902 2135 | 
             
                }, options));
         | 
| 1903 2136 | 
             
                this.currentVisit.start();
         | 
| @@ -1905,7 +2138,11 @@ class Navigator { | |
| 1905 2138 | 
             
              submitForm(form, submitter) {
         | 
| 1906 2139 | 
             
                this.stop();
         | 
| 1907 2140 | 
             
                this.formSubmission = new FormSubmission(this, form, submitter, true);
         | 
| 1908 | 
            -
                this.formSubmission. | 
| 2141 | 
            +
                if (this.formSubmission.fetchRequest.isIdempotent) {
         | 
| 2142 | 
            +
                  this.proposeVisit(this.formSubmission.fetchRequest.url);
         | 
| 2143 | 
            +
                } else {
         | 
| 2144 | 
            +
                  this.formSubmission.start();
         | 
| 2145 | 
            +
                }
         | 
| 1909 2146 | 
             
              }
         | 
| 1910 2147 | 
             
              stop() {
         | 
| 1911 2148 | 
             
                if (this.formSubmission) {
         | 
| @@ -1948,10 +2185,8 @@ class Navigator { | |
| 1948 2185 | 
             
              async formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
         | 
| 1949 2186 | 
             
                const responseHTML = await fetchResponse.responseHTML;
         | 
| 1950 2187 | 
             
                if (responseHTML) {
         | 
| 1951 | 
            -
                  const snapshot =  | 
| 1952 | 
            -
                  this.view. | 
| 1953 | 
            -
                    snapshot: snapshot
         | 
| 1954 | 
            -
                  }, (() => {}));
         | 
| 2188 | 
            +
                  const snapshot = PageSnapshot.fromHTMLString(responseHTML);
         | 
| 2189 | 
            +
                  await this.view.renderPage(snapshot);
         | 
| 1955 2190 | 
             
                  this.view.clearSnapshotCache();
         | 
| 1956 2191 | 
             
                }
         | 
| 1957 2192 | 
             
              }
         | 
| @@ -2061,51 +2296,10 @@ class ScrollObserver { | |
| 2061 2296 | 
             
              }
         | 
| 2062 2297 | 
             
            }
         | 
| 2063 2298 |  | 
| 2064 | 
            -
            class StreamMessage {
         | 
| 2065 | 
            -
              constructor(html) {
         | 
| 2066 | 
            -
                this.templateElement = document.createElement("template");
         | 
| 2067 | 
            -
                this.templateElement.innerHTML = html;
         | 
| 2068 | 
            -
              }
         | 
| 2069 | 
            -
              static wrap(message) {
         | 
| 2070 | 
            -
                if (typeof message == "string") {
         | 
| 2071 | 
            -
                  return new this(message);
         | 
| 2072 | 
            -
                } else {
         | 
| 2073 | 
            -
                  return message;
         | 
| 2074 | 
            -
                }
         | 
| 2075 | 
            -
              }
         | 
| 2076 | 
            -
              get fragment() {
         | 
| 2077 | 
            -
                const fragment = document.createDocumentFragment();
         | 
| 2078 | 
            -
                for (const element of this.foreignElements) {
         | 
| 2079 | 
            -
                  fragment.appendChild(document.importNode(element, true));
         | 
| 2080 | 
            -
                }
         | 
| 2081 | 
            -
                return fragment;
         | 
| 2082 | 
            -
              }
         | 
| 2083 | 
            -
              get foreignElements() {
         | 
| 2084 | 
            -
                return this.templateChildren.reduce(((streamElements, child) => {
         | 
| 2085 | 
            -
                  if (child.tagName.toLowerCase() == "turbo-stream") {
         | 
| 2086 | 
            -
                    return [ ...streamElements, child ];
         | 
| 2087 | 
            -
                  } else {
         | 
| 2088 | 
            -
                    return streamElements;
         | 
| 2089 | 
            -
                  }
         | 
| 2090 | 
            -
                }), []);
         | 
| 2091 | 
            -
              }
         | 
| 2092 | 
            -
              get templateChildren() {
         | 
| 2093 | 
            -
                return Array.from(this.templateElement.content.children);
         | 
| 2094 | 
            -
              }
         | 
| 2095 | 
            -
            }
         | 
| 2096 | 
            -
             | 
| 2097 2299 | 
             
            class StreamObserver {
         | 
| 2098 2300 | 
             
              constructor(delegate) {
         | 
| 2099 2301 | 
             
                this.sources = new Set;
         | 
| 2100 2302 | 
             
                this.started = false;
         | 
| 2101 | 
            -
                this.prepareFetchRequest = event => {
         | 
| 2102 | 
            -
                  var _a;
         | 
| 2103 | 
            -
                  const fetchOptions = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchOptions;
         | 
| 2104 | 
            -
                  if (fetchOptions) {
         | 
| 2105 | 
            -
                    const {headers: headers} = fetchOptions;
         | 
| 2106 | 
            -
                    headers.Accept = [ "text/vnd.turbo-stream.html", headers.Accept ].join(", ");
         | 
| 2107 | 
            -
                  }
         | 
| 2108 | 
            -
                };
         | 
| 2109 2303 | 
             
                this.inspectFetchResponse = event => {
         | 
| 2110 2304 | 
             
                  const response = fetchResponseFromEvent(event);
         | 
| 2111 2305 | 
             
                  if (response && fetchResponseIsStream(response)) {
         | 
| @@ -2123,14 +2317,12 @@ class StreamObserver { | |
| 2123 2317 | 
             
              start() {
         | 
| 2124 2318 | 
             
                if (!this.started) {
         | 
| 2125 2319 | 
             
                  this.started = true;
         | 
| 2126 | 
            -
                  addEventListener("turbo:before-fetch-request", this.prepareFetchRequest, true);
         | 
| 2127 2320 | 
             
                  addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
         | 
| 2128 2321 | 
             
                }
         | 
| 2129 2322 | 
             
              }
         | 
| 2130 2323 | 
             
              stop() {
         | 
| 2131 2324 | 
             
                if (this.started) {
         | 
| 2132 2325 | 
             
                  this.started = false;
         | 
| 2133 | 
            -
                  removeEventListener("turbo:before-fetch-request", this.prepareFetchRequest, true);
         | 
| 2134 2326 | 
             
                  removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false);
         | 
| 2135 2327 | 
             
                }
         | 
| 2136 2328 | 
             
              }
         | 
| @@ -2171,70 +2363,25 @@ function fetchResponseFromEvent(event) { | |
| 2171 2363 | 
             
            function fetchResponseIsStream(response) {
         | 
| 2172 2364 | 
             
              var _a;
         | 
| 2173 2365 | 
             
              const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
         | 
| 2174 | 
            -
              return  | 
| 2366 | 
            +
              return contentType.startsWith(StreamMessage.contentType);
         | 
| 2175 2367 | 
             
            }
         | 
| 2176 2368 |  | 
| 2177 2369 | 
             
            function isAction(action) {
         | 
| 2178 2370 | 
             
              return action == "advance" || action == "replace" || action == "restore";
         | 
| 2179 2371 | 
             
            }
         | 
| 2180 2372 |  | 
| 2181 | 
            -
            class Renderer {
         | 
| 2182 | 
            -
              renderView(callback) {
         | 
| 2183 | 
            -
                this.delegate.viewWillRender(this.newBody);
         | 
| 2184 | 
            -
                callback();
         | 
| 2185 | 
            -
                this.delegate.viewRendered(this.newBody);
         | 
| 2186 | 
            -
              }
         | 
| 2187 | 
            -
              invalidateView() {
         | 
| 2188 | 
            -
                this.delegate.viewInvalidated();
         | 
| 2189 | 
            -
              }
         | 
| 2190 | 
            -
              createScriptElement(element) {
         | 
| 2191 | 
            -
                if (element.getAttribute("data-turbo-eval") == "false") {
         | 
| 2192 | 
            -
                  return element;
         | 
| 2193 | 
            -
                } else {
         | 
| 2194 | 
            -
                  const createdScriptElement = document.createElement("script");
         | 
| 2195 | 
            -
                  createdScriptElement.textContent = element.textContent;
         | 
| 2196 | 
            -
                  createdScriptElement.async = false;
         | 
| 2197 | 
            -
                  copyElementAttributes(createdScriptElement, element);
         | 
| 2198 | 
            -
                  return createdScriptElement;
         | 
| 2199 | 
            -
                }
         | 
| 2200 | 
            -
              }
         | 
| 2201 | 
            -
            }
         | 
| 2202 | 
            -
             | 
| 2203 | 
            -
            function copyElementAttributes(destinationElement, sourceElement) {
         | 
| 2204 | 
            -
              for (const {name: name, value: value} of [ ...sourceElement.attributes ]) {
         | 
| 2205 | 
            -
                destinationElement.setAttribute(name, value);
         | 
| 2206 | 
            -
              }
         | 
| 2207 | 
            -
            }
         | 
| 2208 | 
            -
             | 
| 2209 2373 | 
             
            class ErrorRenderer extends Renderer {
         | 
| 2210 | 
            -
               | 
| 2211 | 
            -
                 | 
| 2212 | 
            -
                this. | 
| 2213 | 
            -
                this.htmlElement = (() => {
         | 
| 2214 | 
            -
                  const htmlElement = document.createElement("html");
         | 
| 2215 | 
            -
                  htmlElement.innerHTML = html;
         | 
| 2216 | 
            -
                  return htmlElement;
         | 
| 2217 | 
            -
                })();
         | 
| 2218 | 
            -
                this.newHead = this.htmlElement.querySelector("head") || document.createElement("head");
         | 
| 2219 | 
            -
                this.newBody = this.htmlElement.querySelector("body") || document.createElement("body");
         | 
| 2220 | 
            -
              }
         | 
| 2221 | 
            -
              static render(delegate, callback, html) {
         | 
| 2222 | 
            -
                return new this(delegate, html).render(callback);
         | 
| 2223 | 
            -
              }
         | 
| 2224 | 
            -
              render(callback) {
         | 
| 2225 | 
            -
                this.renderView((() => {
         | 
| 2226 | 
            -
                  this.replaceHeadAndBody();
         | 
| 2227 | 
            -
                  this.activateBodyScriptElements();
         | 
| 2228 | 
            -
                  callback();
         | 
| 2229 | 
            -
                }));
         | 
| 2374 | 
            +
              async render() {
         | 
| 2375 | 
            +
                this.replaceHeadAndBody();
         | 
| 2376 | 
            +
                this.activateScriptElements();
         | 
| 2230 2377 | 
             
              }
         | 
| 2231 2378 | 
             
              replaceHeadAndBody() {
         | 
| 2232 2379 | 
             
                const {documentElement: documentElement, head: head, body: body} = document;
         | 
| 2233 2380 | 
             
                documentElement.replaceChild(this.newHead, head);
         | 
| 2234 | 
            -
                documentElement.replaceChild(this. | 
| 2381 | 
            +
                documentElement.replaceChild(this.newElement, body);
         | 
| 2235 2382 | 
             
              }
         | 
| 2236 | 
            -
               | 
| 2237 | 
            -
                for (const replaceableElement of this. | 
| 2383 | 
            +
              activateScriptElements() {
         | 
| 2384 | 
            +
                for (const replaceableElement of this.scriptElements) {
         | 
| 2238 2385 | 
             
                  const parentNode = replaceableElement.parentNode;
         | 
| 2239 2386 | 
             
                  if (parentNode) {
         | 
| 2240 2387 | 
             
                    const element = this.createScriptElement(replaceableElement);
         | 
| @@ -2242,82 +2389,38 @@ class ErrorRenderer extends Renderer { | |
| 2242 2389 | 
             
                  }
         | 
| 2243 2390 | 
             
                }
         | 
| 2244 2391 | 
             
              }
         | 
| 2245 | 
            -
               | 
| 2392 | 
            +
              get newHead() {
         | 
| 2393 | 
            +
                return this.newSnapshot.headSnapshot.element;
         | 
| 2394 | 
            +
              }
         | 
| 2395 | 
            +
              get scriptElements() {
         | 
| 2246 2396 | 
             
                return [ ...document.documentElement.querySelectorAll("script") ];
         | 
| 2247 2397 | 
             
              }
         | 
| 2248 2398 | 
             
            }
         | 
| 2249 2399 |  | 
| 2250 | 
            -
            class  | 
| 2251 | 
            -
               | 
| 2252 | 
            -
                this. | 
| 2253 | 
            -
                this.snapshots = {};
         | 
| 2254 | 
            -
                this.size = size;
         | 
| 2255 | 
            -
              }
         | 
| 2256 | 
            -
              has(location) {
         | 
| 2257 | 
            -
                return location.toCacheKey() in this.snapshots;
         | 
| 2258 | 
            -
              }
         | 
| 2259 | 
            -
              get(location) {
         | 
| 2260 | 
            -
                if (this.has(location)) {
         | 
| 2261 | 
            -
                  const snapshot = this.read(location);
         | 
| 2262 | 
            -
                  this.touch(location);
         | 
| 2263 | 
            -
                  return snapshot;
         | 
| 2264 | 
            -
                }
         | 
| 2265 | 
            -
              }
         | 
| 2266 | 
            -
              put(location, snapshot) {
         | 
| 2267 | 
            -
                this.write(location, snapshot);
         | 
| 2268 | 
            -
                this.touch(location);
         | 
| 2269 | 
            -
                return snapshot;
         | 
| 2270 | 
            -
              }
         | 
| 2271 | 
            -
              clear() {
         | 
| 2272 | 
            -
                this.snapshots = {};
         | 
| 2273 | 
            -
              }
         | 
| 2274 | 
            -
              read(location) {
         | 
| 2275 | 
            -
                return this.snapshots[location.toCacheKey()];
         | 
| 2400 | 
            +
            class PageRenderer extends Renderer {
         | 
| 2401 | 
            +
              get shouldRender() {
         | 
| 2402 | 
            +
                return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
         | 
| 2276 2403 | 
             
              }
         | 
| 2277 | 
            -
               | 
| 2278 | 
            -
                this. | 
| 2404 | 
            +
              prepareToRender() {
         | 
| 2405 | 
            +
                this.mergeHead();
         | 
| 2279 2406 | 
             
              }
         | 
| 2280 | 
            -
               | 
| 2281 | 
            -
                 | 
| 2282 | 
            -
                const index = this.keys.indexOf(key);
         | 
| 2283 | 
            -
                if (index > -1) this.keys.splice(index, 1);
         | 
| 2284 | 
            -
                this.keys.unshift(key);
         | 
| 2285 | 
            -
                this.trim();
         | 
| 2407 | 
            +
              async render() {
         | 
| 2408 | 
            +
                this.replaceBody();
         | 
| 2286 2409 | 
             
              }
         | 
| 2287 | 
            -
               | 
| 2288 | 
            -
                 | 
| 2289 | 
            -
             | 
| 2410 | 
            +
              finishRendering() {
         | 
| 2411 | 
            +
                super.finishRendering();
         | 
| 2412 | 
            +
                if (this.isPreview) {
         | 
| 2413 | 
            +
                  this.focusFirstAutofocusableElement();
         | 
| 2290 2414 | 
             
                }
         | 
| 2291 2415 | 
             
              }
         | 
| 2292 | 
            -
             | 
| 2293 | 
            -
             | 
| 2294 | 
            -
            class SnapshotRenderer extends Renderer {
         | 
| 2295 | 
            -
              constructor(delegate, currentSnapshot, newSnapshot, isPreview) {
         | 
| 2296 | 
            -
                super();
         | 
| 2297 | 
            -
                this.delegate = delegate;
         | 
| 2298 | 
            -
                this.currentSnapshot = currentSnapshot;
         | 
| 2299 | 
            -
                this.currentHeadDetails = currentSnapshot.headDetails;
         | 
| 2300 | 
            -
                this.newSnapshot = newSnapshot;
         | 
| 2301 | 
            -
                this.newHeadDetails = newSnapshot.headDetails;
         | 
| 2302 | 
            -
                this.newBody = newSnapshot.bodyElement;
         | 
| 2303 | 
            -
                this.isPreview = isPreview;
         | 
| 2416 | 
            +
              get currentHeadSnapshot() {
         | 
| 2417 | 
            +
                return this.currentSnapshot.headSnapshot;
         | 
| 2304 2418 | 
             
              }
         | 
| 2305 | 
            -
               | 
| 2306 | 
            -
                return  | 
| 2419 | 
            +
              get newHeadSnapshot() {
         | 
| 2420 | 
            +
                return this.newSnapshot.headSnapshot;
         | 
| 2307 2421 | 
             
              }
         | 
| 2308 | 
            -
               | 
| 2309 | 
            -
                 | 
| 2310 | 
            -
                  this.mergeHead();
         | 
| 2311 | 
            -
                  this.renderView((() => {
         | 
| 2312 | 
            -
                    this.replaceBody();
         | 
| 2313 | 
            -
                    if (!this.isPreview) {
         | 
| 2314 | 
            -
                      this.focusFirstAutofocusableElement();
         | 
| 2315 | 
            -
                    }
         | 
| 2316 | 
            -
                    callback();
         | 
| 2317 | 
            -
                  }));
         | 
| 2318 | 
            -
                } else {
         | 
| 2319 | 
            -
                  this.invalidateView();
         | 
| 2320 | 
            -
                }
         | 
| 2422 | 
            +
              get newElement() {
         | 
| 2423 | 
            +
                return this.newSnapshot.element;
         | 
| 2321 2424 | 
             
              }
         | 
| 2322 2425 | 
             
              mergeHead() {
         | 
| 2323 2426 | 
             
                this.copyNewHeadStylesheetElements();
         | 
| @@ -2326,190 +2429,145 @@ class SnapshotRenderer extends Renderer { | |
| 2326 2429 | 
             
                this.copyNewHeadProvisionalElements();
         | 
| 2327 2430 | 
             
              }
         | 
| 2328 2431 | 
             
              replaceBody() {
         | 
| 2329 | 
            -
                 | 
| 2330 | 
            -
             | 
| 2331 | 
            -
             | 
| 2332 | 
            -
                 | 
| 2333 | 
            -
              }
         | 
| 2334 | 
            -
              shouldRender() {
         | 
| 2335 | 
            -
                return this.newSnapshot.isVisitable() && this.trackedElementsAreIdentical();
         | 
| 2432 | 
            +
                this.preservingPermanentElements((() => {
         | 
| 2433 | 
            +
                  this.activateNewBody();
         | 
| 2434 | 
            +
                  this.assignNewBody();
         | 
| 2435 | 
            +
                }));
         | 
| 2336 2436 | 
             
              }
         | 
| 2337 | 
            -
              trackedElementsAreIdentical() {
         | 
| 2338 | 
            -
                return this. | 
| 2437 | 
            +
              get trackedElementsAreIdentical() {
         | 
| 2438 | 
            +
                return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;
         | 
| 2339 2439 | 
             
              }
         | 
| 2340 2440 | 
             
              copyNewHeadStylesheetElements() {
         | 
| 2341 | 
            -
                for (const element of this. | 
| 2441 | 
            +
                for (const element of this.newHeadStylesheetElements) {
         | 
| 2342 2442 | 
             
                  document.head.appendChild(element);
         | 
| 2343 2443 | 
             
                }
         | 
| 2344 2444 | 
             
              }
         | 
| 2345 2445 | 
             
              copyNewHeadScriptElements() {
         | 
| 2346 | 
            -
                for (const element of this. | 
| 2446 | 
            +
                for (const element of this.newHeadScriptElements) {
         | 
| 2347 2447 | 
             
                  document.head.appendChild(this.createScriptElement(element));
         | 
| 2348 2448 | 
             
                }
         | 
| 2349 2449 | 
             
              }
         | 
| 2350 2450 | 
             
              removeCurrentHeadProvisionalElements() {
         | 
| 2351 | 
            -
                for (const element of this. | 
| 2451 | 
            +
                for (const element of this.currentHeadProvisionalElements) {
         | 
| 2352 2452 | 
             
                  document.head.removeChild(element);
         | 
| 2353 2453 | 
             
                }
         | 
| 2354 2454 | 
             
              }
         | 
| 2355 2455 | 
             
              copyNewHeadProvisionalElements() {
         | 
| 2356 | 
            -
                for (const element of this. | 
| 2456 | 
            +
                for (const element of this.newHeadProvisionalElements) {
         | 
| 2357 2457 | 
             
                  document.head.appendChild(element);
         | 
| 2358 2458 | 
             
                }
         | 
| 2359 2459 | 
             
              }
         | 
| 2360 | 
            -
              relocateCurrentBodyPermanentElements() {
         | 
| 2361 | 
            -
                return this.getCurrentBodyPermanentElements().reduce(((placeholders, permanentElement) => {
         | 
| 2362 | 
            -
                  const newElement = this.newSnapshot.getPermanentElementById(permanentElement.id);
         | 
| 2363 | 
            -
                  if (newElement) {
         | 
| 2364 | 
            -
                    const placeholder = createPlaceholderForPermanentElement(permanentElement);
         | 
| 2365 | 
            -
                    replaceElementWithElement(permanentElement, placeholder.element);
         | 
| 2366 | 
            -
                    replaceElementWithElement(newElement, permanentElement);
         | 
| 2367 | 
            -
                    return [ ...placeholders, placeholder ];
         | 
| 2368 | 
            -
                  } else {
         | 
| 2369 | 
            -
                    return placeholders;
         | 
| 2370 | 
            -
                  }
         | 
| 2371 | 
            -
                }), []);
         | 
| 2372 | 
            -
              }
         | 
| 2373 | 
            -
              replacePlaceholderElementsWithClonedPermanentElements(placeholders) {
         | 
| 2374 | 
            -
                for (const {element: element, permanentElement: permanentElement} of placeholders) {
         | 
| 2375 | 
            -
                  const clonedElement = permanentElement.cloneNode(true);
         | 
| 2376 | 
            -
                  replaceElementWithElement(element, clonedElement);
         | 
| 2377 | 
            -
                }
         | 
| 2378 | 
            -
              }
         | 
| 2379 2460 | 
             
              activateNewBody() {
         | 
| 2380 | 
            -
                document.adoptNode(this. | 
| 2461 | 
            +
                document.adoptNode(this.newElement);
         | 
| 2381 2462 | 
             
                this.activateNewBodyScriptElements();
         | 
| 2382 2463 | 
             
              }
         | 
| 2383 2464 | 
             
              activateNewBodyScriptElements() {
         | 
| 2384 | 
            -
                for (const inertScriptElement of this. | 
| 2465 | 
            +
                for (const inertScriptElement of this.newBodyScriptElements) {
         | 
| 2385 2466 | 
             
                  const activatedScriptElement = this.createScriptElement(inertScriptElement);
         | 
| 2386 2467 | 
             
                  replaceElementWithElement(inertScriptElement, activatedScriptElement);
         | 
| 2387 2468 | 
             
                }
         | 
| 2388 2469 | 
             
              }
         | 
| 2389 2470 | 
             
              assignNewBody() {
         | 
| 2390 | 
            -
                if (document.body) {
         | 
| 2391 | 
            -
                  replaceElementWithElement(document.body, this. | 
| 2471 | 
            +
                if (document.body && this.newElement instanceof HTMLBodyElement) {
         | 
| 2472 | 
            +
                  replaceElementWithElement(document.body, this.newElement);
         | 
| 2392 2473 | 
             
                } else {
         | 
| 2393 | 
            -
                  document.documentElement.appendChild(this. | 
| 2394 | 
            -
                }
         | 
| 2395 | 
            -
              }
         | 
| 2396 | 
            -
              focusFirstAutofocusableElement() {
         | 
| 2397 | 
            -
                const element = this.newSnapshot.findFirstAutofocusableElement();
         | 
| 2398 | 
            -
                if (elementIsFocusable(element)) {
         | 
| 2399 | 
            -
                  element.focus();
         | 
| 2474 | 
            +
                  document.documentElement.appendChild(this.newElement);
         | 
| 2400 2475 | 
             
                }
         | 
| 2401 2476 | 
             
              }
         | 
| 2402 | 
            -
               | 
| 2403 | 
            -
                return this. | 
| 2477 | 
            +
              get newHeadStylesheetElements() {
         | 
| 2478 | 
            +
                return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
         | 
| 2404 2479 | 
             
              }
         | 
| 2405 | 
            -
               | 
| 2406 | 
            -
                return this. | 
| 2480 | 
            +
              get newHeadScriptElements() {
         | 
| 2481 | 
            +
                return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot);
         | 
| 2407 2482 | 
             
              }
         | 
| 2408 | 
            -
               | 
| 2409 | 
            -
                return this. | 
| 2483 | 
            +
              get currentHeadProvisionalElements() {
         | 
| 2484 | 
            +
                return this.currentHeadSnapshot.provisionalElements;
         | 
| 2410 2485 | 
             
              }
         | 
| 2411 | 
            -
               | 
| 2412 | 
            -
                return this. | 
| 2486 | 
            +
              get newHeadProvisionalElements() {
         | 
| 2487 | 
            +
                return this.newHeadSnapshot.provisionalElements;
         | 
| 2413 2488 | 
             
              }
         | 
| 2414 | 
            -
               | 
| 2415 | 
            -
                return this. | 
| 2489 | 
            +
              get newBodyScriptElements() {
         | 
| 2490 | 
            +
                return [ ...this.newElement.querySelectorAll("script") ];
         | 
| 2416 2491 | 
             
              }
         | 
| 2417 | 
            -
              getNewBodyScriptElements() {
         | 
| 2418 | 
            -
                return [ ...this.newBody.querySelectorAll("script") ];
         | 
| 2419 | 
            -
              }
         | 
| 2420 | 
            -
            }
         | 
| 2421 | 
            -
             | 
| 2422 | 
            -
            function createPlaceholderForPermanentElement(permanentElement) {
         | 
| 2423 | 
            -
              const element = document.createElement("meta");
         | 
| 2424 | 
            -
              element.setAttribute("name", "turbo-permanent-placeholder");
         | 
| 2425 | 
            -
              element.setAttribute("content", permanentElement.id);
         | 
| 2426 | 
            -
              return {
         | 
| 2427 | 
            -
                element: element,
         | 
| 2428 | 
            -
                permanentElement: permanentElement
         | 
| 2429 | 
            -
              };
         | 
| 2430 2492 | 
             
            }
         | 
| 2431 2493 |  | 
| 2432 | 
            -
             | 
| 2433 | 
            -
               | 
| 2434 | 
            -
             | 
| 2435 | 
            -
                 | 
| 2494 | 
            +
            class SnapshotCache {
         | 
| 2495 | 
            +
              constructor(size) {
         | 
| 2496 | 
            +
                this.keys = [];
         | 
| 2497 | 
            +
                this.snapshots = {};
         | 
| 2498 | 
            +
                this.size = size;
         | 
| 2499 | 
            +
              }
         | 
| 2500 | 
            +
              has(location) {
         | 
| 2501 | 
            +
                return toCacheKey(location) in this.snapshots;
         | 
| 2502 | 
            +
              }
         | 
| 2503 | 
            +
              get(location) {
         | 
| 2504 | 
            +
                if (this.has(location)) {
         | 
| 2505 | 
            +
                  const snapshot = this.read(location);
         | 
| 2506 | 
            +
                  this.touch(location);
         | 
| 2507 | 
            +
                  return snapshot;
         | 
| 2508 | 
            +
                }
         | 
| 2509 | 
            +
              }
         | 
| 2510 | 
            +
              put(location, snapshot) {
         | 
| 2511 | 
            +
                this.write(location, snapshot);
         | 
| 2512 | 
            +
                this.touch(location);
         | 
| 2513 | 
            +
                return snapshot;
         | 
| 2514 | 
            +
              }
         | 
| 2515 | 
            +
              clear() {
         | 
| 2516 | 
            +
                this.snapshots = {};
         | 
| 2517 | 
            +
              }
         | 
| 2518 | 
            +
              read(location) {
         | 
| 2519 | 
            +
                return this.snapshots[toCacheKey(location)];
         | 
| 2520 | 
            +
              }
         | 
| 2521 | 
            +
              write(location, snapshot) {
         | 
| 2522 | 
            +
                this.snapshots[toCacheKey(location)] = snapshot;
         | 
| 2523 | 
            +
              }
         | 
| 2524 | 
            +
              touch(location) {
         | 
| 2525 | 
            +
                const key = toCacheKey(location);
         | 
| 2526 | 
            +
                const index = this.keys.indexOf(key);
         | 
| 2527 | 
            +
                if (index > -1) this.keys.splice(index, 1);
         | 
| 2528 | 
            +
                this.keys.unshift(key);
         | 
| 2529 | 
            +
                this.trim();
         | 
| 2530 | 
            +
              }
         | 
| 2531 | 
            +
              trim() {
         | 
| 2532 | 
            +
                for (const key of this.keys.splice(this.size)) {
         | 
| 2533 | 
            +
                  delete this.snapshots[key];
         | 
| 2534 | 
            +
                }
         | 
| 2436 2535 | 
             
              }
         | 
| 2437 2536 | 
             
            }
         | 
| 2438 2537 |  | 
| 2439 | 
            -
             | 
| 2440 | 
            -
               | 
| 2441 | 
            -
             | 
| 2442 | 
            -
             | 
| 2443 | 
            -
            class View {
         | 
| 2444 | 
            -
              constructor(delegate) {
         | 
| 2445 | 
            -
                this.htmlElement = document.documentElement;
         | 
| 2538 | 
            +
            class PageView extends View {
         | 
| 2539 | 
            +
              constructor() {
         | 
| 2540 | 
            +
                super(...arguments);
         | 
| 2446 2541 | 
             
                this.snapshotCache = new SnapshotCache(10);
         | 
| 2447 | 
            -
                this. | 
| 2542 | 
            +
                this.lastRenderedLocation = new URL(location.href);
         | 
| 2448 2543 | 
             
              }
         | 
| 2449 | 
            -
               | 
| 2450 | 
            -
                 | 
| 2451 | 
            -
             | 
| 2452 | 
            -
              getElementForAnchor(anchor) {
         | 
| 2453 | 
            -
                return this.getSnapshot().getElementForAnchor(anchor);
         | 
| 2544 | 
            +
              renderPage(snapshot, isPreview = false) {
         | 
| 2545 | 
            +
                const renderer = new PageRenderer(this.snapshot, snapshot, isPreview);
         | 
| 2546 | 
            +
                return this.render(renderer);
         | 
| 2454 2547 | 
             
              }
         | 
| 2455 | 
            -
               | 
| 2456 | 
            -
                 | 
| 2548 | 
            +
              renderError(snapshot) {
         | 
| 2549 | 
            +
                const renderer = new ErrorRenderer(this.snapshot, snapshot, false);
         | 
| 2550 | 
            +
                this.render(renderer);
         | 
| 2457 2551 | 
             
              }
         | 
| 2458 2552 | 
             
              clearSnapshotCache() {
         | 
| 2459 2553 | 
             
                this.snapshotCache.clear();
         | 
| 2460 2554 | 
             
              }
         | 
| 2461 | 
            -
              shouldCacheSnapshot() {
         | 
| 2462 | 
            -
                return this.getSnapshot().isCacheable();
         | 
| 2463 | 
            -
              }
         | 
| 2464 2555 | 
             
              async cacheSnapshot() {
         | 
| 2465 | 
            -
                if (this.shouldCacheSnapshot | 
| 2556 | 
            +
                if (this.shouldCacheSnapshot) {
         | 
| 2466 2557 | 
             
                  this.delegate.viewWillCacheSnapshot();
         | 
| 2467 | 
            -
                  const snapshot = this | 
| 2468 | 
            -
                   | 
| 2469 | 
            -
                  await nextMicrotask();
         | 
| 2558 | 
            +
                  const {snapshot: snapshot, lastRenderedLocation: location} = this;
         | 
| 2559 | 
            +
                  await nextEventLoopTick();
         | 
| 2470 2560 | 
             
                  this.snapshotCache.put(location, snapshot.clone());
         | 
| 2471 2561 | 
             
                }
         | 
| 2472 2562 | 
             
              }
         | 
| 2473 2563 | 
             
              getCachedSnapshotForLocation(location) {
         | 
| 2474 2564 | 
             
                return this.snapshotCache.get(location);
         | 
| 2475 2565 | 
             
              }
         | 
| 2476 | 
            -
               | 
| 2477 | 
            -
                this. | 
| 2478 | 
            -
                if (snapshot) {
         | 
| 2479 | 
            -
                  this.renderSnapshot(snapshot, isPreview, callback);
         | 
| 2480 | 
            -
                } else {
         | 
| 2481 | 
            -
                  this.renderError(error, callback);
         | 
| 2482 | 
            -
                }
         | 
| 2483 | 
            -
              }
         | 
| 2484 | 
            -
              scrollToAnchor(anchor) {
         | 
| 2485 | 
            -
                const element = this.getElementForAnchor(anchor);
         | 
| 2486 | 
            -
                if (element) {
         | 
| 2487 | 
            -
                  this.scrollToElement(element);
         | 
| 2488 | 
            -
                } else {
         | 
| 2489 | 
            -
                  this.scrollToPosition({
         | 
| 2490 | 
            -
                    x: 0,
         | 
| 2491 | 
            -
                    y: 0
         | 
| 2492 | 
            -
                  });
         | 
| 2493 | 
            -
                }
         | 
| 2494 | 
            -
              }
         | 
| 2495 | 
            -
              scrollToElement(element) {
         | 
| 2496 | 
            -
                element.scrollIntoView();
         | 
| 2497 | 
            -
              }
         | 
| 2498 | 
            -
              scrollToPosition({x: x, y: y}) {
         | 
| 2499 | 
            -
                window.scrollTo(x, y);
         | 
| 2500 | 
            -
              }
         | 
| 2501 | 
            -
              markAsPreview(isPreview) {
         | 
| 2502 | 
            -
                if (isPreview) {
         | 
| 2503 | 
            -
                  this.htmlElement.setAttribute("data-turbo-preview", "");
         | 
| 2504 | 
            -
                } else {
         | 
| 2505 | 
            -
                  this.htmlElement.removeAttribute("data-turbo-preview");
         | 
| 2506 | 
            -
                }
         | 
| 2507 | 
            -
              }
         | 
| 2508 | 
            -
              renderSnapshot(snapshot, isPreview, callback) {
         | 
| 2509 | 
            -
                SnapshotRenderer.render(this.delegate, callback, this.getSnapshot(), snapshot, isPreview || false);
         | 
| 2566 | 
            +
              get snapshot() {
         | 
| 2567 | 
            +
                return PageSnapshot.fromElement(this.element);
         | 
| 2510 2568 | 
             
              }
         | 
| 2511 | 
            -
               | 
| 2512 | 
            -
                 | 
| 2569 | 
            +
              get shouldCacheSnapshot() {
         | 
| 2570 | 
            +
                return this.snapshot.isCacheable;
         | 
| 2513 2571 | 
             
              }
         | 
| 2514 2572 | 
             
            }
         | 
| 2515 2573 |  | 
| @@ -2517,7 +2575,7 @@ class Session { | |
| 2517 2575 | 
             
              constructor() {
         | 
| 2518 2576 | 
             
                this.navigator = new Navigator(this);
         | 
| 2519 2577 | 
             
                this.history = new History(this);
         | 
| 2520 | 
            -
                this.view = new  | 
| 2578 | 
            +
                this.view = new PageView(this, document.documentElement);
         | 
| 2521 2579 | 
             
                this.adapter = new BrowserAdapter(this);
         | 
| 2522 2580 | 
             
                this.pageObserver = new PageObserver(this);
         | 
| 2523 2581 | 
             
                this.linkClickObserver = new LinkClickObserver(this);
         | 
| @@ -2561,7 +2619,7 @@ class Session { | |
| 2561 2619 | 
             
                this.adapter = adapter;
         | 
| 2562 2620 | 
             
              }
         | 
| 2563 2621 | 
             
              visit(location, options = {}) {
         | 
| 2564 | 
            -
                this.navigator.proposeVisit( | 
| 2622 | 
            +
                this.navigator.proposeVisit(expandURL(location), options);
         | 
| 2565 2623 | 
             
              }
         | 
| 2566 2624 | 
             
              connectStreamSource(source) {
         | 
| 2567 2625 | 
             
                this.streamObserver.connectStreamSource(source);
         | 
| @@ -2604,7 +2662,7 @@ class Session { | |
| 2604 2662 | 
             
              }
         | 
| 2605 2663 | 
             
              followedLinkToLocation(link, location) {
         | 
| 2606 2664 | 
             
                const action = this.getActionForLink(link);
         | 
| 2607 | 
            -
                this.visit(location, {
         | 
| 2665 | 
            +
                this.visit(location.href, {
         | 
| 2608 2666 | 
             
                  action: action
         | 
| 2609 2667 | 
             
                });
         | 
| 2610 2668 | 
             
              }
         | 
| @@ -2612,9 +2670,11 @@ class Session { | |
| 2612 2670 | 
             
                return this.applicationAllowsVisitingLocation(location);
         | 
| 2613 2671 | 
             
              }
         | 
| 2614 2672 | 
             
              visitProposedToLocation(location, options) {
         | 
| 2673 | 
            +
                extendURLWithDeprecatedProperties(location);
         | 
| 2615 2674 | 
             
                this.adapter.visitProposedToLocation(location, options);
         | 
| 2616 2675 | 
             
              }
         | 
| 2617 2676 | 
             
              visitStarted(visit) {
         | 
| 2677 | 
            +
                extendURLWithDeprecatedProperties(visit.location);
         | 
| 2618 2678 | 
             
                this.notifyApplicationAfterVisitingLocation(visit.location);
         | 
| 2619 2679 | 
             
              }
         | 
| 2620 2680 | 
             
              visitCompleted(visit) {
         | 
| @@ -2639,19 +2699,19 @@ class Session { | |
| 2639 2699 | 
             
              receivedMessageFromStream(message) {
         | 
| 2640 2700 | 
             
                this.renderStreamMessage(message);
         | 
| 2641 2701 | 
             
              }
         | 
| 2642 | 
            -
               | 
| 2643 | 
            -
                this. | 
| 2702 | 
            +
              viewWillCacheSnapshot() {
         | 
| 2703 | 
            +
                this.notifyApplicationBeforeCachingSnapshot();
         | 
| 2704 | 
            +
              }
         | 
| 2705 | 
            +
              viewWillRenderSnapshot({element: element}, isPreview) {
         | 
| 2706 | 
            +
                this.notifyApplicationBeforeRender(element);
         | 
| 2644 2707 | 
             
              }
         | 
| 2645 | 
            -
               | 
| 2708 | 
            +
              viewRenderedSnapshot(snapshot, isPreview) {
         | 
| 2646 2709 | 
             
                this.view.lastRenderedLocation = this.history.location;
         | 
| 2647 2710 | 
             
                this.notifyApplicationAfterRender();
         | 
| 2648 2711 | 
             
              }
         | 
| 2649 2712 | 
             
              viewInvalidated() {
         | 
| 2650 2713 | 
             
                this.adapter.pageInvalidated();
         | 
| 2651 2714 | 
             
              }
         | 
| 2652 | 
            -
              viewWillCacheSnapshot() {
         | 
| 2653 | 
            -
                this.notifyApplicationBeforeCachingSnapshot();
         | 
| 2654 | 
            -
              }
         | 
| 2655 2715 | 
             
              applicationAllowsFollowingLinkToLocation(link, location) {
         | 
| 2656 2716 | 
             
                const event = this.notifyApplicationAfterClickingLinkToLocation(link, location);
         | 
| 2657 2717 | 
             
                return !event.defaultPrevented;
         | 
| @@ -2664,7 +2724,7 @@ class Session { | |
| 2664 2724 | 
             
                return dispatch("turbo:click", {
         | 
| 2665 2725 | 
             
                  target: link,
         | 
| 2666 2726 | 
             
                  detail: {
         | 
| 2667 | 
            -
                    url: location. | 
| 2727 | 
            +
                    url: location.href
         | 
| 2668 2728 | 
             
                  },
         | 
| 2669 2729 | 
             
                  cancelable: true
         | 
| 2670 2730 | 
             
                });
         | 
| @@ -2672,7 +2732,7 @@ class Session { | |
| 2672 2732 | 
             
              notifyApplicationBeforeVisitingLocation(location) {
         | 
| 2673 2733 | 
             
                return dispatch("turbo:before-visit", {
         | 
| 2674 2734 | 
             
                  detail: {
         | 
| 2675 | 
            -
                    url: location. | 
| 2735 | 
            +
                    url: location.href
         | 
| 2676 2736 | 
             
                  },
         | 
| 2677 2737 | 
             
                  cancelable: true
         | 
| 2678 2738 | 
             
                });
         | 
| @@ -2680,7 +2740,7 @@ class Session { | |
| 2680 2740 | 
             
              notifyApplicationAfterVisitingLocation(location) {
         | 
| 2681 2741 | 
             
                return dispatch("turbo:visit", {
         | 
| 2682 2742 | 
             
                  detail: {
         | 
| 2683 | 
            -
                    url: location. | 
| 2743 | 
            +
                    url: location.href
         | 
| 2684 2744 | 
             
                  }
         | 
| 2685 2745 | 
             
                });
         | 
| 2686 2746 | 
             
              }
         | 
| @@ -2700,7 +2760,7 @@ class Session { | |
| 2700 2760 | 
             
              notifyApplicationAfterPageLoad(timing = {}) {
         | 
| 2701 2761 | 
             
                return dispatch("turbo:load", {
         | 
| 2702 2762 | 
             
                  detail: {
         | 
| 2703 | 
            -
                    url: this.location. | 
| 2763 | 
            +
                    url: this.location.href,
         | 
| 2704 2764 | 
             
                    timing: timing
         | 
| 2705 2765 | 
             
                  }
         | 
| 2706 2766 | 
             
                });
         | 
| @@ -2718,10 +2778,25 @@ class Session { | |
| 2718 2778 | 
             
                }
         | 
| 2719 2779 | 
             
              }
         | 
| 2720 2780 | 
             
              locationIsVisitable(location) {
         | 
| 2721 | 
            -
                return  | 
| 2781 | 
            +
                return isPrefixedBy(location, this.snapshot.rootLocation) && isHTML(location);
         | 
| 2722 2782 | 
             
              }
         | 
| 2783 | 
            +
              get snapshot() {
         | 
| 2784 | 
            +
                return this.view.snapshot;
         | 
| 2785 | 
            +
              }
         | 
| 2786 | 
            +
            }
         | 
| 2787 | 
            +
             | 
| 2788 | 
            +
            function extendURLWithDeprecatedProperties(url) {
         | 
| 2789 | 
            +
              Object.defineProperties(url, deprecatedLocationPropertyDescriptors);
         | 
| 2723 2790 | 
             
            }
         | 
| 2724 2791 |  | 
| 2792 | 
            +
            const deprecatedLocationPropertyDescriptors = {
         | 
| 2793 | 
            +
              absoluteURL: {
         | 
| 2794 | 
            +
                get() {
         | 
| 2795 | 
            +
                  return this.toString();
         | 
| 2796 | 
            +
                }
         | 
| 2797 | 
            +
              }
         | 
| 2798 | 
            +
            };
         | 
| 2799 | 
            +
             | 
| 2725 2800 | 
             
            const session = new Session;
         | 
| 2726 2801 |  | 
| 2727 2802 | 
             
            const {navigator: navigator} = session;
         |