aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2022-02-07 15:22:05 +0100
committerSébastien Dailly <sebastien@dailly.me>2022-02-07 16:22:43 +0100
commit3ce21441d5116b69eb511f5dba70765ec6eccbd2 (patch)
treeb5a4f44d577638437f2256db9df4e1ad8e34bd58
parent92fe01fc6e93faf3ef77b45eb77632bc2806f202 (diff)
Added a file loader element
-rwxr-xr-xcss/merger.ml72
-rwxr-xr-xlib/elements/input.ml47
2 files changed, 74 insertions, 45 deletions
diff --git a/css/merger.ml b/css/merger.ml
index 752a38f..569dd27 100755
--- a/css/merger.ml
+++ b/css/merger.ml
@@ -55,7 +55,9 @@ module AddFile = struct
end
module DelFile = struct
+
type t = File.t
+
let update file state =
let files = state.files##filter
(Js.wrap_callback @@ (fun elt _ _ -> Js.bool (elt.file != file))) in
@@ -64,24 +66,6 @@ module DelFile = struct
{ files ; elements ; result_css }
end
-(** Read the content from the file *)
-let file_loader
- : file Note.E.send -> File.t -> unit
- = fun event file ->
- let blob = File.as_blob file in
- Fut.await
- (Blob.text blob)
- (Result.iter
- (fun content ->
-
- let str_content = Jstr.to_string content in
- let css = try
- Some (Css.Parser.parse_stylesheet str_content)
- with
- | _ -> None
- in
- event {file; css} ))
-
let header =
let button =
El.span
@@ -143,26 +127,15 @@ let file_list
let buttons:
- state -> on_change:(Brr.File.t list -> unit) -> El.t list
- = fun state ~on_change ->
- let _ = state in
- (* The input file can't be styled we hide it and use a click forwarding
- button instead. *)
- let i = El.input ()
- ~at:[ At.type' (Jstr.v "file")
- ; (At.v (Jstr.v "accept")) (Jstr.v ".css")
- ] in
- El.set_inline_style El.Style.display (Jstr.v "none") i;
-
+ state -> El.t -> El.t list
+ = fun state input ->
let b = El.button [ El.txt' "Ajouter un fichier…" ]
~at:[ At.class' (Jstr.v "button")] in
let d = El.button [ El.txt' "Télécharger" ]
~at:[ At.class' (Jstr.v "button")] in
- Ev.listen Ev.click (fun _e -> El.click i) (El.as_target b);
- Ev.listen Ev.change (fun _e -> on_change (El.Input.files i)) (El.as_target i);
-
+ Ev.listen Ev.click (fun _e -> El.click input) (El.as_target b);
Ev.listen Ev.click (fun _ ->
match state.result_css with
@@ -182,8 +155,8 @@ let buttons:
(Js.wrap_callback (fun elem _idx _arr -> Js.bool (elem.css != None))) in
match Js.to_bool has_css with
- | true -> [i; b; d]
- | false -> [i; b]
+ | true -> [b; d]
+ | false -> [b]
let display_content css =
@@ -228,18 +201,29 @@ let main id =
| false ->
let elements = El.div [] in
- let add_file_event, add_file_sender = Note.E.create () in
let del_file_event, del_file_sender = Note.E.create () in
+ let file_event, input = Elements.Input.file_loader
+ (Jstr.v "css") in
+
+ let add_file_event =
+ Note.E.map
+ (fun Elements.Input.{file ; content} ->
+ let str_content = Jstr.to_string content in
+ let css = try
+ Some (Css.Parser.parse_stylesheet str_content)
+ with
+ | _ -> None
+ in
+ App.E ( { file ; css }
+ , (module AddFile: App.Event with type t = AddFile.t )))
+ file_event in
let state =
App.run
init
(E.select
- [ E.map (fun f ->
- App.E ( f
- , (module AddFile: App.Event with type t = AddFile.t )))
- add_file_event
+ [ add_file_event
; del_file_event
])
in
@@ -260,17 +244,15 @@ let main id =
(display_content state.result_css))
state) in
- let on_change files =
- file_loader
- add_file_sender
- (List.hd files) in
-
let header = El.span [] in
+ (* The input is hidden, it will be activated by a button *)
+ El.set_inline_style El.Style.display (Jstr.v "none") input;
+
Elr.def_children
header
(S.map (fun state ->
- buttons ~on_change state)
+ input::(buttons state input))
state);
El.set_children (Jv.Id.of_jv id) [El.p [header]; elements]
diff --git a/lib/elements/input.ml b/lib/elements/input.ml
index 6ae9aa8..8a082d8 100755
--- a/lib/elements/input.ml
+++ b/lib/elements/input.ml
@@ -21,3 +21,50 @@ let slider
|> S.hold init_value
in
slider, event
+
+type file =
+ { file : File.t
+ ; content : Jstr.t
+ }
+
+(** Read the content from the file *)
+let file_loader
+ : file Note.E.send -> File.t -> unit
+ = fun event file ->
+ let blob = File.as_blob file in
+ Fut.await
+ (Blob.text blob)
+ (Result.iter
+ (fun content ->
+ event ({file; content}) ))
+
+(** Create an imput which load a file.
+
+ [file_loader (Jstr.v ".json"] will create an input which only accept json
+ files, and an event which gives access to the file.
+
+*)
+let file_loader
+ : Jstr.t -> file Note.event * Brr.El.t
+ = fun selector ->
+
+ let add_file_event, add_file_sender = Note.E.create () in
+
+ let i = El.input ()
+ ~at:[ At.type' (Jstr.v "file")
+ ; (At.v (Jstr.v "accept")) selector
+ ] in
+
+ (* The event return a list of files.
+
+ We are only interested by a single on, and keep only the first from the
+ list. *)
+ let on_change files =
+ file_loader add_file_sender (List.hd files) in
+
+ Ev.listen
+ Ev.change
+ (fun _e -> on_change (El.Input.files i)) (El.as_target i);
+
+ ( add_file_event
+ , i )