1import { Controller } from "@hotwired/stimulus" 2 3// Uses the Web Share API (navigator.share) when available, falling back to 4// copying the URL to the clipboard. 5export default class extends Controller { 6 static values = { 7 url: String, 8 title: String, 9 text: String, 10 } 11 static targets = ["label"] 12 13 async share(event) { 14 event.preventDefault() 15 16 const url = this.urlValue || window.location.href 17 const data = { url } 18 if (this.hasTitleValue) data.title = this.titleValue 19 if (this.hasTextValue) data.text = this.textValue 20 21 if (navigator.share) { 22 try { 23 await navigator.share(data) 24 } catch (error) { 25 // User cancelled the share sheet, or it failed â ignore. 26 if (error.name !== "AbortError") this.copyToClipboard(url) 27 } 28 return 29 } 30 31 this.copyToClipboard(url) 32 } 33 34 // Explicit "copy link" action â always copies, never opens the share sheet. 35 copy(event) { 36 event.preventDefault() 37 this.copyToClipboard(this.urlValue || window.location.href) 38 } 39 40 async copyToClipboard(url) { 41 try { 42 await navigator.clipboard.writeText(url) 43 this.flashLabel("Link copied!") 44 } catch (error) { 45 window.prompt("Copy this link:", url) 46 } 47 } 48 49 flashLabel(message) { 50 if (!this.hasLabelTarget) return 51 const original = this.labelTarget.textContent 52 this.labelTarget.textContent = message 53 setTimeout(() => { 54 this.labelTarget.textContent = original 55 }, 2000) 56 } 57}
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.