turbo-rails 2.0.0.pre.beta.3 → 2.0.0.pre.rc.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b7b21819e793a4171cd5ebdcbd3e9082b1337a3623f5241fccccbca26c70989
4
- data.tar.gz: 69d69e925673a080bfe40e719df3cf3c838c7188cceb30194146be63cbb929ba
3
+ metadata.gz: 629282c25f127e2c0942f0a9635086e30595dbebda133ce77184da1d153514d5
4
+ data.tar.gz: 7cb06dba5377f8bbca58b6066b0f13bbb01f1ed705cb11179d326583b9e1e8cf
5
5
  SHA512:
6
- metadata.gz: 81c645877d527bcac7d22acb0d6405bda1d15503008599926882f467d89ad544a1dd923c79b348150679e3cbcc65b7ea6a4835cb4ca0c03bf08a72002a023771
7
- data.tar.gz: 20303a3c019a1f5b8387581b4a29b3bb13b89d8232f58d18efe9de2eb09347eee2964fe78d650b5fb18821cf890092d30025f027f7b530ab53a53e1ee614e189
6
+ metadata.gz: ba7ff71a246d6c088408dafbf6778a734776bf54f8006a6b8d6c375f60e8f6b61b9db35b38ddeb7bb757a4d902fe2bf1c88408c0437f7eafef14854741e39aee
7
+ data.tar.gz: d0ce9c29add7525e7afdf8fcc691b937df92a51a39588d86d45ad88e5236dec28630d52722032024b67d534ca251dde1182666442bab98e9822a60e841548973
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Turbo 8.0.0-beta.3
2
+ Turbo 8.0.0-rc.1
3
3
  Copyright © 2024 37signals LLC
4
4
  */
5
5
  (function(prototype) {
@@ -1228,7 +1228,8 @@ class View {
1228
1228
  return window;
1229
1229
  }
1230
1230
  async render(renderer) {
1231
- const {isPreview: isPreview, shouldRender: shouldRender, newSnapshot: snapshot} = renderer;
1231
+ const {isPreview: isPreview, shouldRender: shouldRender, willRender: willRender, newSnapshot: snapshot} = renderer;
1232
+ const shouldInvalidate = willRender;
1232
1233
  if (shouldRender) {
1233
1234
  try {
1234
1235
  this.renderPromise = new Promise((resolve => this.#resolveRenderPromise = resolve));
@@ -1237,7 +1238,8 @@ class View {
1237
1238
  const renderInterception = new Promise((resolve => this.#resolveInterceptionPromise = resolve));
1238
1239
  const options = {
1239
1240
  resume: this.#resolveInterceptionPromise,
1240
- render: this.renderer.renderElement
1241
+ render: this.renderer.renderElement,
1242
+ renderMethod: this.renderer.renderMethod
1241
1243
  };
1242
1244
  const immediateRender = this.delegate.allowsImmediateRender(snapshot, options);
1243
1245
  if (!immediateRender) await renderInterception;
@@ -1250,7 +1252,7 @@ class View {
1250
1252
  this.#resolveRenderPromise(undefined);
1251
1253
  delete this.renderPromise;
1252
1254
  }
1253
- } else {
1255
+ } else if (shouldInvalidate) {
1254
1256
  this.invalidate(renderer.reloadReason);
1255
1257
  }
1256
1258
  }
@@ -1623,8 +1625,6 @@ function readScrollBehavior(value, defaultValue) {
1623
1625
  }
1624
1626
  }
1625
1627
 
1626
- const ProgressBarID = "turbo-progress-bar";
1627
-
1628
1628
  class ProgressBar {
1629
1629
  static animationDuration=300;
1630
1630
  static get defaultCSS() {
@@ -1712,8 +1712,6 @@ class ProgressBar {
1712
1712
  }
1713
1713
  createStylesheetElement() {
1714
1714
  const element = document.createElement("style");
1715
- element.id = ProgressBarID;
1716
- element.setAttribute("data-turbo-permanent", "");
1717
1715
  element.type = "text/css";
1718
1716
  element.textContent = ProgressBar.defaultCSS;
1719
1717
  if (this.cspNonce) {
@@ -1969,6 +1967,7 @@ class Visit {
1969
1967
  this.snapshotHTML = snapshotHTML;
1970
1968
  this.response = response;
1971
1969
  this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
1970
+ this.isPageRefresh = this.view.isPageRefresh(this);
1972
1971
  this.visitCachedSnapshot = visitCachedSnapshot;
1973
1972
  this.willRender = willRender;
1974
1973
  this.updateHistory = updateHistory;
@@ -2110,7 +2109,7 @@ class Visit {
2110
2109
  const isPreview = this.shouldIssueRequest();
2111
2110
  this.render((async () => {
2112
2111
  this.cacheSnapshot();
2113
- if (this.isSamePage) {
2112
+ if (this.isSamePage || this.isPageRefresh) {
2114
2113
  this.adapter.visitRendered(this);
2115
2114
  } else {
2116
2115
  if (this.view.renderPromise) await this.view.renderPromise;
@@ -2638,17 +2637,14 @@ class LinkPrefetchObserver {
2638
2637
  };
2639
2638
  prepareRequest(request) {
2640
2639
  const link = request.target;
2641
- request.headers["Sec-Purpose"] = "prefetch";
2642
- if (link.dataset.turboFrame && link.dataset.turboFrame !== "_top") {
2643
- request.headers["Turbo-Frame"] = link.dataset.turboFrame;
2644
- } else if (link.dataset.turboFrame !== "_top") {
2645
- const turboFrame = link.closest("turbo-frame");
2646
- if (turboFrame) {
2647
- request.headers["Turbo-Frame"] = turboFrame.id;
2648
- }
2640
+ request.headers["X-Sec-Purpose"] = "prefetch";
2641
+ const turboFrame = link.closest("turbo-frame");
2642
+ const turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id;
2643
+ if (turboFrameTarget && turboFrameTarget !== "_top") {
2644
+ request.headers["Turbo-Frame"] = turboFrameTarget;
2649
2645
  }
2650
2646
  if (link.hasAttribute("data-turbo-stream")) {
2651
- request.acceptResponseType("text/vnd.turbo-stream.html");
2647
+ request.acceptResponseType(StreamMessage.contentType);
2652
2648
  }
2653
2649
  }
2654
2650
  requestSucceededWithResponse() {}
@@ -2662,7 +2658,7 @@ class LinkPrefetchObserver {
2662
2658
  }
2663
2659
  #isPrefetchable(link) {
2664
2660
  const href = link.getAttribute("href");
2665
- if (!href || href === "#" || link.dataset.turbo === "false" || link.dataset.turboPrefetch === "false") {
2661
+ if (!href || href === "#" || link.getAttribute("data-turbo") === "false" || link.getAttribute("data-turbo-prefetch") === "false") {
2666
2662
  return false;
2667
2663
  }
2668
2664
  if (link.origin !== document.location.origin) {
@@ -2674,17 +2670,15 @@ class LinkPrefetchObserver {
2674
2670
  if (link.pathname + link.search === document.location.pathname + document.location.search) {
2675
2671
  return false;
2676
2672
  }
2677
- if (link.dataset.turboMethod && link.dataset.turboMethod !== "get") {
2673
+ const turboMethod = link.getAttribute("data-turbo-method");
2674
+ if (turboMethod && turboMethod !== "get") {
2678
2675
  return false;
2679
2676
  }
2680
2677
  if (targetsIframe(link)) {
2681
2678
  return false;
2682
2679
  }
2683
- if (link.pathname + link.search === document.location.pathname + document.location.search) {
2684
- return false;
2685
- }
2686
2680
  const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
2687
- if (turboPrefetchParent && turboPrefetchParent.dataset.turboPrefetch === "false") {
2681
+ if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false") {
2688
2682
  return false;
2689
2683
  }
2690
2684
  return true;
@@ -3623,76 +3617,6 @@ var Idiomorph = function() {
3623
3617
  };
3624
3618
  }();
3625
3619
 
3626
- class MorphRenderer extends Renderer {
3627
- async render() {
3628
- if (this.willRender) await this.#morphBody();
3629
- }
3630
- get renderMethod() {
3631
- return "morph";
3632
- }
3633
- async #morphBody() {
3634
- this.#morphElements(this.currentElement, this.newElement);
3635
- this.#reloadRemoteFrames();
3636
- dispatch("turbo:morph", {
3637
- detail: {
3638
- currentElement: this.currentElement,
3639
- newElement: this.newElement
3640
- }
3641
- });
3642
- }
3643
- #morphElements(currentElement, newElement, morphStyle = "outerHTML") {
3644
- this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
3645
- Idiomorph.morph(currentElement, newElement, {
3646
- morphStyle: morphStyle,
3647
- callbacks: {
3648
- beforeNodeAdded: this.#shouldAddElement,
3649
- beforeNodeMorphed: this.#shouldMorphElement,
3650
- beforeNodeRemoved: this.#shouldRemoveElement
3651
- }
3652
- });
3653
- }
3654
- #shouldAddElement=node => !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id));
3655
- #shouldMorphElement=(oldNode, newNode) => {
3656
- if (oldNode instanceof HTMLElement) {
3657
- return !oldNode.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(oldNode));
3658
- } else {
3659
- return true;
3660
- }
3661
- };
3662
- #shouldRemoveElement=node => this.#shouldMorphElement(node);
3663
- #reloadRemoteFrames() {
3664
- this.#remoteFrames().forEach((frame => {
3665
- if (this.#isFrameReloadedWithMorph(frame)) {
3666
- this.#renderFrameWithMorph(frame);
3667
- frame.reload();
3668
- }
3669
- }));
3670
- }
3671
- #renderFrameWithMorph(frame) {
3672
- frame.addEventListener("turbo:before-frame-render", (event => {
3673
- event.detail.render = this.#morphFrameUpdate;
3674
- }), {
3675
- once: true
3676
- });
3677
- }
3678
- #morphFrameUpdate=(currentElement, newElement) => {
3679
- dispatch("turbo:before-frame-morph", {
3680
- target: currentElement,
3681
- detail: {
3682
- currentElement: currentElement,
3683
- newElement: newElement
3684
- }
3685
- });
3686
- this.#morphElements(currentElement, newElement.children, "innerHTML");
3687
- };
3688
- #isFrameReloadedWithMorph(element) {
3689
- return element.src && element.refresh === "morph";
3690
- }
3691
- #remoteFrames() {
3692
- return Array.from(document.querySelectorAll("turbo-frame[src]")).filter((frame => !frame.closest("[data-turbo-permanent]")));
3693
- }
3694
- }
3695
-
3696
3620
  class PageRenderer extends Renderer {
3697
3621
  static renderElement(currentElement, newElement) {
3698
3622
  if (document.body && newElement instanceof HTMLBodyElement) {
@@ -3756,7 +3680,7 @@ class PageRenderer extends Renderer {
3756
3680
  await mergedHeadElements;
3757
3681
  await newStylesheetElements;
3758
3682
  if (this.willRender) {
3759
- this.removeUnusedHeadStylesheetElements();
3683
+ this.removeUnusedDynamicStylesheetElements();
3760
3684
  }
3761
3685
  }
3762
3686
  async replaceBody() {
@@ -3781,8 +3705,8 @@ class PageRenderer extends Renderer {
3781
3705
  document.head.appendChild(activateScriptElement(element));
3782
3706
  }
3783
3707
  }
3784
- removeUnusedHeadStylesheetElements() {
3785
- for (const element of this.unusedHeadStylesheetElements) {
3708
+ removeUnusedDynamicStylesheetElements() {
3709
+ for (const element of this.unusedDynamicStylesheetElements) {
3786
3710
  document.head.removeChild(element);
3787
3711
  }
3788
3712
  }
@@ -3838,8 +3762,8 @@ class PageRenderer extends Renderer {
3838
3762
  async assignNewBody() {
3839
3763
  await this.renderElement(this.currentElement, this.newElement);
3840
3764
  }
3841
- get unusedHeadStylesheetElements() {
3842
- return this.oldHeadStylesheetElements.filter((element => !(element.hasAttribute("data-turbo-permanent") || element.hasAttribute("data-tag-name"))));
3765
+ get unusedDynamicStylesheetElements() {
3766
+ return this.oldHeadStylesheetElements.filter((element => element.getAttribute("data-turbo-track") === "dynamic"));
3843
3767
  }
3844
3768
  get oldHeadStylesheetElements() {
3845
3769
  return this.currentHeadSnapshot.getStylesheetElementsNotInSnapshot(this.newHeadSnapshot);
@@ -3861,6 +3785,109 @@ class PageRenderer extends Renderer {
3861
3785
  }
3862
3786
  }
3863
3787
 
3788
+ class MorphRenderer extends PageRenderer {
3789
+ async render() {
3790
+ if (this.willRender) await this.#morphBody();
3791
+ }
3792
+ get renderMethod() {
3793
+ return "morph";
3794
+ }
3795
+ async #morphBody() {
3796
+ this.#morphElements(this.currentElement, this.newElement);
3797
+ this.#reloadRemoteFrames();
3798
+ dispatch("turbo:morph", {
3799
+ detail: {
3800
+ currentElement: this.currentElement,
3801
+ newElement: this.newElement
3802
+ }
3803
+ });
3804
+ }
3805
+ #morphElements(currentElement, newElement, morphStyle = "outerHTML") {
3806
+ this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
3807
+ Idiomorph.morph(currentElement, newElement, {
3808
+ ignoreActiveValue: true,
3809
+ morphStyle: morphStyle,
3810
+ callbacks: {
3811
+ beforeNodeAdded: this.#shouldAddElement,
3812
+ beforeNodeMorphed: this.#shouldMorphElement,
3813
+ beforeAttributeUpdated: this.#shouldUpdateAttribute,
3814
+ beforeNodeRemoved: this.#shouldRemoveElement,
3815
+ afterNodeMorphed: this.#didMorphElement
3816
+ }
3817
+ });
3818
+ }
3819
+ #shouldAddElement=node => !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id));
3820
+ #shouldMorphElement=(oldNode, newNode) => {
3821
+ if (oldNode instanceof HTMLElement) {
3822
+ if (!oldNode.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(oldNode))) {
3823
+ const event = dispatch("turbo:before-morph-element", {
3824
+ cancelable: true,
3825
+ target: oldNode,
3826
+ detail: {
3827
+ newElement: newNode
3828
+ }
3829
+ });
3830
+ return !event.defaultPrevented;
3831
+ } else {
3832
+ return false;
3833
+ }
3834
+ }
3835
+ };
3836
+ #shouldUpdateAttribute=(attributeName, target, mutationType) => {
3837
+ const event = dispatch("turbo:before-morph-attribute", {
3838
+ cancelable: true,
3839
+ target: target,
3840
+ detail: {
3841
+ attributeName: attributeName,
3842
+ mutationType: mutationType
3843
+ }
3844
+ });
3845
+ return !event.defaultPrevented;
3846
+ };
3847
+ #didMorphElement=(oldNode, newNode) => {
3848
+ if (newNode instanceof HTMLElement) {
3849
+ dispatch("turbo:morph-element", {
3850
+ target: oldNode,
3851
+ detail: {
3852
+ newElement: newNode
3853
+ }
3854
+ });
3855
+ }
3856
+ };
3857
+ #shouldRemoveElement=node => this.#shouldMorphElement(node);
3858
+ #reloadRemoteFrames() {
3859
+ this.#remoteFrames().forEach((frame => {
3860
+ if (this.#isFrameReloadedWithMorph(frame)) {
3861
+ this.#renderFrameWithMorph(frame);
3862
+ frame.reload();
3863
+ }
3864
+ }));
3865
+ }
3866
+ #renderFrameWithMorph(frame) {
3867
+ frame.addEventListener("turbo:before-frame-render", (event => {
3868
+ event.detail.render = this.#morphFrameUpdate;
3869
+ }), {
3870
+ once: true
3871
+ });
3872
+ }
3873
+ #morphFrameUpdate=(currentElement, newElement) => {
3874
+ dispatch("turbo:before-frame-morph", {
3875
+ target: currentElement,
3876
+ detail: {
3877
+ currentElement: currentElement,
3878
+ newElement: newElement
3879
+ }
3880
+ });
3881
+ this.#morphElements(currentElement, newElement.children, "innerHTML");
3882
+ };
3883
+ #isFrameReloadedWithMorph(element) {
3884
+ return element.src && element.refresh === "morph";
3885
+ }
3886
+ #remoteFrames() {
3887
+ return Array.from(document.querySelectorAll("turbo-frame[src]")).filter((frame => !frame.closest("[data-turbo-permanent]")));
3888
+ }
3889
+ }
3890
+
3864
3891
  class SnapshotCache {
3865
3892
  keys=[];
3866
3893
  snapshots={};
@@ -3987,7 +4014,7 @@ class Preloader {
3987
4014
  await fetchRequest.perform();
3988
4015
  }
3989
4016
  prepareRequest(fetchRequest) {
3990
- fetchRequest.headers["Sec-Purpose"] = "prefetch";
4017
+ fetchRequest.headers["X-Sec-Purpose"] = "prefetch";
3991
4018
  }
3992
4019
  async requestSucceededWithResponse(fetchRequest, fetchResponse) {
3993
4020
  try {
@@ -4097,8 +4124,9 @@ class Session {
4097
4124
  visit(location, options = {}) {
4098
4125
  const frameElement = options.frame ? document.getElementById(options.frame) : null;
4099
4126
  if (frameElement instanceof FrameElement) {
4127
+ const action = options.action || getVisitAction(frameElement);
4128
+ frameElement.delegate.proposeVisitIfNavigatedWithAction(frameElement, action);
4100
4129
  frameElement.src = location.toString();
4101
- frameElement.loaded;
4102
4130
  } else {
4103
4131
  this.navigator.proposeVisit(expandURL(location), options);
4104
4132
  }
@@ -4568,7 +4596,7 @@ class FrameController {
4568
4596
  }
4569
4597
  }
4570
4598
  elementAppearedInViewport(element) {
4571
- this.proposeVisitIfNavigatedWithAction(element, element);
4599
+ this.proposeVisitIfNavigatedWithAction(element, getVisitAction(element));
4572
4600
  this.#loadSourceURL();
4573
4601
  }
4574
4602
  willSubmitFormLinkToLocation(link) {
@@ -4628,7 +4656,7 @@ class FrameController {
4628
4656
  }
4629
4657
  formSubmissionSucceededWithResponse(formSubmission, response) {
4630
4658
  const frame = this.#findFrameElement(formSubmission.formElement, formSubmission.submitter);
4631
- frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
4659
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(formSubmission.submitter, formSubmission.formElement, frame));
4632
4660
  frame.delegate.loadResponse(response);
4633
4661
  if (!formSubmission.isSafe) {
4634
4662
  session.clearCache();
@@ -4705,13 +4733,13 @@ class FrameController {
4705
4733
  }
4706
4734
  #navigateFrame(element, url, submitter) {
4707
4735
  const frame = this.#findFrameElement(element, submitter);
4708
- frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
4736
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(submitter, element, frame));
4709
4737
  this.#withCurrentNavigationElement(element, (() => {
4710
4738
  frame.src = url;
4711
4739
  }));
4712
4740
  }
4713
- proposeVisitIfNavigatedWithAction(frame, element, submitter) {
4714
- this.action = getVisitAction(submitter, element, frame);
4741
+ proposeVisitIfNavigatedWithAction(frame, action = null) {
4742
+ this.action = action;
4715
4743
  if (this.action) {
4716
4744
  const pageSnapshot = PageSnapshot.fromElement(frame).clone();
4717
4745
  const {visitCachedSnapshot: visitCachedSnapshot} = frame.delegate;