/src/support/z_tags.erl

https://code.google.com/p/zotonic/ · Erlang · 98 lines · 68 code · 18 blank · 12 comment · 1 complexity · 48cb4facefbe086b8ac58121d2368ba0 MD5 · raw file

  1. %% @author Marc Worrell <marc@worrell.nl>
  2. %% @copyright 2009 Marc Worrell <marc@worrell.nl>
  3. %%
  4. %% Based on code Copyright (c) 2008-2009 Rusty Klophaus
  5. %% Original author Tom McNulty <tom.mcnulty@cetiforge.com>
  6. %%
  7. %% @doc Generate a XHTML element with attributes, correctly escape all attributes.
  8. -module (z_tags).
  9. -include("include/zotonic.hrl").
  10. -export([render_tag/2, render_tag/3, render_tag/4]).
  11. -export([optional_escape/1]).
  12. %% @doc Render a tag with properties, return the tag text. div has special handling as <div/> is not allowed.
  13. render_tag("div", Props) ->
  14. render_tag(<<"div">>, Props);
  15. render_tag(<<"div">>, Props) ->
  16. [<<"<div ">>, write_props(Props), <<"></div>">> ];
  17. render_tag(TagName, Props) ->
  18. [$<, TagName, write_props(Props), $/, $> ].
  19. %% @doc Render a tag into the context
  20. render_tag("div", Props, #context{} = Context) ->
  21. render_tag(<<"div">>, Props, Context);
  22. render_tag(<<"div">>, Props, #context{} = Context) ->
  23. Render = [<<"<div ">>, write_props(Props), <<"></div>">> ],
  24. z_render:render(Render, Context);
  25. render_tag(TagName, Props, #context{} = Context) ->
  26. Render = [$<, TagName, write_props(Props), $/, $> ],
  27. z_render:render(Render, Context);
  28. render_tag(TagName, Props, Content) ->
  29. [ $<, TagName, write_props(Props), $>, Content, $<, $/, TagName, $> ].
  30. %%% Tags with child content %%%
  31. render_tag(TagName, Props, undefined, Context) ->
  32. render_tag(TagName, Props, Context);
  33. render_tag(TagName, Props, [], Context) ->
  34. render_tag(TagName, Props, Context);
  35. render_tag(TagName, Props, Content, Context) ->
  36. Render = [ $<, TagName, write_props(Props), $>, Content, $<, $/, TagName, $> ],
  37. z_render:render(Render, Context).
  38. %%% Property display functions %%%
  39. write_props(Props) ->
  40. [ display_property(optional_escape_property(P)) || P <- Props ].
  41. display_property({_Prop, undefined}) ->
  42. [];
  43. display_property({Prop, V}) when is_atom(Prop) ->
  44. display_property({list_to_binary(atom_to_list(Prop)), V});
  45. display_property({_, []}) ->
  46. [];
  47. display_property({Prop, Value}) when is_integer(Value) ->
  48. [32, correct_data(Prop), $=, $', list_to_binary(integer_to_list(Value)), $'];
  49. display_property({Prop, Value}) when is_float(Value) ->
  50. [32, correct_data(Prop), $=, $', list_to_binary(io_lib:format("~f",[Value])), $'];
  51. display_property({Prop, Value}) when is_list(Value) ->
  52. case io_lib:char_list(Value) of
  53. true ->
  54. [32, correct_data(Prop), $=, $', Value, $'];
  55. false ->
  56. [32, correct_data(Prop), $=, $', z_utils:combine_defined(32, Value), $']
  57. end;
  58. display_property({Prop, Value}) when is_atom(Value) ->
  59. [32, correct_data(Prop), $=, $', atom_to_list(Value), $'];
  60. display_property({Prop, Value}) ->
  61. [32, correct_data(Prop), $=, $', Value, $'].
  62. optional_escape_property({href, Uri}) -> {href, optional_escape(Uri)};
  63. optional_escape_property({src, Uri}) -> {src, optional_escape(Uri)};
  64. optional_escape_property({<<"src">>, Uri}) -> {<<"src">>, optional_escape(Uri)};
  65. optional_escape_property({<<"href">>, Uri}) -> {<<"href">>, optional_escape(Uri)};
  66. optional_escape_property(P) -> P.
  67. optional_escape(S) when is_list(S) ->
  68. case string:chr(S, $&) of
  69. 0 -> S;
  70. _ ->
  71. case string:str(S, "&amp;") of
  72. 0 -> mochiweb_html:escape(S);
  73. _ -> S
  74. end
  75. end;
  76. optional_escape(S) -> S.
  77. % @doc Correct data_xxxx attributes, so that they are generated as data-xxxx
  78. correct_data("data_"++P) -> "data-"++P;
  79. correct_data(<<"data_",P/binary>>) -> <<"data-",P/binary>>;
  80. correct_data(P) -> P.