@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 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.
@@ -1,5 +1,5 @@
1
1
  /*
2
- Turbo 7.0.0-rc.2
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 ("SubmitEvent" in window)
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(Event.prototype, "submitter", {
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
- void (target || document.documentElement).dispatchEvent(event);
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", { cancelable: true, detail: { fetchOptions, url: this.url.href, resume: this.resolveRequestPromise } });
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
- if (event.target instanceof HTMLFormElement) {
670
- const form = event.target;
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
- document.body.appendChild(form);
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 };