Packages
nitro
4.10.7
11.4.16
11.4.15
11.4.14
9.9.7
9.9.6
8.2.4
8.2.3
8.2.2
8.2.1
8.2.0
7.12.1
7.10.0
7.9.3
7.9.2
7.9.1
7.9.0
7.8.3
7.8.2
7.8.0
7.7.1
7.7.0
7.6.2
7.6.1
7.6.0
7.5.0
7.4.2
7.4.1
7.4.0
7.2.1
7.2.0
7.1.1
7.1.0
6.12.0
6.11.11
6.11.10
6.11.9
6.11.8
6.11.7
6.11.6
6.11.4
6.11.2
6.11.1
6.10.9
6.10.8
6.10.7
6.10.6
6.10.5
6.10.4
6.10.3
6.10.2
6.10.1
6.9.1
6.6.1
6.5.0
6.4.4
6.4.3
6.4.2
6.4.1
6.4.0
5.12.4
5.12.3
5.12.2
5.12.1
5.12.0
5.11.1
5.11.0
5.9.2
5.9.1
5.8.5
5.8.4
5.8.3
5.8.1
5.8.0
5.6.1
5.5.1
5.4.3
5.4.2
5.4.1
5.3.1
5.3.0
5.2.1
5.1.7
5.1.6
5.1.5
5.1.4
5.1.3
5.1.2
5.1.1
4.12.11
4.12.10
4.12.9
4.12.8
4.12.7
4.12.6
4.12.5
4.12.4
4.12.3
4.12.2
4.12.1
4.12.0
4.11.13
4.11.12
4.11.11
4.11.10
4.11.9
4.11.8
4.11.7
4.11.6
4.11.5
4.11.4
4.11.3
4.11.2
4.11.1
4.11.0
4.10.9
4.10.8
4.10.7
4.10.6
4.10.5
4.10.4
4.10.3
4.10.2
4.10.1
4.10.0
4.7.7
4.7.4
4.7.3
4.7.2
4.7.1
4.7.0
4.4.1
4.4.0
1.4.0
NITRO Nitrogen Web Framework
Current section
Files
Jump to
Current section
Files
src/nitro.erl
-module(nitro).
-include_lib("nitro/include/cx.hrl").
-include_lib("nitro/include/nitro.hrl").
-include_lib("nitro/include/event.hrl").
-compile(export_all).
-behaviour(application).
-export([start/2, stop/1, init/1]).
q(Key) -> q(Key, []).
q(Key, Def) -> case get(Key) of undefined -> Def; Val -> Val end.
qc(Key) -> CX = get(context), qc(Key,CX#cx.req).
qc(Key,Req) -> proplists:get_value(nitro:to_binary(Key),cowboy_req:parse_qs(Req)).
start(_StartType, _StartArgs) -> supervisor:start_link({local, ?MODULE}, ?MODULE, []).
stop(_State) -> ok.
init([]) -> {ok, {{one_for_one, 5, 10}, []}}.
f(S) -> f(S, []).
f(S, Args) -> lists:flatten(io_lib:format(S, Args)).
coalesce([]) -> undefined;
coalesce([H]) -> H;
coalesce([undefined|T]) -> coalesce(T);
coalesce([[]|T]) -> coalesce(T);
coalesce([H|_]) -> H.
jse(X) -> js_escape(X).
hte(X) -> nitro_conv:html_encode(X).
js_escape(undefined) -> [];
js_escape(Value) when is_list(Value) -> binary_to_list(js_escape(iolist_to_binary(Value)));
js_escape(Value) -> js_escape(Value, <<>>).
js_escape(<<"\\", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\\\">>);
js_escape(<<"\r", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\r">>);
js_escape(<<"\n", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\n">>);
js_escape(<<"\"", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "\\\"">>);
js_escape(<<"'",Rest/binary>>,Acc) -> js_escape(Rest, <<Acc/binary, "\\'">>);
js_escape(<<"<script", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "<scr\" + \"ipt">>);
js_escape(<<"script>", Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, "scr\" + \"ipt>">>);
js_escape(<<C, Rest/binary>>, Acc) -> js_escape(Rest, <<Acc/binary, C>>);
js_escape(<<>>, Acc) -> Acc.
-define(IS_STRING(Term), (is_list(Term) andalso Term /= [] andalso is_integer(hd(Term)))).
to_list(L) when ?IS_STRING(L) -> L;
to_list(L) when is_list(L) -> SubLists = [inner_to_list(X) || X <- L], lists:flatten(SubLists);
to_list(A) -> inner_to_list(A).
inner_to_list(A) when is_atom(A) -> atom_to_list(A);
inner_to_list(B) when is_binary(B) -> binary_to_list(B);
inner_to_list(I) when is_integer(I) -> integer_to_list(I);
inner_to_list(L) when is_tuple(L) -> lists:flatten(io_lib:format("~p", [L]));
inner_to_list(L) when is_list(L) -> L;
inner_to_list(F) when is_float(F) -> float_to_list(F,[{decimals,9},compact]).
to_atom(A) when is_atom(A) -> A;
to_atom(B) when is_binary(B) -> to_atom(binary_to_list(B));
to_atom(I) when is_integer(I) -> to_atom(integer_to_list(I));
to_atom(F) when is_float(F) -> to_atom(float_to_list(F,[{decimals,9},compact]));
to_atom(L) when is_list(L) -> list_to_atom(binary_to_list(list_to_binary(L))).
to_binary(A) when is_atom(A) -> atom_to_binary(A,latin1);
to_binary(B) when is_binary(B) -> B;
to_binary(I) when is_integer(I) -> to_binary(integer_to_list(I));
to_binary(F) when is_float(F) -> float_to_binary(F,[{decimals,9},compact]);
to_binary(L) when is_list(L) -> iolist_to_binary(L).
-ifndef(PICKLER).
-define(PICKLER, (application:get_env(n2o,pickler,nitro_pickle))).
-endif.
pickle(Data) -> ?PICKLER:pickle(Data).
depickle(SerializedData) -> ?PICKLER:depickle(SerializedData).
depickle(SerializedData, TTLSeconds) -> ?PICKLER:depickle(SerializedData, TTLSeconds).
render(X) -> wf_render:render(X).
wire(Actions) -> action_wire:wire(Actions).
unique_integer() -> erlang:unique_integer().
temp_id() -> "auto" ++ integer_to_list(unique_integer() rem 1000000).
html_encode(L,Fun) when is_function(Fun) -> Fun(L);
html_encode(L,EncType) when is_atom(L) -> html_encode(nitro:to_list(L),EncType);
html_encode(L,EncType) when is_integer(L) -> html_encode(integer_to_list(L),EncType);
html_encode(L,EncType) when is_float(L) -> html_encode(float_to_list(L,[{decimals,9},compact]),EncType);
html_encode(L, false) -> L;
html_encode(L, true) -> L;
html_encode(L, whites) -> html_encode_whites(nitro:to_list(lists:flatten([L]))).
html_encode(<<>>) -> [];
html_encode([]) -> [];
html_encode([H|T]) ->
case H of
$< -> "<" ++ html_encode(T);
$> -> ">" ++ html_encode(T);
$" -> """ ++ html_encode(T);
$' -> "'" ++ html_encode(T);
$& -> "&" ++ html_encode(T);
BigNum when is_integer(BigNum) andalso BigNum > 255 ->
[$&,$# | nitro:to_list(BigNum)] ++ ";" ++ html_encode(T);
Tup when is_tuple(Tup) -> throw({html_encode,encountered_tuple,Tup});
_ -> [H|html_encode(T)]
end.
html_encode_whites([]) -> [];
html_encode_whites([H|T]) ->
case H of
$\s -> " " ++ html_encode_whites(T);
$\t -> " " ++ html_encode_whites(T);
$< -> "<" ++ html_encode_whites(T);
$> -> ">" ++ html_encode_whites(T);
$" -> """ ++ html_encode_whites(T);
$' -> "'" ++ html_encode_whites(T);
$& -> "&" ++ html_encode_whites(T);
$\n -> "<br>" ++ html_encode_whites(T);
_ -> [H|html_encode_whites(T)]
end.
script() -> get(script).
script(Script) -> put(script,Script).
% Update DOM nitro:update
update(Target, Elements) ->
nitro:wire(#jq{target=Target,property=outerHTML,right=Elements,format="'~s'"}).
insert_top(Tag,Target, Elements) ->
Pid = self(),
Ref = make_ref(),
spawn(fun() -> R = nitro:render(Elements), Pid ! {R,Ref,nitro:actions()} end),
{Render,Ref,Actions} = receive {_, Ref, _} = A -> A end,
nitro:wire(nitro:f(
"qi('~s').insertBefore("
"(function(){var div = qn('~s'); div.innerHTML = '~s'; return div.firstChild; })(),"
"qi('~s').firstChild);",
[Target,Tag,Render,Target])),
nitro:wire(nitro:render(Actions)).
insert_bottom(Tag, Target, Elements) ->
Pid = self(),
Ref = make_ref(),
spawn(fun() -> R = nitro:render(Elements), Pid ! {R,Ref,nitro:actions()} end),
{Render,Ref,Actions} = receive {_, Ref, _} = A -> A end,
nitro:wire(nitro:f(
"(function(){ var div = qn('~s'); div.innerHTML = '~s';"
"qi('~s').appendChild(div.firstChild); })();",
[Tag,Render,Target])),
nitro:wire(nitro:render(Actions)).
insert_adjacent(Command,Target, Elements) ->
Pid = self(),
Ref = make_ref(),
spawn(fun() -> R = nitro:render(Elements), Pid ! {R,Ref,nitro:actions()} end),
{Render,Ref,Actions} = receive {_, Ref, _} = A -> A end,
nitro:wire(nitro:f("qi('~s').insertAdjacentHTML('~s', '~s');",[Target,Command,Render])),
nitro:wire(nitro:render(Actions)).
actions() -> get(actions).
actions(Ac) -> put(actions,Ac).
insert_top(Target, Elements) when element(1,Elements) == tr -> insert_top(tbody,Target, Elements);
insert_top(Target, Elements) -> insert_top('div',Target, Elements).
insert_bottom(Target, Elements) when element(1,Elements) == tr -> insert_bottom(tbody, Target, Elements);
insert_bottom(Target, Elements) -> insert_bottom('div', Target, Elements).
insert_before(Target, Elements) -> insert_adjacent(beforebegin,Target, Elements).
insert_after(Target, Elements) -> insert_adjacent(afterend,Target, Elements).
clear(Target) ->
nitro:wire("var x = qi('"++nitro:to_list(Target)++"'); while (x.firstChild) x.removeChild(x.firstChild);").
remove(Target) ->
nitro:wire("var x=qi('"++nitro:to_list(Target)++"'); x && x.parentNode.removeChild(x);").
% Wire JavaScript nitro:wire
state(Key) -> erlang:get(Key).
state(Key,Value) -> erlang:put(Key,Value).
% Redirect and purge connection nitro:redirect
redirect({http,Url}) -> n2o:header(<<"Location">>,nitro_conv:to_binary(Url)), nitro:state(status,302), [];
redirect(Url) -> nitro:wire(#jq{target='window.top',property=location,args=simple,right=Url}).
%header(K,V) -> nitro:context((?CTX)#cx{req=cowboy_req:set_resp_header(K,V,?CTX#cx.req)}).
% Convert and Utils API
display(Element,Status) ->
nitro:wire("{ var x = qi('"++
nitro:to_list(Element)++"'); if (x) x.style.display = '"++nitro:to_list(Status)++"'; }").
show(Element) -> display(Element,block).
hide(Element) -> display(Element,none).
compact([]) -> "[]";
compact("\n") -> "[]";
compact([X|_]=Y) when is_tuple(X) -> [ compact(F) || F <- Y ];
compact(Tuple) when is_tuple(Tuple) ->
Min = erlang:min(9,size(Tuple)),
Fields = lists:zip(lists:seq(1,Min),lists:sublist(tuple_to_list(Tuple),1,Min)),
"{" ++ string:join([ io_lib:format("~s",[compact(F)]) || {_,F}<- Fields ],",") ++ "}";
compact(Tuple) -> nitro:jse(nitro:to_list(Tuple)).
meg(X) -> integer_to_list(X div 1000000) ++ "M".
rev(X) -> lists:reverse(X).
num(S) -> case rev(S) of
[$K|K] -> list_to_integer(rev(K)) * 1000;
[$M|M] -> list_to_integer(rev(M)) * 1000 * 1000;
[$G|G] -> list_to_integer(rev(G)) * 1000 * 1000 * 1000;
[$T|T] -> list_to_integer(rev(T)) * 1000 * 1000 * 1000 * 1000 end.
cookie_expire(SecondsToLive) ->
Seconds = calendar:datetime_to_gregorian_seconds(calendar:local_time()),
DateTime = calendar:gregorian_seconds_to_datetime(Seconds + SecondsToLive),
cow_date:rfc2109(DateTime).
cookie(Id, Value) -> cookie(Id, Value, 2147483647). % expire never
cookie(Id, Value, Expire) ->
Format = "document.cookie='~s=~s; path=/; expires=~s';",
nitro:wire(nitro:f(Format,[nitro:to_list(Id),nitro:to_list(Value), cookie_expire(Expire)])).
cookies() -> cowboy_req:parse_cookies((get(context))#cx.req).
cookie(Key) -> case lists:keyfind(Key, 1, cowboy_req:parse_cookies((get(context))#cx.req)) of false -> undefined; {_, Value} -> Value end.