Skip to content

Commit

Permalink
Merge branch 'master' into html_from_raw
Browse files Browse the repository at this point in the history
  • Loading branch information
hamza1311 committed Sep 3, 2022
2 parents 07dbcf1 + c7b4029 commit 9a1547f
Show file tree
Hide file tree
Showing 31 changed files with 1,033 additions and 242 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/post-size-cmp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- completed

jobs:
size-cmp:
post-size-cmp:
name: Post Comment on Pull Request
runs-on: ubuntu-latest

Expand Down
31 changes: 30 additions & 1 deletion examples/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 3 additions & 5 deletions examples/boids/src/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ pub struct Props {
pub struct Simulation {
boids: Vec<Boid>,
interval: Interval,
settings: Settings,
generation: usize,
}
impl Component for Simulation {
Expand All @@ -49,7 +48,6 @@ impl Component for Simulation {
Self {
boids,
interval,
settings,
generation,
}
}
Expand All @@ -73,10 +71,10 @@ impl Component for Simulation {
}
}

fn changed(&mut self, ctx: &Context<Self>) -> bool {
fn changed(&mut self, ctx: &Context<Self>, old_props: &Self::Properties) -> bool {
let props = ctx.props();
let should_reset = self.settings != props.settings || self.generation != props.generation;
self.settings = props.settings.clone();
let should_reset =
old_props.settings != props.settings || self.generation != props.generation;
self.generation = props.generation;
if should_reset {
self.boids.clear();
Expand Down
3 changes: 2 additions & 1 deletion examples/file_upload/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ license = "MIT OR Apache-2.0"
[dependencies]
js-sys = "0.3"
yew = { path = "../../packages/yew", features = ["csr"] }
base64 = "0.13.0"
gloo = "0.8"

[dependencies.web-sys]
version = "0.3"
features = ["File"]
features = ["File", "DragEvent", "DataTransfer"]
5 changes: 5 additions & 0 deletions examples/file_upload/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
<title>Yew • File Upload</title>

<link data-trunk rel="rust" />
<link data-trunk rel="css" href="./styles.css" />
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"
/>
</head>

<body></body>
Expand Down
157 changes: 89 additions & 68 deletions examples/file_upload/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
extern crate base64;
use std::collections::HashMap;

use base64::encode;
use gloo::file::callbacks::FileReader;
use gloo::file::File;
use web_sys::{Event, HtmlInputElement};
use web_sys::{DragEvent, Event, FileList, HtmlInputElement};
use yew::html::TargetCast;
use yew::{html, Component, Context, Html};
use yew::{html, Callback, Component, Context, Html};

type Chunks = bool;
struct FileDetails {
name: String,
file_type: String,
data: Vec<u8>,
}

pub enum Msg {
Loaded(String, String),
LoadedBytes(String, Vec<u8>),
Files(Vec<File>, Chunks),
ToggleReadBytes,
Loaded(String, String, Vec<u8>),
Files(Vec<File>),
}

pub struct App {
readers: HashMap<String, FileReader>,
files: Vec<String>,
read_bytes: bool,
files: Vec<FileDetails>,
}

impl Component for App {
Expand All @@ -28,98 +31,116 @@ impl Component for App {
fn create(_ctx: &Context<Self>) -> Self {
Self {
readers: HashMap::default(),
files: vec![],
read_bytes: false,
files: Vec::default(),
}
}

fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Loaded(file_name, data) => {
let info = format!("file_name: {}, data: {:?}", file_name, data);
self.files.push(info);
Msg::Loaded(file_name, file_type, data) => {
self.files.push(FileDetails {
data,
file_type,
name: file_name.clone(),
});
self.readers.remove(&file_name);
true
}
Msg::LoadedBytes(file_name, data) => {
let info = format!("file_name: {}, data: {:?}", file_name, data);
self.files.push(info);
self.readers.remove(&file_name);
true
}
Msg::Files(files, bytes) => {
Msg::Files(files) => {
for file in files.into_iter() {
let file_name = file.name();
let file_type = file.raw_mime_type();

let task = {
let file_name = file_name.clone();
let link = ctx.link().clone();
let file_name = file_name.clone();

if bytes {
gloo::file::callbacks::read_as_bytes(&file, move |res| {
link.send_message(Msg::LoadedBytes(
file_name,
res.expect("failed to read file"),
))
})
} else {
gloo::file::callbacks::read_as_text(&file, move |res| {
link.send_message(Msg::Loaded(
file_name,
res.unwrap_or_else(|e| e.to_string()),
))
})
}
gloo::file::callbacks::read_as_bytes(&file, move |res| {
link.send_message(Msg::Loaded(
file_name,
file_type,
res.expect("failed to read file"),
))
})
};
self.readers.insert(file_name, task);
}
true
}
Msg::ToggleReadBytes => {
self.read_bytes = !self.read_bytes;
true
}
}
}

fn view(&self, ctx: &Context<Self>) -> Html {
let flag = self.read_bytes;
html! {
<div>
<div>
<p>{ "Choose a file to upload to see the uploaded bytes" }</p>
<input type="file" multiple=true onchange={ctx.link().callback(move |e: Event| {
let mut result = Vec::new();
let input: HtmlInputElement = e.target_unchecked_into();

if let Some(files) = input.files() {
let files = js_sys::try_iter(&files)
.unwrap()
.unwrap()
.map(|v| web_sys::File::from(v.unwrap()))
.map(File::from);
result.extend(files);
}
Msg::Files(result, flag)
<div id="wrapper">
<p id="title">{ "Upload Your Files To The Cloud" }</p>
<label for="file-upload">
<div
id="drop-container"
ondrop={ctx.link().callback(|event: DragEvent| {
event.prevent_default();
let files = event.data_transfer().unwrap().files();
Self::upload_files(files)
})}
/>
</div>
<div>
<label>{ "Read bytes" }</label>
<input type="checkbox" checked={flag} onclick={ctx.link().callback(|_| Msg::ToggleReadBytes)} />
ondragover={Callback::from(|event: DragEvent| {
event.prevent_default();
})}
ondragenter={Callback::from(|event: DragEvent| {
event.prevent_default();
})}
>
<i class="fa fa-cloud-upload"></i>
<p>{"Drop your images here or click to select"}</p>
</div>
</label>
<input
id="file-upload"
type="file"
accept="image/*,video/*"
multiple={true}
onchange={ctx.link().callback(move |e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Self::upload_files(input.files())
})}
/>
<div id="preview-area">
{ for self.files.iter().map(Self::view_file) }
</div>
<ul>
{ for self.files.iter().map(|f| Self::view_file(f)) }
</ul>
</div>
}
}
}

impl App {
fn view_file(data: &str) -> Html {
fn view_file(file: &FileDetails) -> Html {
html! {
<li>{ data }</li>
<div class="preview-tile">
<p class="preview-name">{ format!("{}", file.name) }</p>
<div class="preview-media">
if file.file_type.contains("image") {
<img src={format!("data:{};base64,{}", file.file_type, encode(&file.data))} />
} else if file.file_type.contains("video") {
<video controls={true}>
<source src={format!("data:{};base64,{}", file.file_type, encode(&file.data))} type={file.file_type.clone()}/>
</video>
}
</div>
</div>
}
}

fn upload_files(files: Option<FileList>) -> Msg {
let mut result = Vec::new();

if let Some(files) = files {
let files = js_sys::try_iter(&files)
.unwrap()
.unwrap()
.map(|v| web_sys::File::from(v.unwrap()))
.map(File::from);
result.extend(files);
}
Msg::Files(result)
}
}

Expand Down

0 comments on commit 9a1547f

Please sign in to comment.