turbo-rails 2.0.0.pre.beta.4 → 2.0.0.pre.rc.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ebbd80b386f589e8154d0bb0c5a49cbd38dd43e09ad33a33c6981d0d6518d19
4
- data.tar.gz: 94b8d1dcbe102085ddef02c04e3c546d0e96298b7fafce1853875446cb40847a
3
+ metadata.gz: db9fabf188a1b8db9d4a2f15742cbd342293368ba0bb3d23692fa2f1e922e79d
4
+ data.tar.gz: 3080cea594ecd3f05d1d80f515c919992f5e1d8afcbc921b656879ddcda76433
5
5
  SHA512:
6
- metadata.gz: 4851e50f1411ac0544fd2d9f330f82c9453af40e98b92a5a31a117f20e6a2e28ade5298868a1c6786568eb686546db89c213e3c3ad17dffd52c984cbc84a7eb0
7
- data.tar.gz: feb01812e76d08c659e0c9ffff7ef9dea553ae126603b94b63fa88821ec80acd1d4a6dc8c3921270657f236b66adc25d68507c0de0743e3e7d6f7a3df3644a07
6
+ metadata.gz: bdb2fcb4ed4f3d9b63ff6d965b8fa17a0e3b9e004546289f7a4f10b14da66f5c94ba3d5d6ca4c0e9bcbad7253d2250c47034bd4540d5bc1a962a333591892137
7
+ data.tar.gz: 37c771f8632419220a3a017c007867926adf12185cd6de833da527990bf8198a383eea645b53cee3ce38ffefc6ac4a25267b215272957e23aac07948d050e1d0
@@ -1,5 +1,5 @@
1
1
  /*!
2
- Turbo 8.0.0-beta.4
2
+ Turbo 8.0.0-rc.2
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
  }
@@ -1965,6 +1967,7 @@ class Visit {
1965
1967
  this.snapshotHTML = snapshotHTML;
1966
1968
  this.response = response;
1967
1969
  this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action);
1970
+ this.isPageRefresh = this.view.isPageRefresh(this);
1968
1971
  this.visitCachedSnapshot = visitCachedSnapshot;
1969
1972
  this.willRender = willRender;
1970
1973
  this.updateHistory = updateHistory;
@@ -2106,7 +2109,7 @@ class Visit {
2106
2109
  const isPreview = this.shouldIssueRequest();
2107
2110
  this.render((async () => {
2108
2111
  this.cacheSnapshot();
2109
- if (this.isSamePage) {
2112
+ if (this.isSamePage || this.isPageRefresh) {
2110
2113
  this.adapter.visitRendered(this);
2111
2114
  } else {
2112
2115
  if (this.view.renderPromise) await this.view.renderPromise;
@@ -2634,14 +2637,14 @@ class LinkPrefetchObserver {
2634
2637
  };
2635
2638
  prepareRequest(request) {
2636
2639
  const link = request.target;
2637
- request.headers["Sec-Purpose"] = "prefetch";
2640
+ request.headers["X-Sec-Purpose"] = "prefetch";
2638
2641
  const turboFrame = link.closest("turbo-frame");
2639
2642
  const turboFrameTarget = link.getAttribute("data-turbo-frame") || turboFrame?.getAttribute("target") || turboFrame?.id;
2640
2643
  if (turboFrameTarget && turboFrameTarget !== "_top") {
2641
2644
  request.headers["Turbo-Frame"] = turboFrameTarget;
2642
2645
  }
2643
2646
  if (link.hasAttribute("data-turbo-stream")) {
2644
- request.acceptResponseType("text/vnd.turbo-stream.html");
2647
+ request.acceptResponseType(StreamMessage.contentType);
2645
2648
  }
2646
2649
  }
2647
2650
  requestSucceededWithResponse() {}
@@ -2655,7 +2658,7 @@ class LinkPrefetchObserver {
2655
2658
  }
2656
2659
  #isPrefetchable(link) {
2657
2660
  const href = link.getAttribute("href");
2658
- 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") {
2659
2662
  return false;
2660
2663
  }
2661
2664
  if (link.origin !== document.location.origin) {
@@ -2667,17 +2670,15 @@ class LinkPrefetchObserver {
2667
2670
  if (link.pathname + link.search === document.location.pathname + document.location.search) {
2668
2671
  return false;
2669
2672
  }
2670
- if (link.dataset.turboMethod && link.dataset.turboMethod !== "get") {
2673
+ const turboMethod = link.getAttribute("data-turbo-method");
2674
+ if (turboMethod && turboMethod !== "get") {
2671
2675
  return false;
2672
2676
  }
2673
2677
  if (targetsIframe(link)) {
2674
2678
  return false;
2675
2679
  }
2676
- if (link.pathname + link.search === document.location.pathname + document.location.search) {
2677
- return false;
2678
- }
2679
2680
  const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
2680
- if (turboPrefetchParent && turboPrefetchParent.dataset.turboPrefetch === "false") {
2681
+ if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false") {
2681
2682
  return false;
2682
2683
  }
2683
2684
  return true;
@@ -3147,7 +3148,7 @@ var Idiomorph = function() {
3147
3148
  }
3148
3149
  }
3149
3150
  function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
3150
- return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement;
3151
+ return ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
3151
3152
  }
3152
3153
  function morphOldNodeTo(oldNode, newContent, ctx) {
3153
3154
  if (ctx.ignoreActive && oldNode === document.activeElement) ; else if (newContent == null) {
@@ -3616,76 +3617,6 @@ var Idiomorph = function() {
3616
3617
  };
3617
3618
  }();
3618
3619
 
3619
- class MorphRenderer extends Renderer {
3620
- async render() {
3621
- if (this.willRender) await this.#morphBody();
3622
- }
3623
- get renderMethod() {
3624
- return "morph";
3625
- }
3626
- async #morphBody() {
3627
- this.#morphElements(this.currentElement, this.newElement);
3628
- this.#reloadRemoteFrames();
3629
- dispatch("turbo:morph", {
3630
- detail: {
3631
- currentElement: this.currentElement,
3632
- newElement: this.newElement
3633
- }
3634
- });
3635
- }
3636
- #morphElements(currentElement, newElement, morphStyle = "outerHTML") {
3637
- this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
3638
- Idiomorph.morph(currentElement, newElement, {
3639
- morphStyle: morphStyle,
3640
- callbacks: {
3641
- beforeNodeAdded: this.#shouldAddElement,
3642
- beforeNodeMorphed: this.#shouldMorphElement,
3643
- beforeNodeRemoved: this.#shouldRemoveElement
3644
- }
3645
- });
3646
- }
3647
- #shouldAddElement=node => !(node.id && node.hasAttribute("data-turbo-permanent") && document.getElementById(node.id));
3648
- #shouldMorphElement=(oldNode, newNode) => {
3649
- if (oldNode instanceof HTMLElement) {
3650
- return !oldNode.hasAttribute("data-turbo-permanent") && (this.isMorphingTurboFrame || !this.#isFrameReloadedWithMorph(oldNode));
3651
- } else {
3652
- return true;
3653
- }
3654
- };
3655
- #shouldRemoveElement=node => this.#shouldMorphElement(node);
3656
- #reloadRemoteFrames() {
3657
- this.#remoteFrames().forEach((frame => {
3658
- if (this.#isFrameReloadedWithMorph(frame)) {
3659
- this.#renderFrameWithMorph(frame);
3660
- frame.reload();
3661
- }
3662
- }));
3663
- }
3664
- #renderFrameWithMorph(frame) {
3665
- frame.addEventListener("turbo:before-frame-render", (event => {
3666
- event.detail.render = this.#morphFrameUpdate;
3667
- }), {
3668
- once: true
3669
- });
3670
- }
3671
- #morphFrameUpdate=(currentElement, newElement) => {
3672
- dispatch("turbo:before-frame-morph", {
3673
- target: currentElement,
3674
- detail: {
3675
- currentElement: currentElement,
3676
- newElement: newElement
3677
- }
3678
- });
3679
- this.#morphElements(currentElement, newElement.children, "innerHTML");
3680
- };
3681
- #isFrameReloadedWithMorph(element) {
3682
- return element.src && element.refresh === "morph";
3683
- }
3684
- #remoteFrames() {
3685
- return Array.from(document.querySelectorAll("turbo-frame[src]")).filter((frame => !frame.closest("[data-turbo-permanent]")));
3686
- }
3687
- }
3688
-
3689
3620
  class PageRenderer extends Renderer {
3690
3621
  static renderElement(currentElement, newElement) {
3691
3622
  if (document.body && newElement instanceof HTMLBodyElement) {
@@ -3854,6 +3785,109 @@ class PageRenderer extends Renderer {
3854
3785
  }
3855
3786
  }
3856
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
+
3857
3891
  class SnapshotCache {
3858
3892
  keys=[];
3859
3893
  snapshots={};
@@ -3980,7 +4014,7 @@ class Preloader {
3980
4014
  await fetchRequest.perform();
3981
4015
  }
3982
4016
  prepareRequest(fetchRequest) {
3983
- fetchRequest.headers["Sec-Purpose"] = "prefetch";
4017
+ fetchRequest.headers["X-Sec-Purpose"] = "prefetch";
3984
4018
  }
3985
4019
  async requestSucceededWithResponse(fetchRequest, fetchResponse) {
3986
4020
  try {
@@ -4090,8 +4124,9 @@ class Session {
4090
4124
  visit(location, options = {}) {
4091
4125
  const frameElement = options.frame ? document.getElementById(options.frame) : null;
4092
4126
  if (frameElement instanceof FrameElement) {
4127
+ const action = options.action || getVisitAction(frameElement);
4128
+ frameElement.delegate.proposeVisitIfNavigatedWithAction(frameElement, action);
4093
4129
  frameElement.src = location.toString();
4094
- frameElement.loaded;
4095
4130
  } else {
4096
4131
  this.navigator.proposeVisit(expandURL(location), options);
4097
4132
  }
@@ -4561,7 +4596,7 @@ class FrameController {
4561
4596
  }
4562
4597
  }
4563
4598
  elementAppearedInViewport(element) {
4564
- this.proposeVisitIfNavigatedWithAction(element, element);
4599
+ this.proposeVisitIfNavigatedWithAction(element, getVisitAction(element));
4565
4600
  this.#loadSourceURL();
4566
4601
  }
4567
4602
  willSubmitFormLinkToLocation(link) {
@@ -4621,7 +4656,7 @@ class FrameController {
4621
4656
  }
4622
4657
  formSubmissionSucceededWithResponse(formSubmission, response) {
4623
4658
  const frame = this.#findFrameElement(formSubmission.formElement, formSubmission.submitter);
4624
- frame.delegate.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter);
4659
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(formSubmission.submitter, formSubmission.formElement, frame));
4625
4660
  frame.delegate.loadResponse(response);
4626
4661
  if (!formSubmission.isSafe) {
4627
4662
  session.clearCache();
@@ -4698,13 +4733,13 @@ class FrameController {
4698
4733
  }
4699
4734
  #navigateFrame(element, url, submitter) {
4700
4735
  const frame = this.#findFrameElement(element, submitter);
4701
- frame.delegate.proposeVisitIfNavigatedWithAction(frame, element, submitter);
4736
+ frame.delegate.proposeVisitIfNavigatedWithAction(frame, getVisitAction(submitter, element, frame));
4702
4737
  this.#withCurrentNavigationElement(element, (() => {
4703
4738
  frame.src = url;
4704
4739
  }));
4705
4740
  }
4706
- proposeVisitIfNavigatedWithAction(frame, element, submitter) {
4707
- this.action = getVisitAction(submitter, element, frame);
4741
+ proposeVisitIfNavigatedWithAction(frame, action = null) {
4742
+ this.action = action;
4708
4743
  if (this.action) {
4709
4744
  const pageSnapshot = PageSnapshot.fromElement(frame).clone();
4710
4745
  const {visitCachedSnapshot: visitCachedSnapshot} = frame.delegate;