diff --git a/theme/ht_searcher.js b/theme/ht_searcher.js
index bf11595ad..dfed69d36 100644
--- a/theme/ht_searcher.js
+++ b/theme/ht_searcher.js
@@ -1,40 +1,96 @@
-/* ht_searcher.js --------------------------------------------------------- */
+/* ht_searcher.js ───────────────────────────────────────────────── */
+/* Everything – UI + worker – lives in this one file. */
+
(() => {
- const WRAPPER = document.getElementById('search-wrapper');
- const TOGGLE = document.getElementById('search-toggle');
- const INPUT = document.getElementById('searchbar');
- const LIST = document.getElementById('searchresults');
- const HOTKEY = 83; // “s”
- let worker, debounce;
+ /* ──────────────────────────────
+ 0. Build an inline Web Worker
+ ────────────────────────────── */
+ const workerCode = `
+ /* inside the worker thread ################################## */
+ self.window = self; /* let searchindex.js use window */
- function startWorker() {
- if (worker) return;
- worker = new Worker('/search-worker.js', { type:'module' });
- worker.onmessage = ({data}) => {
- LIST.innerHTML = data.slice(0,30).map(h =>
- `
${h.doc.title}`
- ).join('');
- };
- }
+ /* 1. elasticlunr.min.js (CDN → local) */
+ try {
+ importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js');
+ } catch (_) {
+ importScripts('/elasticlunr.min.js');
+ }
- async function openUI() {
- WRAPPER.classList.remove('hidden');
- INPUT.focus();
- startWorker(); // fetches CDN/GitHub in parallel
- }
+ /* 2. searchindex.js (GitHub Raw → local) */
+ (async () => {
+ try {
+ const r = await fetch(
+ 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js',
+ { mode: 'cors' }
+ );
+ if (!r.ok) throw new Error(r.status);
+ const blobURL = URL.createObjectURL(
+ new Blob([await r.text()], { type: 'application/javascript' })
+ ); /* force correct MIME */
+ importScripts(blobURL);
+ } catch (_) {
+ importScripts('/searchindex.js');
+ }
- TOGGLE.addEventListener('click', openUI);
+ /* 3. Build index & reply to queries */
+ const idx = elasticlunr.Index.load(self.search.index);
+
+ self.onmessage = ({ data: q }) => {
+ const hits = idx.search(q, { bool: 'AND', expand: true });
+ postMessage(hits);
+ };
+ })();
+ `;
+
+ /* Turn the string into a real worker file */
+ const workerURL = URL.createObjectURL(
+ new Blob([workerCode], { type: 'application/javascript' })
+ );
+ const worker = new Worker(workerURL); /* classic worker, supports importScripts */
+ URL.revokeObjectURL(workerURL); /* clean up */
+
+ /* ──────────────────────────────
+ 1. Minimal search-UI glue
+ ────────────────────────────── */
+ const WRAP = document.getElementById('search-wrapper');
+ const TOG = document.getElementById('search-toggle');
+ const INP = document.getElementById('searchbar');
+ const LIST = document.getElementById('searchresults');
+ const HOTKEY = 83; /* “s” */
+ let debounce;
+
+ /* Paint results that come back from the worker */
+ const paint = hits => {
+ LIST.innerHTML = hits.slice(0, 30).map(h =>
+ '' + h.doc.title + ''
+ ).join('');
+ };
+
+ worker.onmessage = ({ data }) => paint(data);
+
+ /* Open the search UI */
+ const open = () => {
+ WRAP.classList.remove('hidden');
+ INP.focus();
+ };
+
+ /* Toggle button */
+ TOG.addEventListener('click', open);
+
+ /* Keyboard shortcut: “s” (no modifiers) */
document.addEventListener('keydown', e => {
if (!e.metaKey && !e.ctrlKey && !e.altKey && e.keyCode === HOTKEY) {
- e.preventDefault(); openUI();
+ e.preventDefault();
+ open();
}
});
- INPUT.addEventListener('input', e => {
+ /* Debounced input → worker */
+ INP.addEventListener('input', e => {
clearTimeout(debounce);
debounce = setTimeout(() => {
- worker?.postMessage(e.target.value.trim());
- }, 120); // small debounce keeps typing smooth
+ worker.postMessage(e.target.value.trim());
+ }, 120);
});
})();
\ No newline at end of file
diff --git a/theme/search-worker.js b/theme/search-worker.js
deleted file mode 100644
index f221ce369..000000000
--- a/theme/search-worker.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/* search-worker.js ------------------------------------------------------- */
-/* Make code written for window work in a worker: */
-self.window = self;
-
-////////////////////////////////////////////////////////////////////////////
-// 1. elasticlunr.min.js : CDN first → local fallback
-////////////////////////////////////////////////////////////////////////////
-try {
- importScripts('https://cdn.jsdelivr.net/npm/elasticlunr@0.9.5/elasticlunr.min.js');
-} catch (e) {
- importScripts('/elasticlunr.min.js'); // ship this with your site
-}
-
-////////////////////////////////////////////////////////////////////////////
-// 2. searchindex.js : GitHub Raw first → local fallback
-// We fetch → wrap in a Blob({type:'application/javascript'}) to bypass
-// GitHub’s text/plain + nosniff MIME blocking.
-////////////////////////////////////////////////////////////////////////////
-try {
- const res = await fetch(
- 'https://raw.githubusercontent.com/HackTricks-wiki/hacktricks/refs/heads/master/searchindex.js',
- {mode: 'cors'}
- );
- if (!res.ok) throw new Error(res.status);
- const blobUrl = URL.createObjectURL(
- new Blob([await res.text()], { type:'application/javascript' })
- );
- importScripts(blobUrl); // correct MIME, runs once
-} catch (e) {
- importScripts('/searchindex.js'); // offline fallback
-}
-
-////////////////////////////////////////////////////////////////////////////
-// 3. Build the index once and answer queries
-////////////////////////////////////////////////////////////////////////////
-const idx = elasticlunr.Index.load(self.search.index);
-
-self.onmessage = ({data: q}) => {
- postMessage(idx.search(q, { bool:'AND', expand:true }));
-};
-