rastrillo / fiesta Public

Clone
git clone https://amadan.net/rastrillo/fiesta

Plain git — no account needed to clone.

Download

Download this file

1/*! Fiesta 1.2.0 | MPL-2.0 | https://fiesta.rastrillo.org */
2(function () {
3 "use strict";
4
5 if (window.fiestaCopy) return;
6 window.fiestaCopy = true;
7
8 if (typeof navigator.clipboard?.writeText !== "function") return;
9
10 var BOX = "[rst-snippet],.rst-snippet";
11 var BUTTON = "[rst-snippet-copy],.rst-snippet__copy";
12 var STATUS = "[rst-snippet-status],.rst-snippet__status";
13 var SHOWN_MS = 2000;
14 var SPEAK_MS = 100;
15
16
17 function fiestaPickLang(tag, registry) {
18 var want = String(tag || "").toLowerCase();
19 if (!want) return null;
20 var keys = Object.keys(registry || {}), i;
21 for (i = 0; i < keys.length; i++) {
22 if (keys[i].toLowerCase() === want) return keys[i];
23 }
24 var primary = want.split("-")[0];
25 for (i = 0; i < keys.length; i++) {
26 if (keys[i].toLowerCase().split("-")[0] === primary) return keys[i];
27 }
28 return null;
29 }
30
31 function fiestaWord(el, key, fallback) {
32 var v = el.getAttribute("data-rst-" + key);
33 if (v !== null && v !== "") return v;
34 var registry = (typeof self !== "undefined" && self.fiestaStrings) || {};
35 var lang = fiestaPickLang(document.documentElement.lang, registry);
36 var table = lang ? registry[lang] : null;
37 return table && table[key] !== undefined && table[key] !== "" ? table[key] : fallback;
38 }
39
40 var buttons = new WeakMap();
41 function state(button) {
42 var s = buttons.get(button);
43 if (!s) {
44 s = { label: button.textContent, latest: 0, reset: 0, speak: 0 };
45 buttons.set(button, s);
46 }
47 return s;
48 }
49
50 function select(code) {
51 var range = document.createRange(), selection = window.getSelection();
52 range.selectNodeContents(code);
53 selection.removeAllRanges();
54 selection.addRange(range);
55 }
56
57 function say(s, n, status, text) {
58 if (!status) return;
59 s.speak = setTimeout(function () {
60 if (n === s.latest) status.textContent = text;
61 }, SPEAK_MS);
62 }
63
64 function copy(button, box, code) {
65 var s = state(button), n = ++s.latest, status = box.querySelector(STATUS), write;
66 clearTimeout(s.reset);
67 clearTimeout(s.speak);
68 button.textContent = s.label;
69 if (status) status.textContent = "";
70 try {
71 write = Promise.resolve(navigator.clipboard.writeText(code.textContent));
72 } catch (err) {
73 write = Promise.reject(err);
74 }
75 write.then(function () {
76 if (n !== s.latest) return;
77 var done = fiestaWord(button, "copy-done", "Copied");
78 button.textContent = done;
79 s.reset = setTimeout(function () {
80 if (n === s.latest) button.textContent = s.label;
81 }, SHOWN_MS);
82 say(s, n, status, done);
83 }, function () {
84 if (n !== s.latest) return;
85 select(code);
86 say(s, n, status, fiestaWord(button, "copy-failed", "Copy failed. Select the code and copy it yourself."));
87 });
88 }
89
90 function show() {
91 document.querySelectorAll(BUTTON).forEach(function (button) {
92 state(button);
93 button.hidden = false;
94 });
95 }
96 if (document.readyState === "loading") {
97 document.addEventListener("DOMContentLoaded", show);
98 } else {
99 show();
100 }
101
102 document.addEventListener("click", function (e) {
103 var button = e.target && e.target.closest ? e.target.closest(BUTTON) : null;
104 var box = button && button.closest(BOX);
105 var code = box && box.querySelector("code");
106 if (code) copy(button, box, code);
107 });
108})();
109