1window.copy = (text, el) => { 2 navigator.clipboard.writeText(text); 3 document.activeElement.blur(); // optional: remove focus 4 // optional: simple feedback 5 el.textContent = 'copied!'; 6 setTimeout(() => el.textContent = 'copy', 1000); 7}; 8 9 10window.addEventListener('keyup', e => { 11 if (e.code !== `Backquote`) return 12 if (!('salemMeta' in window)) return 13 14 let jsonHtml = `` 15 const keys = Object.keys(window.salemMeta).sort() 16 keys.forEach(k => { 17 // Tiny escape helpers (no replaceAll needed) 18 const escHtml = (v) => 19 String(v) 20 .replace(/&/g, "&") 21 .replace(/</g, "<") 22 .replace(/>/g, ">") 23 .replace(/"/g, """) 24 .replace(/'/g, "'"); // safer than ' for HTML 25 26 const escAttrSingle = escHtml; // single-quoted attribute uses same escaping 27 28 const val = window.salemMeta[k]; 29 30 if (typeof val === 'object' && val !== null) { 31 let innerHtml = ''; 32 33 for (const [subKey, subVal] of Object.entries(val)) { 34 const displayVal = 35 typeof subVal === 'object' 36 ? JSON.stringify(subVal, null, 2) 37 : subVal; 38 39 innerHtml += ` 40 <div style="display:flex; gap:8px; align-items:flex-start;"> 41 <div><code>${escHtml(subKey)}</code>:</div> 42 <div> 43 <pre style="display:inline; margin:0;">${escHtml(displayVal)}</pre> 44 - <a href="#" 45 class="underline" 46 data-copy='${escAttrSingle(subVal)}' 47 onclick="event.preventDefault(); window.copy(this.dataset.copy, this)"> 48 copy 49 </a> 50 </div> 51 </div>`; 52 } 53 54 jsonHtml += `<div>${escHtml(k)}</div><div>${innerHtml}</div>`; 55 } else if (k.startsWith("hint_")) { 56 jsonHtml += `<div>${escHtml(k)}</div><div>${escHtml(val)}</div>`; 57 } else { 58 // make a link to copy the value 59 jsonHtml += ` 60 <div>${escHtml(k)}</div> 61 <div> 62 ${escHtml(val)} 63 - <a 64 href="#" 65 class="underline" 66 data-copy='${escAttrSingle(val)}' 67 onclick="event.preventDefault(); window.copy(this.dataset.copy, this)"> 68 copy 69 </a> 70 </div>`; 71 } 72 73 }) 74 75 if ('confetti' in window) { 76 window.confetti() 77 } else { 78 const script = document.createElement('script') 79 script.onload = function () { 80 window.confetti() 81 } 82 script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/confetti.browser.min.js' 83 document.head.appendChild(script) 84 } 85 86 const dialogHtml = ` 87 <dialog id='dialogEl' class='rounded [&_a]:text-sky-600'> 88 <div id='dialogInner' style="padding:50px 32px 32px 32px;position:relative;"> 89 <div style="display:grid;grid-template-columns:auto 1fr;column-gap:20px;"> 90 ${jsonHtml} 91 </div> 92 <div class='close' style="position:absolute;cursor:default;border-radius:5px;font-size:12px;border:1px solid darkred;padding:4px;top:8px;right:8px;">ESC</div> 93 </div> 94 </dialog> 95 <style> 96 #dialogEl { border: none; } 97 #dialogEl:focus-visible { outline: none; } 98 #dialogEl::backdrop { 99 background-color: #00000080; 100 } 101 </style> 102 ` 103 104 if (!window.dialogEl) { 105 document.body.insertAdjacentHTML('beforeend', dialogHtml) 106 setTimeout(() => { 107 document.activeElement.blur() 108 }) 109 } 110 111 document.querySelector("#dialogEl .close").onclick = () => { 112 window.dialogEl.close() 113 } 114 115 window.dialogEl.onclick = (e) => { 116 if (e.composedPath().includes(window.dialogInner)) return 117 window.dialogEl.close() 118 } 119 120 window.dialogEl.showModal() 121})
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.