1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#![allow(unused_braces)]
//! An introduction to the minimal, obvious, graphical web application interface.
//!
//! # Welcome!
//! Mogwai is a cute little library for building browser interfaces. It is
//! cognitively small and runtime fast. It acheives these goals by doing very few
//! things, but doing those things well.
//!
//! The following is a short introduction to the concepts of Mogwai.
//!
//! ## Constructing DOM Nodes
//!
//! Building DOM is one of the main tasks of web development. In mogwai the
//! quickest way to construct DOM nodes is by using one of the built in RSX macros.
//!
//! `builder!` or `view!` are flavors of mogwai's RSX that evaluate to
//! [`ViewBuilder`] or [`View`] respectively. RSX is a lot like react.js's JSX,
//! except that it uses type checked rust expressions.
//!
//! Most of the time you'll see the [`builder!`] macro used to create a [`ViewBuilder`]:
//!
//! ```rust
//! # extern crate mogwai;
//! use::mogwai::prelude::*;
//!
//! let my_div: ViewBuilder<HtmlElement> = builder!(
//!     <div class="my-div">
//!         <a href="http://zyghost.com">
//!             "Schellsan's website"
//!         </a>
//!     </div>
//!   );
//! ```
//!
//! The [`ViewBuilder`] can be converted into a [`View`]:
//!
//! ```rust
//! # extern crate mogwai;
//! # use::mogwai::prelude::*;
//!
//! # let my_div: ViewBuilder<HtmlElement> = builder!(
//! #     <div class="my-div">
//! #         <a href="http://zyghost.com">
//! #             "Schellsan's website"
//! #         </a>
//! #     </div>
//! #   );
//! let view: View<HtmlElement> = View::from(my_div);
//!
//! assert_eq!(
//!     view.html_string(),
//!     r#"<div class="my-div"><a href="http://zyghost.com">Schellsan's website</a></div>"#
//! );
//! ```
//!
//! As you can see the above example creates a DOM node with a link inside it:
//!
//! ```html
//! <div class="my-div">
//!       <a href="http://zyghost.com">Schell's website</a>
//! </div>
//! ```
//!
//! ### Appending a [`View`] to the DOM
//!
//! To append a [`View`] to the DOM's `document.body` we can use [`View::run`]:
//!
//! ```rust, no_run
//! # extern crate mogwai;
//! # use::mogwai::prelude::*;
//!
//! # let my_div: ViewBuilder<HtmlElement> = builder!(
//! #     <div class="my-div">
//! #         <a href="http://zyghost.com">
//! #             "Schellsan's website"
//! #         </a>
//! #     </div>
//! #   );
//! # let view: View<HtmlElement> = View::from(my_div);
//! view.run().unwrap();
//! ```
//!
//! [`View::run`] consumes the view, *handing ownership to the browser window*.
//! Because of this it is only available on `wasm32`.
//!
//! ### Dropping a [`View`]
//!
//! By handing the [`View`] off to the window it never goes out of scope.
//! This is important - when a [`View`] is dropped and all references
//! to its inner DOM node are no longer in scope, that DOM node is removed from
//! the DOM.
//!
//! ### Wiring DOM
//!
//! [`View`]s can be static like the one above, or they can change over time.
//! [`View`]s get their dynamic values from the receiving end of a channel
//! called a [`Receiver<T>`]. The transmitting end of the channel is called a
//! [`Transmitter<T>`]. This should be somewhat familiar if you've ever used a
//! channel in other rust libraries.
//!
//! You can create a channel using the [txrx()] function. Then "wire" it
//! into the DOM using RSX - simply assign it to an attribute or add
//! it as a text node. You may even tuple it with an initial value.
//!
//! Whenever the `Transmitter<T>` of the channel sends a value, the DOM is
//! updated.
//!
//! ```rust
//! # extern crate mogwai;
//! use::mogwai::prelude::*;
//!
//! let (tx, rx) = txrx();
//!
//! let my_view = view!(
//!     <div class="my-div">
//!         <a href="http://zyghost.com">
//!             // start with a value and update when a message
//!             // is received on rx.
//!             {("Schellsan's website", rx)}
//!         </a>
//!     </div>
//! );
//!
//! tx.send(&"Gizmo's website".into());
//! ```
//!
//! A [`Transmitter`] can be used to send DOM events as messages, allowing
//! your view to communicate with itself or other components:
//! ```rust
//! # extern crate mogwai;
//! use::mogwai::prelude::*;
//!
//! let (tx, rx) = txrx();
//!
//! let my_view = view!(
//!     <div class="my-div">
//!         <a href="#" on:click=tx.contra_map(|_: &Event| "Gizmo's website".to_string())>
//!             // start with a value and update when a message
//!             // is received on rx.
//!             {("Schellsan's website", rx)}
//!         </a>
//!     </div>
//! );
//! ```
//!
//! See [txrx's module level documentation](super::txrx) for more info on mapping
//! `Transmitter`s and `Receiver`s.
//!
//! ### Accessing the underlying DOM node
//!
//! The [`View`] contains a reference to the raw DOM node, making it possible
//! to manipulate the DOM by hand using Javascript FFI bindings and functions
//! provided by the great `web_sys` crate:
//!
//! ```rust, no_run
//! # extern crate mogwai;
//! # use::mogwai::prelude::*;
//!
//! # let (tx, rx) = txrx();
//!
//! # let my_view = view!(
//! #     <div class="my-div">
//! #         <a href="http://zyghost.com">
//! #             // start with a value and update when a message
//! #             // is received on rx.
//! #             {("Schellsan's website", rx)}
//! #         </a>
//! #     </div>
//! # );
//! # tx.send(&"Gizmo's website".into());
//! #
//! let node: std::cell::Ref<HtmlElement> = my_view.dom_ref();
//! assert_eq!(
//!     node.inner_html(),
//!     r#"<a href="http://zyghost.com">Gizmo's website</a>"#
//! );
//! ```
//!
//! ### Components and more advanced wiring
//!
//! For anything but the simplest view, it is recommended you use the
//! [`Component`] trait to build your view components.
//!
//! In bigger applications we often have circular dependencies between buttons,
//! fields and other interface elements. When these complex situations arise
//! we compartmentalize concerns into [`Component`]s.
//!
//! Other times we don't need a full component with an update cycle and instead
//! we simply require
//! [transmitters, receivers and some handy folds and maps](super::txrx).
//!
//! ## JavaScript interoperability
//! The library itself is a thin layer on top of the
//! [web-sys](https://crates.io/crates/web-sys) crate which provides raw bindings
//! to _tons_ of browser web APIs. Many of the DOM specific structs, enums and
//! traits come from `web-sys`. Some of those types are re-exported by Mogwai's
//! [prelude](../prelude). The most important trait to understand for the
//! purposes of this introduction (and for writing web apps in Rust, in general)
//! is the [`JsCast`](../prelude/trait.JsCast.html) trait. Its `dyn_into` and
//! `dyn_ref` functions are the primary way to cast JavaScript values as specific
//! types.
use super::prelude::*;
use crate as mogwai;

struct Unit {}

impl Component for Unit {
    type ModelMsg = ();
    type ViewMsg = ();
    type DomNode = HtmlElement;

    fn view(&self, _: &Transmitter<()>, _: &Receiver<()>) -> ViewBuilder<HtmlElement> {
        builder! {
            <a href="/#">"Hello"</a>
        }
    }
    fn update(&mut self, _: &(), _: &Transmitter<()>, _sub: &Subscriber<()>) {}
}

// This is here just for the documentation links.
fn _not_used() {
    let (_tx, _rx) = txrx::<()>();
}