1import { Controller } from "@hotwired/stimulus" 2 3/** 4 * One-click social sharing for a blog post. 5 * 6 * The element is a form wrapping the share button. Clicking the button: 7 * 1. copies the post text to the clipboard, for the networks whose 8 * composers can't be prefilled (Facebook, LinkedIn) 9 * 2. submits the form, which records the share and re-renders the row 10 * 11 * The button is a link, so the composer opens natively in a new tab â 12 * deliberately not window.open, which popup blockers intercept. 13 * 14 * Named post-share rather than share because same-named app controllers 15 * silently lose to the honey gems' controllers, which register first. 16 * 17 * Usage: 18 * <form data-controller="post-share" 19 * data-post-share-text-value="Post copy..."> 20 * <a href="https://..." target="_blank" data-action="post-share#share"> 21 * </form> 22 */ 23export default class extends Controller { 24 static values = { text: String } 25 26 async share() { 27 if (this.textValue) await this.#copy(this.textValue) 28 29 this.element.requestSubmit() 30 } 31 32 async #copy(text) { 33 try { 34 await navigator.clipboard.writeText(text) 35 } catch { 36 this.#copyFallback(text) 37 } 38 } 39 40 // Older Safari and any non-secure context reject the async clipboard API. 41 #copyFallback(text) { 42 const field = document.createElement("textarea") 43 field.value = text 44 field.setAttribute("readonly", "") 45 field.style.position = "fixed" 46 field.style.opacity = "0" 47 document.body.appendChild(field) 48 field.select() 49 50 try { 51 document.execCommand("copy") 52 } catch { 53 // Nothing more to try â the text is on screen to copy by hand. 54 } 55 56 document.body.removeChild(field) 57 } 58}
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.