Skip to content

Commit f2d5998

Browse files
committed
Move builder into new file and some fn typedefs into a separate file
1 parent 2d7e285 commit f2d5998

File tree

4 files changed

+255
-208
lines changed

4 files changed

+255
-208
lines changed

src/vdom.rs

Lines changed: 10 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,23 @@ use crate::{
2121
websys_bridge,
2222
};
2323

24+
mod alias;
25+
mod builder;
26+
27+
pub use alias::*;
28+
pub use builder::{Builder as AppBuilder, Init, Initializer, UrlHandling};
29+
2430
pub enum Effect<Ms, GMs> {
2531
Msg(Ms),
2632
Cmd(Box<dyn Future<Item = Ms, Error = Ms> + 'static>),
2733
GMsg(GMs),
2834
GCmd(Box<dyn Future<Item = GMs, Error = GMs> + 'static>),
2935
}
30-
3136
impl<Ms, GMs> From<Ms> for Effect<Ms, GMs> {
3237
fn from(message: Ms) -> Self {
3338
Effect::Msg(message)
3439
}
3540
}
36-
3741
impl<Ms: 'static, OtherMs: 'static, GMs> MessageMapper<Ms, OtherMs> for Effect<Ms, GMs> {
3842
type SelfWithOtherMs = Effect<OtherMs, GMs>;
3943
fn map_message(self, f: impl FnOnce(Ms) -> OtherMs + 'static + Clone) -> Effect<OtherMs, GMs> {
@@ -53,47 +57,6 @@ pub enum ShouldRender {
5357
Skip,
5458
}
5559

56-
//type InitFn<Ms, Mdl, ElC, GMs> =
57-
// Box<dyn FnOnce(routing::Url, &mut OrdersContainer<Ms, Mdl, ElC, GMs>) -> Mdl>;
58-
type InitFn<Ms, Mdl, ElC, GMs> =
59-
Box<dyn FnOnce(routing::Url, &mut OrdersContainer<Ms, Mdl, ElC, GMs>) -> Init<Mdl>>;
60-
type UpdateFn<Ms, Mdl, ElC, GMs> = fn(Ms, &mut Mdl, &mut OrdersContainer<Ms, Mdl, ElC, GMs>);
61-
type SinkFn<Ms, Mdl, ElC, GMs> = fn(GMs, &mut Mdl, &mut OrdersContainer<Ms, Mdl, ElC, GMs>);
62-
type ViewFn<Mdl, ElC> = fn(&Mdl) -> ElC;
63-
type RoutesFn<Ms> = fn(routing::Url) -> Option<Ms>;
64-
type WindowEvents<Ms, Mdl> = fn(&Mdl) -> Vec<events::Listener<Ms>>;
65-
type MsgListeners<Ms> = Vec<Box<dyn Fn(&Ms)>>;
66-
67-
/// Used for handling initial routing.
68-
pub enum UrlHandling {
69-
PassToRoutes,
70-
None,
71-
// todo: Expand later, as-required
72-
}
73-
74-
/// Used as a flexible wrapper for the init function.
75-
pub struct Init<Mdl> {
76-
// init: InitFn<Ms, Mdl, ElC, GMs>,
77-
model: Mdl,
78-
url_handling: UrlHandling,
79-
}
80-
81-
impl<Mdl> Init<Mdl> {
82-
pub const fn new(model: Mdl) -> Self {
83-
Self {
84-
model,
85-
url_handling: UrlHandling::PassToRoutes,
86-
}
87-
}
88-
89-
pub const fn new_with_url_handling(model: Mdl, url_handling: UrlHandling) -> Self {
90-
Self {
91-
model,
92-
url_handling,
93-
}
94-
}
95-
}
96-
9760
pub struct Mailbox<Message: 'static> {
9861
func: Rc<dyn Fn(Message)>,
9962
}
@@ -170,169 +133,18 @@ impl<Ms: 'static + Clone, Mdl: 'static, ElC: View<Ms>, GMs> ::std::fmt::Debug
170133
}
171134
}
172135

173-
pub trait MountPoint {
174-
fn element(self) -> Element;
175-
}
176-
177-
impl MountPoint for &str {
178-
fn element(self) -> Element {
179-
util::document().get_element_by_id(self).unwrap_or_else(|| {
180-
panic!(
181-
"Can't find element with id={:?} - app cannot be mounted!\n\
182-
(Id defaults to \"app\", or can be set with the .mount() method)",
183-
self
184-
)
185-
})
186-
}
187-
}
188-
189-
impl MountPoint for Element {
190-
fn element(self) -> Element {
191-
self
192-
}
193-
}
194-
195-
impl MountPoint for web_sys::HtmlElement {
196-
fn element(self) -> Element {
197-
self.into()
198-
}
199-
}
200-
201-
/// Used to create and store initial app configuration, ie items passed by the app creator
202-
pub struct AppBuilder<Ms: 'static + Clone, Mdl: 'static, ElC: View<Ms>, GMs> {
203-
init: InitFn<Ms, Mdl, ElC, GMs>,
204-
update: UpdateFn<Ms, Mdl, ElC, GMs>,
205-
sink: Option<SinkFn<Ms, Mdl, ElC, GMs>>,
206-
view: ViewFn<Mdl, ElC>,
207-
mount_point: Option<Element>,
208-
takeover_mount: bool,
209-
routes: Option<RoutesFn<Ms>>,
210-
window_events: Option<WindowEvents<Ms, Mdl>>,
211-
}
212-
213-
impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> AppBuilder<Ms, Mdl, ElC, GMs> {
214-
/// Choose the element where the application will be mounted.
215-
/// The default one is the element with `id` = "app".
216-
///
217-
/// # Examples
218-
///
219-
/// ```rust,no_run
220-
/// // argument is `&str`
221-
/// mount("another_id")
222-
///
223-
/// // argument is `HTMLElement`
224-
/// // NOTE: Be careful with mounting into body,
225-
/// // it can cause hard-to-debug bugs when there are other scripts in the body.
226-
/// mount(seed::body())
227-
///
228-
/// // argument is `Element`
229-
/// mount(seed::body().querySelector("section").unwrap().unwrap())
230-
/// ```
231-
pub fn mount(mut self, mount_point: impl MountPoint) -> Self {
232-
self.mount_point = Some(mount_point.element());
233-
self
234-
}
235-
236-
#[deprecated(since = "0.3.3", note = "please use `mount` instead")]
237-
pub fn mount_el(mut self, el: Element) -> Self {
238-
self.mount_point = Some(el);
239-
self
240-
}
241-
242-
/// Allows for the [`App`] to takeover all the children of the mount point. The default
243-
/// behavior is that the [`App`] ignores the children and leaves them in place. The new
244-
/// behavior can be useful if SSR is implemented.
245-
///
246-
/// As of right now, nodes found in the root will be destroyed and recreated once. This can
247-
/// cause duplicated scripts, css, and other tags that should not otherwise be duplicated.
248-
/// Unrecognized tags are also converted into spans, so take note.
249-
pub fn takeover_mount(mut self, should_takeover: bool) -> Self {
250-
self.takeover_mount = should_takeover;
251-
self
252-
}
253-
254-
/// Registers a function which maps URLs to messages.
255-
pub fn routes(mut self, routes: RoutesFn<Ms>) -> Self {
256-
self.routes = Some(routes);
257-
self
258-
}
259-
260-
/// Registers a function which decides how window events will be handled.
261-
pub fn window_events(mut self, evts: WindowEvents<Ms, Mdl>) -> Self {
262-
self.window_events = Some(evts);
263-
self
264-
}
265-
266-
/// Registers a sink function.
267-
///
268-
/// The sink function is a function which can update the model based
269-
/// on global messages. Consider to use a sink function when a
270-
/// submodule needs to trigger changes in other modules.
271-
pub fn sink(mut self, sink: SinkFn<Ms, Mdl, ElC, GMs>) -> Self {
272-
self.sink = Some(sink);
273-
self
274-
}
275-
276-
/// Turn this [`AppBuilder`] into an [`App`] which is ready to run.
277-
///
278-
/// [`AppBuilder`]: struct.AppBuilder.html
279-
/// [`App`]: struct.App.html
280-
pub fn finish(mut self) -> App<Ms, Mdl, ElC, GMs> {
281-
if self.mount_point.is_none() {
282-
self = self.mount("app")
283-
}
284-
285-
let app = App::new(
286-
self.update,
287-
self.sink,
288-
self.view,
289-
self.mount_point.unwrap(),
290-
self.takeover_mount,
291-
self.routes,
292-
self.window_events,
293-
);
294-
295-
let mut initial_orders = OrdersContainer::new(app.clone());
296-
let mut init = (self.init)(routing::initial_url(), &mut initial_orders);
297-
298-
match init.url_handling {
299-
UrlHandling::PassToRoutes => {
300-
let url = routing::initial_url();
301-
if let Some(r) = self.routes {
302-
(self.update)(r(url).unwrap(), &mut init.model, &mut initial_orders);
303-
}
304-
}
305-
UrlHandling::None => (),
306-
};
307-
308-
app.cfg.initial_orders.replace(Some(initial_orders));
309-
app.data.model.replace(Some(init.model));
310-
311-
app
312-
}
313-
}
314-
315136
/// We use a struct instead of series of functions, in order to avoid passing
316137
/// repetitive sequences of parameters.
317138
impl<Ms: Clone, Mdl, ElC: View<Ms> + 'static, GMs: 'static> App<Ms, Mdl, ElC, GMs> {
318-
pub fn build(
319-
init: impl FnOnce(routing::Url, &mut OrdersContainer<Ms, Mdl, ElC, GMs>) -> Init<Mdl> + 'static,
139+
pub fn build<I: FnOnce(routing::Url, &mut OrdersContainer<Ms, Mdl, ElC, GMs>) -> Init<Mdl>>(
140+
init: I,
320141
update: UpdateFn<Ms, Mdl, ElC, GMs>,
321142
view: ViewFn<Mdl, ElC>,
322-
) -> AppBuilder<Ms, Mdl, ElC, GMs> {
143+
) -> AppBuilder<Ms, Mdl, ElC, GMs, I> {
323144
// Allows panic messages to output to the browser console.error.
324145
console_error_panic_hook::set_once();
325146

326-
AppBuilder {
327-
init: Box::new(init),
328-
update,
329-
view,
330-
sink: None,
331-
mount_point: None,
332-
takeover_mount: false,
333-
routes: None,
334-
window_events: None,
335-
}
147+
AppBuilder::new(init, update, view)
336148
}
337149

338150
#[allow(clippy::too_many_arguments)]

src/vdom/alias.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use crate::{events, orders::OrdersContainer, routing};
2+
3+
pub type UpdateFn<Ms, Mdl, ElC, GMs> = fn(Ms, &mut Mdl, &mut OrdersContainer<Ms, Mdl, ElC, GMs>);
4+
pub type SinkFn<Ms, Mdl, ElC, GMs> = fn(GMs, &mut Mdl, &mut OrdersContainer<Ms, Mdl, ElC, GMs>);
5+
pub type ViewFn<Mdl, ElC> = fn(&Mdl) -> ElC;
6+
pub type RoutesFn<Ms> = fn(routing::Url) -> Option<Ms>;
7+
pub type WindowEvents<Ms, Mdl> = fn(&Mdl) -> Vec<events::Listener<Ms>>;
8+
pub type MsgListeners<Ms> = Vec<Box<dyn Fn(&Ms)>>;

0 commit comments

Comments
 (0)