mirror of https://github.com/yewstack/yew
Minimal prototype
This commit is contained in:
commit
6a0067838a
|
@ -0,0 +1,3 @@
|
|||
|
||||
/target/
|
||||
**/*.rs.bk
|
|
@ -0,0 +1,54 @@
|
|||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.1.3"
|
||||
source = "git+https://github.com/koute/stdweb#5eb5f0ff176464dbd30d41f31b53804a8bb2847b"
|
||||
dependencies = [
|
||||
"serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yew-prototype"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"stdweb 0.1.3 (git+https://github.com/koute/stdweb)",
|
||||
]
|
||||
|
||||
[metadata]
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||
"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070"
|
||||
"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
|
||||
"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839"
|
||||
"checksum stdweb 0.1.3 (git+https://github.com/koute/stdweb)" = "<none>"
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "yew-prototype"
|
||||
version = "0.1.0"
|
||||
authors = ["Denis Kolodin <deniskolodin@gmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
stdweb = { git = "https://github.com/koute/stdweb" }
|
|
@ -0,0 +1,171 @@
|
|||
#[macro_use]
|
||||
extern crate stdweb;
|
||||
|
||||
struct Model {
|
||||
value: u8,
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
Increment,
|
||||
Decrement,
|
||||
}
|
||||
|
||||
fn update(model: &mut Model, msg: Msg) {
|
||||
match msg {
|
||||
Msg::Increment => {
|
||||
model.value = model.value + 1;
|
||||
}
|
||||
Msg::Decrement => {
|
||||
model.value = model.value - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn view(model: &Model) -> html::Html<Msg> {
|
||||
use html::*;
|
||||
div(vec![
|
||||
onclick(|_| Msg::Increment)
|
||||
])
|
||||
}
|
||||
|
||||
/*
|
||||
html! {
|
||||
<div onClick=(|_| { Msg::Increment })>{ model.x }>
|
||||
}
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
let model = Model {
|
||||
value: 0,
|
||||
};
|
||||
html::program(model, update, view);
|
||||
}
|
||||
|
||||
mod html {
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
/*
|
||||
pub trait Message {}
|
||||
|
||||
impl<T: ConcreteEvent> Fn(T) -> Self for Message {
|
||||
}
|
||||
*/
|
||||
|
||||
use stdweb;
|
||||
|
||||
use stdweb::web::{
|
||||
INode,
|
||||
IEventTarget,
|
||||
Element,
|
||||
document,
|
||||
};
|
||||
use stdweb::web::event::{
|
||||
ClickEvent,
|
||||
};
|
||||
|
||||
fn replace_body(element: Element) {
|
||||
let body = document().query_selector("body").unwrap();
|
||||
while body.has_child_nodes() {
|
||||
body.remove_child(&body.last_child().unwrap()).unwrap();
|
||||
}
|
||||
body.append_child(&element);
|
||||
}
|
||||
|
||||
pub fn program<M, MSG, U, V>(mut model: M, update: U, view: V)
|
||||
where
|
||||
M: 'static,
|
||||
MSG: 'static,
|
||||
U: Fn(&mut M, MSG) + 'static,
|
||||
V: Fn(&M) -> Html<MSG> + 'static,
|
||||
{
|
||||
stdweb::initialize();
|
||||
// No messages at start
|
||||
let messages = Rc::new(RefCell::new(Vec::new()));
|
||||
let mut callback = move || {
|
||||
println!("Process messages");
|
||||
let mut borrowed = messages.borrow_mut();
|
||||
for msg in borrowed.drain(..) {
|
||||
update(&mut model, msg);
|
||||
}
|
||||
let html = view(&model);
|
||||
let element = html.render(messages.clone());
|
||||
replace_body(element);
|
||||
};
|
||||
// Initial call for first rendering
|
||||
callback();
|
||||
js! {
|
||||
let callback = @{callback};
|
||||
window.yew_loop = function() {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
stdweb::event_loop();
|
||||
}
|
||||
|
||||
pub type Html<MSG> = Tag<MSG>;
|
||||
|
||||
pub trait Listener<MSG> {
|
||||
fn attach(&mut self, element: &Element, messages: Messages<MSG>);
|
||||
}
|
||||
|
||||
type Messages<MSG> = Rc<RefCell<Vec<MSG>>>;
|
||||
type Listeners<MSG> = Vec<Box<Listener<MSG>>>;
|
||||
|
||||
pub struct Tag<MSG> {
|
||||
tag: &'static str,
|
||||
listeners: Listeners<MSG>,
|
||||
}
|
||||
|
||||
impl<MSG> Tag<MSG> {
|
||||
fn new(tag: &'static str, listeners: Listeners<MSG>) -> Self {
|
||||
Tag { tag, listeners }
|
||||
}
|
||||
|
||||
fn render(self, messages: Messages<MSG>) -> Element {
|
||||
let element = document().create_element(self.tag);
|
||||
for mut listener in self.listeners {
|
||||
listener.attach(&element, messages.clone());
|
||||
}
|
||||
element
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div<MSG>(listeners: Vec<Box<Listener<MSG>>>) -> Tag<MSG> {
|
||||
Tag::new("div", listeners)
|
||||
}
|
||||
|
||||
pub fn button<MSG>(listeners: Vec<Box<Listener<MSG>>>) -> Tag<MSG> {
|
||||
Tag::new("button", listeners)
|
||||
}
|
||||
|
||||
pub fn onclick<F, MSG>(handler: F) -> Box<Listener<MSG>>
|
||||
where
|
||||
MSG: 'static,
|
||||
F: Fn(ClickEvent) -> MSG + 'static
|
||||
{
|
||||
Box::new(OnClick(Some(handler)))
|
||||
}
|
||||
|
||||
struct OnClick<T>(Option<T>);
|
||||
|
||||
impl<T, MSG> Listener<MSG> for OnClick<T>
|
||||
where
|
||||
MSG: 'static,
|
||||
T: Fn(ClickEvent) -> MSG + 'static,
|
||||
{
|
||||
fn attach(&mut self, element: &Element, messages: Messages<MSG>) {
|
||||
let handler = self.0.take().unwrap();
|
||||
let sender = move |event| {
|
||||
println!("Clicked!");
|
||||
let msg = handler(event);
|
||||
messages.borrow_mut().push(msg);
|
||||
js! {
|
||||
yew_loop();
|
||||
}
|
||||
};
|
||||
element.add_event_listener(sender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue