@hotwired/turbo 7.1.0 → 7.2.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/turbo.es2017-esm.js +712 -364
- package/dist/turbo.es2017-umd.js +717 -365
- package/dist/types/core/bardo.d.ts +7 -2
- package/dist/types/core/cache.d.ts +10 -0
- package/dist/types/core/drive/error_renderer.d.ts +1 -0
- package/dist/types/core/drive/form_submission.d.ts +12 -3
- package/dist/types/core/drive/history.d.ts +1 -1
- package/dist/types/core/drive/navigator.d.ts +1 -0
- package/dist/types/core/drive/page_renderer.d.ts +3 -0
- package/dist/types/core/drive/page_view.d.ts +8 -5
- package/dist/types/core/drive/preloader.d.ts +14 -0
- package/dist/types/core/drive/progress_bar.d.ts +1 -0
- package/dist/types/core/drive/visit.d.ts +3 -3
- package/dist/types/core/frames/frame_controller.d.ts +26 -16
- package/dist/types/core/frames/frame_redirector.d.ts +1 -1
- package/dist/types/core/frames/frame_renderer.d.ts +8 -1
- package/dist/types/core/frames/frame_view.d.ts +2 -1
- package/dist/types/core/frames/link_interceptor.d.ts +1 -1
- package/dist/types/core/index.d.ts +11 -2
- package/dist/types/core/native/adapter.d.ts +2 -1
- package/dist/types/core/native/browser_adapter.d.ts +17 -8
- package/dist/types/core/renderer.d.ts +12 -4
- package/dist/types/core/session.d.ts +68 -16
- package/dist/types/core/snapshot.d.ts +2 -1
- package/dist/types/core/view.d.ts +12 -6
- package/dist/types/elements/frame_element.d.ts +5 -1
- package/dist/types/elements/stream_element.d.ts +1 -0
- package/dist/types/elements/stream_source_element.d.ts +7 -0
- package/dist/types/http/fetch_request.d.ts +8 -0
- package/dist/types/observers/cache_observer.d.ts +1 -1
- package/dist/types/observers/form_link_interceptor.d.ts +14 -0
- package/dist/types/observers/link_click_observer.d.ts +2 -2
- package/dist/types/polyfills/submit-event.d.ts +1 -7
- package/dist/types/tests/functional/async_script_tests.d.ts +1 -6
- package/dist/types/tests/functional/autofocus_tests.d.ts +1 -9
- package/dist/types/tests/functional/cache_observer_tests.d.ts +1 -5
- package/dist/types/tests/functional/drive_disabled_tests.d.ts +1 -9
- package/dist/types/tests/functional/drive_tests.d.ts +1 -8
- package/dist/types/tests/functional/form_submission_tests.d.ts +1 -84
- package/dist/types/tests/functional/frame_navigation_tests.d.ts +1 -7
- package/dist/types/tests/functional/frame_tests.d.ts +1 -52
- package/dist/types/tests/functional/import_tests.d.ts +1 -4
- package/dist/types/tests/functional/loading_tests.d.ts +1 -13
- package/dist/types/tests/functional/navigation_tests.d.ts +1 -38
- package/dist/types/tests/functional/pausable_rendering_tests.d.ts +1 -6
- package/dist/types/tests/functional/pausable_requests_tests.d.ts +1 -6
- package/dist/types/tests/functional/preloader_tests.d.ts +1 -0
- package/dist/types/tests/functional/rendering_tests.d.ts +1 -35
- package/dist/types/tests/functional/scroll_restoration_tests.d.ts +1 -6
- package/dist/types/tests/functional/stream_tests.d.ts +1 -6
- package/dist/types/tests/functional/visit_tests.d.ts +1 -15
- package/dist/types/tests/helpers/page.d.ts +44 -0
- package/dist/types/tests/unit/deprecated_adapter_support_test.d.ts +10 -10
- package/dist/types/util.d.ts +6 -3
- package/package.json +22 -8
- package/CHANGELOG.md +0 -3
- package/dist/types/tests/functional/index.d.ts +0 -17
- package/dist/types/tests/helpers/functional_test_case.d.ts +0 -44
- package/dist/types/tests/helpers/remote_channel.d.ts +0 -10
- package/dist/types/tests/helpers/turbo_drive_test_case.d.ts +0 -21
package/dist/turbo.es2017-esm.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Turbo 7.
|
|
3
|
-
Copyright ©
|
|
2
|
+
Turbo 7.2.0-beta.1
|
|
3
|
+
Copyright © 2022 Basecamp, LLC
|
|
4
4
|
*/
|
|
5
5
|
(function () {
|
|
6
|
-
if (window.Reflect === undefined ||
|
|
6
|
+
if (window.Reflect === undefined ||
|
|
7
|
+
window.customElements === undefined ||
|
|
7
8
|
window.customElements.polyfillWrapFlushCallback) {
|
|
8
9
|
return;
|
|
9
10
|
}
|
|
10
11
|
const BuiltInHTMLElement = HTMLElement;
|
|
11
12
|
const wrapperForTheName = {
|
|
12
|
-
|
|
13
|
+
HTMLElement: function HTMLElement() {
|
|
13
14
|
return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
|
|
14
|
-
}
|
|
15
|
+
},
|
|
15
16
|
};
|
|
16
|
-
window.HTMLElement =
|
|
17
|
-
wrapperForTheName['HTMLElement'];
|
|
17
|
+
window.HTMLElement = wrapperForTheName["HTMLElement"];
|
|
18
18
|
HTMLElement.prototype = BuiltInHTMLElement.prototype;
|
|
19
19
|
HTMLElement.prototype.constructor = HTMLElement;
|
|
20
20
|
Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
|
|
@@ -72,7 +72,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
72
72
|
}
|
|
73
73
|
})(HTMLFormElement.prototype);
|
|
74
74
|
|
|
75
|
-
const submittersByForm = new WeakMap;
|
|
75
|
+
const submittersByForm = new WeakMap();
|
|
76
76
|
function findSubmitterFromClickTarget(target) {
|
|
77
77
|
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
78
78
|
const candidate = element ? element.closest("input, button") : null;
|
|
@@ -103,7 +103,7 @@ function clickCaptured(event) {
|
|
|
103
103
|
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
104
104
|
return submittersByForm.get(this.target);
|
|
105
105
|
}
|
|
106
|
-
}
|
|
106
|
+
},
|
|
107
107
|
});
|
|
108
108
|
})();
|
|
109
109
|
|
|
@@ -119,7 +119,7 @@ class FrameElement extends HTMLElement {
|
|
|
119
119
|
this.delegate = new FrameElement.delegateConstructor(this);
|
|
120
120
|
}
|
|
121
121
|
static get observedAttributes() {
|
|
122
|
-
return ["disabled", "loading", "src"];
|
|
122
|
+
return ["disabled", "complete", "loading", "src"];
|
|
123
123
|
}
|
|
124
124
|
connectedCallback() {
|
|
125
125
|
this.delegate.connect();
|
|
@@ -129,6 +129,7 @@ class FrameElement extends HTMLElement {
|
|
|
129
129
|
}
|
|
130
130
|
reload() {
|
|
131
131
|
const { src } = this;
|
|
132
|
+
this.removeAttribute("complete");
|
|
132
133
|
this.src = null;
|
|
133
134
|
this.src = src;
|
|
134
135
|
}
|
|
@@ -136,6 +137,9 @@ class FrameElement extends HTMLElement {
|
|
|
136
137
|
if (name == "loading") {
|
|
137
138
|
this.delegate.loadingStyleChanged();
|
|
138
139
|
}
|
|
140
|
+
else if (name == "complete") {
|
|
141
|
+
this.delegate.completeChanged();
|
|
142
|
+
}
|
|
139
143
|
else if (name == "src") {
|
|
140
144
|
this.delegate.sourceURLChanged();
|
|
141
145
|
}
|
|
@@ -200,8 +204,10 @@ class FrameElement extends HTMLElement {
|
|
|
200
204
|
}
|
|
201
205
|
function frameLoadingStyleFromString(style) {
|
|
202
206
|
switch (style.toLowerCase()) {
|
|
203
|
-
case "lazy":
|
|
204
|
-
|
|
207
|
+
case "lazy":
|
|
208
|
+
return FrameLoadingStyle.lazy;
|
|
209
|
+
default:
|
|
210
|
+
return FrameLoadingStyle.eager;
|
|
205
211
|
}
|
|
206
212
|
}
|
|
207
213
|
|
|
@@ -213,7 +219,7 @@ function getAnchor(url) {
|
|
|
213
219
|
if (url.hash) {
|
|
214
220
|
return url.hash.slice(1);
|
|
215
221
|
}
|
|
216
|
-
else if (anchorMatch = url.href.match(/#(.*)$/)) {
|
|
222
|
+
else if ((anchorMatch = url.href.match(/#(.*)$/))) {
|
|
217
223
|
return anchorMatch[1];
|
|
218
224
|
}
|
|
219
225
|
}
|
|
@@ -225,7 +231,7 @@ function getExtension(url) {
|
|
|
225
231
|
return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
|
226
232
|
}
|
|
227
233
|
function isHTML(url) {
|
|
228
|
-
return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml))$/);
|
|
234
|
+
return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml|php))$/);
|
|
229
235
|
}
|
|
230
236
|
function isPrefixedBy(baseURL, url) {
|
|
231
237
|
const prefix = getPrefix(url);
|
|
@@ -236,9 +242,7 @@ function locationIsVisitable(location, rootLocation) {
|
|
|
236
242
|
}
|
|
237
243
|
function getRequestURL(url) {
|
|
238
244
|
const anchor = getAnchor(url);
|
|
239
|
-
return anchor != null
|
|
240
|
-
? url.href.slice(0, -(anchor.length + 1))
|
|
241
|
-
: url.href;
|
|
245
|
+
return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
|
|
242
246
|
}
|
|
243
247
|
function toCacheKey(url) {
|
|
244
248
|
return getRequestURL(url);
|
|
@@ -307,7 +311,11 @@ class FetchResponse {
|
|
|
307
311
|
}
|
|
308
312
|
|
|
309
313
|
function dispatch(eventName, { target, cancelable, detail } = {}) {
|
|
310
|
-
const event = new CustomEvent(eventName, {
|
|
314
|
+
const event = new CustomEvent(eventName, {
|
|
315
|
+
cancelable,
|
|
316
|
+
bubbles: true,
|
|
317
|
+
detail,
|
|
318
|
+
});
|
|
311
319
|
if (target && target.isConnected) {
|
|
312
320
|
target.dispatchEvent(event);
|
|
313
321
|
}
|
|
@@ -317,10 +325,10 @@ function dispatch(eventName, { target, cancelable, detail } = {}) {
|
|
|
317
325
|
return event;
|
|
318
326
|
}
|
|
319
327
|
function nextAnimationFrame() {
|
|
320
|
-
return new Promise(resolve => requestAnimationFrame(() => resolve()));
|
|
328
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
321
329
|
}
|
|
322
330
|
function nextEventLoopTick() {
|
|
323
|
-
return new Promise(resolve => setTimeout(() => resolve(), 0));
|
|
331
|
+
return new Promise((resolve) => setTimeout(() => resolve(), 0));
|
|
324
332
|
}
|
|
325
333
|
function nextMicrotask() {
|
|
326
334
|
return Promise.resolve();
|
|
@@ -332,7 +340,7 @@ function unindent(strings, ...values) {
|
|
|
332
340
|
const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
|
|
333
341
|
const match = lines[0].match(/^\s+/);
|
|
334
342
|
const indent = match ? match[0].length : 0;
|
|
335
|
-
return lines.map(line => line.slice(indent)).join("\n");
|
|
343
|
+
return lines.map((line) => line.slice(indent)).join("\n");
|
|
336
344
|
}
|
|
337
345
|
function interpolate(strings, values) {
|
|
338
346
|
return strings.reduce((result, string, i) => {
|
|
@@ -341,7 +349,8 @@ function interpolate(strings, values) {
|
|
|
341
349
|
}, "");
|
|
342
350
|
}
|
|
343
351
|
function uuid() {
|
|
344
|
-
return Array.
|
|
352
|
+
return Array.from({ length: 36 })
|
|
353
|
+
.map((_, i) => {
|
|
345
354
|
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
|
346
355
|
return "-";
|
|
347
356
|
}
|
|
@@ -354,10 +363,11 @@ function uuid() {
|
|
|
354
363
|
else {
|
|
355
364
|
return Math.floor(Math.random() * 15).toString(16);
|
|
356
365
|
}
|
|
357
|
-
})
|
|
366
|
+
})
|
|
367
|
+
.join("");
|
|
358
368
|
}
|
|
359
369
|
function getAttribute(attributeName, ...elements) {
|
|
360
|
-
for (const value of elements.map(element => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
|
370
|
+
for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
|
361
371
|
if (typeof value == "string")
|
|
362
372
|
return value;
|
|
363
373
|
}
|
|
@@ -379,6 +389,23 @@ function clearBusyState(...elements) {
|
|
|
379
389
|
element.removeAttribute("aria-busy");
|
|
380
390
|
}
|
|
381
391
|
}
|
|
392
|
+
function getMetaElement(name) {
|
|
393
|
+
return document.querySelector(`meta[name="${name}"]`);
|
|
394
|
+
}
|
|
395
|
+
function getMetaContent(name) {
|
|
396
|
+
const element = getMetaElement(name);
|
|
397
|
+
return element && element.content;
|
|
398
|
+
}
|
|
399
|
+
function setMetaContent(name, content) {
|
|
400
|
+
let element = getMetaElement(name);
|
|
401
|
+
if (!element) {
|
|
402
|
+
element = document.createElement("meta");
|
|
403
|
+
element.setAttribute("name", name);
|
|
404
|
+
document.head.appendChild(element);
|
|
405
|
+
}
|
|
406
|
+
element.setAttribute("content", content);
|
|
407
|
+
return element;
|
|
408
|
+
}
|
|
382
409
|
|
|
383
410
|
var FetchMethod;
|
|
384
411
|
(function (FetchMethod) {
|
|
@@ -390,17 +417,22 @@ var FetchMethod;
|
|
|
390
417
|
})(FetchMethod || (FetchMethod = {}));
|
|
391
418
|
function fetchMethodFromString(method) {
|
|
392
419
|
switch (method.toLowerCase()) {
|
|
393
|
-
case "get":
|
|
394
|
-
|
|
395
|
-
case "
|
|
396
|
-
|
|
397
|
-
case "
|
|
420
|
+
case "get":
|
|
421
|
+
return FetchMethod.get;
|
|
422
|
+
case "post":
|
|
423
|
+
return FetchMethod.post;
|
|
424
|
+
case "put":
|
|
425
|
+
return FetchMethod.put;
|
|
426
|
+
case "patch":
|
|
427
|
+
return FetchMethod.patch;
|
|
428
|
+
case "delete":
|
|
429
|
+
return FetchMethod.delete;
|
|
398
430
|
}
|
|
399
431
|
}
|
|
400
432
|
class FetchRequest {
|
|
401
|
-
constructor(delegate, method, location, body = new URLSearchParams, target = null) {
|
|
402
|
-
this.abortController = new AbortController;
|
|
403
|
-
this.resolveRequestPromise = (
|
|
433
|
+
constructor(delegate, method, location, body = new URLSearchParams(), target = null) {
|
|
434
|
+
this.abortController = new AbortController();
|
|
435
|
+
this.resolveRequestPromise = (_value) => { };
|
|
404
436
|
this.delegate = delegate;
|
|
405
437
|
this.method = method;
|
|
406
438
|
this.headers = this.defaultHeaders;
|
|
@@ -431,7 +463,7 @@ class FetchRequest {
|
|
|
431
463
|
return await this.receive(response);
|
|
432
464
|
}
|
|
433
465
|
catch (error) {
|
|
434
|
-
if (error.name !==
|
|
466
|
+
if (error.name !== "AbortError") {
|
|
435
467
|
this.delegate.requestErrored(this, error);
|
|
436
468
|
throw error;
|
|
437
469
|
}
|
|
@@ -442,7 +474,11 @@ class FetchRequest {
|
|
|
442
474
|
}
|
|
443
475
|
async receive(response) {
|
|
444
476
|
const fetchResponse = new FetchResponse(response);
|
|
445
|
-
const event = dispatch("turbo:before-fetch-response", {
|
|
477
|
+
const event = dispatch("turbo:before-fetch-response", {
|
|
478
|
+
cancelable: true,
|
|
479
|
+
detail: { fetchResponse },
|
|
480
|
+
target: this.target,
|
|
481
|
+
});
|
|
446
482
|
if (event.defaultPrevented) {
|
|
447
483
|
this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
|
|
448
484
|
}
|
|
@@ -463,12 +499,12 @@ class FetchRequest {
|
|
|
463
499
|
redirect: "follow",
|
|
464
500
|
body: this.isIdempotent ? null : this.body,
|
|
465
501
|
signal: this.abortSignal,
|
|
466
|
-
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
|
|
502
|
+
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href,
|
|
467
503
|
};
|
|
468
504
|
}
|
|
469
505
|
get defaultHeaders() {
|
|
470
506
|
return {
|
|
471
|
-
|
|
507
|
+
Accept: "text/html, application/xhtml+xml",
|
|
472
508
|
};
|
|
473
509
|
}
|
|
474
510
|
get isIdempotent() {
|
|
@@ -478,15 +514,15 @@ class FetchRequest {
|
|
|
478
514
|
return this.abortController.signal;
|
|
479
515
|
}
|
|
480
516
|
async allowRequestToBeIntercepted(fetchOptions) {
|
|
481
|
-
const requestInterception = new Promise(resolve => this.resolveRequestPromise = resolve);
|
|
517
|
+
const requestInterception = new Promise((resolve) => (this.resolveRequestPromise = resolve));
|
|
482
518
|
const event = dispatch("turbo:before-fetch-request", {
|
|
483
519
|
cancelable: true,
|
|
484
520
|
detail: {
|
|
485
521
|
fetchOptions,
|
|
486
522
|
url: this.url,
|
|
487
|
-
resume: this.resolveRequestPromise
|
|
523
|
+
resume: this.resolveRequestPromise,
|
|
488
524
|
},
|
|
489
|
-
target: this.target
|
|
525
|
+
target: this.target,
|
|
490
526
|
});
|
|
491
527
|
if (event.defaultPrevented)
|
|
492
528
|
await requestInterception;
|
|
@@ -496,7 +532,7 @@ class FetchRequest {
|
|
|
496
532
|
class AppearanceObserver {
|
|
497
533
|
constructor(delegate, element) {
|
|
498
534
|
this.started = false;
|
|
499
|
-
this.intersect = entries => {
|
|
535
|
+
this.intersect = (entries) => {
|
|
500
536
|
const lastEntry = entries.slice(-1)[0];
|
|
501
537
|
if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
|
502
538
|
this.delegate.elementAppearedInViewport(this.element);
|
|
@@ -573,9 +609,12 @@ var FormEnctype;
|
|
|
573
609
|
})(FormEnctype || (FormEnctype = {}));
|
|
574
610
|
function formEnctypeFromString(encoding) {
|
|
575
611
|
switch (encoding.toLowerCase()) {
|
|
576
|
-
case FormEnctype.multipart:
|
|
577
|
-
|
|
578
|
-
|
|
612
|
+
case FormEnctype.multipart:
|
|
613
|
+
return FormEnctype.multipart;
|
|
614
|
+
case FormEnctype.plain:
|
|
615
|
+
return FormEnctype.plain;
|
|
616
|
+
default:
|
|
617
|
+
return FormEnctype.urlEncoded;
|
|
579
618
|
}
|
|
580
619
|
}
|
|
581
620
|
class FormSubmission {
|
|
@@ -592,8 +631,8 @@ class FormSubmission {
|
|
|
592
631
|
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
|
593
632
|
this.mustRedirect = mustRedirect;
|
|
594
633
|
}
|
|
595
|
-
static confirmMethod(message,
|
|
596
|
-
return confirm(message);
|
|
634
|
+
static confirmMethod(message, _element) {
|
|
635
|
+
return Promise.resolve(confirm(message));
|
|
597
636
|
}
|
|
598
637
|
get method() {
|
|
599
638
|
var _a;
|
|
@@ -602,8 +641,13 @@ class FormSubmission {
|
|
|
602
641
|
}
|
|
603
642
|
get action() {
|
|
604
643
|
var _a;
|
|
605
|
-
const formElementAction = typeof this.formElement.action ===
|
|
606
|
-
|
|
644
|
+
const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
|
|
645
|
+
if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
|
|
646
|
+
return this.submitter.getAttribute("formaction") || "";
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
return this.formElement.getAttribute("action") || formElementAction || "";
|
|
650
|
+
}
|
|
607
651
|
}
|
|
608
652
|
get body() {
|
|
609
653
|
if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
|
|
@@ -626,7 +670,8 @@ class FormSubmission {
|
|
|
626
670
|
}, []);
|
|
627
671
|
}
|
|
628
672
|
get confirmationMessage() {
|
|
629
|
-
|
|
673
|
+
var _a;
|
|
674
|
+
return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-confirm")) || this.formElement.getAttribute("data-turbo-confirm");
|
|
630
675
|
}
|
|
631
676
|
get needsConfirmation() {
|
|
632
677
|
return this.confirmationMessage !== null;
|
|
@@ -634,7 +679,7 @@ class FormSubmission {
|
|
|
634
679
|
async start() {
|
|
635
680
|
const { initialized, requesting } = FormSubmissionState;
|
|
636
681
|
if (this.needsConfirmation) {
|
|
637
|
-
const answer = FormSubmission.confirmMethod(this.confirmationMessage, this.formElement);
|
|
682
|
+
const answer = await FormSubmission.confirmMethod(this.confirmationMessage, this.formElement);
|
|
638
683
|
if (!answer) {
|
|
639
684
|
return;
|
|
640
685
|
}
|
|
@@ -658,14 +703,19 @@ class FormSubmission {
|
|
|
658
703
|
if (token) {
|
|
659
704
|
headers["X-CSRF-Token"] = token;
|
|
660
705
|
}
|
|
706
|
+
}
|
|
707
|
+
if (this.requestAcceptsTurboStreamResponse(request)) {
|
|
661
708
|
headers["Accept"] = [StreamMessage.contentType, headers["Accept"]].join(", ");
|
|
662
709
|
}
|
|
663
710
|
}
|
|
664
|
-
requestStarted(
|
|
711
|
+
requestStarted(_request) {
|
|
665
712
|
var _a;
|
|
666
713
|
this.state = FormSubmissionState.waiting;
|
|
667
714
|
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
|
|
668
|
-
dispatch("turbo:submit-start", {
|
|
715
|
+
dispatch("turbo:submit-start", {
|
|
716
|
+
target: this.formElement,
|
|
717
|
+
detail: { formSubmission: this },
|
|
718
|
+
});
|
|
669
719
|
this.delegate.formSubmissionStarted(this);
|
|
670
720
|
}
|
|
671
721
|
requestPreventedHandlingResponse(request, response) {
|
|
@@ -693,16 +743,22 @@ class FormSubmission {
|
|
|
693
743
|
this.result = { success: false, error };
|
|
694
744
|
this.delegate.formSubmissionErrored(this, error);
|
|
695
745
|
}
|
|
696
|
-
requestFinished(
|
|
746
|
+
requestFinished(_request) {
|
|
697
747
|
var _a;
|
|
698
748
|
this.state = FormSubmissionState.stopped;
|
|
699
749
|
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
|
|
700
|
-
dispatch("turbo:submit-end", {
|
|
750
|
+
dispatch("turbo:submit-end", {
|
|
751
|
+
target: this.formElement,
|
|
752
|
+
detail: Object.assign({ formSubmission: this }, this.result),
|
|
753
|
+
});
|
|
701
754
|
this.delegate.formSubmissionFinished(this);
|
|
702
755
|
}
|
|
703
756
|
requestMustRedirect(request) {
|
|
704
757
|
return !request.isIdempotent && this.mustRedirect;
|
|
705
758
|
}
|
|
759
|
+
requestAcceptsTurboStreamResponse(request) {
|
|
760
|
+
return !request.isIdempotent || this.formElement.hasAttribute("data-turbo-stream");
|
|
761
|
+
}
|
|
706
762
|
}
|
|
707
763
|
function buildFormData(formElement, submitter) {
|
|
708
764
|
const formData = new FormData(formElement);
|
|
@@ -723,15 +779,11 @@ function getCookieValue(cookieName) {
|
|
|
723
779
|
}
|
|
724
780
|
}
|
|
725
781
|
}
|
|
726
|
-
function getMetaContent(name) {
|
|
727
|
-
const element = document.querySelector(`meta[name="${name}"]`);
|
|
728
|
-
return element && element.content;
|
|
729
|
-
}
|
|
730
782
|
function responseSucceededWithoutRedirect(response) {
|
|
731
783
|
return response.statusCode == 200 && !response.redirected;
|
|
732
784
|
}
|
|
733
785
|
function mergeFormDataEntries(url, entries) {
|
|
734
|
-
const searchParams = new URLSearchParams;
|
|
786
|
+
const searchParams = new URLSearchParams();
|
|
735
787
|
for (const [name, value] of entries) {
|
|
736
788
|
if (value instanceof File)
|
|
737
789
|
continue;
|
|
@@ -745,6 +797,9 @@ class Snapshot {
|
|
|
745
797
|
constructor(element) {
|
|
746
798
|
this.element = element;
|
|
747
799
|
}
|
|
800
|
+
get activeElement() {
|
|
801
|
+
return this.element.ownerDocument.activeElement;
|
|
802
|
+
}
|
|
748
803
|
get children() {
|
|
749
804
|
return [...this.element.children];
|
|
750
805
|
}
|
|
@@ -783,7 +838,9 @@ class FormInterceptor {
|
|
|
783
838
|
constructor(delegate, element) {
|
|
784
839
|
this.submitBubbled = ((event) => {
|
|
785
840
|
const form = event.target;
|
|
786
|
-
if (!event.defaultPrevented &&
|
|
841
|
+
if (!event.defaultPrevented &&
|
|
842
|
+
form instanceof HTMLFormElement &&
|
|
843
|
+
form.closest("turbo-frame, html") == this.element) {
|
|
787
844
|
const submitter = event.submitter || undefined;
|
|
788
845
|
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.method;
|
|
789
846
|
if (method != "dialog" && this.delegate.shouldInterceptFormSubmission(form, submitter)) {
|
|
@@ -806,8 +863,8 @@ class FormInterceptor {
|
|
|
806
863
|
|
|
807
864
|
class View {
|
|
808
865
|
constructor(delegate, element) {
|
|
809
|
-
this.resolveRenderPromise = (
|
|
810
|
-
this.resolveInterceptionPromise = (
|
|
866
|
+
this.resolveRenderPromise = (_value) => { };
|
|
867
|
+
this.resolveInterceptionPromise = (_value) => { };
|
|
811
868
|
this.delegate = delegate;
|
|
812
869
|
this.element = element;
|
|
813
870
|
}
|
|
@@ -852,15 +909,17 @@ class View {
|
|
|
852
909
|
const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
|
|
853
910
|
if (shouldRender) {
|
|
854
911
|
try {
|
|
855
|
-
this.renderPromise = new Promise(resolve => this.resolveRenderPromise = resolve);
|
|
912
|
+
this.renderPromise = new Promise((resolve) => (this.resolveRenderPromise = resolve));
|
|
856
913
|
this.renderer = renderer;
|
|
857
914
|
this.prepareToRenderSnapshot(renderer);
|
|
858
|
-
const renderInterception = new Promise(resolve => this.resolveInterceptionPromise = resolve);
|
|
859
|
-
const
|
|
915
|
+
const renderInterception = new Promise((resolve) => (this.resolveInterceptionPromise = resolve));
|
|
916
|
+
const options = { resume: this.resolveInterceptionPromise, render: this.renderer.renderElement };
|
|
917
|
+
const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
|
|
860
918
|
if (!immediateRender)
|
|
861
919
|
await renderInterception;
|
|
862
920
|
await this.renderSnapshot(renderer);
|
|
863
921
|
this.delegate.viewRenderedSnapshot(snapshot, isPreview);
|
|
922
|
+
this.delegate.preloadOnLoadLinksForView(this.element);
|
|
864
923
|
this.finishRenderingSnapshot(renderer);
|
|
865
924
|
}
|
|
866
925
|
finally {
|
|
@@ -870,11 +929,11 @@ class View {
|
|
|
870
929
|
}
|
|
871
930
|
}
|
|
872
931
|
else {
|
|
873
|
-
this.invalidate();
|
|
932
|
+
this.invalidate(renderer.reloadReason);
|
|
874
933
|
}
|
|
875
934
|
}
|
|
876
|
-
invalidate() {
|
|
877
|
-
this.delegate.viewInvalidated();
|
|
935
|
+
invalidate(reason) {
|
|
936
|
+
this.delegate.viewInvalidated(reason);
|
|
878
937
|
}
|
|
879
938
|
prepareToRenderSnapshot(renderer) {
|
|
880
939
|
this.markAsPreview(renderer.isPreview);
|
|
@@ -925,9 +984,9 @@ class LinkInterceptor {
|
|
|
925
984
|
}
|
|
926
985
|
delete this.clickEvent;
|
|
927
986
|
});
|
|
928
|
-
this.willVisit = () => {
|
|
987
|
+
this.willVisit = ((_event) => {
|
|
929
988
|
delete this.clickEvent;
|
|
930
|
-
};
|
|
989
|
+
});
|
|
931
990
|
this.delegate = delegate;
|
|
932
991
|
this.element = element;
|
|
933
992
|
}
|
|
@@ -942,28 +1001,65 @@ class LinkInterceptor {
|
|
|
942
1001
|
document.removeEventListener("turbo:before-visit", this.willVisit);
|
|
943
1002
|
}
|
|
944
1003
|
respondsToEventTarget(target) {
|
|
945
|
-
const element = target instanceof Element
|
|
946
|
-
? target
|
|
947
|
-
: target instanceof Node
|
|
948
|
-
? target.parentElement
|
|
949
|
-
: null;
|
|
1004
|
+
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
950
1005
|
return element && element.closest("turbo-frame, html") == this.element;
|
|
951
1006
|
}
|
|
952
1007
|
}
|
|
953
1008
|
|
|
1009
|
+
class FormLinkInterceptor {
|
|
1010
|
+
constructor(delegate, element) {
|
|
1011
|
+
this.delegate = delegate;
|
|
1012
|
+
this.linkInterceptor = new LinkInterceptor(this, element);
|
|
1013
|
+
}
|
|
1014
|
+
start() {
|
|
1015
|
+
this.linkInterceptor.start();
|
|
1016
|
+
}
|
|
1017
|
+
stop() {
|
|
1018
|
+
this.linkInterceptor.stop();
|
|
1019
|
+
}
|
|
1020
|
+
shouldInterceptLinkClick(link) {
|
|
1021
|
+
return (this.delegate.shouldInterceptFormLinkClick(link) &&
|
|
1022
|
+
(link.hasAttribute("data-turbo-method") || link.hasAttribute("data-turbo-stream")));
|
|
1023
|
+
}
|
|
1024
|
+
linkClickIntercepted(link, action) {
|
|
1025
|
+
const form = document.createElement("form");
|
|
1026
|
+
form.setAttribute("data-turbo", "true");
|
|
1027
|
+
form.setAttribute("action", action);
|
|
1028
|
+
form.setAttribute("hidden", "");
|
|
1029
|
+
const method = link.getAttribute("data-turbo-method");
|
|
1030
|
+
if (method)
|
|
1031
|
+
form.setAttribute("method", method);
|
|
1032
|
+
const turboFrame = link.getAttribute("data-turbo-frame");
|
|
1033
|
+
if (turboFrame)
|
|
1034
|
+
form.setAttribute("data-turbo-frame", turboFrame);
|
|
1035
|
+
const turboConfirm = link.getAttribute("data-turbo-confirm");
|
|
1036
|
+
if (turboConfirm)
|
|
1037
|
+
form.setAttribute("data-turbo-confirm", turboConfirm);
|
|
1038
|
+
const turboStream = link.hasAttribute("data-turbo-stream");
|
|
1039
|
+
if (turboStream)
|
|
1040
|
+
form.setAttribute("data-turbo-stream", "");
|
|
1041
|
+
this.delegate.formLinkClickIntercepted(link, form);
|
|
1042
|
+
document.body.appendChild(form);
|
|
1043
|
+
form.requestSubmit();
|
|
1044
|
+
form.remove();
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
954
1048
|
class Bardo {
|
|
955
|
-
constructor(permanentElementMap) {
|
|
1049
|
+
constructor(delegate, permanentElementMap) {
|
|
1050
|
+
this.delegate = delegate;
|
|
956
1051
|
this.permanentElementMap = permanentElementMap;
|
|
957
1052
|
}
|
|
958
|
-
static preservingPermanentElements(permanentElementMap, callback) {
|
|
959
|
-
const bardo = new this(permanentElementMap);
|
|
1053
|
+
static preservingPermanentElements(delegate, permanentElementMap, callback) {
|
|
1054
|
+
const bardo = new this(delegate, permanentElementMap);
|
|
960
1055
|
bardo.enter();
|
|
961
1056
|
callback();
|
|
962
1057
|
bardo.leave();
|
|
963
1058
|
}
|
|
964
1059
|
enter() {
|
|
965
1060
|
for (const id in this.permanentElementMap) {
|
|
966
|
-
const [, newPermanentElement] = this.permanentElementMap[id];
|
|
1061
|
+
const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
|
|
1062
|
+
this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);
|
|
967
1063
|
this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);
|
|
968
1064
|
}
|
|
969
1065
|
}
|
|
@@ -972,6 +1068,7 @@ class Bardo {
|
|
|
972
1068
|
const [currentPermanentElement] = this.permanentElementMap[id];
|
|
973
1069
|
this.replaceCurrentPermanentElementWithClone(currentPermanentElement);
|
|
974
1070
|
this.replacePlaceholderWithPermanentElement(currentPermanentElement);
|
|
1071
|
+
this.delegate.leavingBardo(currentPermanentElement);
|
|
975
1072
|
}
|
|
976
1073
|
}
|
|
977
1074
|
replaceNewPermanentElementWithPlaceholder(permanentElement) {
|
|
@@ -987,7 +1084,7 @@ class Bardo {
|
|
|
987
1084
|
placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);
|
|
988
1085
|
}
|
|
989
1086
|
getPlaceholderById(id) {
|
|
990
|
-
return this.placeholders.find(element => element.content == id);
|
|
1087
|
+
return this.placeholders.find((element) => element.content == id);
|
|
991
1088
|
}
|
|
992
1089
|
get placeholders() {
|
|
993
1090
|
return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")];
|
|
@@ -1001,16 +1098,21 @@ function createPlaceholderForPermanentElement(permanentElement) {
|
|
|
1001
1098
|
}
|
|
1002
1099
|
|
|
1003
1100
|
class Renderer {
|
|
1004
|
-
constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {
|
|
1101
|
+
constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
|
1102
|
+
this.activeElement = null;
|
|
1005
1103
|
this.currentSnapshot = currentSnapshot;
|
|
1006
1104
|
this.newSnapshot = newSnapshot;
|
|
1007
1105
|
this.isPreview = isPreview;
|
|
1008
1106
|
this.willRender = willRender;
|
|
1009
|
-
this.
|
|
1107
|
+
this.renderElement = renderElement;
|
|
1108
|
+
this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));
|
|
1010
1109
|
}
|
|
1011
1110
|
get shouldRender() {
|
|
1012
1111
|
return true;
|
|
1013
1112
|
}
|
|
1113
|
+
get reloadReason() {
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1014
1116
|
prepareToRender() {
|
|
1015
1117
|
return;
|
|
1016
1118
|
}
|
|
@@ -1036,7 +1138,7 @@ class Renderer {
|
|
|
1036
1138
|
}
|
|
1037
1139
|
}
|
|
1038
1140
|
preservingPermanentElements(callback) {
|
|
1039
|
-
Bardo.preservingPermanentElements(this.permanentElementMap, callback);
|
|
1141
|
+
Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
|
|
1040
1142
|
}
|
|
1041
1143
|
focusFirstAutofocusableElement() {
|
|
1042
1144
|
const element = this.connectedSnapshot.firstAutofocusableElement;
|
|
@@ -1044,6 +1146,19 @@ class Renderer {
|
|
|
1044
1146
|
element.focus();
|
|
1045
1147
|
}
|
|
1046
1148
|
}
|
|
1149
|
+
enteringBardo(currentPermanentElement) {
|
|
1150
|
+
if (this.activeElement)
|
|
1151
|
+
return;
|
|
1152
|
+
if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
|
|
1153
|
+
this.activeElement = this.currentSnapshot.activeElement;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
leavingBardo(currentPermanentElement) {
|
|
1157
|
+
if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {
|
|
1158
|
+
this.activeElement.focus();
|
|
1159
|
+
this.activeElement = null;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1047
1162
|
get connectedSnapshot() {
|
|
1048
1163
|
return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;
|
|
1049
1164
|
}
|
|
@@ -1057,8 +1172,7 @@ class Renderer {
|
|
|
1057
1172
|
return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
|
|
1058
1173
|
}
|
|
1059
1174
|
get cspNonce() {
|
|
1060
|
-
|
|
1061
|
-
return (_a = document.head.querySelector('meta[name="csp-nonce"]')) === null || _a === void 0 ? void 0 : _a.getAttribute("content");
|
|
1175
|
+
return getMetaContent("csp-nonce");
|
|
1062
1176
|
}
|
|
1063
1177
|
}
|
|
1064
1178
|
function copyElementAttributes(destinationElement, sourceElement) {
|
|
@@ -1071,6 +1185,22 @@ function elementIsFocusable(element) {
|
|
|
1071
1185
|
}
|
|
1072
1186
|
|
|
1073
1187
|
class FrameRenderer extends Renderer {
|
|
1188
|
+
constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
|
1189
|
+
super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
|
|
1190
|
+
this.delegate = delegate;
|
|
1191
|
+
}
|
|
1192
|
+
static renderElement(currentElement, newElement) {
|
|
1193
|
+
var _a;
|
|
1194
|
+
const destinationRange = document.createRange();
|
|
1195
|
+
destinationRange.selectNodeContents(currentElement);
|
|
1196
|
+
destinationRange.deleteContents();
|
|
1197
|
+
const frameElement = newElement;
|
|
1198
|
+
const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
|
1199
|
+
if (sourceRange) {
|
|
1200
|
+
sourceRange.selectNodeContents(frameElement);
|
|
1201
|
+
currentElement.appendChild(sourceRange.extractContents());
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1074
1204
|
get shouldRender() {
|
|
1075
1205
|
return true;
|
|
1076
1206
|
}
|
|
@@ -1086,23 +1216,16 @@ class FrameRenderer extends Renderer {
|
|
|
1086
1216
|
this.activateScriptElements();
|
|
1087
1217
|
}
|
|
1088
1218
|
loadFrameElement() {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
destinationRange.selectNodeContents(this.currentElement);
|
|
1092
|
-
destinationRange.deleteContents();
|
|
1093
|
-
const frameElement = this.newElement;
|
|
1094
|
-
const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
|
1095
|
-
if (sourceRange) {
|
|
1096
|
-
sourceRange.selectNodeContents(frameElement);
|
|
1097
|
-
this.currentElement.appendChild(sourceRange.extractContents());
|
|
1098
|
-
}
|
|
1219
|
+
this.delegate.frameExtracted(this.newElement.cloneNode(true));
|
|
1220
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
1099
1221
|
}
|
|
1100
1222
|
scrollFrameIntoView() {
|
|
1101
1223
|
if (this.currentElement.autoscroll || this.newElement.autoscroll) {
|
|
1102
1224
|
const element = this.currentElement.firstElementChild;
|
|
1103
1225
|
const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
|
|
1226
|
+
const behavior = readScrollBehavior(this.currentElement.getAttribute("data-autoscroll-behavior"), "auto");
|
|
1104
1227
|
if (element) {
|
|
1105
|
-
element.scrollIntoView({ block });
|
|
1228
|
+
element.scrollIntoView({ block, behavior });
|
|
1106
1229
|
return true;
|
|
1107
1230
|
}
|
|
1108
1231
|
}
|
|
@@ -1126,6 +1249,14 @@ function readScrollLogicalPosition(value, defaultValue) {
|
|
|
1126
1249
|
return defaultValue;
|
|
1127
1250
|
}
|
|
1128
1251
|
}
|
|
1252
|
+
function readScrollBehavior(value, defaultValue) {
|
|
1253
|
+
if (value == "auto" || value == "smooth") {
|
|
1254
|
+
return value;
|
|
1255
|
+
}
|
|
1256
|
+
else {
|
|
1257
|
+
return defaultValue;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1129
1260
|
|
|
1130
1261
|
class ProgressBar {
|
|
1131
1262
|
constructor() {
|
|
@@ -1149,7 +1280,7 @@ class ProgressBar {
|
|
|
1149
1280
|
left: 0;
|
|
1150
1281
|
height: 3px;
|
|
1151
1282
|
background: #0076ff;
|
|
1152
|
-
z-index:
|
|
1283
|
+
z-index: 2147483647;
|
|
1153
1284
|
transition:
|
|
1154
1285
|
width ${ProgressBar.animationDuration}ms ease-out,
|
|
1155
1286
|
opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in;
|
|
@@ -1208,13 +1339,16 @@ class ProgressBar {
|
|
|
1208
1339
|
}
|
|
1209
1340
|
refresh() {
|
|
1210
1341
|
requestAnimationFrame(() => {
|
|
1211
|
-
this.progressElement.style.width = `${10 +
|
|
1342
|
+
this.progressElement.style.width = `${10 + this.value * 90}%`;
|
|
1212
1343
|
});
|
|
1213
1344
|
}
|
|
1214
1345
|
createStylesheetElement() {
|
|
1215
1346
|
const element = document.createElement("style");
|
|
1216
1347
|
element.type = "text/css";
|
|
1217
1348
|
element.textContent = ProgressBar.defaultCSS;
|
|
1349
|
+
if (this.cspNonce) {
|
|
1350
|
+
element.nonce = this.cspNonce;
|
|
1351
|
+
}
|
|
1218
1352
|
return element;
|
|
1219
1353
|
}
|
|
1220
1354
|
createProgressElement() {
|
|
@@ -1222,6 +1356,9 @@ class ProgressBar {
|
|
|
1222
1356
|
element.className = "turbo-progress-bar";
|
|
1223
1357
|
return element;
|
|
1224
1358
|
}
|
|
1359
|
+
get cspNonce() {
|
|
1360
|
+
return getMetaContent("csp-nonce");
|
|
1361
|
+
}
|
|
1225
1362
|
}
|
|
1226
1363
|
ProgressBar.animationDuration = 300;
|
|
1227
1364
|
|
|
@@ -1238,14 +1375,14 @@ class HeadSnapshot extends Snapshot {
|
|
|
1238
1375
|
: {
|
|
1239
1376
|
type: elementType(element),
|
|
1240
1377
|
tracked: elementIsTracked(element),
|
|
1241
|
-
elements: []
|
|
1378
|
+
elements: [],
|
|
1242
1379
|
};
|
|
1243
1380
|
return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });
|
|
1244
1381
|
}, {});
|
|
1245
1382
|
}
|
|
1246
1383
|
get trackedElementSignature() {
|
|
1247
1384
|
return Object.keys(this.detailsByOuterHTML)
|
|
1248
|
-
.filter(outerHTML => this.detailsByOuterHTML[outerHTML].tracked)
|
|
1385
|
+
.filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked)
|
|
1249
1386
|
.join("");
|
|
1250
1387
|
}
|
|
1251
1388
|
getScriptElementsNotInSnapshot(snapshot) {
|
|
@@ -1256,8 +1393,8 @@ class HeadSnapshot extends Snapshot {
|
|
|
1256
1393
|
}
|
|
1257
1394
|
getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
|
|
1258
1395
|
return Object.keys(this.detailsByOuterHTML)
|
|
1259
|
-
.filter(outerHTML => !(outerHTML in snapshot.detailsByOuterHTML))
|
|
1260
|
-
.map(outerHTML => this.detailsByOuterHTML[outerHTML])
|
|
1396
|
+
.filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML))
|
|
1397
|
+
.map((outerHTML) => this.detailsByOuterHTML[outerHTML])
|
|
1261
1398
|
.filter(({ type }) => type == matchedType)
|
|
1262
1399
|
.map(({ elements: [element] }) => element);
|
|
1263
1400
|
}
|
|
@@ -1277,13 +1414,11 @@ class HeadSnapshot extends Snapshot {
|
|
|
1277
1414
|
}
|
|
1278
1415
|
getMetaValue(name) {
|
|
1279
1416
|
const element = this.findMetaElementByName(name);
|
|
1280
|
-
return element
|
|
1281
|
-
? element.getAttribute("content")
|
|
1282
|
-
: null;
|
|
1417
|
+
return element ? element.getAttribute("content") : null;
|
|
1283
1418
|
}
|
|
1284
1419
|
findMetaElementByName(name) {
|
|
1285
1420
|
return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
|
1286
|
-
const { elements: [element] } = this.detailsByOuterHTML[outerHTML];
|
|
1421
|
+
const { elements: [element], } = this.detailsByOuterHTML[outerHTML];
|
|
1287
1422
|
return elementIsMetaElementWithName(element, name) ? element : result;
|
|
1288
1423
|
}, undefined);
|
|
1289
1424
|
}
|
|
@@ -1450,9 +1585,11 @@ class Visit {
|
|
|
1450
1585
|
if (this.state == VisitState.started) {
|
|
1451
1586
|
this.recordTimingMetric(TimingMetric.visitEnd);
|
|
1452
1587
|
this.state = VisitState.completed;
|
|
1453
|
-
this.adapter.visitCompleted(this);
|
|
1454
|
-
this.delegate.visitCompleted(this);
|
|
1455
1588
|
this.followRedirect();
|
|
1589
|
+
if (!this.followedRedirect) {
|
|
1590
|
+
this.adapter.visitCompleted(this);
|
|
1591
|
+
this.delegate.visitCompleted(this);
|
|
1592
|
+
}
|
|
1456
1593
|
}
|
|
1457
1594
|
}
|
|
1458
1595
|
fail() {
|
|
@@ -1514,12 +1651,12 @@ class Visit {
|
|
|
1514
1651
|
if (this.view.renderPromise)
|
|
1515
1652
|
await this.view.renderPromise;
|
|
1516
1653
|
if (isSuccessful(statusCode) && responseHTML != null) {
|
|
1517
|
-
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender);
|
|
1654
|
+
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);
|
|
1518
1655
|
this.adapter.visitRendered(this);
|
|
1519
1656
|
this.complete();
|
|
1520
1657
|
}
|
|
1521
1658
|
else {
|
|
1522
|
-
await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML));
|
|
1659
|
+
await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);
|
|
1523
1660
|
this.adapter.visitRendered(this);
|
|
1524
1661
|
this.fail();
|
|
1525
1662
|
}
|
|
@@ -1554,7 +1691,7 @@ class Visit {
|
|
|
1554
1691
|
else {
|
|
1555
1692
|
if (this.view.renderPromise)
|
|
1556
1693
|
await this.view.renderPromise;
|
|
1557
|
-
await this.view.renderPage(snapshot, isPreview, this.willRender);
|
|
1694
|
+
await this.view.renderPage(snapshot, isPreview, this.willRender, this);
|
|
1558
1695
|
this.adapter.visitRendered(this);
|
|
1559
1696
|
if (!isPreview) {
|
|
1560
1697
|
this.complete();
|
|
@@ -1567,8 +1704,9 @@ class Visit {
|
|
|
1567
1704
|
var _a;
|
|
1568
1705
|
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
|
1569
1706
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
|
1570
|
-
action:
|
|
1571
|
-
|
|
1707
|
+
action: "replace",
|
|
1708
|
+
willRender: false,
|
|
1709
|
+
response: this.response,
|
|
1572
1710
|
});
|
|
1573
1711
|
this.followedRedirect = true;
|
|
1574
1712
|
}
|
|
@@ -1584,13 +1722,15 @@ class Visit {
|
|
|
1584
1722
|
requestStarted() {
|
|
1585
1723
|
this.startRequest();
|
|
1586
1724
|
}
|
|
1587
|
-
requestPreventedHandlingResponse(
|
|
1588
|
-
}
|
|
1725
|
+
requestPreventedHandlingResponse(_request, _response) { }
|
|
1589
1726
|
async requestSucceededWithResponse(request, response) {
|
|
1590
1727
|
const responseHTML = await response.responseHTML;
|
|
1591
1728
|
const { redirected, statusCode } = response;
|
|
1592
1729
|
if (responseHTML == undefined) {
|
|
1593
|
-
this.recordResponse({
|
|
1730
|
+
this.recordResponse({
|
|
1731
|
+
statusCode: SystemStatusCode.contentTypeMismatch,
|
|
1732
|
+
redirected,
|
|
1733
|
+
});
|
|
1594
1734
|
}
|
|
1595
1735
|
else {
|
|
1596
1736
|
this.redirectedToLocation = response.redirected ? response.location : undefined;
|
|
@@ -1601,14 +1741,20 @@ class Visit {
|
|
|
1601
1741
|
const responseHTML = await response.responseHTML;
|
|
1602
1742
|
const { redirected, statusCode } = response;
|
|
1603
1743
|
if (responseHTML == undefined) {
|
|
1604
|
-
this.recordResponse({
|
|
1744
|
+
this.recordResponse({
|
|
1745
|
+
statusCode: SystemStatusCode.contentTypeMismatch,
|
|
1746
|
+
redirected,
|
|
1747
|
+
});
|
|
1605
1748
|
}
|
|
1606
1749
|
else {
|
|
1607
1750
|
this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
|
1608
1751
|
}
|
|
1609
1752
|
}
|
|
1610
|
-
requestErrored(
|
|
1611
|
-
this.recordResponse({
|
|
1753
|
+
requestErrored(_request, _error) {
|
|
1754
|
+
this.recordResponse({
|
|
1755
|
+
statusCode: SystemStatusCode.networkFailure,
|
|
1756
|
+
redirected: false,
|
|
1757
|
+
});
|
|
1612
1758
|
}
|
|
1613
1759
|
requestFinished() {
|
|
1614
1760
|
this.finishRequest();
|
|
@@ -1649,9 +1795,11 @@ class Visit {
|
|
|
1649
1795
|
}
|
|
1650
1796
|
getHistoryMethodForAction(action) {
|
|
1651
1797
|
switch (action) {
|
|
1652
|
-
case "replace":
|
|
1798
|
+
case "replace":
|
|
1799
|
+
return history.replaceState;
|
|
1653
1800
|
case "advance":
|
|
1654
|
-
case "restore":
|
|
1801
|
+
case "restore":
|
|
1802
|
+
return history.pushState;
|
|
1655
1803
|
}
|
|
1656
1804
|
}
|
|
1657
1805
|
hasPreloadedResponse() {
|
|
@@ -1670,18 +1818,20 @@ class Visit {
|
|
|
1670
1818
|
}
|
|
1671
1819
|
cacheSnapshot() {
|
|
1672
1820
|
if (!this.snapshotCached) {
|
|
1673
|
-
this.view.cacheSnapshot().then(snapshot => snapshot && this.visitCachedSnapshot(snapshot));
|
|
1821
|
+
this.view.cacheSnapshot().then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));
|
|
1674
1822
|
this.snapshotCached = true;
|
|
1675
1823
|
}
|
|
1676
1824
|
}
|
|
1677
1825
|
async render(callback) {
|
|
1678
1826
|
this.cancelRender();
|
|
1679
|
-
await new Promise(resolve => {
|
|
1827
|
+
await new Promise((resolve) => {
|
|
1680
1828
|
this.frame = requestAnimationFrame(() => resolve());
|
|
1681
1829
|
});
|
|
1682
1830
|
await callback();
|
|
1683
1831
|
delete this.frame;
|
|
1684
|
-
this.
|
|
1832
|
+
if (!this.view.forceReloaded) {
|
|
1833
|
+
this.performScroll();
|
|
1834
|
+
}
|
|
1685
1835
|
}
|
|
1686
1836
|
cancelRender() {
|
|
1687
1837
|
if (this.frame) {
|
|
@@ -1696,7 +1846,7 @@ function isSuccessful(statusCode) {
|
|
|
1696
1846
|
|
|
1697
1847
|
class BrowserAdapter {
|
|
1698
1848
|
constructor(session) {
|
|
1699
|
-
this.progressBar = new ProgressBar;
|
|
1849
|
+
this.progressBar = new ProgressBar();
|
|
1700
1850
|
this.showProgressBar = () => {
|
|
1701
1851
|
this.progressBar.show();
|
|
1702
1852
|
};
|
|
@@ -1706,9 +1856,9 @@ class BrowserAdapter {
|
|
|
1706
1856
|
this.navigator.startVisit(location, uuid(), options);
|
|
1707
1857
|
}
|
|
1708
1858
|
visitStarted(visit) {
|
|
1859
|
+
this.location = visit.location;
|
|
1709
1860
|
visit.loadCachedSnapshot();
|
|
1710
1861
|
visit.issueRequest();
|
|
1711
|
-
visit.changeHistory();
|
|
1712
1862
|
visit.goToSamePageAnchor();
|
|
1713
1863
|
}
|
|
1714
1864
|
visitRequestStarted(visit) {
|
|
@@ -1728,29 +1878,31 @@ class BrowserAdapter {
|
|
|
1728
1878
|
case SystemStatusCode.networkFailure:
|
|
1729
1879
|
case SystemStatusCode.timeoutFailure:
|
|
1730
1880
|
case SystemStatusCode.contentTypeMismatch:
|
|
1731
|
-
return this.reload(
|
|
1881
|
+
return this.reload({
|
|
1882
|
+
reason: "request_failed",
|
|
1883
|
+
context: {
|
|
1884
|
+
statusCode,
|
|
1885
|
+
},
|
|
1886
|
+
});
|
|
1732
1887
|
default:
|
|
1733
1888
|
return visit.loadResponse();
|
|
1734
1889
|
}
|
|
1735
1890
|
}
|
|
1736
|
-
visitRequestFinished(
|
|
1891
|
+
visitRequestFinished(_visit) {
|
|
1737
1892
|
this.progressBar.setValue(1);
|
|
1738
1893
|
this.hideVisitProgressBar();
|
|
1739
1894
|
}
|
|
1740
|
-
visitCompleted(
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
this.reload();
|
|
1744
|
-
}
|
|
1745
|
-
visitFailed(visit) {
|
|
1895
|
+
visitCompleted(_visit) { }
|
|
1896
|
+
pageInvalidated(reason) {
|
|
1897
|
+
this.reload(reason);
|
|
1746
1898
|
}
|
|
1747
|
-
|
|
1748
|
-
}
|
|
1749
|
-
formSubmissionStarted(
|
|
1899
|
+
visitFailed(_visit) { }
|
|
1900
|
+
visitRendered(_visit) { }
|
|
1901
|
+
formSubmissionStarted(_formSubmission) {
|
|
1750
1902
|
this.progressBar.setValue(0);
|
|
1751
1903
|
this.showFormProgressBarAfterDelay();
|
|
1752
1904
|
}
|
|
1753
|
-
formSubmissionFinished(
|
|
1905
|
+
formSubmissionFinished(_formSubmission) {
|
|
1754
1906
|
this.progressBar.setValue(1);
|
|
1755
1907
|
this.hideFormProgressBar();
|
|
1756
1908
|
}
|
|
@@ -1776,8 +1928,11 @@ class BrowserAdapter {
|
|
|
1776
1928
|
delete this.formProgressBarTimeout;
|
|
1777
1929
|
}
|
|
1778
1930
|
}
|
|
1779
|
-
reload() {
|
|
1780
|
-
|
|
1931
|
+
reload(reason) {
|
|
1932
|
+
dispatch("turbo:reload", { detail: reason });
|
|
1933
|
+
if (!this.location)
|
|
1934
|
+
return;
|
|
1935
|
+
window.location.href = this.location.toString();
|
|
1781
1936
|
}
|
|
1782
1937
|
get navigator() {
|
|
1783
1938
|
return this.session.navigator;
|
|
@@ -1787,6 +1942,12 @@ class BrowserAdapter {
|
|
|
1787
1942
|
class CacheObserver {
|
|
1788
1943
|
constructor() {
|
|
1789
1944
|
this.started = false;
|
|
1945
|
+
this.removeStaleElements = ((_event) => {
|
|
1946
|
+
const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
|
|
1947
|
+
for (const element of staleElements) {
|
|
1948
|
+
element.remove();
|
|
1949
|
+
}
|
|
1950
|
+
});
|
|
1790
1951
|
}
|
|
1791
1952
|
start() {
|
|
1792
1953
|
if (!this.started) {
|
|
@@ -1800,12 +1961,6 @@ class CacheObserver {
|
|
|
1800
1961
|
removeEventListener("turbo:before-cache", this.removeStaleElements, false);
|
|
1801
1962
|
}
|
|
1802
1963
|
}
|
|
1803
|
-
removeStaleElements() {
|
|
1804
|
-
const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
|
|
1805
|
-
for (const element of staleElements) {
|
|
1806
|
-
element.remove();
|
|
1807
|
-
}
|
|
1808
|
-
}
|
|
1809
1964
|
}
|
|
1810
1965
|
|
|
1811
1966
|
class FormSubmitObserver {
|
|
@@ -1819,12 +1974,12 @@ class FormSubmitObserver {
|
|
|
1819
1974
|
if (!event.defaultPrevented) {
|
|
1820
1975
|
const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
|
1821
1976
|
const submitter = event.submitter || undefined;
|
|
1822
|
-
if (form
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1977
|
+
if (form &&
|
|
1978
|
+
submissionDoesNotDismissDialog(form, submitter) &&
|
|
1979
|
+
submissionDoesNotTargetIFrame(form, submitter) &&
|
|
1980
|
+
this.delegate.willSubmitForm(form, submitter)) {
|
|
1981
|
+
event.preventDefault();
|
|
1982
|
+
this.delegate.formSubmitted(form, submitter);
|
|
1828
1983
|
}
|
|
1829
1984
|
}
|
|
1830
1985
|
});
|
|
@@ -1843,6 +1998,18 @@ class FormSubmitObserver {
|
|
|
1843
1998
|
}
|
|
1844
1999
|
}
|
|
1845
2000
|
}
|
|
2001
|
+
function submissionDoesNotDismissDialog(form, submitter) {
|
|
2002
|
+
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
|
|
2003
|
+
return method != "dialog";
|
|
2004
|
+
}
|
|
2005
|
+
function submissionDoesNotTargetIFrame(form, submitter) {
|
|
2006
|
+
const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
|
|
2007
|
+
for (const element of document.getElementsByName(target)) {
|
|
2008
|
+
if (element instanceof HTMLIFrameElement)
|
|
2009
|
+
return false;
|
|
2010
|
+
}
|
|
2011
|
+
return true;
|
|
2012
|
+
}
|
|
1846
2013
|
|
|
1847
2014
|
class FrameRedirector {
|
|
1848
2015
|
constructor(element) {
|
|
@@ -1858,7 +2025,7 @@ class FrameRedirector {
|
|
|
1858
2025
|
this.linkInterceptor.stop();
|
|
1859
2026
|
this.formInterceptor.stop();
|
|
1860
2027
|
}
|
|
1861
|
-
shouldInterceptLinkClick(element,
|
|
2028
|
+
shouldInterceptLinkClick(element, _url) {
|
|
1862
2029
|
return this.shouldRedirect(element);
|
|
1863
2030
|
}
|
|
1864
2031
|
linkClickIntercepted(element, url) {
|
|
@@ -1873,7 +2040,6 @@ class FrameRedirector {
|
|
|
1873
2040
|
formSubmissionIntercepted(element, submitter) {
|
|
1874
2041
|
const frame = this.findFrameElement(element, submitter);
|
|
1875
2042
|
if (frame) {
|
|
1876
|
-
frame.removeAttribute("reloadable");
|
|
1877
2043
|
frame.delegate.formSubmissionIntercepted(element, submitter);
|
|
1878
2044
|
}
|
|
1879
2045
|
}
|
|
@@ -1916,7 +2082,7 @@ class History {
|
|
|
1916
2082
|
}
|
|
1917
2083
|
}
|
|
1918
2084
|
};
|
|
1919
|
-
this.onPageLoad = async (
|
|
2085
|
+
this.onPageLoad = async (_event) => {
|
|
1920
2086
|
await nextMicrotask();
|
|
1921
2087
|
this.pageLoaded = true;
|
|
1922
2088
|
};
|
|
@@ -1989,9 +2155,9 @@ class LinkClickObserver {
|
|
|
1989
2155
|
if (this.clickEventIsSignificant(event)) {
|
|
1990
2156
|
const target = (event.composedPath && event.composedPath()[0]) || event.target;
|
|
1991
2157
|
const link = this.findLinkFromClickTarget(target);
|
|
1992
|
-
if (link) {
|
|
2158
|
+
if (link && doesNotTargetIFrame(link)) {
|
|
1993
2159
|
const location = this.getLocationForLink(link);
|
|
1994
|
-
if (this.delegate.willFollowLinkToLocation(link, location)) {
|
|
2160
|
+
if (this.delegate.willFollowLinkToLocation(link, location, event)) {
|
|
1995
2161
|
event.preventDefault();
|
|
1996
2162
|
this.delegate.followedLinkToLocation(link, location);
|
|
1997
2163
|
}
|
|
@@ -2013,13 +2179,13 @@ class LinkClickObserver {
|
|
|
2013
2179
|
}
|
|
2014
2180
|
}
|
|
2015
2181
|
clickEventIsSignificant(event) {
|
|
2016
|
-
return !((event.target && event.target.isContentEditable)
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2182
|
+
return !((event.target && event.target.isContentEditable) ||
|
|
2183
|
+
event.defaultPrevented ||
|
|
2184
|
+
event.which > 1 ||
|
|
2185
|
+
event.altKey ||
|
|
2186
|
+
event.ctrlKey ||
|
|
2187
|
+
event.metaKey ||
|
|
2188
|
+
event.shiftKey);
|
|
2023
2189
|
}
|
|
2024
2190
|
findLinkFromClickTarget(target) {
|
|
2025
2191
|
if (target instanceof Element) {
|
|
@@ -2030,6 +2196,13 @@ class LinkClickObserver {
|
|
|
2030
2196
|
return expandURL(link.getAttribute("href") || "");
|
|
2031
2197
|
}
|
|
2032
2198
|
}
|
|
2199
|
+
function doesNotTargetIFrame(anchor) {
|
|
2200
|
+
for (const element of document.getElementsByName(anchor.target)) {
|
|
2201
|
+
if (element instanceof HTMLIFrameElement)
|
|
2202
|
+
return false;
|
|
2203
|
+
}
|
|
2204
|
+
return true;
|
|
2205
|
+
}
|
|
2033
2206
|
|
|
2034
2207
|
function isAction(action) {
|
|
2035
2208
|
return action == "advance" || action == "replace" || action == "restore";
|
|
@@ -2050,6 +2223,7 @@ class Navigator {
|
|
|
2050
2223
|
}
|
|
2051
2224
|
}
|
|
2052
2225
|
startVisit(locatable, restorationIdentifier, options = {}) {
|
|
2226
|
+
this.lastVisit = this.currentVisit;
|
|
2053
2227
|
this.stop();
|
|
2054
2228
|
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));
|
|
2055
2229
|
this.currentVisit.start();
|
|
@@ -2079,7 +2253,7 @@ class Navigator {
|
|
|
2079
2253
|
return this.delegate.history;
|
|
2080
2254
|
}
|
|
2081
2255
|
formSubmissionStarted(formSubmission) {
|
|
2082
|
-
if (typeof this.adapter.formSubmissionStarted ===
|
|
2256
|
+
if (typeof this.adapter.formSubmissionStarted === "function") {
|
|
2083
2257
|
this.adapter.formSubmissionStarted(formSubmission);
|
|
2084
2258
|
}
|
|
2085
2259
|
}
|
|
@@ -2092,7 +2266,10 @@ class Navigator {
|
|
|
2092
2266
|
}
|
|
2093
2267
|
const { statusCode, redirected } = fetchResponse;
|
|
2094
2268
|
const action = this.getActionForFormSubmission(formSubmission);
|
|
2095
|
-
const visitOptions = {
|
|
2269
|
+
const visitOptions = {
|
|
2270
|
+
action,
|
|
2271
|
+
response: { statusCode, responseHTML, redirected },
|
|
2272
|
+
};
|
|
2096
2273
|
this.proposeVisit(fetchResponse.location, visitOptions);
|
|
2097
2274
|
}
|
|
2098
2275
|
}
|
|
@@ -2102,10 +2279,10 @@ class Navigator {
|
|
|
2102
2279
|
if (responseHTML) {
|
|
2103
2280
|
const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
|
2104
2281
|
if (fetchResponse.serverError) {
|
|
2105
|
-
await this.view.renderError(snapshot);
|
|
2282
|
+
await this.view.renderError(snapshot, this.currentVisit);
|
|
2106
2283
|
}
|
|
2107
2284
|
else {
|
|
2108
|
-
await this.view.renderPage(snapshot);
|
|
2285
|
+
await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
|
2109
2286
|
}
|
|
2110
2287
|
this.view.scrollToTop();
|
|
2111
2288
|
this.view.clearSnapshotCache();
|
|
@@ -2115,7 +2292,7 @@ class Navigator {
|
|
|
2115
2292
|
console.error(error);
|
|
2116
2293
|
}
|
|
2117
2294
|
formSubmissionFinished(formSubmission) {
|
|
2118
|
-
if (typeof this.adapter.formSubmissionFinished ===
|
|
2295
|
+
if (typeof this.adapter.formSubmissionFinished === "function") {
|
|
2119
2296
|
this.adapter.formSubmissionFinished(formSubmission);
|
|
2120
2297
|
}
|
|
2121
2298
|
}
|
|
@@ -2126,12 +2303,14 @@ class Navigator {
|
|
|
2126
2303
|
this.delegate.visitCompleted(visit);
|
|
2127
2304
|
}
|
|
2128
2305
|
locationWithActionIsSamePage(location, action) {
|
|
2306
|
+
var _a;
|
|
2129
2307
|
const anchor = getAnchor(location);
|
|
2130
|
-
const
|
|
2131
|
-
const
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
(
|
|
2308
|
+
const lastLocation = ((_a = this.lastVisit) === null || _a === void 0 ? void 0 : _a.location) || this.view.lastRenderedLocation;
|
|
2309
|
+
const currentAnchor = getAnchor(lastLocation);
|
|
2310
|
+
const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
|
2311
|
+
return (action !== "replace" &&
|
|
2312
|
+
getRequestURL(location) === getRequestURL(lastLocation) &&
|
|
2313
|
+
(isRestorationToTop || (anchor != null && anchor !== currentAnchor)));
|
|
2135
2314
|
}
|
|
2136
2315
|
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
2137
2316
|
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
|
@@ -2237,7 +2416,7 @@ class ScrollObserver {
|
|
|
2237
2416
|
|
|
2238
2417
|
class StreamObserver {
|
|
2239
2418
|
constructor(delegate) {
|
|
2240
|
-
this.sources = new Set;
|
|
2419
|
+
this.sources = new Set();
|
|
2241
2420
|
this.started = false;
|
|
2242
2421
|
this.inspectFetchResponse = ((event) => {
|
|
2243
2422
|
const response = fetchResponseFromEvent(event);
|
|
@@ -2304,14 +2483,18 @@ function fetchResponseIsStream(response) {
|
|
|
2304
2483
|
}
|
|
2305
2484
|
|
|
2306
2485
|
class ErrorRenderer extends Renderer {
|
|
2486
|
+
static renderElement(currentElement, newElement) {
|
|
2487
|
+
const { documentElement, body } = document;
|
|
2488
|
+
documentElement.replaceChild(newElement, body);
|
|
2489
|
+
}
|
|
2307
2490
|
async render() {
|
|
2308
2491
|
this.replaceHeadAndBody();
|
|
2309
2492
|
this.activateScriptElements();
|
|
2310
2493
|
}
|
|
2311
2494
|
replaceHeadAndBody() {
|
|
2312
|
-
const { documentElement, head
|
|
2495
|
+
const { documentElement, head } = document;
|
|
2313
2496
|
documentElement.replaceChild(this.newHead, head);
|
|
2314
|
-
|
|
2497
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
2315
2498
|
}
|
|
2316
2499
|
activateScriptElements() {
|
|
2317
2500
|
for (const replaceableElement of this.scriptElements) {
|
|
@@ -2331,9 +2514,29 @@ class ErrorRenderer extends Renderer {
|
|
|
2331
2514
|
}
|
|
2332
2515
|
|
|
2333
2516
|
class PageRenderer extends Renderer {
|
|
2517
|
+
static renderElement(currentElement, newElement) {
|
|
2518
|
+
if (document.body && newElement instanceof HTMLBodyElement) {
|
|
2519
|
+
document.body.replaceWith(newElement);
|
|
2520
|
+
}
|
|
2521
|
+
else {
|
|
2522
|
+
document.documentElement.appendChild(newElement);
|
|
2523
|
+
}
|
|
2524
|
+
}
|
|
2334
2525
|
get shouldRender() {
|
|
2335
2526
|
return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
|
|
2336
2527
|
}
|
|
2528
|
+
get reloadReason() {
|
|
2529
|
+
if (!this.newSnapshot.isVisitable) {
|
|
2530
|
+
return {
|
|
2531
|
+
reason: "turbo_visit_control_is_reload",
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
if (!this.trackedElementsAreIdentical) {
|
|
2535
|
+
return {
|
|
2536
|
+
reason: "tracked_element_mismatch",
|
|
2537
|
+
};
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2337
2540
|
prepareToRender() {
|
|
2338
2541
|
this.mergeHead();
|
|
2339
2542
|
}
|
|
@@ -2403,12 +2606,7 @@ class PageRenderer extends Renderer {
|
|
|
2403
2606
|
}
|
|
2404
2607
|
}
|
|
2405
2608
|
assignNewBody() {
|
|
2406
|
-
|
|
2407
|
-
document.body.replaceWith(this.newElement);
|
|
2408
|
-
}
|
|
2409
|
-
else {
|
|
2410
|
-
document.documentElement.appendChild(this.newElement);
|
|
2411
|
-
}
|
|
2609
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
2412
2610
|
}
|
|
2413
2611
|
get newHeadStylesheetElements() {
|
|
2414
2612
|
return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
|
@@ -2477,13 +2675,21 @@ class PageView extends View {
|
|
|
2477
2675
|
super(...arguments);
|
|
2478
2676
|
this.snapshotCache = new SnapshotCache(10);
|
|
2479
2677
|
this.lastRenderedLocation = new URL(location.href);
|
|
2678
|
+
this.forceReloaded = false;
|
|
2480
2679
|
}
|
|
2481
|
-
renderPage(snapshot, isPreview = false, willRender = true) {
|
|
2482
|
-
const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender);
|
|
2680
|
+
renderPage(snapshot, isPreview = false, willRender = true, visit) {
|
|
2681
|
+
const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
|
|
2682
|
+
if (!renderer.shouldRender) {
|
|
2683
|
+
this.forceReloaded = true;
|
|
2684
|
+
}
|
|
2685
|
+
else {
|
|
2686
|
+
visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
|
2687
|
+
}
|
|
2483
2688
|
return this.render(renderer);
|
|
2484
2689
|
}
|
|
2485
|
-
renderError(snapshot) {
|
|
2486
|
-
|
|
2690
|
+
renderError(snapshot, visit) {
|
|
2691
|
+
visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
|
2692
|
+
const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
|
|
2487
2693
|
return this.render(renderer);
|
|
2488
2694
|
}
|
|
2489
2695
|
clearSnapshotCache() {
|
|
@@ -2510,10 +2716,50 @@ class PageView extends View {
|
|
|
2510
2716
|
}
|
|
2511
2717
|
}
|
|
2512
2718
|
|
|
2719
|
+
class Preloader {
|
|
2720
|
+
constructor(delegate) {
|
|
2721
|
+
this.selector = "a[data-turbo-preload]";
|
|
2722
|
+
this.delegate = delegate;
|
|
2723
|
+
}
|
|
2724
|
+
get snapshotCache() {
|
|
2725
|
+
return this.delegate.navigator.view.snapshotCache;
|
|
2726
|
+
}
|
|
2727
|
+
start() {
|
|
2728
|
+
if (document.readyState === "loading") {
|
|
2729
|
+
return document.addEventListener("DOMContentLoaded", () => {
|
|
2730
|
+
this.preloadOnLoadLinksForView(document.body);
|
|
2731
|
+
});
|
|
2732
|
+
}
|
|
2733
|
+
else {
|
|
2734
|
+
this.preloadOnLoadLinksForView(document.body);
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
preloadOnLoadLinksForView(element) {
|
|
2738
|
+
for (const link of element.querySelectorAll(this.selector)) {
|
|
2739
|
+
this.preloadURL(link);
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
async preloadURL(link) {
|
|
2743
|
+
const location = new URL(link.href);
|
|
2744
|
+
if (this.snapshotCache.has(location)) {
|
|
2745
|
+
return;
|
|
2746
|
+
}
|
|
2747
|
+
try {
|
|
2748
|
+
const response = await fetch(location.toString(), { headers: { "VND.PREFETCH": "true", Accept: "text/html" } });
|
|
2749
|
+
const responseText = await response.text();
|
|
2750
|
+
const snapshot = PageSnapshot.fromHTMLString(responseText);
|
|
2751
|
+
this.snapshotCache.put(location, snapshot);
|
|
2752
|
+
}
|
|
2753
|
+
catch (_) {
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
|
|
2513
2758
|
class Session {
|
|
2514
2759
|
constructor() {
|
|
2515
2760
|
this.navigator = new Navigator(this);
|
|
2516
2761
|
this.history = new History(this);
|
|
2762
|
+
this.preloader = new Preloader(this);
|
|
2517
2763
|
this.view = new PageView(this, document.documentElement);
|
|
2518
2764
|
this.adapter = new BrowserAdapter(this);
|
|
2519
2765
|
this.pageObserver = new PageObserver(this);
|
|
@@ -2522,22 +2768,26 @@ class Session {
|
|
|
2522
2768
|
this.formSubmitObserver = new FormSubmitObserver(this);
|
|
2523
2769
|
this.scrollObserver = new ScrollObserver(this);
|
|
2524
2770
|
this.streamObserver = new StreamObserver(this);
|
|
2771
|
+
this.formLinkInterceptor = new FormLinkInterceptor(this, document.documentElement);
|
|
2525
2772
|
this.frameRedirector = new FrameRedirector(document.documentElement);
|
|
2526
2773
|
this.drive = true;
|
|
2527
2774
|
this.enabled = true;
|
|
2528
2775
|
this.progressBarDelay = 500;
|
|
2529
2776
|
this.started = false;
|
|
2777
|
+
this.formMode = "on";
|
|
2530
2778
|
}
|
|
2531
2779
|
start() {
|
|
2532
2780
|
if (!this.started) {
|
|
2533
2781
|
this.pageObserver.start();
|
|
2534
2782
|
this.cacheObserver.start();
|
|
2783
|
+
this.formLinkInterceptor.start();
|
|
2535
2784
|
this.linkClickObserver.start();
|
|
2536
2785
|
this.formSubmitObserver.start();
|
|
2537
2786
|
this.scrollObserver.start();
|
|
2538
2787
|
this.streamObserver.start();
|
|
2539
2788
|
this.frameRedirector.start();
|
|
2540
2789
|
this.history.start();
|
|
2790
|
+
this.preloader.start();
|
|
2541
2791
|
this.started = true;
|
|
2542
2792
|
this.enabled = true;
|
|
2543
2793
|
}
|
|
@@ -2549,6 +2799,7 @@ class Session {
|
|
|
2549
2799
|
if (this.started) {
|
|
2550
2800
|
this.pageObserver.stop();
|
|
2551
2801
|
this.cacheObserver.stop();
|
|
2802
|
+
this.formLinkInterceptor.stop();
|
|
2552
2803
|
this.linkClickObserver.stop();
|
|
2553
2804
|
this.formSubmitObserver.stop();
|
|
2554
2805
|
this.scrollObserver.stop();
|
|
@@ -2579,6 +2830,9 @@ class Session {
|
|
|
2579
2830
|
setProgressBarDelay(delay) {
|
|
2580
2831
|
this.progressBarDelay = delay;
|
|
2581
2832
|
}
|
|
2833
|
+
setFormMode(mode) {
|
|
2834
|
+
this.formMode = mode;
|
|
2835
|
+
}
|
|
2582
2836
|
get location() {
|
|
2583
2837
|
return this.history.location;
|
|
2584
2838
|
}
|
|
@@ -2587,48 +2841,32 @@ class Session {
|
|
|
2587
2841
|
}
|
|
2588
2842
|
historyPoppedToLocationWithRestorationIdentifier(location, restorationIdentifier) {
|
|
2589
2843
|
if (this.enabled) {
|
|
2590
|
-
this.navigator.startVisit(location, restorationIdentifier, {
|
|
2844
|
+
this.navigator.startVisit(location, restorationIdentifier, {
|
|
2845
|
+
action: "restore",
|
|
2846
|
+
historyChanged: true,
|
|
2847
|
+
});
|
|
2591
2848
|
}
|
|
2592
2849
|
else {
|
|
2593
|
-
this.adapter.pageInvalidated(
|
|
2850
|
+
this.adapter.pageInvalidated({
|
|
2851
|
+
reason: "turbo_disabled",
|
|
2852
|
+
});
|
|
2594
2853
|
}
|
|
2595
2854
|
}
|
|
2596
2855
|
scrollPositionChanged(position) {
|
|
2597
2856
|
this.history.updateRestorationData({ scrollPosition: position });
|
|
2598
2857
|
}
|
|
2599
|
-
|
|
2600
|
-
return
|
|
2601
|
-
|
|
2602
|
-
|
|
2858
|
+
shouldInterceptFormLinkClick(_link) {
|
|
2859
|
+
return true;
|
|
2860
|
+
}
|
|
2861
|
+
formLinkClickIntercepted(_link, _form) { }
|
|
2862
|
+
willFollowLinkToLocation(link, location, event) {
|
|
2863
|
+
return (this.elementDriveEnabled(link) &&
|
|
2864
|
+
locationIsVisitable(location, this.snapshot.rootLocation) &&
|
|
2865
|
+
this.applicationAllowsFollowingLinkToLocation(link, location, event));
|
|
2603
2866
|
}
|
|
2604
2867
|
followedLinkToLocation(link, location) {
|
|
2605
2868
|
const action = this.getActionForLink(link);
|
|
2606
|
-
this.
|
|
2607
|
-
}
|
|
2608
|
-
convertLinkWithMethodClickToFormSubmission(link) {
|
|
2609
|
-
const linkMethod = link.getAttribute("data-turbo-method");
|
|
2610
|
-
if (linkMethod) {
|
|
2611
|
-
const form = document.createElement("form");
|
|
2612
|
-
form.method = linkMethod;
|
|
2613
|
-
form.action = link.getAttribute("href") || "undefined";
|
|
2614
|
-
form.hidden = true;
|
|
2615
|
-
if (link.hasAttribute("data-turbo-confirm")) {
|
|
2616
|
-
form.setAttribute("data-turbo-confirm", link.getAttribute("data-turbo-confirm"));
|
|
2617
|
-
}
|
|
2618
|
-
const frame = this.getTargetFrameForLink(link);
|
|
2619
|
-
if (frame) {
|
|
2620
|
-
form.setAttribute("data-turbo-frame", frame);
|
|
2621
|
-
form.addEventListener("turbo:submit-start", () => form.remove());
|
|
2622
|
-
}
|
|
2623
|
-
else {
|
|
2624
|
-
form.addEventListener("submit", () => form.remove());
|
|
2625
|
-
}
|
|
2626
|
-
document.body.appendChild(form);
|
|
2627
|
-
return dispatch("submit", { cancelable: true, target: form });
|
|
2628
|
-
}
|
|
2629
|
-
else {
|
|
2630
|
-
return false;
|
|
2631
|
-
}
|
|
2869
|
+
this.visit(location.href, { action });
|
|
2632
2870
|
}
|
|
2633
2871
|
allowsVisitingLocationWithAction(location, action) {
|
|
2634
2872
|
return this.locationWithActionIsSamePage(location, action) || this.applicationAllowsVisitingLocation(location);
|
|
@@ -2654,9 +2892,9 @@ class Session {
|
|
|
2654
2892
|
}
|
|
2655
2893
|
willSubmitForm(form, submitter) {
|
|
2656
2894
|
const action = getAction(form, submitter);
|
|
2657
|
-
return this.elementDriveEnabled(form)
|
|
2658
|
-
|
|
2659
|
-
|
|
2895
|
+
return (this.elementDriveEnabled(form) &&
|
|
2896
|
+
(!submitter || this.formElementDriveEnabled(submitter)) &&
|
|
2897
|
+
locationIsVisitable(expandURL(action), this.snapshot.rootLocation));
|
|
2660
2898
|
}
|
|
2661
2899
|
formSubmitted(form, submitter) {
|
|
2662
2900
|
this.navigator.submitForm(form, submitter);
|
|
@@ -2680,16 +2918,23 @@ class Session {
|
|
|
2680
2918
|
this.notifyApplicationBeforeCachingSnapshot();
|
|
2681
2919
|
}
|
|
2682
2920
|
}
|
|
2683
|
-
allowsImmediateRender({ element },
|
|
2684
|
-
const event = this.notifyApplicationBeforeRender(element,
|
|
2685
|
-
|
|
2921
|
+
allowsImmediateRender({ element }, options) {
|
|
2922
|
+
const event = this.notifyApplicationBeforeRender(element, options);
|
|
2923
|
+
const { defaultPrevented, detail: { render }, } = event;
|
|
2924
|
+
if (this.view.renderer && render) {
|
|
2925
|
+
this.view.renderer.renderElement = render;
|
|
2926
|
+
}
|
|
2927
|
+
return !defaultPrevented;
|
|
2686
2928
|
}
|
|
2687
|
-
viewRenderedSnapshot(
|
|
2929
|
+
viewRenderedSnapshot(_snapshot, _isPreview) {
|
|
2688
2930
|
this.view.lastRenderedLocation = this.history.location;
|
|
2689
2931
|
this.notifyApplicationAfterRender();
|
|
2690
2932
|
}
|
|
2691
|
-
|
|
2692
|
-
this.
|
|
2933
|
+
preloadOnLoadLinksForView(element) {
|
|
2934
|
+
this.preloader.preloadOnLoadLinksForView(element);
|
|
2935
|
+
}
|
|
2936
|
+
viewInvalidated(reason) {
|
|
2937
|
+
this.adapter.pageInvalidated(reason);
|
|
2693
2938
|
}
|
|
2694
2939
|
frameLoaded(frame) {
|
|
2695
2940
|
this.notifyApplicationAfterFrameLoad(frame);
|
|
@@ -2697,19 +2942,26 @@ class Session {
|
|
|
2697
2942
|
frameRendered(fetchResponse, frame) {
|
|
2698
2943
|
this.notifyApplicationAfterFrameRender(fetchResponse, frame);
|
|
2699
2944
|
}
|
|
2700
|
-
applicationAllowsFollowingLinkToLocation(link, location) {
|
|
2701
|
-
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location);
|
|
2945
|
+
applicationAllowsFollowingLinkToLocation(link, location, ev) {
|
|
2946
|
+
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location, ev);
|
|
2702
2947
|
return !event.defaultPrevented;
|
|
2703
2948
|
}
|
|
2704
2949
|
applicationAllowsVisitingLocation(location) {
|
|
2705
2950
|
const event = this.notifyApplicationBeforeVisitingLocation(location);
|
|
2706
2951
|
return !event.defaultPrevented;
|
|
2707
2952
|
}
|
|
2708
|
-
notifyApplicationAfterClickingLinkToLocation(link, location) {
|
|
2709
|
-
return dispatch("turbo:click", {
|
|
2953
|
+
notifyApplicationAfterClickingLinkToLocation(link, location, event) {
|
|
2954
|
+
return dispatch("turbo:click", {
|
|
2955
|
+
target: link,
|
|
2956
|
+
detail: { url: location.href, originalEvent: event },
|
|
2957
|
+
cancelable: true,
|
|
2958
|
+
});
|
|
2710
2959
|
}
|
|
2711
2960
|
notifyApplicationBeforeVisitingLocation(location) {
|
|
2712
|
-
return dispatch("turbo:before-visit", {
|
|
2961
|
+
return dispatch("turbo:before-visit", {
|
|
2962
|
+
detail: { url: location.href },
|
|
2963
|
+
cancelable: true,
|
|
2964
|
+
});
|
|
2713
2965
|
}
|
|
2714
2966
|
notifyApplicationAfterVisitingLocation(location, action) {
|
|
2715
2967
|
markAsBusy(document.documentElement);
|
|
@@ -2718,24 +2970,46 @@ class Session {
|
|
|
2718
2970
|
notifyApplicationBeforeCachingSnapshot() {
|
|
2719
2971
|
return dispatch("turbo:before-cache");
|
|
2720
2972
|
}
|
|
2721
|
-
notifyApplicationBeforeRender(newBody,
|
|
2722
|
-
return dispatch("turbo:before-render", {
|
|
2973
|
+
notifyApplicationBeforeRender(newBody, options) {
|
|
2974
|
+
return dispatch("turbo:before-render", {
|
|
2975
|
+
detail: Object.assign({ newBody }, options),
|
|
2976
|
+
cancelable: true,
|
|
2977
|
+
});
|
|
2723
2978
|
}
|
|
2724
2979
|
notifyApplicationAfterRender() {
|
|
2725
2980
|
return dispatch("turbo:render");
|
|
2726
2981
|
}
|
|
2727
2982
|
notifyApplicationAfterPageLoad(timing = {}) {
|
|
2728
2983
|
clearBusyState(document.documentElement);
|
|
2729
|
-
return dispatch("turbo:load", {
|
|
2984
|
+
return dispatch("turbo:load", {
|
|
2985
|
+
detail: { url: this.location.href, timing },
|
|
2986
|
+
});
|
|
2730
2987
|
}
|
|
2731
2988
|
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
|
2732
|
-
dispatchEvent(new HashChangeEvent("hashchange", {
|
|
2989
|
+
dispatchEvent(new HashChangeEvent("hashchange", {
|
|
2990
|
+
oldURL: oldURL.toString(),
|
|
2991
|
+
newURL: newURL.toString(),
|
|
2992
|
+
}));
|
|
2733
2993
|
}
|
|
2734
2994
|
notifyApplicationAfterFrameLoad(frame) {
|
|
2735
2995
|
return dispatch("turbo:frame-load", { target: frame });
|
|
2736
2996
|
}
|
|
2737
2997
|
notifyApplicationAfterFrameRender(fetchResponse, frame) {
|
|
2738
|
-
return dispatch("turbo:frame-render", {
|
|
2998
|
+
return dispatch("turbo:frame-render", {
|
|
2999
|
+
detail: { fetchResponse },
|
|
3000
|
+
target: frame,
|
|
3001
|
+
cancelable: true,
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
formElementDriveEnabled(element) {
|
|
3005
|
+
if (this.formMode == "off") {
|
|
3006
|
+
return false;
|
|
3007
|
+
}
|
|
3008
|
+
if (this.formMode == "optin") {
|
|
3009
|
+
const form = element === null || element === void 0 ? void 0 : element.closest("form[data-turbo]");
|
|
3010
|
+
return (form === null || form === void 0 ? void 0 : form.getAttribute("data-turbo")) == "true";
|
|
3011
|
+
}
|
|
3012
|
+
return this.elementDriveEnabled(element);
|
|
2739
3013
|
}
|
|
2740
3014
|
elementDriveEnabled(element) {
|
|
2741
3015
|
const container = element === null || element === void 0 ? void 0 : element.closest("[data-turbo]");
|
|
@@ -2760,18 +3034,6 @@ class Session {
|
|
|
2760
3034
|
const action = link.getAttribute("data-turbo-action");
|
|
2761
3035
|
return isAction(action) ? action : "advance";
|
|
2762
3036
|
}
|
|
2763
|
-
getTargetFrameForLink(link) {
|
|
2764
|
-
const frame = link.getAttribute("data-turbo-frame");
|
|
2765
|
-
if (frame) {
|
|
2766
|
-
return frame;
|
|
2767
|
-
}
|
|
2768
|
-
else {
|
|
2769
|
-
const container = link.closest("turbo-frame");
|
|
2770
|
-
if (container) {
|
|
2771
|
-
return container.id;
|
|
2772
|
-
}
|
|
2773
|
-
}
|
|
2774
|
-
}
|
|
2775
3037
|
get snapshot() {
|
|
2776
3038
|
return this.view.snapshot;
|
|
2777
3039
|
}
|
|
@@ -2783,11 +3045,59 @@ const deprecatedLocationPropertyDescriptors = {
|
|
|
2783
3045
|
absoluteURL: {
|
|
2784
3046
|
get() {
|
|
2785
3047
|
return this.toString();
|
|
2786
|
-
}
|
|
3048
|
+
},
|
|
3049
|
+
},
|
|
3050
|
+
};
|
|
3051
|
+
|
|
3052
|
+
class Cache {
|
|
3053
|
+
constructor(session) {
|
|
3054
|
+
this.session = session;
|
|
2787
3055
|
}
|
|
3056
|
+
clear() {
|
|
3057
|
+
this.session.clearCache();
|
|
3058
|
+
}
|
|
3059
|
+
resetCacheControl() {
|
|
3060
|
+
this.setCacheControl("");
|
|
3061
|
+
}
|
|
3062
|
+
exemptPageFromCache() {
|
|
3063
|
+
this.setCacheControl("no-cache");
|
|
3064
|
+
}
|
|
3065
|
+
exemptPageFromPreview() {
|
|
3066
|
+
this.setCacheControl("no-preview");
|
|
3067
|
+
}
|
|
3068
|
+
setCacheControl(value) {
|
|
3069
|
+
setMetaContent("turbo-cache-control", value);
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
const StreamActions = {
|
|
3074
|
+
after() {
|
|
3075
|
+
this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });
|
|
3076
|
+
},
|
|
3077
|
+
append() {
|
|
3078
|
+
this.removeDuplicateTargetChildren();
|
|
3079
|
+
this.targetElements.forEach((e) => e.append(this.templateContent));
|
|
3080
|
+
},
|
|
3081
|
+
before() {
|
|
3082
|
+
this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });
|
|
3083
|
+
},
|
|
3084
|
+
prepend() {
|
|
3085
|
+
this.removeDuplicateTargetChildren();
|
|
3086
|
+
this.targetElements.forEach((e) => e.prepend(this.templateContent));
|
|
3087
|
+
},
|
|
3088
|
+
remove() {
|
|
3089
|
+
this.targetElements.forEach((e) => e.remove());
|
|
3090
|
+
},
|
|
3091
|
+
replace() {
|
|
3092
|
+
this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
|
|
3093
|
+
},
|
|
3094
|
+
update() {
|
|
3095
|
+
this.targetElements.forEach((e) => e.replaceChildren(this.templateContent));
|
|
3096
|
+
},
|
|
2788
3097
|
};
|
|
2789
3098
|
|
|
2790
|
-
const session = new Session;
|
|
3099
|
+
const session = new Session();
|
|
3100
|
+
const cache = new Cache(session);
|
|
2791
3101
|
const { navigator: navigator$1 } = session;
|
|
2792
3102
|
function start() {
|
|
2793
3103
|
session.start();
|
|
@@ -2808,6 +3118,7 @@ function renderStreamMessage(message) {
|
|
|
2808
3118
|
session.renderStreamMessage(message);
|
|
2809
3119
|
}
|
|
2810
3120
|
function clearCache() {
|
|
3121
|
+
console.warn("Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`");
|
|
2811
3122
|
session.clearCache();
|
|
2812
3123
|
}
|
|
2813
3124
|
function setProgressBarDelay(delay) {
|
|
@@ -2816,13 +3127,18 @@ function setProgressBarDelay(delay) {
|
|
|
2816
3127
|
function setConfirmMethod(confirmMethod) {
|
|
2817
3128
|
FormSubmission.confirmMethod = confirmMethod;
|
|
2818
3129
|
}
|
|
3130
|
+
function setFormMode(mode) {
|
|
3131
|
+
session.setFormMode(mode);
|
|
3132
|
+
}
|
|
2819
3133
|
|
|
2820
3134
|
var Turbo = /*#__PURE__*/Object.freeze({
|
|
2821
3135
|
__proto__: null,
|
|
2822
3136
|
navigator: navigator$1,
|
|
2823
3137
|
session: session,
|
|
3138
|
+
cache: cache,
|
|
2824
3139
|
PageRenderer: PageRenderer,
|
|
2825
3140
|
PageSnapshot: PageSnapshot,
|
|
3141
|
+
FrameRenderer: FrameRenderer,
|
|
2826
3142
|
start: start,
|
|
2827
3143
|
registerAdapter: registerAdapter,
|
|
2828
3144
|
visit: visit,
|
|
@@ -2831,39 +3147,52 @@ var Turbo = /*#__PURE__*/Object.freeze({
|
|
|
2831
3147
|
renderStreamMessage: renderStreamMessage,
|
|
2832
3148
|
clearCache: clearCache,
|
|
2833
3149
|
setProgressBarDelay: setProgressBarDelay,
|
|
2834
|
-
setConfirmMethod: setConfirmMethod
|
|
3150
|
+
setConfirmMethod: setConfirmMethod,
|
|
3151
|
+
setFormMode: setFormMode,
|
|
3152
|
+
StreamActions: StreamActions
|
|
2835
3153
|
});
|
|
2836
3154
|
|
|
2837
3155
|
class FrameController {
|
|
2838
3156
|
constructor(element) {
|
|
2839
|
-
this.fetchResponseLoaded = (
|
|
3157
|
+
this.fetchResponseLoaded = (_fetchResponse) => { };
|
|
2840
3158
|
this.currentFetchRequest = null;
|
|
2841
3159
|
this.resolveVisitPromise = () => { };
|
|
2842
3160
|
this.connected = false;
|
|
2843
3161
|
this.hasBeenLoaded = false;
|
|
2844
|
-
this.
|
|
3162
|
+
this.ignoredAttributes = new Set();
|
|
3163
|
+
this.visitCachedSnapshot = ({ element }) => {
|
|
3164
|
+
const frame = element.querySelector("#" + this.element.id);
|
|
3165
|
+
if (frame && this.previousFrameElement) {
|
|
3166
|
+
frame.replaceChildren(...this.previousFrameElement.children);
|
|
3167
|
+
}
|
|
3168
|
+
delete this.previousFrameElement;
|
|
3169
|
+
};
|
|
2845
3170
|
this.element = element;
|
|
2846
3171
|
this.view = new FrameView(this, this.element);
|
|
2847
3172
|
this.appearanceObserver = new AppearanceObserver(this, this.element);
|
|
3173
|
+
this.formLinkInterceptor = new FormLinkInterceptor(this, this.element);
|
|
2848
3174
|
this.linkInterceptor = new LinkInterceptor(this, this.element);
|
|
2849
3175
|
this.formInterceptor = new FormInterceptor(this, this.element);
|
|
2850
3176
|
}
|
|
2851
3177
|
connect() {
|
|
2852
3178
|
if (!this.connected) {
|
|
2853
3179
|
this.connected = true;
|
|
2854
|
-
this.reloadable = false;
|
|
2855
3180
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
2856
3181
|
this.appearanceObserver.start();
|
|
2857
3182
|
}
|
|
3183
|
+
else {
|
|
3184
|
+
this.loadSourceURL();
|
|
3185
|
+
}
|
|
3186
|
+
this.formLinkInterceptor.start();
|
|
2858
3187
|
this.linkInterceptor.start();
|
|
2859
3188
|
this.formInterceptor.start();
|
|
2860
|
-
this.sourceURLChanged();
|
|
2861
3189
|
}
|
|
2862
3190
|
}
|
|
2863
3191
|
disconnect() {
|
|
2864
3192
|
if (this.connected) {
|
|
2865
3193
|
this.connected = false;
|
|
2866
3194
|
this.appearanceObserver.stop();
|
|
3195
|
+
this.formLinkInterceptor.stop();
|
|
2867
3196
|
this.linkInterceptor.stop();
|
|
2868
3197
|
this.formInterceptor.stop();
|
|
2869
3198
|
}
|
|
@@ -2874,10 +3203,20 @@ class FrameController {
|
|
|
2874
3203
|
}
|
|
2875
3204
|
}
|
|
2876
3205
|
sourceURLChanged() {
|
|
3206
|
+
if (this.isIgnoringChangesTo("src"))
|
|
3207
|
+
return;
|
|
3208
|
+
if (this.element.isConnected) {
|
|
3209
|
+
this.complete = false;
|
|
3210
|
+
}
|
|
2877
3211
|
if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
|
|
2878
3212
|
this.loadSourceURL();
|
|
2879
3213
|
}
|
|
2880
3214
|
}
|
|
3215
|
+
completeChanged() {
|
|
3216
|
+
if (this.isIgnoringChangesTo("complete"))
|
|
3217
|
+
return;
|
|
3218
|
+
this.loadSourceURL();
|
|
3219
|
+
}
|
|
2881
3220
|
loadingStyleChanged() {
|
|
2882
3221
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
2883
3222
|
this.appearanceObserver.start();
|
|
@@ -2888,21 +3227,11 @@ class FrameController {
|
|
|
2888
3227
|
}
|
|
2889
3228
|
}
|
|
2890
3229
|
async loadSourceURL() {
|
|
2891
|
-
if (
|
|
2892
|
-
|
|
2893
|
-
this.
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
this.element.loaded = this.visit(expandURL(this.sourceURL));
|
|
2897
|
-
this.appearanceObserver.stop();
|
|
2898
|
-
await this.element.loaded;
|
|
2899
|
-
this.hasBeenLoaded = true;
|
|
2900
|
-
}
|
|
2901
|
-
catch (error) {
|
|
2902
|
-
this.currentURL = previousURL;
|
|
2903
|
-
throw error;
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
3230
|
+
if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
|
|
3231
|
+
this.element.loaded = this.visit(expandURL(this.sourceURL));
|
|
3232
|
+
this.appearanceObserver.stop();
|
|
3233
|
+
await this.element.loaded;
|
|
3234
|
+
this.hasBeenLoaded = true;
|
|
2906
3235
|
}
|
|
2907
3236
|
}
|
|
2908
3237
|
async loadResponse(fetchResponse) {
|
|
@@ -2914,10 +3243,11 @@ class FrameController {
|
|
|
2914
3243
|
if (html) {
|
|
2915
3244
|
const { body } = parseHTMLDocument(html);
|
|
2916
3245
|
const snapshot = new Snapshot(await this.extractForeignFrameElement(body));
|
|
2917
|
-
const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false);
|
|
3246
|
+
const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
|
|
2918
3247
|
if (this.view.renderPromise)
|
|
2919
3248
|
await this.view.renderPromise;
|
|
2920
3249
|
await this.view.render(renderer);
|
|
3250
|
+
this.complete = true;
|
|
2921
3251
|
session.frameRendered(fetchResponse, this.element);
|
|
2922
3252
|
session.frameLoaded(this.element);
|
|
2923
3253
|
this.fetchResponseLoaded(fetchResponse);
|
|
@@ -2931,19 +3261,21 @@ class FrameController {
|
|
|
2931
3261
|
this.fetchResponseLoaded = () => { };
|
|
2932
3262
|
}
|
|
2933
3263
|
}
|
|
2934
|
-
elementAppearedInViewport(
|
|
3264
|
+
elementAppearedInViewport(_element) {
|
|
2935
3265
|
this.loadSourceURL();
|
|
2936
3266
|
}
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
3267
|
+
shouldInterceptFormLinkClick(link) {
|
|
3268
|
+
return this.shouldInterceptNavigation(link);
|
|
3269
|
+
}
|
|
3270
|
+
formLinkClickIntercepted(link, form) {
|
|
3271
|
+
const frame = this.findFrameElement(link);
|
|
3272
|
+
if (frame)
|
|
3273
|
+
form.setAttribute("data-turbo-frame", frame.id);
|
|
3274
|
+
}
|
|
3275
|
+
shouldInterceptLinkClick(element, _url) {
|
|
3276
|
+
return this.shouldInterceptNavigation(element);
|
|
2944
3277
|
}
|
|
2945
3278
|
linkClickIntercepted(element, url) {
|
|
2946
|
-
this.reloadable = true;
|
|
2947
3279
|
this.navigateFrame(element, url);
|
|
2948
3280
|
}
|
|
2949
3281
|
shouldInterceptFormSubmission(element, submitter) {
|
|
@@ -2953,19 +3285,18 @@ class FrameController {
|
|
|
2953
3285
|
if (this.formSubmission) {
|
|
2954
3286
|
this.formSubmission.stop();
|
|
2955
3287
|
}
|
|
2956
|
-
this.reloadable = false;
|
|
2957
3288
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
|
2958
3289
|
const { fetchRequest } = this.formSubmission;
|
|
2959
3290
|
this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest);
|
|
2960
3291
|
this.formSubmission.start();
|
|
2961
3292
|
}
|
|
2962
|
-
prepareHeadersForRequest(headers,
|
|
3293
|
+
prepareHeadersForRequest(headers, _request) {
|
|
2963
3294
|
headers["Turbo-Frame"] = this.id;
|
|
2964
3295
|
}
|
|
2965
|
-
requestStarted(
|
|
3296
|
+
requestStarted(_request) {
|
|
2966
3297
|
markAsBusy(this.element);
|
|
2967
3298
|
}
|
|
2968
|
-
requestPreventedHandlingResponse(
|
|
3299
|
+
requestPreventedHandlingResponse(_request, _response) {
|
|
2969
3300
|
this.resolveVisitPromise();
|
|
2970
3301
|
}
|
|
2971
3302
|
async requestSucceededWithResponse(request, response) {
|
|
@@ -2980,7 +3311,7 @@ class FrameController {
|
|
|
2980
3311
|
console.error(error);
|
|
2981
3312
|
this.resolveVisitPromise();
|
|
2982
3313
|
}
|
|
2983
|
-
requestFinished(
|
|
3314
|
+
requestFinished(_request) {
|
|
2984
3315
|
clearBusyState(this.element);
|
|
2985
3316
|
}
|
|
2986
3317
|
formSubmissionStarted({ formElement }) {
|
|
@@ -3000,19 +3331,32 @@ class FrameController {
|
|
|
3000
3331
|
formSubmissionFinished({ formElement }) {
|
|
3001
3332
|
clearBusyState(formElement, this.findFrameElement(formElement));
|
|
3002
3333
|
}
|
|
3003
|
-
allowsImmediateRender(
|
|
3004
|
-
|
|
3334
|
+
allowsImmediateRender({ element: newFrame }, options) {
|
|
3335
|
+
const event = dispatch("turbo:before-frame-render", {
|
|
3336
|
+
target: this.element,
|
|
3337
|
+
detail: Object.assign({ newFrame }, options),
|
|
3338
|
+
cancelable: true,
|
|
3339
|
+
});
|
|
3340
|
+
const { defaultPrevented, detail: { render }, } = event;
|
|
3341
|
+
if (this.view.renderer && render) {
|
|
3342
|
+
this.view.renderer.renderElement = render;
|
|
3343
|
+
}
|
|
3344
|
+
return !defaultPrevented;
|
|
3005
3345
|
}
|
|
3006
|
-
viewRenderedSnapshot(
|
|
3346
|
+
viewRenderedSnapshot(_snapshot, _isPreview) { }
|
|
3347
|
+
preloadOnLoadLinksForView(element) {
|
|
3348
|
+
session.preloadOnLoadLinksForView(element);
|
|
3007
3349
|
}
|
|
3008
|
-
viewInvalidated() {
|
|
3350
|
+
viewInvalidated() { }
|
|
3351
|
+
frameExtracted(element) {
|
|
3352
|
+
this.previousFrameElement = element;
|
|
3009
3353
|
}
|
|
3010
3354
|
async visit(url) {
|
|
3011
3355
|
var _a;
|
|
3012
|
-
const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams, this.element);
|
|
3356
|
+
const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
|
|
3013
3357
|
(_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
3014
3358
|
this.currentFetchRequest = request;
|
|
3015
|
-
return new Promise(resolve => {
|
|
3359
|
+
return new Promise((resolve) => {
|
|
3016
3360
|
this.resolveVisitPromise = () => {
|
|
3017
3361
|
this.resolveVisitPromise = () => { };
|
|
3018
3362
|
this.currentFetchRequest = null;
|
|
@@ -3024,19 +3368,23 @@ class FrameController {
|
|
|
3024
3368
|
navigateFrame(element, url, submitter) {
|
|
3025
3369
|
const frame = this.findFrameElement(element, submitter);
|
|
3026
3370
|
this.proposeVisitIfNavigatedWithAction(frame, element, submitter);
|
|
3027
|
-
frame.setAttribute("reloadable", "");
|
|
3028
3371
|
frame.src = url;
|
|
3029
3372
|
}
|
|
3030
3373
|
proposeVisitIfNavigatedWithAction(frame, element, submitter) {
|
|
3031
3374
|
const action = getAttribute("data-turbo-action", submitter, element, frame);
|
|
3032
3375
|
if (isAction(action)) {
|
|
3033
|
-
const { visitCachedSnapshot } =
|
|
3376
|
+
const { visitCachedSnapshot } = frame.delegate;
|
|
3034
3377
|
frame.delegate.fetchResponseLoaded = (fetchResponse) => {
|
|
3035
3378
|
if (frame.src) {
|
|
3036
3379
|
const { statusCode, redirected } = fetchResponse;
|
|
3037
3380
|
const responseHTML = frame.ownerDocument.documentElement.outerHTML;
|
|
3038
3381
|
const response = { statusCode, redirected, responseHTML };
|
|
3039
|
-
session.visit(frame.src, {
|
|
3382
|
+
session.visit(frame.src, {
|
|
3383
|
+
action,
|
|
3384
|
+
response,
|
|
3385
|
+
visitCachedSnapshot,
|
|
3386
|
+
willRender: false,
|
|
3387
|
+
});
|
|
3040
3388
|
}
|
|
3041
3389
|
};
|
|
3042
3390
|
}
|
|
@@ -3050,10 +3398,12 @@ class FrameController {
|
|
|
3050
3398
|
let element;
|
|
3051
3399
|
const id = CSS.escape(this.id);
|
|
3052
3400
|
try {
|
|
3053
|
-
|
|
3401
|
+
element = activateElement(container.querySelector(`turbo-frame#${id}`), this.sourceURL);
|
|
3402
|
+
if (element) {
|
|
3054
3403
|
return element;
|
|
3055
3404
|
}
|
|
3056
|
-
|
|
3405
|
+
element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.sourceURL);
|
|
3406
|
+
if (element) {
|
|
3057
3407
|
await element.loaded;
|
|
3058
3408
|
return await this.extractForeignFrameElement(element);
|
|
3059
3409
|
}
|
|
@@ -3101,24 +3451,10 @@ class FrameController {
|
|
|
3101
3451
|
return this.element.src;
|
|
3102
3452
|
}
|
|
3103
3453
|
}
|
|
3104
|
-
get reloadable() {
|
|
3105
|
-
const frame = this.findFrameElement(this.element);
|
|
3106
|
-
return frame.hasAttribute("reloadable");
|
|
3107
|
-
}
|
|
3108
|
-
set reloadable(value) {
|
|
3109
|
-
const frame = this.findFrameElement(this.element);
|
|
3110
|
-
if (value) {
|
|
3111
|
-
frame.setAttribute("reloadable", "");
|
|
3112
|
-
}
|
|
3113
|
-
else {
|
|
3114
|
-
frame.removeAttribute("reloadable");
|
|
3115
|
-
}
|
|
3116
|
-
}
|
|
3117
3454
|
set sourceURL(sourceURL) {
|
|
3118
|
-
this.
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
this.settingSourceURL = false;
|
|
3455
|
+
this.ignoringChangesToAttribute("src", () => {
|
|
3456
|
+
this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
|
|
3457
|
+
});
|
|
3122
3458
|
}
|
|
3123
3459
|
get loadingStyle() {
|
|
3124
3460
|
return this.element.loading;
|
|
@@ -3126,6 +3462,19 @@ class FrameController {
|
|
|
3126
3462
|
get isLoading() {
|
|
3127
3463
|
return this.formSubmission !== undefined || this.resolveVisitPromise() !== undefined;
|
|
3128
3464
|
}
|
|
3465
|
+
get complete() {
|
|
3466
|
+
return this.element.hasAttribute("complete");
|
|
3467
|
+
}
|
|
3468
|
+
set complete(value) {
|
|
3469
|
+
this.ignoringChangesToAttribute("complete", () => {
|
|
3470
|
+
if (value) {
|
|
3471
|
+
this.element.setAttribute("complete", "");
|
|
3472
|
+
}
|
|
3473
|
+
else {
|
|
3474
|
+
this.element.removeAttribute("complete");
|
|
3475
|
+
}
|
|
3476
|
+
});
|
|
3477
|
+
}
|
|
3129
3478
|
get isActive() {
|
|
3130
3479
|
return this.element.isActive && this.connected;
|
|
3131
3480
|
}
|
|
@@ -3135,16 +3484,13 @@ class FrameController {
|
|
|
3135
3484
|
const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
|
|
3136
3485
|
return expandURL(root);
|
|
3137
3486
|
}
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
};
|
|
3146
|
-
this.clone = element.cloneNode(true);
|
|
3147
|
-
this.id = element.id;
|
|
3487
|
+
isIgnoringChangesTo(attributeName) {
|
|
3488
|
+
return this.ignoredAttributes.has(attributeName);
|
|
3489
|
+
}
|
|
3490
|
+
ignoringChangesToAttribute(attributeName, callback) {
|
|
3491
|
+
this.ignoredAttributes.add(attributeName);
|
|
3492
|
+
callback();
|
|
3493
|
+
this.ignoredAttributes.delete(attributeName);
|
|
3148
3494
|
}
|
|
3149
3495
|
}
|
|
3150
3496
|
function getFrameElementById(id) {
|
|
@@ -3172,35 +3518,6 @@ function activateElement(element, currentURL) {
|
|
|
3172
3518
|
}
|
|
3173
3519
|
}
|
|
3174
3520
|
|
|
3175
|
-
const StreamActions = {
|
|
3176
|
-
after() {
|
|
3177
|
-
this.targetElements.forEach(e => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });
|
|
3178
|
-
},
|
|
3179
|
-
append() {
|
|
3180
|
-
this.removeDuplicateTargetChildren();
|
|
3181
|
-
this.targetElements.forEach(e => e.append(this.templateContent));
|
|
3182
|
-
},
|
|
3183
|
-
before() {
|
|
3184
|
-
this.targetElements.forEach(e => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });
|
|
3185
|
-
},
|
|
3186
|
-
prepend() {
|
|
3187
|
-
this.removeDuplicateTargetChildren();
|
|
3188
|
-
this.targetElements.forEach(e => e.prepend(this.templateContent));
|
|
3189
|
-
},
|
|
3190
|
-
remove() {
|
|
3191
|
-
this.targetElements.forEach(e => e.remove());
|
|
3192
|
-
},
|
|
3193
|
-
replace() {
|
|
3194
|
-
this.targetElements.forEach(e => e.replaceWith(this.templateContent));
|
|
3195
|
-
},
|
|
3196
|
-
update() {
|
|
3197
|
-
this.targetElements.forEach(e => {
|
|
3198
|
-
e.innerHTML = "";
|
|
3199
|
-
e.append(this.templateContent);
|
|
3200
|
-
});
|
|
3201
|
-
}
|
|
3202
|
-
};
|
|
3203
|
-
|
|
3204
3521
|
class StreamElement extends HTMLElement {
|
|
3205
3522
|
async connectedCallback() {
|
|
3206
3523
|
try {
|
|
@@ -3215,12 +3532,12 @@ class StreamElement extends HTMLElement {
|
|
|
3215
3532
|
}
|
|
3216
3533
|
async render() {
|
|
3217
3534
|
var _a;
|
|
3218
|
-
return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
|
3535
|
+
return ((_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
|
3219
3536
|
if (this.dispatchEvent(this.beforeRenderEvent)) {
|
|
3220
3537
|
await nextAnimationFrame();
|
|
3221
3538
|
this.performAction();
|
|
3222
3539
|
}
|
|
3223
|
-
})());
|
|
3540
|
+
})()));
|
|
3224
3541
|
}
|
|
3225
3542
|
disconnect() {
|
|
3226
3543
|
try {
|
|
@@ -3229,13 +3546,13 @@ class StreamElement extends HTMLElement {
|
|
|
3229
3546
|
catch (_a) { }
|
|
3230
3547
|
}
|
|
3231
3548
|
removeDuplicateTargetChildren() {
|
|
3232
|
-
this.duplicateChildren.forEach(c => c.remove());
|
|
3549
|
+
this.duplicateChildren.forEach((c) => c.remove());
|
|
3233
3550
|
}
|
|
3234
3551
|
get duplicateChildren() {
|
|
3235
3552
|
var _a;
|
|
3236
|
-
const existingChildren = this.targetElements.flatMap(e => [...e.children]).filter(c => !!c.id);
|
|
3237
|
-
const newChildrenIds = [...(_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children].filter(c => !!c.id).map(c => c.id);
|
|
3238
|
-
return existingChildren.filter(c => newChildrenIds.includes(c.id));
|
|
3553
|
+
const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);
|
|
3554
|
+
const newChildrenIds = [...(((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || [])].filter((c) => !!c.id).map((c) => c.id);
|
|
3555
|
+
return existingChildren.filter((c) => newChildrenIds.includes(c.id));
|
|
3239
3556
|
}
|
|
3240
3557
|
get performAction() {
|
|
3241
3558
|
if (this.action) {
|
|
@@ -3284,7 +3601,10 @@ class StreamElement extends HTMLElement {
|
|
|
3284
3601
|
return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
|
|
3285
3602
|
}
|
|
3286
3603
|
get beforeRenderEvent() {
|
|
3287
|
-
return new CustomEvent("turbo:before-stream-render", {
|
|
3604
|
+
return new CustomEvent("turbo:before-stream-render", {
|
|
3605
|
+
bubbles: true,
|
|
3606
|
+
cancelable: true,
|
|
3607
|
+
});
|
|
3288
3608
|
}
|
|
3289
3609
|
get targetElementsById() {
|
|
3290
3610
|
var _a;
|
|
@@ -3308,9 +3628,35 @@ class StreamElement extends HTMLElement {
|
|
|
3308
3628
|
}
|
|
3309
3629
|
}
|
|
3310
3630
|
|
|
3631
|
+
class StreamSourceElement extends HTMLElement {
|
|
3632
|
+
constructor() {
|
|
3633
|
+
super(...arguments);
|
|
3634
|
+
this.streamSource = null;
|
|
3635
|
+
}
|
|
3636
|
+
connectedCallback() {
|
|
3637
|
+
this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
|
|
3638
|
+
connectStreamSource(this.streamSource);
|
|
3639
|
+
}
|
|
3640
|
+
disconnectedCallback() {
|
|
3641
|
+
if (this.streamSource) {
|
|
3642
|
+
disconnectStreamSource(this.streamSource);
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
get src() {
|
|
3646
|
+
return this.getAttribute("src") || "";
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3311
3650
|
FrameElement.delegateConstructor = FrameController;
|
|
3312
|
-
customElements.
|
|
3313
|
-
customElements.define("turbo-
|
|
3651
|
+
if (customElements.get("turbo-frame") === undefined) {
|
|
3652
|
+
customElements.define("turbo-frame", FrameElement);
|
|
3653
|
+
}
|
|
3654
|
+
if (customElements.get("turbo-stream") === undefined) {
|
|
3655
|
+
customElements.define("turbo-stream", StreamElement);
|
|
3656
|
+
}
|
|
3657
|
+
if (customElements.get("turbo-stream-source") === undefined) {
|
|
3658
|
+
customElements.define("turbo-stream-source", StreamSourceElement);
|
|
3659
|
+
}
|
|
3314
3660
|
|
|
3315
3661
|
(() => {
|
|
3316
3662
|
let element = document.currentScript;
|
|
@@ -3318,7 +3664,8 @@ customElements.define("turbo-stream", StreamElement);
|
|
|
3318
3664
|
return;
|
|
3319
3665
|
if (element.hasAttribute("data-turbo-suppress-warning"))
|
|
3320
3666
|
return;
|
|
3321
|
-
|
|
3667
|
+
element = element.parentElement;
|
|
3668
|
+
while (element) {
|
|
3322
3669
|
if (element == document.body) {
|
|
3323
3670
|
return console.warn(unindent `
|
|
3324
3671
|
You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
|
|
@@ -3331,10 +3678,11 @@ customElements.define("turbo-stream", StreamElement);
|
|
|
3331
3678
|
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
|
3332
3679
|
`, element.outerHTML);
|
|
3333
3680
|
}
|
|
3681
|
+
element = element.parentElement;
|
|
3334
3682
|
}
|
|
3335
3683
|
})();
|
|
3336
3684
|
|
|
3337
3685
|
window.Turbo = Turbo;
|
|
3338
3686
|
start();
|
|
3339
3687
|
|
|
3340
|
-
export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator$1 as navigator, registerAdapter, renderStreamMessage, session, setConfirmMethod, setProgressBarDelay, start, visit };
|
|
3688
|
+
export { FrameRenderer, PageRenderer, PageSnapshot, StreamActions, cache, clearCache, connectStreamSource, disconnectStreamSource, navigator$1 as navigator, registerAdapter, renderStreamMessage, session, setConfirmMethod, setFormMode, setProgressBarDelay, start, visit };
|