max / quasi
| 1 | // Putting a described value on the clipboard. |
| 2 | // |
| 3 | // `c3e145e0`. An `Act` can say that pressing it copies a value, and this is the |
| 4 | // browser's half. It replaces seven `window.<name>` globals across 14 sites on |
| 5 | // the MNW server, six of which scraped the text back off the DOM at press time |
| 6 | // and one of which read an element by id. |
| 7 | // |
| 8 | // It reads one attribute the node emitter writes and nothing else: |
| 9 | // `data-copies` carries the value. An ordinary escaped attribute, so nothing |
| 10 | // here is a program built out of app text -- the same rule that makes this a |
| 11 | // script rather than an emitted _hyperscript program. A licence key reading |
| 12 | // `"; alert(1); "` is a value in an attribute here and could not be one in a |
| 13 | // program. |
| 14 | // |
| 15 | // What it does NOT do is say "Copied!". Every shipped site relabelled its own |
| 16 | // button and reverted, six at 1500ms and one at 2000ms, and that is a temporary |
| 17 | // label rather than a copy: it belongs to `makeover-timing` and to mnw-server |
| 18 | // `033c722f`. Splitting them is deliberate -- a host with no notion of a |
| 19 | // reverting label still needs to be told the act copies something. |
| 20 | |
| 21 | "use strict"; |
| 22 | |
| 23 | /** The value to put on the clipboard. */ |
| 24 | const VALUE = "data-copies"; |
| 25 | |
| 26 | /** |
| 27 | * Write `text` to the clipboard, preferring the async API. |
| 28 | * |
| 29 | * `navigator.clipboard` is unavailable on an insecure origin and can be |
| 30 | * refused by permissions policy, and neither is an error worth surfacing to |
| 31 | * a reader who pressed a copy button. The fallback is the old selection |
| 32 | * dance, which works in both cases and is why it is still here. |
| 33 | */ |
| 34 | const |
| 35 | |
| 36 | |
| 37 | await navigator..; |
| 38 | return; |
| 39 | |
| 40 | |
| 41 | // Fall through: refused, or no permission. The fallback below does |
| 42 | // not ask for one. |
| 43 | |
| 44 | |
| 45 | const carrier = document.; |
| 46 | carrier. = text; |
| 47 | // Off-screen rather than hidden: a `display: none` element cannot be |
| 48 | // selected, and selecting is the whole mechanism here. |
| 49 | carrier.; |
| 50 | carrier.. = "fixed"; |
| 51 | carrier.. = "-9999px"; |
| 52 | document..; |
| 53 | carrier.; |
| 54 | |
| 55 | document.; |
| 56 | |
| 57 | // Nothing left to try. The reader sees no change, which is the |
| 58 | // same outcome as a page that never described the copy at all. |
| 59 | |
| 60 | carrier.; |
| 61 | }; |
| 62 | |
| 63 | // One delegated listener rather than one per control, for `FILL_JS`' |
| 64 | // reason: these controls arrive in swaps, so binding per element would mean |
| 65 | // rebinding on every swap. |
| 66 | document. |
| 67 | const control = event.?.?.; |
| 68 | |
| 69 | return; |
| 70 | |
| 71 | void ; |
| 72 | }; |
| 73 | }); |
| 74 |