@hotwired/turbo 7.1.0-rc.3 → 7.2.0-beta.2
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 +1027 -613
- package/dist/turbo.es2017-umd.js +1032 -614
- 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 +2 -1
- package/dist/types/core/drive/form_submission.d.ts +13 -4
- package/dist/types/core/drive/head_snapshot.d.ts +3 -3
- package/dist/types/core/drive/history.d.ts +1 -1
- package/dist/types/core/drive/navigator.d.ts +4 -3
- package/dist/types/core/drive/page_renderer.d.ts +8 -5
- 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 +15 -4
- package/dist/types/core/frames/frame_controller.d.ts +43 -23
- package/dist/types/core/frames/frame_redirector.d.ts +12 -10
- 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/index.d.ts +14 -4
- package/dist/types/core/native/adapter.d.ts +3 -2
- package/dist/types/core/native/browser_adapter.d.ts +18 -9
- package/dist/types/core/renderer.d.ts +11 -5
- package/dist/types/core/session.d.ts +78 -19
- package/dist/types/core/snapshot.d.ts +2 -1
- package/dist/types/core/streams/stream_message.d.ts +2 -6
- package/dist/types/core/types.d.ts +4 -0
- package/dist/types/core/view.d.ts +13 -7
- package/dist/types/elements/frame_element.d.ts +10 -6
- package/dist/types/elements/stream_element.d.ts +3 -0
- package/dist/types/elements/stream_source_element.d.ts +7 -0
- package/dist/types/http/fetch_request.d.ts +9 -0
- package/dist/types/observers/cache_observer.d.ts +1 -1
- package/dist/types/observers/form_link_click_observer.d.ts +14 -0
- package/dist/types/observers/form_submit_observer.d.ts +2 -1
- package/dist/types/observers/link_click_observer.d.ts +5 -4
- 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_mode_tests.d.ts +1 -0
- 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 -51
- 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 -37
- 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 -14
- 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 +12 -3
- package/package.json +22 -8
- package/CHANGELOG.md +0 -3
- package/dist/types/core/frames/form_interceptor.d.ts +0 -12
- package/dist/types/core/frames/link_interceptor.d.ts +0 -16
- 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-umd.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Turbo 7.
|
|
3
|
-
Copyright ©
|
|
2
|
+
Turbo 7.2.0-beta.2
|
|
3
|
+
Copyright © 2022 Basecamp, LLC
|
|
4
4
|
*/
|
|
5
5
|
(function (global, factory) {
|
|
6
6
|
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
7
7
|
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
8
8
|
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Turbo = {}));
|
|
9
|
-
}(this, (function (exports) { 'use strict';
|
|
9
|
+
})(this, (function (exports) { 'use strict';
|
|
10
10
|
|
|
11
11
|
(function () {
|
|
12
|
-
if (window.Reflect === undefined ||
|
|
12
|
+
if (window.Reflect === undefined ||
|
|
13
|
+
window.customElements === undefined ||
|
|
13
14
|
window.customElements.polyfillWrapFlushCallback) {
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
16
17
|
const BuiltInHTMLElement = HTMLElement;
|
|
17
18
|
const wrapperForTheName = {
|
|
18
|
-
|
|
19
|
+
HTMLElement: function HTMLElement() {
|
|
19
20
|
return Reflect.construct(BuiltInHTMLElement, [], this.constructor);
|
|
20
|
-
}
|
|
21
|
+
},
|
|
21
22
|
};
|
|
22
|
-
window.HTMLElement =
|
|
23
|
-
wrapperForTheName['HTMLElement'];
|
|
23
|
+
window.HTMLElement = wrapperForTheName["HTMLElement"];
|
|
24
24
|
HTMLElement.prototype = BuiltInHTMLElement.prototype;
|
|
25
25
|
HTMLElement.prototype.constructor = HTMLElement;
|
|
26
26
|
Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);
|
|
@@ -78,7 +78,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
78
78
|
}
|
|
79
79
|
})(HTMLFormElement.prototype);
|
|
80
80
|
|
|
81
|
-
const submittersByForm = new WeakMap;
|
|
81
|
+
const submittersByForm = new WeakMap();
|
|
82
82
|
function findSubmitterFromClickTarget(target) {
|
|
83
83
|
const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
|
|
84
84
|
const candidate = element ? element.closest("input, button") : null;
|
|
@@ -109,7 +109,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
109
109
|
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
110
110
|
return submittersByForm.get(this.target);
|
|
111
111
|
}
|
|
112
|
-
}
|
|
112
|
+
},
|
|
113
113
|
});
|
|
114
114
|
})();
|
|
115
115
|
|
|
@@ -125,7 +125,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
125
125
|
this.delegate = new FrameElement.delegateConstructor(this);
|
|
126
126
|
}
|
|
127
127
|
static get observedAttributes() {
|
|
128
|
-
return ["disabled", "loading", "src"];
|
|
128
|
+
return ["disabled", "complete", "loading", "src"];
|
|
129
129
|
}
|
|
130
130
|
connectedCallback() {
|
|
131
131
|
this.delegate.connect();
|
|
@@ -135,13 +135,18 @@ Copyright © 2021 Basecamp, LLC
|
|
|
135
135
|
}
|
|
136
136
|
reload() {
|
|
137
137
|
const { src } = this;
|
|
138
|
+
this.removeAttribute("complete");
|
|
138
139
|
this.src = null;
|
|
139
140
|
this.src = src;
|
|
141
|
+
return this.loaded;
|
|
140
142
|
}
|
|
141
143
|
attributeChangedCallback(name) {
|
|
142
144
|
if (name == "loading") {
|
|
143
145
|
this.delegate.loadingStyleChanged();
|
|
144
146
|
}
|
|
147
|
+
else if (name == "complete") {
|
|
148
|
+
this.delegate.completeChanged();
|
|
149
|
+
}
|
|
145
150
|
else if (name == "src") {
|
|
146
151
|
this.delegate.sourceURLChanged();
|
|
147
152
|
}
|
|
@@ -206,8 +211,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
206
211
|
}
|
|
207
212
|
function frameLoadingStyleFromString(style) {
|
|
208
213
|
switch (style.toLowerCase()) {
|
|
209
|
-
case "lazy":
|
|
210
|
-
|
|
214
|
+
case "lazy":
|
|
215
|
+
return FrameLoadingStyle.lazy;
|
|
216
|
+
default:
|
|
217
|
+
return FrameLoadingStyle.eager;
|
|
211
218
|
}
|
|
212
219
|
}
|
|
213
220
|
|
|
@@ -219,7 +226,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
219
226
|
if (url.hash) {
|
|
220
227
|
return url.hash.slice(1);
|
|
221
228
|
}
|
|
222
|
-
else if (anchorMatch = url.href.match(/#(.*)$/)) {
|
|
229
|
+
else if ((anchorMatch = url.href.match(/#(.*)$/))) {
|
|
223
230
|
return anchorMatch[1];
|
|
224
231
|
}
|
|
225
232
|
}
|
|
@@ -231,7 +238,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
231
238
|
return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || "";
|
|
232
239
|
}
|
|
233
240
|
function isHTML(url) {
|
|
234
|
-
return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml))$/);
|
|
241
|
+
return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml|php))$/);
|
|
235
242
|
}
|
|
236
243
|
function isPrefixedBy(baseURL, url) {
|
|
237
244
|
const prefix = getPrefix(url);
|
|
@@ -242,9 +249,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
242
249
|
}
|
|
243
250
|
function getRequestURL(url) {
|
|
244
251
|
const anchor = getAnchor(url);
|
|
245
|
-
return anchor != null
|
|
246
|
-
? url.href.slice(0, -(anchor.length + 1))
|
|
247
|
-
: url.href;
|
|
252
|
+
return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href;
|
|
248
253
|
}
|
|
249
254
|
function toCacheKey(url) {
|
|
250
255
|
return getRequestURL(url);
|
|
@@ -312,8 +317,42 @@ Copyright © 2021 Basecamp, LLC
|
|
|
312
317
|
}
|
|
313
318
|
}
|
|
314
319
|
|
|
320
|
+
function isAction(action) {
|
|
321
|
+
return action == "advance" || action == "replace" || action == "restore";
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function activateScriptElement(element) {
|
|
325
|
+
if (element.getAttribute("data-turbo-eval") == "false") {
|
|
326
|
+
return element;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
const createdScriptElement = document.createElement("script");
|
|
330
|
+
const cspNonce = getMetaContent("csp-nonce");
|
|
331
|
+
if (cspNonce) {
|
|
332
|
+
createdScriptElement.nonce = cspNonce;
|
|
333
|
+
}
|
|
334
|
+
createdScriptElement.textContent = element.textContent;
|
|
335
|
+
createdScriptElement.async = false;
|
|
336
|
+
copyElementAttributes(createdScriptElement, element);
|
|
337
|
+
return createdScriptElement;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function copyElementAttributes(destinationElement, sourceElement) {
|
|
341
|
+
for (const { name, value } of sourceElement.attributes) {
|
|
342
|
+
destinationElement.setAttribute(name, value);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
function createDocumentFragment(html) {
|
|
346
|
+
const template = document.createElement("template");
|
|
347
|
+
template.innerHTML = html;
|
|
348
|
+
return template.content;
|
|
349
|
+
}
|
|
315
350
|
function dispatch(eventName, { target, cancelable, detail } = {}) {
|
|
316
|
-
const event = new CustomEvent(eventName, {
|
|
351
|
+
const event = new CustomEvent(eventName, {
|
|
352
|
+
cancelable,
|
|
353
|
+
bubbles: true,
|
|
354
|
+
detail,
|
|
355
|
+
});
|
|
317
356
|
if (target && target.isConnected) {
|
|
318
357
|
target.dispatchEvent(event);
|
|
319
358
|
}
|
|
@@ -323,10 +362,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
323
362
|
return event;
|
|
324
363
|
}
|
|
325
364
|
function nextAnimationFrame() {
|
|
326
|
-
return new Promise(resolve => requestAnimationFrame(() => resolve()));
|
|
365
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
327
366
|
}
|
|
328
367
|
function nextEventLoopTick() {
|
|
329
|
-
return new Promise(resolve => setTimeout(() => resolve(), 0));
|
|
368
|
+
return new Promise((resolve) => setTimeout(() => resolve(), 0));
|
|
330
369
|
}
|
|
331
370
|
function nextMicrotask() {
|
|
332
371
|
return Promise.resolve();
|
|
@@ -338,7 +377,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
338
377
|
const lines = interpolate(strings, values).replace(/^\n/, "").split("\n");
|
|
339
378
|
const match = lines[0].match(/^\s+/);
|
|
340
379
|
const indent = match ? match[0].length : 0;
|
|
341
|
-
return lines.map(line => line.slice(indent)).join("\n");
|
|
380
|
+
return lines.map((line) => line.slice(indent)).join("\n");
|
|
342
381
|
}
|
|
343
382
|
function interpolate(strings, values) {
|
|
344
383
|
return strings.reduce((result, string, i) => {
|
|
@@ -347,7 +386,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
347
386
|
}, "");
|
|
348
387
|
}
|
|
349
388
|
function uuid() {
|
|
350
|
-
return Array.
|
|
389
|
+
return Array.from({ length: 36 })
|
|
390
|
+
.map((_, i) => {
|
|
351
391
|
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
|
352
392
|
return "-";
|
|
353
393
|
}
|
|
@@ -360,10 +400,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
360
400
|
else {
|
|
361
401
|
return Math.floor(Math.random() * 15).toString(16);
|
|
362
402
|
}
|
|
363
|
-
})
|
|
403
|
+
})
|
|
404
|
+
.join("");
|
|
364
405
|
}
|
|
365
406
|
function getAttribute(attributeName, ...elements) {
|
|
366
|
-
for (const value of elements.map(element => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
|
407
|
+
for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) {
|
|
367
408
|
if (typeof value == "string")
|
|
368
409
|
return value;
|
|
369
410
|
}
|
|
@@ -385,6 +426,48 @@ Copyright © 2021 Basecamp, LLC
|
|
|
385
426
|
element.removeAttribute("aria-busy");
|
|
386
427
|
}
|
|
387
428
|
}
|
|
429
|
+
function waitForLoad(element, timeoutInMilliseconds = 2000) {
|
|
430
|
+
return new Promise((resolve) => {
|
|
431
|
+
const onComplete = () => {
|
|
432
|
+
element.removeEventListener("error", onComplete);
|
|
433
|
+
element.removeEventListener("load", onComplete);
|
|
434
|
+
resolve();
|
|
435
|
+
};
|
|
436
|
+
element.addEventListener("load", onComplete, { once: true });
|
|
437
|
+
element.addEventListener("error", onComplete, { once: true });
|
|
438
|
+
setTimeout(resolve, timeoutInMilliseconds);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
function getHistoryMethodForAction(action) {
|
|
442
|
+
switch (action) {
|
|
443
|
+
case "replace":
|
|
444
|
+
return history.replaceState;
|
|
445
|
+
case "advance":
|
|
446
|
+
case "restore":
|
|
447
|
+
return history.pushState;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
function getVisitAction(...elements) {
|
|
451
|
+
const action = getAttribute("data-turbo-action", ...elements);
|
|
452
|
+
return isAction(action) ? action : null;
|
|
453
|
+
}
|
|
454
|
+
function getMetaElement(name) {
|
|
455
|
+
return document.querySelector(`meta[name="${name}"]`);
|
|
456
|
+
}
|
|
457
|
+
function getMetaContent(name) {
|
|
458
|
+
const element = getMetaElement(name);
|
|
459
|
+
return element && element.content;
|
|
460
|
+
}
|
|
461
|
+
function setMetaContent(name, content) {
|
|
462
|
+
let element = getMetaElement(name);
|
|
463
|
+
if (!element) {
|
|
464
|
+
element = document.createElement("meta");
|
|
465
|
+
element.setAttribute("name", name);
|
|
466
|
+
document.head.appendChild(element);
|
|
467
|
+
}
|
|
468
|
+
element.setAttribute("content", content);
|
|
469
|
+
return element;
|
|
470
|
+
}
|
|
388
471
|
|
|
389
472
|
var FetchMethod;
|
|
390
473
|
(function (FetchMethod) {
|
|
@@ -396,24 +479,27 @@ Copyright © 2021 Basecamp, LLC
|
|
|
396
479
|
})(FetchMethod || (FetchMethod = {}));
|
|
397
480
|
function fetchMethodFromString(method) {
|
|
398
481
|
switch (method.toLowerCase()) {
|
|
399
|
-
case "get":
|
|
400
|
-
|
|
401
|
-
case "
|
|
402
|
-
|
|
403
|
-
case "
|
|
482
|
+
case "get":
|
|
483
|
+
return FetchMethod.get;
|
|
484
|
+
case "post":
|
|
485
|
+
return FetchMethod.post;
|
|
486
|
+
case "put":
|
|
487
|
+
return FetchMethod.put;
|
|
488
|
+
case "patch":
|
|
489
|
+
return FetchMethod.patch;
|
|
490
|
+
case "delete":
|
|
491
|
+
return FetchMethod.delete;
|
|
404
492
|
}
|
|
405
493
|
}
|
|
406
494
|
class FetchRequest {
|
|
407
|
-
constructor(delegate, method, location, body = new URLSearchParams, target = null) {
|
|
408
|
-
this.abortController = new AbortController;
|
|
409
|
-
this.resolveRequestPromise = (
|
|
495
|
+
constructor(delegate, method, location, body = new URLSearchParams(), target = null) {
|
|
496
|
+
this.abortController = new AbortController();
|
|
497
|
+
this.resolveRequestPromise = (_value) => { };
|
|
410
498
|
this.delegate = delegate;
|
|
411
499
|
this.method = method;
|
|
412
500
|
this.headers = this.defaultHeaders;
|
|
413
501
|
this.body = body;
|
|
414
|
-
this.url =
|
|
415
|
-
mergeFormDataEntries(new URL(location.href), this.entries) :
|
|
416
|
-
location;
|
|
502
|
+
this.url = location;
|
|
417
503
|
this.target = target;
|
|
418
504
|
}
|
|
419
505
|
get location() {
|
|
@@ -439,7 +525,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
439
525
|
return await this.receive(response);
|
|
440
526
|
}
|
|
441
527
|
catch (error) {
|
|
442
|
-
if (error.name !==
|
|
528
|
+
if (error.name !== "AbortError") {
|
|
443
529
|
this.delegate.requestErrored(this, error);
|
|
444
530
|
throw error;
|
|
445
531
|
}
|
|
@@ -450,7 +536,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
450
536
|
}
|
|
451
537
|
async receive(response) {
|
|
452
538
|
const fetchResponse = new FetchResponse(response);
|
|
453
|
-
const event = dispatch("turbo:before-fetch-response", {
|
|
539
|
+
const event = dispatch("turbo:before-fetch-response", {
|
|
540
|
+
cancelable: true,
|
|
541
|
+
detail: { fetchResponse },
|
|
542
|
+
target: this.target,
|
|
543
|
+
});
|
|
454
544
|
if (event.defaultPrevented) {
|
|
455
545
|
this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
|
|
456
546
|
}
|
|
@@ -471,12 +561,12 @@ Copyright © 2021 Basecamp, LLC
|
|
|
471
561
|
redirect: "follow",
|
|
472
562
|
body: this.isIdempotent ? null : this.body,
|
|
473
563
|
signal: this.abortSignal,
|
|
474
|
-
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href
|
|
564
|
+
referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href,
|
|
475
565
|
};
|
|
476
566
|
}
|
|
477
567
|
get defaultHeaders() {
|
|
478
568
|
return {
|
|
479
|
-
|
|
569
|
+
Accept: "text/html, application/xhtml+xml",
|
|
480
570
|
};
|
|
481
571
|
}
|
|
482
572
|
get isIdempotent() {
|
|
@@ -485,36 +575,29 @@ Copyright © 2021 Basecamp, LLC
|
|
|
485
575
|
get abortSignal() {
|
|
486
576
|
return this.abortController.signal;
|
|
487
577
|
}
|
|
578
|
+
acceptResponseType(mimeType) {
|
|
579
|
+
this.headers["Accept"] = [mimeType, this.headers["Accept"]].join(", ");
|
|
580
|
+
}
|
|
488
581
|
async allowRequestToBeIntercepted(fetchOptions) {
|
|
489
|
-
const requestInterception = new Promise(resolve => this.resolveRequestPromise = resolve);
|
|
582
|
+
const requestInterception = new Promise((resolve) => (this.resolveRequestPromise = resolve));
|
|
490
583
|
const event = dispatch("turbo:before-fetch-request", {
|
|
491
584
|
cancelable: true,
|
|
492
585
|
detail: {
|
|
493
586
|
fetchOptions,
|
|
494
587
|
url: this.url,
|
|
495
|
-
resume: this.resolveRequestPromise
|
|
588
|
+
resume: this.resolveRequestPromise,
|
|
496
589
|
},
|
|
497
|
-
target: this.target
|
|
590
|
+
target: this.target,
|
|
498
591
|
});
|
|
499
592
|
if (event.defaultPrevented)
|
|
500
593
|
await requestInterception;
|
|
501
594
|
}
|
|
502
595
|
}
|
|
503
|
-
function mergeFormDataEntries(url, entries) {
|
|
504
|
-
const searchParams = new URLSearchParams;
|
|
505
|
-
for (const [name, value] of entries) {
|
|
506
|
-
if (value instanceof File)
|
|
507
|
-
continue;
|
|
508
|
-
searchParams.append(name, value);
|
|
509
|
-
}
|
|
510
|
-
url.search = searchParams.toString();
|
|
511
|
-
return url;
|
|
512
|
-
}
|
|
513
596
|
|
|
514
597
|
class AppearanceObserver {
|
|
515
598
|
constructor(delegate, element) {
|
|
516
599
|
this.started = false;
|
|
517
|
-
this.intersect = entries => {
|
|
600
|
+
this.intersect = (entries) => {
|
|
518
601
|
const lastEntry = entries.slice(-1)[0];
|
|
519
602
|
if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
|
520
603
|
this.delegate.elementAppearedInViewport(this.element);
|
|
@@ -539,40 +622,29 @@ Copyright © 2021 Basecamp, LLC
|
|
|
539
622
|
}
|
|
540
623
|
|
|
541
624
|
class StreamMessage {
|
|
542
|
-
constructor(
|
|
543
|
-
this.
|
|
544
|
-
this.templateElement.innerHTML = html;
|
|
625
|
+
constructor(fragment) {
|
|
626
|
+
this.fragment = importStreamElements(fragment);
|
|
545
627
|
}
|
|
546
628
|
static wrap(message) {
|
|
547
629
|
if (typeof message == "string") {
|
|
548
|
-
return new this(message);
|
|
630
|
+
return new this(createDocumentFragment(message));
|
|
549
631
|
}
|
|
550
632
|
else {
|
|
551
633
|
return message;
|
|
552
634
|
}
|
|
553
635
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
636
|
+
}
|
|
637
|
+
StreamMessage.contentType = "text/vnd.turbo-stream.html";
|
|
638
|
+
function importStreamElements(fragment) {
|
|
639
|
+
for (const element of fragment.querySelectorAll("turbo-stream")) {
|
|
640
|
+
const streamElement = document.importNode(element, true);
|
|
641
|
+
for (const inertScriptElement of streamElement.templateElement.content.querySelectorAll("script")) {
|
|
642
|
+
inertScriptElement.replaceWith(activateScriptElement(inertScriptElement));
|
|
558
643
|
}
|
|
559
|
-
|
|
560
|
-
}
|
|
561
|
-
get foreignElements() {
|
|
562
|
-
return this.templateChildren.reduce((streamElements, child) => {
|
|
563
|
-
if (child.tagName.toLowerCase() == "turbo-stream") {
|
|
564
|
-
return [...streamElements, child];
|
|
565
|
-
}
|
|
566
|
-
else {
|
|
567
|
-
return streamElements;
|
|
568
|
-
}
|
|
569
|
-
}, []);
|
|
570
|
-
}
|
|
571
|
-
get templateChildren() {
|
|
572
|
-
return Array.from(this.templateElement.content.children);
|
|
644
|
+
element.replaceWith(streamElement);
|
|
573
645
|
}
|
|
646
|
+
return fragment;
|
|
574
647
|
}
|
|
575
|
-
StreamMessage.contentType = "text/vnd.turbo-stream.html";
|
|
576
648
|
|
|
577
649
|
var FormSubmissionState;
|
|
578
650
|
(function (FormSubmissionState) {
|
|
@@ -591,9 +663,12 @@ Copyright © 2021 Basecamp, LLC
|
|
|
591
663
|
})(FormEnctype || (FormEnctype = {}));
|
|
592
664
|
function formEnctypeFromString(encoding) {
|
|
593
665
|
switch (encoding.toLowerCase()) {
|
|
594
|
-
case FormEnctype.multipart:
|
|
595
|
-
|
|
596
|
-
|
|
666
|
+
case FormEnctype.multipart:
|
|
667
|
+
return FormEnctype.multipart;
|
|
668
|
+
case FormEnctype.plain:
|
|
669
|
+
return FormEnctype.plain;
|
|
670
|
+
default:
|
|
671
|
+
return FormEnctype.urlEncoded;
|
|
597
672
|
}
|
|
598
673
|
}
|
|
599
674
|
class FormSubmission {
|
|
@@ -603,11 +678,15 @@ Copyright © 2021 Basecamp, LLC
|
|
|
603
678
|
this.formElement = formElement;
|
|
604
679
|
this.submitter = submitter;
|
|
605
680
|
this.formData = buildFormData(formElement, submitter);
|
|
681
|
+
this.location = expandURL(this.action);
|
|
682
|
+
if (this.method == FetchMethod.get) {
|
|
683
|
+
mergeFormDataEntries(this.location, [...this.body.entries()]);
|
|
684
|
+
}
|
|
606
685
|
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
|
607
686
|
this.mustRedirect = mustRedirect;
|
|
608
687
|
}
|
|
609
|
-
static confirmMethod(message,
|
|
610
|
-
return confirm(message);
|
|
688
|
+
static confirmMethod(message, _element) {
|
|
689
|
+
return Promise.resolve(confirm(message));
|
|
611
690
|
}
|
|
612
691
|
get method() {
|
|
613
692
|
var _a;
|
|
@@ -616,11 +695,13 @@ Copyright © 2021 Basecamp, LLC
|
|
|
616
695
|
}
|
|
617
696
|
get action() {
|
|
618
697
|
var _a;
|
|
619
|
-
const formElementAction = typeof this.formElement.action ===
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
698
|
+
const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null;
|
|
699
|
+
if ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.hasAttribute("formaction")) {
|
|
700
|
+
return this.submitter.getAttribute("formaction") || "";
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
return this.formElement.getAttribute("action") || formElementAction || "";
|
|
704
|
+
}
|
|
624
705
|
}
|
|
625
706
|
get body() {
|
|
626
707
|
if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) {
|
|
@@ -643,7 +724,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
643
724
|
}, []);
|
|
644
725
|
}
|
|
645
726
|
get confirmationMessage() {
|
|
646
|
-
|
|
727
|
+
var _a;
|
|
728
|
+
return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("data-turbo-confirm")) || this.formElement.getAttribute("data-turbo-confirm");
|
|
647
729
|
}
|
|
648
730
|
get needsConfirmation() {
|
|
649
731
|
return this.confirmationMessage !== null;
|
|
@@ -651,7 +733,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
651
733
|
async start() {
|
|
652
734
|
const { initialized, requesting } = FormSubmissionState;
|
|
653
735
|
if (this.needsConfirmation) {
|
|
654
|
-
const answer = FormSubmission.confirmMethod(this.confirmationMessage, this.formElement);
|
|
736
|
+
const answer = await FormSubmission.confirmMethod(this.confirmationMessage, this.formElement);
|
|
655
737
|
if (!answer) {
|
|
656
738
|
return;
|
|
657
739
|
}
|
|
@@ -675,14 +757,19 @@ Copyright © 2021 Basecamp, LLC
|
|
|
675
757
|
if (token) {
|
|
676
758
|
headers["X-CSRF-Token"] = token;
|
|
677
759
|
}
|
|
678
|
-
|
|
760
|
+
}
|
|
761
|
+
if (this.requestAcceptsTurboStreamResponse(request)) {
|
|
762
|
+
request.acceptResponseType(StreamMessage.contentType);
|
|
679
763
|
}
|
|
680
764
|
}
|
|
681
|
-
requestStarted(
|
|
765
|
+
requestStarted(_request) {
|
|
682
766
|
var _a;
|
|
683
767
|
this.state = FormSubmissionState.waiting;
|
|
684
768
|
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", "");
|
|
685
|
-
dispatch("turbo:submit-start", {
|
|
769
|
+
dispatch("turbo:submit-start", {
|
|
770
|
+
target: this.formElement,
|
|
771
|
+
detail: { formSubmission: this },
|
|
772
|
+
});
|
|
686
773
|
this.delegate.formSubmissionStarted(this);
|
|
687
774
|
}
|
|
688
775
|
requestPreventedHandlingResponse(request, response) {
|
|
@@ -708,25 +795,35 @@ Copyright © 2021 Basecamp, LLC
|
|
|
708
795
|
}
|
|
709
796
|
requestErrored(request, error) {
|
|
710
797
|
this.result = { success: false, error };
|
|
798
|
+
dispatch("turbo:fetch-request-error", {
|
|
799
|
+
target: this.formElement,
|
|
800
|
+
detail: { request, error },
|
|
801
|
+
});
|
|
711
802
|
this.delegate.formSubmissionErrored(this, error);
|
|
712
803
|
}
|
|
713
|
-
requestFinished(
|
|
804
|
+
requestFinished(_request) {
|
|
714
805
|
var _a;
|
|
715
806
|
this.state = FormSubmissionState.stopped;
|
|
716
807
|
(_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled");
|
|
717
|
-
dispatch("turbo:submit-end", {
|
|
808
|
+
dispatch("turbo:submit-end", {
|
|
809
|
+
target: this.formElement,
|
|
810
|
+
detail: Object.assign({ formSubmission: this }, this.result),
|
|
811
|
+
});
|
|
718
812
|
this.delegate.formSubmissionFinished(this);
|
|
719
813
|
}
|
|
720
814
|
requestMustRedirect(request) {
|
|
721
815
|
return !request.isIdempotent && this.mustRedirect;
|
|
722
816
|
}
|
|
817
|
+
requestAcceptsTurboStreamResponse(request) {
|
|
818
|
+
return !request.isIdempotent || this.formElement.hasAttribute("data-turbo-stream");
|
|
819
|
+
}
|
|
723
820
|
}
|
|
724
821
|
function buildFormData(formElement, submitter) {
|
|
725
822
|
const formData = new FormData(formElement);
|
|
726
823
|
const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name");
|
|
727
824
|
const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value");
|
|
728
|
-
if (name
|
|
729
|
-
formData.append(name, value);
|
|
825
|
+
if (name) {
|
|
826
|
+
formData.append(name, value || "");
|
|
730
827
|
}
|
|
731
828
|
return formData;
|
|
732
829
|
}
|
|
@@ -740,18 +837,27 @@ Copyright © 2021 Basecamp, LLC
|
|
|
740
837
|
}
|
|
741
838
|
}
|
|
742
839
|
}
|
|
743
|
-
function getMetaContent(name) {
|
|
744
|
-
const element = document.querySelector(`meta[name="${name}"]`);
|
|
745
|
-
return element && element.content;
|
|
746
|
-
}
|
|
747
840
|
function responseSucceededWithoutRedirect(response) {
|
|
748
841
|
return response.statusCode == 200 && !response.redirected;
|
|
749
842
|
}
|
|
843
|
+
function mergeFormDataEntries(url, entries) {
|
|
844
|
+
const searchParams = new URLSearchParams();
|
|
845
|
+
for (const [name, value] of entries) {
|
|
846
|
+
if (value instanceof File)
|
|
847
|
+
continue;
|
|
848
|
+
searchParams.append(name, value);
|
|
849
|
+
}
|
|
850
|
+
url.search = searchParams.toString();
|
|
851
|
+
return url;
|
|
852
|
+
}
|
|
750
853
|
|
|
751
854
|
class Snapshot {
|
|
752
855
|
constructor(element) {
|
|
753
856
|
this.element = element;
|
|
754
857
|
}
|
|
858
|
+
get activeElement() {
|
|
859
|
+
return this.element.ownerDocument.activeElement;
|
|
860
|
+
}
|
|
755
861
|
get children() {
|
|
756
862
|
return [...this.element.children];
|
|
757
863
|
}
|
|
@@ -765,7 +871,14 @@ Copyright © 2021 Basecamp, LLC
|
|
|
765
871
|
return this.element.isConnected;
|
|
766
872
|
}
|
|
767
873
|
get firstAutofocusableElement() {
|
|
768
|
-
|
|
874
|
+
const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
|
|
875
|
+
for (const element of this.element.querySelectorAll("[autofocus]")) {
|
|
876
|
+
if (element.closest(inertDisabledOrHidden) == null)
|
|
877
|
+
return element;
|
|
878
|
+
else
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
return null;
|
|
769
882
|
}
|
|
770
883
|
get permanentElements() {
|
|
771
884
|
return [...this.element.querySelectorAll("[id][data-turbo-permanent]")];
|
|
@@ -786,35 +899,59 @@ Copyright © 2021 Basecamp, LLC
|
|
|
786
899
|
}
|
|
787
900
|
}
|
|
788
901
|
|
|
789
|
-
class
|
|
790
|
-
constructor(delegate,
|
|
902
|
+
class FormSubmitObserver {
|
|
903
|
+
constructor(delegate, eventTarget) {
|
|
904
|
+
this.started = false;
|
|
905
|
+
this.submitCaptured = () => {
|
|
906
|
+
this.eventTarget.removeEventListener("submit", this.submitBubbled, false);
|
|
907
|
+
this.eventTarget.addEventListener("submit", this.submitBubbled, false);
|
|
908
|
+
};
|
|
791
909
|
this.submitBubbled = ((event) => {
|
|
792
|
-
|
|
793
|
-
|
|
910
|
+
if (!event.defaultPrevented) {
|
|
911
|
+
const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
|
794
912
|
const submitter = event.submitter || undefined;
|
|
795
|
-
|
|
796
|
-
|
|
913
|
+
if (form &&
|
|
914
|
+
submissionDoesNotDismissDialog(form, submitter) &&
|
|
915
|
+
submissionDoesNotTargetIFrame(form, submitter) &&
|
|
916
|
+
this.delegate.willSubmitForm(form, submitter)) {
|
|
797
917
|
event.preventDefault();
|
|
798
|
-
|
|
799
|
-
this.delegate.formSubmissionIntercepted(form, submitter);
|
|
918
|
+
this.delegate.formSubmitted(form, submitter);
|
|
800
919
|
}
|
|
801
920
|
}
|
|
802
921
|
});
|
|
803
922
|
this.delegate = delegate;
|
|
804
|
-
this.
|
|
923
|
+
this.eventTarget = eventTarget;
|
|
805
924
|
}
|
|
806
925
|
start() {
|
|
807
|
-
|
|
926
|
+
if (!this.started) {
|
|
927
|
+
this.eventTarget.addEventListener("submit", this.submitCaptured, true);
|
|
928
|
+
this.started = true;
|
|
929
|
+
}
|
|
808
930
|
}
|
|
809
931
|
stop() {
|
|
810
|
-
|
|
932
|
+
if (this.started) {
|
|
933
|
+
this.eventTarget.removeEventListener("submit", this.submitCaptured, true);
|
|
934
|
+
this.started = false;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function submissionDoesNotDismissDialog(form, submitter) {
|
|
939
|
+
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
|
|
940
|
+
return method != "dialog";
|
|
941
|
+
}
|
|
942
|
+
function submissionDoesNotTargetIFrame(form, submitter) {
|
|
943
|
+
const target = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formtarget")) || form.target;
|
|
944
|
+
for (const element of document.getElementsByName(target)) {
|
|
945
|
+
if (element instanceof HTMLIFrameElement)
|
|
946
|
+
return false;
|
|
811
947
|
}
|
|
948
|
+
return true;
|
|
812
949
|
}
|
|
813
950
|
|
|
814
951
|
class View {
|
|
815
952
|
constructor(delegate, element) {
|
|
816
|
-
this.resolveRenderPromise = (
|
|
817
|
-
this.resolveInterceptionPromise = (
|
|
953
|
+
this.resolveRenderPromise = (_value) => { };
|
|
954
|
+
this.resolveInterceptionPromise = (_value) => { };
|
|
818
955
|
this.delegate = delegate;
|
|
819
956
|
this.element = element;
|
|
820
957
|
}
|
|
@@ -859,15 +996,17 @@ Copyright © 2021 Basecamp, LLC
|
|
|
859
996
|
const { isPreview, shouldRender, newSnapshot: snapshot } = renderer;
|
|
860
997
|
if (shouldRender) {
|
|
861
998
|
try {
|
|
862
|
-
this.renderPromise = new Promise(resolve => this.resolveRenderPromise = resolve);
|
|
999
|
+
this.renderPromise = new Promise((resolve) => (this.resolveRenderPromise = resolve));
|
|
863
1000
|
this.renderer = renderer;
|
|
864
|
-
this.prepareToRenderSnapshot(renderer);
|
|
865
|
-
const renderInterception = new Promise(resolve => this.resolveInterceptionPromise = resolve);
|
|
866
|
-
const
|
|
1001
|
+
await this.prepareToRenderSnapshot(renderer);
|
|
1002
|
+
const renderInterception = new Promise((resolve) => (this.resolveInterceptionPromise = resolve));
|
|
1003
|
+
const options = { resume: this.resolveInterceptionPromise, render: this.renderer.renderElement };
|
|
1004
|
+
const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
|
|
867
1005
|
if (!immediateRender)
|
|
868
1006
|
await renderInterception;
|
|
869
1007
|
await this.renderSnapshot(renderer);
|
|
870
1008
|
this.delegate.viewRenderedSnapshot(snapshot, isPreview);
|
|
1009
|
+
this.delegate.preloadOnLoadLinksForView(this.element);
|
|
871
1010
|
this.finishRenderingSnapshot(renderer);
|
|
872
1011
|
}
|
|
873
1012
|
finally {
|
|
@@ -877,15 +1016,15 @@ Copyright © 2021 Basecamp, LLC
|
|
|
877
1016
|
}
|
|
878
1017
|
}
|
|
879
1018
|
else {
|
|
880
|
-
this.invalidate();
|
|
1019
|
+
this.invalidate(renderer.reloadReason);
|
|
881
1020
|
}
|
|
882
1021
|
}
|
|
883
|
-
invalidate() {
|
|
884
|
-
this.delegate.viewInvalidated();
|
|
1022
|
+
invalidate(reason) {
|
|
1023
|
+
this.delegate.viewInvalidated(reason);
|
|
885
1024
|
}
|
|
886
|
-
prepareToRenderSnapshot(renderer) {
|
|
1025
|
+
async prepareToRenderSnapshot(renderer) {
|
|
887
1026
|
this.markAsPreview(renderer.isPreview);
|
|
888
|
-
renderer.prepareToRender();
|
|
1027
|
+
await renderer.prepareToRender();
|
|
889
1028
|
}
|
|
890
1029
|
markAsPreview(isPreview) {
|
|
891
1030
|
if (isPreview) {
|
|
@@ -912,65 +1051,122 @@ Copyright © 2021 Basecamp, LLC
|
|
|
912
1051
|
}
|
|
913
1052
|
}
|
|
914
1053
|
|
|
915
|
-
class
|
|
916
|
-
constructor(delegate,
|
|
917
|
-
this.
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
else {
|
|
922
|
-
delete this.clickEvent;
|
|
923
|
-
}
|
|
1054
|
+
class LinkClickObserver {
|
|
1055
|
+
constructor(delegate, eventTarget) {
|
|
1056
|
+
this.started = false;
|
|
1057
|
+
this.clickCaptured = () => {
|
|
1058
|
+
this.eventTarget.removeEventListener("click", this.clickBubbled, false);
|
|
1059
|
+
this.eventTarget.addEventListener("click", this.clickBubbled, false);
|
|
924
1060
|
};
|
|
925
|
-
this.
|
|
926
|
-
if (
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
this.
|
|
1061
|
+
this.clickBubbled = (event) => {
|
|
1062
|
+
if (event instanceof MouseEvent && this.clickEventIsSignificant(event)) {
|
|
1063
|
+
const target = (event.composedPath && event.composedPath()[0]) || event.target;
|
|
1064
|
+
const link = this.findLinkFromClickTarget(target);
|
|
1065
|
+
if (link && doesNotTargetIFrame(link)) {
|
|
1066
|
+
const location = this.getLocationForLink(link);
|
|
1067
|
+
if (this.delegate.willFollowLinkToLocation(link, location, event)) {
|
|
1068
|
+
event.preventDefault();
|
|
1069
|
+
this.delegate.followedLinkToLocation(link, location);
|
|
1070
|
+
}
|
|
931
1071
|
}
|
|
932
1072
|
}
|
|
933
|
-
delete this.clickEvent;
|
|
934
|
-
});
|
|
935
|
-
this.willVisit = () => {
|
|
936
|
-
delete this.clickEvent;
|
|
937
1073
|
};
|
|
938
1074
|
this.delegate = delegate;
|
|
939
|
-
this.
|
|
1075
|
+
this.eventTarget = eventTarget;
|
|
1076
|
+
}
|
|
1077
|
+
start() {
|
|
1078
|
+
if (!this.started) {
|
|
1079
|
+
this.eventTarget.addEventListener("click", this.clickCaptured, true);
|
|
1080
|
+
this.started = true;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
stop() {
|
|
1084
|
+
if (this.started) {
|
|
1085
|
+
this.eventTarget.removeEventListener("click", this.clickCaptured, true);
|
|
1086
|
+
this.started = false;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
clickEventIsSignificant(event) {
|
|
1090
|
+
return !((event.target && event.target.isContentEditable) ||
|
|
1091
|
+
event.defaultPrevented ||
|
|
1092
|
+
event.which > 1 ||
|
|
1093
|
+
event.altKey ||
|
|
1094
|
+
event.ctrlKey ||
|
|
1095
|
+
event.metaKey ||
|
|
1096
|
+
event.shiftKey);
|
|
1097
|
+
}
|
|
1098
|
+
findLinkFromClickTarget(target) {
|
|
1099
|
+
if (target instanceof Element) {
|
|
1100
|
+
return target.closest("a[href]:not([target^=_]):not([download])");
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
getLocationForLink(link) {
|
|
1104
|
+
return expandURL(link.getAttribute("href") || "");
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function doesNotTargetIFrame(anchor) {
|
|
1108
|
+
for (const element of document.getElementsByName(anchor.target)) {
|
|
1109
|
+
if (element instanceof HTMLIFrameElement)
|
|
1110
|
+
return false;
|
|
1111
|
+
}
|
|
1112
|
+
return true;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
class FormLinkClickObserver {
|
|
1116
|
+
constructor(delegate, element) {
|
|
1117
|
+
this.delegate = delegate;
|
|
1118
|
+
this.linkClickObserver = new LinkClickObserver(this, element);
|
|
940
1119
|
}
|
|
941
1120
|
start() {
|
|
942
|
-
this.
|
|
943
|
-
document.addEventListener("turbo:click", this.linkClicked);
|
|
944
|
-
document.addEventListener("turbo:before-visit", this.willVisit);
|
|
1121
|
+
this.linkClickObserver.start();
|
|
945
1122
|
}
|
|
946
1123
|
stop() {
|
|
947
|
-
this.
|
|
948
|
-
|
|
949
|
-
|
|
1124
|
+
this.linkClickObserver.stop();
|
|
1125
|
+
}
|
|
1126
|
+
willFollowLinkToLocation(link, location, originalEvent) {
|
|
1127
|
+
return (this.delegate.willSubmitFormLinkToLocation(link, location, originalEvent) &&
|
|
1128
|
+
link.hasAttribute("data-turbo-method"));
|
|
950
1129
|
}
|
|
951
|
-
|
|
952
|
-
const
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1130
|
+
followedLinkToLocation(link, location) {
|
|
1131
|
+
const action = location.href;
|
|
1132
|
+
const form = document.createElement("form");
|
|
1133
|
+
form.setAttribute("data-turbo", "true");
|
|
1134
|
+
form.setAttribute("action", action);
|
|
1135
|
+
form.setAttribute("hidden", "");
|
|
1136
|
+
const method = link.getAttribute("data-turbo-method");
|
|
1137
|
+
if (method)
|
|
1138
|
+
form.setAttribute("method", method);
|
|
1139
|
+
const turboFrame = link.getAttribute("data-turbo-frame");
|
|
1140
|
+
if (turboFrame)
|
|
1141
|
+
form.setAttribute("data-turbo-frame", turboFrame);
|
|
1142
|
+
const turboConfirm = link.getAttribute("data-turbo-confirm");
|
|
1143
|
+
if (turboConfirm)
|
|
1144
|
+
form.setAttribute("data-turbo-confirm", turboConfirm);
|
|
1145
|
+
const turboStream = link.hasAttribute("data-turbo-stream");
|
|
1146
|
+
if (turboStream)
|
|
1147
|
+
form.setAttribute("data-turbo-stream", "");
|
|
1148
|
+
this.delegate.submittedFormLinkToLocation(link, location, form);
|
|
1149
|
+
document.body.appendChild(form);
|
|
1150
|
+
form.requestSubmit();
|
|
1151
|
+
form.remove();
|
|
958
1152
|
}
|
|
959
1153
|
}
|
|
960
1154
|
|
|
961
1155
|
class Bardo {
|
|
962
|
-
constructor(permanentElementMap) {
|
|
1156
|
+
constructor(delegate, permanentElementMap) {
|
|
1157
|
+
this.delegate = delegate;
|
|
963
1158
|
this.permanentElementMap = permanentElementMap;
|
|
964
1159
|
}
|
|
965
|
-
static preservingPermanentElements(permanentElementMap, callback) {
|
|
966
|
-
const bardo = new this(permanentElementMap);
|
|
1160
|
+
static preservingPermanentElements(delegate, permanentElementMap, callback) {
|
|
1161
|
+
const bardo = new this(delegate, permanentElementMap);
|
|
967
1162
|
bardo.enter();
|
|
968
1163
|
callback();
|
|
969
1164
|
bardo.leave();
|
|
970
1165
|
}
|
|
971
1166
|
enter() {
|
|
972
1167
|
for (const id in this.permanentElementMap) {
|
|
973
|
-
const [, newPermanentElement] = this.permanentElementMap[id];
|
|
1168
|
+
const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id];
|
|
1169
|
+
this.delegate.enteringBardo(currentPermanentElement, newPermanentElement);
|
|
974
1170
|
this.replaceNewPermanentElementWithPlaceholder(newPermanentElement);
|
|
975
1171
|
}
|
|
976
1172
|
}
|
|
@@ -979,6 +1175,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
979
1175
|
const [currentPermanentElement] = this.permanentElementMap[id];
|
|
980
1176
|
this.replaceCurrentPermanentElementWithClone(currentPermanentElement);
|
|
981
1177
|
this.replacePlaceholderWithPermanentElement(currentPermanentElement);
|
|
1178
|
+
this.delegate.leavingBardo(currentPermanentElement);
|
|
982
1179
|
}
|
|
983
1180
|
}
|
|
984
1181
|
replaceNewPermanentElementWithPlaceholder(permanentElement) {
|
|
@@ -994,7 +1191,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
994
1191
|
placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement);
|
|
995
1192
|
}
|
|
996
1193
|
getPlaceholderById(id) {
|
|
997
|
-
return this.placeholders.find(element => element.content == id);
|
|
1194
|
+
return this.placeholders.find((element) => element.content == id);
|
|
998
1195
|
}
|
|
999
1196
|
get placeholders() {
|
|
1000
1197
|
return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")];
|
|
@@ -1008,16 +1205,21 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1008
1205
|
}
|
|
1009
1206
|
|
|
1010
1207
|
class Renderer {
|
|
1011
|
-
constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) {
|
|
1208
|
+
constructor(currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
|
1209
|
+
this.activeElement = null;
|
|
1012
1210
|
this.currentSnapshot = currentSnapshot;
|
|
1013
1211
|
this.newSnapshot = newSnapshot;
|
|
1014
1212
|
this.isPreview = isPreview;
|
|
1015
1213
|
this.willRender = willRender;
|
|
1016
|
-
this.
|
|
1214
|
+
this.renderElement = renderElement;
|
|
1215
|
+
this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));
|
|
1017
1216
|
}
|
|
1018
1217
|
get shouldRender() {
|
|
1019
1218
|
return true;
|
|
1020
1219
|
}
|
|
1220
|
+
get reloadReason() {
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1021
1223
|
prepareToRender() {
|
|
1022
1224
|
return;
|
|
1023
1225
|
}
|
|
@@ -1027,23 +1229,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1027
1229
|
delete this.resolvingFunctions;
|
|
1028
1230
|
}
|
|
1029
1231
|
}
|
|
1030
|
-
createScriptElement(element) {
|
|
1031
|
-
if (element.getAttribute("data-turbo-eval") == "false") {
|
|
1032
|
-
return element;
|
|
1033
|
-
}
|
|
1034
|
-
else {
|
|
1035
|
-
const createdScriptElement = document.createElement("script");
|
|
1036
|
-
if (this.cspNonce) {
|
|
1037
|
-
createdScriptElement.nonce = this.cspNonce;
|
|
1038
|
-
}
|
|
1039
|
-
createdScriptElement.textContent = element.textContent;
|
|
1040
|
-
createdScriptElement.async = false;
|
|
1041
|
-
copyElementAttributes(createdScriptElement, element);
|
|
1042
|
-
return createdScriptElement;
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
1232
|
preservingPermanentElements(callback) {
|
|
1046
|
-
Bardo.preservingPermanentElements(this.permanentElementMap, callback);
|
|
1233
|
+
Bardo.preservingPermanentElements(this, this.permanentElementMap, callback);
|
|
1047
1234
|
}
|
|
1048
1235
|
focusFirstAutofocusableElement() {
|
|
1049
1236
|
const element = this.connectedSnapshot.firstAutofocusableElement;
|
|
@@ -1051,6 +1238,19 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1051
1238
|
element.focus();
|
|
1052
1239
|
}
|
|
1053
1240
|
}
|
|
1241
|
+
enteringBardo(currentPermanentElement) {
|
|
1242
|
+
if (this.activeElement)
|
|
1243
|
+
return;
|
|
1244
|
+
if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) {
|
|
1245
|
+
this.activeElement = this.currentSnapshot.activeElement;
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
leavingBardo(currentPermanentElement) {
|
|
1249
|
+
if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) {
|
|
1250
|
+
this.activeElement.focus();
|
|
1251
|
+
this.activeElement = null;
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1054
1254
|
get connectedSnapshot() {
|
|
1055
1255
|
return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot;
|
|
1056
1256
|
}
|
|
@@ -1063,21 +1263,28 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1063
1263
|
get permanentElementMap() {
|
|
1064
1264
|
return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot);
|
|
1065
1265
|
}
|
|
1066
|
-
get cspNonce() {
|
|
1067
|
-
var _a;
|
|
1068
|
-
return (_a = document.head.querySelector('meta[name="csp-nonce"]')) === null || _a === void 0 ? void 0 : _a.getAttribute("content");
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
function copyElementAttributes(destinationElement, sourceElement) {
|
|
1072
|
-
for (const { name, value } of [...sourceElement.attributes]) {
|
|
1073
|
-
destinationElement.setAttribute(name, value);
|
|
1074
|
-
}
|
|
1075
1266
|
}
|
|
1076
1267
|
function elementIsFocusable(element) {
|
|
1077
1268
|
return element && typeof element.focus == "function";
|
|
1078
1269
|
}
|
|
1079
1270
|
|
|
1080
1271
|
class FrameRenderer extends Renderer {
|
|
1272
|
+
constructor(delegate, currentSnapshot, newSnapshot, renderElement, isPreview, willRender = true) {
|
|
1273
|
+
super(currentSnapshot, newSnapshot, renderElement, isPreview, willRender);
|
|
1274
|
+
this.delegate = delegate;
|
|
1275
|
+
}
|
|
1276
|
+
static renderElement(currentElement, newElement) {
|
|
1277
|
+
var _a;
|
|
1278
|
+
const destinationRange = document.createRange();
|
|
1279
|
+
destinationRange.selectNodeContents(currentElement);
|
|
1280
|
+
destinationRange.deleteContents();
|
|
1281
|
+
const frameElement = newElement;
|
|
1282
|
+
const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
|
1283
|
+
if (sourceRange) {
|
|
1284
|
+
sourceRange.selectNodeContents(frameElement);
|
|
1285
|
+
currentElement.appendChild(sourceRange.extractContents());
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1081
1288
|
get shouldRender() {
|
|
1082
1289
|
return true;
|
|
1083
1290
|
}
|
|
@@ -1093,23 +1300,16 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1093
1300
|
this.activateScriptElements();
|
|
1094
1301
|
}
|
|
1095
1302
|
loadFrameElement() {
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
destinationRange.selectNodeContents(this.currentElement);
|
|
1099
|
-
destinationRange.deleteContents();
|
|
1100
|
-
const frameElement = this.newElement;
|
|
1101
|
-
const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange();
|
|
1102
|
-
if (sourceRange) {
|
|
1103
|
-
sourceRange.selectNodeContents(frameElement);
|
|
1104
|
-
this.currentElement.appendChild(sourceRange.extractContents());
|
|
1105
|
-
}
|
|
1303
|
+
this.delegate.willRenderFrame(this.currentElement, this.newElement);
|
|
1304
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
1106
1305
|
}
|
|
1107
1306
|
scrollFrameIntoView() {
|
|
1108
1307
|
if (this.currentElement.autoscroll || this.newElement.autoscroll) {
|
|
1109
1308
|
const element = this.currentElement.firstElementChild;
|
|
1110
1309
|
const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end");
|
|
1310
|
+
const behavior = readScrollBehavior(this.currentElement.getAttribute("data-autoscroll-behavior"), "auto");
|
|
1111
1311
|
if (element) {
|
|
1112
|
-
element.scrollIntoView({ block });
|
|
1312
|
+
element.scrollIntoView({ block, behavior });
|
|
1113
1313
|
return true;
|
|
1114
1314
|
}
|
|
1115
1315
|
}
|
|
@@ -1117,7 +1317,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1117
1317
|
}
|
|
1118
1318
|
activateScriptElements() {
|
|
1119
1319
|
for (const inertScriptElement of this.newScriptElements) {
|
|
1120
|
-
const activatedScriptElement =
|
|
1320
|
+
const activatedScriptElement = activateScriptElement(inertScriptElement);
|
|
1121
1321
|
inertScriptElement.replaceWith(activatedScriptElement);
|
|
1122
1322
|
}
|
|
1123
1323
|
}
|
|
@@ -1133,6 +1333,14 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1133
1333
|
return defaultValue;
|
|
1134
1334
|
}
|
|
1135
1335
|
}
|
|
1336
|
+
function readScrollBehavior(value, defaultValue) {
|
|
1337
|
+
if (value == "auto" || value == "smooth") {
|
|
1338
|
+
return value;
|
|
1339
|
+
}
|
|
1340
|
+
else {
|
|
1341
|
+
return defaultValue;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1136
1344
|
|
|
1137
1345
|
class ProgressBar {
|
|
1138
1346
|
constructor() {
|
|
@@ -1156,7 +1364,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1156
1364
|
left: 0;
|
|
1157
1365
|
height: 3px;
|
|
1158
1366
|
background: #0076ff;
|
|
1159
|
-
z-index:
|
|
1367
|
+
z-index: 2147483647;
|
|
1160
1368
|
transition:
|
|
1161
1369
|
width ${ProgressBar.animationDuration}ms ease-out,
|
|
1162
1370
|
opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in;
|
|
@@ -1215,13 +1423,16 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1215
1423
|
}
|
|
1216
1424
|
refresh() {
|
|
1217
1425
|
requestAnimationFrame(() => {
|
|
1218
|
-
this.progressElement.style.width = `${10 +
|
|
1426
|
+
this.progressElement.style.width = `${10 + this.value * 90}%`;
|
|
1219
1427
|
});
|
|
1220
1428
|
}
|
|
1221
1429
|
createStylesheetElement() {
|
|
1222
1430
|
const element = document.createElement("style");
|
|
1223
1431
|
element.type = "text/css";
|
|
1224
1432
|
element.textContent = ProgressBar.defaultCSS;
|
|
1433
|
+
if (this.cspNonce) {
|
|
1434
|
+
element.nonce = this.cspNonce;
|
|
1435
|
+
}
|
|
1225
1436
|
return element;
|
|
1226
1437
|
}
|
|
1227
1438
|
createProgressElement() {
|
|
@@ -1229,6 +1440,9 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1229
1440
|
element.className = "turbo-progress-bar";
|
|
1230
1441
|
return element;
|
|
1231
1442
|
}
|
|
1443
|
+
get cspNonce() {
|
|
1444
|
+
return getMetaContent("csp-nonce");
|
|
1445
|
+
}
|
|
1232
1446
|
}
|
|
1233
1447
|
ProgressBar.animationDuration = 300;
|
|
1234
1448
|
|
|
@@ -1245,14 +1459,14 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1245
1459
|
: {
|
|
1246
1460
|
type: elementType(element),
|
|
1247
1461
|
tracked: elementIsTracked(element),
|
|
1248
|
-
elements: []
|
|
1462
|
+
elements: [],
|
|
1249
1463
|
};
|
|
1250
1464
|
return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) });
|
|
1251
1465
|
}, {});
|
|
1252
1466
|
}
|
|
1253
1467
|
get trackedElementSignature() {
|
|
1254
1468
|
return Object.keys(this.detailsByOuterHTML)
|
|
1255
|
-
.filter(outerHTML => this.detailsByOuterHTML[outerHTML].tracked)
|
|
1469
|
+
.filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked)
|
|
1256
1470
|
.join("");
|
|
1257
1471
|
}
|
|
1258
1472
|
getScriptElementsNotInSnapshot(snapshot) {
|
|
@@ -1263,8 +1477,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1263
1477
|
}
|
|
1264
1478
|
getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) {
|
|
1265
1479
|
return Object.keys(this.detailsByOuterHTML)
|
|
1266
|
-
.filter(outerHTML => !(outerHTML in snapshot.detailsByOuterHTML))
|
|
1267
|
-
.map(outerHTML => this.detailsByOuterHTML[outerHTML])
|
|
1480
|
+
.filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML))
|
|
1481
|
+
.map((outerHTML) => this.detailsByOuterHTML[outerHTML])
|
|
1268
1482
|
.filter(({ type }) => type == matchedType)
|
|
1269
1483
|
.map(({ elements: [element] }) => element);
|
|
1270
1484
|
}
|
|
@@ -1284,13 +1498,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1284
1498
|
}
|
|
1285
1499
|
getMetaValue(name) {
|
|
1286
1500
|
const element = this.findMetaElementByName(name);
|
|
1287
|
-
return element
|
|
1288
|
-
? element.getAttribute("content")
|
|
1289
|
-
: null;
|
|
1501
|
+
return element ? element.getAttribute("content") : null;
|
|
1290
1502
|
}
|
|
1291
1503
|
findMetaElementByName(name) {
|
|
1292
1504
|
return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => {
|
|
1293
|
-
const { elements: [element] } = this.detailsByOuterHTML[outerHTML];
|
|
1505
|
+
const { elements: [element], } = this.detailsByOuterHTML[outerHTML];
|
|
1294
1506
|
return elementIsMetaElementWithName(element, name) ? element : result;
|
|
1295
1507
|
}, undefined);
|
|
1296
1508
|
}
|
|
@@ -1391,6 +1603,9 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1391
1603
|
historyChanged: false,
|
|
1392
1604
|
visitCachedSnapshot: () => { },
|
|
1393
1605
|
willRender: true,
|
|
1606
|
+
updateHistory: true,
|
|
1607
|
+
shouldCacheSnapshot: true,
|
|
1608
|
+
acceptsStreamResponse: false,
|
|
1394
1609
|
};
|
|
1395
1610
|
var SystemStatusCode;
|
|
1396
1611
|
(function (SystemStatusCode) {
|
|
@@ -1405,12 +1620,15 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1405
1620
|
this.followedRedirect = false;
|
|
1406
1621
|
this.historyChanged = false;
|
|
1407
1622
|
this.scrolled = false;
|
|
1623
|
+
this.shouldCacheSnapshot = true;
|
|
1624
|
+
this.acceptsStreamResponse = false;
|
|
1408
1625
|
this.snapshotCached = false;
|
|
1409
1626
|
this.state = VisitState.initialized;
|
|
1410
1627
|
this.delegate = delegate;
|
|
1411
1628
|
this.location = location;
|
|
1412
1629
|
this.restorationIdentifier = restorationIdentifier || uuid();
|
|
1413
|
-
|
|
1630
|
+
this.promise = new Promise((resolve, reject) => (this.resolvingFunctions = { resolve, reject }));
|
|
1631
|
+
const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender, updateHistory, shouldCacheSnapshot, acceptsStreamResponse, } = Object.assign(Object.assign({}, defaultOptions), options);
|
|
1414
1632
|
this.action = action;
|
|
1415
1633
|
this.historyChanged = historyChanged;
|
|
1416
1634
|
this.referrer = referrer;
|
|
@@ -1419,7 +1637,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1419
1637
|
this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
|
|
1420
1638
|
this.visitCachedSnapshot = visitCachedSnapshot;
|
|
1421
1639
|
this.willRender = willRender;
|
|
1640
|
+
this.updateHistory = updateHistory;
|
|
1422
1641
|
this.scrolled = !willRender;
|
|
1642
|
+
this.shouldCacheSnapshot = shouldCacheSnapshot;
|
|
1643
|
+
this.acceptsStreamResponse = acceptsStreamResponse;
|
|
1423
1644
|
}
|
|
1424
1645
|
get adapter() {
|
|
1425
1646
|
return this.delegate.adapter;
|
|
@@ -1451,28 +1672,33 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1451
1672
|
}
|
|
1452
1673
|
this.cancelRender();
|
|
1453
1674
|
this.state = VisitState.canceled;
|
|
1675
|
+
this.resolvingFunctions.reject();
|
|
1454
1676
|
}
|
|
1455
1677
|
}
|
|
1456
1678
|
complete() {
|
|
1457
1679
|
if (this.state == VisitState.started) {
|
|
1458
1680
|
this.recordTimingMetric(TimingMetric.visitEnd);
|
|
1459
1681
|
this.state = VisitState.completed;
|
|
1460
|
-
this.adapter.visitCompleted(this);
|
|
1461
|
-
this.delegate.visitCompleted(this);
|
|
1462
1682
|
this.followRedirect();
|
|
1683
|
+
if (!this.followedRedirect) {
|
|
1684
|
+
this.adapter.visitCompleted(this);
|
|
1685
|
+
this.delegate.visitCompleted(this);
|
|
1686
|
+
}
|
|
1687
|
+
this.resolvingFunctions.resolve();
|
|
1463
1688
|
}
|
|
1464
1689
|
}
|
|
1465
1690
|
fail() {
|
|
1466
1691
|
if (this.state == VisitState.started) {
|
|
1467
1692
|
this.state = VisitState.failed;
|
|
1468
1693
|
this.adapter.visitFailed(this);
|
|
1694
|
+
this.resolvingFunctions.reject();
|
|
1469
1695
|
}
|
|
1470
1696
|
}
|
|
1471
1697
|
changeHistory() {
|
|
1472
1698
|
var _a;
|
|
1473
|
-
if (!this.historyChanged) {
|
|
1699
|
+
if (!this.historyChanged && this.updateHistory) {
|
|
1474
1700
|
const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action;
|
|
1475
|
-
const method =
|
|
1701
|
+
const method = getHistoryMethodForAction(actionForHistory);
|
|
1476
1702
|
this.history.update(method, this.location, this.restorationIdentifier);
|
|
1477
1703
|
this.historyChanged = true;
|
|
1478
1704
|
}
|
|
@@ -1517,16 +1743,18 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1517
1743
|
if (this.response) {
|
|
1518
1744
|
const { statusCode, responseHTML } = this.response;
|
|
1519
1745
|
this.render(async () => {
|
|
1520
|
-
this.
|
|
1746
|
+
if (this.shouldCacheSnapshot)
|
|
1747
|
+
this.cacheSnapshot();
|
|
1521
1748
|
if (this.view.renderPromise)
|
|
1522
1749
|
await this.view.renderPromise;
|
|
1523
1750
|
if (isSuccessful(statusCode) && responseHTML != null) {
|
|
1524
|
-
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender);
|
|
1751
|
+
await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender, this);
|
|
1752
|
+
this.performScroll();
|
|
1525
1753
|
this.adapter.visitRendered(this);
|
|
1526
1754
|
this.complete();
|
|
1527
1755
|
}
|
|
1528
1756
|
else {
|
|
1529
|
-
await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML));
|
|
1757
|
+
await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML), this);
|
|
1530
1758
|
this.adapter.visitRendered(this);
|
|
1531
1759
|
this.fail();
|
|
1532
1760
|
}
|
|
@@ -1561,7 +1789,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1561
1789
|
else {
|
|
1562
1790
|
if (this.view.renderPromise)
|
|
1563
1791
|
await this.view.renderPromise;
|
|
1564
|
-
await this.view.renderPage(snapshot, isPreview, this.willRender);
|
|
1792
|
+
await this.view.renderPage(snapshot, isPreview, this.willRender, this);
|
|
1793
|
+
this.performScroll();
|
|
1565
1794
|
this.adapter.visitRendered(this);
|
|
1566
1795
|
if (!isPreview) {
|
|
1567
1796
|
this.complete();
|
|
@@ -1574,8 +1803,9 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1574
1803
|
var _a;
|
|
1575
1804
|
if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) {
|
|
1576
1805
|
this.adapter.visitProposedToLocation(this.redirectedToLocation, {
|
|
1577
|
-
action:
|
|
1578
|
-
|
|
1806
|
+
action: "replace",
|
|
1807
|
+
willRender: false,
|
|
1808
|
+
response: this.response,
|
|
1579
1809
|
});
|
|
1580
1810
|
this.followedRedirect = true;
|
|
1581
1811
|
}
|
|
@@ -1584,20 +1814,28 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1584
1814
|
if (this.isSamePage) {
|
|
1585
1815
|
this.render(async () => {
|
|
1586
1816
|
this.cacheSnapshot();
|
|
1817
|
+
this.performScroll();
|
|
1587
1818
|
this.adapter.visitRendered(this);
|
|
1588
1819
|
});
|
|
1589
1820
|
}
|
|
1590
1821
|
}
|
|
1822
|
+
prepareHeadersForRequest(headers, request) {
|
|
1823
|
+
if (this.acceptsStreamResponse) {
|
|
1824
|
+
request.acceptResponseType(StreamMessage.contentType);
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1591
1827
|
requestStarted() {
|
|
1592
1828
|
this.startRequest();
|
|
1593
1829
|
}
|
|
1594
|
-
requestPreventedHandlingResponse(
|
|
1595
|
-
}
|
|
1830
|
+
requestPreventedHandlingResponse(_request, _response) { }
|
|
1596
1831
|
async requestSucceededWithResponse(request, response) {
|
|
1597
1832
|
const responseHTML = await response.responseHTML;
|
|
1598
1833
|
const { redirected, statusCode } = response;
|
|
1599
1834
|
if (responseHTML == undefined) {
|
|
1600
|
-
this.recordResponse({
|
|
1835
|
+
this.recordResponse({
|
|
1836
|
+
statusCode: SystemStatusCode.contentTypeMismatch,
|
|
1837
|
+
redirected,
|
|
1838
|
+
});
|
|
1601
1839
|
}
|
|
1602
1840
|
else {
|
|
1603
1841
|
this.redirectedToLocation = response.redirected ? response.location : undefined;
|
|
@@ -1608,20 +1846,26 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1608
1846
|
const responseHTML = await response.responseHTML;
|
|
1609
1847
|
const { redirected, statusCode } = response;
|
|
1610
1848
|
if (responseHTML == undefined) {
|
|
1611
|
-
this.recordResponse({
|
|
1849
|
+
this.recordResponse({
|
|
1850
|
+
statusCode: SystemStatusCode.contentTypeMismatch,
|
|
1851
|
+
redirected,
|
|
1852
|
+
});
|
|
1612
1853
|
}
|
|
1613
1854
|
else {
|
|
1614
1855
|
this.recordResponse({ statusCode: statusCode, responseHTML, redirected });
|
|
1615
1856
|
}
|
|
1616
1857
|
}
|
|
1617
|
-
requestErrored(
|
|
1618
|
-
this.recordResponse({
|
|
1858
|
+
requestErrored(_request, _error) {
|
|
1859
|
+
this.recordResponse({
|
|
1860
|
+
statusCode: SystemStatusCode.networkFailure,
|
|
1861
|
+
redirected: false,
|
|
1862
|
+
});
|
|
1619
1863
|
}
|
|
1620
1864
|
requestFinished() {
|
|
1621
1865
|
this.finishRequest();
|
|
1622
1866
|
}
|
|
1623
1867
|
performScroll() {
|
|
1624
|
-
if (!this.scrolled) {
|
|
1868
|
+
if (!this.scrolled && !this.view.forceReloaded) {
|
|
1625
1869
|
if (this.action == "restore") {
|
|
1626
1870
|
this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop();
|
|
1627
1871
|
}
|
|
@@ -1656,9 +1900,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1656
1900
|
}
|
|
1657
1901
|
getHistoryMethodForAction(action) {
|
|
1658
1902
|
switch (action) {
|
|
1659
|
-
case "replace":
|
|
1903
|
+
case "replace":
|
|
1904
|
+
return history.replaceState;
|
|
1660
1905
|
case "advance":
|
|
1661
|
-
case "restore":
|
|
1906
|
+
case "restore":
|
|
1907
|
+
return history.pushState;
|
|
1662
1908
|
}
|
|
1663
1909
|
}
|
|
1664
1910
|
hasPreloadedResponse() {
|
|
@@ -1677,18 +1923,17 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1677
1923
|
}
|
|
1678
1924
|
cacheSnapshot() {
|
|
1679
1925
|
if (!this.snapshotCached) {
|
|
1680
|
-
this.view.cacheSnapshot().then(snapshot => snapshot && this.visitCachedSnapshot(snapshot));
|
|
1926
|
+
this.view.cacheSnapshot().then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot));
|
|
1681
1927
|
this.snapshotCached = true;
|
|
1682
1928
|
}
|
|
1683
1929
|
}
|
|
1684
1930
|
async render(callback) {
|
|
1685
1931
|
this.cancelRender();
|
|
1686
|
-
await new Promise(resolve => {
|
|
1932
|
+
await new Promise((resolve) => {
|
|
1687
1933
|
this.frame = requestAnimationFrame(() => resolve());
|
|
1688
1934
|
});
|
|
1689
1935
|
await callback();
|
|
1690
1936
|
delete this.frame;
|
|
1691
|
-
this.performScroll();
|
|
1692
1937
|
}
|
|
1693
1938
|
cancelRender() {
|
|
1694
1939
|
if (this.frame) {
|
|
@@ -1703,19 +1948,19 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1703
1948
|
|
|
1704
1949
|
class BrowserAdapter {
|
|
1705
1950
|
constructor(session) {
|
|
1706
|
-
this.progressBar = new ProgressBar;
|
|
1951
|
+
this.progressBar = new ProgressBar();
|
|
1707
1952
|
this.showProgressBar = () => {
|
|
1708
1953
|
this.progressBar.show();
|
|
1709
1954
|
};
|
|
1710
1955
|
this.session = session;
|
|
1711
1956
|
}
|
|
1712
1957
|
visitProposedToLocation(location, options) {
|
|
1713
|
-
this.navigator.startVisit(location, uuid(), options);
|
|
1958
|
+
return this.navigator.startVisit(location, (options === null || options === void 0 ? void 0 : options.restorationIdentifier) || uuid(), options);
|
|
1714
1959
|
}
|
|
1715
1960
|
visitStarted(visit) {
|
|
1961
|
+
this.location = visit.location;
|
|
1716
1962
|
visit.loadCachedSnapshot();
|
|
1717
1963
|
visit.issueRequest();
|
|
1718
|
-
visit.changeHistory();
|
|
1719
1964
|
visit.goToSamePageAnchor();
|
|
1720
1965
|
}
|
|
1721
1966
|
visitRequestStarted(visit) {
|
|
@@ -1735,29 +1980,31 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1735
1980
|
case SystemStatusCode.networkFailure:
|
|
1736
1981
|
case SystemStatusCode.timeoutFailure:
|
|
1737
1982
|
case SystemStatusCode.contentTypeMismatch:
|
|
1738
|
-
return this.reload(
|
|
1983
|
+
return this.reload({
|
|
1984
|
+
reason: "request_failed",
|
|
1985
|
+
context: {
|
|
1986
|
+
statusCode,
|
|
1987
|
+
},
|
|
1988
|
+
});
|
|
1739
1989
|
default:
|
|
1740
1990
|
return visit.loadResponse();
|
|
1741
1991
|
}
|
|
1742
1992
|
}
|
|
1743
|
-
visitRequestFinished(
|
|
1993
|
+
visitRequestFinished(_visit) {
|
|
1744
1994
|
this.progressBar.setValue(1);
|
|
1745
1995
|
this.hideVisitProgressBar();
|
|
1746
1996
|
}
|
|
1747
|
-
visitCompleted(
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
this.reload();
|
|
1751
|
-
}
|
|
1752
|
-
visitFailed(visit) {
|
|
1997
|
+
visitCompleted(_visit) { }
|
|
1998
|
+
pageInvalidated(reason) {
|
|
1999
|
+
this.reload(reason);
|
|
1753
2000
|
}
|
|
1754
|
-
|
|
1755
|
-
}
|
|
1756
|
-
formSubmissionStarted(
|
|
2001
|
+
visitFailed(_visit) { }
|
|
2002
|
+
visitRendered(_visit) { }
|
|
2003
|
+
formSubmissionStarted(_formSubmission) {
|
|
1757
2004
|
this.progressBar.setValue(0);
|
|
1758
2005
|
this.showFormProgressBarAfterDelay();
|
|
1759
2006
|
}
|
|
1760
|
-
formSubmissionFinished(
|
|
2007
|
+
formSubmissionFinished(_formSubmission) {
|
|
1761
2008
|
this.progressBar.setValue(1);
|
|
1762
2009
|
this.hideFormProgressBar();
|
|
1763
2010
|
}
|
|
@@ -1783,8 +2030,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1783
2030
|
delete this.formProgressBarTimeout;
|
|
1784
2031
|
}
|
|
1785
2032
|
}
|
|
1786
|
-
reload() {
|
|
1787
|
-
|
|
2033
|
+
reload(reason) {
|
|
2034
|
+
dispatch("turbo:reload", { detail: reason });
|
|
2035
|
+
if (!this.location)
|
|
2036
|
+
return;
|
|
2037
|
+
window.location.href = this.location.toString();
|
|
1788
2038
|
}
|
|
1789
2039
|
get navigator() {
|
|
1790
2040
|
return this.session.navigator;
|
|
@@ -1794,94 +2044,60 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1794
2044
|
class CacheObserver {
|
|
1795
2045
|
constructor() {
|
|
1796
2046
|
this.started = false;
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
addEventListener("turbo:before-cache", this.removeStaleElements, false);
|
|
1802
|
-
}
|
|
1803
|
-
}
|
|
1804
|
-
stop() {
|
|
1805
|
-
if (this.started) {
|
|
1806
|
-
this.started = false;
|
|
1807
|
-
removeEventListener("turbo:before-cache", this.removeStaleElements, false);
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
removeStaleElements() {
|
|
1811
|
-
const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
|
|
1812
|
-
for (const element of staleElements) {
|
|
1813
|
-
element.remove();
|
|
1814
|
-
}
|
|
1815
|
-
}
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
class FormSubmitObserver {
|
|
1819
|
-
constructor(delegate) {
|
|
1820
|
-
this.started = false;
|
|
1821
|
-
this.submitCaptured = () => {
|
|
1822
|
-
removeEventListener("submit", this.submitBubbled, false);
|
|
1823
|
-
addEventListener("submit", this.submitBubbled, false);
|
|
1824
|
-
};
|
|
1825
|
-
this.submitBubbled = ((event) => {
|
|
1826
|
-
if (!event.defaultPrevented) {
|
|
1827
|
-
const form = event.target instanceof HTMLFormElement ? event.target : undefined;
|
|
1828
|
-
const submitter = event.submitter || undefined;
|
|
1829
|
-
if (form) {
|
|
1830
|
-
const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method");
|
|
1831
|
-
if (method != "dialog" && this.delegate.willSubmitForm(form, submitter)) {
|
|
1832
|
-
event.preventDefault();
|
|
1833
|
-
this.delegate.formSubmitted(form, submitter);
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
2047
|
+
this.removeStaleElements = ((_event) => {
|
|
2048
|
+
const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')];
|
|
2049
|
+
for (const element of staleElements) {
|
|
2050
|
+
element.remove();
|
|
1836
2051
|
}
|
|
1837
2052
|
});
|
|
1838
|
-
this.delegate = delegate;
|
|
1839
2053
|
}
|
|
1840
2054
|
start() {
|
|
1841
2055
|
if (!this.started) {
|
|
1842
|
-
addEventListener("submit", this.submitCaptured, true);
|
|
1843
2056
|
this.started = true;
|
|
2057
|
+
addEventListener("turbo:before-cache", this.removeStaleElements, false);
|
|
1844
2058
|
}
|
|
1845
2059
|
}
|
|
1846
2060
|
stop() {
|
|
1847
2061
|
if (this.started) {
|
|
1848
|
-
removeEventListener("submit", this.submitCaptured, true);
|
|
1849
2062
|
this.started = false;
|
|
2063
|
+
removeEventListener("turbo:before-cache", this.removeStaleElements, false);
|
|
1850
2064
|
}
|
|
1851
2065
|
}
|
|
1852
2066
|
}
|
|
1853
2067
|
|
|
1854
2068
|
class FrameRedirector {
|
|
1855
|
-
constructor(element) {
|
|
2069
|
+
constructor(session, element) {
|
|
2070
|
+
this.session = session;
|
|
1856
2071
|
this.element = element;
|
|
1857
|
-
this.
|
|
1858
|
-
this.
|
|
2072
|
+
this.linkClickObserver = new LinkClickObserver(this, element);
|
|
2073
|
+
this.formSubmitObserver = new FormSubmitObserver(this, element);
|
|
1859
2074
|
}
|
|
1860
2075
|
start() {
|
|
1861
|
-
this.
|
|
1862
|
-
this.
|
|
2076
|
+
this.linkClickObserver.start();
|
|
2077
|
+
this.formSubmitObserver.start();
|
|
1863
2078
|
}
|
|
1864
2079
|
stop() {
|
|
1865
|
-
this.
|
|
1866
|
-
this.
|
|
2080
|
+
this.linkClickObserver.stop();
|
|
2081
|
+
this.formSubmitObserver.stop();
|
|
1867
2082
|
}
|
|
1868
|
-
|
|
2083
|
+
willFollowLinkToLocation(element) {
|
|
1869
2084
|
return this.shouldRedirect(element);
|
|
1870
2085
|
}
|
|
1871
|
-
|
|
2086
|
+
followedLinkToLocation(element, url) {
|
|
1872
2087
|
const frame = this.findFrameElement(element);
|
|
1873
2088
|
if (frame) {
|
|
1874
|
-
frame.delegate.
|
|
2089
|
+
frame.delegate.followedLinkToLocation(element, url);
|
|
1875
2090
|
}
|
|
1876
2091
|
}
|
|
1877
|
-
|
|
1878
|
-
return
|
|
2092
|
+
willSubmitForm(element, submitter) {
|
|
2093
|
+
return (element.closest("turbo-frame") == null &&
|
|
2094
|
+
this.shouldSubmit(element, submitter) &&
|
|
2095
|
+
this.shouldRedirect(element, submitter));
|
|
1879
2096
|
}
|
|
1880
|
-
|
|
2097
|
+
formSubmitted(element, submitter) {
|
|
1881
2098
|
const frame = this.findFrameElement(element, submitter);
|
|
1882
2099
|
if (frame) {
|
|
1883
|
-
frame.
|
|
1884
|
-
frame.delegate.formSubmissionIntercepted(element, submitter);
|
|
2100
|
+
frame.delegate.formSubmitted(element, submitter);
|
|
1885
2101
|
}
|
|
1886
2102
|
}
|
|
1887
2103
|
shouldSubmit(form, submitter) {
|
|
@@ -1892,8 +2108,16 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1892
2108
|
return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation);
|
|
1893
2109
|
}
|
|
1894
2110
|
shouldRedirect(element, submitter) {
|
|
1895
|
-
const
|
|
1896
|
-
|
|
2111
|
+
const isNavigatable = element instanceof HTMLFormElement
|
|
2112
|
+
? this.session.submissionIsNavigatable(element, submitter)
|
|
2113
|
+
: this.session.elementIsNavigatable(element);
|
|
2114
|
+
if (isNavigatable) {
|
|
2115
|
+
const frame = this.findFrameElement(element, submitter);
|
|
2116
|
+
return frame ? frame != element.closest("turbo-frame") : false;
|
|
2117
|
+
}
|
|
2118
|
+
else {
|
|
2119
|
+
return false;
|
|
2120
|
+
}
|
|
1897
2121
|
}
|
|
1898
2122
|
findFrameElement(element, submitter) {
|
|
1899
2123
|
const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame");
|
|
@@ -1923,7 +2147,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1923
2147
|
}
|
|
1924
2148
|
}
|
|
1925
2149
|
};
|
|
1926
|
-
this.onPageLoad = async (
|
|
2150
|
+
this.onPageLoad = async (_event) => {
|
|
1927
2151
|
await nextMicrotask();
|
|
1928
2152
|
this.pageLoaded = true;
|
|
1929
2153
|
};
|
|
@@ -1985,81 +2209,30 @@ Copyright © 2021 Basecamp, LLC
|
|
|
1985
2209
|
}
|
|
1986
2210
|
}
|
|
1987
2211
|
|
|
1988
|
-
class
|
|
1989
|
-
constructor(delegate) {
|
|
1990
|
-
this.started = false;
|
|
1991
|
-
this.clickCaptured = () => {
|
|
1992
|
-
removeEventListener("click", this.clickBubbled, false);
|
|
1993
|
-
addEventListener("click", this.clickBubbled, false);
|
|
1994
|
-
};
|
|
1995
|
-
this.clickBubbled = (event) => {
|
|
1996
|
-
if (this.clickEventIsSignificant(event)) {
|
|
1997
|
-
const target = (event.composedPath && event.composedPath()[0]) || event.target;
|
|
1998
|
-
const link = this.findLinkFromClickTarget(target);
|
|
1999
|
-
if (link) {
|
|
2000
|
-
const location = this.getLocationForLink(link);
|
|
2001
|
-
if (this.delegate.willFollowLinkToLocation(link, location)) {
|
|
2002
|
-
event.preventDefault();
|
|
2003
|
-
this.delegate.followedLinkToLocation(link, location);
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
}
|
|
2007
|
-
};
|
|
2008
|
-
this.delegate = delegate;
|
|
2009
|
-
}
|
|
2010
|
-
start() {
|
|
2011
|
-
if (!this.started) {
|
|
2012
|
-
addEventListener("click", this.clickCaptured, true);
|
|
2013
|
-
this.started = true;
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
stop() {
|
|
2017
|
-
if (this.started) {
|
|
2018
|
-
removeEventListener("click", this.clickCaptured, true);
|
|
2019
|
-
this.started = false;
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
clickEventIsSignificant(event) {
|
|
2023
|
-
return !((event.target && event.target.isContentEditable)
|
|
2024
|
-
|| event.defaultPrevented
|
|
2025
|
-
|| event.which > 1
|
|
2026
|
-
|| event.altKey
|
|
2027
|
-
|| event.ctrlKey
|
|
2028
|
-
|| event.metaKey
|
|
2029
|
-
|| event.shiftKey);
|
|
2030
|
-
}
|
|
2031
|
-
findLinkFromClickTarget(target) {
|
|
2032
|
-
if (target instanceof Element) {
|
|
2033
|
-
return target.closest("a[href]:not([target^=_]):not([download])");
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
getLocationForLink(link) {
|
|
2037
|
-
return expandURL(link.getAttribute("href") || "");
|
|
2038
|
-
}
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
function isAction(action) {
|
|
2042
|
-
return action == "advance" || action == "replace" || action == "restore";
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
class Navigator {
|
|
2212
|
+
class Navigator {
|
|
2046
2213
|
constructor(delegate) {
|
|
2047
2214
|
this.delegate = delegate;
|
|
2048
2215
|
}
|
|
2049
2216
|
proposeVisit(location, options = {}) {
|
|
2050
2217
|
if (this.delegate.allowsVisitingLocationWithAction(location, options.action)) {
|
|
2051
2218
|
if (locationIsVisitable(location, this.view.snapshot.rootLocation)) {
|
|
2052
|
-
this.delegate.visitProposedToLocation(location, options);
|
|
2219
|
+
return this.delegate.visitProposedToLocation(location, options);
|
|
2053
2220
|
}
|
|
2054
2221
|
else {
|
|
2055
2222
|
window.location.href = location.toString();
|
|
2223
|
+
return Promise.resolve();
|
|
2056
2224
|
}
|
|
2057
2225
|
}
|
|
2226
|
+
else {
|
|
2227
|
+
return Promise.reject();
|
|
2228
|
+
}
|
|
2058
2229
|
}
|
|
2059
2230
|
startVisit(locatable, restorationIdentifier, options = {}) {
|
|
2231
|
+
this.lastVisit = this.currentVisit;
|
|
2060
2232
|
this.stop();
|
|
2061
2233
|
this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options));
|
|
2062
2234
|
this.currentVisit.start();
|
|
2235
|
+
return this.currentVisit.promise;
|
|
2063
2236
|
}
|
|
2064
2237
|
submitForm(form, submitter) {
|
|
2065
2238
|
this.stop();
|
|
@@ -2086,7 +2259,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2086
2259
|
return this.delegate.history;
|
|
2087
2260
|
}
|
|
2088
2261
|
formSubmissionStarted(formSubmission) {
|
|
2089
|
-
if (typeof this.adapter.formSubmissionStarted ===
|
|
2262
|
+
if (typeof this.adapter.formSubmissionStarted === "function") {
|
|
2090
2263
|
this.adapter.formSubmissionStarted(formSubmission);
|
|
2091
2264
|
}
|
|
2092
2265
|
}
|
|
@@ -2094,12 +2267,17 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2094
2267
|
if (formSubmission == this.formSubmission) {
|
|
2095
2268
|
const responseHTML = await fetchResponse.responseHTML;
|
|
2096
2269
|
if (responseHTML) {
|
|
2097
|
-
|
|
2270
|
+
const shouldCacheSnapshot = formSubmission.method == FetchMethod.get;
|
|
2271
|
+
if (!shouldCacheSnapshot) {
|
|
2098
2272
|
this.view.clearSnapshotCache();
|
|
2099
2273
|
}
|
|
2100
2274
|
const { statusCode, redirected } = fetchResponse;
|
|
2101
2275
|
const action = this.getActionForFormSubmission(formSubmission);
|
|
2102
|
-
const visitOptions = {
|
|
2276
|
+
const visitOptions = {
|
|
2277
|
+
action,
|
|
2278
|
+
shouldCacheSnapshot,
|
|
2279
|
+
response: { statusCode, responseHTML, redirected },
|
|
2280
|
+
};
|
|
2103
2281
|
this.proposeVisit(fetchResponse.location, visitOptions);
|
|
2104
2282
|
}
|
|
2105
2283
|
}
|
|
@@ -2109,10 +2287,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2109
2287
|
if (responseHTML) {
|
|
2110
2288
|
const snapshot = PageSnapshot.fromHTMLString(responseHTML);
|
|
2111
2289
|
if (fetchResponse.serverError) {
|
|
2112
|
-
await this.view.renderError(snapshot);
|
|
2290
|
+
await this.view.renderError(snapshot, this.currentVisit);
|
|
2113
2291
|
}
|
|
2114
2292
|
else {
|
|
2115
|
-
await this.view.renderPage(snapshot);
|
|
2293
|
+
await this.view.renderPage(snapshot, false, true, this.currentVisit);
|
|
2116
2294
|
}
|
|
2117
2295
|
this.view.scrollToTop();
|
|
2118
2296
|
this.view.clearSnapshotCache();
|
|
@@ -2122,7 +2300,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2122
2300
|
console.error(error);
|
|
2123
2301
|
}
|
|
2124
2302
|
formSubmissionFinished(formSubmission) {
|
|
2125
|
-
if (typeof this.adapter.formSubmissionFinished ===
|
|
2303
|
+
if (typeof this.adapter.formSubmissionFinished === "function") {
|
|
2126
2304
|
this.adapter.formSubmissionFinished(formSubmission);
|
|
2127
2305
|
}
|
|
2128
2306
|
}
|
|
@@ -2133,12 +2311,14 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2133
2311
|
this.delegate.visitCompleted(visit);
|
|
2134
2312
|
}
|
|
2135
2313
|
locationWithActionIsSamePage(location, action) {
|
|
2314
|
+
var _a;
|
|
2136
2315
|
const anchor = getAnchor(location);
|
|
2137
|
-
const
|
|
2138
|
-
const
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
(
|
|
2316
|
+
const lastLocation = ((_a = this.lastVisit) === null || _a === void 0 ? void 0 : _a.location) || this.view.lastRenderedLocation;
|
|
2317
|
+
const currentAnchor = getAnchor(lastLocation);
|
|
2318
|
+
const isRestorationToTop = action === "restore" && typeof anchor === "undefined";
|
|
2319
|
+
return (action !== "replace" &&
|
|
2320
|
+
getRequestURL(location) === getRequestURL(lastLocation) &&
|
|
2321
|
+
(isRestorationToTop || (anchor != null && anchor !== currentAnchor)));
|
|
2142
2322
|
}
|
|
2143
2323
|
visitScrolledToSamePageLocation(oldURL, newURL) {
|
|
2144
2324
|
this.delegate.visitScrolledToSamePageLocation(oldURL, newURL);
|
|
@@ -2244,7 +2424,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2244
2424
|
|
|
2245
2425
|
class StreamObserver {
|
|
2246
2426
|
constructor(delegate) {
|
|
2247
|
-
this.sources = new Set;
|
|
2427
|
+
this.sources = new Set();
|
|
2248
2428
|
this.started = false;
|
|
2249
2429
|
this.inspectFetchResponse = ((event) => {
|
|
2250
2430
|
const response = fetchResponseFromEvent(event);
|
|
@@ -2294,7 +2474,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2294
2474
|
}
|
|
2295
2475
|
}
|
|
2296
2476
|
receiveMessageHTML(html) {
|
|
2297
|
-
this.delegate.receivedMessageFromStream(
|
|
2477
|
+
this.delegate.receivedMessageFromStream(StreamMessage.wrap(html));
|
|
2298
2478
|
}
|
|
2299
2479
|
}
|
|
2300
2480
|
function fetchResponseFromEvent(event) {
|
|
@@ -2311,20 +2491,24 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2311
2491
|
}
|
|
2312
2492
|
|
|
2313
2493
|
class ErrorRenderer extends Renderer {
|
|
2494
|
+
static renderElement(currentElement, newElement) {
|
|
2495
|
+
const { documentElement, body } = document;
|
|
2496
|
+
documentElement.replaceChild(newElement, body);
|
|
2497
|
+
}
|
|
2314
2498
|
async render() {
|
|
2315
2499
|
this.replaceHeadAndBody();
|
|
2316
2500
|
this.activateScriptElements();
|
|
2317
2501
|
}
|
|
2318
2502
|
replaceHeadAndBody() {
|
|
2319
|
-
const { documentElement, head
|
|
2503
|
+
const { documentElement, head } = document;
|
|
2320
2504
|
documentElement.replaceChild(this.newHead, head);
|
|
2321
|
-
|
|
2505
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
2322
2506
|
}
|
|
2323
2507
|
activateScriptElements() {
|
|
2324
2508
|
for (const replaceableElement of this.scriptElements) {
|
|
2325
2509
|
const parentNode = replaceableElement.parentNode;
|
|
2326
2510
|
if (parentNode) {
|
|
2327
|
-
const element =
|
|
2511
|
+
const element = activateScriptElement(replaceableElement);
|
|
2328
2512
|
parentNode.replaceChild(element, replaceableElement);
|
|
2329
2513
|
}
|
|
2330
2514
|
}
|
|
@@ -2333,16 +2517,36 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2333
2517
|
return this.newSnapshot.headSnapshot.element;
|
|
2334
2518
|
}
|
|
2335
2519
|
get scriptElements() {
|
|
2336
|
-
return
|
|
2520
|
+
return document.documentElement.querySelectorAll("script");
|
|
2337
2521
|
}
|
|
2338
2522
|
}
|
|
2339
2523
|
|
|
2340
2524
|
class PageRenderer extends Renderer {
|
|
2525
|
+
static renderElement(currentElement, newElement) {
|
|
2526
|
+
if (document.body && newElement instanceof HTMLBodyElement) {
|
|
2527
|
+
document.body.replaceWith(newElement);
|
|
2528
|
+
}
|
|
2529
|
+
else {
|
|
2530
|
+
document.documentElement.appendChild(newElement);
|
|
2531
|
+
}
|
|
2532
|
+
}
|
|
2341
2533
|
get shouldRender() {
|
|
2342
2534
|
return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical;
|
|
2343
2535
|
}
|
|
2344
|
-
|
|
2345
|
-
this.
|
|
2536
|
+
get reloadReason() {
|
|
2537
|
+
if (!this.newSnapshot.isVisitable) {
|
|
2538
|
+
return {
|
|
2539
|
+
reason: "turbo_visit_control_is_reload",
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
if (!this.trackedElementsAreIdentical) {
|
|
2543
|
+
return {
|
|
2544
|
+
reason: "tracked_element_mismatch",
|
|
2545
|
+
};
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
async prepareToRender() {
|
|
2549
|
+
await this.mergeHead();
|
|
2346
2550
|
}
|
|
2347
2551
|
async render() {
|
|
2348
2552
|
if (this.willRender) {
|
|
@@ -2364,11 +2568,12 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2364
2568
|
get newElement() {
|
|
2365
2569
|
return this.newSnapshot.element;
|
|
2366
2570
|
}
|
|
2367
|
-
mergeHead() {
|
|
2368
|
-
this.copyNewHeadStylesheetElements();
|
|
2571
|
+
async mergeHead() {
|
|
2572
|
+
const newStylesheetElements = this.copyNewHeadStylesheetElements();
|
|
2369
2573
|
this.copyNewHeadScriptElements();
|
|
2370
2574
|
this.removeCurrentHeadProvisionalElements();
|
|
2371
2575
|
this.copyNewHeadProvisionalElements();
|
|
2576
|
+
await newStylesheetElements;
|
|
2372
2577
|
}
|
|
2373
2578
|
replaceBody() {
|
|
2374
2579
|
this.preservingPermanentElements(() => {
|
|
@@ -2379,14 +2584,17 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2379
2584
|
get trackedElementsAreIdentical() {
|
|
2380
2585
|
return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature;
|
|
2381
2586
|
}
|
|
2382
|
-
copyNewHeadStylesheetElements() {
|
|
2587
|
+
async copyNewHeadStylesheetElements() {
|
|
2588
|
+
const loadingElements = [];
|
|
2383
2589
|
for (const element of this.newHeadStylesheetElements) {
|
|
2590
|
+
loadingElements.push(waitForLoad(element));
|
|
2384
2591
|
document.head.appendChild(element);
|
|
2385
2592
|
}
|
|
2593
|
+
await Promise.all(loadingElements);
|
|
2386
2594
|
}
|
|
2387
2595
|
copyNewHeadScriptElements() {
|
|
2388
2596
|
for (const element of this.newHeadScriptElements) {
|
|
2389
|
-
document.head.appendChild(
|
|
2597
|
+
document.head.appendChild(activateScriptElement(element));
|
|
2390
2598
|
}
|
|
2391
2599
|
}
|
|
2392
2600
|
removeCurrentHeadProvisionalElements() {
|
|
@@ -2405,17 +2613,12 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2405
2613
|
}
|
|
2406
2614
|
activateNewBodyScriptElements() {
|
|
2407
2615
|
for (const inertScriptElement of this.newBodyScriptElements) {
|
|
2408
|
-
const activatedScriptElement =
|
|
2616
|
+
const activatedScriptElement = activateScriptElement(inertScriptElement);
|
|
2409
2617
|
inertScriptElement.replaceWith(activatedScriptElement);
|
|
2410
2618
|
}
|
|
2411
2619
|
}
|
|
2412
2620
|
assignNewBody() {
|
|
2413
|
-
|
|
2414
|
-
document.body.replaceWith(this.newElement);
|
|
2415
|
-
}
|
|
2416
|
-
else {
|
|
2417
|
-
document.documentElement.appendChild(this.newElement);
|
|
2418
|
-
}
|
|
2621
|
+
this.renderElement(this.currentElement, this.newElement);
|
|
2419
2622
|
}
|
|
2420
2623
|
get newHeadStylesheetElements() {
|
|
2421
2624
|
return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot);
|
|
@@ -2484,13 +2687,21 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2484
2687
|
super(...arguments);
|
|
2485
2688
|
this.snapshotCache = new SnapshotCache(10);
|
|
2486
2689
|
this.lastRenderedLocation = new URL(location.href);
|
|
2690
|
+
this.forceReloaded = false;
|
|
2487
2691
|
}
|
|
2488
|
-
renderPage(snapshot, isPreview = false, willRender = true) {
|
|
2489
|
-
const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender);
|
|
2692
|
+
renderPage(snapshot, isPreview = false, willRender = true, visit) {
|
|
2693
|
+
const renderer = new PageRenderer(this.snapshot, snapshot, PageRenderer.renderElement, isPreview, willRender);
|
|
2694
|
+
if (!renderer.shouldRender) {
|
|
2695
|
+
this.forceReloaded = true;
|
|
2696
|
+
}
|
|
2697
|
+
else {
|
|
2698
|
+
visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
|
2699
|
+
}
|
|
2490
2700
|
return this.render(renderer);
|
|
2491
2701
|
}
|
|
2492
|
-
renderError(snapshot) {
|
|
2493
|
-
|
|
2702
|
+
renderError(snapshot, visit) {
|
|
2703
|
+
visit === null || visit === void 0 ? void 0 : visit.changeHistory();
|
|
2704
|
+
const renderer = new ErrorRenderer(this.snapshot, snapshot, ErrorRenderer.renderElement, false);
|
|
2494
2705
|
return this.render(renderer);
|
|
2495
2706
|
}
|
|
2496
2707
|
clearSnapshotCache() {
|
|
@@ -2517,34 +2728,78 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2517
2728
|
}
|
|
2518
2729
|
}
|
|
2519
2730
|
|
|
2731
|
+
class Preloader {
|
|
2732
|
+
constructor(delegate) {
|
|
2733
|
+
this.selector = "a[data-turbo-preload]";
|
|
2734
|
+
this.delegate = delegate;
|
|
2735
|
+
}
|
|
2736
|
+
get snapshotCache() {
|
|
2737
|
+
return this.delegate.navigator.view.snapshotCache;
|
|
2738
|
+
}
|
|
2739
|
+
start() {
|
|
2740
|
+
if (document.readyState === "loading") {
|
|
2741
|
+
return document.addEventListener("DOMContentLoaded", () => {
|
|
2742
|
+
this.preloadOnLoadLinksForView(document.body);
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
else {
|
|
2746
|
+
this.preloadOnLoadLinksForView(document.body);
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
preloadOnLoadLinksForView(element) {
|
|
2750
|
+
for (const link of element.querySelectorAll(this.selector)) {
|
|
2751
|
+
this.preloadURL(link);
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
async preloadURL(link) {
|
|
2755
|
+
const location = new URL(link.href);
|
|
2756
|
+
if (this.snapshotCache.has(location)) {
|
|
2757
|
+
return;
|
|
2758
|
+
}
|
|
2759
|
+
try {
|
|
2760
|
+
const response = await fetch(location.toString(), { headers: { "VND.PREFETCH": "true", Accept: "text/html" } });
|
|
2761
|
+
const responseText = await response.text();
|
|
2762
|
+
const snapshot = PageSnapshot.fromHTMLString(responseText);
|
|
2763
|
+
this.snapshotCache.put(location, snapshot);
|
|
2764
|
+
}
|
|
2765
|
+
catch (_) {
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2520
2770
|
class Session {
|
|
2521
2771
|
constructor() {
|
|
2522
2772
|
this.navigator = new Navigator(this);
|
|
2523
2773
|
this.history = new History(this);
|
|
2774
|
+
this.preloader = new Preloader(this);
|
|
2524
2775
|
this.view = new PageView(this, document.documentElement);
|
|
2525
2776
|
this.adapter = new BrowserAdapter(this);
|
|
2526
2777
|
this.pageObserver = new PageObserver(this);
|
|
2527
2778
|
this.cacheObserver = new CacheObserver();
|
|
2528
|
-
this.linkClickObserver = new LinkClickObserver(this);
|
|
2529
|
-
this.formSubmitObserver = new FormSubmitObserver(this);
|
|
2779
|
+
this.linkClickObserver = new LinkClickObserver(this, window);
|
|
2780
|
+
this.formSubmitObserver = new FormSubmitObserver(this, document);
|
|
2530
2781
|
this.scrollObserver = new ScrollObserver(this);
|
|
2531
2782
|
this.streamObserver = new StreamObserver(this);
|
|
2532
|
-
this.
|
|
2783
|
+
this.formLinkClickObserver = new FormLinkClickObserver(this, document.documentElement);
|
|
2784
|
+
this.frameRedirector = new FrameRedirector(this, document.documentElement);
|
|
2533
2785
|
this.drive = true;
|
|
2534
2786
|
this.enabled = true;
|
|
2535
2787
|
this.progressBarDelay = 500;
|
|
2536
2788
|
this.started = false;
|
|
2789
|
+
this.formMode = "on";
|
|
2537
2790
|
}
|
|
2538
2791
|
start() {
|
|
2539
2792
|
if (!this.started) {
|
|
2540
2793
|
this.pageObserver.start();
|
|
2541
2794
|
this.cacheObserver.start();
|
|
2795
|
+
this.formLinkClickObserver.start();
|
|
2542
2796
|
this.linkClickObserver.start();
|
|
2543
2797
|
this.formSubmitObserver.start();
|
|
2544
2798
|
this.scrollObserver.start();
|
|
2545
2799
|
this.streamObserver.start();
|
|
2546
2800
|
this.frameRedirector.start();
|
|
2547
2801
|
this.history.start();
|
|
2802
|
+
this.preloader.start();
|
|
2548
2803
|
this.started = true;
|
|
2549
2804
|
this.enabled = true;
|
|
2550
2805
|
}
|
|
@@ -2556,6 +2811,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2556
2811
|
if (this.started) {
|
|
2557
2812
|
this.pageObserver.stop();
|
|
2558
2813
|
this.cacheObserver.stop();
|
|
2814
|
+
this.formLinkClickObserver.stop();
|
|
2559
2815
|
this.linkClickObserver.stop();
|
|
2560
2816
|
this.formSubmitObserver.stop();
|
|
2561
2817
|
this.scrollObserver.stop();
|
|
@@ -2569,7 +2825,14 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2569
2825
|
this.adapter = adapter;
|
|
2570
2826
|
}
|
|
2571
2827
|
visit(location, options = {}) {
|
|
2572
|
-
|
|
2828
|
+
const frameElement = document.getElementById(options.frame || "");
|
|
2829
|
+
if (frameElement instanceof FrameElement) {
|
|
2830
|
+
frameElement.src = location.toString();
|
|
2831
|
+
return frameElement.loaded;
|
|
2832
|
+
}
|
|
2833
|
+
else {
|
|
2834
|
+
return this.navigator.proposeVisit(expandURL(location), options);
|
|
2835
|
+
}
|
|
2573
2836
|
}
|
|
2574
2837
|
connectStreamSource(source) {
|
|
2575
2838
|
this.streamObserver.connectStreamSource(source);
|
|
@@ -2586,6 +2849,9 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2586
2849
|
setProgressBarDelay(delay) {
|
|
2587
2850
|
this.progressBarDelay = delay;
|
|
2588
2851
|
}
|
|
2852
|
+
setFormMode(mode) {
|
|
2853
|
+
this.formMode = mode;
|
|
2854
|
+
}
|
|
2589
2855
|
get location() {
|
|
2590
2856
|
return this.history.location;
|
|
2591
2857
|
}
|
|
@@ -2594,55 +2860,40 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2594
2860
|
}
|
|
2595
2861
|
historyPoppedToLocationWithRestorationIdentifier(location, restorationIdentifier) {
|
|
2596
2862
|
if (this.enabled) {
|
|
2597
|
-
this.navigator.startVisit(location, restorationIdentifier, {
|
|
2863
|
+
this.navigator.startVisit(location, restorationIdentifier, {
|
|
2864
|
+
action: "restore",
|
|
2865
|
+
historyChanged: true,
|
|
2866
|
+
});
|
|
2598
2867
|
}
|
|
2599
2868
|
else {
|
|
2600
|
-
this.adapter.pageInvalidated(
|
|
2869
|
+
this.adapter.pageInvalidated({
|
|
2870
|
+
reason: "turbo_disabled",
|
|
2871
|
+
});
|
|
2601
2872
|
}
|
|
2602
2873
|
}
|
|
2603
2874
|
scrollPositionChanged(position) {
|
|
2604
2875
|
this.history.updateRestorationData({ scrollPosition: position });
|
|
2605
2876
|
}
|
|
2606
|
-
|
|
2607
|
-
return this.
|
|
2608
|
-
|
|
2609
|
-
|
|
2877
|
+
willSubmitFormLinkToLocation(link, location) {
|
|
2878
|
+
return this.elementIsNavigatable(link) && locationIsVisitable(location, this.snapshot.rootLocation);
|
|
2879
|
+
}
|
|
2880
|
+
submittedFormLinkToLocation() { }
|
|
2881
|
+
willFollowLinkToLocation(link, location, event) {
|
|
2882
|
+
return (this.elementIsNavigatable(link) &&
|
|
2883
|
+
locationIsVisitable(location, this.snapshot.rootLocation) &&
|
|
2884
|
+
this.applicationAllowsFollowingLinkToLocation(link, location, event));
|
|
2610
2885
|
}
|
|
2611
2886
|
followedLinkToLocation(link, location) {
|
|
2612
2887
|
const action = this.getActionForLink(link);
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
convertLinkWithMethodClickToFormSubmission(link) {
|
|
2616
|
-
const linkMethod = link.getAttribute("data-turbo-method");
|
|
2617
|
-
if (linkMethod) {
|
|
2618
|
-
const form = document.createElement("form");
|
|
2619
|
-
form.method = linkMethod;
|
|
2620
|
-
form.action = link.getAttribute("href") || "undefined";
|
|
2621
|
-
form.hidden = true;
|
|
2622
|
-
if (link.hasAttribute("data-turbo-confirm")) {
|
|
2623
|
-
form.setAttribute("data-turbo-confirm", link.getAttribute("data-turbo-confirm"));
|
|
2624
|
-
}
|
|
2625
|
-
const frame = this.getTargetFrameForLink(link);
|
|
2626
|
-
if (frame) {
|
|
2627
|
-
form.setAttribute("data-turbo-frame", frame);
|
|
2628
|
-
form.addEventListener("turbo:submit-start", () => form.remove());
|
|
2629
|
-
}
|
|
2630
|
-
else {
|
|
2631
|
-
form.addEventListener("submit", () => form.remove());
|
|
2632
|
-
}
|
|
2633
|
-
document.body.appendChild(form);
|
|
2634
|
-
return dispatch("submit", { cancelable: true, target: form });
|
|
2635
|
-
}
|
|
2636
|
-
else {
|
|
2637
|
-
return false;
|
|
2638
|
-
}
|
|
2888
|
+
const acceptsStreamResponse = link.hasAttribute("data-turbo-stream");
|
|
2889
|
+
this.visit(location.href, { action, acceptsStreamResponse });
|
|
2639
2890
|
}
|
|
2640
2891
|
allowsVisitingLocationWithAction(location, action) {
|
|
2641
2892
|
return this.locationWithActionIsSamePage(location, action) || this.applicationAllowsVisitingLocation(location);
|
|
2642
2893
|
}
|
|
2643
2894
|
visitProposedToLocation(location, options) {
|
|
2644
2895
|
extendURLWithDeprecatedProperties(location);
|
|
2645
|
-
this.adapter.visitProposedToLocation(location, options);
|
|
2896
|
+
return this.adapter.visitProposedToLocation(location, options);
|
|
2646
2897
|
}
|
|
2647
2898
|
visitStarted(visit) {
|
|
2648
2899
|
extendURLWithDeprecatedProperties(visit.location);
|
|
@@ -2661,9 +2912,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2661
2912
|
}
|
|
2662
2913
|
willSubmitForm(form, submitter) {
|
|
2663
2914
|
const action = getAction(form, submitter);
|
|
2664
|
-
return this.
|
|
2665
|
-
|
|
2666
|
-
&& locationIsVisitable(expandURL(action), this.snapshot.rootLocation);
|
|
2915
|
+
return (this.submissionIsNavigatable(form, submitter) &&
|
|
2916
|
+
locationIsVisitable(expandURL(action), this.snapshot.rootLocation));
|
|
2667
2917
|
}
|
|
2668
2918
|
formSubmitted(form, submitter) {
|
|
2669
2919
|
this.navigator.submitForm(form, submitter);
|
|
@@ -2687,16 +2937,23 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2687
2937
|
this.notifyApplicationBeforeCachingSnapshot();
|
|
2688
2938
|
}
|
|
2689
2939
|
}
|
|
2690
|
-
allowsImmediateRender({ element },
|
|
2691
|
-
const event = this.notifyApplicationBeforeRender(element,
|
|
2692
|
-
|
|
2940
|
+
allowsImmediateRender({ element }, options) {
|
|
2941
|
+
const event = this.notifyApplicationBeforeRender(element, options);
|
|
2942
|
+
const { defaultPrevented, detail: { render }, } = event;
|
|
2943
|
+
if (this.view.renderer && render) {
|
|
2944
|
+
this.view.renderer.renderElement = render;
|
|
2945
|
+
}
|
|
2946
|
+
return !defaultPrevented;
|
|
2693
2947
|
}
|
|
2694
|
-
viewRenderedSnapshot(
|
|
2948
|
+
viewRenderedSnapshot(_snapshot, _isPreview) {
|
|
2695
2949
|
this.view.lastRenderedLocation = this.history.location;
|
|
2696
2950
|
this.notifyApplicationAfterRender();
|
|
2697
2951
|
}
|
|
2698
|
-
|
|
2699
|
-
this.
|
|
2952
|
+
preloadOnLoadLinksForView(element) {
|
|
2953
|
+
this.preloader.preloadOnLoadLinksForView(element);
|
|
2954
|
+
}
|
|
2955
|
+
viewInvalidated(reason) {
|
|
2956
|
+
this.adapter.pageInvalidated(reason);
|
|
2700
2957
|
}
|
|
2701
2958
|
frameLoaded(frame) {
|
|
2702
2959
|
this.notifyApplicationAfterFrameLoad(frame);
|
|
@@ -2704,19 +2961,30 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2704
2961
|
frameRendered(fetchResponse, frame) {
|
|
2705
2962
|
this.notifyApplicationAfterFrameRender(fetchResponse, frame);
|
|
2706
2963
|
}
|
|
2707
|
-
|
|
2708
|
-
|
|
2964
|
+
frameMissing(frame, fetchResponse) {
|
|
2965
|
+
console.warn(`Completing full-page visit as matching frame for #${frame.id} was missing from the response`);
|
|
2966
|
+
return this.visit(fetchResponse.location);
|
|
2967
|
+
}
|
|
2968
|
+
applicationAllowsFollowingLinkToLocation(link, location, ev) {
|
|
2969
|
+
const event = this.notifyApplicationAfterClickingLinkToLocation(link, location, ev);
|
|
2709
2970
|
return !event.defaultPrevented;
|
|
2710
2971
|
}
|
|
2711
2972
|
applicationAllowsVisitingLocation(location) {
|
|
2712
2973
|
const event = this.notifyApplicationBeforeVisitingLocation(location);
|
|
2713
2974
|
return !event.defaultPrevented;
|
|
2714
2975
|
}
|
|
2715
|
-
notifyApplicationAfterClickingLinkToLocation(link, location) {
|
|
2716
|
-
return dispatch("turbo:click", {
|
|
2976
|
+
notifyApplicationAfterClickingLinkToLocation(link, location, event) {
|
|
2977
|
+
return dispatch("turbo:click", {
|
|
2978
|
+
target: link,
|
|
2979
|
+
detail: { url: location.href, originalEvent: event },
|
|
2980
|
+
cancelable: true,
|
|
2981
|
+
});
|
|
2717
2982
|
}
|
|
2718
2983
|
notifyApplicationBeforeVisitingLocation(location) {
|
|
2719
|
-
return dispatch("turbo:before-visit", {
|
|
2984
|
+
return dispatch("turbo:before-visit", {
|
|
2985
|
+
detail: { url: location.href },
|
|
2986
|
+
cancelable: true,
|
|
2987
|
+
});
|
|
2720
2988
|
}
|
|
2721
2989
|
notifyApplicationAfterVisitingLocation(location, action) {
|
|
2722
2990
|
markAsBusy(document.documentElement);
|
|
@@ -2725,28 +2993,55 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2725
2993
|
notifyApplicationBeforeCachingSnapshot() {
|
|
2726
2994
|
return dispatch("turbo:before-cache");
|
|
2727
2995
|
}
|
|
2728
|
-
notifyApplicationBeforeRender(newBody,
|
|
2729
|
-
return dispatch("turbo:before-render", {
|
|
2996
|
+
notifyApplicationBeforeRender(newBody, options) {
|
|
2997
|
+
return dispatch("turbo:before-render", {
|
|
2998
|
+
detail: Object.assign({ newBody }, options),
|
|
2999
|
+
cancelable: true,
|
|
3000
|
+
});
|
|
2730
3001
|
}
|
|
2731
3002
|
notifyApplicationAfterRender() {
|
|
2732
3003
|
return dispatch("turbo:render");
|
|
2733
3004
|
}
|
|
2734
3005
|
notifyApplicationAfterPageLoad(timing = {}) {
|
|
2735
3006
|
clearBusyState(document.documentElement);
|
|
2736
|
-
return dispatch("turbo:load", {
|
|
3007
|
+
return dispatch("turbo:load", {
|
|
3008
|
+
detail: { url: this.location.href, timing },
|
|
3009
|
+
});
|
|
2737
3010
|
}
|
|
2738
3011
|
notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) {
|
|
2739
|
-
dispatchEvent(new HashChangeEvent("hashchange", {
|
|
3012
|
+
dispatchEvent(new HashChangeEvent("hashchange", {
|
|
3013
|
+
oldURL: oldURL.toString(),
|
|
3014
|
+
newURL: newURL.toString(),
|
|
3015
|
+
}));
|
|
2740
3016
|
}
|
|
2741
3017
|
notifyApplicationAfterFrameLoad(frame) {
|
|
2742
3018
|
return dispatch("turbo:frame-load", { target: frame });
|
|
2743
3019
|
}
|
|
2744
3020
|
notifyApplicationAfterFrameRender(fetchResponse, frame) {
|
|
2745
|
-
return dispatch("turbo:frame-render", {
|
|
3021
|
+
return dispatch("turbo:frame-render", {
|
|
3022
|
+
detail: { fetchResponse },
|
|
3023
|
+
target: frame,
|
|
3024
|
+
cancelable: true,
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
3027
|
+
submissionIsNavigatable(form, submitter) {
|
|
3028
|
+
if (this.formMode == "off") {
|
|
3029
|
+
return false;
|
|
3030
|
+
}
|
|
3031
|
+
else {
|
|
3032
|
+
const submitterIsNavigatable = submitter ? this.elementIsNavigatable(submitter) : true;
|
|
3033
|
+
if (this.formMode == "optin") {
|
|
3034
|
+
return submitterIsNavigatable && form.closest('[data-turbo="true"]') != null;
|
|
3035
|
+
}
|
|
3036
|
+
else {
|
|
3037
|
+
return submitterIsNavigatable && this.elementIsNavigatable(form);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
2746
3040
|
}
|
|
2747
|
-
|
|
2748
|
-
const container = element
|
|
2749
|
-
|
|
3041
|
+
elementIsNavigatable(element) {
|
|
3042
|
+
const container = element.closest("[data-turbo]");
|
|
3043
|
+
const withinFrame = element.closest("turbo-frame");
|
|
3044
|
+
if (this.drive || withinFrame) {
|
|
2750
3045
|
if (container) {
|
|
2751
3046
|
return container.getAttribute("data-turbo") != "false";
|
|
2752
3047
|
}
|
|
@@ -2767,18 +3062,6 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2767
3062
|
const action = link.getAttribute("data-turbo-action");
|
|
2768
3063
|
return isAction(action) ? action : "advance";
|
|
2769
3064
|
}
|
|
2770
|
-
getTargetFrameForLink(link) {
|
|
2771
|
-
const frame = link.getAttribute("data-turbo-frame");
|
|
2772
|
-
if (frame) {
|
|
2773
|
-
return frame;
|
|
2774
|
-
}
|
|
2775
|
-
else {
|
|
2776
|
-
const container = link.closest("turbo-frame");
|
|
2777
|
-
if (container) {
|
|
2778
|
-
return container.id;
|
|
2779
|
-
}
|
|
2780
|
-
}
|
|
2781
|
-
}
|
|
2782
3065
|
get snapshot() {
|
|
2783
3066
|
return this.view.snapshot;
|
|
2784
3067
|
}
|
|
@@ -2790,11 +3073,59 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2790
3073
|
absoluteURL: {
|
|
2791
3074
|
get() {
|
|
2792
3075
|
return this.toString();
|
|
2793
|
-
}
|
|
3076
|
+
},
|
|
3077
|
+
},
|
|
3078
|
+
};
|
|
3079
|
+
|
|
3080
|
+
class Cache {
|
|
3081
|
+
constructor(session) {
|
|
3082
|
+
this.session = session;
|
|
3083
|
+
}
|
|
3084
|
+
clear() {
|
|
3085
|
+
this.session.clearCache();
|
|
2794
3086
|
}
|
|
3087
|
+
resetCacheControl() {
|
|
3088
|
+
this.setCacheControl("");
|
|
3089
|
+
}
|
|
3090
|
+
exemptPageFromCache() {
|
|
3091
|
+
this.setCacheControl("no-cache");
|
|
3092
|
+
}
|
|
3093
|
+
exemptPageFromPreview() {
|
|
3094
|
+
this.setCacheControl("no-preview");
|
|
3095
|
+
}
|
|
3096
|
+
setCacheControl(value) {
|
|
3097
|
+
setMetaContent("turbo-cache-control", value);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
const StreamActions = {
|
|
3102
|
+
after() {
|
|
3103
|
+
this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });
|
|
3104
|
+
},
|
|
3105
|
+
append() {
|
|
3106
|
+
this.removeDuplicateTargetChildren();
|
|
3107
|
+
this.targetElements.forEach((e) => e.append(this.templateContent));
|
|
3108
|
+
},
|
|
3109
|
+
before() {
|
|
3110
|
+
this.targetElements.forEach((e) => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });
|
|
3111
|
+
},
|
|
3112
|
+
prepend() {
|
|
3113
|
+
this.removeDuplicateTargetChildren();
|
|
3114
|
+
this.targetElements.forEach((e) => e.prepend(this.templateContent));
|
|
3115
|
+
},
|
|
3116
|
+
remove() {
|
|
3117
|
+
this.targetElements.forEach((e) => e.remove());
|
|
3118
|
+
},
|
|
3119
|
+
replace() {
|
|
3120
|
+
this.targetElements.forEach((e) => e.replaceWith(this.templateContent));
|
|
3121
|
+
},
|
|
3122
|
+
update() {
|
|
3123
|
+
this.targetElements.forEach((e) => e.replaceChildren(this.templateContent));
|
|
3124
|
+
},
|
|
2795
3125
|
};
|
|
2796
3126
|
|
|
2797
|
-
const session = new Session;
|
|
3127
|
+
const session = new Session();
|
|
3128
|
+
const cache = new Cache(session);
|
|
2798
3129
|
const { navigator: navigator$1 } = session;
|
|
2799
3130
|
function start() {
|
|
2800
3131
|
session.start();
|
|
@@ -2803,7 +3134,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2803
3134
|
session.registerAdapter(adapter);
|
|
2804
3135
|
}
|
|
2805
3136
|
function visit(location, options) {
|
|
2806
|
-
session.visit(location, options);
|
|
3137
|
+
return session.visit(location, options);
|
|
2807
3138
|
}
|
|
2808
3139
|
function connectStreamSource(source) {
|
|
2809
3140
|
session.connectStreamSource(source);
|
|
@@ -2815,6 +3146,7 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2815
3146
|
session.renderStreamMessage(message);
|
|
2816
3147
|
}
|
|
2817
3148
|
function clearCache() {
|
|
3149
|
+
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.`");
|
|
2818
3150
|
session.clearCache();
|
|
2819
3151
|
}
|
|
2820
3152
|
function setProgressBarDelay(delay) {
|
|
@@ -2823,13 +3155,18 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2823
3155
|
function setConfirmMethod(confirmMethod) {
|
|
2824
3156
|
FormSubmission.confirmMethod = confirmMethod;
|
|
2825
3157
|
}
|
|
3158
|
+
function setFormMode(mode) {
|
|
3159
|
+
session.setFormMode(mode);
|
|
3160
|
+
}
|
|
2826
3161
|
|
|
2827
3162
|
var Turbo = /*#__PURE__*/Object.freeze({
|
|
2828
3163
|
__proto__: null,
|
|
2829
3164
|
navigator: navigator$1,
|
|
2830
3165
|
session: session,
|
|
3166
|
+
cache: cache,
|
|
2831
3167
|
PageRenderer: PageRenderer,
|
|
2832
3168
|
PageSnapshot: PageSnapshot,
|
|
3169
|
+
FrameRenderer: FrameRenderer,
|
|
2833
3170
|
start: start,
|
|
2834
3171
|
registerAdapter: registerAdapter,
|
|
2835
3172
|
visit: visit,
|
|
@@ -2838,41 +3175,56 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2838
3175
|
renderStreamMessage: renderStreamMessage,
|
|
2839
3176
|
clearCache: clearCache,
|
|
2840
3177
|
setProgressBarDelay: setProgressBarDelay,
|
|
2841
|
-
setConfirmMethod: setConfirmMethod
|
|
3178
|
+
setConfirmMethod: setConfirmMethod,
|
|
3179
|
+
setFormMode: setFormMode,
|
|
3180
|
+
StreamActions: StreamActions
|
|
2842
3181
|
});
|
|
2843
3182
|
|
|
2844
3183
|
class FrameController {
|
|
2845
3184
|
constructor(element) {
|
|
2846
|
-
this.fetchResponseLoaded = (
|
|
3185
|
+
this.fetchResponseLoaded = (_fetchResponse) => { };
|
|
2847
3186
|
this.currentFetchRequest = null;
|
|
2848
3187
|
this.resolveVisitPromise = () => { };
|
|
2849
3188
|
this.connected = false;
|
|
2850
3189
|
this.hasBeenLoaded = false;
|
|
2851
|
-
this.
|
|
3190
|
+
this.ignoredAttributes = new Set();
|
|
3191
|
+
this.action = null;
|
|
3192
|
+
this.visitCachedSnapshot = ({ element }) => {
|
|
3193
|
+
const frame = element.querySelector("#" + this.element.id);
|
|
3194
|
+
if (frame && this.previousFrameElement) {
|
|
3195
|
+
frame.replaceChildren(...this.previousFrameElement.children);
|
|
3196
|
+
}
|
|
3197
|
+
delete this.previousFrameElement;
|
|
3198
|
+
};
|
|
2852
3199
|
this.element = element;
|
|
2853
3200
|
this.view = new FrameView(this, this.element);
|
|
2854
3201
|
this.appearanceObserver = new AppearanceObserver(this, this.element);
|
|
2855
|
-
this.
|
|
2856
|
-
this.
|
|
3202
|
+
this.formLinkClickObserver = new FormLinkClickObserver(this, this.element);
|
|
3203
|
+
this.linkClickObserver = new LinkClickObserver(this, this.element);
|
|
3204
|
+
this.restorationIdentifier = uuid();
|
|
3205
|
+
this.formSubmitObserver = new FormSubmitObserver(this, this.element);
|
|
2857
3206
|
}
|
|
2858
3207
|
connect() {
|
|
2859
3208
|
if (!this.connected) {
|
|
2860
3209
|
this.connected = true;
|
|
2861
|
-
this.reloadable = false;
|
|
2862
3210
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
2863
3211
|
this.appearanceObserver.start();
|
|
2864
3212
|
}
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
3213
|
+
else {
|
|
3214
|
+
this.loadSourceURL();
|
|
3215
|
+
}
|
|
3216
|
+
this.formLinkClickObserver.start();
|
|
3217
|
+
this.linkClickObserver.start();
|
|
3218
|
+
this.formSubmitObserver.start();
|
|
2868
3219
|
}
|
|
2869
3220
|
}
|
|
2870
3221
|
disconnect() {
|
|
2871
3222
|
if (this.connected) {
|
|
2872
3223
|
this.connected = false;
|
|
2873
3224
|
this.appearanceObserver.stop();
|
|
2874
|
-
this.
|
|
2875
|
-
this.
|
|
3225
|
+
this.formLinkClickObserver.stop();
|
|
3226
|
+
this.linkClickObserver.stop();
|
|
3227
|
+
this.formSubmitObserver.stop();
|
|
2876
3228
|
}
|
|
2877
3229
|
}
|
|
2878
3230
|
disabledChanged() {
|
|
@@ -2881,10 +3233,20 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2881
3233
|
}
|
|
2882
3234
|
}
|
|
2883
3235
|
sourceURLChanged() {
|
|
3236
|
+
if (this.isIgnoringChangesTo("src"))
|
|
3237
|
+
return;
|
|
3238
|
+
if (this.element.isConnected) {
|
|
3239
|
+
this.complete = false;
|
|
3240
|
+
}
|
|
2884
3241
|
if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) {
|
|
2885
3242
|
this.loadSourceURL();
|
|
2886
3243
|
}
|
|
2887
3244
|
}
|
|
3245
|
+
completeChanged() {
|
|
3246
|
+
if (this.isIgnoringChangesTo("complete"))
|
|
3247
|
+
return;
|
|
3248
|
+
this.loadSourceURL();
|
|
3249
|
+
}
|
|
2888
3250
|
loadingStyleChanged() {
|
|
2889
3251
|
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
2890
3252
|
this.appearanceObserver.start();
|
|
@@ -2895,21 +3257,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2895
3257
|
}
|
|
2896
3258
|
}
|
|
2897
3259
|
async loadSourceURL() {
|
|
2898
|
-
if (
|
|
2899
|
-
|
|
2900
|
-
this.
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
this.element.loaded = this.visit(expandURL(this.sourceURL));
|
|
2904
|
-
this.appearanceObserver.stop();
|
|
2905
|
-
await this.element.loaded;
|
|
2906
|
-
this.hasBeenLoaded = true;
|
|
2907
|
-
}
|
|
2908
|
-
catch (error) {
|
|
2909
|
-
this.currentURL = previousURL;
|
|
2910
|
-
throw error;
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
3260
|
+
if (this.enabled && this.isActive && !this.complete && this.sourceURL) {
|
|
3261
|
+
this.element.loaded = this.visit(expandURL(this.sourceURL));
|
|
3262
|
+
this.appearanceObserver.stop();
|
|
3263
|
+
await this.element.loaded;
|
|
3264
|
+
this.hasBeenLoaded = true;
|
|
2913
3265
|
}
|
|
2914
3266
|
}
|
|
2915
3267
|
async loadResponse(fetchResponse) {
|
|
@@ -2920,14 +3272,22 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2920
3272
|
const html = await fetchResponse.responseHTML;
|
|
2921
3273
|
if (html) {
|
|
2922
3274
|
const { body } = parseHTMLDocument(html);
|
|
2923
|
-
const
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
3275
|
+
const newFrameElement = await this.extractForeignFrameElement(body);
|
|
3276
|
+
if (newFrameElement) {
|
|
3277
|
+
const snapshot = new Snapshot(newFrameElement);
|
|
3278
|
+
const renderer = new FrameRenderer(this, this.view.snapshot, snapshot, FrameRenderer.renderElement, false, false);
|
|
3279
|
+
if (this.view.renderPromise)
|
|
3280
|
+
await this.view.renderPromise;
|
|
3281
|
+
this.changeHistory();
|
|
3282
|
+
await this.view.render(renderer);
|
|
3283
|
+
this.complete = true;
|
|
3284
|
+
session.frameRendered(fetchResponse, this.element);
|
|
3285
|
+
session.frameLoaded(this.element);
|
|
3286
|
+
this.fetchResponseLoaded(fetchResponse);
|
|
3287
|
+
}
|
|
3288
|
+
else if (this.sessionWillHandleMissingFrame(fetchResponse)) {
|
|
3289
|
+
await session.frameMissing(this.element, fetchResponse);
|
|
3290
|
+
}
|
|
2931
3291
|
}
|
|
2932
3292
|
}
|
|
2933
3293
|
catch (error) {
|
|
@@ -2938,41 +3298,46 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2938
3298
|
this.fetchResponseLoaded = () => { };
|
|
2939
3299
|
}
|
|
2940
3300
|
}
|
|
2941
|
-
elementAppearedInViewport(
|
|
3301
|
+
elementAppearedInViewport(_element) {
|
|
2942
3302
|
this.loadSourceURL();
|
|
2943
3303
|
}
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
3304
|
+
willSubmitFormLinkToLocation(link) {
|
|
3305
|
+
return link.closest("turbo-frame") == this.element && this.shouldInterceptNavigation(link);
|
|
3306
|
+
}
|
|
3307
|
+
submittedFormLinkToLocation(link, _location, form) {
|
|
3308
|
+
const frame = this.findFrameElement(link);
|
|
3309
|
+
if (frame)
|
|
3310
|
+
form.setAttribute("data-turbo-frame", frame.id);
|
|
3311
|
+
}
|
|
3312
|
+
willFollowLinkToLocation(element) {
|
|
3313
|
+
return this.shouldInterceptNavigation(element);
|
|
2951
3314
|
}
|
|
2952
|
-
|
|
2953
|
-
this.
|
|
2954
|
-
this.navigateFrame(element, url);
|
|
3315
|
+
followedLinkToLocation(element, location) {
|
|
3316
|
+
this.navigateFrame(element, location.href);
|
|
2955
3317
|
}
|
|
2956
|
-
|
|
2957
|
-
return this.shouldInterceptNavigation(element, submitter);
|
|
3318
|
+
willSubmitForm(element, submitter) {
|
|
3319
|
+
return element.closest("turbo-frame") == this.element && this.shouldInterceptNavigation(element, submitter);
|
|
2958
3320
|
}
|
|
2959
|
-
|
|
3321
|
+
formSubmitted(element, submitter) {
|
|
2960
3322
|
if (this.formSubmission) {
|
|
2961
3323
|
this.formSubmission.stop();
|
|
2962
3324
|
}
|
|
2963
|
-
this.reloadable = false;
|
|
2964
3325
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
|
2965
3326
|
const { fetchRequest } = this.formSubmission;
|
|
2966
3327
|
this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest);
|
|
2967
3328
|
this.formSubmission.start();
|
|
2968
3329
|
}
|
|
2969
3330
|
prepareHeadersForRequest(headers, request) {
|
|
3331
|
+
var _a;
|
|
2970
3332
|
headers["Turbo-Frame"] = this.id;
|
|
3333
|
+
if ((_a = this.currentNavigationElement) === null || _a === void 0 ? void 0 : _a.hasAttribute("data-turbo-stream")) {
|
|
3334
|
+
request.acceptResponseType(StreamMessage.contentType);
|
|
3335
|
+
}
|
|
2971
3336
|
}
|
|
2972
|
-
requestStarted(
|
|
3337
|
+
requestStarted(_request) {
|
|
2973
3338
|
markAsBusy(this.element);
|
|
2974
3339
|
}
|
|
2975
|
-
requestPreventedHandlingResponse(
|
|
3340
|
+
requestPreventedHandlingResponse(_request, _response) {
|
|
2976
3341
|
this.resolveVisitPromise();
|
|
2977
3342
|
}
|
|
2978
3343
|
async requestSucceededWithResponse(request, response) {
|
|
@@ -2985,9 +3350,13 @@ Copyright © 2021 Basecamp, LLC
|
|
|
2985
3350
|
}
|
|
2986
3351
|
requestErrored(request, error) {
|
|
2987
3352
|
console.error(error);
|
|
3353
|
+
dispatch("turbo:fetch-request-error", {
|
|
3354
|
+
target: this.element,
|
|
3355
|
+
detail: { request, error },
|
|
3356
|
+
});
|
|
2988
3357
|
this.resolveVisitPromise();
|
|
2989
3358
|
}
|
|
2990
|
-
requestFinished(
|
|
3359
|
+
requestFinished(_request) {
|
|
2991
3360
|
clearBusyState(this.element);
|
|
2992
3361
|
}
|
|
2993
3362
|
formSubmissionStarted({ formElement }) {
|
|
@@ -3007,19 +3376,32 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3007
3376
|
formSubmissionFinished({ formElement }) {
|
|
3008
3377
|
clearBusyState(formElement, this.findFrameElement(formElement));
|
|
3009
3378
|
}
|
|
3010
|
-
allowsImmediateRender(
|
|
3011
|
-
|
|
3379
|
+
allowsImmediateRender({ element: newFrame }, options) {
|
|
3380
|
+
const event = dispatch("turbo:before-frame-render", {
|
|
3381
|
+
target: this.element,
|
|
3382
|
+
detail: Object.assign({ newFrame }, options),
|
|
3383
|
+
cancelable: true,
|
|
3384
|
+
});
|
|
3385
|
+
const { defaultPrevented, detail: { render }, } = event;
|
|
3386
|
+
if (this.view.renderer && render) {
|
|
3387
|
+
this.view.renderer.renderElement = render;
|
|
3388
|
+
}
|
|
3389
|
+
return !defaultPrevented;
|
|
3012
3390
|
}
|
|
3013
|
-
viewRenderedSnapshot(
|
|
3391
|
+
viewRenderedSnapshot(_snapshot, _isPreview) { }
|
|
3392
|
+
preloadOnLoadLinksForView(element) {
|
|
3393
|
+
session.preloadOnLoadLinksForView(element);
|
|
3014
3394
|
}
|
|
3015
|
-
viewInvalidated() {
|
|
3395
|
+
viewInvalidated() { }
|
|
3396
|
+
willRenderFrame(currentElement, _newElement) {
|
|
3397
|
+
this.previousFrameElement = currentElement.cloneNode(true);
|
|
3016
3398
|
}
|
|
3017
3399
|
async visit(url) {
|
|
3018
3400
|
var _a;
|
|
3019
|
-
const request = new FetchRequest(this, FetchMethod.get, url,
|
|
3401
|
+
const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element);
|
|
3020
3402
|
(_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel();
|
|
3021
3403
|
this.currentFetchRequest = request;
|
|
3022
|
-
return new Promise(resolve => {
|
|
3404
|
+
return new Promise((resolve) => {
|
|
3023
3405
|
this.resolveVisitPromise = () => {
|
|
3024
3406
|
this.resolveVisitPromise = () => { };
|
|
3025
3407
|
this.currentFetchRequest = null;
|
|
@@ -3031,23 +3413,49 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3031
3413
|
navigateFrame(element, url, submitter) {
|
|
3032
3414
|
const frame = this.findFrameElement(element, submitter);
|
|
3033
3415
|
this.proposeVisitIfNavigatedWithAction(frame, element, submitter);
|
|
3034
|
-
|
|
3035
|
-
|
|
3416
|
+
this.withCurrentNavigationElement(element, () => {
|
|
3417
|
+
frame.src = url;
|
|
3418
|
+
});
|
|
3036
3419
|
}
|
|
3037
3420
|
proposeVisitIfNavigatedWithAction(frame, element, submitter) {
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3421
|
+
this.action = getVisitAction(submitter, element, frame);
|
|
3422
|
+
this.frame = frame;
|
|
3423
|
+
if (isAction(this.action)) {
|
|
3424
|
+
const { visitCachedSnapshot } = frame.delegate;
|
|
3041
3425
|
frame.delegate.fetchResponseLoaded = (fetchResponse) => {
|
|
3042
3426
|
if (frame.src) {
|
|
3043
3427
|
const { statusCode, redirected } = fetchResponse;
|
|
3044
3428
|
const responseHTML = frame.ownerDocument.documentElement.outerHTML;
|
|
3045
3429
|
const response = { statusCode, redirected, responseHTML };
|
|
3046
|
-
|
|
3430
|
+
const options = {
|
|
3431
|
+
response,
|
|
3432
|
+
visitCachedSnapshot,
|
|
3433
|
+
willRender: false,
|
|
3434
|
+
updateHistory: false,
|
|
3435
|
+
restorationIdentifier: this.restorationIdentifier,
|
|
3436
|
+
};
|
|
3437
|
+
if (this.action)
|
|
3438
|
+
options.action = this.action;
|
|
3439
|
+
session.visit(frame.src, options);
|
|
3047
3440
|
}
|
|
3048
3441
|
};
|
|
3049
3442
|
}
|
|
3050
3443
|
}
|
|
3444
|
+
changeHistory() {
|
|
3445
|
+
if (this.action && this.frame) {
|
|
3446
|
+
const method = getHistoryMethodForAction(this.action);
|
|
3447
|
+
session.history.update(method, expandURL(this.frame.src || ""), this.restorationIdentifier);
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
sessionWillHandleMissingFrame(fetchResponse) {
|
|
3451
|
+
this.element.setAttribute("complete", "");
|
|
3452
|
+
const event = dispatch("turbo:frame-missing", {
|
|
3453
|
+
target: this.element,
|
|
3454
|
+
detail: { fetchResponse },
|
|
3455
|
+
cancelable: true,
|
|
3456
|
+
});
|
|
3457
|
+
return !event.defaultPrevented;
|
|
3458
|
+
}
|
|
3051
3459
|
findFrameElement(element, submitter) {
|
|
3052
3460
|
var _a;
|
|
3053
3461
|
const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target");
|
|
@@ -3057,19 +3465,21 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3057
3465
|
let element;
|
|
3058
3466
|
const id = CSS.escape(this.id);
|
|
3059
3467
|
try {
|
|
3060
|
-
|
|
3468
|
+
element = activateElement(container.querySelector(`turbo-frame#${id}`), this.sourceURL);
|
|
3469
|
+
if (element) {
|
|
3061
3470
|
return element;
|
|
3062
3471
|
}
|
|
3063
|
-
|
|
3472
|
+
element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.sourceURL);
|
|
3473
|
+
if (element) {
|
|
3064
3474
|
await element.loaded;
|
|
3065
3475
|
return await this.extractForeignFrameElement(element);
|
|
3066
3476
|
}
|
|
3067
|
-
console.error(`Response has no matching <turbo-frame id="${id}"> element`);
|
|
3068
3477
|
}
|
|
3069
3478
|
catch (error) {
|
|
3070
3479
|
console.error(error);
|
|
3480
|
+
return new FrameElement();
|
|
3071
3481
|
}
|
|
3072
|
-
return
|
|
3482
|
+
return null;
|
|
3073
3483
|
}
|
|
3074
3484
|
formActionIsVisitable(form, submitter) {
|
|
3075
3485
|
const action = getAction(form, submitter);
|
|
@@ -3089,10 +3499,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3089
3499
|
return !frameElement.disabled;
|
|
3090
3500
|
}
|
|
3091
3501
|
}
|
|
3092
|
-
if (!session.
|
|
3502
|
+
if (!session.elementIsNavigatable(element)) {
|
|
3093
3503
|
return false;
|
|
3094
3504
|
}
|
|
3095
|
-
if (submitter && !session.
|
|
3505
|
+
if (submitter && !session.elementIsNavigatable(submitter)) {
|
|
3096
3506
|
return false;
|
|
3097
3507
|
}
|
|
3098
3508
|
return true;
|
|
@@ -3108,24 +3518,10 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3108
3518
|
return this.element.src;
|
|
3109
3519
|
}
|
|
3110
3520
|
}
|
|
3111
|
-
get reloadable() {
|
|
3112
|
-
const frame = this.findFrameElement(this.element);
|
|
3113
|
-
return frame.hasAttribute("reloadable");
|
|
3114
|
-
}
|
|
3115
|
-
set reloadable(value) {
|
|
3116
|
-
const frame = this.findFrameElement(this.element);
|
|
3117
|
-
if (value) {
|
|
3118
|
-
frame.setAttribute("reloadable", "");
|
|
3119
|
-
}
|
|
3120
|
-
else {
|
|
3121
|
-
frame.removeAttribute("reloadable");
|
|
3122
|
-
}
|
|
3123
|
-
}
|
|
3124
3521
|
set sourceURL(sourceURL) {
|
|
3125
|
-
this.
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
this.settingSourceURL = false;
|
|
3522
|
+
this.ignoringChangesToAttribute("src", () => {
|
|
3523
|
+
this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null;
|
|
3524
|
+
});
|
|
3129
3525
|
}
|
|
3130
3526
|
get loadingStyle() {
|
|
3131
3527
|
return this.element.loading;
|
|
@@ -3133,6 +3529,19 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3133
3529
|
get isLoading() {
|
|
3134
3530
|
return this.formSubmission !== undefined || this.resolveVisitPromise() !== undefined;
|
|
3135
3531
|
}
|
|
3532
|
+
get complete() {
|
|
3533
|
+
return this.element.hasAttribute("complete");
|
|
3534
|
+
}
|
|
3535
|
+
set complete(value) {
|
|
3536
|
+
this.ignoringChangesToAttribute("complete", () => {
|
|
3537
|
+
if (value) {
|
|
3538
|
+
this.element.setAttribute("complete", "");
|
|
3539
|
+
}
|
|
3540
|
+
else {
|
|
3541
|
+
this.element.removeAttribute("complete");
|
|
3542
|
+
}
|
|
3543
|
+
});
|
|
3544
|
+
}
|
|
3136
3545
|
get isActive() {
|
|
3137
3546
|
return this.element.isActive && this.connected;
|
|
3138
3547
|
}
|
|
@@ -3142,16 +3551,18 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3142
3551
|
const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/";
|
|
3143
3552
|
return expandURL(root);
|
|
3144
3553
|
}
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
this.
|
|
3554
|
+
isIgnoringChangesTo(attributeName) {
|
|
3555
|
+
return this.ignoredAttributes.has(attributeName);
|
|
3556
|
+
}
|
|
3557
|
+
ignoringChangesToAttribute(attributeName, callback) {
|
|
3558
|
+
this.ignoredAttributes.add(attributeName);
|
|
3559
|
+
callback();
|
|
3560
|
+
this.ignoredAttributes.delete(attributeName);
|
|
3561
|
+
}
|
|
3562
|
+
withCurrentNavigationElement(element, callback) {
|
|
3563
|
+
this.currentNavigationElement = element;
|
|
3564
|
+
callback();
|
|
3565
|
+
delete this.currentNavigationElement;
|
|
3155
3566
|
}
|
|
3156
3567
|
}
|
|
3157
3568
|
function getFrameElementById(id) {
|
|
@@ -3179,35 +3590,6 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3179
3590
|
}
|
|
3180
3591
|
}
|
|
3181
3592
|
|
|
3182
|
-
const StreamActions = {
|
|
3183
|
-
after() {
|
|
3184
|
-
this.targetElements.forEach(e => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); });
|
|
3185
|
-
},
|
|
3186
|
-
append() {
|
|
3187
|
-
this.removeDuplicateTargetChildren();
|
|
3188
|
-
this.targetElements.forEach(e => e.append(this.templateContent));
|
|
3189
|
-
},
|
|
3190
|
-
before() {
|
|
3191
|
-
this.targetElements.forEach(e => { var _a; return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); });
|
|
3192
|
-
},
|
|
3193
|
-
prepend() {
|
|
3194
|
-
this.removeDuplicateTargetChildren();
|
|
3195
|
-
this.targetElements.forEach(e => e.prepend(this.templateContent));
|
|
3196
|
-
},
|
|
3197
|
-
remove() {
|
|
3198
|
-
this.targetElements.forEach(e => e.remove());
|
|
3199
|
-
},
|
|
3200
|
-
replace() {
|
|
3201
|
-
this.targetElements.forEach(e => e.replaceWith(this.templateContent));
|
|
3202
|
-
},
|
|
3203
|
-
update() {
|
|
3204
|
-
this.targetElements.forEach(e => {
|
|
3205
|
-
e.innerHTML = "";
|
|
3206
|
-
e.append(this.templateContent);
|
|
3207
|
-
});
|
|
3208
|
-
}
|
|
3209
|
-
};
|
|
3210
|
-
|
|
3211
3593
|
class StreamElement extends HTMLElement {
|
|
3212
3594
|
async connectedCallback() {
|
|
3213
3595
|
try {
|
|
@@ -3222,12 +3604,12 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3222
3604
|
}
|
|
3223
3605
|
async render() {
|
|
3224
3606
|
var _a;
|
|
3225
|
-
return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
|
3607
|
+
return ((_a = this.renderPromise) !== null && _a !== void 0 ? _a : (this.renderPromise = (async () => {
|
|
3226
3608
|
if (this.dispatchEvent(this.beforeRenderEvent)) {
|
|
3227
3609
|
await nextAnimationFrame();
|
|
3228
3610
|
this.performAction();
|
|
3229
3611
|
}
|
|
3230
|
-
})());
|
|
3612
|
+
})()));
|
|
3231
3613
|
}
|
|
3232
3614
|
disconnect() {
|
|
3233
3615
|
try {
|
|
@@ -3236,13 +3618,13 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3236
3618
|
catch (_a) { }
|
|
3237
3619
|
}
|
|
3238
3620
|
removeDuplicateTargetChildren() {
|
|
3239
|
-
this.duplicateChildren.forEach(c => c.remove());
|
|
3621
|
+
this.duplicateChildren.forEach((c) => c.remove());
|
|
3240
3622
|
}
|
|
3241
3623
|
get duplicateChildren() {
|
|
3242
3624
|
var _a;
|
|
3243
|
-
const existingChildren = this.targetElements.flatMap(e => [...e.children]).filter(c => !!c.id);
|
|
3244
|
-
const newChildrenIds = [...(_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children].filter(c => !!c.id).map(c => c.id);
|
|
3245
|
-
return existingChildren.filter(c => newChildrenIds.includes(c.id));
|
|
3625
|
+
const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id);
|
|
3626
|
+
const newChildrenIds = [...(((_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children) || [])].filter((c) => !!c.id).map((c) => c.id);
|
|
3627
|
+
return existingChildren.filter((c) => newChildrenIds.includes(c.id));
|
|
3246
3628
|
}
|
|
3247
3629
|
get performAction() {
|
|
3248
3630
|
if (this.action) {
|
|
@@ -3291,7 +3673,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3291
3673
|
return (_b = ((_a = this.outerHTML.match(/<[^>]+>/)) !== null && _a !== void 0 ? _a : [])[0]) !== null && _b !== void 0 ? _b : "<turbo-stream>";
|
|
3292
3674
|
}
|
|
3293
3675
|
get beforeRenderEvent() {
|
|
3294
|
-
return new CustomEvent("turbo:before-stream-render", {
|
|
3676
|
+
return new CustomEvent("turbo:before-stream-render", {
|
|
3677
|
+
bubbles: true,
|
|
3678
|
+
cancelable: true,
|
|
3679
|
+
detail: { newStream: this },
|
|
3680
|
+
});
|
|
3295
3681
|
}
|
|
3296
3682
|
get targetElementsById() {
|
|
3297
3683
|
var _a;
|
|
@@ -3315,9 +3701,35 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3315
3701
|
}
|
|
3316
3702
|
}
|
|
3317
3703
|
|
|
3704
|
+
class StreamSourceElement extends HTMLElement {
|
|
3705
|
+
constructor() {
|
|
3706
|
+
super(...arguments);
|
|
3707
|
+
this.streamSource = null;
|
|
3708
|
+
}
|
|
3709
|
+
connectedCallback() {
|
|
3710
|
+
this.streamSource = this.src.match(/^ws{1,2}:/) ? new WebSocket(this.src) : new EventSource(this.src);
|
|
3711
|
+
connectStreamSource(this.streamSource);
|
|
3712
|
+
}
|
|
3713
|
+
disconnectedCallback() {
|
|
3714
|
+
if (this.streamSource) {
|
|
3715
|
+
disconnectStreamSource(this.streamSource);
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
get src() {
|
|
3719
|
+
return this.getAttribute("src") || "";
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3318
3723
|
FrameElement.delegateConstructor = FrameController;
|
|
3319
|
-
customElements.
|
|
3320
|
-
|
|
3724
|
+
if (customElements.get("turbo-frame") === undefined) {
|
|
3725
|
+
customElements.define("turbo-frame", FrameElement);
|
|
3726
|
+
}
|
|
3727
|
+
if (customElements.get("turbo-stream") === undefined) {
|
|
3728
|
+
customElements.define("turbo-stream", StreamElement);
|
|
3729
|
+
}
|
|
3730
|
+
if (customElements.get("turbo-stream-source") === undefined) {
|
|
3731
|
+
customElements.define("turbo-stream-source", StreamSourceElement);
|
|
3732
|
+
}
|
|
3321
3733
|
|
|
3322
3734
|
(() => {
|
|
3323
3735
|
let element = document.currentScript;
|
|
@@ -3325,7 +3737,8 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3325
3737
|
return;
|
|
3326
3738
|
if (element.hasAttribute("data-turbo-suppress-warning"))
|
|
3327
3739
|
return;
|
|
3328
|
-
|
|
3740
|
+
element = element.parentElement;
|
|
3741
|
+
while (element) {
|
|
3329
3742
|
if (element == document.body) {
|
|
3330
3743
|
return console.warn(unindent `
|
|
3331
3744
|
You are loading Turbo from a <script> element inside the <body> element. This is probably not what you meant to do!
|
|
@@ -3338,14 +3751,18 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3338
3751
|
Suppress this warning by adding a "data-turbo-suppress-warning" attribute to: %s
|
|
3339
3752
|
`, element.outerHTML);
|
|
3340
3753
|
}
|
|
3754
|
+
element = element.parentElement;
|
|
3341
3755
|
}
|
|
3342
3756
|
})();
|
|
3343
3757
|
|
|
3344
3758
|
window.Turbo = Turbo;
|
|
3345
3759
|
start();
|
|
3346
3760
|
|
|
3761
|
+
exports.FrameRenderer = FrameRenderer;
|
|
3347
3762
|
exports.PageRenderer = PageRenderer;
|
|
3348
3763
|
exports.PageSnapshot = PageSnapshot;
|
|
3764
|
+
exports.StreamActions = StreamActions;
|
|
3765
|
+
exports.cache = cache;
|
|
3349
3766
|
exports.clearCache = clearCache;
|
|
3350
3767
|
exports.connectStreamSource = connectStreamSource;
|
|
3351
3768
|
exports.disconnectStreamSource = disconnectStreamSource;
|
|
@@ -3354,10 +3771,11 @@ Copyright © 2021 Basecamp, LLC
|
|
|
3354
3771
|
exports.renderStreamMessage = renderStreamMessage;
|
|
3355
3772
|
exports.session = session;
|
|
3356
3773
|
exports.setConfirmMethod = setConfirmMethod;
|
|
3774
|
+
exports.setFormMode = setFormMode;
|
|
3357
3775
|
exports.setProgressBarDelay = setProgressBarDelay;
|
|
3358
3776
|
exports.start = start;
|
|
3359
3777
|
exports.visit = visit;
|
|
3360
3778
|
|
|
3361
3779
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
3362
3780
|
|
|
3363
|
-
}))
|
|
3781
|
+
}));
|