1//go:build webkit_cgo
2
3package webkit
4
5// ucmOmniboxScript is injected at document-start via WebKit UserContentManager.
6// It renders a minimal overlay with an input and a suggestions list, handles
7// Ctrl+L to toggle, Enter to navigate, and posts search queries to native.
8const ucmOmniboxScript = `(() => {
9 try {
10 if (window.__dumber_omnibox_loaded) return; // idempotent
11 window.__dumber_omnibox_loaded = true;
12
13 const H = {
14 el: null,
15 input: null,
16 list: null,
17 visible: false,
18 suggestions: [],
19 debounceTimer: 0,
20 post(msg){ try { window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.dumber && window.webkit.messageHandlers.dumber.postMessage(JSON.stringify(msg)); } catch(_){} },
21 render(){
22 if (!H.el) H.mount();
23 H.el.style.display = H.visible ? 'block' : 'none';
24 if (H.visible) H.input.focus();
25 },
26 mount(){
27 const root = document.createElement('div');
28 root.id = 'dumber-omnibox-root';
29 root.style.cssText = 'position:fixed;inset:0;z-index:2147483647;display:none;';
30 const box = document.createElement('div');
31 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;';
32 const input = document.createElement('input');
33 input.type = 'text';
34 input.placeholder = 'Type URL or search…';
35 input.style.cssText = 'width:100%;padding:10px 12px;border-radius:6px;border:1px solid #555;background:#121212;color:#eee;font-size:16px;outline:none;';
36 const list = document.createElement('div');
37 list.style.cssText = 'margin-top:8px;max-height:50vh;overflow:auto;border-top:1px solid #333;';
38 box.appendChild(input); box.appendChild(list); root.appendChild(box); document.documentElement.appendChild(root);
39 input.addEventListener('keydown', (e)=>{
40 if (e.key === 'Escape'){ H.toggle(false); }
41 else if (e.key === 'Enter'){
42 const pick = H.suggestions && H.suggestions[H.selectedIndex|0];
43 const v = (pick && pick.url) || input.value || '';
44 if (v) H.post({type:'navigate', url:v});
45 H.toggle(false);
46 } else if (e.key === 'ArrowDown' || e.key === 'ArrowUp'){
47 e.preventDefault();
48 const n = H.suggestions.length;
49 if (n){
50 H.selectedIndex = (H.selectedIndex||0) + (e.key==='ArrowDown'?1:-1);
51 if (H.selectedIndex<0) H.selectedIndex = n-1; if (H.selectedIndex>=n) H.selectedIndex = 0;
52 H.paintList();
53 }
54 }
55 });
56 input.addEventListener('input', ()=>{
57 clearTimeout(H.debounceTimer);
58 const q = input.value;
59 H.debounceTimer = setTimeout(()=> H.post({type:'query', q, limit:10}), 120);
60 });
61 H.el = root; H.input = input; H.list = list; H.selectedIndex = -1; H.paintList();
62 },
63 paintList(){
64 const list = H.list; if (!list) return;
65 list.textContent = '';
66 H.suggestions.forEach((s, i)=>{
67 const item = document.createElement('div');
68 item.style.cssText = 'padding:8px 10px;display:flex;gap:10px;align-items:center;cursor:pointer;border-bottom:1px solid #2a2a2a;'+(i===H.selectedIndex?'background:#0a0a0a;':'');
69 const url = document.createElement('div'); url.textContent = s.url || ''; url.style.cssText = 'flex:1;color:#9ad;word-break:break-all;';
70 const title = document.createElement('div'); title.textContent = s.title || ''; title.style.cssText = 'flex:1;color:#ccc;opacity:.9;';
71 item.appendChild(title); item.appendChild(url);
72 item.addEventListener('click',()=>{ H.post({type:'navigate', url:s.url}); H.toggle(false); });
73 list.appendChild(item);
74 });
75 },
76 toggle(v){ H.visible = (typeof v==='boolean')? v : !H.visible; H.render(); },
77 setSuggestions(arr){ H.suggestions = Array.isArray(arr)? arr: []; H.selectedIndex = -1; H.paintList(); }
78 };
79 window.addEventListener('keydown', (e)=>{
80 if ((e.ctrlKey||e.metaKey) && (e.key==='l' || e.key==='L')) { e.preventDefault(); H.toggle(true); }
81 }, true);
82 // Allow native side to update suggestions or toggle
83 window.__dumber_setSuggestions = (arr)=> H.setSuggestions(arr);
84 window.__dumber_toggle = ()=> H.toggle();
85 } catch (e) { /* no-op */ }
86})();`