find: Enter focuses selected match (centered) and closes overlay; clicking a match also closes; right-side context stops at nearest punctuation (, . -) to avoid awkward truncation
- commit
- 86107469f15ca1235e19b8cc7ba677fa803f789f
- author
- bamen · · 2025-09-09 16:02 UTC
- committer
- bamen · · 2025-09-09 19:47 UTC
- parent
- 6f48527
- signature
- unsigned
2 files · +20 -19
D pkg/webkit/ucm_js_access.go +0 -8
| @@ -1,8 +0,0 @@ | |||
| 1 | - | package webkit | |
| 2 | - | ||
| 3 | - | // getOmniboxScript exposes the injected omnibox/find component script as a function | |
| 4 | - | // to avoid any build-tag edge cases when referenced from cgo files. | |
| 5 | - | func getOmniboxScript() string { | |
| 6 | - | return ucmOmniboxScript | |
| 7 | - | } | |
| 8 | - | ||
| @@ -1,8 +0,0 @@ | |||||
| 1 | - | package webkit | |||
| 2 | - | ||||
| 3 | - | // getOmniboxScript exposes the injected omnibox/find component script as a function | |||
| 4 | - | // to avoid any build-tag edge cases when referenced from cgo files. | |||
| 5 | - | func getOmniboxScript() string { | |||
| 6 | - | return ucmOmniboxScript | |||
| 7 | - | } | |||
| 8 | - | ||||
R pkg/webkit/ucm_js.go → pkg/webkit/ucm_js_cgo.go +20 -11 renamed, 91% similar
| @@ -1,10 +1,12 @@ | |||
| 1 | + | //go:build webkit_cgo | |
| 2 | + | ||
| 1 | 3 | package webkit | |
| 2 | 4 | ||
| 3 | - | // ucmOmniboxScript is injected at document-start via WebKit UserContentManager. | |
| 4 | - | // It provides a reusable overlay component with two modes: | |
| 5 | - | // - "omnibox": navigation/search suggestions (Ctrl/Cmd+L) | |
| 6 | - | // - "find": in-page find with yellow highlights and match list (Ctrl/Cmd+F) | |
| 7 | - | const ucmOmniboxScript = `(() => { | |
| 5 | + | // getOmniboxScript returns the injected omnibox/find component script. | |
| 6 | + | // Kept in a cgo-tagged file to ensure availability when referenced | |
| 7 | + | // from other cgo files in this package. | |
| 8 | + | func getOmniboxScript() string { | |
| 9 | + | return `(() => { | |
| 8 | 10 | try { | |
| 9 | 11 | if (window.__dumber_omnibox_loaded) return; // idempotent | |
| 10 | 12 | window.__dumber_omnibox_loaded = true; | |
| @@ -38,7 +40,7 @@ const ucmOmniboxScript = `(() => { | |||
| 38 | 40 | root.id = 'dumber-omnibox-root'; | |
| 39 | 41 | root.style.cssText = 'position:fixed;inset:0;z-index:2147483647;display:none;'; | |
| 40 | 42 | const box = document.createElement('div'); | |
| 41 | - | box.style.cssText = 'max-width:720px;margin:8vh auto;padding:8px 10px;background:#1b1b1b;color:#eee;border:1px solid #444;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.6);font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,\"Helvetica Neue\",Arial,sans-serif;'; | |
| 43 | + | box.style.cssText = 'max-width:720px;margin:8vh auto;padding:8px 10px;background:#1b1b1b;color:#eee;border:1px solid #444;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.6);font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,"Helvetica Neue",Arial,sans-serif;'; | |
| 42 | 44 | const input = document.createElement('input'); | |
| 43 | 45 | input.type = 'text'; | |
| 44 | 46 | input.placeholder = 'Type URL or search…'; | |
| @@ -57,9 +59,9 @@ const ucmOmniboxScript = `(() => { | |||
| 57 | 59 | if (v) H.post({type:'navigate', url:v}); | |
| 58 | 60 | H.toggle(false); | |
| 59 | 61 | } else if (H.mode==='find' && e.key === 'Enter'){ | |
| 60 | - | e.preventDefault(); H.jump(1); | |
| 61 | - | } else if (H.mode==='find' && e.key === 'Enter' && e.shiftKey){ | |
| 62 | - | e.preventDefault(); H.jump(-1); | |
| 62 | + | e.preventDefault(); | |
| 63 | + | if (e.shiftKey) { H.jump(-1); } | |
| 64 | + | else { H.revealSelection(); H.close(); } | |
| 63 | 65 | } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp'){ | |
| 64 | 66 | e.preventDefault(); | |
| 65 | 67 | const n = (H.mode==='find'? H.matches.length : H.suggestions.length); | |
| @@ -106,7 +108,7 @@ const ucmOmniboxScript = `(() => { | |||
| 106 | 108 | item.style.cssText = 'padding:8px 10px;cursor:pointer;border-bottom:1px solid #2a2a2a;'+(i===H.selectedIndex?'background:#0a0a0a;':''); | |
| 107 | 109 | const ctx = document.createElement('div'); ctx.textContent = m.context || ''; ctx.style.cssText = 'color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;'; | |
| 108 | 110 | item.appendChild(ctx); | |
| 109 | - | item.addEventListener('click',()=>{ H.selectedIndex=i; H.revealSelection(); H.paintList(); }); | |
| 111 | + | item.addEventListener('click',()=>{ H.selectedIndex=i; H.revealSelection(); H.paintList(); H.close(); }); | |
| 110 | 112 | list.appendChild(item); | |
| 111 | 113 | }); | |
| 112 | 114 | } | |
| @@ -153,7 +155,13 @@ const ucmOmniboxScript = `(() => { | |||
| 153 | 155 | parent.insertBefore(span, text); | |
| 154 | 156 | text.nodeValue = afterVal; | |
| 155 | 157 | H.highlightNodes.push({span, text: match}); | |
| 156 | - | const context = (before.nodeValue.slice(-30) + match.nodeValue + afterVal.slice(0, 30)).replace(/\s+/g,' ').trim(); | |
| 158 | + | const leftCtx = before.nodeValue.slice(-30); | |
| 159 | + | let rightRaw = afterVal.slice(0, 30); | |
| 160 | + | const boundaryIdx = rightRaw.search(/[.,-]/); | |
| 161 | + | if (boundaryIdx !== -1) { | |
| 162 | + | rightRaw = rightRaw.slice(0, boundaryIdx+1); | |
| 163 | + | } | |
| 164 | + | const context = (leftCtx + match.nodeValue + rightRaw).replace(/\s+/g,' ').trim(); | |
| 157 | 165 | H.matches.push({el: span, context}); | |
| 158 | 166 | if (H.matches.length >= MAX_MATCHES) break; | |
| 159 | 167 | s = afterVal; | |
| @@ -190,3 +198,4 @@ const ucmOmniboxScript = `(() => { | |||
| 190 | 198 | window.__dumber_find_query = (q)=> { if (H.mode!=='find') H.setMode('find'); if (!H.visible) H.toggle(true); H.input.value = q||''; H.find(q||''); }; | |
| 191 | 199 | } catch (e) { /* no-op */ } | |
| 192 | 200 | })();` | |
| 201 | + | } | |
| @@ -1,10 +1,12 @@ | |||||
| 1 | + | //go:build webkit_cgo | |||
| 2 | + | ||||
| 1 | package webkit | 3 | package webkit | ||
| 2 | 4 | ||||
| 3 | - | // ucmOmniboxScript is injected at document-start via WebKit UserContentManager. | 5 | + | // getOmniboxScript returns the injected omnibox/find component script. |
| 4 | - | // It provides a reusable overlay component with two modes: | 6 | + | // Kept in a cgo-tagged file to ensure availability when referenced |
| 5 | - | // - "omnibox": navigation/search suggestions (Ctrl/Cmd+L) | 7 | + | // from other cgo files in this package. |
| 6 | - | // - "find": in-page find with yellow highlights and match list (Ctrl/Cmd+F) | 8 | + | func getOmniboxScript() string { |
| 7 | - | const ucmOmniboxScript = `(() => { | 9 | + | return `(() => { |
| 8 | try { | 10 | try { | ||
| 9 | if (window.__dumber_omnibox_loaded) return; // idempotent | 11 | if (window.__dumber_omnibox_loaded) return; // idempotent | ||
| 10 | window.__dumber_omnibox_loaded = true; | 12 | window.__dumber_omnibox_loaded = true; | ||
| @@ -38,7 +40,7 @@ const ucmOmniboxScript = `(() => { | |||||
| 38 | root.id = 'dumber-omnibox-root'; | 40 | root.id = 'dumber-omnibox-root'; | ||
| 39 | root.style.cssText = 'position:fixed;inset:0;z-index:2147483647;display:none;'; | 41 | root.style.cssText = 'position:fixed;inset:0;z-index:2147483647;display:none;'; | ||
| 40 | const box = document.createElement('div'); | 42 | const box = document.createElement('div'); | ||
| 41 | - | box.style.cssText = 'max-width:720px;margin:8vh auto;padding:8px 10px;background:#1b1b1b;color:#eee;border:1px solid #444;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.6);font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,\"Helvetica Neue\",Arial,sans-serif;'; | 43 | + | box.style.cssText = 'max-width:720px;margin:8vh auto;padding:8px 10px;background:#1b1b1b;color:#eee;border:1px solid #444;border-radius:8px;box-shadow:0 10px 30px rgba(0,0,0,.6);font-family:system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,"Helvetica Neue",Arial,sans-serif;'; |
| 42 | const input = document.createElement('input'); | 44 | const input = document.createElement('input'); | ||
| 43 | input.type = 'text'; | 45 | input.type = 'text'; | ||
| 44 | input.placeholder = 'Type URL or search…'; | 46 | input.placeholder = 'Type URL or search…'; | ||
| @@ -57,9 +59,9 @@ const ucmOmniboxScript = `(() => { | |||||
| 57 | if (v) H.post({type:'navigate', url:v}); | 59 | if (v) H.post({type:'navigate', url:v}); | ||
| 58 | H.toggle(false); | 60 | H.toggle(false); | ||
| 59 | } else if (H.mode==='find' && e.key === 'Enter'){ | 61 | } else if (H.mode==='find' && e.key === 'Enter'){ | ||
| 60 | - | e.preventDefault(); H.jump(1); | 62 | + | e.preventDefault(); |
| 61 | - | } else if (H.mode==='find' && e.key === 'Enter' && e.shiftKey){ | 63 | + | if (e.shiftKey) { H.jump(-1); } |
| 62 | - | e.preventDefault(); H.jump(-1); | 64 | + | else { H.revealSelection(); H.close(); } |
| 63 | } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp'){ | 65 | } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp'){ | ||
| 64 | e.preventDefault(); | 66 | e.preventDefault(); | ||
| 65 | const n = (H.mode==='find'? H.matches.length : H.suggestions.length); | 67 | const n = (H.mode==='find'? H.matches.length : H.suggestions.length); | ||
| @@ -106,7 +108,7 @@ const ucmOmniboxScript = `(() => { | |||||
| 106 | item.style.cssText = 'padding:8px 10px;cursor:pointer;border-bottom:1px solid #2a2a2a;'+(i===H.selectedIndex?'background:#0a0a0a;':''); | 108 | item.style.cssText = 'padding:8px 10px;cursor:pointer;border-bottom:1px solid #2a2a2a;'+(i===H.selectedIndex?'background:#0a0a0a;':''); | ||
| 107 | const ctx = document.createElement('div'); ctx.textContent = m.context || ''; ctx.style.cssText = 'color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;'; | 109 | const ctx = document.createElement('div'); ctx.textContent = m.context || ''; ctx.style.cssText = 'color:#ddd;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;'; | ||
| 108 | item.appendChild(ctx); | 110 | item.appendChild(ctx); | ||
| 109 | - | item.addEventListener('click',()=>{ H.selectedIndex=i; H.revealSelection(); H.paintList(); }); | 111 | + | item.addEventListener('click',()=>{ H.selectedIndex=i; H.revealSelection(); H.paintList(); H.close(); }); |
| 110 | list.appendChild(item); | 112 | list.appendChild(item); | ||
| 111 | }); | 113 | }); | ||
| 112 | } | 114 | } | ||
| @@ -153,7 +155,13 @@ const ucmOmniboxScript = `(() => { | |||||
| 153 | parent.insertBefore(span, text); | 155 | parent.insertBefore(span, text); | ||
| 154 | text.nodeValue = afterVal; | 156 | text.nodeValue = afterVal; | ||
| 155 | H.highlightNodes.push({span, text: match}); | 157 | H.highlightNodes.push({span, text: match}); | ||
| 156 | - | const context = (before.nodeValue.slice(-30) + match.nodeValue + afterVal.slice(0, 30)).replace(/\s+/g,' ').trim(); | 158 | + | const leftCtx = before.nodeValue.slice(-30); |
| 159 | + | let rightRaw = afterVal.slice(0, 30); | |||
| 160 | + | const boundaryIdx = rightRaw.search(/[.,-]/); | |||
| 161 | + | if (boundaryIdx !== -1) { | |||
| 162 | + | rightRaw = rightRaw.slice(0, boundaryIdx+1); | |||
| 163 | + | } | |||
| 164 | + | const context = (leftCtx + match.nodeValue + rightRaw).replace(/\s+/g,' ').trim(); | |||
| 157 | H.matches.push({el: span, context}); | 165 | H.matches.push({el: span, context}); | ||
| 158 | if (H.matches.length >= MAX_MATCHES) break; | 166 | if (H.matches.length >= MAX_MATCHES) break; | ||
| 159 | s = afterVal; | 167 | s = afterVal; | ||
| @@ -190,3 +198,4 @@ const ucmOmniboxScript = `(() => { | |||||
| 190 | window.__dumber_find_query = (q)=> { if (H.mode!=='find') H.setMode('find'); if (!H.visible) H.toggle(true); H.input.value = q||''; H.find(q||''); }; | 198 | window.__dumber_find_query = (q)=> { if (H.mode!=='find') H.setMode('find'); if (!H.visible) H.toggle(true); H.input.value = q||''; H.find(q||''); }; | ||
| 191 | } catch (e) { /* no-op */ } | 199 | } catch (e) { /* no-op */ } | ||
| 192 | })();` | 200 | })();` | ||
| 201 | + | } | |||