diff --git a/src/util/JsUtil.re b/src/util/JsUtil.re index 5fae47089b..afd5d3581e 100644 --- a/src/util/JsUtil.re +++ b/src/util/JsUtil.re @@ -78,6 +78,13 @@ let read_file = (file, k) => { }); }; +let reset_file_input = (input_id: string): unit => { + switch (get_elem_by_id_opt(input_id)) { + | Some(elem) => Js.Unsafe.set(elem, "value", Js.string("")) + | None => () + }; +}; + let set_localstore = (k: string, v: string): unit => { let local_store = Js.Optdef.get(Dom_html.window##.localStorage, () => assert(false)); diff --git a/src/web/app/common/Widgets.re b/src/web/app/common/Widgets.re index fc23d630c1..5b707973ea 100644 --- a/src/web/app/common/Widgets.re +++ b/src/web/app/common/Widgets.re @@ -74,14 +74,15 @@ let file_select_button = (~tooltip="", id, icon, on_input) => { ); }; -let file_select_button_named = (~tooltip="", id, icon, on_input) => +let file_select_button_named = + (~tooltip="", ~accept=[`Extension("json")], id, icon, on_input) => /* https://stackoverflow.com/questions/572768/styling-an-input-type-file-button */ label( ~attrs=[Attr.for_(id)], [ Vdom_input_widgets.File_select.single( ~extra_attrs=[Attr.class_("file-select-button"), Attr.id(id)], - ~accept=[`Extension("json")], + ~accept, ~on_input, (), ), diff --git a/src/web/view/ScratchMode.re b/src/web/view/ScratchMode.re index 80aeb58f83..43ba343f12 100644 --- a/src/web/view/ScratchMode.re +++ b/src/web/view/ScratchMode.re @@ -136,9 +136,13 @@ module Update = { }; let export_scratch_slide = (model: Model.t): unit => { - Store.save(model |> Model.persist); - let data = Store.export(); - let current_name = List.nth(model.scratchpads, model.current) |> fst; + let (current_name, current_editor) = + List.nth(model.scratchpads, model.current); + let persistent = CellEditor.Model.persist(current_editor); + let data = + persistent + |> CellEditor.Model.sexp_of_persistent + |> Sexplib.Sexp.to_string; let filename = current_name |> StringUtil.sanitize_filename; JsUtil.download_string_file( ~filename, @@ -334,22 +338,31 @@ module Update = { schedule_action(FinishImportScratchpad(data)) ); model |> return_quiet; - | FinishImportScratchpad(None) => model |> return_quiet - | FinishImportScratchpad(Some(data)) => - let key = List.nth(model.scratchpads, model.current) |> fst; - let new_data = - data - |> Sexplib.Sexp.of_string - |> CellEditor.Model.persistent_of_sexp - |> CellEditor.Model.unpersist(~settings=settings.core); - - let scratchpads = - ListUtil.put_nth(model.current, (key, new_data), model.scratchpads); - { - ...model, - scratchpads, - } - |> Updated.return; + | FinishImportScratchpad(data) => + // reset file input so same file can be re-imported if desired + JsUtil.reset_file_input("import-scratchpad"); + switch (data) { + | None => model |> return_quiet + | Some(data) => + let key = List.nth(model.scratchpads, model.current) |> fst; + let new_data = + data + |> Sexplib.Sexp.of_string + |> CellEditor.Model.persistent_of_sexp + |> CellEditor.Model.unpersist(~settings=settings.core); + + let scratchpads = + ListUtil.put_nth( + model.current, + (key, new_data), + model.scratchpads, + ); + { + ...model, + scratchpads, + } + |> Updated.return; + }; | Export => export_scratch_slide(model); model |> Updated.return_quiet; @@ -525,6 +538,7 @@ module View = { | Some(file) => inject(InitImportScratchpad(file)) } }, + ~accept=[], ~tooltip="Import Scratchpad", );