Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions examples/cssclasstest-brr/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Minesweeper</title>
<title>Minesweeper embryo</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="main.js"></script>
<style>
.square {
width: 1px;;
height: 1px;
padding: 1px;
width: 10px;;
height: 10px;
padding: 10px;
border: solid 1px;
}
.square-on {
Expand All @@ -19,9 +19,14 @@
.square-off {
background-color: blue;
}
.game-board {
width:800px;
display: flex;
flex-wrap: wrap;
}
</style>
</head>
<body>
<div id="main"></div>
<div class="game-board"></div>
</body>
</html>
25 changes: 14 additions & 11 deletions examples/cssclasstest-brr/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,21 @@ let ui =
Lwd_seq.monoid
squares
in
Elwd.div ~at:[ `P (At.class' (Jstr.v "game-board")) ] [
[
`S (Lwd_seq.lift board)
]

let () =
let ui = Lwd.observe ui in
let on_invalidate _ =
ignore @@ G.request_animation_frame @@ fun _ ->
ignore @@ Lwd.quick_sample ui
in
let on_load _ =
El.append_children (Document.body G.document) [ Lwd.quick_sample ui ];
Lwd.set_on_invalidate ui on_invalidate
let defer_after_dom_loading f =
let on_load _ = f () in
let _listen_id =
Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window)
in
ignore @@ Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window)
()

let () =
defer_after_dom_loading @@ fun () ->
match El.find_first_by_selector (Jstr.v ".game-board") with
| None -> failwith ".game-board could not be found, check your html"
| Some main ->
let _remove_token = Elwd.set_children main ui in
()
29 changes: 12 additions & 17 deletions examples/focustest-brr/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,17 @@ let ui =
`S (Lwd_seq.map El.txt' values);
]

let () =
let ui = Lwd.observe ui in
let on_invalidate _ =
Console.(log [str "on invalidate"]);
let _ : int =
G.request_animation_frame @@ fun _ ->
let _ui = Lwd.quick_sample ui in
(*El.set_children (Document.body G.document) [ui]*)
()
in
()
in
let on_load _ =
Console.(log [str "onload"]);
El.append_children (Document.body G.document) [Lwd.quick_sample ui];
Lwd.set_on_invalidate ui on_invalidate
let defer_after_dom_loading f =
let on_load _ = f () in
let _listen_id =
Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window)
in
ignore (Ev.listen Ev.dom_content_loaded on_load (Window.as_target G.window));
()

let () =
defer_after_dom_loading @@ fun () ->
match El.find_first_by_selector (Jstr.v "#main") with
| None -> failwith "#main could not be found, check your html"
| Some main ->
let _remove_token = Elwd.insert_sibling `Replace main ui in
()
58 changes: 58 additions & 0 deletions lib/brr-lwd/elwd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -409,3 +409,61 @@ let ul = cons Name.ul
let var = cons Name.var
let video = cons Name.video
let wbr = void_cons Name.wbr

type root = t Lwd.root

let insert first_insert anchor reactive =
let root = Lwd.observe reactive in
let last_element = ref (Lwd.quick_sample root) in
first_insert anchor [!last_element];
let on_invalidate _ =
let _ : int =
G.request_animation_frame @@ fun _ ->
let new_element = Lwd.quick_sample root in
if !last_element = new_element then ()
else (
El.insert_siblings `Replace !last_element [ new_element ];
last_element := new_element
Comment thread
voodoos marked this conversation as resolved.
)
in
()
in
Lwd.set_on_invalidate root on_invalidate;
root

let insert_sibling where anchor reactive =
let first_insert = El.insert_siblings where in
insert first_insert anchor reactive

let append_child anchor reactive =
insert El.append_children anchor reactive

let prepend_child anchor reactive =
insert El.prepend_children anchor reactive

let set_children el children =
let reactive =
let children, impure_children = consume_children children in
match impure_children with
| None -> El.set_children el children; Lwd.pure el
| Some children ->
let root = Lwd.observe children in
let c = Lwd.quick_sample root in
El.set_children el (Lwd_seq.to_list c);
Lwd.quick_release root;
update_children el children
Comment on lines +450 to +454

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well there is a bug here. Update_children expects no children at the beginning, so it will add them (again) and we end up with a duplicated initial value.
The fix is probably:

Suggested change
let root = Lwd.observe children in
let c = Lwd.quick_sample root in
El.set_children el (Lwd_seq.to_list c);
Lwd.quick_release root;
update_children el children
update_children el children

in
let root = Lwd.observe reactive in
let _el = Lwd.quick_sample root in
let on_invalidate _ =
let _ : int =
G.request_animation_frame @@ fun _ ->
let _el = Lwd.quick_sample root in
()
in
()
in
Lwd.set_on_invalidate root on_invalidate;
root

let release root = Lwd.quick_release root
27 changes: 27 additions & 0 deletions lib/brr-lwd/elwd.mli
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,33 @@ val v : ?d:document -> ?at:At.t col -> ?ev:handler col -> tag_name -> t col -> t
the final value. [d] is the document on which the element is
defined it defaults {!Brr.G.document}. *)


(** {1 Inserting reactive elements in the DOM} *)

type root

val insert_sibling : [ `Before | `After | `Replace ] -> t -> t Lwd.t -> root
(** Inserts a reactive element in the DOM, right before/after/instead of the
given element. The element is updated until the return value is passed to
{!release}. *)

val set_children : t -> t col -> root
(** Sets a set of reactive elements as the children of the given element. The
set is updated until the return value is passed to {!release}. *)

val append_child : t -> t Lwd.t -> root
(** Inserts a reactive element in the DOM, as last child of the given
element. The element is updated until the return value is passed to
{!release}. *)

val prepend_child : t -> t Lwd.t -> root
(** Inserts a reactive element in the DOM, as first child of the given
element. The element is updated until the return value is passed to
{!release}. *)

val release : root -> unit
(** Stop updating the reactive elements, leaving what is currently there. *)

(** {1:els Element constructors} *)

type cons = ?d:document -> ?at:At.t col -> ?ev:handler col -> t col -> t Lwd.t
Expand Down