-module(term2html). -export([expand/1]). -include_lib("../include/term2html.hrl"). expand(Items) -> unicode:characters_to_list(expand(Items, [])). expand([], Acc) -> ?REV(Acc); expand([Item | Rest], Acc) when is_tuple(Item) -> expand(Rest, [expand_item(Item) | Acc]); expand(Item, Acc) when is_binary(Item) -> ?REV([Item | Acc]); expand(Item, Acc) when is_tuple(Item) -> ?REV([expand_item(Item) | Acc]); expand(Item, Acc) when is_list(Item) -> case is_string(Item) of true -> [Item | Acc]; _ -> ?REV([[expand(I, []) || I <- Item] | Acc]) end; expand(Other, Acc) when is_integer(Other); is_float(Other); is_atom(Other) -> ?REV([to_str(Other) | Acc]). expand_item({Tag}) -> expand_item({Tag, []}); expand_item({Tag, Attributes}) -> case is_void_element(Tag) of true -> opening_tag(Tag, Attributes); _ -> expand_item({Tag, Attributes, ""}) end; expand_item({Tag, Attributes, Content}) -> InnerHTML = expand(Content, []), [opening_tag(Tag, Attributes), InnerHTML, ""]. opening_tag(Tag, Attributes) -> TagStr = to_str(Tag), case item_attributes(Attributes) of [] -> ["<", TagStr, ">"]; Attr -> ["<", TagStr, " ", Attr, ">"] end. item_attributes(Attributes) -> lists:join(" ", lists:map(fun attr/1, Attributes)). attr({Key, List}) when is_list(List) -> KeyStr = to_str(Key), case is_string(List) of true -> [KeyStr, "=\"", escape(List), "\""]; _ when Key =:= class -> [KeyStr, "=\"", clsx:run(List), "\""]; _ -> [KeyStr, "=\"", lists:map(fun to_str/1, List), "\""] end; attr({Key, Value}) -> [to_str(Key), "=\"", to_str(Value), "\""]; attr(Other) -> to_str(Other). to_str(Atom) when is_atom(Atom) -> atom_to_list(Atom); to_str(Binary) when is_binary(Binary) -> Binary; to_str(Integer) when is_integer(Integer) -> integer_to_list(Integer); to_str(Float) when is_float(Float) -> float_to_list(Float, [compact, {decimals, 15}]); to_str(String) when is_list(String) -> String. escape(String) -> escape(String, []). escape([], Acc) -> ?REV(Acc); escape([$& | Tail], Acc) -> escape(Tail, ["&" | Acc]); escape([$< | Tail], Acc) -> escape(Tail, ["<" | Acc]); escape([$> | Tail], Acc) -> escape(Tail, [">" | Acc]); escape([$" | Tail], Acc) -> escape(Tail, [""" | Acc]); escape([L | Tail], Acc) -> escape(Tail, [L | Acc]). is_string([]) -> true; is_string([I | Tail]) when is_integer(I) -> is_string(Tail); is_string(_) -> false. void_elements() -> [area, base, br, col, frame, embed, hr, img, input, isindex, link, meta, param, source, track, wbr]. is_void_element(Tag) -> lists:member(Tag, void_elements()).