diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1a7eb7e3b..06f2f48f9 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,6 +2,9 @@ on: [push, pull_request] name: CI +env: + RUSTFLAGS: --cfg=web_sys_unstable_apis + jobs: check: name: Check diff --git a/Cargo.lock b/Cargo.lock index 68f206466..6854f607e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -561,6 +561,7 @@ dependencies = [ "serde", "serde_json", "wasm-bindgen", + "wasm-bindgen-futures", "web-sys", ] @@ -1578,6 +1579,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" +dependencies = [ + "cfg-if 0.1.10", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.68" diff --git a/TODO.md b/TODO.md index 3b380942b..f95d08355 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ TODO-list for the Egui project. If you looking for something to do, look here. ## Top priority -* Egui-web copy-paste * Egui-web fetch ## Other @@ -83,7 +82,7 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [x] Change to resize cursor on hover * [x] Port most code to Rust * [x] Read url fragment and redirect to a subpage (e.g. different examples apps)] -* [ ] Copy/paste support +* [x] Copy/paste support * [ ] Async HTTP requests * [ ] Fix WebGL colors/blending (try EXT_sRGB) * [ ] Embeddability diff --git a/build_web.sh b/build_web.sh index b79452318..4f5917be7 100755 --- a/build_web.sh +++ b/build_web.sh @@ -12,6 +12,8 @@ fi # BUILD=debug BUILD=release +export RUSTFLAGS=--cfg=web_sys_unstable_apis # required for the clipboard API + # Clear output from old stuff: rm -rf docs/*.wasm diff --git a/check.sh b/check.sh index a7f312215..1058d44cb 100755 --- a/check.sh +++ b/check.sh @@ -1,6 +1,8 @@ #!/bin/bash set -eu +export RUSTFLAGS=--cfg=web_sys_unstable_apis # required for the clipboard API + cargo check --workspace --all-targets --all-features --release cargo fmt --all -- --check CARGO_INCREMENTAL=0 cargo clippy --workspace --all-targets --all-features -- -D warnings -W clippy::all #-W clippy::pedantic -W clippy::restriction -W clippy::nursery diff --git a/docs/demo_web.js b/docs/demo_web.js index bb9ec0727..9dcc65fe6 100644 --- a/docs/demo_web.js +++ b/docs/demo_web.js @@ -221,19 +221,27 @@ function __wbg_adapter_27(arg0, arg1) { } function __wbg_adapter_30(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c48a81a2a124c76(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h263b0f4bde31efb0(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_33(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c48a81a2a124c76(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h263b0f4bde31efb0(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_36(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c48a81a2a124c76(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h263b0f4bde31efb0(arg0, arg1, addHeapObject(arg2)); } function __wbg_adapter_39(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5c48a81a2a124c76(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h263b0f4bde31efb0(arg0, arg1, addHeapObject(arg2)); +} + +function __wbg_adapter_42(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h263b0f4bde31efb0(arg0, arg1, addHeapObject(arg2)); +} + +function __wbg_adapter_45(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hd5c13e870f8bfcb3(arg0, arg1, addHeapObject(arg2)); } /** @@ -334,6 +342,10 @@ async function init(input) { var ret = getObject(arg0).location; return addHeapObject(ret); }; + imports.wbg.__wbg_navigator_71c234326c0a2ebb = function(arg0) { + var ret = getObject(arg0).navigator; + return addHeapObject(ret); + }; imports.wbg.__wbg_innerWidth_60241abd729ed26f = handleError(function(arg0) { var ret = getObject(arg0).innerWidth; return addHeapObject(ret); @@ -370,52 +382,99 @@ async function init(input) { var ret = getObject(arg0).getElementById(getStringFromWasm0(arg1, arg2)); return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_touches_1cfb9ad18bd08588 = function(arg0) { - var ret = getObject(arg0).touches; - return addHeapObject(ret); + imports.wbg.__wbg_now_49847177a6d1d57e = function(arg0) { + var ret = getObject(arg0).now(); + return ret; + }; + imports.wbg.__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3 = function(arg0) { + var ret = getObject(arg0) instanceof HTMLCanvasElement; + return ret; + }; + imports.wbg.__wbg_width_a22f9855caa54b53 = function(arg0) { + var ret = getObject(arg0).width; + return ret; + }; + imports.wbg.__wbg_setwidth_5f26a8ba9dbfa0d0 = function(arg0, arg1) { + getObject(arg0).width = arg1 >>> 0; + }; + imports.wbg.__wbg_height_9a404a6b3c61c7ef = function(arg0) { + var ret = getObject(arg0).height; + return ret; + }; + imports.wbg.__wbg_setheight_70f62727aa9383c2 = function(arg0, arg1) { + getObject(arg0).height = arg1 >>> 0; + }; + imports.wbg.__wbg_getContext_37ca0870acb096d9 = handleError(function(arg0, arg1, arg2) { + var ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2)); + return isLikeNone(ret) ? 0 : addHeapObject(ret); + }); + imports.wbg.__wbg_pageX_234547d8f89fd3d0 = function(arg0) { + var ret = getObject(arg0).pageX; + return ret; + }; + imports.wbg.__wbg_pageY_4f94b607e8f1a8a2 = function(arg0) { + var ret = getObject(arg0).pageY; + return ret; }; imports.wbg.__wbg_get_814461b8584a55e7 = function(arg0, arg1) { var ret = getObject(arg0)[arg1 >>> 0]; return isLikeNone(ret) ? 0 : addHeapObject(ret); }; - imports.wbg.__wbg_top_a6f8db7db6d2bf17 = function(arg0) { - var ret = getObject(arg0).top; + imports.wbg.__wbg_keyCode_689d196ab65a93d7 = function(arg0) { + var ret = getObject(arg0).keyCode; return ret; }; - imports.wbg.__wbg_left_b19dce37a1320f04 = function(arg0) { - var ret = getObject(arg0).left; + imports.wbg.__wbg_altKey_1b58e09f218a0f4b = function(arg0) { + var ret = getObject(arg0).altKey; return ret; }; - imports.wbg.__wbg_hash_1e68d402e53cef74 = handleError(function(arg0, arg1) { - var ret = getObject(arg1).hash; + imports.wbg.__wbg_ctrlKey_f080ec163dcc2703 = function(arg0) { + var ret = getObject(arg0).ctrlKey; + return ret; + }; + imports.wbg.__wbg_shiftKey_d11f615955404512 = function(arg0) { + var ret = getObject(arg0).shiftKey; + return ret; + }; + imports.wbg.__wbg_metaKey_9bc40bb1d5972ef2 = function(arg0) { + var ret = getObject(arg0).metaKey; + return ret; + }; + imports.wbg.__wbg_isComposing_c0f97b8c3f5992b5 = function(arg0) { + var ret = getObject(arg0).isComposing; + return ret; + }; + imports.wbg.__wbg_key_590d4d2a765d1b58 = function(arg0, arg1) { + var ret = getObject(arg1).key; var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len0 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len0; getInt32Memory0()[arg0 / 4 + 0] = ptr0; - }); - imports.wbg.__wbg_setProperty_42eabadfcd7d6199 = handleError(function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).setProperty(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); - }); - imports.wbg.__wbg_addEventListener_9e7b0c3f65ebc0d7 = handleError(function(arg0, arg1, arg2, arg3) { - getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); - }); - imports.wbg.__wbg_getItem_cb17cd47353971da = handleError(function(arg0, arg1, arg2, arg3) { - var ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); - var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + }; + imports.wbg.__wbg_touches_1cfb9ad18bd08588 = function(arg0) { + var ret = getObject(arg0).touches; + return addHeapObject(ret); + }; + imports.wbg.__wbg_getData_0a2347233cf89d01 = handleError(function(arg0, arg1, arg2, arg3) { + var ret = getObject(arg1).getData(getStringFromWasm0(arg2, arg3)); + var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len0 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len0; getInt32Memory0()[arg0 / 4 + 0] = ptr0; }); - imports.wbg.__wbg_setItem_71df4161bb87d575 = handleError(function(arg0, arg1, arg2, arg3, arg4) { - getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); - }); - imports.wbg.__wbg_deltaX_ee242e8414135d41 = function(arg0) { - var ret = getObject(arg0).deltaX; - return ret; + imports.wbg.__wbg_preventDefault_93d06688748bfc14 = function(arg0) { + getObject(arg0).preventDefault(); }; - imports.wbg.__wbg_deltaY_35bf8632b9f25820 = function(arg0) { - var ret = getObject(arg0).deltaY; - return ret; + imports.wbg.__wbg_stopPropagation_a47dd3b6ffe6b400 = function(arg0) { + getObject(arg0).stopPropagation(); + }; + imports.wbg.__wbg_clipboardData_d3dc621a701f9c49 = function(arg0) { + var ret = getObject(arg0).clipboardData; + return isLikeNone(ret) ? 0 : addHeapObject(ret); + }; + imports.wbg.__wbg_clipboard_7862c97f3561ff94 = function(arg0) { + var ret = getObject(arg0).clipboard; + return addHeapObject(ret); }; imports.wbg.__wbg_getBoundingClientRect_c6d612c06726983e = function(arg0) { var ret = getObject(arg0).getBoundingClientRect(); @@ -547,69 +606,57 @@ async function init(input) { var ret = getObject(arg0).style; return addHeapObject(ret); }; - imports.wbg.__wbg_clientX_c1a2c3a6a07188a2 = function(arg0) { - var ret = getObject(arg0).clientX; - return ret; - }; - imports.wbg.__wbg_clientY_090f8ba07f76875d = function(arg0) { - var ret = getObject(arg0).clientY; - return ret; - }; - imports.wbg.__wbg_now_49847177a6d1d57e = function(arg0) { - var ret = getObject(arg0).now(); - return ret; - }; - imports.wbg.__wbg_pageX_234547d8f89fd3d0 = function(arg0) { - var ret = getObject(arg0).pageX; - return ret; - }; - imports.wbg.__wbg_pageY_4f94b607e8f1a8a2 = function(arg0) { - var ret = getObject(arg0).pageY; - return ret; - }; - imports.wbg.__wbg_keyCode_689d196ab65a93d7 = function(arg0) { - var ret = getObject(arg0).keyCode; + imports.wbg.__wbg_top_a6f8db7db6d2bf17 = function(arg0) { + var ret = getObject(arg0).top; return ret; }; - imports.wbg.__wbg_isComposing_c0f97b8c3f5992b5 = function(arg0) { - var ret = getObject(arg0).isComposing; + imports.wbg.__wbg_left_b19dce37a1320f04 = function(arg0) { + var ret = getObject(arg0).left; return ret; }; - imports.wbg.__wbg_key_590d4d2a765d1b58 = function(arg0, arg1) { - var ret = getObject(arg1).key; + imports.wbg.__wbg_setProperty_42eabadfcd7d6199 = handleError(function(arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).setProperty(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }); + imports.wbg.__wbg_hash_1e68d402e53cef74 = handleError(function(arg0, arg1) { + var ret = getObject(arg1).hash; var ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); var len0 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len0; getInt32Memory0()[arg0 / 4 + 0] = ptr0; - }; - imports.wbg.__wbg_preventDefault_93d06688748bfc14 = function(arg0) { - getObject(arg0).preventDefault(); - }; - imports.wbg.__wbg_stopPropagation_a47dd3b6ffe6b400 = function(arg0) { - getObject(arg0).stopPropagation(); - }; - imports.wbg.__wbg_instanceof_HtmlCanvasElement_4f5b5ec6cd53ccf3 = function(arg0) { - var ret = getObject(arg0) instanceof HTMLCanvasElement; + }); + imports.wbg.__wbg_getItem_cb17cd47353971da = handleError(function(arg0, arg1, arg2, arg3) { + var ret = getObject(arg1).getItem(getStringFromWasm0(arg2, arg3)); + var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len0 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len0; + getInt32Memory0()[arg0 / 4 + 0] = ptr0; + }); + imports.wbg.__wbg_setItem_71df4161bb87d575 = handleError(function(arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).setItem(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }); + imports.wbg.__wbg_clientX_c1a2c3a6a07188a2 = function(arg0) { + var ret = getObject(arg0).clientX; return ret; }; - imports.wbg.__wbg_width_a22f9855caa54b53 = function(arg0) { - var ret = getObject(arg0).width; + imports.wbg.__wbg_clientY_090f8ba07f76875d = function(arg0) { + var ret = getObject(arg0).clientY; return ret; }; - imports.wbg.__wbg_setwidth_5f26a8ba9dbfa0d0 = function(arg0, arg1) { - getObject(arg0).width = arg1 >>> 0; + imports.wbg.__wbg_writeText_f87e9b63346a7e47 = function(arg0, arg1, arg2) { + var ret = getObject(arg0).writeText(getStringFromWasm0(arg1, arg2)); + return addHeapObject(ret); }; - imports.wbg.__wbg_height_9a404a6b3c61c7ef = function(arg0) { - var ret = getObject(arg0).height; + imports.wbg.__wbg_addEventListener_9e7b0c3f65ebc0d7 = handleError(function(arg0, arg1, arg2, arg3) { + getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); + }); + imports.wbg.__wbg_deltaX_ee242e8414135d41 = function(arg0) { + var ret = getObject(arg0).deltaX; return ret; }; - imports.wbg.__wbg_setheight_70f62727aa9383c2 = function(arg0, arg1) { - getObject(arg0).height = arg1 >>> 0; + imports.wbg.__wbg_deltaY_35bf8632b9f25820 = function(arg0) { + var ret = getObject(arg0).deltaY; + return ret; }; - imports.wbg.__wbg_getContext_37ca0870acb096d9 = handleError(function(arg0, arg1, arg2) { - var ret = getObject(arg0).getContext(getStringFromWasm0(arg1, arg2)); - return isLikeNone(ret) ? 0 : addHeapObject(ret); - }); imports.wbg.__wbg_call_8e95613cc6524977 = handleError(function(arg0, arg1) { var ret = getObject(arg0).call(getObject(arg1)); return addHeapObject(ret); @@ -642,6 +689,18 @@ async function init(input) { var ret = new Date(); return addHeapObject(ret); }; + imports.wbg.__wbg_resolve_2529512c3bb73938 = function(arg0) { + var ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_then_4a7a614abbbe6d81 = function(arg0, arg1) { + var ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_then_3b7ac098cfda2fa5 = function(arg0, arg1, arg2) { + var ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }; imports.wbg.__wbg_self_07b2f89e82ceb76d = handleError(function() { var ret = self.self; return addHeapObject(ret); @@ -722,28 +781,36 @@ async function init(input) { var ret = wasm.memory; return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper203 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_24); + imports.wbg.__wbindgen_closure_wrapper398 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_24); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_closure_wrapper399 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_27); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_closure_wrapper402 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_30); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper204 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_27); + imports.wbg.__wbindgen_closure_wrapper404 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_33); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper207 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_30); + imports.wbg.__wbindgen_closure_wrapper406 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_36); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper209 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_33); + imports.wbg.__wbindgen_closure_wrapper408 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_39); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper211 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_36); + imports.wbg.__wbindgen_closure_wrapper410 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 86, __wbg_adapter_42); return addHeapObject(ret); }; - imports.wbg.__wbindgen_closure_wrapper213 = function(arg0, arg1, arg2) { - var ret = makeMutClosure(arg0, arg1, 41, __wbg_adapter_39); + imports.wbg.__wbindgen_closure_wrapper452 = function(arg0, arg1, arg2) { + var ret = makeMutClosure(arg0, arg1, 106, __wbg_adapter_45); return addHeapObject(ret); }; diff --git a/docs/demo_web_bg.wasm b/docs/demo_web_bg.wasm index 710815a23..5e7156a4e 100644 Binary files a/docs/demo_web_bg.wasm and b/docs/demo_web_bg.wasm differ diff --git a/egui_web/Cargo.toml b/egui_web/Cargo.toml index 3928dd19d..40d4b1d9d 100644 --- a/egui_web/Cargo.toml +++ b/egui_web/Cargo.toml @@ -22,12 +22,16 @@ parking_lot = "0.11" serde = "1" serde_json = "1" wasm-bindgen = "0.2" +wasm-bindgen-futures = "0.4" [dependencies.web-sys] version = "0.3" features = [ + 'Clipboard', + 'ClipboardEvent', 'console', 'CssStyleDeclaration', + 'DataTransfer', 'Document', 'DomRect', 'Element', @@ -36,6 +40,7 @@ features = [ 'KeyboardEvent', 'Location', 'MouseEvent', + 'Navigator', 'Performance', 'Storage', 'Touch', diff --git a/egui_web/src/lib.rs b/egui_web/src/lib.rs index 66df5aa7c..571df05ab 100644 --- a/egui_web/src/lib.rs +++ b/egui_web/src/lib.rs @@ -134,7 +134,7 @@ pub fn save_memory(ctx: &egui::Context) { } Err(err) => { console_log(format!( - "ERROR: Failed to seriealize memory as json: {}", + "ERROR: Failed to serialize memory as json: {}", err )); } @@ -142,9 +142,20 @@ pub fn save_memory(ctx: &egui::Context) { } pub fn handle_output(output: &egui::Output) { - set_cursor_icon(output.cursor_icon); - if let Some(url) = &output.open_url { - open_url(url); + let egui::Output { + cursor_icon, + open_url, + copied_text, + needs_repaint: _, // handled elsewhere + } = output; + + set_cursor_icon(*cursor_icon); + if let Some(url) = open_url { + crate::open_url(url); + } + + if !copied_text.is_empty() { + set_clipboard_text(copied_text); } } @@ -157,6 +168,20 @@ pub fn set_cursor_icon(cursor: egui::CursorIcon) -> Option<()> { .ok() } +pub fn set_clipboard_text(s: &str) { + if let Some(window) = web_sys::window() { + let clipboard = window.navigator().clipboard(); + let promise = clipboard.write_text(s); + let future = wasm_bindgen_futures::JsFuture::from(promise); + let future = async move { + if let Err(err) = future.await { + console_log(format!("Copy/cut action denied: {:?}", err)); + } + }; + wasm_bindgen_futures::spawn_local(future); + } +} + fn cursor_web_name(cursor: egui::CursorIcon) -> &'static str { use egui::CursorIcon::*; match cursor { @@ -335,6 +360,46 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { closure.forget(); } + { + // paste + let runner_ref = runner_ref.clone(); + let closure = Closure::wrap(Box::new(move |event: web_sys::ClipboardEvent| { + if let Some(data) = event.clipboard_data() { + if let Ok(text) = data.get_data("text") { + let mut runner_lock = runner_ref.0.lock(); + runner_lock.input.raw.events.push(egui::Event::Text(text)); + runner_lock.needs_repaint = true; + } + } + }) as Box); + document.add_event_listener_with_callback("paste", closure.as_ref().unchecked_ref())?; + closure.forget(); + } + + { + // cut + let runner_ref = runner_ref.clone(); + let closure = Closure::wrap(Box::new(move |_: web_sys::ClipboardEvent| { + let mut runner_lock = runner_ref.0.lock(); + runner_lock.input.raw.events.push(egui::Event::Cut); + runner_lock.needs_repaint = true; + }) as Box); + document.add_event_listener_with_callback("cut", closure.as_ref().unchecked_ref())?; + closure.forget(); + } + + { + // copy + let runner_ref = runner_ref.clone(); + let closure = Closure::wrap(Box::new(move |_: web_sys::ClipboardEvent| { + let mut runner_lock = runner_ref.0.lock(); + runner_lock.input.raw.events.push(egui::Event::Copy); + runner_lock.needs_repaint = true; + }) as Box); + document.add_event_listener_with_callback("copy", closure.as_ref().unchecked_ref())?; + closure.forget(); + } + for event_name in &["load", "pagehide", "pageshow", "resize"] { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move || {