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
//! 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. //! //! ## Building Gizmos (aka constructing DOM widgets) //! Building DOM is one of the main authorship modes in Mogwai. DOM nodes //! are created using a builder pattern. The builder itself is called //! [`GizmoBuilder`] and it gets built into a [`Gizmo`]. A `Gizmo` is Mogwai's //! name for a widget. `Gizmo`s can be run or attached to other `Gizmo`s. The //! builder pattern looks like this: //! //! ```rust, no_run //! extern crate mogwai; //! use::mogwai::prelude::*; //! //! div() //! .class("my-div") //! .with( //! a() //! .attribute("href", "http://zyghost.com") //! .text("Schellsan's website") //! ) //! .run().unwrap_throw() //! ``` //! //! The example above would create a DOM node and append it to the document //! body. It would look like this: //! //! ```html //! <div class="my-div"> //! <a href="http://zyghost.com">Schell's website</a> //! </div> //! ``` //! //! ### Running Gizmos and removing gizmos //! //! Note that the builder is built into a [`Gizmo`] with [`GizmoBuilder::build`] //! and then added to the body automatically with the [`GizmoBuilder::run`] //! function. This `run` function is special. It hands off the gizmo to be //! owned by the window. Otherwise the gizmo would go out of scope and be //! dropped. When a gizmo is dropped its [`HtmlElement`] is removed from the DOM. //! //! You may have noticed that we can use the [`GizmoBuilder::class`] method to set //! the class of our `div` tag, but we use the [`GizmoBuilder::attribute`] method //! to set the href attribute of our `a` tag. That's because [`GizmoBuilder::class`] //! is a convenience method that simply calls [`GizmoBuilder::attribute`] under the //! hood. Some DOM attributes have these conveniences and others do not. See the //! documentation for [`GizmoBuilder`] for more info. If you don't see a method that //! you think should be there, I welcome you to //! [add it in a pull request](https://github.com/schell/mogwai) :) //! //! ### Wiring DOM //! //! `Gizmo`s can be static like the one above, or they can change over time. //! `Gizmo`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. //! //! Creating a channel is easy using the [txrx()] function. Then we "wire" it //! into the `GizmoBuilder` with one of a number of `rx_` flavored `GizmoBuilder` //! methods. //! //! Whenever the `Transmitter<T>` of the channel sends a value, the DOM is //! updated. //! //! ```rust, no_run //! extern crate mogwai; //! use::mogwai::prelude::*; //! //! let (tx, rx) = txrx(); //! //! div() //! .class("my-div") //! .with( //! a() //! .attribute("href", "https://zyghost.com") //! .rx_text("Schellsan's website", rx) //! ) //! .run().unwrap_throw(); //! //! tx.send(&"Gizmo's website".into()); //! ``` //! //! Just like previously, this builds a DOM node and appends it to the document //! body, but this time we've already updated the link's text to "Gizmo's website": //! //! ```html //! <div class="my-div"> //! <a href="http://zyghost.com">Gizmo's website</a> //! </div> //! ``` //! //! ### Components and more advanced wiring //! //! 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. //! //! [`GizmoBuilder::build`]: GizmoBuilder::build //! [`GizmoBuilder::run`]: GizmoBuilder::method@run //! [`GizmoBuilder`]: struct@GizmoBuilder //! [`Gizmo`]: struct@Gizmo //! [`Transmitter<T>`]: struct@Transmitter //! [`Receiver<T>`]: struct@Receiver //! [`HtmlElement`]: struct@HtmlElement //! [`Component`]: trait@Component use super::gizmo::*; use super::txrx::*; use super::component::*; use super::component::subscriber::*; struct Unit {} impl Component for Unit { type ModelMsg = (); type ViewMsg = (); type DomNode = Element; fn view(&self, _: Transmitter<()>, _: Receiver<()>) -> Gizmo<Element> { Gizmo::element("") as Gizmo<Element> } fn update(&mut self, _: &(), _: &Transmitter<()>, _sub: &Subscriber<()>) {} } // This is here just for the documentation links. fn _not_used() { let _element = Gizmo::element(""); let (_tx, _rx) = txrx::<()>(); }