summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjelemux <jeremias.weber@protonmail.com>2021-02-09 22:38:40 +0100
committerjelemux <jeremias.weber@protonmail.com>2021-02-09 22:38:40 +0100
commit9df3ff8d633a18e934d4e62b0e2e718620760552 (patch)
tree9d84d5fd3e418807905b3da928c1a2c3664b0272
parentad9ba30ed217ec9907d1faf389c321a1dcf5c13a (diff)
downloadwasm-card-9df3ff8d633a18e934d4e62b0e2e718620760552.tar.gz
wasm-card-9df3ff8d633a18e934d4e62b0e2e718620760552.tar.bz2
add file input field, include file as data url in vcard
-rw-r--r--Cargo.toml6
-rw-r--r--src/view/main.rs7
-rw-r--r--src/view/organizational.rs3
-rw-r--r--src/viewmodel/mod.rs95
-rw-r--r--src/viewmodel/organizational.rs47
-rw-r--r--src/viewmodel/utility.rs6
-rw-r--r--static/fontawesome-solid.min.css5
-rw-r--r--static/index.html1
8 files changed, 156 insertions, 14 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 34281a3..54657ea 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,4 +29,8 @@ features = ["services"]
[dependencies.chrono]
version = "0.4.19"
default-features = false
-features = ["wasmbind", "js-sys"] \ No newline at end of file
+features = ["wasmbind", "js-sys"]
+
+[dependencies.web-sys]
+version = "0.3.47"
+features = ["FileReaderSync"] \ No newline at end of file
diff --git a/src/view/main.rs b/src/view/main.rs
index c2af72a..d6b2cb9 100644
--- a/src/view/main.rs
+++ b/src/view/main.rs
@@ -377,9 +377,10 @@ impl Component for MainView {
builder = builder.with_org(vec![organizational.org]);
}
- if !organizational.logo.is_empty() {
- builder = builder.with_logo(organizational.logo);
- }
+ match organizational.logo {
+ Some(file) => builder = builder.with_logo(file.content),
+ None => (),
+ };
if !organizational.title.is_empty() {
builder = builder.with_title(organizational.title);
diff --git a/src/view/organizational.rs b/src/view/organizational.rs
index b11c181..e6636ec 100644
--- a/src/view/organizational.rs
+++ b/src/view/organizational.rs
@@ -1,3 +1,4 @@
+use crate::viewmodel::utility::File;
use yew::prelude::*;
use yewtil::NeqAssign;
use crate::viewmodel::Error;
@@ -17,7 +18,7 @@ pub struct OrganizationalView {
pub enum Msg {
UpdateOrg(String),
- UpdateLogo(String),
+ UpdateLogo(Option<File>),
UpdateTitle(String),
UpdateRole(String),
UpdateMember(String),
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
diff --git a/static/fontawesome-solid.min.css b/static/fontawesome-solid.min.css
new file mode 100644
index 0000000..d61a2d3
--- /dev/null
+++ b/static/fontawesome-solid.min.css
@@ -0,0 +1,5 @@
+/*!
+ * Font Awesome Free 5.15.2 by @fontawesome - https://fontawesome.com
+ * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
+ */
+@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.fas{font-family:"Font Awesome 5 Free";font-weight:900} \ No newline at end of file
diff --git a/static/index.html b/static/index.html
index 21f35d4..c067b51 100644
--- a/static/index.html
+++ b/static/index.html
@@ -5,6 +5,7 @@
<meta charset="utf-8">
<link rel="icon" href="./favicon.ico" type="image/png" />
<link rel="stylesheet" href="./bulma.min.css" />
+ <link rel="stylesheet" href="./fontawesome-solid.min.css" />
<title>BCard Wasm Web App</title>
</head>