Skip to content

Commit 1757b54

Browse files
committed
Fetch latest changes to turbo-offline
1 parent 13377ac commit 1757b54

9 files changed

Lines changed: 623 additions & 176 deletions

app/assets/javascripts/turbo-offline-umd.js

Lines changed: 276 additions & 71 deletions
Large diffs are not rendered by default.

app/assets/javascripts/turbo-offline-umd.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/javascripts/turbo-offline-umd.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/javascripts/turbo-offline.js

Lines changed: 281 additions & 72 deletions
Large diffs are not rendered by default.

app/assets/javascripts/turbo-offline.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/javascripts/turbo-offline.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/javascripts/turbo.js

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
2-
Turbo 8.0.20
3-
Copyright © 2025 37signals LLC
2+
Turbo 8.0.23
3+
Copyright © 2026 37signals LLC
44
*/
55
const FrameLoadingStyle = {
66
eager: "eager",
@@ -313,6 +313,10 @@ function findClosestRecursively(element, selector) {
313313
}
314314
}
315315

316+
function elementIsStylesheet(element) {
317+
return element.localName === "style" || element.localName === "link" && element.relList.contains("stylesheet");
318+
}
319+
316320
function elementIsFocusable(element) {
317321
const inertDisabledOrHidden = "[inert], :disabled, [hidden], details:not([open]), dialog:not([open])";
318322
return !!element && element.closest(inertDisabledOrHidden) == null && typeof element.focus == "function";
@@ -2589,11 +2593,6 @@ function elementIsNoscript(element) {
25892593
return tagName == "noscript";
25902594
}
25912595

2592-
function elementIsStylesheet(element) {
2593-
const tagName = element.localName;
2594-
return tagName == "style" || tagName == "link" && element.getAttribute("rel") == "stylesheet";
2595-
}
2596-
25972596
function elementIsMetaElementWithName(element, name) {
25982597
const tagName = element.localName;
25992598
return tagName == "meta" && element.getAttribute("name") == name;
@@ -2634,7 +2633,11 @@ class PageSnapshot extends Snapshot {
26342633
clonedPasswordInput.value = "";
26352634
}
26362635
for (const clonedNoscriptElement of clonedElement.querySelectorAll("noscript")) {
2637-
clonedNoscriptElement.remove();
2636+
for (const child of [ ...clonedNoscriptElement.children ]) {
2637+
if (elementIsStylesheet(child)) {
2638+
child.remove();
2639+
}
2640+
}
26382641
}
26392642
return new PageSnapshot(this.documentElement, clonedElement, this.headSnapshot);
26402643
}
@@ -3985,12 +3988,16 @@ class PageRenderer extends Renderer {
39853988
}
39863989
activateNewBody() {
39873990
document.adoptNode(this.newElement);
3988-
this.removeNoscriptElements();
3991+
this.deactivateNoscriptStylesheetElements();
39893992
this.activateNewBodyScriptElements();
39903993
}
3991-
removeNoscriptElements() {
3994+
deactivateNoscriptStylesheetElements() {
39923995
for (const noscriptElement of this.newElement.querySelectorAll("noscript")) {
3993-
noscriptElement.remove();
3996+
for (const child of [ ...noscriptElement.children ]) {
3997+
if (elementIsStylesheet(child)) {
3998+
child.remove();
3999+
}
4000+
}
39944001
}
39954002
}
39964003
activateNewBodyScriptElements() {
@@ -4572,13 +4579,14 @@ const deprecatedLocationPropertyDescriptors = {
45724579

45734580
class Offline {
45744581
serviceWorker;
4575-
async start(url = "/service-worker.js", {scope: scope = "/", type: type = "classic", native: native = true} = {}) {
4582+
async start(url = "/service-worker.js", {scope: scope = "/", type: type = "classic", native: native = true, preload: preload} = {}) {
45764583
if (!("serviceWorker" in navigator)) {
45774584
console.warn("Service Worker not available.");
45784585
return;
45794586
}
45804587
if (native) this.#setUserAgentCookie();
45814588
await this.#domReady();
4589+
const needsPreloading = preload && !navigator.serviceWorker.controller;
45824590
this.#checkExistingController(navigator.serviceWorker.controller, url);
45834591
try {
45844592
const registration = await navigator.serviceWorker.register(url, {
@@ -4588,6 +4596,9 @@ class Offline {
45884596
const registered = registration.active || registration.waiting || registration.installing;
45894597
this.#checkExistingController(registered, url);
45904598
this.serviceWorker = registered;
4599+
if (needsPreloading) {
4600+
this.#preloadWhenReady(preload);
4601+
}
45914602
return registration;
45924603
} catch (error) {
45934604
console.error(error);
@@ -4602,6 +4613,28 @@ class Offline {
46024613
console.warn(`Expected service worker script ${url} but found ${controller.scriptURL}. ` + `This may indicate multiple service workers or a cached version.`);
46034614
}
46044615
}
4616+
async clearCache() {
4617+
const registration = await (navigator.serviceWorker?.ready);
4618+
registration?.active?.postMessage({
4619+
action: "clearCache"
4620+
});
4621+
}
4622+
#preloadWhenReady(pattern) {
4623+
navigator.serviceWorker.addEventListener("controllerchange", (() => {
4624+
this.#preloadResources(pattern);
4625+
}), {
4626+
once: true
4627+
});
4628+
}
4629+
#preloadResources(pattern) {
4630+
const urls = performance.getEntriesByType("resource").map((entry => entry.name)).filter((url => pattern.test(url)));
4631+
navigator.serviceWorker.controller.postMessage({
4632+
action: "preloadResources",
4633+
params: {
4634+
urls: urls
4635+
}
4636+
});
4637+
}
46054638
#domReady() {
46064639
return new Promise((resolve => {
46074640
if (document.readyState !== "complete") {
@@ -4617,7 +4650,7 @@ const offline = new Offline;
46174650

46184651
const session = new Session(recentRequests);
46194652

4620-
const {cache: cache, navigator: navigator} = session;
4653+
const {cache: cache, navigator: sessionNavigator} = session;
46214654

46224655
function start() {
46234656
session.start();
@@ -4668,15 +4701,15 @@ function morphTurboFrameElements(currentFrame, newFrame) {
46684701

46694702
var Turbo = Object.freeze({
46704703
__proto__: null,
4671-
navigator: navigator,
4672-
session: session,
4673-
cache: cache,
46744704
PageRenderer: PageRenderer,
46754705
PageSnapshot: PageSnapshot,
46764706
FrameRenderer: FrameRenderer,
46774707
fetch: fetchWithTurboHeaders,
46784708
config: config,
46794709
offline: offline,
4710+
session: session,
4711+
cache: cache,
4712+
navigator: sessionNavigator,
46804713
start: start,
46814714
registerAdapter: registerAdapter,
46824715
visit: visit,
@@ -5418,7 +5451,7 @@ var Turbo$1 = Object.freeze({
54185451
morphChildren: morphChildren,
54195452
morphElements: morphElements,
54205453
morphTurboFrameElements: morphTurboFrameElements,
5421-
navigator: navigator$1,
5454+
navigator: sessionNavigator,
54225455
offline: offline,
54235456
registerAdapter: registerAdapter,
54245457
renderStreamMessage: renderStreamMessage,

app/assets/javascripts/turbo.min.js

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/assets/javascripts/turbo.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)