turbo-rails 2.0.0.pre.beta.3 → 2.0.0.pre.rc.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 629282c25f127e2c0942f0a9635086e30595dbebda133ce77184da1d153514d5
|
4
|
+
data.tar.gz: 7cb06dba5377f8bbca58b6066b0f13bbb01f1ed705cb11179d326583b9e1e8cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba7ff71a246d6c088408dafbf6778a734776bf54f8006a6b8d6c375f60e8f6b61b9db35b38ddeb7bb757a4d902fe2bf1c88408c0437f7eafef14854741e39aee
|
7
|
+
data.tar.gz: d0ce9c29add7525e7afdf8fcc691b937df92a51a39588d86d45ad88e5236dec28630d52722032024b67d534ca251dde1182666442bab98e9822a60e841548973
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
Turbo 8.0.0-
|
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
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
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(
|
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.
|
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
|
-
|
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.
|
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.
|
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
|
-
|
3785
|
-
for (const element of this.
|
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
|
3842
|
-
return this.oldHeadStylesheetElements.filter((element =>
|
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.
|
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,
|
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,
|
4714
|
-
this.action =
|
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;
|