Просмотр исходного кода

Implement truncatewords_html filter

Evan Miller 14 лет назад
Родитель
Сommit
fc76082e62
2 измененных файлов с 43 добавлено и 3 удалено
  1. 40 3
      src/erlydtl_filters.erl
  2. 3 0
      tests/src/erlydtl_unittests.erl

+ 40 - 3
src/erlydtl_filters.erl

@@ -101,7 +101,7 @@
         timeuntil/2,
         title/1,
         truncatewords/2,
-        %truncatewords_html/,
+        truncatewords_html/2,
         unordered_list/1,
         upper/1,
         urlencode/1,
@@ -698,13 +698,21 @@ title(Input) when is_list(Input) ->
     title(Input, []).
 
 %% @doc Truncates a string after a certain number of words.
-truncatewords(Input, Max) when is_binary(Input) ->
-    list_to_binary(truncatewords(binary_to_list(Input), Max));
 truncatewords(_Input, Max) when Max =< 0 ->
     "";
+truncatewords(Input, Max) when is_binary(Input) ->
+    list_to_binary(truncatewords(binary_to_list(Input), Max));
 truncatewords(Input, Max) ->
     truncatewords(Input, Max, []).
 
+%% @doc Similar to truncatewords, except that it is aware of HTML tags.
+truncatewords_html(_Input, Max) when Max =< 0 ->
+    "";
+truncatewords_html(Input, Max) when is_binary(Input) ->
+    truncatewords_html(binary_to_list(Input), Max);
+truncatewords_html(Input, Max) ->
+    truncatewords_html(Input, Max, [], [], text).
+
 %% @doc Recursively takes a self-nested list and returns an HTML unordered list -- WITHOUT opening and closing <ul> tags. 
 unordered_list(List) ->
     String = lists:flatten(unordered_list(List, [])),
@@ -909,6 +917,35 @@ truncatewords([C1, C2|Rest], WordsLeft, Acc) when C1 =/= $\  andalso C2 =:= $\
 truncatewords([C1|Rest], WordsLeft, Acc) ->
     truncatewords(Rest, WordsLeft, [C1|Acc]).
 
+truncatewords_html([], _WordsLeft, Acc, [], _) ->
+    lists:reverse(Acc);
+truncatewords_html(_Input, 0, Acc, [], _) ->
+    lists:reverse(Acc);
+truncatewords_html(Input, 0, Acc, [Tag|RestOfTags], done) ->
+    truncatewords_html(Input, 0, ">"++Tag++"/<" ++ Acc, RestOfTags, done);
+truncatewords_html(Input, 0, Acc, [Tag|RestOfTags], _) ->
+    truncatewords_html(Input, 0, "...>"++Tag++"/<" ++ Acc, RestOfTags, done);
+truncatewords_html([], WordsLeft, Acc, [Tag|RestOfTags], _) ->
+    truncatewords_html([], WordsLeft, ">"++Tag++"/<" ++ Acc, RestOfTags, text);
+truncatewords_html([C|Rest], WordsLeft, Acc, Tags, text) when C =:= $< ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], [""|Tags], tag);
+truncatewords_html([C1, C2|Rest], WordsLeft, Acc, Tags, text) when C1 =/= $\ , C2 =:= $\ ; C1 =/= $\ , C2 =:= $< ->
+    truncatewords_html([C2|Rest], WordsLeft - 1, [C1|Acc], Tags, text);
+truncatewords_html([C|Rest], WordsLeft, Acc, Tags, text) ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], Tags, text);
+truncatewords_html([C|Rest], WordsLeft, Acc, [""|Tags], tag) when C =:= $/ ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], Tags, close_tag);
+truncatewords_html([C|Rest], WordsLeft, Acc, [Tag|RestOfTags], tag) when C >= $a, C =< $z; C >= $A, C =< $Z ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], [[C|Tag]|RestOfTags], tag);
+truncatewords_html([C|Rest], WordsLeft, Acc, Tags, tag) when C =:= $> ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], Tags, text);
+truncatewords_html([C|Rest], WordsLeft, Acc, Tags, tag) ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], Tags, attrs);
+truncatewords_html([C|Rest], WordsLeft, Acc, Tags, attrs) when C =:= $> ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], Tags, text);
+truncatewords_html([C|Rest], WordsLeft, Acc, [_Tag|RestOfTags], close_tag) when C =:= $> ->
+    truncatewords_html(Rest, WordsLeft, [C|Acc], RestOfTags, text).
+
 wordcount([], Count) ->
     Count;
 wordcount([C1], Count) when C1 =/= $\  ->

+ 3 - 0
tests/src/erlydtl_unittests.erl

@@ -778,6 +778,9 @@ tests() ->
                 {"|truncatewords:3",
                     <<"{{ var1|truncatewords:3 }}">>, [{var1, "Don't Truncate Me"}],
                     <<"Don't Truncate Me">>},
+                {"|truncatewords_html:4",
+                    <<"{{ var1|truncatewords_html:4 }}">>, [{var1, "<p>The <strong>Long and <em>Winding</em> Road</strong> is too long</p>"}],
+                    <<"<p>The <strong>Long and <em>Winding</em>...</strong></p>">>},
                 {"|unordered_list",
                     <<"{{ var1|unordered_list }}">>, [{var1, ["States", ["Kansas", ["Lawrence", "Topeka"], "Illinois"]]}],
                     <<"<li>States<ul><li>Kansas<ul><li>Lawrence<li>Topeka</ul><li>Illinois</ul>">>},