@hotwired/turbo 7.0.0-rc.3 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -2
- package/dist/turbo.es2017-esm.js +63 -29
- package/dist/turbo.es2017-esm.js.map +1 -0
- package/dist/turbo.es2017-umd.js +63 -29
- package/dist/turbo.es2017-umd.js.map +1 -0
- package/dist/turbo.es5-umd.js +3954 -0
- package/dist/turbo.es5-umd.js.map +1 -0
- package/dist/types/http/fetch_request.d.ts +3 -1
- package/dist/types/tests/functional/drive_disabled_tests.d.ts +2 -0
- package/dist/types/tests/functional/form_submission_tests.d.ts +8 -1
- package/dist/types/tests/functional/frame_navigation_tests.d.ts +1 -0
- package/dist/types/tests/functional/frame_tests.d.ts +8 -0
- package/dist/types/tests/functional/rendering_tests.d.ts +1 -0
- package/dist/types/tests/functional/visit_tests.d.ts +1 -0
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -11,6 +11,4 @@ It's all done by sending HTML over the wire. And for those instances when that's
|
|
|
11
11
|
|
|
12
12
|
Read more on [turbo.hotwired.dev](https://turbo.hotwired.dev).
|
|
13
13
|
|
|
14
|
-
_Note: Turbo is currently in beta. We're using it in production with [HEY](https://hey.com), but expect that significant changes might be made in response to early feedback ✌️❤️_
|
|
15
|
-
|
|
16
14
|
© 2021 Basecamp, LLC.
|
package/dist/turbo.es2017-esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
Turbo 7.0.0
|
|
2
|
+
Turbo 7.0.0
|
|
3
3
|
Copyright © 2021 Basecamp, LLC
|
|
4
4
|
*/
|
|
5
5
|
(function () {
|
|
@@ -33,10 +33,20 @@ function clickCaptured(event) {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
(function () {
|
|
36
|
-
if ("
|
|
36
|
+
if ("submitter" in Event.prototype)
|
|
37
37
|
return;
|
|
38
|
+
let prototype;
|
|
39
|
+
if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) {
|
|
40
|
+
prototype = window.SubmitEvent.prototype;
|
|
41
|
+
}
|
|
42
|
+
else if ("SubmitEvent" in window) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
prototype = window.Event.prototype;
|
|
47
|
+
}
|
|
38
48
|
addEventListener("click", clickCaptured, true);
|
|
39
|
-
Object.defineProperty(
|
|
49
|
+
Object.defineProperty(prototype, "submitter", {
|
|
40
50
|
get() {
|
|
41
51
|
if (this.type == "submit" && this.target instanceof HTMLFormElement) {
|
|
42
52
|
return submittersByForm.get(this.target);
|
|
@@ -222,11 +232,11 @@ class FetchResponse {
|
|
|
222
232
|
return this.header("Content-Type");
|
|
223
233
|
}
|
|
224
234
|
get responseText() {
|
|
225
|
-
return this.response.text();
|
|
235
|
+
return this.response.clone().text();
|
|
226
236
|
}
|
|
227
237
|
get responseHTML() {
|
|
228
238
|
if (this.isHTML) {
|
|
229
|
-
return this.response.text();
|
|
239
|
+
return this.response.clone().text();
|
|
230
240
|
}
|
|
231
241
|
else {
|
|
232
242
|
return Promise.resolve(undefined);
|
|
@@ -239,7 +249,12 @@ class FetchResponse {
|
|
|
239
249
|
|
|
240
250
|
function dispatch(eventName, { target, cancelable, detail } = {}) {
|
|
241
251
|
const event = new CustomEvent(eventName, { cancelable, bubbles: true, detail });
|
|
242
|
-
|
|
252
|
+
if (target && target.isConnected) {
|
|
253
|
+
target.dispatchEvent(event);
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
document.documentElement.dispatchEvent(event);
|
|
257
|
+
}
|
|
243
258
|
return event;
|
|
244
259
|
}
|
|
245
260
|
function nextAnimationFrame() {
|
|
@@ -301,7 +316,7 @@ function fetchMethodFromString(method) {
|
|
|
301
316
|
}
|
|
302
317
|
}
|
|
303
318
|
class FetchRequest {
|
|
304
|
-
constructor(delegate, method, location, body = new URLSearchParams) {
|
|
319
|
+
constructor(delegate, method, location, body = new URLSearchParams, target = null) {
|
|
305
320
|
this.abortController = new AbortController;
|
|
306
321
|
this.resolveRequestPromise = (value) => { };
|
|
307
322
|
this.delegate = delegate;
|
|
@@ -314,6 +329,7 @@ class FetchRequest {
|
|
|
314
329
|
this.body = body;
|
|
315
330
|
this.url = location;
|
|
316
331
|
}
|
|
332
|
+
this.target = target;
|
|
317
333
|
}
|
|
318
334
|
get location() {
|
|
319
335
|
return this.url;
|
|
@@ -349,7 +365,7 @@ class FetchRequest {
|
|
|
349
365
|
}
|
|
350
366
|
async receive(response) {
|
|
351
367
|
const fetchResponse = new FetchResponse(response);
|
|
352
|
-
const event = dispatch("turbo:before-fetch-response", { cancelable: true, detail: { fetchResponse } });
|
|
368
|
+
const event = dispatch("turbo:before-fetch-response", { cancelable: true, detail: { fetchResponse }, target: this.target });
|
|
353
369
|
if (event.defaultPrevented) {
|
|
354
370
|
this.delegate.requestPreventedHandlingResponse(this, fetchResponse);
|
|
355
371
|
}
|
|
@@ -386,7 +402,15 @@ class FetchRequest {
|
|
|
386
402
|
}
|
|
387
403
|
async allowRequestToBeIntercepted(fetchOptions) {
|
|
388
404
|
const requestInterception = new Promise(resolve => this.resolveRequestPromise = resolve);
|
|
389
|
-
const event = dispatch("turbo:before-fetch-request", {
|
|
405
|
+
const event = dispatch("turbo:before-fetch-request", {
|
|
406
|
+
cancelable: true,
|
|
407
|
+
detail: {
|
|
408
|
+
fetchOptions,
|
|
409
|
+
url: this.url.href,
|
|
410
|
+
resume: this.resolveRequestPromise
|
|
411
|
+
},
|
|
412
|
+
target: this.target
|
|
413
|
+
});
|
|
390
414
|
if (event.defaultPrevented)
|
|
391
415
|
await requestInterception;
|
|
392
416
|
}
|
|
@@ -499,7 +523,7 @@ class FormSubmission {
|
|
|
499
523
|
this.formElement = formElement;
|
|
500
524
|
this.submitter = submitter;
|
|
501
525
|
this.formData = buildFormData(formElement, submitter);
|
|
502
|
-
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body);
|
|
526
|
+
this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement);
|
|
503
527
|
this.mustRedirect = mustRedirect;
|
|
504
528
|
}
|
|
505
529
|
get method() {
|
|
@@ -666,8 +690,8 @@ class Snapshot {
|
|
|
666
690
|
class FormInterceptor {
|
|
667
691
|
constructor(delegate, element) {
|
|
668
692
|
this.submitBubbled = ((event) => {
|
|
669
|
-
|
|
670
|
-
|
|
693
|
+
const form = event.target;
|
|
694
|
+
if (form instanceof HTMLFormElement && form.closest("turbo-frame, html") == this.element) {
|
|
671
695
|
const submitter = event.submitter || undefined;
|
|
672
696
|
if (this.delegate.shouldInterceptFormSubmission(form, submitter)) {
|
|
673
697
|
event.preventDefault();
|
|
@@ -1112,6 +1136,7 @@ class HeadSnapshot extends Snapshot {
|
|
|
1112
1136
|
super(...arguments);
|
|
1113
1137
|
this.detailsByOuterHTML = this.children
|
|
1114
1138
|
.filter((element) => !elementIsNoscript(element))
|
|
1139
|
+
.map((element) => elementWithoutNonce(element))
|
|
1115
1140
|
.reduce((result, element) => {
|
|
1116
1141
|
const { outerHTML } = element;
|
|
1117
1142
|
const details = outerHTML in result
|
|
@@ -1196,6 +1221,12 @@ function elementIsMetaElementWithName(element, name) {
|
|
|
1196
1221
|
const tagName = element.tagName.toLowerCase();
|
|
1197
1222
|
return tagName == "meta" && element.getAttribute("name") == name;
|
|
1198
1223
|
}
|
|
1224
|
+
function elementWithoutNonce(element) {
|
|
1225
|
+
if (element.hasAttribute("nonce")) {
|
|
1226
|
+
element.setAttribute("nonce", "");
|
|
1227
|
+
}
|
|
1228
|
+
return element;
|
|
1229
|
+
}
|
|
1199
1230
|
|
|
1200
1231
|
class PageSnapshot extends Snapshot {
|
|
1201
1232
|
constructor(element, headSnapshot) {
|
|
@@ -1739,18 +1770,18 @@ class FrameRedirector {
|
|
|
1739
1770
|
return this.shouldRedirect(element, submitter);
|
|
1740
1771
|
}
|
|
1741
1772
|
formSubmissionIntercepted(element, submitter) {
|
|
1742
|
-
const frame = this.findFrameElement(element);
|
|
1773
|
+
const frame = this.findFrameElement(element, submitter);
|
|
1743
1774
|
if (frame) {
|
|
1744
1775
|
frame.removeAttribute("reloadable");
|
|
1745
1776
|
frame.delegate.formSubmissionIntercepted(element, submitter);
|
|
1746
1777
|
}
|
|
1747
1778
|
}
|
|
1748
1779
|
shouldRedirect(element, submitter) {
|
|
1749
|
-
const frame = this.findFrameElement(element);
|
|
1780
|
+
const frame = this.findFrameElement(element, submitter);
|
|
1750
1781
|
return frame ? frame != element.closest("turbo-frame") : false;
|
|
1751
1782
|
}
|
|
1752
|
-
findFrameElement(element) {
|
|
1753
|
-
const id = element.getAttribute("data-turbo-frame");
|
|
1783
|
+
findFrameElement(element, submitter) {
|
|
1784
|
+
const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame");
|
|
1754
1785
|
if (id && id != "_top") {
|
|
1755
1786
|
const frame = this.element.querySelector(`#${id}:not([disabled])`);
|
|
1756
1787
|
if (frame instanceof FrameElement) {
|
|
@@ -2462,12 +2493,14 @@ class Session {
|
|
|
2462
2493
|
this.convertLinkWithMethodClickToFormSubmission(link) || this.visit(location.href, { action });
|
|
2463
2494
|
}
|
|
2464
2495
|
convertLinkWithMethodClickToFormSubmission(link) {
|
|
2496
|
+
var _a;
|
|
2465
2497
|
const linkMethod = link.getAttribute("data-turbo-method");
|
|
2466
2498
|
if (linkMethod) {
|
|
2467
2499
|
const form = document.createElement("form");
|
|
2468
2500
|
form.method = linkMethod;
|
|
2469
2501
|
form.action = link.getAttribute("href") || "undefined";
|
|
2470
|
-
|
|
2502
|
+
form.hidden = true;
|
|
2503
|
+
(_a = link.parentNode) === null || _a === void 0 ? void 0 : _a.insertBefore(form, link);
|
|
2471
2504
|
return dispatch("submit", { cancelable: true, target: form });
|
|
2472
2505
|
}
|
|
2473
2506
|
else {
|
|
@@ -2497,7 +2530,7 @@ class Session {
|
|
|
2497
2530
|
this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL);
|
|
2498
2531
|
}
|
|
2499
2532
|
willSubmitForm(form, submitter) {
|
|
2500
|
-
return this.elementDriveEnabled(form) && this.elementDriveEnabled(submitter);
|
|
2533
|
+
return this.elementDriveEnabled(form) && (!submitter || this.elementDriveEnabled(submitter));
|
|
2501
2534
|
}
|
|
2502
2535
|
formSubmitted(form, submitter) {
|
|
2503
2536
|
this.navigator.submitForm(form, submitter);
|
|
@@ -2618,7 +2651,7 @@ const deprecatedLocationPropertyDescriptors = {
|
|
|
2618
2651
|
};
|
|
2619
2652
|
|
|
2620
2653
|
const session = new Session;
|
|
2621
|
-
const { navigator } = session;
|
|
2654
|
+
const { navigator: navigator$1 } = session;
|
|
2622
2655
|
function start() {
|
|
2623
2656
|
session.start();
|
|
2624
2657
|
}
|
|
@@ -2646,7 +2679,7 @@ function setProgressBarDelay(delay) {
|
|
|
2646
2679
|
|
|
2647
2680
|
var Turbo = /*#__PURE__*/Object.freeze({
|
|
2648
2681
|
__proto__: null,
|
|
2649
|
-
navigator: navigator,
|
|
2682
|
+
navigator: navigator$1,
|
|
2650
2683
|
session: session,
|
|
2651
2684
|
PageRenderer: PageRenderer,
|
|
2652
2685
|
PageSnapshot: PageSnapshot,
|
|
@@ -2776,7 +2809,7 @@ class FrameController {
|
|
|
2776
2809
|
this.reloadable = false;
|
|
2777
2810
|
this.formSubmission = new FormSubmission(this, element, submitter);
|
|
2778
2811
|
if (this.formSubmission.fetchRequest.isIdempotent) {
|
|
2779
|
-
this.navigateFrame(element, this.formSubmission.fetchRequest.url.href);
|
|
2812
|
+
this.navigateFrame(element, this.formSubmission.fetchRequest.url.href, submitter);
|
|
2780
2813
|
}
|
|
2781
2814
|
else {
|
|
2782
2815
|
const { fetchRequest } = this.formSubmission;
|
|
@@ -2813,7 +2846,7 @@ class FrameController {
|
|
|
2813
2846
|
frame.setAttribute("busy", "");
|
|
2814
2847
|
}
|
|
2815
2848
|
formSubmissionSucceededWithResponse(formSubmission, response) {
|
|
2816
|
-
const frame = this.findFrameElement(formSubmission.formElement);
|
|
2849
|
+
const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter);
|
|
2817
2850
|
frame.delegate.loadResponse(response);
|
|
2818
2851
|
}
|
|
2819
2852
|
formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
|
@@ -2834,7 +2867,7 @@ class FrameController {
|
|
|
2834
2867
|
viewInvalidated() {
|
|
2835
2868
|
}
|
|
2836
2869
|
async visit(url) {
|
|
2837
|
-
const request = new FetchRequest(this, FetchMethod.get, expandURL(url));
|
|
2870
|
+
const request = new FetchRequest(this, FetchMethod.get, expandURL(url), undefined, this.element);
|
|
2838
2871
|
return new Promise(resolve => {
|
|
2839
2872
|
this.resolveVisitPromise = () => {
|
|
2840
2873
|
this.resolveVisitPromise = () => { };
|
|
@@ -2843,13 +2876,14 @@ class FrameController {
|
|
|
2843
2876
|
request.perform();
|
|
2844
2877
|
});
|
|
2845
2878
|
}
|
|
2846
|
-
navigateFrame(element, url) {
|
|
2847
|
-
const frame = this.findFrameElement(element);
|
|
2879
|
+
navigateFrame(element, url, submitter) {
|
|
2880
|
+
const frame = this.findFrameElement(element, submitter);
|
|
2881
|
+
frame.setAttribute("reloadable", "");
|
|
2848
2882
|
frame.src = url;
|
|
2849
2883
|
}
|
|
2850
|
-
findFrameElement(element) {
|
|
2884
|
+
findFrameElement(element, submitter) {
|
|
2851
2885
|
var _a;
|
|
2852
|
-
const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
|
2886
|
+
const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
|
2853
2887
|
return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
|
|
2854
2888
|
}
|
|
2855
2889
|
async extractForeignFrameElement(container) {
|
|
@@ -2871,7 +2905,7 @@ class FrameController {
|
|
|
2871
2905
|
return new FrameElement();
|
|
2872
2906
|
}
|
|
2873
2907
|
shouldInterceptNavigation(element, submitter) {
|
|
2874
|
-
const id = element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
|
2908
|
+
const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame") || this.element.getAttribute("target");
|
|
2875
2909
|
if (!this.enabled || id == "_top") {
|
|
2876
2910
|
return false;
|
|
2877
2911
|
}
|
|
@@ -3118,4 +3152,4 @@ customElements.define("turbo-stream", StreamElement);
|
|
|
3118
3152
|
window.Turbo = Turbo;
|
|
3119
3153
|
start();
|
|
3120
3154
|
|
|
3121
|
-
export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator, registerAdapter, renderStreamMessage, session, setProgressBarDelay, start, visit };
|
|
3155
|
+
export { PageRenderer, PageSnapshot, clearCache, connectStreamSource, disconnectStreamSource, navigator$1 as navigator, registerAdapter, renderStreamMessage, session, setProgressBarDelay, start, visit };
|