diff --git a/ChangeLog b/ChangeLog index 6270afdc3..aaae27172 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2009-01-12 Badlop + * src/web/ejabberd_web_admin.erl: Use textareas for large input + like ejabberd module options and listening port options. Show + result of POST more clearly. Ensure access rules are shown with + some minimum separation. Improve menu headers. (EJAB-562) + * src/web/ejabberd_web_admin.hrl: Likewise + * src/mod_offline.erl: Likewise + * src/mod_offline_odbc.erl: Likewise + * src/mod_roster.erl: Likewise + * src/mod_roster_odbc.erl: Likewise + * src/mod_shared_roster.erl: Likewise + * src/ejabberd_listener.erl: New way to configure IP address and IP version of listener. Support for definition of IP address in string format, and implicit definition of IP @@ -13,6 +24,7 @@ * src/mod_proxy65/mod_proxy65_stream.erl: Likewise * src/mod_proxy65/mod_proxy65_service.erl: Likewise * src/web/ejabberd_web_admin.erl: Likewise + * doc/guide.tex: Document the new way to configure IP address and IP version of listener, undocument options ip and inet6 * doc/guide.html: Likewise diff --git a/src/mod_offline.erl b/src/mod_offline.erl index b2e2b5db2..0607ddb8b 100644 --- a/src/mod_offline.erl +++ b/src/mod_offline.erl @@ -500,7 +500,7 @@ user_queue(User, Server, Query, Lang) -> [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), [us_to_list(US)]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; + ok -> [?XREST("Submitted")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_offline_odbc.erl b/src/mod_offline_odbc.erl index b3f1ec10a..e70cfbe69 100644 --- a/src/mod_offline_odbc.erl +++ b/src/mod_offline_odbc.erl @@ -358,7 +358,7 @@ user_queue(User, Server, Query, Lang) -> [?XC("h1", io_lib:format(?T("~s's Offline Messages Queue"), [us_to_list(US)]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; + ok -> [?XREST("Submitted")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_roster.erl b/src/mod_roster.erl index c52ff57f4..a1639c55f 100644 --- a/src/mod_roster.erl +++ b/src/mod_roster.erl @@ -844,8 +844,8 @@ user_roster(User, Server, Query, Lang) -> end, [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_roster_odbc.erl b/src/mod_roster_odbc.erl index 1678e5259..ee4e326a7 100644 --- a/src/mod_roster_odbc.erl +++ b/src/mod_roster_odbc.erl @@ -944,8 +944,8 @@ user_roster(User, Server, Query, Lang) -> end, [?XC("h1", ?T("Roster of ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl index 01bd16622..1a15119b5 100644 --- a/src/mod_shared_roster.erl +++ b/src/mod_shared_roster.erl @@ -725,8 +725,8 @@ list_shared_roster_groups(Host, Query, Lang) -> )]), ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -789,8 +789,9 @@ shared_roster_group(Host, Group, Query, Lang) -> [] end ++ [[us_to_list(Member), $\n] || Member <- Members], FDisplayedGroups = [[DG, $\n] || DG <- DisplayedGroups], + DescNL = length(element(2, regexp:split(Description, "\n"))), FGroup = - ?XAE("table", [], + ?XAE("table", [{"class", "withtextareas"}], [?XE("tbody", [?XE("tr", [?XCT("td", "Name:"), @@ -799,34 +800,34 @@ shared_roster_group(Host, Group, Query, Lang) -> ), ?XE("tr", [?XCT("td", "Description:"), - ?XE("td", [?XAC("textarea", [{"name", "description"}, - {"rows", "3"}, - {"cols", "20"}], - Description)]) + ?XE("td", [ + ?TEXTAREA("description", integer_to_list(lists:max([3, DescNL])), "20", Description) + ] + ) ] ), ?XE("tr", [?XCT("td", "Members:"), - ?XE("td", [?XAC("textarea", [{"name", "members"}, - {"rows", "3"}, - {"cols", "20"}], - FMembers)]) + ?XE("td", [ + ?TEXTAREA("members", integer_to_list(lists:max([3, length(FMembers)])), "20", FMembers) + ] + ) ] ), ?XE("tr", [?XCT("td", "Displayed Groups:"), - ?XE("td", [?XAC("textarea", [{"name", "dispgroups"}, - {"rows", "3"}, - {"cols", "20"}], - FDisplayedGroups)]) + ?XE("td", [ + ?TEXTAREA("dispgroups", integer_to_list(lists:max([3, length(FDisplayedGroups)])), "20", FDisplayedGroups) + ] + ) ] )] )]), ?H1GL(?T("Shared Roster Groups"), "modsharedroster", "mod_shared_roster") ++ [?XC("h2", ?T("Group ") ++ Group)] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index cf3150b90..ea1a936eb 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -157,7 +157,7 @@ make_xhtml(Els, Host, Node, Lang) -> [?XAE("div", [{"id", "header"}], [?XE("h1", - [?ACT("/admin/", "Administration")] + [?ACT("/admin/", "ejabberd Web Admin")] )]), ?XAE("div", [{"id", "navigation"}], @@ -312,6 +312,7 @@ ul li #navhead a, ul li #navheadsub a, ul li #navheadsubsub a { text-align: center; border-top: 2px solid #d47911; border-bottom: 1px solid #d47911; + background: #FED6A6; } #navheadsub, #navitemsub { @@ -367,10 +368,6 @@ textarea { border: 1px solid #d6760e; color: #723202; background-color: #fff2e8; - vertical-align: middle; - margin-top: 7px; - margin-bottom: 5px; - padding: 0.1em; } select { @@ -538,6 +535,19 @@ div.guidelink { padding-right: 1em; } +table.withtextareas>tbody>tr>td { + vertical-align: top; +} + +p.result { + border: 1px; + border-style: dashed; + border-color: #FE8A02; + padding: 1em; + margin-right: 1em; + background: #FFE3C9; +} + *.alignright { font-size: 10pt; } @@ -633,6 +643,7 @@ process_admin(Host, #request{path = ["acls-raw"], q = Query, lang = Lang}) -> + Res = case lists:keysearch("acls", 1, Query) of {value, {_, String}} -> case erl_scan:string(String) of @@ -654,22 +665,17 @@ process_admin(Host, _ -> nothing end, - ACLs = lists:flatten( - io_lib:format( - "~p.", [lists:keysort( - 2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, - [], [{{acl, '$1', '$2'}}]}]))])), + ACLs = lists:keysort(2, ets:select(acl, [{{acl, {'$1', Host}, '$2'}, + [], [{{acl, '$1', '$2'}}]}])), + {NumLines, ACLsP} = term_to_paragraph(ACLs, 80), make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAC("textarea", [{"name", "acls"}, - {"rows", "16"}, - {"cols", "80"}], - ACLs), + [?TEXTAREA("acls", integer_to_list(lists:max([16, NumLines])), "80", ACLsP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") ]) @@ -704,8 +710,8 @@ process_admin(Host, [], [{{acl, '$1', '$2'}}]}])), make_xhtml(?H1GL(?T("Access Control Lists"), "ACLDefinition", "ACL Definition") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE("p", [?ACT("../acls-raw/", "Raw")])] ++ @@ -764,23 +770,19 @@ process_admin(Host, nothing end, Access = - lists:flatten( - io_lib:format( - "~p.", [ets:select(config, + ets:select(config, [{{config, {access, '$1', Host}, '$2'}, [], - [{{access, '$1', '$2'}}]}])])), + [{{access, '$1', '$2'}}]}]), + {NumLines, AccessP} = term_to_paragraph(Access, 80), make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], - [?XAC("textarea", [{"name", "access"}, - {"rows", "16"}, - {"cols", "80"}], - Access), + [?TEXTAREA("access", integer_to_list(lists:max([16, NumLines])), "80", AccessP++"."), ?BR, ?INPUTT("submit", "submit", "Submit") ]) @@ -810,8 +812,8 @@ process_admin(Host, [{{access, '$1', '$2'}}]}]), make_xhtml(?H1GL(?T("Access Rules"), "AccessRights", "Access Rights") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE("p", [?ACT("../access-raw/", "Raw")])] ++ @@ -850,8 +852,8 @@ process_admin(Host, make_xhtml([?XC("h1", io_lib:format(?T("~s access rule configuration"), [SName]))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -1054,12 +1056,20 @@ acl_spec_select(ID, Opt) -> node_regexp, user_glob, server_glob, node_glob, all, raw]))]). +%% @spec (T::any()) -> StringLine::string() term_to_string(T) -> StringParagraph = lists:flatten(io_lib:format("~1000000p", [T])), %% Remove from the string all the carriage returns characters {ok, StringLine, _} = regexp:gsub(StringParagraph, "\\n ", ""), StringLine. +%% @spec (T::any()) -> {NumLines::integer(), Paragraph::string()} +term_to_paragraph(T, Cols) -> + Paragraph = erl_prettypr:format(erl_syntax:abstract(T), [{paper, Cols}]), + {ok, FieldList} = regexp:split(Paragraph, "\n"), + NumLines = length(FieldList), + {NumLines, Paragraph}. + term_to_id(T) -> jlib:encode_base64(binary_to_list(term_to_binary(T))). @@ -1227,7 +1237,7 @@ access_rule_to_xhtml(Rules) -> fun({Access, ACL} = _Rule) -> SAccess = element_to_list(Access), SACL = atom_to_list(ACL), - SAccess ++ "\t" ++ SACL ++ "\n" + SAccess ++ "\s\t" ++ SACL ++ "\n" end, Rules), ?XAC("textarea", [{"name", "rules"}, {"rows", "16"}, @@ -1304,8 +1314,8 @@ list_users(Host, Query, Lang, URLFunc) -> end, lists:seq(1, N, M)) end, case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -1500,8 +1510,8 @@ user_info(User, Server, Query, Lang) -> [User, Server, Lang]), [?XC("h1", ?T("User ") ++ us_to_list(US))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -1668,8 +1678,8 @@ get_node(global, Node, [], Query, Lang) -> MenuItems2 = make_menu_items(global, Node, Base, Lang), [?XC("h1", ?T("Node ") ++ atom_to_list(Node))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XE("ul", @@ -1698,7 +1708,10 @@ get_node(global, Node, ["db"], Query, Lang) -> {badrpc, _Reason} -> [?XCT("h1", "RPC Call Error")]; Tables -> - node_db_parse_query(Node, Tables, Query), + ResS = case node_db_parse_query(Node, Tables, Query) of + nothing -> []; + ok -> [?XREST("Submitted")] + end, STables = lists:sort(Tables), Rows = lists:map( fun(Table) -> @@ -1735,7 +1748,7 @@ get_node(global, Node, ["db"], Query, Lang) -> ]) end, STables), [?XC("h1", ?T("Database Tables at ") ++ atom_to_list(Node))] ++ - [?CT("Submitted"), ?P] ++ + ResS ++ [?XAE("form", [{"action", ""}, {"method", "post"}], [?XAE("table", [], [?XE("thead", @@ -1757,9 +1770,14 @@ get_node(global, Node, ["db"], Query, Lang) -> end; get_node(global, Node, ["backup"], Query, Lang) -> - _Res = node_backup_parse_query(Node, Query), - [?XC("h1", ?T("Backup of ") ++ atom_to_list(Node)), - ?XCT("p", "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), + ResS = case node_backup_parse_query(Node, Query) of + nothing -> []; + ok -> [?XREST("Submitted")]; + {error, Error} -> [?XRES(?T("Error") ++": " ++ io_lib:format("~p", [Error]))] + end, + [?XC("h1", ?T("Backup of ") ++ atom_to_list(Node))] ++ + ResS ++ + [?XCT("p", "Remark that these options will only backup the builtin Mnesia database. If you are using the ODBC module, you also need to backup your SQL database separately."), ?XAE("form", [{"action", ""}, {"method", "post"}], [?XAE("table", [], [?XE("tbody", @@ -1822,9 +1840,9 @@ get_node(global, Node, ["ports"], Query, Lang) -> H1String = ?T("Listened Ports at ") ++ atom_to_list(Node), ?H1GL(H1String, "listened", "Listening Ports") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; - {error, ReasonT} -> [?CT("Problem: "), ?C(ReasonT), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; + {error, ReasonT} -> [?XRES(?T("Error") ++ ": " ++ ReasonT)]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -1847,8 +1865,8 @@ get_node(Host, Node, ["modules"], Query, Lang) when is_list(Host) -> H1String = ?T("Modules at ") ++ atom_to_list(Node), ?H1GL(H1String, "modoverview", "Modules Overview") ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], @@ -1916,17 +1934,19 @@ get_node(global, Node, ["update"], Query, Lang) -> FmtLowLevelScript = ?XC("pre", io_lib:format("~p", [LowLevelScript])), [?XC("h1", ?T("Update ") ++ atom_to_list(Node))] ++ case Res of - ok -> [?CT("Submitted"), ?P]; - error -> [?CT("Bad format"), ?P]; + ok -> [?XREST("Submitted")]; + error -> [?XREST("Bad format")]; nothing -> [] end ++ [?XAE("form", [{"action", ""}, {"method", "post"}], - [?INPUTT("submit", "update", "Update"), + [ ?XCT("h2", "Update plan"), - ?XCT("h3", "Updated modules"), Mods, + ?XCT("h3", "Modified modules"), Mods, ?XCT("h3", "Update script"), FmtScript, ?XCT("h3", "Low level update script"), FmtLowLevelScript, - ?XCT("h3", "Script check"), ?C(atom_to_list(Check))]) + ?XCT("h3", "Script check"), ?XC("pre", atom_to_list(Check)), + ?INPUTT("submit", "update", "Update") + ]) ]; get_node(Host, Node, NPath, Query, Lang) -> @@ -1981,6 +2001,8 @@ db_storage_select(ID, Opt, Lang) -> {disc_only_copies, "Disc only copy"}, {unknown, "Remote copy"}])). +node_db_parse_query(_Node, _Tables, [{nokey,[]}]) -> + nothing; node_db_parse_query(Node, Tables, Query) -> lists:foreach( fun(Table) -> @@ -2014,6 +2036,8 @@ node_db_parse_query(Node, Tables, Query) -> end, Tables), ok. +node_backup_parse_query(_Node, [{nokey,[]}]) -> + nothing; node_backup_parse_query(Node, Query) -> lists:foldl( fun(Action, nothing) -> @@ -2040,15 +2064,15 @@ node_backup_parse_query(Node, Query) -> load_textfile, [Path]) end, case Res of - {error, _Reason} -> - error; - {badrpc, _Reason} -> - error; + {error, Reason} -> + {error, Reason}; + {badrpc, Reason} -> + {badrpc, Reason}; _ -> ok end; - _ -> - error + OtherError -> + {error, OtherError} end; _ -> nothing @@ -2059,7 +2083,7 @@ node_backup_parse_query(Node, Query) -> node_ports_to_xhtml(Ports, Lang) -> - ?XAE("table", [], + ?XAE("table", [{"class", "withtextareas"}], [?XE("thead", [?XE("tr", [?XCT("td", "Port"), @@ -2073,14 +2097,14 @@ node_ports_to_xhtml(Ports, Lang) -> {_Port, SPort, _TIP, SIP, SSPort, OptsClean} = get_port_data(PortIP, Opts), SModule = atom_to_list(Module), + {NumLines, SOptsClean} = term_to_paragraph(OptsClean, 40), %%ID = term_to_id(E), ?XE("tr", [?XAE("td", [{"size", "6"}], [?C(SPort)]), ?XAE("td", [{"size", "15"}], [?C(SIP)]), ?XE("td", [?INPUTS("text", "module" ++ SSPort, SModule, "15")]), - ?XE("td", [?INPUTS("text", "opts" ++ SSPort, - term_to_string(OptsClean), "40")]), + ?XE("td", [?TEXTAREA("opts" ++ SSPort, integer_to_list(NumLines), "35", SOptsClean)]), ?XE("td", [?INPUTT("submit", "add" ++ SSPort, "Update")]), ?XE("td", [?INPUTT("submit", "delete" ++ SSPort, @@ -2091,8 +2115,8 @@ node_ports_to_xhtml(Ports, Lang) -> [?XE("tr", [?XE("td", [?INPUTS("text", "portnew", "", "6")]), ?XE("td", [?INPUTS("text", "ipnew", "0.0.0.0", "15")]), - ?XE("td", [?INPUTS("text", "modulenew", "", "17")]), - ?XE("td", [?INPUTS("text", "optsnew", "[]", "40")]), + ?XE("td", [?INPUTS("text", "modulenew", "", "15")]), + ?XE("td", [?TEXTAREA("optsnew", "2", "35", "[]")]), ?XAE("td", [{"colspan", "2"}], [?INPUTT("submit", "addnew", "Add New")]) ] @@ -2170,7 +2194,7 @@ node_ports_parse_query(Node, Ports, Query) -> end. node_modules_to_xhtml(Modules, Lang) -> - ?XAE("table", [], + ?XAE("table", [{"class", "withtextareas"}], [?XE("thead", [?XE("tr", [?XCT("td", "Module"), @@ -2180,11 +2204,11 @@ node_modules_to_xhtml(Modules, Lang) -> lists:map( fun({Module, Opts} = _E) -> SModule = atom_to_list(Module), + {NumLines, SOpts} = term_to_paragraph(Opts, 40), %%ID = term_to_id(E), ?XE("tr", [?XC("td", SModule), - ?XE("td", [?INPUTS("text", "opts" ++ SModule, - term_to_string(Opts), "40")]), + ?XE("td", [?TEXTAREA("opts" ++ SModule, integer_to_list(NumLines), "40", SOpts)]), ?XE("td", [?INPUTT("submit", "restart" ++ SModule, "Restart")]), ?XE("td", [?INPUTT("submit", "stop" ++ SModule, @@ -2194,7 +2218,7 @@ node_modules_to_xhtml(Modules, Lang) -> end, Modules) ++ [?XE("tr", [?XE("td", [?INPUT("text", "modulenew", "")]), - ?XE("td", [?INPUTS("text", "optsnew", "", "40")]), + ?XE("td", [?TEXTAREA("optsnew", "2", "40", "[]")]), ?XAE("td", [{"colspan", "2"}], [?INPUTT("submit", "start", "Start")]) ] @@ -2437,11 +2461,11 @@ make_menu_items2(Lang, Deep, {MURI, MName, [Item | Items]}, Res) -> make_menu_items2(Lang, Deep, {MURI, MName, Items}, Res2). make_menu_item(header, 1, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navhead"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE("div", [{"id", "navhead"}], [?AC(URI, Name)] )]); make_menu_item(header, 2, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navheadsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE("div", [{"id", "navheadsub"}], [?AC(URI, Name)] )]); make_menu_item(header, 3, URI, Name, _Lang) -> - ?LI([?XAE("div", [{"id", "navheadsubsub"}], [?AC(URI, "~ "++Name++" ~")] )]); + ?LI([?XAE("div", [{"id", "navheadsubsub"}], [?AC(URI, Name)] )]); make_menu_item(item, 1, URI, Name, Lang) -> ?LI([?XAE("div", [{"id", "navitem"}], [?ACT(URI, Name)] )]); make_menu_item(item, 2, URI, Name, Lang) -> diff --git a/src/web/ejabberd_web_admin.hrl b/src/web/ejabberd_web_admin.hrl index d197e3abe..2bf164e0b 100644 --- a/src/web/ejabberd_web_admin.hrl +++ b/src/web/ejabberd_web_admin.hrl @@ -51,6 +51,16 @@ -define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). -define(ACLINPUT(Text), ?XE("td", [?INPUT("text", "value" ++ ID, Text)])). +-define(TEXTAREA(Name, Rows, Cols, Value), + ?XAC("textarea", [{"name", Name}, + {"rows", Rows}, + {"cols", Cols}], + Value)). + +%% Build an xmlelement for result +-define(XRES(Text), ?XAC("p", [{"class", "result"}], Text)). +-define(XREST(Text), ?XRES(?T(Text))). + %% Guide Link -define(GL(Ref, Title), ?XAE("div",