diff options
Diffstat (limited to 'src/viewmodel')
-rw-r--r-- | src/viewmodel/mod.rs | 95 | ||||
-rw-r--r-- | src/viewmodel/organizational.rs | 47 | ||||
-rw-r--r-- | src/viewmodel/utility.rs | 6 |
3 files changed, 139 insertions, 9 deletions
diff --git a/src/viewmodel/mod.rs b/src/viewmodel/mod.rs index 75ed1d2..044dbad 100644 --- a/src/viewmodel/mod.rs +++ b/src/viewmodel/mod.rs @@ -1,3 +1,8 @@ +use wasm_bindgen::closure::Closure; +use web_sys::FileReader; +use wasm_bindgen::JsCast; +use yew::services::ConsoleService; +use crate::viewmodel::utility::File; use yew::prelude::*; use crate::view::VCardPropertyInputComponent; @@ -50,7 +55,13 @@ pub enum VCardPropertyInputField { placeholder: Option<String>, oninput: Callback<InputData>, value: String, - typ: String + typ: String, + }, + File { + label: String, + name: String, + callback: Callback<Option<File>>, + value: Option<File>, }, CheckBox { label: String, @@ -72,6 +83,12 @@ impl VCardPropertyInputField { value: _, typ, } => Self::text_field_input(label, id, placeholder, oninput, typ), + Self::File { + label, + name, + callback, + value, + } => Self::file_field_input(label, name, callback, value), Self::CheckBox { label, id, @@ -99,6 +116,82 @@ impl VCardPropertyInputField { </div> } } + /// Returns an `Html` representation of a file input field with the given parameters. + fn file_field_input(label: &str, name: &str, callback: &Callback<Option<File>>, file: &Option<File>) -> Html { + let callback = callback.clone(); + let onchange = Callback::<()>::default(); + let onchange = onchange.reform(move |c: ChangeData| + if let ChangeData::Files(files) = c { + match files.item(0) { + Some(file) => { + let file_reader = FileReader::new().unwrap(); + match file_reader.read_as_data_url(&file) { + Ok(_) => (), + Err(_) => ConsoleService::warn("Error: Couldn't get file as data url."), + }; + + let callback = callback.clone(); + let onload = Closure::wrap(Box::new(move |event: Event|{ + let file_reader: FileReader = event.target().unwrap().dyn_into().unwrap(); + let data_url: Option<String> = file_reader.result().unwrap().as_string(); + match data_url { + Some(content) => callback.emit( + Some(File { + name: file.name(), + content, + }) + ), + None => { + ConsoleService::warn("Couldn't get data url as string."); + callback.emit(None); + }, + }; + }) as Box<dyn FnMut(_)>); + + file_reader.set_onload(Some(onload.as_ref().unchecked_ref())); + onload.forget(); + }, + None => callback.emit(None), + } + } else { + callback.emit(None); + } + ); + html!{ + <div class="field column + is-one-fifth-widescreen + is-one-quarter-desktop + is-one-third-tablet + is-half-mobile" > + <label class="label">{ label }</label> + <div class="file has-name control"> + <label class="file-label"> + <input class="file-input" + type="file" + name=name + onchange=onchange + /> + <span class="file-cta"> + <span class="file-icon"> + <i class="fas fa-upload"></i> + </span> + <span class="file-label"> + { "Choose file..." } + </span> + </span> + <span class="file-name"> + { + match file { + Some(file) => file.name.clone(), + None => String::from("No file selected"), + } + } + </span> + </label> + </div> + </div> + } + } /// Returns an `Html` representation of a checkbox input field with the given parameters. fn checkbox_field_input(label: &str, id: &Option<String>, checked: &bool, onclick: &Callback<MouseEvent>) -> Html { html!{ diff --git a/src/viewmodel/organizational.rs b/src/viewmodel/organizational.rs index e7a4ae7..c8f7164 100644 --- a/src/viewmodel/organizational.rs +++ b/src/viewmodel/organizational.rs @@ -4,7 +4,7 @@ use super::*; #[derive(Clone,Debug,PartialEq)] pub struct Organizational { pub org: String, - pub logo: String, + pub logo: Option<File>, pub title: String, pub role: String, pub member: String, @@ -15,7 +15,7 @@ impl VCardPropertyInputObject<OrganizationalView> for Organizational { fn new() -> Self { Self { org: String::new(), - logo: String::new(), + logo: None, title: String::new(), role: String::new(), member: String::new(), @@ -33,13 +33,44 @@ impl VCardPropertyInputObject<OrganizationalView> for Organizational { value: self.org.clone(), typ: typ.clone(), }, - VCardPropertyInputField::Text{ // TODO: Add Upload for logo + VCardPropertyInputField::File{ // TODO: Add Upload for logo label: "Logo".to_string(), - id: Some("logo".to_string()), - placeholder: None, - oninput: link.callback(|e: InputData| Msg::UpdateLogo(e.value)), + name: "logo".to_string(), + callback: link.callback(|file: Option<File>| + /* + if let ChangeData::Files(files) = c { + match files.item(0) { + Some(file) => { + let filereader = match FileReaderSync::new() { + Ok(reader) => reader, + Err(_) => { + ConsoleService::warn("Couldn't create new filereader."); + return Msg::UpdateLogo(None) + }, + }; + let content = match filereader.read_as_data_url(&file) { + Ok(content) => content, + Err(_) => { + ConsoleService::warn("Error: Couldn't get file as data url."); + return Msg::UpdateLogo(None) + }, + }; + Msg::UpdateLogo( + Some(File { + name: file.name(), + content, + }) + ) + }, + None => Msg::UpdateLogo(None), + } + } else { + Msg::UpdateLogo(None) + } + */ + Msg::UpdateLogo(file) + ), value: self.logo.clone(), - typ: typ.clone(), }, VCardPropertyInputField::Text{ label: "Title".to_string(), @@ -77,7 +108,7 @@ impl VCardPropertyInputObject<OrganizationalView> for Organizational { } fn is_empty(&self) -> bool { self.org.is_empty() && - self.logo.is_empty() && + self.logo.is_none() && self.title.is_empty() && self.role.is_empty() && self.member.is_empty() && diff --git a/src/viewmodel/utility.rs b/src/viewmodel/utility.rs index 4a82a42..cb581ac 100644 --- a/src/viewmodel/utility.rs +++ b/src/viewmodel/utility.rs @@ -38,4 +38,10 @@ pub enum DownloadOption { PDF, VCard, QrCode, +} + +#[derive(Clone,Debug,PartialEq)] +pub struct File { + pub name: String, + pub content: String, }
\ No newline at end of file |