///|
const STATUS_NOT_AVAILABLE : Int = 1
///|
const STATUS_PERMISSION_DENIED : Int = 2
///|
const STATUS_BACKEND_FAILURE : Int = 3
///|
async fn[T, E : Error] suspend(
f : ((T) -> Unit, (E) -> Unit) -> Unit,
) -> T raise E = "%async.suspend"
///|
extern "js" fn js_read_text(
on_ok : (String) -> Unit,
on_err : (Int, String) -> Unit,
) -> Unit =
#|(onOk, onErr) => {
#| const g = globalThis;
#| const api = g?.navigator?.clipboard;
#| const isBrowser = !!api && typeof api.readText === "function";
#| if (isBrowser) {
#| api.readText().then(
#| (text) => onOk(String(text)),
#| (err) => {
#| const name = err && err.name ? String(err.name) : "";
#| const message = err && err.message ? String(err.message) : String(err);
#| if (name === "NotAllowedError" || name === "SecurityError") {
#| onErr(2, message);
#| } else {
#| onErr(3, message);
#| }
#| }
#| );
#| return;
#| }
#| const isNode = !!g?.process?.versions?.node;
#| if (!isNode) {
#| onErr(1, "Clipboard API is unavailable");
#| return;
#| }
#| const loadClipboardy =
#| typeof require === "function"
#| ? Promise.resolve().then(() => require("clipboardy"))
#| : import("clipboardy");
#| loadClipboardy
#| .then((mod) => {
#| const clipboardy = mod && mod.default ? mod.default : mod;
#| if (!clipboardy || typeof clipboardy.read !== "function") {
#| throw { name: "ClipboardUnavailable", message: "clipboardy.read is unavailable" };
#| }
#| return clipboardy.read();
#| })
#| .then(
#| (text) => onOk(String(text)),
#| (err) => {
#| const code = err && err.code ? String(err.code) : "";
#| const name = err && err.name ? String(err.name) : "";
#| const message = err && err.message ? String(err.message) : String(err);
#| if (
#| code === "MODULE_NOT_FOUND" ||
#| code === "ERR_MODULE_NOT_FOUND" ||
#| name === "ClipboardUnavailable"
#| ) {
#| onErr(1, message);
#| } else if (name === "NotAllowedError" || name === "SecurityError") {
#| onErr(2, message);
#| } else {
#| onErr(3, message);
#| }
#| }
#| );
#|}
///|
extern "js" fn js_write_text(
text : String,
on_ok : () -> Unit,
on_err : (Int, String) -> Unit,
) -> Unit =
#|(text, onOk, onErr) => {
#| const g = globalThis;
#| const api = g?.navigator?.clipboard;
#| const isBrowser = !!api && typeof api.writeText === "function";
#| if (isBrowser) {
#| api.writeText(text).then(
#| () => onOk(),
#| (err) => {
#| const name = err && err.name ? String(err.name) : "";
#| const message = err && err.message ? String(err.message) : String(err);
#| if (name === "NotAllowedError" || name === "SecurityError") {
#| onErr(2, message);
#| } else {
#| onErr(3, message);
#| }
#| }
#| );
#| return;
#| }
#| const isNode = !!g?.process?.versions?.node;
#| if (!isNode) {
#| onErr(1, "Clipboard API is unavailable");
#| return;
#| }
#| const loadClipboardy =
#| typeof require === "function"
#| ? Promise.resolve().then(() => require("clipboardy"))
#| : import("clipboardy");
#| loadClipboardy
#| .then((mod) => {
#| const clipboardy = mod && mod.default ? mod.default : mod;
#| if (!clipboardy || typeof clipboardy.write !== "function") {
#| throw { name: "ClipboardUnavailable", message: "clipboardy.write is unavailable" };
#| }
#| return clipboardy.write(text);
#| })
#| .then(
#| () => onOk(),
#| (err) => {
#| const code = err && err.code ? String(err.code) : "";
#| const name = err && err.name ? String(err.name) : "";
#| const message = err && err.message ? String(err.message) : String(err);
#| if (
#| code === "MODULE_NOT_FOUND" ||
#| code === "ERR_MODULE_NOT_FOUND" ||
#| name === "ClipboardUnavailable"
#| ) {
#| onErr(1, message);
#| } else if (name === "NotAllowedError" || name === "SecurityError") {
#| onErr(2, message);
#| } else {
#| onErr(3, message);
#| }
#| }
#| );
#|}
///|
fn raise_for_status(
status : Int,
message : String,
) -> Unit raise ClipboardError {
match status {
0 => ()
STATUS_NOT_AVAILABLE => raise NotAvailable
STATUS_PERMISSION_DENIED => raise PermissionDenied
STATUS_BACKEND_FAILURE => raise BackendFailure(message)
_ => raise BackendFailure(message)
}
}
///|
async fn read_text_async_impl() -> String raise ClipboardError {
suspend((resume_ok, resume_err) => {
js_read_text(resume_ok, (status, message) => {
try {
raise_for_status(status, message)
resume_ok("")
} catch {
err => resume_err(err)
}
})
})
}
///|
async fn write_text_async_impl(text : String) -> Unit raise ClipboardError {
suspend((resume_ok, resume_err) => {
js_write_text(text, () => resume_ok(()), (status, message) => {
try {
raise_for_status(status, message)
resume_ok(())
} catch {
err => resume_err(err)
}
})
})
}