try to create a new behavior
This commit is contained in:
104
src/gabarit_generator.erl
Normal file
104
src/gabarit_generator.erl
Normal file
@@ -0,0 +1,104 @@
|
||||
%%%===================================================================
|
||||
%%% @doc draft.
|
||||
%%% @end
|
||||
%%%===================================================================
|
||||
-module(gabarit_generator).
|
||||
-export([compile/3, compile/4]).
|
||||
-export([flatten/2]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
compile(Module, Args, Data) ->
|
||||
compile(Module, Args, Data, #{}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
compile(Module, Args, Data, Opts) ->
|
||||
init_loop(Module, Args, Data, Opts).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
init_loop(Module, Args, Data, Opts) ->
|
||||
try Module:init(Args) of
|
||||
{ok, State} ->
|
||||
loop(Module, Data, Opts, State, [], [])
|
||||
catch
|
||||
E:R:S ->
|
||||
{error, {E,R,S}}
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% custom function to flatten an improper list containing binaries and
|
||||
%% other terms.
|
||||
%%--------------------------------------------------------------------
|
||||
flatten([], Buffer)
|
||||
when is_binary(Buffer) -> Buffer;
|
||||
flatten([], Buffer)
|
||||
when is_list(Buffer) -> lists:reverse(Buffer);
|
||||
flatten([H|T], Buffer)
|
||||
when is_binary(H), is_binary(Buffer) ->
|
||||
flatten(T, <<Buffer/binary, H/binary>>);
|
||||
flatten([H|T], Buffer)
|
||||
when is_binary(Buffer) ->
|
||||
flatten(T, [H|[Buffer]]);
|
||||
flatten([H|T], [Last|Rest])
|
||||
when is_binary(Last), is_binary(H) ->
|
||||
flatten(T, [<<Last/binary, H/binary>>|Rest]);
|
||||
flatten([H|T], Buffer)
|
||||
when is_list(Buffer) ->
|
||||
flatten(T, [H|Buffer]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
loop(Module, Data, Opts, State, LBuffer, RBuffer) ->
|
||||
case elements(Module, Data, Opts, State, LBuffer, RBuffer) of
|
||||
{ok, L, R, _State} ->
|
||||
List = lists:flatten([L,R]),
|
||||
Flatten = flatten(List, <<>>),
|
||||
{ok, Flatten};
|
||||
Elsewise ->
|
||||
Elsewise
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
elements(Module, [], Opts, State, LB, RB) ->
|
||||
{ok, LB, RB, State};
|
||||
elements(Module, [Element|Elements], Opts, State, LB, RB) ->
|
||||
case element(Module, Element, Opts, State) of
|
||||
{ok, Content, NewState} ->
|
||||
elements(Module, Elements, Opts, NewState, [LB, Content], RB);
|
||||
{ok, Begin, End, NewState} ->
|
||||
elements(Module, Elements, Opts, NewState, [LB, Begin], [End,RB]);
|
||||
Elsewise ->
|
||||
Elsewise
|
||||
end;
|
||||
elements(Module, Element, Opts, State, LB, RB) ->
|
||||
case element(Module, Element, Opts, State) of
|
||||
{ok, Content, NewState} ->
|
||||
{ok, [LB, Content], RB, NewState};
|
||||
{ok, Begin, End, NewState} ->
|
||||
{ok, [LB, Begin], [End,RB], NewState};
|
||||
Elsewise ->
|
||||
Elsewise
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
element(Module, Element, Opts, State) ->
|
||||
case Module:tag(Element, Opts, State) of
|
||||
{ok, Content, NewState} ->
|
||||
{ok, Content, NewState};
|
||||
{ok, Begin, End, NewState} ->
|
||||
{ok, Begin, End, NewState};
|
||||
{ok, Begin, End, Inner, NewState} ->
|
||||
elements(Module, Inner, Opts, NewState, [Begin], [End]);
|
||||
Elsewise ->
|
||||
Elsewise
|
||||
end.
|
||||
@@ -33,17 +33,55 @@
|
||||
%%% module when compiling. Different models can be used:
|
||||
%%%
|
||||
%%% - Store templates into ETS (in memory)
|
||||
%%%
|
||||
%%%
|
||||
%%% - Compile a module with common interface
|
||||
%%%
|
||||
%%% - Store static page in cache with versionning and dynamic one on
|
||||
%%% another storage layer.
|
||||
%%%
|
||||
%%% == Notes ==
|
||||
%%%
|
||||
%%% ```
|
||||
%%% {}: null
|
||||
%%% {Variable}: variable
|
||||
%%% {Tag, Content}: tag without attribute
|
||||
%%% {Tag, Attribute, Content}: full tag
|
||||
%%% {Tag, Attribute, Content, Opts}: full tag with custom options
|
||||
%%% {apply, Module, Function, Args}: special tag
|
||||
%%% {apply, Function}
|
||||
%%% {apply, Function, Args}
|
||||
%%% '''
|
||||
%%%
|
||||
%%% Static template produce (a binary):
|
||||
%%%
|
||||
%%% ```
|
||||
%%% <<"<body><head>test</head></body>">>
|
||||
%%% '''
|
||||
%%%
|
||||
%%% Dynamic template production (a list of binaries and tuples):
|
||||
%%%
|
||||
%%% ```
|
||||
%%% [ <<"<body><head>"
|
||||
%%% , {apply, Module, Function, Args}
|
||||
%%% , "</head></body>">>
|
||||
%%% ]
|
||||
%%% '''
|
||||
%%%
|
||||
%%% ```
|
||||
%%% 1: [{body, #{}, {head, #{}, []}}].
|
||||
%%% 2: {body, #{}, {head, #{}, []}}.
|
||||
%%% 3: ["<body>", {head, #{}, []} ,"</body>"]
|
||||
%%% 4: ["<body>", "<head>", "</head>", "</body>"]
|
||||
%%% 5: "<body><head></head></body>"
|
||||
%%% '''
|
||||
%%%
|
||||
%%% @end
|
||||
%%%===================================================================
|
||||
-module(gabarit_html_tag).
|
||||
-export([create/1, create/2]).
|
||||
-export([init/1]).
|
||||
-export([tag/3]).
|
||||
-export([attribute/4, key/3, value/3]).
|
||||
-export([attribute/5]).
|
||||
-export([content/3]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
@@ -55,6 +93,22 @@
|
||||
-type return_stop() :: {stop, term(), state()}.
|
||||
-type return() :: return_ok() | return_stop().
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
create(Data) -> create(Data, #{}).
|
||||
create(Data, Opts) -> gabarit_generator:compile(?MODULE, Opts, Data).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
-spec init(Args) -> Return when
|
||||
Args :: term(),
|
||||
Return :: term().
|
||||
|
||||
init(Args) ->
|
||||
{ok, []}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc main function used to generate html using gabarit tags.
|
||||
%% @end
|
||||
@@ -69,69 +123,120 @@
|
||||
% add variable support (template only). A variable can be any Erlang
|
||||
% term but MUST be present in variables key from Opts
|
||||
%---------------------------------------------------------------------
|
||||
tag({Variable}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({Variable} = Tag, Opts, State) ->
|
||||
{stop, {todo, Tag, Opts}, State};
|
||||
|
||||
%--------------------------------------------------------------------
|
||||
% explicit content with specific options
|
||||
%--------------------------------------------------------------------
|
||||
tag({content, Content} = Tag, Opts, State) ->
|
||||
content(Content, Opts, State);
|
||||
tag({content, Content, LocalOpts} = Tag, Opts, State) ->
|
||||
content(Content, maps:merge(Opts, LocalOpts), State);
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add raw include support. A raw include can use default parameters
|
||||
% from Opts but can also use local parameters, useful if someone needs
|
||||
% to insert a script or stylecheat.
|
||||
%---------------------------------------------------------------------
|
||||
tag({include_raw, Path}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({include_raw, Path, LocalOpts}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({include_raw, Path} = Tag, Opts, State) ->
|
||||
{stop, {todo, Tag, Opts}, State};
|
||||
tag({include_raw, Path, LocalOpts} = Tag, Opts, State) ->
|
||||
{stop, {todo, Tag, Opts}, State};
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add template include support. A template is an erml file or a list
|
||||
% of term containing gabarit html tags.
|
||||
%---------------------------------------------------------------------
|
||||
tag({include_template, Path}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({include_template, Path, LocalOpts}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({include_template, Path} = Tag, Opts, State) ->
|
||||
{stop, {todo, Tag, Opts}, State};
|
||||
tag({include_template, Path, LocalOpts} = Tag, Opts, State) ->
|
||||
{stop, {todo, Tag, Opts}, State};
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% call a standard behaviors and integrate their answer in the
|
||||
% template. this will create a dynamic template. This part of the code
|
||||
% is managed by the generator or the final renderer.
|
||||
%---------------------------------------------------------------------
|
||||
% default call to gen_server
|
||||
tag({call, Pid, Message}, Opts, State) ->
|
||||
tag({gen_server, call, Pid, Message, 1000}, Opts, State);
|
||||
tag({call, Pid, Message, Timeout}, Opts, State) ->
|
||||
tag({gen_server, call, Pid, Message, Timeout}, Opts, State);
|
||||
|
||||
% gen_server support
|
||||
tag({gen_server, call, Pid, Message}, Opts, State) ->
|
||||
tag({gen_server, call, Pid, Message, 1000}, Opts, State);
|
||||
tag({gen_server, call, Pid, Message, Timeout} = Call, Opts, State) ->
|
||||
{ok, Call, State};
|
||||
|
||||
% statem support
|
||||
tag({gen_statem, call, Pid, Message}, Opts, State) ->
|
||||
tag({gen_statem, call, Pid, Message, 1000}, Opts, State);
|
||||
tag({gen_statem, call, Pid, Message, Timeout} = Call, Opts, State) ->
|
||||
{ok, Call, State};
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add MFA support. This part of the code add a dynamic layer to the
|
||||
% page. Every time the page is called, MFA defined is called and then
|
||||
% generate a new page.
|
||||
%---------------------------------------------------------------------
|
||||
tag({apply, {Module, Function, Arguments}}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({apply, Module, Function, Arguments}, Opts, State)
|
||||
when is_atom(Module), is_atom(Function), is_list(Arguments) ->
|
||||
try apply(Module, Function, Arguments) of
|
||||
{ok, Result} when is_binary(Result) ->
|
||||
{ok, Result, State}
|
||||
catch
|
||||
E:R:S -> {E,R,S}
|
||||
end;
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add local function support (helper) from gabarit. Same as MFA.
|
||||
% add local function support (helper) to execute on the same module.
|
||||
%---------------------------------------------------------------------
|
||||
tag({apply, {Function, Arguments}}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({apply, Function, Arguments}, Opts, State)
|
||||
when is_atom(Function), is_list(Arguments) ->
|
||||
try Function(Arguments) of
|
||||
{ok, Result} when is_binary(Result) ->
|
||||
{ok, Result, State}
|
||||
catch
|
||||
E:R:S -> {E,R,S}
|
||||
end;
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add support for function generator (without argument). Same as MFA.
|
||||
%---------------------------------------------------------------------
|
||||
tag({apply, Function}, Opts, State)
|
||||
tag({apply, Function}, Opts, State)
|
||||
when is_function(Function, 0) ->
|
||||
{ok, todo, State};
|
||||
try Function() of
|
||||
{ok, Result} when is_binary(Result) ->
|
||||
{ok, Result, State}
|
||||
catch
|
||||
E:R:S -> {E,R,S}
|
||||
end;
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add support for function with opts. Same as MFA.
|
||||
%---------------------------------------------------------------------
|
||||
tag({apply, Function}, Opts, State)
|
||||
tag({apply, Function}, Opts, State)
|
||||
when is_function(Function, 1) ->
|
||||
{ok, todo, State};
|
||||
try Function(Opts) of
|
||||
{ok, Result} when is_binary(Result) ->
|
||||
{ok, Result, State}
|
||||
catch
|
||||
E:R:S -> {E,R,S}
|
||||
end;
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add support for empty tag. Empty tags are special tags without
|
||||
% content.
|
||||
%---------------------------------------------------------------------
|
||||
tag({empty, Tag}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({{empty, Tag}, Attributes}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({empty, Tag} = T, Opts, State) ->
|
||||
{stop, {todo, T, Opts}, State};
|
||||
tag({{empty, Tag} = T, Attributes}, Opts, State) ->
|
||||
{stop, {todo, T, Opts}, State};
|
||||
|
||||
%--------------------------------------------------------------------
|
||||
% some tags will behave differently:
|
||||
% - code
|
||||
% - pre
|
||||
% - base
|
||||
% - br
|
||||
% - img
|
||||
@@ -140,33 +245,67 @@ tag({{empty, Tag}, Attributes}, Opts, State) ->
|
||||
% - meta
|
||||
% - source
|
||||
%--------------------------------------------------------------------
|
||||
tag({<<"code">>, Content}, Opts, State) ->
|
||||
tag({<<"code">>, #{}, Content}, Opts, State);
|
||||
tag({<<"code">>, Attributes, [Integer|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_integer(Integer), Integer>0 ->
|
||||
Result = list_to_binary(Content),
|
||||
tag({<<"code">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"code">>, Attributes, [List|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_list(List) ->
|
||||
Result = list_to_binary(string:join(Content, "\n")),
|
||||
tag({<<"code">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"code">>, Attributes, [Binary|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_binary(Binary) ->
|
||||
Result = join(Content, <<"\n">>),
|
||||
tag({<<"code">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"code">>, Attributes, Content}, Opts, State)
|
||||
when is_list(Content) ->
|
||||
{ok, todo, State};
|
||||
when is_binary(Content) ->
|
||||
Begin = bracket(<<"code">>, <<>>),
|
||||
End = bracket_end(<<"code">>),
|
||||
{ok, <<Begin/binary, Content/binary, End/binary>>, State};
|
||||
|
||||
tag({<<"pre">>, Content}, Opts, State) ->
|
||||
tag({<<"pre">>, #{}, Content}, Opts, State);
|
||||
tag({<<"pre">>, Attributes, [Integer|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_integer(Integer), Integer>0 ->
|
||||
Result = list_to_binary(Content),
|
||||
tag({<<"pre">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"pre">>, Attributes, [List|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_list(List) ->
|
||||
Result = list_to_binary(string:join(Content, "\n")),
|
||||
tag({<<"pre">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"pre">>, Attributes, [Binary|_] = Content} = Tag, Opts, State)
|
||||
when is_list(Content), is_binary(Binary) ->
|
||||
Result = join(Content, <<"\n">>),
|
||||
tag({<<"pre">>, Attributes, Result}, Opts, State);
|
||||
tag({<<"pre">>, Attributes, Content}, Opts, State)
|
||||
when is_list(Content) ->
|
||||
{ok, todo, state};
|
||||
when is_binary(Content) ->
|
||||
Begin = bracket(<<"pre">>, <<>>),
|
||||
End = bracket_end(<<"pre">>),
|
||||
{ok, <<Begin/binary, Content/binary, End/binary>>, State};
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add support for regular tag
|
||||
%---------------------------------------------------------------------
|
||||
tag({Tag, Content}, Opts, State) ->
|
||||
tag({Tag, #{}, Content}, Opts, State);
|
||||
tag({Tag, Attributes, Content}, Opts, State) ->
|
||||
{ok, todo, State};
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
when is_binary(Tag) ->
|
||||
case attributes(Tag, Attributes, Opts, State) of
|
||||
{ok, <<>>, NewState} ->
|
||||
Begin = <<"<", Tag/binary,">">>,
|
||||
End = <<"</",Tag/binary,">">>,
|
||||
{ok, Begin, End, Content, State};
|
||||
{ok, Serialized, NewState} ->
|
||||
Begin = <<"<", Tag/binary," ", Serialized/binary, ">">>,
|
||||
End = <<"</",Tag/binary,">">>,
|
||||
{ok, Begin, End, Content, State}
|
||||
end;
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% add support when a list is present. If a list is present, we assume
|
||||
% this is a list of tags and we should treat them one by one.
|
||||
%---------------------------------------------------------------------
|
||||
tag(Tags, Opts, State)
|
||||
tag(Tags, Opts, State)
|
||||
when is_list(Tags) ->
|
||||
{ok, todo, State};
|
||||
{stop, {todo, Tags, Opts}, State};
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% All tags defined as atom, list or numbers are converted into binary
|
||||
@@ -178,15 +317,15 @@ tag({Tag, Attributes, Content}, Opts, State)
|
||||
when is_atom(Tag) ->
|
||||
NewTag = atom_to_binary(Tag),
|
||||
tag({NewTag, Attributes, Content}, Opts, State);
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
when is_list(Tag) ->
|
||||
NewTag = list_to_binary(Tag),
|
||||
tag({NewTag, Attributes, Content}, Opts, State);
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
when is_integer(Tag) ->
|
||||
NewTag = integer_to_binary(Tag),
|
||||
tag({NewTag, Attributes, Content}, Opts, State);
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
tag({Tag, Attributes, Content}, Opts, State)
|
||||
when is_float(Tag) ->
|
||||
NewTag = float_to_binary(Tag),
|
||||
tag({NewTag, Attributes, Content}, Opts, State);
|
||||
@@ -195,64 +334,88 @@ tag({Tag, Attributes, Content}, Opts, State)
|
||||
% we assume binary, numbers, and atoms are text. these tags must be
|
||||
% protected and encoded with html entities.
|
||||
%--------------------------------------------------------------------
|
||||
tag(Text, Opts, State)
|
||||
when is_binary(Text) ->
|
||||
{ok, todo, State};
|
||||
tag(Text, Opts, State)
|
||||
when is_atom(Text) ->
|
||||
{ok, todo, State};
|
||||
tag(Text, Opts, State)
|
||||
when is_number(Text) ->
|
||||
{ok, todo, State};
|
||||
tag(Text, Opts, State)
|
||||
when is_binary(Text); is_atom(Text);
|
||||
is_integer(Text); is_float(Text) ->
|
||||
content(Text, Opts, State);
|
||||
|
||||
%---------------------------------------------------------------------
|
||||
% If unsupported tags are present, we should stop.
|
||||
%---------------------------------------------------------------------
|
||||
tag(Unsupported, Opts, State) ->
|
||||
{stop, Unsupported, State}.
|
||||
{stop, {todo, Unsupported, Opts}, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
attributes(Tag, Attributes, Opts, State) ->
|
||||
attributes(Tag, Attributes, maps:keys(Attributes), [], Opts, State).
|
||||
|
||||
attributes(Tag, Attributes, [], Buffer, Opts, State) ->
|
||||
{ok, join(lists:reverse(Buffer)), State};
|
||||
attributes(Tag, Attributes, [Key|Keys], Buffer, Opts, State) ->
|
||||
Value = maps:get(Key, Attributes),
|
||||
case attribute(Tag, Key, Value, Opts, State) of
|
||||
{ok, K, V, NewState} ->
|
||||
Pair = <<K/binary,"=",V/binary>>,
|
||||
attributes(Tag, Attributes, Keys, [Pair|Buffer], Opts, NewState);
|
||||
Elsewise ->
|
||||
Elsewise
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc main function used to generate html using gabarit tags.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec attribute(Key, Value, Opts, State) -> Return when
|
||||
-spec attribute(Tag, Key, Value, Opts, State) -> Return when
|
||||
Tag :: binary(),
|
||||
Key :: term(),
|
||||
Value :: term(),
|
||||
Opts :: map(),
|
||||
State :: term(),
|
||||
Return :: return().
|
||||
|
||||
attribute(Key, Value, Opts, State) ->
|
||||
{ok, todo, State}.
|
||||
% convert keys to binary
|
||||
attribute(Tag, Key, Value, Opts, State)
|
||||
when is_atom(Key) ->
|
||||
attribute(Tag, atom_to_binary(Key), Value, Opts, State);
|
||||
attribute(Tag, Key, Value, Opts, State)
|
||||
when is_list(Key) ->
|
||||
attribute(Tag, list_to_binary(Key), Value, Opts, State);
|
||||
|
||||
% convert values to binary
|
||||
attribute(Tag, Key, Value, Opts, State)
|
||||
when is_atom(Value) ->
|
||||
attribute(Tag, Key, atom_to_binary(Value), Opts, State);
|
||||
attribute(Tag, Key, Value, Opts, State)
|
||||
when is_list(Value) ->
|
||||
attribute(Tag, Key, list_to_binary(Value), Opts, State);
|
||||
|
||||
% some example of specific attributes
|
||||
attribute(<<"a">>, <<"href">> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(<<"img">>, <<"src">> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(_Tag, <<"style">>, Value, Opts, State) ->
|
||||
{ok, <<"style">>, Value, State};
|
||||
attribute(_Tag, <<"on", _/binary>> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(_Tag, <<"hx-vals">> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(_Tag, <<"hx-", _binary/binary>> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(_Tag, <<"htmx-", _binary/binary>> = Key, Value, Opts, State) ->
|
||||
{ok, Key, Value, State};
|
||||
attribute(_Tag, Key, Value, Opts, State)
|
||||
when is_binary(Key), is_binary(Value) ->
|
||||
{ok, Key, quote(Value, $"), State};
|
||||
|
||||
% global attributes, by default, not supported
|
||||
attribute(Tag, Key, Value, Opts, State) ->
|
||||
{stop, {todo, Tag, Key, Value, Opts, State}, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc main function to check attribute keys.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec key(Key, Opts, State) -> Return when
|
||||
Key :: term(),
|
||||
Opts :: map(),
|
||||
State :: term(),
|
||||
Return :: return().
|
||||
|
||||
key(Key, Opts, State) ->
|
||||
{ok, todo, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc main function to check attribute values.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec value(Value, Opts, State) -> Return when
|
||||
Value :: term(),
|
||||
Opts :: map(),
|
||||
State :: term(),
|
||||
Return :: return().
|
||||
|
||||
value(Value, Opts, State) ->
|
||||
{ok, todo, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @doc main function to check content.
|
||||
%% @doc main function to check content (inner text).
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec content(Content, Opts, State) -> Return when
|
||||
@@ -261,5 +424,66 @@ value(Value, Opts, State) ->
|
||||
State :: term(),
|
||||
Return :: return().
|
||||
|
||||
content(Content, Opts, State)
|
||||
when is_atom(Content) ->
|
||||
content(atom_to_binary(Content), Opts, State);
|
||||
content(Content, Opts, State)
|
||||
when is_integer(Content) ->
|
||||
content(integer_to_binary(Content), Opts, State);
|
||||
content(Content, Opts, State)
|
||||
when is_float(Content) ->
|
||||
content(float_to_binary(Content), Opts, State);
|
||||
content(Content, Opts, State)
|
||||
when is_list(Content) ->
|
||||
content(list_to_binary(Content), Opts, State);
|
||||
content(Content, #{ entities := false } = _Opts, State)
|
||||
when is_binary(Content) ->
|
||||
{ok, Content, State};
|
||||
content(Content, Opts, State)
|
||||
when is_binary(Content) ->
|
||||
{ok, gabarit_html_entities:encode(Content), State};
|
||||
content(Content, Opts, State) ->
|
||||
{ok, todo, State}.
|
||||
{stop, {todo, content, Content, Opts, State}, State}.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
join([]) -> <<>>;
|
||||
join(Binaries) -> join(Binaries, <<" ">>).
|
||||
|
||||
join([], _) -> <<>>;
|
||||
join(Binaries, Sep) -> join(Binaries, Sep, <<>>).
|
||||
|
||||
join([], _, Buffer) -> Buffer;
|
||||
join([Binary], _, Buffer) ->
|
||||
<<Binary/binary, Buffer/binary>>;
|
||||
join([Binary|Rest], Sep, Buffer) ->
|
||||
join(Rest, Sep, <<Sep/binary, Binary/binary, Buffer/binary>>).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
quote(Value, Char) ->
|
||||
<<Char, Value/binary, Char>>.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
bracket_empty(Element, <<>>) ->
|
||||
<<"<", Element/binary, " />">>;
|
||||
bracket_empty(Element, Attributes) ->
|
||||
<<"<", Element/binary, " ", Attributes/binary, " />">>.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
bracket(Element, <<>>) ->
|
||||
<<"<", Element/binary, ">">>;
|
||||
bracket(Element, Attributes) ->
|
||||
<<"<", Element/binary, " ", Attributes/binary, ">">>.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%%
|
||||
%%--------------------------------------------------------------------
|
||||
bracket_end(Element) ->
|
||||
<<"</", Element/binary, ">">>.
|
||||
|
||||
Reference in New Issue
Block a user