Packages
form
4.7.0
11.4.15
11.4.14
8.3.0
8.0.0
7.10.0
7.8.0
7.7.0
7.6.2
7.6.1
7.6.0
7.4.2
7.4.1
7.4.0
7.1.0
6.11.1
6.10.7
6.10.6
6.10.5
6.10.4
6.10.2
6.10.1
6.4.0
5.12.1
5.12.0
5.8.7
5.8.6
5.8.5
5.8.4
5.8.3
5.8.2
5.8.1
5.8.0
5.7.0
5.5.0
5.3.4
5.3.3
5.3.2
5.3.1
5.3.0
5.1.10
5.1.9
5.1.8
5.1.7
5.1.6
5.1.5
5.1.4
5.1.3
5.1.2
5.1.1
4.12.3
4.12.2
4.12.1
4.12.0
4.11.15
4.11.14
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.5
4.10.4
4.10.3
4.10.2
4.10.1
4.10.0
4.7.0
4.6.0
ERP/1 X-FORM Business Cartulary
Current section
Files
Jump to
Current section
Files
src/form.erl
-module(form).
-behaviour(supervisor).
-behaviour(application).
-copyright('Maxim Sokhatsky').
-compile(export_all).
-export([start/0, start/1, start/2, stop/1, new/2, init/1, id/0]).
-export([form/2, steps/2, caption/2, fields/2, buttons/2, component/3]).
-include_lib("nitro/include/nitro.hrl").
-include("step_wizard.hrl").
-include("meta.hrl").
id() -> fun (X) -> X end.
translate_error(A,B) -> io_lib:format("~p",[{A,B}]).
translate(A,B) -> io_lib:format("~p",[{A,B}]).
translate(A) -> io_lib:format("~p",[A]).
stop(_) -> ok.
main(A) -> mad:main(A).
start() -> start(normal,[]).
start(_) -> start().
init([]) -> {ok, {{one_for_one, 5, 10}, [] }}.
start(_,_) -> supervisor:start_link({local,form},form,[]).
atom(List) when is_list(List) -> string:join([ nitro:to_list(L) || L <- List],"_");
atom(Scalar) -> nitro:to_list(Scalar).
new(Document = #document{},Object) ->
Name = Document#document.name,
#panel{
id=form:atom([form,Name]), class=form,
body= [BuildBlock(Document, Object)
|| BuildBlock <- [fun steps/2,fun caption/2,fun fields/2,fun buttons/2]]};
new(Document,Object) -> Document.
form(Document,_Object) ->
Name = Document#document.name,
#panel { id=form:atom([form,Name]), class=form}.
steps(Document, _Object) ->
% step wizard
StepWizard = Document#document.steps,
case StepWizard of
#step_wizard{} ->
#panel{class=steps, body=
#b{body= [ nitro:f(translate(step_wizard),
[StepWizard#step_wizard.current_step,StepWizard#step_wizard.steps]) ]} };
_ -> []
end.
caption(Document, _Object) ->
% caption
SectionList = Document#document.sections,
#panel{class=caption,body=
[begin
[#h4{ class=Section#sec.nameClass, body=Section#sec.name},
#panel{ class=Section#sec.descClass, body = Section#sec.desc}]
end || Section <- SectionList]}.
fields(Document, Object) ->
% fields
Name = Document#document.name,
Fields = Document#document.fields,
lists:foldr(
% empty
fun (#field{type=empty}=X1,Acc) ->
[#panel{class=box, style="display:none;",id=form:atom([X1#field.name,Name])}|Acc];
%% dynamic component (that is build with fun component/3 and inserted)
(#field{type=dynamic}=X4,Acc) -> [X4#field.raw|Acc];
% card row
(#field{type=card,name=[Name1,Name2,Name3]}=X2,Acc) ->
[#panel { id=form:atom([Name1,Name]), class=[box,pad0], body=[
#panel { class=label, body = X2#field.title},
#panel { class=field, style="width:66.63%", body=
#panel {id=form:atom([Name2,Name]), body=[
#panel{class=field,style="width:90%;", body =
#select{id=form:atom([Name3, Name]), disabled=true, validation="Validation.card(e)",
body= #option{selected=true, body= form:translate(loading)}}},
#panel { class=tool, body= [#image{src="/static/app/img/preloader.gif"}]} ]}} ]}|Acc];
% comment for front manager
(#field{type=comment}=X3,Acc) ->
[#panel { id=commentBlock, class=box, body=[
case X3#field.tooltips of
false -> [];
true ->[#panel { class=label, body=" " },
#panel { class=field, body=" " },
#panel { class=tool, body=[
#link{id=form:atom([commentlink,X3#field.name,Name]), class=tooltips, onclick=nitro:f("showComment(this);"), body=[
#image{src="/static/app/img/icon-comment-blue2.png"} ]} ]}] end,
#panel { class=comment, id=form:atom([X3#field.name,Name]), body=[X3#field.desc],
style=case X3#field.tooltips of
false -> "";
true -> "display:none;" end} ]}|Acc];
% integer money combo sring
(#field{}=X,Acc) ->
Panel = case X#field.name of undefined -> #panel{};
_ -> #panel{id=form:atom([wrap,X#field.name,Name])} end,
Tooltips = [
case Tx of
{N} -> #panel{id=form:atom([tooltip,N,Name]), body=[]};
_ -> #link { class=tooltips, tabindex="-1", onmouseover="setHeight(this);", body=[
#image { src= "/static/app/img/question.png" },
#span { body=Tx } ]} end || Tx <- lists:reverse(X#field.tooltips) ],
Options = [ case {X#field.type, O#opt.noRadioButton} of
{_,true} -> #label{id=form:atom([label,O#opt.name,Name]), body=[]};
{combo,_} -> #panel{body= #label{body=
#radio{name=form:atom([X#field.name,combo]),
id=form:atom([O#opt.name,Name]),
body = O#opt.title,
checked=O#opt.checked,
disabled=O#opt.disabled,
postback={O#opt.name,Name}}}};
{select,_} -> #option{value = O#opt.name, body = O#opt.title, selected = O#opt.checked};
{check,_} -> #checkbox{id=form:atom([O#opt.name,Name]),source=[form:atom([O#opt.name,Name])],
body = O#opt.title, disabled=O#opt.disabled, checked=O#opt.checked, postback={O#opt.name,Name}} end || O <- X#field.options],
[Panel#panel { class=X#field.boxClass, body=[
#panel { class=X#field.labelClass, body = X#field.title},
#panel { class=X#field.fieldClass,
body = case X#field.type of
text -> #panel{id=form:atom([X#field.name,Name]), body=X#field.desc};
integer -> #b{body= nitro:f(X#field.format,
[case X#field.postfun of
[] -> element(X#field.pos,Object);
PostFun -> PostFun(element(X#field.pos,Object)) end] )};
money -> [ #input{ id=form:atom([X#field.name,Name]), pattern="[0-9]*",
validation=nitro:f("Validation.money(e, ~w, ~w, '~s')",[X#field.min,X#field.max, form:translate({?MODULE, error})]),
onkeypress=nitro:f("return fieldsFilter(event, ~w, '~w');",[X#field.length,X#field.type]), onkeyup="beautiful_numbers(event);",
value=nitro:to_list(element(X#field.pos,Object)) },
#panel{ class=pt10,body= [ form:translate({?MODULE, warning}), nitro:to_binary(X#field.min), " ", X#field.curr ] } ];
pay -> #panel{body=[#input{ id=form:atom([X#field.name,Name]), pattern="[0-9]*",
validation=X#field.validation,
onkeypress=nitro:f("return fieldsFilter(event, ~w, '~w');",[X#field.length,X#field.type]),
onkeyup="beautiful_numbers(event);",
value=nitro:to_list(element(X#field.pos,Object)) }, <<" ">>, #span{body=X#field.curr}]};
combo -> case length(Options) of
1 -> tl(lists:flatten(lists:zipwith(fun(A,B) -> [A,B] end,
lists:duplicate(length(Options),#br{}),Options)));
_ -> tl(lists:flatten(lists:zipwith(fun(A,B) -> [A,B] end,
lists:duplicate(length(Options),#panel{}),Options))) end;
select -> #select{ id=form:atom([X#field.name,Name]), postback=X#field.postback, onchange=X#field.onchange, body=Options};
check -> case length(Options) of
1 -> tl(lists:flatten(lists:zipwith(fun(A,B) -> [A,B] end,
lists:duplicate(length(Options),#br{}),Options)));
_ -> tl(lists:flatten(lists:zipwith(fun(A,B) -> [A,B] end,
lists:duplicate(length(Options),#panel{}),Options))) end;
string -> #input{ class=dep_name,id=form:atom([X#field.name,Name]),
% validation=nitro:f("Validation.length(e, ~w, ~w)",[X#field.min,X#field.max]),
% onkeypress="return removeAllErrorsFromInput(this);",
value=element(X#field.pos,Object)};
phone -> #input{ id=form:atom([X#field.name,Name]), class=phone, pattern="[0-9]*",
onkeypress=nitro:f("return fieldsFilter(event, ~w, '~w');",[X#field.length,X#field.type]),
validation=nitro:f("Validation.phone(e, ~w, ~w)",[X#field.min,X#field.max]), value="+380"};
auth -> [
#input{ id=form:atom([X#field.name,Name]), class=phone, type=password,
onkeypress="return removeAllErrorsFromInput(this);",
onkeyup="nextByEnter(event);",
validation=nitro:f("Validation.length(e, ~w, ~w)",[X#field.min,X#field.max]),
placeholder= form:translate({auth, holder}) },
#span{class=auth_link,body=
[#link{href= form:translate({auth, lost_pass_link}), target="_blank",
postback=undefined, body= form:translate({auth, lost_pass}) }, #br{},
#link{href= form:translate({auth, change_login_link}), target="_blank",
postback=undefined, body= form:translate({auth, change_login}) }]} ];
otp -> #input{ class=[phone,pass],id=form:atom([X#field.name,Name]), placeholder="(XXXX)", pattern="[0-9]*"
% validation="Validation.nums(e, 4, 4, 'otp')",
% onkeypress="return fieldsFilter(event, 4, 'otp');"
};
datepay -> #panel{class=[field,sub,'input-date'], body=
[#calendar{id=form:atom([X#field.name,Name]), onkeypress="return fieldsFilter(event, 10, 'date');",
validation="Validation.dateRegPay(e)", style="width:70%", disableDayFn="disableDays4Charge",
class = ['input-date'], format="DD.MM.YYYY", minDate=X#field.min, maxDate = X#field.max, lang=en,value=element(X#field.pos,Object)},
#span{class=['calendar-area','icon-calendar'],body=[]}]} end},
#panel { class=tool, body= case Tooltips of
[] -> [];
_ -> case length(Tooltips) of
1 -> tl(lists:flatten(lists:zipwith(fun(A2,B2) -> [A2,B2] end,
lists:duplicate(length(Tooltips),#br{}),Tooltips)));
_ -> tl(lists:flatten(lists:zipwith(fun(A2,B2) -> [A2,B2] end,
lists:duplicate(length(Tooltips),#panel{style="height:10px;"}),Tooltips))) end end} ]}|Acc] end,[],Fields).
buttons(Document, _Object) ->
% buttons
Name = Document#document.name,
Buttons = Document#document.buttons,
#panel{id=forpreload,class=buttons,body= lists:foldr(fun(#but{}=But,Acc) ->
[#link{id=But#but.id, class=But#but.class, validate=But#but.validation, postback=But#but.postback, body=But#but.title, onclick=But#but.onclick,
href=But#but.href, target=But#but.target, source=[form:atom([S,Name])||S<-But#but.sources]}|Acc] end,[],Buttons)}.
component(FormId, Document, Object) ->
Name = Document#document.name,
#panel{id=form:atom([FormId,Name]), body= [BuildBlock(Document, Object) || BuildBlock <- [fun fields/2]]}.