turbo-rails 2.0.0 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -6
- data/app/assets/javascripts/turbo.js +40 -39
- data/app/assets/javascripts/turbo.min.js +6 -6
- data/app/assets/javascripts/turbo.min.js.map +1 -1
- data/app/channels/turbo/streams/broadcasts.rb +1 -1
- data/app/controllers/turbo/frames/frame_request.rb +2 -2
- data/app/controllers/turbo/native/navigation.rb +6 -3
- data/app/helpers/turbo/drive_helper.rb +17 -18
- data/app/helpers/turbo/frames_helper.rb +4 -7
- data/app/helpers/turbo/streams/action_helper.rb +4 -1
- data/app/helpers/turbo/streams_helper.rb +0 -1
- data/app/models/concerns/turbo/broadcastable.rb +89 -15
- data/lib/turbo/broadcastable/test_helper.rb +4 -4
- data/lib/turbo/engine.rb +7 -2
- data/lib/turbo/test_assertions/integration_test_assertions.rb +2 -2
- data/lib/turbo/test_assertions.rb +2 -2
- data/lib/turbo/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ce426f6fcdec338c0a3eb5c3f97ee2660ef618d23535671ddf464d2650041997
|
4
|
+
data.tar.gz: eab0160dacd564b0e002ea3fe658bbc6f4770b7c912867c335758d2c3237c24b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d80adee8976dad280b8ff058d5c0615617f37ca3ba5c164db63dce81ad9263b8cfdf704b50c0aaeac9d5d675ad66298ca34902f2e31f5cfc493f8041ca32d12e
|
7
|
+
data.tar.gz: 696dc8a61b6b0860ca5b2db540f4e573e7531a293a84854068bb1277997f3c73aa993527afdd4a9dc5c741fc8c83ef258cf2022d3a354c6b4d3e2fef2cca0dd1
|
data/README.md
CHANGED
@@ -6,7 +6,6 @@ On top of accelerating web applications, Turbo was built from the ground-up to f
|
|
6
6
|
|
7
7
|
Turbo is a language-agnostic framework written in JavaScript, but this gem builds on top of those basics to make the integration with Rails as smooth as possible. You can deliver turbo updates via model callbacks over Action Cable, respond to controller actions with native navigation or standard redirects, and render turbo frames with helpers and layout-free responses.
|
8
8
|
|
9
|
-
|
10
9
|
## Navigate with Turbo Drive
|
11
10
|
|
12
11
|
Turbo is a continuation of the ideas from the previous [Turbolinks](https://github.com/turbolinks/turbolinks) framework, and the heart of that past approach lives on as Turbo Drive. When installed, Turbo automatically intercepts all clicks on `<a href>` links to the same domain. When you click an eligible link, Turbo prevents the browser from following it. Instead, Turbo changes the browser’s URL using the History API, requests the new page using `fetch`, and then renders the HTML response.
|
@@ -122,7 +121,6 @@ The `Turbo` instance is automatically assigned to `window.Turbo` upon import:
|
|
122
121
|
import "@hotwired/turbo-rails"
|
123
122
|
```
|
124
123
|
|
125
|
-
|
126
124
|
## Usage
|
127
125
|
|
128
126
|
You can watch [the video introduction to Hotwire](https://hotwired.dev/#screencast), which focuses extensively on demonstrating Turbo in a Rails demo. Then you should familiarize yourself with [Turbo handbook](https://turbo.hotwired.dev/handbook/introduction) to understand Drive, Frames, and Streams in-depth. Finally, dive into the code documentation by starting with [`Turbo::FramesHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/frames_helper.rb), [`Turbo::StreamsHelper`](https://github.com/hotwired/turbo-rails/blob/main/app/helpers/turbo/streams_helper.rb), [`Turbo::Streams::TagBuilder`](https://github.com/hotwired/turbo-rails/blob/main/app/models/turbo/streams/tag_builder.rb), and [`Turbo::Broadcastable`](https://github.com/hotwired/turbo-rails/blob/main/app/models/concerns/turbo/broadcastable.rb).
|
@@ -130,6 +128,17 @@ You can watch [the video introduction to Hotwire](https://hotwired.dev/#screenca
|
|
130
128
|
### RubyDoc Documentation
|
131
129
|
|
132
130
|
For the API documentation covering this gem's classes and packages, [visit the RubyDoc page](https://rubydoc.info/github/hotwired/turbo-rails/main).
|
131
|
+
Note that this documentation is updated automatically from the main branch, so it may contain features that are not released yet.
|
132
|
+
|
133
|
+
- [Turbo Drive Helpers](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/DriveHelper)
|
134
|
+
- [Turbo Frames Helpers](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/FramesHelper)
|
135
|
+
- [Turbo Streams View Helpers](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/StreamsHelper)
|
136
|
+
- [Turbo Streams Broadcast Methods](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/Broadcastable)
|
137
|
+
- [Turbo Streams Channel](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/StreamsChannel)
|
138
|
+
- [Turbo Native Navigation](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/Native/Navigation)
|
139
|
+
- [Turbo Test Assertions](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/TestAssertions)
|
140
|
+
- [Turbo Integration Test Assertions](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/TestAssertions/IntegrationTestAssertions)
|
141
|
+
- [Turbo Broadcastable Test Helper](https://rubydoc.info/github/hotwired/turbo-rails/main/Turbo/Broadcastable/TestHelper)
|
133
142
|
|
134
143
|
## Compatibility with Rails UJS
|
135
144
|
|
@@ -137,18 +146,16 @@ Turbo can coexist with Rails UJS, but you need to take a series of upgrade steps
|
|
137
146
|
|
138
147
|
## Testing
|
139
148
|
|
140
|
-
|
141
|
-
The [`Turbo::TestAssertions`](./lib/turbo/test_assertions.rb) concern provides Turbo Stream test helpers that assert the presence or absence of `<turbo-stream>` elements in a rendered fragment of HTML. `Turbo::TestAssertions` are automatically included in [`ActiveSupport::TestCase`](https://edgeapi.rubyonrails.org/classes/ActiveSupport/TestCase.html) and depend on the presence of [`rails-dom-testing`](https://github.com/rails/rails-dom-testing/) assertions.
|
149
|
+
The [`Turbo::TestAssertions`](./lib/turbo/test_assertions.rb) concern provides Turbo Stream test helpers that assert the presence or absence ofs s `<turbo-stream>` elements in a rendered fragment of HTML. `Turbo::TestAssertions` are automatically included in [`ActiveSupport::TestCase`](https://edgeapi.rubyonrails.org/classes/ActiveSupport/TestCase.html) and depend on the presence of [`rails-dom-testing`](https://github.com/rails/rails-dom-testing/) assertions.
|
142
150
|
|
143
151
|
The [`Turbo::TestAssertions::IntegrationTestAssertions`](./lib/turbo/test_assertions/integration_test_assertions.rb) are built on top of `Turbo::TestAssertions`, and add support for passing a `status:` keyword. They are automatically included in [`ActionDispatch::IntegrationTest`](https://edgeguides.rubyonrails.org/testing.html#integration-testing).
|
144
152
|
|
145
|
-
The [`Turbo::Broadcastable::TestHelper`](./lib/turbo/broadcastable/test_helper.rb) concern provides Action Cable-aware test helpers that assert that `<turbo-stream>` elements were or were not broadcast over Action Cable.
|
153
|
+
The [`Turbo::Broadcastable::TestHelper`](./lib/turbo/broadcastable/test_helper.rb) concern provides Action Cable-aware test helpers that assert that `<turbo-stream>` elements were or were not broadcast over Action Cable. `Turbo::Broadcastable::TestHelper` is automatically included in [`ActiveSupport::TestCase`](https://edgeapi.rubyonrails.org/classes/ActiveSupport/TestCase.html).
|
146
154
|
|
147
155
|
## Development
|
148
156
|
|
149
157
|
Run the tests with `./bin/test`.
|
150
158
|
|
151
|
-
|
152
159
|
## License
|
153
160
|
|
154
161
|
Turbo is released under the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
Turbo 8.0.
|
2
|
+
Turbo 8.0.3
|
3
3
|
Copyright © 2024 37signals LLC
|
4
4
|
*/
|
5
5
|
(function(prototype) {
|
@@ -2011,10 +2011,10 @@ class Visit {
|
|
2011
2011
|
complete() {
|
2012
2012
|
if (this.state == VisitState.started) {
|
2013
2013
|
this.recordTimingMetric(TimingMetric.visitEnd);
|
2014
|
+
this.adapter.visitCompleted(this);
|
2014
2015
|
this.state = VisitState.completed;
|
2015
2016
|
this.followRedirect();
|
2016
2017
|
if (!this.followedRedirect) {
|
2017
|
-
this.adapter.visitCompleted(this);
|
2018
2018
|
this.delegate.visitCompleted(this);
|
2019
2019
|
}
|
2020
2020
|
}
|
@@ -2647,9 +2647,6 @@ class LinkPrefetchObserver {
|
|
2647
2647
|
if (turboFrameTarget && turboFrameTarget !== "_top") {
|
2648
2648
|
request.headers["Turbo-Frame"] = turboFrameTarget;
|
2649
2649
|
}
|
2650
|
-
if (link.hasAttribute("data-turbo-stream")) {
|
2651
|
-
request.acceptResponseType(StreamMessage.contentType);
|
2652
|
-
}
|
2653
2650
|
}
|
2654
2651
|
requestSucceededWithResponse() {}
|
2655
2652
|
requestStarted(fetchRequest) {}
|
@@ -2662,41 +2659,46 @@ class LinkPrefetchObserver {
|
|
2662
2659
|
}
|
2663
2660
|
#isPrefetchable(link) {
|
2664
2661
|
const href = link.getAttribute("href");
|
2665
|
-
if (!href
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
|
2671
|
-
});
|
2672
|
-
if (event.defaultPrevented) {
|
2673
|
-
return false;
|
2674
|
-
}
|
2675
|
-
if (link.origin !== document.location.origin) {
|
2676
|
-
return false;
|
2677
|
-
}
|
2678
|
-
if (![ "http:", "https:" ].includes(link.protocol)) {
|
2679
|
-
return false;
|
2680
|
-
}
|
2681
|
-
if (link.pathname + link.search === document.location.pathname + document.location.search) {
|
2682
|
-
return false;
|
2683
|
-
}
|
2684
|
-
const turboMethod = link.getAttribute("data-turbo-method");
|
2685
|
-
if (turboMethod && turboMethod !== "get") {
|
2686
|
-
return false;
|
2687
|
-
}
|
2688
|
-
if (targetsIframe(link)) {
|
2689
|
-
return false;
|
2690
|
-
}
|
2691
|
-
const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
|
2692
|
-
if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false") {
|
2693
|
-
return false;
|
2694
|
-
}
|
2662
|
+
if (!href) return false;
|
2663
|
+
if (unfetchableLink(link)) return false;
|
2664
|
+
if (linkToTheSamePage(link)) return false;
|
2665
|
+
if (linkOptsOut(link)) return false;
|
2666
|
+
if (nonSafeLink(link)) return false;
|
2667
|
+
if (eventPrevented(link)) return false;
|
2695
2668
|
return true;
|
2696
2669
|
}
|
2697
2670
|
}
|
2698
2671
|
|
2699
|
-
const
|
2672
|
+
const unfetchableLink = link => link.origin !== document.location.origin || ![ "http:", "https:" ].includes(link.protocol) || link.hasAttribute("target");
|
2673
|
+
|
2674
|
+
const linkToTheSamePage = link => link.pathname + link.search === document.location.pathname + document.location.search || link.href.startsWith("#");
|
2675
|
+
|
2676
|
+
const linkOptsOut = link => {
|
2677
|
+
if (link.getAttribute("data-turbo-prefetch") === "false") return true;
|
2678
|
+
if (link.getAttribute("data-turbo") === "false") return true;
|
2679
|
+
const turboPrefetchParent = findClosestRecursively(link, "[data-turbo-prefetch]");
|
2680
|
+
if (turboPrefetchParent && turboPrefetchParent.getAttribute("data-turbo-prefetch") === "false") return true;
|
2681
|
+
return false;
|
2682
|
+
};
|
2683
|
+
|
2684
|
+
const nonSafeLink = link => {
|
2685
|
+
const turboMethod = link.getAttribute("data-turbo-method");
|
2686
|
+
if (turboMethod && turboMethod.toLowerCase() !== "get") return true;
|
2687
|
+
if (isUJS(link)) return true;
|
2688
|
+
if (link.hasAttribute("data-turbo-confirm")) return true;
|
2689
|
+
if (link.hasAttribute("data-turbo-stream")) return true;
|
2690
|
+
return false;
|
2691
|
+
};
|
2692
|
+
|
2693
|
+
const isUJS = link => link.hasAttribute("data-remote") || link.hasAttribute("data-behavior") || link.hasAttribute("data-confirm") || link.hasAttribute("data-method");
|
2694
|
+
|
2695
|
+
const eventPrevented = link => {
|
2696
|
+
const event = dispatch("turbo:before-prefetch", {
|
2697
|
+
target: link,
|
2698
|
+
cancelable: true
|
2699
|
+
});
|
2700
|
+
return event.defaultPrevented;
|
2701
|
+
};
|
2700
2702
|
|
2701
2703
|
class Navigator {
|
2702
2704
|
constructor(delegate) {
|
@@ -3816,7 +3818,6 @@ class MorphRenderer extends PageRenderer {
|
|
3816
3818
|
#morphElements(currentElement, newElement, morphStyle = "outerHTML") {
|
3817
3819
|
this.isMorphingTurboFrame = this.#isFrameReloadedWithMorph(currentElement);
|
3818
3820
|
Idiomorph.morph(currentElement, newElement, {
|
3819
|
-
ignoreActiveValue: true,
|
3820
3821
|
morphStyle: morphStyle,
|
3821
3822
|
callbacks: {
|
3822
3823
|
beforeNodeAdded: this.#shouldAddElement,
|
@@ -4145,9 +4146,9 @@ class Session {
|
|
4145
4146
|
refresh(url, requestId) {
|
4146
4147
|
const isRecentRequest = requestId && this.recentRequests.has(requestId);
|
4147
4148
|
if (!isRecentRequest) {
|
4148
|
-
this.cache.exemptPageFromPreview();
|
4149
4149
|
this.visit(url, {
|
4150
|
-
action: "replace"
|
4150
|
+
action: "replace",
|
4151
|
+
shouldCacheSnapshot: false
|
4151
4152
|
});
|
4152
4153
|
}
|
4153
4154
|
}
|