starfish/
lib.rs

1use wasm_bindgen::prelude::*;
2use wasm_bindgen::JsCast;
3use wasm_bindgen_futures;
4use web_sys::HtmlInputElement;
5use web_sys::HtmlTextAreaElement;
6use web_sys::HtmlElement;
7use starfish::*;
8use js_sys;
9
10static mut RUNNING: bool = false;
11static mut RUN_COUNT: usize = 0;
12static mut INPUT_READY: bool = false;
13
14#[wasm_bindgen]
15extern {
16    fn getScriptVar() -> String;
17
18    #[wasm_bindgen(js_namespace = LZString)]
19    fn compressToEncodedURIComponent(s: &str) -> String;
20
21    #[wasm_bindgen(js_namespace = LZString)]
22    fn decompressFromEncodedURIComponent(s: &str) -> String;
23}
24
25#[wasm_bindgen]
26pub fn run() {
27    let script = getScriptVar();
28    if &script != "" {
29        let window = web_sys::window().unwrap();
30        let document = window.document().unwrap();
31        let script_box = get_textarea_element_by_id(&document, "script");
32        script_box.set_value(&decompressFromEncodedURIComponent(&script));
33    }
34}
35
36fn create_box(code_box: &CodeBox) -> String {
37    let mut output = String::from("<pre><br>");
38    let code_box = code_box.code_box();
39    for y in 0..code_box.len() {
40        for x in 0..code_box[y].len() {
41            if x != 0 || y != 0 {
42                output.push_str(&format!("<c id=\"{}x{}\">", x, y));
43            } else {
44                output.push_str(&format!("<c id=\"{}x{}\"  class=\"s\">", x, y));
45            }
46            output.push(code_box[y][x] as char);
47            output.push_str("</c>");
48        }
49        output.push_str("<br>");
50    }
51    output.push_str("<br></pre>");
52    return output;
53}
54
55fn get_input_element_by_id(document: &web_sys::Document, id: &str) -> HtmlInputElement {
56    document.get_element_by_id(id).unwrap().
57        dyn_into::<HtmlInputElement>().unwrap()
58}
59
60fn get_textarea_element_by_id(document: &web_sys::Document, id: &str) -> HtmlTextAreaElement {
61    document.get_element_by_id(id).unwrap().
62        dyn_into::<HtmlTextAreaElement>().unwrap()
63}
64
65fn get_html_element_by_id(document: &web_sys::Document, id: &str) -> HtmlElement {
66    document.get_element_by_id(id).unwrap().
67        dyn_into::<HtmlElement>().unwrap()
68}
69
70#[wasm_bindgen]
71pub fn share_script() {
72    let window = web_sys::window().unwrap();
73    let document = window.document().unwrap();
74    
75    let mut url = window.location().href().unwrap();
76    if url.contains("?") {
77        url = url.split("?").next().unwrap().to_string();
78    }
79
80    let share_field = get_input_element_by_id(&document, "sharefield");
81    url.push_str("?script=");
82    url.push_str(&compressToEncodedURIComponent(&get_textarea_element_by_id(&document, "script").value()));
83    share_field.set_value(&url);
84
85    let share_box = document.get_element_by_id("sharebox").unwrap();
86    _ = share_box.set_attribute("style", "");
87}
88
89async fn sleep(ms: i32) -> Result<JsValue, JsValue> {
90    let promise = js_sys::Promise::new(&mut |resolve, _| {
91        web_sys::window()
92            .unwrap()
93            .set_timeout_with_callback_and_timeout_and_arguments_0(&resolve, ms)
94            .unwrap();
95    });
96    let result = wasm_bindgen_futures::JsFuture::from(promise).await?;
97    Ok(result)
98}
99
100#[wasm_bindgen]
101pub fn stop_script() {
102    unsafe {
103        RUN_COUNT += 1;
104    }
105}
106
107#[wasm_bindgen]
108pub fn collect_input() {
109    let window = web_sys::window().unwrap();
110    let document = window.document().unwrap();
111
112    let input_input = get_textarea_element_by_id(&document, "inputfield");
113    let input_box = get_html_element_by_id(&document, "input");
114
115    let mut out_text = input_box.inner_text();
116    out_text.push_str(&input_input.value());
117
118    input_box.set_inner_text(&out_text);
119    input_input.set_value("");
120
121    unsafe {
122        INPUT_READY = true;
123    }
124}
125
126#[wasm_bindgen]
127pub async fn run_script() {
128    let my_count: usize;
129    unsafe {
130        if RUNNING {
131            return
132        }
133        RUNNING = true;
134        my_count = RUN_COUNT;
135    }
136
137    let window = web_sys::window().unwrap();
138    let document = window.document().unwrap();
139
140    let out_box = get_html_element_by_id(&document, "output");
141    out_box.set_inner_text("");
142    let mut out_string = String::new();
143
144    let stack_box = get_html_element_by_id(&document, "stack");
145
146    let stack = Stack::from_string(&get_input_element_by_id(&document, "initialstack").value()).unwrap_or(Stack::new(None));
147    let mut code_box = starfish::CodeBox::new(&get_textarea_element_by_id(&document, "script").value(), stack, false);
148    let delay: i32 = get_input_element_by_id(&document, "delay").value().parse().unwrap_or(0);
149
150    let code_box_elem = get_html_element_by_id(&document, "codebox");
151    code_box_elem.set_inner_html(&create_box(&code_box));
152
153    let mut end = false;
154    let mut output: Option<String>;
155    let mut sleep_ms: f64;
156
157    let mut last_x: usize = 0;
158    let mut last_y: usize = 0;
159
160    let input_box = get_html_element_by_id(&document, "input");
161
162    while !end {
163        unsafe {
164            if INPUT_READY {
165                INPUT_READY = false;
166                let input_text = input_box.inner_text();
167                code_box.inject_input(input_text.as_bytes().to_vec());
168                input_box.set_inner_text("");
169            }
170        }
171
172        (output, end, sleep_ms) = code_box.swim();
173        match output {
174            Some(val) => {
175                if val.as_bytes()[0] == 13 {
176                    out_string = String::new();
177                } else {
178                    out_string.push_str(&val);
179                }
180                out_box.set_inner_text(&out_string);
181            },
182            None => {}
183        }
184
185        if sleep_ms > 0.0 {
186            _ = sleep(sleep_ms as i32).await;
187        }
188        if delay > 0 {
189            _ = sleep(delay).await;
190        }
191
192        unsafe {
193            if my_count != RUN_COUNT {
194                break;
195            }
196        }
197
198        if sleep_ms > 0.0 || delay > 0 {
199            if !end {
200                let last_pos = document.get_element_by_id(&format!("{}x{}", last_x, last_y)).unwrap();
201                _ = last_pos.set_attribute("class", "");
202                (last_x, last_y) = code_box.position();
203                let cur_pos = document.get_element_by_id(&format!("{}x{}", last_x, last_y)).unwrap();
204                if code_box.deep_sea() {
205                    _ = cur_pos.set_attribute("class", "u");
206                } else {
207                    _ = cur_pos.set_attribute("class", "s");
208                }
209            }
210            
211            stack_box.set_inner_text(&code_box.string_stack());
212        }
213    }
214
215    unsafe {
216        RUNNING = false;
217    }
218}