turbo-rails 0.5.3 → 0.5.4
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 +4 -4
- data/README.md +7 -1
- data/app/assets/javascripts/turbo.js +243 -129
- data/app/helpers/turbo/streams_helper.rb +2 -2
- data/lib/install/turbo_with_webpacker.rb +1 -2
- data/lib/turbo/engine.rb +1 -1
- data/lib/turbo/version.rb +1 -1
- metadata +7 -173
- data/.github/workflows/ci.yml +0 -30
- data/.gitignore +0 -2
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -147
- data/package.json +0 -47
- data/rollup.config.js +0 -23
- data/test/drive/drive_helper_test.rb +0 -8
- data/test/dummy/.babelrc +0 -18
- data/test/dummy/.gitignore +0 -3
- data/test/dummy/.postcssrc.yml +0 -3
- data/test/dummy/Rakefile +0 -6
- data/test/dummy/app/assets/config/manifest.js +0 -2
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +0 -15
- data/test/dummy/app/assets/stylesheets/scaffold.css +0 -80
- data/test/dummy/app/channels/application_cable/channel.rb +0 -4
- data/test/dummy/app/channels/application_cable/connection.rb +0 -4
- data/test/dummy/app/controllers/application_controller.rb +0 -2
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/controllers/messages_controller.rb +0 -12
- data/test/dummy/app/controllers/trays_controller.rb +0 -17
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/javascript/packs/application.js +0 -0
- data/test/dummy/app/jobs/application_job.rb +0 -2
- data/test/dummy/app/mailboxes/application_mailbox.rb +0 -2
- data/test/dummy/app/mailboxes/messages_mailbox.rb +0 -4
- data/test/dummy/app/mailers/application_mailer.rb +0 -4
- data/test/dummy/app/models/application_record.rb +0 -3
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/message.rb +0 -29
- data/test/dummy/app/views/layouts/application.html.erb +0 -14
- data/test/dummy/app/views/layouts/mailer.html.erb +0 -13
- data/test/dummy/app/views/layouts/mailer.text.erb +0 -1
- data/test/dummy/app/views/messages/_message.html.erb +0 -1
- data/test/dummy/app/views/messages/_message.turbo_stream.erb +0 -1
- data/test/dummy/app/views/messages/show.turbo_stream.erb +0 -9
- data/test/dummy/app/views/trays/index.html.erb +0 -3
- data/test/dummy/app/views/trays/show.html.erb +0 -3
- data/test/dummy/bin/bundle +0 -3
- data/test/dummy/bin/rails +0 -4
- data/test/dummy/bin/rake +0 -4
- data/test/dummy/bin/setup +0 -36
- data/test/dummy/bin/update +0 -31
- data/test/dummy/bin/yarn +0 -11
- data/test/dummy/config.ru +0 -5
- data/test/dummy/config/application.rb +0 -22
- data/test/dummy/config/boot.rb +0 -5
- data/test/dummy/config/cable.yml +0 -10
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -34
- data/test/dummy/config/environments/production.rb +0 -96
- data/test/dummy/config/environments/test.rb +0 -38
- data/test/dummy/config/initializers/application_controller_renderer.rb +0 -8
- data/test/dummy/config/initializers/assets.rb +0 -14
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/content_security_policy.rb +0 -22
- data/test/dummy/config/initializers/cookies_serializer.rb +0 -5
- data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
- data/test/dummy/config/initializers/inflections.rb +0 -16
- data/test/dummy/config/initializers/mime_types.rb +0 -4
- data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/test/dummy/config/locales/en.yml +0 -33
- data/test/dummy/config/puma.rb +0 -34
- data/test/dummy/config/routes.rb +0 -4
- data/test/dummy/config/spring.rb +0 -6
- data/test/dummy/config/webpack/development.js +0 -3
- data/test/dummy/config/webpack/environment.js +0 -3
- data/test/dummy/config/webpack/production.js +0 -3
- data/test/dummy/config/webpack/test.js +0 -3
- data/test/dummy/config/webpacker.yml +0 -65
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +0 -67
- data/test/dummy/public/422.html +0 -67
- data/test/dummy/public/500.html +0 -66
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/frames/frame_request_controller_test.rb +0 -21
- data/test/frames/frames_helper_test.rb +0 -21
- data/test/native/navigation_controller_test.rb +0 -42
- data/test/streams/broadcastable_test.rb +0 -80
- data/test/streams/streams_channel_test.rb +0 -111
- data/test/streams/streams_controller_test.rb +0 -29
- data/test/turbo_test.rb +0 -10
- data/turbo-rails.gemspec +0 -17
- data/yarn.lock +0 -283
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5ecf40714a59522c484900685826a53c6c5396d7f4cbe02583278e657db5d999
|
|
4
|
+
data.tar.gz: 418e450bb22bb03b92605b47f2181ba9ebdceae4e9cf4337c124cf4c6598e5fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de89fcedf66a77fc03c984ce128cf088194c13969417e978e95755b94cb8a04b852269ff39196abf2ca7d2da91738cbf4d5f06f958d150eebc2fe53c38865664
|
|
7
|
+
data.tar.gz: 0223bc0f45e495659673f7c5bdbf03cefa8645f8a5781e372753a034007524a06828d5db37dd0eeaad99a9b6036598e983abdf453f168513f4d2237595bb009d
|
data/README.md
CHANGED
|
@@ -40,8 +40,14 @@ The JavaScript for Turbo can either be run through the asset pipeline, which is
|
|
|
40
40
|
|
|
41
41
|
Running `turbo:install` will install through NPM if Webpacker is installed in the application. Otherwise the asset pipeline version is used.
|
|
42
42
|
|
|
43
|
-
If you're using Webpack and need to use either the cable consumer or the Turbo instance, you can import [`Turbo`](https://turbo.hotwire.dev/reference/drive) and/or [`cable`](https://github.com/hotwired/turbo-rails/blob/
|
|
43
|
+
If you're using Webpack and need to use either the cable consumer or the Turbo instance, you can import [`Turbo`](https://turbo.hotwire.dev/reference/drive) and/or [`cable`](https://github.com/hotwired/turbo-rails/blob/main/app/javascript/turbo/cable.js) (`import { Turbo, cable } from "@hotwired/turbo-rails"`), but ensure that your application actually *uses* the members it `import`s when using this style (see [turbo-rails#48](https://github.com/hotwired/turbo-rails/issues/48)).
|
|
44
44
|
|
|
45
|
+
If you're using a [native adapter](https://turbo.hotwire.dev/handbook/native), you'll need to assign `window.Turbo`, even if it's not used for anything else:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import { Turbo } from "@hotwired/turbo-rails"
|
|
49
|
+
window.Turbo = Turbo
|
|
50
|
+
```
|
|
45
51
|
|
|
46
52
|
## Usage
|
|
47
53
|
|
|
@@ -41,6 +41,97 @@ function clickCaptured(event) {
|
|
|
41
41
|
});
|
|
42
42
|
})();
|
|
43
43
|
|
|
44
|
+
var FrameLoadingStyle;
|
|
45
|
+
|
|
46
|
+
(function(FrameLoadingStyle) {
|
|
47
|
+
FrameLoadingStyle["eager"] = "eager";
|
|
48
|
+
FrameLoadingStyle["lazy"] = "lazy";
|
|
49
|
+
})(FrameLoadingStyle || (FrameLoadingStyle = {}));
|
|
50
|
+
|
|
51
|
+
class FrameElement extends HTMLElement {
|
|
52
|
+
constructor() {
|
|
53
|
+
super();
|
|
54
|
+
this.loaded = Promise.resolve();
|
|
55
|
+
this.delegate = new FrameElement.delegateConstructor(this);
|
|
56
|
+
}
|
|
57
|
+
static get observedAttributes() {
|
|
58
|
+
return [ "loading", "src" ];
|
|
59
|
+
}
|
|
60
|
+
connectedCallback() {
|
|
61
|
+
this.delegate.connect();
|
|
62
|
+
}
|
|
63
|
+
disconnectedCallback() {
|
|
64
|
+
this.delegate.disconnect();
|
|
65
|
+
}
|
|
66
|
+
attributeChangedCallback(name) {
|
|
67
|
+
if (name == "loading") {
|
|
68
|
+
this.delegate.loadingStyleChanged();
|
|
69
|
+
} else if (name == "src") {
|
|
70
|
+
this.delegate.sourceURLChanged();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
get src() {
|
|
74
|
+
return this.getAttribute("src");
|
|
75
|
+
}
|
|
76
|
+
set src(value) {
|
|
77
|
+
if (value) {
|
|
78
|
+
this.setAttribute("src", value);
|
|
79
|
+
} else {
|
|
80
|
+
this.removeAttribute("src");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
get loading() {
|
|
84
|
+
return frameLoadingStyleFromString(this.getAttribute("loading") || "");
|
|
85
|
+
}
|
|
86
|
+
set loading(value) {
|
|
87
|
+
if (value) {
|
|
88
|
+
this.setAttribute("loading", value);
|
|
89
|
+
} else {
|
|
90
|
+
this.removeAttribute("loading");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
get disabled() {
|
|
94
|
+
return this.hasAttribute("disabled");
|
|
95
|
+
}
|
|
96
|
+
set disabled(value) {
|
|
97
|
+
if (value) {
|
|
98
|
+
this.setAttribute("disabled", "");
|
|
99
|
+
} else {
|
|
100
|
+
this.removeAttribute("disabled");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
get autoscroll() {
|
|
104
|
+
return this.hasAttribute("autoscroll");
|
|
105
|
+
}
|
|
106
|
+
set autoscroll(value) {
|
|
107
|
+
if (value) {
|
|
108
|
+
this.setAttribute("autoscroll", "");
|
|
109
|
+
} else {
|
|
110
|
+
this.removeAttribute("autoscroll");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
get complete() {
|
|
114
|
+
return !this.delegate.isLoading;
|
|
115
|
+
}
|
|
116
|
+
get isActive() {
|
|
117
|
+
return this.ownerDocument === document && !this.isPreview;
|
|
118
|
+
}
|
|
119
|
+
get isPreview() {
|
|
120
|
+
var _a, _b;
|
|
121
|
+
return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function frameLoadingStyleFromString(style) {
|
|
126
|
+
switch (style.toLowerCase()) {
|
|
127
|
+
case "lazy":
|
|
128
|
+
return FrameLoadingStyle.lazy;
|
|
129
|
+
|
|
130
|
+
default:
|
|
131
|
+
return FrameLoadingStyle.eager;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
44
135
|
class Location {
|
|
45
136
|
constructor(url) {
|
|
46
137
|
const linkWithAnchor = document.createElement("a");
|
|
@@ -142,7 +233,7 @@ class FetchResponse {
|
|
|
142
233
|
return Location.wrap(this.response.url);
|
|
143
234
|
}
|
|
144
235
|
get isHTML() {
|
|
145
|
-
return this.contentType && this.contentType.match(/^text\/html
|
|
236
|
+
return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/);
|
|
146
237
|
}
|
|
147
238
|
get statusCode() {
|
|
148
239
|
return this.response.status;
|
|
@@ -336,27 +427,30 @@ class FetchRequest {
|
|
|
336
427
|
}
|
|
337
428
|
}
|
|
338
429
|
|
|
339
|
-
class
|
|
430
|
+
class AppearanceObserver {
|
|
340
431
|
constructor(delegate, element) {
|
|
341
|
-
this.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
event.preventDefault();
|
|
347
|
-
event.stopImmediatePropagation();
|
|
348
|
-
this.delegate.formSubmissionIntercepted(form, submitter);
|
|
349
|
-
}
|
|
432
|
+
this.started = false;
|
|
433
|
+
this.intersect = entries => {
|
|
434
|
+
const lastEntry = entries.slice(-1)[0];
|
|
435
|
+
if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) {
|
|
436
|
+
this.delegate.elementAppearedInViewport(this.element);
|
|
350
437
|
}
|
|
351
438
|
};
|
|
352
439
|
this.delegate = delegate;
|
|
353
440
|
this.element = element;
|
|
441
|
+
this.intersectionObserver = new IntersectionObserver(this.intersect);
|
|
354
442
|
}
|
|
355
443
|
start() {
|
|
356
|
-
|
|
444
|
+
if (!this.started) {
|
|
445
|
+
this.started = true;
|
|
446
|
+
this.intersectionObserver.observe(this.element);
|
|
447
|
+
}
|
|
357
448
|
}
|
|
358
449
|
stop() {
|
|
359
|
-
|
|
450
|
+
if (this.started) {
|
|
451
|
+
this.started = false;
|
|
452
|
+
this.intersectionObserver.unobserve(this.element);
|
|
453
|
+
}
|
|
360
454
|
}
|
|
361
455
|
}
|
|
362
456
|
|
|
@@ -437,7 +531,7 @@ class FormSubmission {
|
|
|
437
531
|
requestSucceededWithResponse(request, response) {
|
|
438
532
|
if (response.clientError || response.serverError) {
|
|
439
533
|
this.delegate.formSubmissionFailedWithResponse(this, response);
|
|
440
|
-
} else if (this.requestMustRedirect(request) &&
|
|
534
|
+
} else if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) {
|
|
441
535
|
const error = new Error("Form responses must redirect to another location");
|
|
442
536
|
this.delegate.formSubmissionErrored(this, error);
|
|
443
537
|
} else {
|
|
@@ -504,6 +598,34 @@ function getMetaContent(name) {
|
|
|
504
598
|
return element && element.content;
|
|
505
599
|
}
|
|
506
600
|
|
|
601
|
+
function responseSucceededWithoutRedirect(response) {
|
|
602
|
+
return response.statusCode == 200 && !response.redirected;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
class FormInterceptor {
|
|
606
|
+
constructor(delegate, element) {
|
|
607
|
+
this.submitBubbled = event => {
|
|
608
|
+
if (event.target instanceof HTMLFormElement) {
|
|
609
|
+
const form = event.target;
|
|
610
|
+
const submitter = event.submitter || undefined;
|
|
611
|
+
if (this.delegate.shouldInterceptFormSubmission(form, submitter)) {
|
|
612
|
+
event.preventDefault();
|
|
613
|
+
event.stopImmediatePropagation();
|
|
614
|
+
this.delegate.formSubmissionIntercepted(form, submitter);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
this.delegate = delegate;
|
|
619
|
+
this.element = element;
|
|
620
|
+
}
|
|
621
|
+
start() {
|
|
622
|
+
this.element.addEventListener("submit", this.submitBubbled);
|
|
623
|
+
}
|
|
624
|
+
stop() {
|
|
625
|
+
this.element.removeEventListener("submit", this.submitBubbled);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
507
629
|
class LinkInterceptor {
|
|
508
630
|
constructor(delegate, element) {
|
|
509
631
|
this.clickBubbled = event => {
|
|
@@ -549,17 +671,61 @@ class FrameController {
|
|
|
549
671
|
constructor(element) {
|
|
550
672
|
this.resolveVisitPromise = () => {};
|
|
551
673
|
this.element = element;
|
|
674
|
+
this.appearanceObserver = new AppearanceObserver(this, this.element);
|
|
552
675
|
this.linkInterceptor = new LinkInterceptor(this, this.element);
|
|
553
676
|
this.formInterceptor = new FormInterceptor(this, this.element);
|
|
554
677
|
}
|
|
555
678
|
connect() {
|
|
679
|
+
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
680
|
+
this.appearanceObserver.start();
|
|
681
|
+
}
|
|
556
682
|
this.linkInterceptor.start();
|
|
557
683
|
this.formInterceptor.start();
|
|
558
684
|
}
|
|
559
685
|
disconnect() {
|
|
686
|
+
this.appearanceObserver.stop();
|
|
560
687
|
this.linkInterceptor.stop();
|
|
561
688
|
this.formInterceptor.stop();
|
|
562
689
|
}
|
|
690
|
+
sourceURLChanged() {
|
|
691
|
+
if (this.loadingStyle == FrameLoadingStyle.eager) {
|
|
692
|
+
this.loadSourceURL();
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
loadingStyleChanged() {
|
|
696
|
+
if (this.loadingStyle == FrameLoadingStyle.lazy) {
|
|
697
|
+
this.appearanceObserver.start();
|
|
698
|
+
} else {
|
|
699
|
+
this.appearanceObserver.stop();
|
|
700
|
+
this.loadSourceURL();
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
async loadSourceURL() {
|
|
704
|
+
if (this.isActive && this.sourceURL && this.sourceURL != this.loadingURL) {
|
|
705
|
+
try {
|
|
706
|
+
this.loadingURL = this.sourceURL;
|
|
707
|
+
this.element.loaded = this.visit(this.sourceURL);
|
|
708
|
+
this.appearanceObserver.stop();
|
|
709
|
+
await this.element.loaded;
|
|
710
|
+
} finally {
|
|
711
|
+
delete this.loadingURL;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async loadResponse(response) {
|
|
716
|
+
const fragment = fragmentFromHTML(await response.responseHTML);
|
|
717
|
+
if (fragment) {
|
|
718
|
+
const element = await this.extractForeignFrameElement(fragment);
|
|
719
|
+
await nextAnimationFrame();
|
|
720
|
+
this.loadFrameElement(element);
|
|
721
|
+
this.scrollFrameIntoView(element);
|
|
722
|
+
await nextAnimationFrame();
|
|
723
|
+
this.focusFirstAutofocusableElement();
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
elementAppearedInViewport(element) {
|
|
727
|
+
this.loadSourceURL();
|
|
728
|
+
}
|
|
563
729
|
shouldInterceptLinkClick(element, url) {
|
|
564
730
|
return this.shouldInterceptNavigation(element);
|
|
565
731
|
}
|
|
@@ -580,17 +746,6 @@ class FrameController {
|
|
|
580
746
|
this.formSubmission.start();
|
|
581
747
|
}
|
|
582
748
|
}
|
|
583
|
-
async visit(url) {
|
|
584
|
-
const location = Location.wrap(url);
|
|
585
|
-
const request = new FetchRequest(this, FetchMethod.get, location);
|
|
586
|
-
return new Promise((resolve => {
|
|
587
|
-
this.resolveVisitPromise = () => {
|
|
588
|
-
this.resolveVisitPromise = () => {};
|
|
589
|
-
resolve();
|
|
590
|
-
};
|
|
591
|
-
request.perform();
|
|
592
|
-
}));
|
|
593
|
-
}
|
|
594
749
|
additionalHeadersForRequest(request) {
|
|
595
750
|
return {
|
|
596
751
|
"Turbo-Frame": this.id
|
|
@@ -620,13 +775,24 @@ class FrameController {
|
|
|
620
775
|
formSubmissionStarted(formSubmission) {}
|
|
621
776
|
formSubmissionSucceededWithResponse(formSubmission, response) {
|
|
622
777
|
const frame = this.findFrameElement(formSubmission.formElement);
|
|
623
|
-
frame.
|
|
778
|
+
frame.delegate.loadResponse(response);
|
|
624
779
|
}
|
|
625
780
|
formSubmissionFailedWithResponse(formSubmission, fetchResponse) {
|
|
626
|
-
this.element.
|
|
781
|
+
this.element.delegate.loadResponse(fetchResponse);
|
|
627
782
|
}
|
|
628
783
|
formSubmissionErrored(formSubmission, error) {}
|
|
629
784
|
formSubmissionFinished(formSubmission) {}
|
|
785
|
+
async visit(url) {
|
|
786
|
+
const location = Location.wrap(url);
|
|
787
|
+
const request = new FetchRequest(this, FetchMethod.get, location);
|
|
788
|
+
return new Promise((resolve => {
|
|
789
|
+
this.resolveVisitPromise = () => {
|
|
790
|
+
this.resolveVisitPromise = () => {};
|
|
791
|
+
resolve();
|
|
792
|
+
};
|
|
793
|
+
request.perform();
|
|
794
|
+
}));
|
|
795
|
+
}
|
|
630
796
|
navigateFrame(element, url) {
|
|
631
797
|
const frame = this.findFrameElement(element);
|
|
632
798
|
frame.src = url;
|
|
@@ -636,17 +802,6 @@ class FrameController {
|
|
|
636
802
|
const id = element.getAttribute("data-turbo-frame");
|
|
637
803
|
return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element;
|
|
638
804
|
}
|
|
639
|
-
async loadResponse(response) {
|
|
640
|
-
const fragment = fragmentFromHTML(await response.responseHTML);
|
|
641
|
-
const element = await this.extractForeignFrameElement(fragment);
|
|
642
|
-
if (element) {
|
|
643
|
-
await nextAnimationFrame();
|
|
644
|
-
this.loadFrameElement(element);
|
|
645
|
-
this.scrollFrameIntoView(element);
|
|
646
|
-
await nextAnimationFrame();
|
|
647
|
-
this.focusFirstAutofocusableElement();
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
805
|
async extractForeignFrameElement(container) {
|
|
651
806
|
let element;
|
|
652
807
|
const id = CSS.escape(this.id);
|
|
@@ -657,6 +812,8 @@ class FrameController {
|
|
|
657
812
|
await element.loaded;
|
|
658
813
|
return await this.extractForeignFrameElement(element);
|
|
659
814
|
}
|
|
815
|
+
console.error(`Response has no matching <turbo-frame id="${id}"> element`);
|
|
816
|
+
return new FrameElement;
|
|
660
817
|
}
|
|
661
818
|
loadFrameElement(frameElement) {
|
|
662
819
|
var _a;
|
|
@@ -713,6 +870,18 @@ class FrameController {
|
|
|
713
870
|
get enabled() {
|
|
714
871
|
return !this.element.disabled;
|
|
715
872
|
}
|
|
873
|
+
get sourceURL() {
|
|
874
|
+
return this.element.src;
|
|
875
|
+
}
|
|
876
|
+
get loadingStyle() {
|
|
877
|
+
return this.element.loading;
|
|
878
|
+
}
|
|
879
|
+
get isLoading() {
|
|
880
|
+
return this.formSubmission !== undefined || this.loadingURL !== undefined;
|
|
881
|
+
}
|
|
882
|
+
get isActive() {
|
|
883
|
+
return this.element.isActive;
|
|
884
|
+
}
|
|
716
885
|
}
|
|
717
886
|
|
|
718
887
|
function getFrameElementById(id) {
|
|
@@ -732,9 +901,11 @@ function readScrollLogicalPosition(value, defaultValue) {
|
|
|
732
901
|
}
|
|
733
902
|
}
|
|
734
903
|
|
|
735
|
-
function fragmentFromHTML(html
|
|
736
|
-
|
|
737
|
-
|
|
904
|
+
function fragmentFromHTML(html) {
|
|
905
|
+
if (html) {
|
|
906
|
+
const foreignDocument = document.implementation.createHTMLDocument();
|
|
907
|
+
return foreignDocument.createRange().createContextualFragment(html);
|
|
908
|
+
}
|
|
738
909
|
}
|
|
739
910
|
|
|
740
911
|
function activateElement(element) {
|
|
@@ -746,76 +917,6 @@ function activateElement(element) {
|
|
|
746
917
|
}
|
|
747
918
|
}
|
|
748
919
|
|
|
749
|
-
class FrameElement extends HTMLElement {
|
|
750
|
-
constructor() {
|
|
751
|
-
super();
|
|
752
|
-
this.controller = new FrameController(this);
|
|
753
|
-
}
|
|
754
|
-
static get observedAttributes() {
|
|
755
|
-
return [ "src" ];
|
|
756
|
-
}
|
|
757
|
-
connectedCallback() {
|
|
758
|
-
this.controller.connect();
|
|
759
|
-
}
|
|
760
|
-
disconnectedCallback() {
|
|
761
|
-
this.controller.disconnect();
|
|
762
|
-
}
|
|
763
|
-
attributeChangedCallback() {
|
|
764
|
-
if (this.src && this.isActive) {
|
|
765
|
-
const value = this.controller.visit(this.src);
|
|
766
|
-
Object.defineProperty(this, "loaded", {
|
|
767
|
-
value: value,
|
|
768
|
-
configurable: true
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
formSubmissionIntercepted(element, submitter) {
|
|
773
|
-
this.controller.formSubmissionIntercepted(element, submitter);
|
|
774
|
-
}
|
|
775
|
-
get src() {
|
|
776
|
-
return this.getAttribute("src");
|
|
777
|
-
}
|
|
778
|
-
set src(value) {
|
|
779
|
-
if (value) {
|
|
780
|
-
this.setAttribute("src", value);
|
|
781
|
-
} else {
|
|
782
|
-
this.removeAttribute("src");
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
get loaded() {
|
|
786
|
-
return Promise.resolve(undefined);
|
|
787
|
-
}
|
|
788
|
-
get disabled() {
|
|
789
|
-
return this.hasAttribute("disabled");
|
|
790
|
-
}
|
|
791
|
-
set disabled(value) {
|
|
792
|
-
if (value) {
|
|
793
|
-
this.setAttribute("disabled", "");
|
|
794
|
-
} else {
|
|
795
|
-
this.removeAttribute("disabled");
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
get autoscroll() {
|
|
799
|
-
return this.hasAttribute("autoscroll");
|
|
800
|
-
}
|
|
801
|
-
set autoscroll(value) {
|
|
802
|
-
if (value) {
|
|
803
|
-
this.setAttribute("autoscroll", "");
|
|
804
|
-
} else {
|
|
805
|
-
this.removeAttribute("autoscroll");
|
|
806
|
-
}
|
|
807
|
-
}
|
|
808
|
-
get isActive() {
|
|
809
|
-
return this.ownerDocument === document && !this.isPreview;
|
|
810
|
-
}
|
|
811
|
-
get isPreview() {
|
|
812
|
-
var _a, _b;
|
|
813
|
-
return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview");
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
customElements.define("turbo-frame", FrameElement);
|
|
818
|
-
|
|
819
920
|
const StreamActions = {
|
|
820
921
|
append() {
|
|
821
922
|
var _a;
|
|
@@ -912,6 +1013,10 @@ class StreamElement extends HTMLElement {
|
|
|
912
1013
|
}
|
|
913
1014
|
}
|
|
914
1015
|
|
|
1016
|
+
FrameElement.delegateConstructor = FrameController;
|
|
1017
|
+
|
|
1018
|
+
customElements.define("turbo-frame", FrameElement);
|
|
1019
|
+
|
|
915
1020
|
customElements.define("turbo-stream", StreamElement);
|
|
916
1021
|
|
|
917
1022
|
(() => {
|
|
@@ -1633,7 +1738,7 @@ class FrameRedirector {
|
|
|
1633
1738
|
formSubmissionIntercepted(element, submitter) {
|
|
1634
1739
|
const frame = this.findFrameElement(element);
|
|
1635
1740
|
if (frame) {
|
|
1636
|
-
frame.formSubmissionIntercepted(element, submitter);
|
|
1741
|
+
frame.delegate.formSubmissionIntercepted(element, submitter);
|
|
1637
1742
|
}
|
|
1638
1743
|
}
|
|
1639
1744
|
shouldRedirect(element, submitter) {
|
|
@@ -1677,8 +1782,6 @@ class History {
|
|
|
1677
1782
|
}
|
|
1678
1783
|
start() {
|
|
1679
1784
|
if (!this.started) {
|
|
1680
|
-
this.previousScrollRestoration = history.scrollRestoration;
|
|
1681
|
-
history.scrollRestoration = "manual";
|
|
1682
1785
|
addEventListener("popstate", this.onPopState, false);
|
|
1683
1786
|
addEventListener("load", this.onPageLoad, false);
|
|
1684
1787
|
this.started = true;
|
|
@@ -1686,9 +1789,7 @@ class History {
|
|
|
1686
1789
|
}
|
|
1687
1790
|
}
|
|
1688
1791
|
stop() {
|
|
1689
|
-
var _a;
|
|
1690
1792
|
if (this.started) {
|
|
1691
|
-
history.scrollRestoration = (_a = this.previousScrollRestoration) !== null && _a !== void 0 ? _a : "auto";
|
|
1692
1793
|
removeEventListener("popstate", this.onPopState, false);
|
|
1693
1794
|
removeEventListener("load", this.onPageLoad, false);
|
|
1694
1795
|
this.started = false;
|
|
@@ -1718,6 +1819,19 @@ class History {
|
|
|
1718
1819
|
const restorationData = this.restorationData[restorationIdentifier];
|
|
1719
1820
|
this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData);
|
|
1720
1821
|
}
|
|
1822
|
+
assumeControlOfScrollRestoration() {
|
|
1823
|
+
var _a;
|
|
1824
|
+
if (!this.previousScrollRestoration) {
|
|
1825
|
+
this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto";
|
|
1826
|
+
history.scrollRestoration = "manual";
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
relinquishControlOfScrollRestoration() {
|
|
1830
|
+
if (this.previousScrollRestoration) {
|
|
1831
|
+
history.scrollRestoration = this.previousScrollRestoration;
|
|
1832
|
+
delete this.previousScrollRestoration;
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1721
1835
|
shouldHandlePopState() {
|
|
1722
1836
|
return this.pageIsLoaded();
|
|
1723
1837
|
}
|
|
@@ -1864,7 +1978,6 @@ var PageStage;
|
|
|
1864
1978
|
PageStage[PageStage["loading"] = 1] = "loading";
|
|
1865
1979
|
PageStage[PageStage["interactive"] = 2] = "interactive";
|
|
1866
1980
|
PageStage[PageStage["complete"] = 3] = "complete";
|
|
1867
|
-
PageStage[PageStage["invalidated"] = 4] = "invalidated";
|
|
1868
1981
|
})(PageStage || (PageStage = {}));
|
|
1869
1982
|
|
|
1870
1983
|
class PageObserver {
|
|
@@ -1879,6 +1992,9 @@ class PageObserver {
|
|
|
1879
1992
|
this.pageIsComplete();
|
|
1880
1993
|
}
|
|
1881
1994
|
};
|
|
1995
|
+
this.pageWillUnload = () => {
|
|
1996
|
+
this.delegate.pageWillUnload();
|
|
1997
|
+
};
|
|
1882
1998
|
this.delegate = delegate;
|
|
1883
1999
|
}
|
|
1884
2000
|
start() {
|
|
@@ -1887,21 +2003,17 @@ class PageObserver {
|
|
|
1887
2003
|
this.stage = PageStage.loading;
|
|
1888
2004
|
}
|
|
1889
2005
|
document.addEventListener("readystatechange", this.interpretReadyState, false);
|
|
2006
|
+
addEventListener("pagehide", this.pageWillUnload, false);
|
|
1890
2007
|
this.started = true;
|
|
1891
2008
|
}
|
|
1892
2009
|
}
|
|
1893
2010
|
stop() {
|
|
1894
2011
|
if (this.started) {
|
|
1895
2012
|
document.removeEventListener("readystatechange", this.interpretReadyState, false);
|
|
2013
|
+
removeEventListener("pagehide", this.pageWillUnload, false);
|
|
1896
2014
|
this.started = false;
|
|
1897
2015
|
}
|
|
1898
2016
|
}
|
|
1899
|
-
invalidate() {
|
|
1900
|
-
if (this.stage != PageStage.invalidated) {
|
|
1901
|
-
this.stage = PageStage.invalidated;
|
|
1902
|
-
this.delegate.pageInvalidated();
|
|
1903
|
-
}
|
|
1904
|
-
}
|
|
1905
2017
|
pageIsInteractive() {
|
|
1906
2018
|
if (this.stage == PageStage.loading) {
|
|
1907
2019
|
this.stage = PageStage.interactive;
|
|
@@ -1991,7 +2103,7 @@ class StreamObserver {
|
|
|
1991
2103
|
const fetchOptions = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchOptions;
|
|
1992
2104
|
if (fetchOptions) {
|
|
1993
2105
|
const {headers: headers} = fetchOptions;
|
|
1994
|
-
headers.Accept = [ "text/
|
|
2106
|
+
headers.Accept = [ "text/vnd.turbo-stream.html", headers.Accept ].join(", ");
|
|
1995
2107
|
}
|
|
1996
2108
|
};
|
|
1997
2109
|
this.inspectFetchResponse = event => {
|
|
@@ -2059,7 +2171,7 @@ function fetchResponseFromEvent(event) {
|
|
|
2059
2171
|
function fetchResponseIsStream(response) {
|
|
2060
2172
|
var _a;
|
|
2061
2173
|
const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : "";
|
|
2062
|
-
return
|
|
2174
|
+
return /^text\/vnd\.turbo-stream\.html\b/.test(contentType);
|
|
2063
2175
|
}
|
|
2064
2176
|
|
|
2065
2177
|
function isAction(action) {
|
|
@@ -2518,9 +2630,11 @@ class Session {
|
|
|
2518
2630
|
this.view.lastRenderedLocation = this.location;
|
|
2519
2631
|
this.notifyApplicationAfterPageLoad();
|
|
2520
2632
|
}
|
|
2521
|
-
pageLoaded() {
|
|
2522
|
-
|
|
2523
|
-
|
|
2633
|
+
pageLoaded() {
|
|
2634
|
+
this.history.assumeControlOfScrollRestoration();
|
|
2635
|
+
}
|
|
2636
|
+
pageWillUnload() {
|
|
2637
|
+
this.history.relinquishControlOfScrollRestoration();
|
|
2524
2638
|
}
|
|
2525
2639
|
receivedMessageFromStream(message) {
|
|
2526
2640
|
this.renderStreamMessage(message);
|
|
@@ -2533,7 +2647,7 @@ class Session {
|
|
|
2533
2647
|
this.notifyApplicationAfterRender();
|
|
2534
2648
|
}
|
|
2535
2649
|
viewInvalidated() {
|
|
2536
|
-
this.
|
|
2650
|
+
this.adapter.pageInvalidated();
|
|
2537
2651
|
}
|
|
2538
2652
|
viewWillCacheSnapshot() {
|
|
2539
2653
|
this.notifyApplicationBeforeCachingSnapshot();
|