feat: adds dynamic word retreival
looks like we're live :)
This commit is contained in:
parent
7553025731
commit
6b9e50ef43
@ -22,3 +22,4 @@ gloo-net = "0.6.0"
|
|||||||
serde = { version = "1.0.198", features = ["derive"] }
|
serde = { version = "1.0.198", features = ["derive"] }
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
|
tracing = "0.1.40"
|
||||||
|
10
frontend/dist/index.html
vendored
10
frontend/dist/index.html
vendored
@ -9,13 +9,13 @@
|
|||||||
|
|
||||||
<link rel="manifest" href="public/manifest.json" />
|
<link rel="manifest" href="public/manifest.json" />
|
||||||
|
|
||||||
<link rel="modulepreload" href="/wordl-frontend-fc53a686d7997e96.js" crossorigin=anonymous integrity="sha384-mYYngEqwNe/MByGAOghKzFvwKtcFKa49nvztLGp2bWtEr122LZIy90IwuEsz1d3/">
|
<link rel="modulepreload" href="/wordl-frontend-f12cb96db58e762c.js" crossorigin=anonymous integrity="sha384-bBxFiVwzR66Z1hv0ruG4aGTidjq8XBRcL0Crsv4fRIK6kj1hmLn4dH0tm6t9qsCH">
|
||||||
<link rel="preload" href="/wordl-frontend-fc53a686d7997e96_bg.wasm" crossorigin=anonymous integrity="sha384-91qkiGfY7l6p7THqCtyecHAhThTZ71cH0SN3l03GQI8qH7nFwZxck5c25JS+LlCd" as="fetch" type="application/wasm"></head>
|
<link rel="preload" href="/wordl-frontend-f12cb96db58e762c_bg.wasm" crossorigin=anonymous integrity="sha384-rH9nswm1hLZCk8ksVMGninp4DCq3b/MGGV6gv4p6gPvfWUVvNswadaIr2RbcyaNS" as="fetch" type="application/wasm"></head>
|
||||||
<body class="bg-black text-white">
|
<body class="bg-black text-white">
|
||||||
|
|
||||||
<script type="module" nonce="z1ycfrQCqxwlbyPwNQ2Ltg==">
|
<script type="module" nonce="FBx2FAPOfqu3mKchrgJ5jg==">
|
||||||
import init, * as bindings from '/wordl-frontend-fc53a686d7997e96.js';
|
import init, * as bindings from '/wordl-frontend-f12cb96db58e762c.js';
|
||||||
const wasm = await init('/wordl-frontend-fc53a686d7997e96_bg.wasm');
|
const wasm = await init('/wordl-frontend-f12cb96db58e762c_bg.wasm');
|
||||||
|
|
||||||
|
|
||||||
window.wasmBindings = bindings;
|
window.wasmBindings = bindings;
|
||||||
|
@ -20,6 +20,15 @@ function takeObject(idx) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addHeapObject(obj) {
|
||||||
|
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||||
|
const idx = heap_next;
|
||||||
|
heap_next = heap[idx];
|
||||||
|
|
||||||
|
heap[idx] = obj;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||||
|
|
||||||
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||||
@ -38,15 +47,6 @@ function getStringFromWasm0(ptr, len) {
|
|||||||
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
||||||
}
|
}
|
||||||
|
|
||||||
function addHeapObject(obj) {
|
|
||||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
|
||||||
const idx = heap_next;
|
|
||||||
heap_next = heap[idx];
|
|
||||||
|
|
||||||
heap[idx] = obj;
|
|
||||||
return idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
let WASM_VECTOR_LEN = 0;
|
let WASM_VECTOR_LEN = 0;
|
||||||
|
|
||||||
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
|
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
|
||||||
@ -324,14 +324,14 @@ function __wbg_get_imports() {
|
|||||||
const ret = false;
|
const ret = false;
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
|
||||||
const ret = getStringFromWasm0(arg0, arg1);
|
|
||||||
return addHeapObject(ret);
|
|
||||||
};
|
|
||||||
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
|
||||||
const ret = getObject(arg0);
|
const ret = getObject(arg0);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
|
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
|
||||||
|
const ret = getStringFromWasm0(arg0, arg1);
|
||||||
|
return addHeapObject(ret);
|
||||||
|
};
|
||||||
imports.wbg.__wbg_listenerid_6dcf1c62b7b7de58 = function(arg0, arg1) {
|
imports.wbg.__wbg_listenerid_6dcf1c62b7b7de58 = function(arg0, arg1) {
|
||||||
const ret = getObject(arg1).__yew_listener_id;
|
const ret = getObject(arg1).__yew_listener_id;
|
||||||
getDataViewMemory0().setInt32(arg0 + 4 * 1, isLikeNone(ret) ? 0 : ret, true);
|
getDataViewMemory0().setInt32(arg0 + 4 * 1, isLikeNone(ret) ? 0 : ret, true);
|
||||||
@ -435,11 +435,6 @@ function __wbg_get_imports() {
|
|||||||
wasm.__wbindgen_free(arg0, arg1 * 4, 4);
|
wasm.__wbindgen_free(arg0, arg1 * 4, 4);
|
||||||
console.error(...v0);
|
console.error(...v0);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbg_log_7c3433e130418e14 = function(arg0, arg1) {
|
|
||||||
var v0 = getArrayJsValueFromWasm0(arg0, arg1).slice();
|
|
||||||
wasm.__wbindgen_free(arg0, arg1 * 4, 4);
|
|
||||||
console.log(...v0);
|
|
||||||
};
|
|
||||||
imports.wbg.__wbg_fetch_eeae7120f2a07ede = function(arg0) {
|
imports.wbg.__wbg_fetch_eeae7120f2a07ede = function(arg0) {
|
||||||
const ret = fetch(getObject(arg0));
|
const ret = fetch(getObject(arg0));
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
@ -963,16 +958,16 @@ function __wbg_get_imports() {
|
|||||||
const ret = wasm.memory;
|
const ret = wasm.memory;
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper913 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper916 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeClosure(arg0, arg1, 370, __wbg_adapter_38);
|
const ret = makeClosure(arg0, arg1, 381, __wbg_adapter_38);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper1061 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper1023 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 417, __wbg_adapter_41);
|
const ret = makeMutClosure(arg0, arg1, 408, __wbg_adapter_41);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
imports.wbg.__wbindgen_closure_wrapper1155 = function(arg0, arg1, arg2) {
|
imports.wbg.__wbindgen_closure_wrapper1116 = function(arg0, arg1, arg2) {
|
||||||
const ret = makeMutClosure(arg0, arg1, 455, __wbg_adapter_44);
|
const ret = makeMutClosure(arg0, arg1, 446, __wbg_adapter_44);
|
||||||
return addHeapObject(ret);
|
return addHeapObject(ret);
|
||||||
};
|
};
|
||||||
|
|
BIN
frontend/dist/wordl-frontend-f12cb96db58e762c_bg.wasm
vendored
Normal file
BIN
frontend/dist/wordl-frontend-f12cb96db58e762c_bg.wasm
vendored
Normal file
Binary file not shown.
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
use gloo_console::log;
|
// use gloo_console::log;
|
||||||
|
use tracing::{debug, error, info};
|
||||||
use gloo_net::http::Request;
|
use gloo_net::http::Request;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use web_sys::wasm_bindgen::convert::OptionIntoWasmAbi;
|
use web_sys::wasm_bindgen::convert::OptionIntoWasmAbi;
|
||||||
@ -11,6 +12,7 @@ use yew::{classes, function_component, Callback, Html};
|
|||||||
use crate::CharStatus;
|
use crate::CharStatus;
|
||||||
|
|
||||||
static NEW_WORD_URI: &str = "https://wordl.shuttleapp.rs/word";
|
static NEW_WORD_URI: &str = "https://wordl.shuttleapp.rs/word";
|
||||||
|
static MAX_TRIES: usize = 5;
|
||||||
|
|
||||||
fn set_focus(index: usize) {
|
fn set_focus(index: usize) {
|
||||||
if let Some(w) = web_sys::window() {
|
if let Some(w) = web_sys::window() {
|
||||||
@ -100,114 +102,137 @@ fn string_to_html(input: &[CharStatus<String>]) -> Html {
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct Word(String);
|
struct Word(String);
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn get_word(handle: UseStateHandle<String>) {
|
fn get_word(handle: UseStateHandle<String>) {
|
||||||
use_effect_with((), move |()| {
|
use_effect_with((), move |()| {
|
||||||
// let word = handle.clone();
|
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
log!("retrieving word");
|
info!("retreiving word");
|
||||||
let res = Request::get(NEW_WORD_URI).send().await;
|
let res = Request::get(NEW_WORD_URI).send().await;
|
||||||
log!(format!("RESPONSE: {res:?}"));
|
debug!(RESULT = format!("{res:?}"));
|
||||||
match res {
|
match res {
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
log!(format!("{r:?}"));
|
debug!(RESPONSE = format!("{r:?}"));
|
||||||
match r.body() {
|
match r.text().await {
|
||||||
Some(j) => {
|
Ok(w) => {
|
||||||
let j = j.to_string();
|
debug!(WORD = &w);
|
||||||
let data = format!("{j:?}");
|
handle.set(w);
|
||||||
log!(&data);
|
|
||||||
handle.set(data);
|
|
||||||
}
|
}
|
||||||
None => log!("no body"),
|
Err(e) => error!(ERROR = format!("{e:?}"),"failed to get request body"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => log!(format!("FETCH: {e:?}")),
|
Err(e) => error!(ERROR = format!("{e:?}"),"failed to retreive word"),
|
||||||
}
|
}
|
||||||
// let res: Word = Request::get(NEW_WORD_URI).send().await.unwrap().json().await.unwrap();
|
|
||||||
// log!(res);
|
|
||||||
// handle.set(res.0);
|
|
||||||
// if let Ok(r) = res {
|
|
||||||
// if let Some(w) = r.body() {
|
|
||||||
|
|
||||||
// word.set(w.to_string());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
|| ()
|
|| ()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch_new_word(
|
||||||
|
word: &UseStateHandle<String>,
|
||||||
|
loading: &UseStateHandle<bool>,
|
||||||
|
submitted_words: &UseStateHandle<Vec<Vec<CharStatus<String>>>>,
|
||||||
|
input_values: &UseStateHandle<Vec<String>>,
|
||||||
|
game_over: &UseStateHandle<bool>,
|
||||||
|
length: &UseStateHandle<usize>,
|
||||||
|
node_refs: &UseStateHandle<Vec<NodeRef>>,
|
||||||
|
) {
|
||||||
|
let handle = word.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
let submitted_words = submitted_words.clone();
|
||||||
|
let input_values = input_values.clone();
|
||||||
|
let game_over = game_over.clone();
|
||||||
|
let length = length.clone();
|
||||||
|
let node_refs = node_refs.clone();
|
||||||
|
|
||||||
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
|
debug!("retrieving word");
|
||||||
|
let res = Request::get(NEW_WORD_URI).send().await;
|
||||||
|
debug!(RESULT = format!("{res:?}"));
|
||||||
|
match res {
|
||||||
|
Ok(r) => {
|
||||||
|
debug!(RESPONSE = format!("{r:?}"));
|
||||||
|
match r.text().await {
|
||||||
|
Ok(w) => {
|
||||||
|
debug!(WORD = &w);
|
||||||
|
length.set(w.len());
|
||||||
|
node_refs.set(vec![NodeRef::default(); w.len()]);
|
||||||
|
input_values.set(vec![String::new(); w.len()]);
|
||||||
|
handle.set(w.to_uppercase());
|
||||||
|
submitted_words.set(Vec::with_capacity(MAX_TRIES));
|
||||||
|
game_over.set(false);
|
||||||
|
loading.set(false);
|
||||||
|
}
|
||||||
|
Err(e) => error!(ERROR = format!("{e:?}"), "failed to get request body"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => error!(ERROR = format!("{e:?}"), "failed to retrieve word"),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[function_component]
|
#[function_component]
|
||||||
pub fn Home() -> Html {
|
pub fn Home() -> Html {
|
||||||
// let got_word = "HALLO";
|
|
||||||
// let length = got_word.len();
|
|
||||||
log!("STARTING");
|
|
||||||
|
|
||||||
let word: UseStateHandle<String> = use_state(String::new);
|
let word: UseStateHandle<String> = use_state(String::new);
|
||||||
|
let loading: UseStateHandle<bool> = use_state(|| true);
|
||||||
|
|
||||||
// get_word(word.clone());
|
let length = use_state(|| 0usize);
|
||||||
|
let submitted_words: UseStateHandle<Vec<Vec<CharStatus<String>>>> =
|
||||||
|
use_state(|| std::vec::Vec::with_capacity(MAX_TRIES));
|
||||||
|
|
||||||
|
let node_refs = use_state(|| vec![NodeRef::default(); 10]);
|
||||||
|
let input_values: UseStateHandle<Vec<String>> = use_state(|| vec![String::new(); *length]);
|
||||||
|
let game_over = use_state(|| false);
|
||||||
|
|
||||||
{
|
{
|
||||||
let handle = word.clone();
|
let handle = word.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
|
||||||
|
let submitted_words = submitted_words.clone();
|
||||||
|
let input_values = input_values.clone();
|
||||||
|
let game_over = game_over.clone();
|
||||||
|
let length = length.clone();
|
||||||
|
let node_refs = node_refs.clone();
|
||||||
|
|
||||||
use_effect_with((), move |()| {
|
use_effect_with((), move |()| {
|
||||||
// let word = handle.clone();
|
|
||||||
wasm_bindgen_futures::spawn_local(async move {
|
wasm_bindgen_futures::spawn_local(async move {
|
||||||
log!("retrieving word");
|
debug!("retreiving word");
|
||||||
let res = Request::get(NEW_WORD_URI).send().await;
|
let res = Request::get(NEW_WORD_URI).send().await;
|
||||||
log!(format!("RESPONSE: {res:?}"));
|
debug!(RESULT = format!("{res:?}"));
|
||||||
match res {
|
match res {
|
||||||
// Ok(r) => {
|
|
||||||
// log!(format!("{r:?}"));
|
|
||||||
// match r.json::<Word>().await {
|
|
||||||
// Ok(j) => {
|
|
||||||
// let data = format!("{j:?}");
|
|
||||||
// log!(&data);
|
|
||||||
// handle.set(data);
|
|
||||||
// },
|
|
||||||
// Err(e) => log!(format!("{e:?}")),
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
log!(format!("{r:?}"));
|
debug!(RESPONSE = format!("{r:?}"));
|
||||||
match r.body() {
|
match r.text().await {
|
||||||
Some(j) => {
|
Ok(w) => {
|
||||||
let j = j.to_string();
|
debug!(WORD = &w);
|
||||||
let data = format!("{j:?}");
|
length.set(w.len());
|
||||||
log!(&data);
|
node_refs.set(vec![NodeRef::default(); w.len()]);
|
||||||
handle.set(data);
|
input_values.set(vec![String::new(); w.len()]);
|
||||||
|
handle.set(w.to_uppercase());
|
||||||
|
submitted_words.set(std::vec::Vec::with_capacity(MAX_TRIES));
|
||||||
|
game_over.set(false);
|
||||||
|
loading.set(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
None => log!("no body"),
|
Err(e) => error!(ERROR = format!("{e:?}"),"failed to get request body"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => log!(format!("FETCH: {e:?}")),
|
Err(e) => error!(ERROR = format!("{e:?}"),"failed to retreive word"),
|
||||||
}
|
}
|
||||||
// let res: Word = Request::get(NEW_WORD_URI).send().await.unwrap().json().await.unwrap();
|
|
||||||
// log!(res);
|
|
||||||
// handle.set(res.0);
|
|
||||||
// if let Ok(r) = res {
|
|
||||||
// if let Some(w) = r.body() {
|
|
||||||
|
|
||||||
// word.set(w.to_string());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
|| ()
|
|| ()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let length = word.len();
|
|
||||||
|
|
||||||
let submitted_words: UseStateHandle<Vec<Vec<CharStatus<String>>>> =
|
|
||||||
use_state(|| std::vec::Vec::with_capacity(length));
|
|
||||||
|
|
||||||
let node_refs = use_state(|| vec![NodeRef::default(); length]);
|
|
||||||
let input_values: UseStateHandle<Vec<String>> = use_state(|| vec![String::new(); length]);
|
|
||||||
let game_over = use_state(|| false);
|
|
||||||
let game_over_check = {
|
let game_over_check = {
|
||||||
let word = word.clone();
|
let word = word.clone();
|
||||||
let submitted_words = submitted_words.clone();
|
let submitted_words = submitted_words.clone();
|
||||||
let iv = input_values.clone();
|
let iv = input_values.clone();
|
||||||
let game_over = game_over.clone();
|
let game_over = game_over.clone();
|
||||||
|
let length = length.clone();
|
||||||
Callback::from(move |_| {
|
Callback::from(move |_| {
|
||||||
if submitted_words.iter().count() >= length - 1
|
if submitted_words.iter().count() >= *length - 1
|
||||||
|| crate::compare_strings(&word, &iv.join(""))
|
|| crate::compare_strings(&word, &iv.join(""))
|
||||||
.iter()
|
.iter()
|
||||||
.all(|v| matches!(v, CharStatus::Match(_)))
|
.all(|v| matches!(v, CharStatus::Match(_)))
|
||||||
@ -221,12 +246,22 @@ pub fn Home() -> Html {
|
|||||||
let input_values = input_values.clone();
|
let input_values = input_values.clone();
|
||||||
let submitted_words = submitted_words.clone();
|
let submitted_words = submitted_words.clone();
|
||||||
let game_over = game_over.clone();
|
let game_over = game_over.clone();
|
||||||
|
let length = length.clone();
|
||||||
let word = word.clone();
|
let word = word.clone();
|
||||||
|
let node_refs = node_refs.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
|
||||||
|
|
||||||
Callback::from(move |_e: MouseEvent| {
|
Callback::from(move |_e: MouseEvent| {
|
||||||
if *game_over {
|
if *game_over {
|
||||||
submitted_words.set(std::vec::Vec::with_capacity(length));
|
let input_values = input_values.clone();
|
||||||
input_values.set(vec![String::new(); length]);
|
let submitted_words = submitted_words.clone();
|
||||||
game_over.set(false);
|
let game_over = game_over.clone();
|
||||||
|
let length = length.clone();
|
||||||
|
let word = word.clone();
|
||||||
|
let loading = loading.clone();
|
||||||
|
let node_refs = node_refs.clone();
|
||||||
|
fetch_new_word(&word, &loading, &submitted_words, &input_values, &game_over, &length, &node_refs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let values: Vec<_> = input_values.iter().cloned().collect();
|
let values: Vec<_> = input_values.iter().cloned().collect();
|
||||||
@ -266,7 +301,7 @@ pub fn Home() -> Html {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<h1>{(*word).clone()}</h1>
|
// <h1>{(*word).clone()} {" NODE_REFS: "}{node_refs.len()} {" WORD_LEN: "}{*length}</h1>
|
||||||
<div
|
<div
|
||||||
class="h-4/6 flex flex-col"
|
class="h-4/6 flex flex-col"
|
||||||
>
|
>
|
||||||
@ -285,7 +320,10 @@ pub fn Home() -> Html {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
if !*game_over && !word.is_empty() {
|
if *loading {
|
||||||
|
html!(<p>{"Loading..."}</p>)
|
||||||
|
}
|
||||||
|
else if !*game_over {
|
||||||
node_refs.iter().enumerate().map(|(index, node_ref)| {
|
node_refs.iter().enumerate().map(|(index, node_ref)| {
|
||||||
let on_input = {
|
let on_input = {
|
||||||
let node_ref = node_ref.clone();
|
let node_ref = node_ref.clone();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user