Current section
Files
Jump to
Current section
Files
src/hx@hx_header.erl
-module(hx@hx_header).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/hx/hx_header.gleam").
-export([redirect/1, refresh/0, push_url/1, replace_url/1, reswap/1, retarget/1, reselect/1, location/1, trigger/1, trigger_after_swap/1, trigger_after_settle/1, location_with/1, location_config/1, target/2, swap/2, event/2, source/2, values/2]).
-export_type([location_config/0, trigger_event/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" HTMX Response Headers\n"
"\n"
" This module provides functions for setting HTMX-specific HTTP response headers.\n"
" These headers allow the server to control HTMX behavior on the client-side, enabling\n"
" powerful server-driven interactions without writing JavaScript.\n"
"\n"
" ## Framework Integration\n"
"\n"
" This module is framework-agnostic and returns standard `#(String, String)` tuples\n"
" that can be used with any Gleam web framework:\n"
"\n"
" ### Wisp\n"
" ```gleam\n"
" import hx/hx_header\n"
" import wisp\n"
"\n"
" pub fn handler(req) {\n"
" let #(name, value) = hx_header.trigger([\n"
" hx_header.SimpleTrigger(\"reload\")\n"
" ])\n"
"\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" |> wisp.html_body(\"<div>Updated</div>\")\n"
" }\n"
" ```\n"
"\n"
" ### Mist\n"
" ```gleam\n"
" import hx/hx_header\n"
" import mist\n"
"\n"
" pub fn handler(req) {\n"
" let #(name, value) = hx_header.push_url(\"/new-url\")\n"
" mist.Response(\n"
" status: 200,\n"
" headers: [#(name, value)],\n"
" body: mist.Bytes(bytes_builder.from_string(\"<div>Updated</div>\"))\n"
" )\n"
" }\n"
" ```\n"
"\n"
" ### gleam_http\n"
" ```gleam\n"
" import hx/hx_header\n"
" import gleam/http/response as http_response\n"
"\n"
" pub fn handler(req) {\n"
" let #(name, value) = hx_header.redirect(\"/login\")\n"
"\n"
" http_response.new(200)\n"
" |> http_response.set_header(name, value)\n"
" |> http_response.set_body(\"<div>Redirecting...</div>\")\n"
" }\n"
" ```\n"
"\n"
" ## Response Header Reference\n"
"\n"
" For complete documentation of HTMX response headers, see:\n"
" - [HTMX Response Headers](https://htmx.org/reference/#response_headers)\n"
" - [HX-Trigger Documentation](https://htmx.org/headers/hx-trigger/)\n"
" - [HX-Location Documentation](https://htmx.org/headers/hx-location/)\n"
).
-type location_config() :: {location_config,
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(binary()),
gleam@option:option(gleam@json:json())}.
-type trigger_event() :: {simple_trigger, binary()} |
{detailed_trigger, binary(), gleam@json:json()}.
-file("src/hx/hx_header.gleam", 119).
?DOC(
" Returns HX-Redirect header for a full page redirect.\n"
"\n"
" This will cause the browser to perform a full page reload to the specified URL,\n"
" replacing the current page entirely.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.redirect(\"/login\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec redirect(binary()) -> {binary(), binary()}.
redirect(Url) ->
{<<"HX-Redirect"/utf8>>, Url}.
-file("src/hx/hx_header.gleam", 135).
?DOC(
" Returns HX-Refresh header to refresh the page.\n"
"\n"
" This will cause the client to perform a full page refresh.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.refresh()\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec refresh() -> {binary(), binary()}.
refresh() ->
{<<"HX-Refresh"/utf8>>, <<"true"/utf8>>}.
-file("src/hx/hx_header.gleam", 151).
?DOC(
" Returns HX-Push-Url header to push a URL into the browser history.\n"
"\n"
" This updates the browser's address bar without performing a full page reload.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.push_url(\"/new-path\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec push_url(binary()) -> {binary(), binary()}.
push_url(Url) ->
{<<"HX-Push-Url"/utf8>>, Url}.
-file("src/hx/hx_header.gleam", 167).
?DOC(
" Returns HX-Replace-Url header to replace the current URL in browser history.\n"
"\n"
" This updates the browser's address bar by replacing the current history entry.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.replace_url(\"/updated-path\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec replace_url(binary()) -> {binary(), binary()}.
replace_url(Url) ->
{<<"HX-Replace-Url"/utf8>>, Url}.
-file("src/hx/hx_header.gleam", 184).
?DOC(
" Returns HX-Reswap header to change the swap strategy.\n"
"\n"
" This overrides the swap strategy specified on the element.\n"
" Valid values include: innerHTML, outerHTML, beforebegin, afterbegin, beforeend, afterend, delete, none.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.reswap(\"outerHTML\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec reswap(binary()) -> {binary(), binary()}.
reswap(Swap) ->
{<<"HX-Reswap"/utf8>>, Swap}.
-file("src/hx/hx_header.gleam", 200).
?DOC(
" Returns HX-Retarget header to change the target element.\n"
"\n"
" This overrides the target element specified on the original element.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.retarget(\"#different-element\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec retarget(binary()) -> {binary(), binary()}.
retarget(Selector) ->
{<<"HX-Retarget"/utf8>>, Selector}.
-file("src/hx/hx_header.gleam", 216).
?DOC(
" Returns HX-Reselect header to change the selected content.\n"
"\n"
" This allows you to choose a different part of the response to swap in.\n"
"\n"
" [Official Documentation](https://htmx.org/reference/#response_headers)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.reselect(\"#content\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec reselect(binary()) -> {binary(), binary()}.
reselect(Selector) ->
{<<"HX-Reselect"/utf8>>, Selector}.
-file("src/hx/hx_header.gleam", 234).
?DOC(
" Returns HX-Location header for a simple client-side redirect.\n"
"\n"
" This performs a client-side redirect using HTMX navigation to the specified URL.\n"
"\n"
" [Official Documentation](https://htmx.org/headers/hx-location/)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.location(\"/dashboard\")\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec location(binary()) -> {binary(), binary()}.
location(Url) ->
{<<"HX-Location"/utf8>>, Url}.
-file("src/hx/hx_header.gleam", 364).
-spec all_simple(list(trigger_event())) -> boolean().
all_simple(Events) ->
gleam@list:all(Events, fun(Event) -> case Event of
{simple_trigger, _} ->
true;
{detailed_trigger, _, _} ->
false
end end).
-file("src/hx/hx_header.gleam", 373).
-spec build_trigger_json(list(trigger_event())) -> gleam@json:json().
build_trigger_json(Events) ->
_pipe = Events,
_pipe@1 = gleam@list:map(_pipe, fun(Event) -> case Event of
{simple_trigger, Name} ->
{Name, gleam@json:null()};
{detailed_trigger, Name@1, Details} ->
{Name@1, Details}
end end),
gleam@json:object(_pipe@1).
-file("src/hx/hx_header.gleam", 345).
-spec build_trigger_value(list(trigger_event())) -> binary().
build_trigger_value(Events) ->
case Events of
[] ->
<<""/utf8>>;
[{simple_trigger, Name}] ->
Name;
_ ->
case all_simple(Events) of
true ->
_pipe = Events,
_pipe@1 = gleam@list:map(
_pipe,
fun(Event) ->
Name@2 = case Event of
{simple_trigger, Name@1} -> Name@1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"hx/hx_header"/utf8>>,
function => <<"build_trigger_value"/utf8>>,
line => 354,
value => _assert_fail,
start => 10166,
'end' => 10204,
pattern_start => 10177,
pattern_end => 10196})
end,
Name@2
end
),
gleam@string:join(_pipe@1, <<", "/utf8>>);
false ->
_pipe@2 = build_trigger_json(Events),
gleam@json:to_string(_pipe@2)
end
end.
-file("src/hx/hx_header.gleam", 303).
?DOC(
" Returns HX-Trigger header to trigger client-side events.\n"
"\n"
" This triggers events on the client-side immediately after receiving the response.\n"
" Events can be simple (just a name) or detailed (with a JSON payload).\n"
"\n"
" [Official Documentation](https://htmx.org/headers/hx-trigger/)\n"
"\n"
" ## Examples\n"
"\n"
" Simple event:\n"
" ```gleam\n"
" let #(name, value) = hx_header.trigger([\n"
" hx_header.SimpleTrigger(\"reload\")\n"
" ])\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
"\n"
" Event with details:\n"
" ```gleam\n"
" let details = json.object([\n"
" #(\"message\", json.string(\"Success!\")),\n"
" #(\"level\", json.string(\"info\"))\n"
" ])\n"
"\n"
" let #(name, value) = hx_header.hx_trigger([\n"
" hx_header.DetailedTrigger(\"showNotification\", details)\n"
" ])\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
"\n"
" Multiple events:\n"
" ```gleam\n"
" let #(name, value) = hx_header.trigger([\n"
" hx_header.SimpleTrigger(\"reload\"),\n"
" hx_header.SimpleTrigger(\"clearForm\")\n"
" ])\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec trigger(list(trigger_event())) -> {binary(), binary()}.
trigger(Events) ->
{<<"HX-Trigger"/utf8>>, build_trigger_value(Events)}.
-file("src/hx/hx_header.gleam", 321).
?DOC(
" Returns HX-Trigger-After-Swap header to trigger events after the swap phase.\n"
"\n"
" This triggers events after the swap has occurred but before the settle phase.\n"
"\n"
" [Official Documentation](https://htmx.org/headers/hx-trigger/)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.trigger_after_swap([\n"
" hx_header.SimpleTrigger(\"highlightNew\")\n"
" ])\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec trigger_after_swap(list(trigger_event())) -> {binary(), binary()}.
trigger_after_swap(Events) ->
{<<"HX-Trigger-After-Swap"/utf8>>, build_trigger_value(Events)}.
-file("src/hx/hx_header.gleam", 339).
?DOC(
" Returns HX-Trigger-After-Settle header to trigger events after the settle phase.\n"
"\n"
" This triggers events after the settle phase has completed.\n"
"\n"
" [Official Documentation](https://htmx.org/headers/hx-trigger/)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let #(name, value) = hx_header.trigger_after_settle([\n"
" hx_header.SimpleTrigger(\"scrollToTop\")\n"
" ])\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec trigger_after_settle(list(trigger_event())) -> {binary(), binary()}.
trigger_after_settle(Events) ->
{<<"HX-Trigger-After-Settle"/utf8>>, build_trigger_value(Events)}.
-file("src/hx/hx_header.gleam", 384).
-spec build_location_json(location_config()) -> gleam@json:json().
build_location_json(Config) ->
Base = [{<<"path"/utf8>>, gleam@json:string(erlang:element(2, Config))}],
With_source = case erlang:element(3, Config) of
{some, Source} ->
lists:append(Base, [{<<"source"/utf8>>, gleam@json:string(Source)}]);
none ->
Base
end,
With_event = case erlang:element(4, Config) of
{some, Event} ->
lists:append(
With_source,
[{<<"event"/utf8>>, gleam@json:string(Event)}]
);
none ->
With_source
end,
With_target = case erlang:element(5, Config) of
{some, Target} ->
lists:append(
With_event,
[{<<"target"/utf8>>, gleam@json:string(Target)}]
);
none ->
With_event
end,
With_swap = case erlang:element(6, Config) of
{some, Swap} ->
lists:append(
With_target,
[{<<"swap"/utf8>>, gleam@json:string(Swap)}]
);
none ->
With_target
end,
With_values = case erlang:element(7, Config) of
{some, Values} ->
lists:append(With_swap, [{<<"values"/utf8>>, Values}]);
none ->
With_swap
end,
gleam@json:object(With_values).
-file("src/hx/hx_header.gleam", 256).
?DOC(
" Returns HX-Location header with advanced options.\n"
"\n"
" This allows you to specify additional options for the client-side redirect,\n"
" such as target element, swap strategy, event source, and additional values.\n"
"\n"
" [Official Documentation](https://htmx.org/headers/hx-location/)\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let config =\n"
" hx_header.location(\"/dashboard\")\n"
" |> hx_header.with_target(\"#main\")\n"
" |> hx_header.with_swap(\"innerHTML\")\n"
"\n"
" let #(name, value) = hx_header.location_with(config)\n"
" wisp.ok()\n"
" |> wisp.set_header(name, value)\n"
" ```\n"
).
-spec location_with(location_config()) -> {binary(), binary()}.
location_with(Config) ->
{<<"HX-Location"/utf8>>,
begin
_pipe = build_location_json(Config),
gleam@json:to_string(_pipe)
end}.
-file("src/hx/hx_header.gleam", 428).
?DOC(
" Creates a new LocationConfig with the specified path.\n"
"\n"
" Use the builder functions to add additional options.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let config =\n"
" hx_header.location_config(\"/dashboard\")\n"
" |> hx_header.target(\"#main\")\n"
" |> hx_header.swap(\"innerHTML\")\n"
" ```\n"
).
-spec location_config(binary()) -> location_config().
location_config(Path) ->
{location_config, Path, none, none, none, none, none}.
-file("src/hx/hx_header.gleam", 446).
?DOC(
" Sets the target element for the location redirect.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" hx_header.location_config(\"/page\")\n"
" |> hx_header.target(\"#content\")\n"
" ```\n"
).
-spec target(location_config(), binary()) -> location_config().
target(Config, Target) ->
{location_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
{some, Target},
erlang:element(6, Config),
erlang:element(7, Config)}.
-file("src/hx/hx_header.gleam", 457).
?DOC(
" Sets the swap strategy for the location redirect.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" hx_header.location_config(\"/page\")\n"
" |> hx_header.swap(\"outerHTML\")\n"
" ```\n"
).
-spec swap(location_config(), binary()) -> location_config().
swap(Config, Swap) ->
{location_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
{some, Swap},
erlang:element(7, Config)}.
-file("src/hx/hx_header.gleam", 468).
?DOC(
" Sets the event that triggered the navigation.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" hx_header.location_config(\"/page\")\n"
" |> hx_header.event(\"click\")\n"
" ```\n"
).
-spec event(location_config(), binary()) -> location_config().
event(Config, Event) ->
{location_config,
erlang:element(2, Config),
erlang:element(3, Config),
{some, Event},
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config)}.
-file("src/hx/hx_header.gleam", 479).
?DOC(
" Sets the source element for the location redirect.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" hx_header.location_config(\"/page\")\n"
" |> hx_header.source(\"#button-1\")\n"
" ```\n"
).
-spec source(location_config(), binary()) -> location_config().
source(Config, Source) ->
{location_config,
erlang:element(2, Config),
{some, Source},
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
erlang:element(7, Config)}.
-file("src/hx/hx_header.gleam", 494).
?DOC(
" Sets additional values to include with the location redirect.\n"
"\n"
" ## Example\n"
" ```gleam\n"
" let values = json.object([\n"
" #(\"userId\", json.int(123))\n"
" ])\n"
"\n"
" hx_header.location_config(\"/page\")\n"
" |> hx_header.values(values)\n"
" ```\n"
).
-spec values(location_config(), gleam@json:json()) -> location_config().
values(Config, Values) ->
{location_config,
erlang:element(2, Config),
erlang:element(3, Config),
erlang:element(4, Config),
erlang:element(5, Config),
erlang:element(6, Config),
{some, Values}}.