Fossil SCM

Add a workaround in the forum post Web Lock for Chrome taking half a minute or more to release the lock when a tab is manually closed, with thanks to an LLM for consulting on this.

stephan 2026-07-04 08:11 UTC trunk
Commit b2d347eaa05f5fc19e6c87ee2a0945bbad70969cd1e733110bb8c3a7a612e77d
1 file changed +22 -2
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -1202,27 +1202,47 @@
12021202
value here). */
12031203
|| fpid
12041204
);
12051205
let releaseLock;
12061206
if( window.navigator.locks ){
1207
+ /* This business with forceReleaseLockOnClose and 'pagehide'
1208
+ event is a workaround for Chrome being overly lazy in
1209
+ releasing Web Locks when a tab is closed. It sometimes
1210
+ waits half a minute or more before release.
1211
+
1212
+ Sidebar: we cannot use AbortController because it cannot
1213
+ be used with the ifAvailable lock check. */
1214
+ let forceReleaseLockOnClose = null;
1215
+ const handlePageHide = ()=>{
1216
+ if( forceReleaseLockOnClose ){
1217
+ forceReleaseLockOnClose();
1218
+ }
1219
+ };
1220
+ window.addEventListener('pagehide', handlePageHide);
12071221
releaseLock = await new Promise((resolve)=>{
12081222
window.navigator.locks.request(
12091223
'fossil-'+draftKey,
12101224
{ifAvailable: true},
1211
- async (lock) => {
1225
+ async (lock)=>{
12121226
if( !lock ){
12131227
/*lock contention*/
12141228
resolve(null);
12151229
return;
12161230
}
12171231
let release;
12181232
const lockReleased = new Promise(res=>release=res);
1219
- resolve(release);
1233
+ forceReleaseLockOnClose = release;
1234
+ const wrappedRelease = ()=>{
1235
+ window.removeEventListener('pagehide', handlePageHide);
1236
+ if( release ) release();
1237
+ };
1238
+ resolve(wrappedRelease);
12201239
await lockReleased/*hold the lock open*/;
12211240
});
12221241
});
12231242
if( !releaseLock ){
1243
+ window.removeEventListener('pagehide', handlePageHide);
12241244
reportFPEError(
12251245
ePost,
12261246
"This post is actively being replied to ",
12271247
"in another tab. To avoid losing edits, ",
12281248
"it cannot be opened here until the locking ",
12291249
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -1202,27 +1202,47 @@
1202 value here). */
1203 || fpid
1204 );
1205 let releaseLock;
1206 if( window.navigator.locks ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1207 releaseLock = await new Promise((resolve)=>{
1208 window.navigator.locks.request(
1209 'fossil-'+draftKey,
1210 {ifAvailable: true},
1211 async (lock) => {
1212 if( !lock ){
1213 /*lock contention*/
1214 resolve(null);
1215 return;
1216 }
1217 let release;
1218 const lockReleased = new Promise(res=>release=res);
1219 resolve(release);
 
 
 
 
 
1220 await lockReleased/*hold the lock open*/;
1221 });
1222 });
1223 if( !releaseLock ){
 
1224 reportFPEError(
1225 ePost,
1226 "This post is actively being replied to ",
1227 "in another tab. To avoid losing edits, ",
1228 "it cannot be opened here until the locking ",
1229
--- src/fossil.page.forumpost.js
+++ src/fossil.page.forumpost.js
@@ -1202,27 +1202,47 @@
1202 value here). */
1203 || fpid
1204 );
1205 let releaseLock;
1206 if( window.navigator.locks ){
1207 /* This business with forceReleaseLockOnClose and 'pagehide'
1208 event is a workaround for Chrome being overly lazy in
1209 releasing Web Locks when a tab is closed. It sometimes
1210 waits half a minute or more before release.
1211
1212 Sidebar: we cannot use AbortController because it cannot
1213 be used with the ifAvailable lock check. */
1214 let forceReleaseLockOnClose = null;
1215 const handlePageHide = ()=>{
1216 if( forceReleaseLockOnClose ){
1217 forceReleaseLockOnClose();
1218 }
1219 };
1220 window.addEventListener('pagehide', handlePageHide);
1221 releaseLock = await new Promise((resolve)=>{
1222 window.navigator.locks.request(
1223 'fossil-'+draftKey,
1224 {ifAvailable: true},
1225 async (lock)=>{
1226 if( !lock ){
1227 /*lock contention*/
1228 resolve(null);
1229 return;
1230 }
1231 let release;
1232 const lockReleased = new Promise(res=>release=res);
1233 forceReleaseLockOnClose = release;
1234 const wrappedRelease = ()=>{
1235 window.removeEventListener('pagehide', handlePageHide);
1236 if( release ) release();
1237 };
1238 resolve(wrappedRelease);
1239 await lockReleased/*hold the lock open*/;
1240 });
1241 });
1242 if( !releaseLock ){
1243 window.removeEventListener('pagehide', handlePageHide);
1244 reportFPEError(
1245 ePost,
1246 "This post is actively being replied to ",
1247 "in another tab. To avoid losing edits, ",
1248 "it cannot be opened here until the locking ",
1249

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button