diff --git a/src/editor_view.rs b/src/editor_view.rs index afccbde..c7bb396 100644 --- a/src/editor_view.rs +++ b/src/editor_view.rs @@ -6,11 +6,10 @@ use create_script_dialog::CreateScriptDialog; use editor_area::EditorArea; use editor_nav::EditorNav; use storage::fetch_initial_editor_state; -use wasm_bindgen::{closure::Closure, JsCast}; use web_sys::KeyboardEvent; use yew::{ - function_component, html, use_effect_with, use_node_ref, use_state, use_state_eq, AttrValue, - Callback, Html, Properties, UseStateHandle, + function_component, html, use_node_ref, use_state_eq, AttrValue, Callback, Html, Properties, + UseStateHandle, }; use self::storage::load_file_contents; @@ -74,6 +73,12 @@ where } } +fn select_file(script: &AttrValue, state: &UseStateHandle>) { + let mut new_state: EditorViewState = state.as_ref().clone(); + new_state.open_file = script.clone(); + state.set(new_state.into()); +} + #[derive(Properties, PartialEq, Clone)] pub struct ErrorBarProps { pub msg: AttrValue, @@ -98,6 +103,27 @@ fn close_modals(state: &UseStateHandle>) { state.set(new_state.into()); } +fn keyboard_handler( + editor_state: UseStateHandle>, + global_memo: GlobalMemoCell, + global_layout: UseStateHandle>, + set_err: Rc, + frame: FrameId, +) -> impl Fn(KeyboardEvent) +where + F: Fn(Option<&str>) + 'static, +{ + move |ev: KeyboardEvent| { + if ev.code() == "Enter" && ev.get_modifier_state("Control") { + run_script(&editor_state.open_file, &global_memo, set_err.clone()); + ev.prevent_default(); + } else if ev.code() == "Escape" || (ev.code() == "KeyX" && ev.get_modifier_state("Control")) + { + close_editor(&frame, &global_layout); + } + } +} + #[function_component(CodeEditorView)] pub fn editor_view(props: &EditorViewProps) -> Html { let editor_state: UseStateHandle> = @@ -110,8 +136,6 @@ pub fn editor_view(props: &EditorViewProps) -> Html { editor_state: editor_state.clone(), }; - let current_script = editor_state.open_file.clone(); - let set_err_state = editor_state.clone(); let set_err = Rc::new(move |msg: Option<&str>| { let mut new_state = (*set_err_state.as_ref()).clone(); @@ -121,38 +145,11 @@ pub fn editor_view(props: &EditorViewProps) -> Html { let editor_ref = use_node_ref(); let global_layout = props.global_layout.clone(); let frame = props.frame.clone(); - type KbClosure = Closure; - let editor_closure: UseStateHandle>> = use_state(|| None); - let editor_ref_eff = editor_ref.clone(); let global_memo = props.global_memo.clone(); - use_effect_with(current_script.clone(), move |_| { - if let Some(editor_node) = editor_ref_eff.get() { - let closure = Closure::new(move |ev: KeyboardEvent| { - if ev.code() == "Enter" && ev.get_modifier_state("Control") { - run_script(¤t_script, &global_memo, set_err.clone()); - ev.prevent_default(); - } else if ev.code() == "Escape" { - close_editor(&frame, &global_layout); - } - }); - let _ = editor_node - .add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref()); - let closure: Rc> = closure.into(); - editor_closure.set(Some(closure.clone())); - - let cleanup: Box = Box::new(move || { - let _ = editor_node.remove_event_listener_with_callback( - "keydown", - (*closure.as_ref()).as_ref().unchecked_ref(), - ); - }); - return cleanup; - } - Box::new(|| {}) - }); + let kb_editor_state = editor_state.clone(); html! { -
+
{if editor_state.show_create_dialog { html! { } } else { diff --git a/src/editor_view/editor_nav.rs b/src/editor_view/editor_nav.rs index b28b536..2aa9f5d 100644 --- a/src/editor_view/editor_nav.rs +++ b/src/editor_view/editor_nav.rs @@ -1,9 +1,10 @@ use std::{ops::Deref, rc::Rc}; use itertools::Itertools; +use web_sys::KeyboardEvent; use yew::{function_component, html, AttrValue, Html, UseStateHandle}; -use super::{close_editor, run_script, EditorViewDetailProps, EditorViewState}; +use super::{close_editor, run_script, select_file, EditorViewDetailProps, EditorViewState}; fn show_create_dialog(state: &UseStateHandle>) { let mut new_state: EditorViewState = (*state.deref().deref()).clone(); @@ -11,6 +12,43 @@ fn show_create_dialog(state: &UseStateHandle>) { state.set(new_state.into()); } +fn item_keyboard_handler( + item: AttrValue, + editor_state: UseStateHandle>, +) -> impl Fn(KeyboardEvent) { + move |ev: KeyboardEvent| { + if ev.code() == "Enter" && !ev.get_modifier_state("Control") { + let mut state_mut = (*editor_state.as_ref()).clone(); + state_mut.open_file = item.clone(); + editor_state.set(state_mut.into()); + } else if ev.code() == "ArrowUp" { + if let Some((pos, _)) = editor_state + .available_files + .iter() + .find_position(|v| **v == editor_state.open_file) + { + if pos > 0 { + let mut state_mut = (*editor_state.as_ref()).clone(); + state_mut.open_file = editor_state.available_files[pos - 1].clone(); + editor_state.set(state_mut.into()); + } + } + } else if ev.code() == "ArrowDown" { + if let Some((pos, _)) = editor_state + .available_files + .iter() + .find_position(|v| **v == editor_state.open_file) + { + if pos < editor_state.available_files.len() - 1 { + let mut state_mut = (*editor_state.as_ref()).clone(); + state_mut.open_file = editor_state.available_files[pos + 1].clone(); + editor_state.set(state_mut.into()); + } + } + } + } +} + #[function_component(EditorNav)] pub(super) fn editor_nav(props: &EditorViewDetailProps) -> Html { let global_memo = props.global_memo.clone(); @@ -49,8 +87,14 @@ pub(super) fn editor_nav(props: &EditorViewDetailProps) -> Html { aria_current = Some("true"); classes.push("active"); } + let filename_for_click: AttrValue = f.clone(); + let state_for_click = props.editor_state.clone(); + let filename_for_kb: AttrValue = f.clone(); + let state_for_kb = props.editor_state.clone(); html! {
  • {f}
  • } })