Skip to content

Commit f62a337

Browse files
authored
update hash on mouseleave and before reload (#631)
* update hash on mouseleave and before reload * update comment * save name as well * simplify * fix
1 parent 1e54877 commit f62a337

File tree

3 files changed

+40
-38
lines changed

3 files changed

+40
-38
lines changed

apps/svelte.dev/src/lib/utils/events.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

apps/svelte.dev/src/routes/(authed)/playground/[id]/+page.svelte

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
1414
let { data } = $props();
1515
16+
const STORAGE_KEY = 'svelte:playground';
17+
1618
let repl = $state() as ReturnType<typeof Repl>;
1719
let name = $state(data.gist.name);
1820
let modified = $state(false);
@@ -60,9 +62,10 @@
6062
}
6163
6264
async function set_files() {
65+
const saved = sessionStorage.getItem(STORAGE_KEY);
6366
const hash = location.hash.slice(1);
6467
65-
if (!hash) {
68+
if (!hash && !saved) {
6669
repl?.set({
6770
// TODO make this munging unnecessary
6871
files: structuredClone(data.gist.components).map(munge)
@@ -73,16 +76,27 @@
7376
}
7477
7578
try {
76-
let files = JSON.parse(await decode_and_decompress_text(hash)).files;
79+
const recovered = JSON.parse(saved ?? (await decode_and_decompress_text(hash)));
80+
let files = recovered.files;
7781
7882
if (files[0]?.source) {
7983
files = files.map(munge);
8084
}
8185
86+
// older hashes may be missing a name
87+
if (recovered.name) {
88+
name = recovered.name;
89+
}
90+
8291
repl.set({ files });
8392
} catch {
8493
alert(`Couldn't load the code from the URL. Make sure you copied the link correctly.`);
8594
}
95+
96+
if (saved) {
97+
sessionStorage.removeItem(STORAGE_KEY);
98+
set_hash(saved);
99+
}
86100
}
87101
88102
function handle_fork({ gist }: { gist: Gist }) {
@@ -93,11 +107,19 @@
93107
// Hide hash from URL
94108
const hash = location.hash.slice(1);
95109
if (hash) {
96-
change_hash();
110+
set_hash();
97111
}
98112
}
99113
100-
async function change_hash(hash?: string) {
114+
async function update_hash() {
115+
// Only change hash when necessary to avoid polluting everyone's browser history
116+
if (modified) {
117+
const json = JSON.stringify({ name, files: repl.toJSON().files });
118+
await set_hash(json);
119+
}
120+
}
121+
122+
async function set_hash(hash?: string) {
101123
let url = `${location.pathname}${location.search}`;
102124
if (hash) {
103125
url += `#${await compress_and_encode_text(hash)}`;
@@ -143,13 +165,23 @@
143165
</svelte:head>
144166

145167
<svelte:window
146-
on:hashchange={() => {
168+
onhashchange={() => {
147169
if (!setting_hash) {
148170
set_files();
149171
}
150172
}}
173+
onbeforeunload={() => {
174+
if (modified) {
175+
// we can't save to the hash because it's an async operation, so we use
176+
// a short-lived sessionStorage value instead
177+
const json = JSON.stringify({ name, files: repl.toJSON().files });
178+
sessionStorage.setItem(STORAGE_KEY, json);
179+
}
180+
}}
151181
/>
152182

183+
<svelte:body onmouseleave={update_hash} />
184+
153185
<div class="repl-outer">
154186
<AppControls
155187
examples={data.examples}
@@ -163,16 +195,7 @@
163195
/>
164196

165197
{#if browser}
166-
<div
167-
style="display: contents"
168-
onfocusout={() => {
169-
// Only change hash on editor blur to not pollute everyone's browser history
170-
if (modified) {
171-
const json = JSON.stringify({ files: repl.toJSON().files });
172-
change_hash(json);
173-
}
174-
}}
175-
>
198+
<div style="display: contents" onfocusout={update_hash}>
176199
<Repl
177200
bind:this={repl}
178201
{svelteUrl}

apps/svelte.dev/src/routes/(authed)/playground/[id]/AppControls.svelte

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import { goto } from '$app/navigation';
33
import UserMenu from './UserMenu.svelte';
44
import { Icon } from '@sveltejs/site-kit/components';
5-
import { enter } from '$lib/utils/events';
65
import { isMac } from '$lib/utils/compat.js';
76
import { get_app_context } from '../../app-context';
87
import type { Gist, User } from '$lib/db/types';
@@ -200,9 +199,9 @@
200199

201200
<input
202201
bind:value={name}
203-
onchange={() => (modified = true)}
202+
oninput={() => (modified = true)}
204203
onfocus={(e) => e.currentTarget.select()}
205-
use:enter={(e) => (e.currentTarget as HTMLInputElement).blur()}
204+
onkeydown={(e) => e.key === 'Enter' && e.currentTarget.blur()}
206205
/>
207206

208207
<div class="buttons">

0 commit comments

Comments
 (0)