///|
/// get basic App structure
pub(all) struct RespoApp[Model] {
store : Ref[Model]
storage_key : String
mount_target : @dom_ffi.Node
}
///|
/// backup store to local storage before unload
pub fn[Model : ToJson] RespoApp::backup_model_beforeunload(
self : RespoApp[Model],
) -> Unit {
let window = @dom_ffi.window()
let storage = window.local_storage()
let p = self.storage_key
let store_ref = self.store // capture the Ref, not the value
let beforeunload = (_e : @dom_ffi.BeforeUnloadEvent) => {
let content = store_ref.val.to_json().stringify() // get current value from Ref
@dom_ffi.log("before unload \{p} \{content}")
storage.set_item(p, content)
}
window.set_onbeforeunload(beforeunload)
}
///|
pub fn[Model : @json.FromJson + Default] try_load_storage(
key : String,
) -> Model {
let window = @dom_ffi.window()
let storage = window.local_storage()
match storage.get_item(key) {
Some(s) => {
println("loaded storage:\n\{s}")
try {
let j = @json.parse(s)
@json.from_json(j) catch {
_e => {
@dom_ffi.log("failed to parse storage: {_e}")
Model::default()
}
}
} catch {
_e => {
@dom_ffi.log("failed to parse storage: {_e}")
Model::default()
}
}
}
None => {
@dom_ffi.log("no storage")
Model::default()
}
}
}
///|
pub fn[Model : Eq, ActionOp] RespoApp::render_loop(
self : RespoApp[Model],
renderer : () -> @node.RespoNode[ActionOp] raise @node.RespoCommonError,
dispatch_action : (ActionOp) -> Unit raise @node.RespoCommonError,
) -> Unit {
let mount_target = self.mount_target
render_node(mount_target, self.store, renderer, dispatch_action, Some(100)) catch {
e => @dom_ffi.error_log(e.to_string())
}
}
// pub trait RespoStore: ToJson + @json.FromJson {
// // TODO better use RespoAction instead of Show
// update(Self, Show) -> Unit!@node.RespoCommonError
// get_states(Self) -> RespoStatesTree
// update_states(Self, RespoStatesTree) -> Unit!@node.RespoCommonError
// to_string(Self) -> String
// try_from_string(Self, String) -> Self!@node.RespoCommonError
// }