Skip to main content

max / goingson

Take quasi 0.68.0 `Act::copies` says a press puts a value on the clipboard, and `Act` gained a field, so this is a breaking bump. Ruling: wiki `quasi-vocabulary-findings`, "copying a value is a member on the act". Nothing here sets it yet; converting MNW's 14 sites is mnw-server `17050ff5`.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-27 17:52 UTC
Signed with PGP, not checked
Commit: f3063e7d5377e0989a96fe526e1007511c466549
Parent: cae79af
4 files changed, +100 insertions, -26 deletions
M Cargo.lock +20 -20
@@ -1387,7 +1387,7 @@
1387 1387 "libc",
1388 1388 "option-ext",
1389 1389 "redox_users",
1390 - "windows-sys 0.60.2",
1390 + "windows-sys 0.61.2",
1391 1391 ]
1392 1392
1393 1393 [[package]]
@@ -1628,7 +1628,7 @@
1628 1628 checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
1629 1629 dependencies = [
1630 1630 "libc",
1631 - "windows-sys 0.60.2",
1631 + "windows-sys 0.61.2",
1632 1632 ]
1633 1633
1634 1634 [[package]]
@@ -3650,7 +3650,7 @@
3650 3650 "png 0.18.1",
3651 3651 "serde",
3652 3652 "thiserror 2.0.20",
3653 - "windows-sys 0.60.2",
3653 + "windows-sys 0.61.2",
3654 3654 ]
3655 3655
3656 3656 [[package]]
@@ -3783,7 +3783,7 @@
3783 3783 source = "registry+https://github.com/rust-lang/crates.io-index"
3784 3784 checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
3785 3785 dependencies = [
3786 - "windows-sys 0.60.2",
3786 + "windows-sys 0.61.2",
3787 3787 ]
3788 3788
3789 3789 [[package]]
@@ -4717,7 +4717,7 @@
4717 4717
4718 4718 [[package]]
4719 4719 name = "quasi-http"
4720 - version = "0.67.0"
4720 + version = "0.68.0"
4721 4721 dependencies = [
4722 4722 "form_urlencoded",
4723 4723 "http",
@@ -4726,7 +4726,7 @@
4726 4726
4727 4727 [[package]]
4728 4728 name = "quasi-notifs"
4729 - version = "0.67.0"
4729 + version = "0.68.0"
4730 4730 dependencies = [
4731 4731 "quasi-router",
4732 4732 "synckit-config",
@@ -4734,14 +4734,14 @@
4734 4734
4735 4735 [[package]]
4736 4736 name = "quasi-router"
4737 - version = "0.67.0"
4737 + version = "0.68.0"
4738 4738 dependencies = [
4739 4739 "makeover-layout",
4740 4740 ]
4741 4741
4742 4742 [[package]]
4743 4743 name = "quasi-tauri"
4744 - version = "0.67.0"
4744 + version = "0.68.0"
4745 4745 dependencies = [
4746 4746 "http",
4747 4747 "quasi-http",
@@ -4767,7 +4767,7 @@
4767 4767
4768 4768 [[package]]
4769 4769 name = "quasi-webview"
4770 - version = "0.67.0"
4770 + version = "0.68.0"
4771 4771 dependencies = [
4772 4772 "docengine",
4773 4773 "makeover-layout",
@@ -5206,7 +5206,7 @@
5206 5206 "errno",
5207 5207 "libc",
5208 5208 "linux-raw-sys",
5209 - "windows-sys 0.60.2",
5209 + "windows-sys 0.61.2",
5210 5210 ]
5211 5211
5212 5212 [[package]]
@@ -5263,7 +5263,7 @@
5263 5263 "security-framework",
5264 5264 "security-framework-sys",
5265 5265 "webpki-root-certs",
5266 - "windows-sys 0.60.2",
5266 + "windows-sys 0.61.2",
5267 5267 ]
5268 5268
5269 5269 [[package]]
@@ -5803,7 +5803,7 @@
5803 5803 checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4"
5804 5804 dependencies = [
5805 5805 "libc",
5806 - "windows-sys 0.60.2",
5806 + "windows-sys 0.61.2",
5807 5807 ]
5808 5808
5809 5809 [[package]]
@@ -6578,7 +6578,7 @@
6578 6578 "getrandom 0.4.3",
6579 6579 "once_cell",
6580 6580 "rustix",
6581 - "windows-sys 0.60.2",
6581 + "windows-sys 0.61.2",
6582 6582 ]
6583 6583
6584 6584 [[package]]
@@ -6600,7 +6600,7 @@
6600 6600 "parking_lot",
6601 6601 "rustix",
6602 6602 "signal-hook",
6603 - "windows-sys 0.60.2",
6603 + "windows-sys 0.61.2",
6604 6604 ]
6605 6605
6606 6606 [[package]]
@@ -7082,7 +7082,7 @@
7082 7082 "png 0.18.1",
7083 7083 "serde",
7084 7084 "thiserror 2.0.20",
7085 - "windows-sys 0.60.2",
7085 + "windows-sys 0.61.2",
7086 7086 ]
7087 7087
7088 7088 [[package]]
@@ -7117,7 +7117,7 @@
7117 7117 dependencies = [
7118 7118 "memoffset",
7119 7119 "tempfile",
7120 - "windows-sys 0.60.2",
7120 + "windows-sys 0.61.2",
7121 7121 ]
7122 7122
7123 7123 [[package]]
@@ -7647,7 +7647,7 @@
7647 7647 source = "registry+https://github.com/rust-lang/crates.io-index"
7648 7648 checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
7649 7649 dependencies = [
7650 - "windows-sys 0.60.2",
7650 + "windows-sys 0.61.2",
7651 7651 ]
7652 7652
7653 7653 [[package]]
@@ -8506,15 +8506,15 @@
8506 8506
8507 8507 [[patch.unused]]
8508 8508 name = "quasi-axum"
8509 - version = "0.67.0"
8509 + version = "0.68.0"
8510 8510
8511 8511 [[patch.unused]]
8512 8512 name = "quasi-basics"
8513 - version = "0.67.0"
8513 + version = "0.68.0"
8514 8514
8515 8515 [[patch.unused]]
8516 8516 name = "quasi-immediate"
8517 - version = "0.67.0"
8517 + version = "0.68.0"
8518 8518
8519 8519 [[patch.unused]]
8520 8520 name = "quasi-store"
@@ -36,7 +36,7 @@
36 36 makeover-geometry = "0.7"
37 37 # Only to write its selection and clock scripts into the frontend. Those two are
38 38 # the whole of `frontend/js/` since the swap.
39 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.67" }
39 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.68" }
40 40
41 41 [dependencies]
42 42 goingson-core = { workspace = true }
@@ -54,10 +54,10 @@
54 54 # dependency's source even with the feature off -- so a public clone could not
55 55 # build at all against a URL it could not reach. quasi went public that day and
56 56 # the URL moved here with it.
57 - quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.67" }
58 - quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.67" }
59 - quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.67" }
60 - quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.67" }
57 + quasi-router = { git = "https://makenot.work/git/max/quasi.git", version = "0.68" }
58 + quasi-http = { git = "https://makenot.work/git/max/quasi.git", version = "0.68" }
59 + quasi-webview = { git = "https://makenot.work/git/max/quasi.git", version = "0.68" }
60 + quasi-tauri = { git = "https://makenot.work/git/max/quasi.git", version = "0.68" }
61 61
62 62 # The notification declaration, and it is NOT behind the `quasi` feature: the
63 63 # watcher is desktop app behaviour rather than a described screen, and the
@@ -74,7 +74,7 @@
74 74 # before it has ported its screens cannot take it. `notifications::Notifier` is
75 75 # the eight lines meanwhile, and it goes when the flip makes quasi-router
76 76 # unconditional here.
77 - quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.67", features = ["synckit", "describe"] }
77 + quasi-notifs = { git = "https://makenot.work/git/max/quasi.git", version = "0.68", features = ["synckit", "describe"] }
78 78
79 79 # Tauri
80 80 tauri = { workspace = true, features = ["image-png", "devtools"] }
@@ -613,6 +613,7 @@
613 613 ("quasi-download.js", quasi_webview::DOWNLOAD_JS),
614 614 ("quasi-fill.js", quasi_webview::FILL_JS),
615 615 ("quasi-reveal.js", quasi_webview::REVEAL_JS),
616 + ("quasi-copy.js", quasi_webview::COPY_JS),
616 617 ("quasi-repeat.js", quasi_webview::REPEAT_JS),
617 618 ("quasi-awaiting.js", quasi_webview::AWAITING_JS),
618 619 ] {
@@ -1,0 +1,73 @@
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 write = async (text) => {
35 + try {
36 + if (navigator.clipboard?.writeText) {
37 + await navigator.clipboard.writeText(text);
38 + return;
39 + }
40 + } catch {
41 + // Fall through: refused, or no permission. The fallback below does
42 + // not ask for one.
43 + }
44 +
45 + const carrier = document.createElement("textarea");
46 + carrier.value = text;
47 + // Off-screen rather than hidden: a `display: none` element cannot be
48 + // selected, and selecting is the whole mechanism here.
49 + carrier.setAttribute("readonly", "");
50 + carrier.style.position = "fixed";
51 + carrier.style.top = "-9999px";
52 + document.body.appendChild(carrier);
53 + carrier.select();
54 + try {
55 + document.execCommand("copy");
56 + } catch {
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.remove();
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.addEventListener("click", (event) => {
67 + const control = event.target?.closest?.(`[${VALUE}]`);
68 + if (!control) {
69 + return;
70 + }
71 + void write(control.getAttribute(VALUE) ?? "");
72 + });
73 + })();