edoc_layout.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 851 行 · 第 1/2 页

ERL
851
字号
%% =====================================================================%% This library is free software; you can redistribute it and/or modify%% it under the terms of the GNU Lesser General Public License as%% published by the Free Software Foundation; either version 2 of the%% License, or (at your option) any later version.%%%% This library is distributed in the hope that it will be useful, but%% WITHOUT ANY WARRANTY; without even the implied warranty of%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU%% Lesser General Public License for more details.%%%% You should have received a copy of the GNU Lesser General Public%% License along with this library; if not, write to the Free Software%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307%% USA%%%% $Id$%%%% @author Richard Carlsson <richardc@it.uu.se>%% @copyright 2001-2006 Richard Carlsson%% @see edoc%% @end%% =====================================================================%% @doc The standard HTML layout module for EDoc. See the {@link edoc}%% module for details on usage.%% Note that this is written so that it is *not* depending on edoc.hrl!-module(edoc_layout).-export([module/2, package/2, overview/2, type/1]).-import(edoc_report, [report/2]).-include("xmerl.hrl").-define(HTML_EXPORT, xmerl_html).-define(DEFAULT_XML_EXPORT, ?HTML_EXPORT).-define(OVERVIEW_SUMMARY, "overview-summary.html").-define(STYLESHEET, "stylesheet.css").-define(NL, "\n").-define(DESCRIPTION_TITLE, "Description").-define(DESCRIPTION_LABEL, "description").-define(DATA_TYPES_TITLE, "Data Types").-define(DATA_TYPES_LABEL, "types").-define(FUNCTION_INDEX_TITLE, "Function Index").-define(FUNCTION_INDEX_LABEL, "index").-define(FUNCTIONS_TITLE, "Function Details").-define(FUNCTIONS_LABEL, "functions").%% @doc The layout function.%%%% Options to the standard layout:%% <dl>%%  <dt>{@type {index_columns, integer()@}}%%  </dt>%%  <dd>Specifies the number of column pairs used for the function%%      index tables. The default value is 1.%%  </dd>%%  <dt>{@type {stylesheet, string()@}}%%  </dt>%%  <dd>Specifies the URI used for referencing the stylesheet. The%%      default value is `"stylesheet.css"'. If an empty string is%%      specified, no stylesheet reference will be generated.%%  </dd>%%  <dt>{@type {xml_export, Module::atom()@}}%%  </dt>%%  <dd>Specifies an {@link //xmerl. `xmerl'} callback module to be%%      used for exporting the documentation. See {@link%%      //xmerl/xmerl:export_simple/3} for details.%%  </dd>%% </dl>%%%% @see edoc:layout/2%% NEW-OPTIONS: xml_export, index_columns, stylesheetmodule(Element, Options) ->    XML = layout_module(Element, init_opts(Element, Options)),    Export = proplists:get_value(xml_export, Options,				 ?DEFAULT_XML_EXPORT),    xmerl:export_simple(XML, Export, []).% Put layout options in a data structure for easier access.%% %Commented out until it can be made private%% %@type opts() = #opts{root = string(),%% %                     stylesheet = string(),%% %                     index_columns = integer()}-record(opts, {root, stylesheet, index_columns}).init_opts(Element, Options) ->    R = #opts{root = get_attrval(root, Element),	      index_columns = proplists:get_value(index_columns,						  Options, 1)	     },    case proplists:get_value(stylesheet, Options) of	undefined ->	    S = edoc_lib:join_uri(R#opts.root, ?STYLESHEET),	    R#opts{stylesheet = S};	"" ->	    R;  % don't use any stylesheet	S when is_list(S) ->	    R#opts{stylesheet = S}; 	_ ->	    report("bad value for option `stylesheet'.", []),	    exit(error)    end.%% =====================================================================%% XML-BASED LAYOUT ENGINE%% =====================================================================%% We assume that we have expanded XML data.%% <!ELEMENT module (behaviour*, description?, author*, copyright?,%%                   version?, since?, deprecated?, see*, reference*,%%                   todo?, typedecls?, functions)>%% <!ATTLIST module%%   name CDATA #REQUIRED%%   private NMTOKEN(yes | no) #IMPLIED%%   root CDATA #IMPLIED>%% <!ELEMENT behaviour (#PCDATA)>%% <!ATTLIST behaviour%%   href CDATA #IMPLIED>%% <!ELEMENT description (briefDescription, fullDescription?)>%% <!ELEMENT briefDescription (#PCDATA)>%% <!ELEMENT fullDescription (#PCDATA)>%% <!ELEMENT author EMPTY>%% <!ATTLIST author%%   name CDATA #REQUIRED%%   email CDATA #IMPLIED%%   website CDATA #IMPLIED>%% <!ELEMENT version (#PCDATA)>%% <!ELEMENT since (#PCDATA)>%% <!ELEMENT copyright (#PCDATA)>%% <!ELEMENT deprecated (description)>%% <!ELEMENT see (#PCDATA)>%% <!ATTLIST see%%   name CDATA #REQUIRED%%   href CDATA #IMPLIED>%% <!ELEMENT reference (#PCDATA)>%% <!ELEMENT todo (#PCDATA)>%% <!ELEMENT typedecls (typedecl+)>%% <!ELEMENT functions (function+)>layout_module(#xmlElement{name = module, content = Es}=E, Opts) ->    Name = get_attrval(name, E),    Title = io_lib:format("Module ~s", [Name]),    Desc = get_content(description, Es),    ShortDesc = get_content(briefDescription, Desc),    FullDesc = get_content(fullDescription, Desc),    Functions = [E || E <- get_content(functions, Es)],    SortedFs = lists:sort([{function_name(E), E} || E <- Functions]),    Types = get_content(typedecls, Es),    SortedTs = lists:sort([{type_name(E), E} || E <- Types]),    Body = (navigation("top")            ++ [?NL, hr, ?NL, ?NL, {h1, [Title]}, ?NL]	    ++ doc_index(FullDesc, Functions, Types)	    ++ ShortDesc	    ++ [?NL]	    ++ copyright(Es)	    ++ deprecated(Es, "module")	    ++ [?NL]	    ++ version(Es)	    ++ since(Es)	    ++ behaviours(Es, Name)	    ++ authors(Es)	    ++ references(Es)	    ++ sees(Es)	    ++ todos(Es)	    ++ if FullDesc == [] -> [];		  true -> [?NL,			   {h2, [{a, [{name, "description"}],				  ["Description"]}]}			   | FullDesc]	       end	    ++ types(SortedTs)	    ++ function_index(SortedFs, Opts#opts.index_columns)	    ++ functions(SortedFs)	    ++ [hr, ?NL]	    ++ navigation("bottom")	    ++ timestamp()),    xhtml(Title, stylesheet(Opts), Body).timestamp() ->    [?NL, {p, [{i, [io_lib:fwrite("Generated by EDoc, ~s, ~s.",				  [edoc_lib:datestr(date()),				   edoc_lib:timestr(time())])		   ]}]},     ?NL]. stylesheet(Opts) ->    case Opts#opts.stylesheet of	undefined ->	    [];	CSS ->	    [{link, [{rel, "stylesheet"},		     {type, "text/css"},		     {href, CSS},		     {title, "EDoc"}], []},	     ?NL]    end.navigation(Where) ->    [?NL,     {'div', [{class, "navbar"}],      [{a, [{name, "#navbar_" ++ Where}], []},       {table, [{width, "100%"}, {border,0},		{cellspacing, 0}, {cellpadding, 2},		{summary, "navigation bar"}],	[{tr,	  [{td, [{a, [{href, ?OVERVIEW_SUMMARY}, {target,"overviewFrame"}],		  ["Overview"]}]},	   {td, [{a, [{href, "http://www.erlang.org/"}],		  [{img, [{src, "erlang.png"}, {align, "right"},			  {border, 0}, {alt, "erlang logo"}],		    []}]}		]}	  ]}	]}      ]}    ].doc_index(FullDesc, Functions, Types) ->    case doc_index_rows(FullDesc, Functions, Types) of	[] -> [];	Rs ->	    [{ul, [{class, "index"}],	      [{li, [{a, [{href, local_label(R)}], [T]}]}	       || {T, R} <- Rs]}]    end.doc_index_rows(FullDesc, Functions, Types) ->    (if FullDesc == [] -> [];	true -> [{?DESCRIPTION_TITLE, ?DESCRIPTION_LABEL}]     end     ++ if Types == [] -> [];	   true -> [{?DATA_TYPES_TITLE, ?DATA_TYPES_LABEL}]	end     ++ if Functions == [] -> [];	   true -> [{?FUNCTION_INDEX_TITLE, ?FUNCTION_INDEX_LABEL},		    {?FUNCTIONS_TITLE, ?FUNCTIONS_LABEL}]	end).function_index(Fs, Cols) ->    case function_index_rows(Fs, Cols, []) of	[] -> [];	Rows ->	    [?NL,	     {h2, [{a, [{name, ?FUNCTION_INDEX_LABEL}],		    [?FUNCTION_INDEX_TITLE]}]},	     ?NL,	     {table, [{width, "100%"}, {border, 1},		      {cellspacing,0}, {cellpadding,2},		      {summary, "function index"}],	      Rows},	     ?NL]    end.function_index_rows(Fs, Cols, Title) ->    Rows = (length(Fs) + (Cols - 1)) div Cols,    (if Title == [] -> [];	true -> [{tr, [{th, [{colspan, Cols * 2}, {align, left}],			[Title]}]},		 ?NL]     end     ++ lists:flatmap(fun index_row/1,		      edoc_lib:transpose(edoc_lib:segment(Fs, Rows)))).index_row(Fs) ->    [{tr, lists:flatmap(fun index_col/1, Fs)}, ?NL].index_col({Name, F=#xmlElement{content = Es}}) ->    [{td, [{valign, "top"}],      label_href(function_header(Name, F, "*"), F)},     {td, index_desc(Es)}].index_desc(Es) ->    Desc = get_content(description, Es),    (case get_content(deprecated, Es) of 	 [] -> []; 	 _ -> ["(", {em, ["Deprecated"]}, ".) "]     end     ++ case get_content(briefDescription, Desc) of	    [] ->		equiv(Es);    % no description at all if no equiv	    ShortDesc ->		ShortDesc	end).label_href(Content, F) ->    case get_attrval(label, F) of	"" -> Content;	Ref -> [{a, [{href, local_label(Ref)}], Content}]    end.%% <!ELEMENT function (args, typespec?, returns?, throws?, equiv?,%%                     description?, since?, deprecated?, see*, todo?)>%% <!ATTLIST function%%   name CDATA #REQUIRED%%   arity CDATA #REQUIRED%%   exported NMTOKEN(yes | no) #REQUIRED%%   label CDATA #IMPLIED>%% <!ELEMENT args (arg*)>%% <!ELEMENT equiv (expr, see?)>%% <!ELEMENT expr (#PCDATA)>functions(Fs) ->    Es = lists:flatmap(fun ({Name, E}) -> function(Name, E) end, Fs),    if Es == [] -> [];       true ->	    [?NL,	     {h2, [{a, [{name, ?FUNCTIONS_LABEL}], [?FUNCTIONS_TITLE]}]},	     ?NL | Es]    end.function(Name, E=#xmlElement{content = Es}) ->    ([?NL,      {h3, [{class, "function"}],       label_anchor(function_header(Name, E, " *"), E)},      ?NL]     ++ [{'div',  [{class, "spec"}],	  [?NL,	   {p,	    case typespec(get_content(typespec, Es)) of		[] ->		    signature(get_content(args, Es),			      get_attrval(name, E));		Spec -> Spec	    end},	   ?NL]	  ++ case params(get_content(args, Es)) of		 [] -> [];		 Ps -> [{p, Ps}, ?NL]	     end	  ++ case returns(get_content(returns, Es)) of		 [] -> [];		 Rs -> [{p, Rs}, ?NL]	     end}]     ++ throws(Es)     ++ equiv_p(Es)     ++ deprecated(Es, "function")     ++ fulldesc(Es)     ++ since(Es)     ++ sees(Es)     ++ todos(Es)).function_name(E) ->    atom(get_attrval(name, E)) ++ "/" ++ get_attrval(arity, E).function_header(Name, E, Private) ->    case is_exported(E) of	true -> [Name];	false -> [Name, Private]    end.is_exported(E) ->    case get_attrval(exported, E) of 	"yes" -> true; 	_ -> false    end.label_anchor(Content, E) ->    case get_attrval(label, E) of	"" -> Content;	Ref -> [{a, [{name, Ref}], Content}]    end.%% <!ELEMENT args (arg*)>%% <!ELEMENT arg (argName, description?)>%% <!ELEMENT argName (#PCDATA)>%% This is currently only done for functions without type spec.signature(Es, Name) ->     [{tt, [Name, "("] ++ seq(fun arg/1, Es) ++ [") -> term()"]}].arg(#xmlElement{content = Es}) ->    [get_text(argName, Es)].%% parameter and return value descriptions (if any)params(Es) ->    As = [{get_text(argName, Es1),	   get_content(fullDescription, get_content(description, Es1))}	  || #xmlElement{content = Es1} <- Es],    As1 = [A || A <- As, element(2, A) /= []],    if As1 == [] ->	    [];       true ->	    [ { [{tt, [A]}, ": "] ++  D ++ [br, ?NL] }	      || {A, D} <- As1]    end.returns(Es) ->    case get_content(fullDescription, get_content(description, Es)) of	[] ->	    [];	D ->	    ["returns: "] ++  D    end.%% <!ELEMENT throws (type, localdef*)>throws(Es) ->    case get_content(throws, Es) of	[] -> [];	Es1 ->	    [{p, (["throws ", {tt, t_utype(get_elem(type, Es1))}]		  ++ local_defs(get_elem(localdef, Es1)))},	     ?NL]    end.%% <!ELEMENT typespec (erlangName, type, localdef*)>typespec([]) -> [];typespec(Es) ->    [{tt, ([t_name(get_elem(erlangName, Es))]	   ++ t_utype(get_elem(type, Es)))}]	++ local_defs(get_elem(localdef, Es)).

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?