Refactor to further split into more files.
This commit is contained in:
parent
180ffda98b
commit
77feb4734d
@ -3,7 +3,8 @@ use std::{ops::Deref, rc::Rc};
|
|||||||
use crate::{FrameId, GlobalLayoutState, GlobalMemoCell, PanelDirection, SplitPanel};
|
use crate::{FrameId, GlobalLayoutState, GlobalMemoCell, PanelDirection, SplitPanel};
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use editor_area::EditorArea;
|
use editor_area::EditorArea;
|
||||||
use itertools::Itertools;
|
use editor_nav::EditorNav;
|
||||||
|
use storage::fetch_initial_editor_state;
|
||||||
use wasm_bindgen::{closure::Closure, JsCast};
|
use wasm_bindgen::{closure::Closure, JsCast};
|
||||||
use web_sys::{window, HtmlInputElement, KeyboardEvent};
|
use web_sys::{window, HtmlInputElement, KeyboardEvent};
|
||||||
use yew::{
|
use yew::{
|
||||||
@ -11,7 +12,11 @@ use yew::{
|
|||||||
Callback, Html, Properties, UseStateHandle,
|
Callback, Html, Properties, UseStateHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::storage::load_file_contents;
|
||||||
|
|
||||||
mod editor_area;
|
mod editor_area;
|
||||||
|
mod editor_nav;
|
||||||
|
mod storage;
|
||||||
|
|
||||||
#[derive(Properties, PartialEq, Clone)]
|
#[derive(Properties, PartialEq, Clone)]
|
||||||
pub struct EditorViewProps {
|
pub struct EditorViewProps {
|
||||||
@ -43,77 +48,6 @@ pub struct EditorViewState {
|
|||||||
show_delete_dialog: Option<String>,
|
show_delete_dialog: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_initial_editor_state_or_fail() -> anyhow::Result<EditorViewState> {
|
|
||||||
let win = window().ok_or_else(|| Error::msg("Can't get window"))?;
|
|
||||||
let local = win
|
|
||||||
.local_storage()
|
|
||||||
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
|
||||||
.ok_or_else(|| Error::msg("Local storage not available"))?;
|
|
||||||
|
|
||||||
let n_keys = local
|
|
||||||
.length()
|
|
||||||
.map_err(|_| Error::msg("localStorage broken"))?;
|
|
||||||
let mut available_files: Vec<AttrValue> = vec![];
|
|
||||||
for i in 0..n_keys {
|
|
||||||
if let Some(key) = local
|
|
||||||
.key(i)
|
|
||||||
.map_err(|_| Error::msg("localStorage broken"))?
|
|
||||||
{
|
|
||||||
match key.strip_prefix("scriptfile_") {
|
|
||||||
None => {}
|
|
||||||
Some(filename) => {
|
|
||||||
available_files.push(filename.to_owned().into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let init_str: AttrValue = "init.lua".into();
|
|
||||||
if !available_files.contains(&init_str) {
|
|
||||||
available_files.push(init_str);
|
|
||||||
local
|
|
||||||
.set(
|
|
||||||
"scriptfile_init.lua",
|
|
||||||
"-- Put any code to run on every client load here.\n",
|
|
||||||
)
|
|
||||||
.map_err(|_| Error::msg("localStorage broken"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(EditorViewState {
|
|
||||||
error_msg: None,
|
|
||||||
available_files,
|
|
||||||
open_file: "init.lua".into(),
|
|
||||||
show_create_dialog: false,
|
|
||||||
show_delete_dialog: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch_initial_editor_state() -> Rc<EditorViewState> {
|
|
||||||
match fetch_initial_editor_state_or_fail() {
|
|
||||||
Ok(s) => s.into(),
|
|
||||||
Err(e) => EditorViewState {
|
|
||||||
error_msg: Some(format!("Can't load editor data: {}", e).into()),
|
|
||||||
available_files: vec![],
|
|
||||||
open_file: "init.lua".into(),
|
|
||||||
show_create_dialog: false,
|
|
||||||
show_delete_dialog: None,
|
|
||||||
}
|
|
||||||
.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_file_contents(file: &str) -> anyhow::Result<String> {
|
|
||||||
let win = window().ok_or_else(|| Error::msg("Can't get window"))?;
|
|
||||||
let local = win
|
|
||||||
.local_storage()
|
|
||||||
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
|
||||||
.ok_or_else(|| Error::msg("Local storage not available"))?;
|
|
||||||
Ok(local
|
|
||||||
.get(&format!("scriptfile_{}", file))
|
|
||||||
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
|
||||||
.unwrap_or_else(|| "".to_owned()))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn try_run_script(script: &str, global_memo: &GlobalMemoCell) -> anyhow::Result<()> {
|
pub fn try_run_script(script: &str, global_memo: &GlobalMemoCell) -> anyhow::Result<()> {
|
||||||
let script = load_file_contents(script)?;
|
let script = load_file_contents(script)?;
|
||||||
global_memo
|
global_memo
|
||||||
@ -138,62 +72,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_create_dialog(state: &UseStateHandle<Rc<EditorViewState>>) {
|
|
||||||
let mut new_state: EditorViewState = (*state.deref().deref()).clone();
|
|
||||||
new_state.show_create_dialog = true;
|
|
||||||
state.set(new_state.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[function_component(EditorNav)]
|
|
||||||
fn editor_nav(props: &EditorViewDetailProps) -> Html {
|
|
||||||
let global_memo = props.global_memo.clone();
|
|
||||||
let global_layout = props.global_layout.clone();
|
|
||||||
let frame = props.frame.clone();
|
|
||||||
let current_script = props.editor_state.open_file.clone();
|
|
||||||
|
|
||||||
let set_err_state = props.editor_state.clone();
|
|
||||||
let set_err = Rc::new(move |msg: Option<&str>| {
|
|
||||||
let mut new_state = (*set_err_state.as_ref()).clone();
|
|
||||||
new_state.error_msg = msg.map(|v| AttrValue::from(String::from(v)));
|
|
||||||
set_err_state.set(new_state.into());
|
|
||||||
});
|
|
||||||
let editor_state = props.editor_state.clone();
|
|
||||||
html! {
|
|
||||||
<div class="editornav">
|
|
||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
|
||||||
<button class="btn" aria-label="Run" title="Run"
|
|
||||||
onclick={move |_ev| run_script(¤t_script, &global_memo, set_err.clone())}>
|
|
||||||
<i class="bi bi-file-earmark-play"></i></button>
|
|
||||||
<button class="btn" aria-label="New file" title="New file"
|
|
||||||
onclick={move |_ev| show_create_dialog(&editor_state) }
|
|
||||||
><i class="bi bi-file-earmark-plus"></i></button>
|
|
||||||
<div class="flex-fill"/>
|
|
||||||
<button class="btn" onclick={move |_ev| close_editor(&frame, &global_layout)} aria-label="Close Editor" title="Close editor"><i class="bi bi-arrow-return-left"></i></button>
|
|
||||||
</nav>
|
|
||||||
<ul class="p-2 list-group">
|
|
||||||
{props
|
|
||||||
.editor_state
|
|
||||||
.available_files
|
|
||||||
.iter()
|
|
||||||
.map(|f| {
|
|
||||||
let mut classes = vec!["list-group-item", "pe-auto"];
|
|
||||||
let mut aria_current = None;
|
|
||||||
if *f == props.editor_state.open_file {
|
|
||||||
aria_current = Some("true");
|
|
||||||
classes.push("active");
|
|
||||||
}
|
|
||||||
html! { <li aria-current={aria_current} tabindex={0}
|
|
||||||
class={classes.iter().join(" ")}
|
|
||||||
style="cursor: pointer"
|
|
||||||
>{f}</li>}
|
|
||||||
})
|
|
||||||
.collect::<Vec<Html>>()
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Properties, PartialEq, Clone)]
|
#[derive(Properties, PartialEq, Clone)]
|
||||||
pub struct ErrorBarProps {
|
pub struct ErrorBarProps {
|
||||||
pub msg: AttrValue,
|
pub msg: AttrValue,
|
||||||
|
62
src/editor_view/editor_nav.rs
Normal file
62
src/editor_view/editor_nav.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use std::{ops::Deref, rc::Rc};
|
||||||
|
|
||||||
|
use itertools::Itertools;
|
||||||
|
use yew::{function_component, html, AttrValue, Html, UseStateHandle};
|
||||||
|
|
||||||
|
use super::{close_editor, run_script, EditorViewDetailProps, EditorViewState};
|
||||||
|
|
||||||
|
fn show_create_dialog(state: &UseStateHandle<Rc<EditorViewState>>) {
|
||||||
|
let mut new_state: EditorViewState = (*state.deref().deref()).clone();
|
||||||
|
new_state.show_create_dialog = true;
|
||||||
|
state.set(new_state.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[function_component(EditorNav)]
|
||||||
|
pub(super) fn editor_nav(props: &EditorViewDetailProps) -> Html {
|
||||||
|
let global_memo = props.global_memo.clone();
|
||||||
|
let global_layout = props.global_layout.clone();
|
||||||
|
let frame = props.frame.clone();
|
||||||
|
let current_script = props.editor_state.open_file.clone();
|
||||||
|
|
||||||
|
let set_err_state = props.editor_state.clone();
|
||||||
|
let set_err = Rc::new(move |msg: Option<&str>| {
|
||||||
|
let mut new_state = (*set_err_state.as_ref()).clone();
|
||||||
|
new_state.error_msg = msg.map(|v| AttrValue::from(String::from(v)));
|
||||||
|
set_err_state.set(new_state.into());
|
||||||
|
});
|
||||||
|
let editor_state = props.editor_state.clone();
|
||||||
|
html! {
|
||||||
|
<div class="editornav">
|
||||||
|
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
||||||
|
<button class="btn" aria-label="Run" title="Run"
|
||||||
|
onclick={move |_ev| run_script(¤t_script, &global_memo, set_err.clone())}>
|
||||||
|
<i class="bi bi-file-earmark-play"></i></button>
|
||||||
|
<button class="btn" aria-label="New file" title="New file"
|
||||||
|
onclick={move |_ev| show_create_dialog(&editor_state) }
|
||||||
|
><i class="bi bi-file-earmark-plus"></i></button>
|
||||||
|
<div class="flex-fill"/>
|
||||||
|
<button class="btn" onclick={move |_ev| close_editor(&frame, &global_layout)} aria-label="Close Editor" title="Close editor"><i class="bi bi-arrow-return-left"></i></button>
|
||||||
|
</nav>
|
||||||
|
<ul class="p-2 list-group">
|
||||||
|
{props
|
||||||
|
.editor_state
|
||||||
|
.available_files
|
||||||
|
.iter()
|
||||||
|
.map(|f| {
|
||||||
|
let mut classes = vec!["list-group-item", "pe-auto"];
|
||||||
|
let mut aria_current = None;
|
||||||
|
if *f == props.editor_state.open_file {
|
||||||
|
aria_current = Some("true");
|
||||||
|
classes.push("active");
|
||||||
|
}
|
||||||
|
html! { <li aria-current={aria_current} tabindex={0}
|
||||||
|
class={classes.iter().join(" ")}
|
||||||
|
style="cursor: pointer"
|
||||||
|
>{f}</li>}
|
||||||
|
})
|
||||||
|
.collect::<Vec<Html>>()
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
77
src/editor_view/storage.rs
Normal file
77
src/editor_view/storage.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::EditorViewState;
|
||||||
|
use anyhow::Error;
|
||||||
|
use web_sys::window;
|
||||||
|
use yew::AttrValue;
|
||||||
|
|
||||||
|
fn fetch_initial_editor_state_or_fail() -> anyhow::Result<EditorViewState> {
|
||||||
|
let win = window().ok_or_else(|| Error::msg("Can't get window"))?;
|
||||||
|
let local = win
|
||||||
|
.local_storage()
|
||||||
|
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
||||||
|
.ok_or_else(|| Error::msg("Local storage not available"))?;
|
||||||
|
|
||||||
|
let n_keys = local
|
||||||
|
.length()
|
||||||
|
.map_err(|_| Error::msg("localStorage broken"))?;
|
||||||
|
let mut available_files: Vec<AttrValue> = vec![];
|
||||||
|
for i in 0..n_keys {
|
||||||
|
if let Some(key) = local
|
||||||
|
.key(i)
|
||||||
|
.map_err(|_| Error::msg("localStorage broken"))?
|
||||||
|
{
|
||||||
|
match key.strip_prefix("scriptfile_") {
|
||||||
|
None => {}
|
||||||
|
Some(filename) => {
|
||||||
|
available_files.push(filename.to_owned().into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let init_str: AttrValue = "init.lua".into();
|
||||||
|
if !available_files.contains(&init_str) {
|
||||||
|
available_files.push(init_str);
|
||||||
|
local
|
||||||
|
.set(
|
||||||
|
"scriptfile_init.lua",
|
||||||
|
"-- Put any code to run on every client load here.\n",
|
||||||
|
)
|
||||||
|
.map_err(|_| Error::msg("localStorage broken"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(EditorViewState {
|
||||||
|
error_msg: None,
|
||||||
|
available_files,
|
||||||
|
open_file: "init.lua".into(),
|
||||||
|
show_create_dialog: false,
|
||||||
|
show_delete_dialog: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn fetch_initial_editor_state() -> Rc<EditorViewState> {
|
||||||
|
match fetch_initial_editor_state_or_fail() {
|
||||||
|
Ok(s) => s.into(),
|
||||||
|
Err(e) => EditorViewState {
|
||||||
|
error_msg: Some(format!("Can't load editor data: {}", e).into()),
|
||||||
|
available_files: vec![],
|
||||||
|
open_file: "init.lua".into(),
|
||||||
|
show_create_dialog: false,
|
||||||
|
show_delete_dialog: None,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_file_contents(file: &str) -> anyhow::Result<String> {
|
||||||
|
let win = window().ok_or_else(|| Error::msg("Can't get window"))?;
|
||||||
|
let local = win
|
||||||
|
.local_storage()
|
||||||
|
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
||||||
|
.ok_or_else(|| Error::msg("Local storage not available"))?;
|
||||||
|
Ok(local
|
||||||
|
.get(&format!("scriptfile_{}", file))
|
||||||
|
.map_err(|_| Error::msg("Error retrieving localStorage"))?
|
||||||
|
.unwrap_or_else(|| "".to_owned()))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user