1import { Controller } from "@hotwired/stimulus" 2 3export default class extends Controller { 4 static values = { text: String } 5 static targets = ["button", "label"] 6 7 async copy() { 8 const text = this.textValue || "" 9 if (!text) return 10 11 let ok = false 12 try { 13 await navigator.clipboard.writeText(text) 14 ok = true 15 } catch { 16 ok = this.fallbackCopy(text) 17 } 18 19 if (ok) this.flashButton() 20 } 21 22 fallbackCopy(text) { 23 const el = document.createElement("textarea") 24 el.value = text 25 el.setAttribute("readonly", "readonly") 26 el.style.position = "absolute" 27 el.style.left = "-9999px" 28 document.body.appendChild(el) 29 el.select() 30 31 let ok = false 32 try { 33 ok = document.execCommand("copy") 34 } catch { 35 ok = false 36 } finally { 37 document.body.removeChild(el) 38 } 39 40 return ok 41 } 42 43 flashButton() { 44 if (!this.hasButtonTarget) return 45 46 const btn = this.buttonTarget 47 btn.disabled = true 48 49 let restoreLabel = null 50 if (this.hasLabelTarget) { 51 const labelEl = this.labelTarget 52 const original = labelEl.textContent 53 labelEl.textContent = "Copied" 54 restoreLabel = () => { labelEl.textContent = original } 55 } 56 57 window.setTimeout(() => { 58 if (restoreLabel) restoreLabel() 59 btn.disabled = false 60 }, 1200) 61 } 62}
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.