-module(sprocket@context). -compile([no_auto_import, nowarn_unused_vars]). -export([new/2, reset_for_render/1, fetch_or_init_hook/2, update_hook/3, push_event_handler/2, get_event_handler/2, dispatch_event/4]). -export_type([element/0, event_handler/0, updater/1, dispatcher/0, component_wip/0, context/0]). -type element() :: {element, binary(), list(sprocket@html@attributes:attribute()), list(element())} | {component, fun((context(), gleam@dynamic:dynamic_()) -> {context(), list(element())}), gleam@dynamic:dynamic_()} | {debug, binary(), gleam@option:option(gleam@dynamic:dynamic_()), element()} | {keyed, binary(), element()} | {ignore_update, element()} | {safe_html, binary()} | {raw, binary()}. -type event_handler() :: {event_handler, sprocket@internal@utils@unique:unique(), sprocket@internal@identifiable_callback:callback_fn()}. -type updater(KNJ) :: {updater, fun((KNJ) -> {ok, nil} | {error, nil})}. -type dispatcher() :: {dispatcher, fun((binary(), binary(), gleam@option:option(binary())) -> {ok, nil} | {error, nil})}. -type component_wip() :: {component_wip, sprocket@internal@utils@ordered_map:ordered_map(integer(), sprocket@hooks:hook()), integer(), boolean()}. -type context() :: {context, element(), component_wip(), list(event_handler()), fun(() -> nil), fun((sprocket@internal@utils@unique:unique(), fun((sprocket@hooks:hook()) -> sprocket@hooks:hook())) -> nil), fun((sprocket@internal@utils@unique:unique(), binary(), gleam@option:option(binary())) -> {ok, nil} | {error, nil})}. -spec new(element(), gleam@option:option(dispatcher())) -> context(). new(View, Dispatcher) -> {context, View, {component_wip, sprocket@internal@utils@ordered_map:new(), 0, true}, [], fun() -> nil end, fun(_, _) -> nil end, fun(Id, Name, Payload) -> case Dispatcher of {some, {dispatcher, Dispatch}} -> Dispatch( sprocket@internal@utils@unique:to_string(Id), Name, Payload ); none -> {error, nil} end end}. -spec reset_for_render(context()) -> context(). reset_for_render(Ctx) -> erlang:setelement(4, Ctx, []). -spec fetch_or_init_hook(context(), fun(() -> sprocket@hooks:hook())) -> {context(), sprocket@hooks:hook(), integer()}. fetch_or_init_hook(Ctx, Init) -> Index = erlang:element(3, erlang:element(3, Ctx)), Hooks = erlang:element(2, erlang:element(3, Ctx)), case sprocket@internal@utils@ordered_map:get(Hooks, Index) of {ok, Hook} -> {erlang:setelement( 3, Ctx, erlang:setelement(3, erlang:element(3, Ctx), Index + 1) ), Hook, Index}; {error, nil} -> case erlang:element(4, erlang:element(3, Ctx)) of true -> nil; false -> sprocket@internal@logger:error( <<<<" Hook not found for index: "/utf8, (gleam@int:to_string(Index))/binary>>/binary, ". This indicates a hook was dynamically created since first render which is not allowed. "/utf8>> ), erlang:error(#{gleam_error => panic, message => <<"panic expression evaluated"/utf8>>, module => <<"sprocket/context"/utf8>>, function => <<"fetch_or_init_hook"/utf8>>, line => 109}) end, Hook@1 = Init(), {erlang:setelement( 3, Ctx, {component_wip, sprocket@internal@utils@ordered_map:insert( erlang:element(2, erlang:element(3, Ctx)), Index, Hook@1 ), Index + 1, erlang:element(4, erlang:element(3, Ctx))} ), Hook@1, Index} end. -spec update_hook(context(), sprocket@hooks:hook(), integer()) -> context(). update_hook(Ctx, Hook, Index) -> erlang:setelement( 3, Ctx, erlang:setelement( 2, erlang:element(3, Ctx), sprocket@internal@utils@ordered_map:update( erlang:element(2, erlang:element(3, Ctx)), Index, Hook ) ) ). -spec push_event_handler( context(), sprocket@internal@identifiable_callback:identifiable_callback() ) -> {context(), sprocket@internal@utils@unique:unique()}. push_event_handler(Ctx, Identifiable_cb) -> {identifiable_callback, Id, Cb} = Identifiable_cb, {erlang:setelement( 4, Ctx, [{event_handler, Id, Cb} | erlang:element(4, Ctx)] ), Id}. -spec get_event_handler(context(), sprocket@internal@utils@unique:unique()) -> {context(), {ok, event_handler()} | {error, nil}}. get_event_handler(Ctx, Id) -> Handler = gleam@list:find( erlang:element(4, Ctx), fun(H) -> {event_handler, I, _} = H, I =:= Id end ), {Ctx, Handler}. -spec dispatch_event( context(), sprocket@internal@utils@unique:unique(), binary(), gleam@option:option(binary()) ) -> {ok, nil} | {error, nil}. dispatch_event(Ctx, Id, Name, Payload) -> (erlang:element(7, Ctx))(Id, Name, Payload).