From 3ce21441d5116b69eb511f5dba70765ec6eccbd2 Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Mon, 7 Feb 2022 15:22:05 +0100 Subject: Added a file loader element --- css/merger.ml | 72 +++++++++++++++++++-------------------------------- lib/elements/input.ml | 47 +++++++++++++++++++++++++++++++++ 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 ) -- cgit v1.2.3