Browse Source

New tag: spaceless

Evan Miller 14 years ago
parent
commit
e26d23fcc4

+ 2 - 2
README.markdown

@@ -3,9 +3,9 @@ ErlyDTL
 
 
 ErlyDTL implements most but not all of the Django Template Language.
 ErlyDTL implements most but not all of the Django Template Language.
 
 
-*Supported tags*: autoescape, block, comment, cycle, extends, filter, firstof, for, if, ifequal, ifnotequal, include, now, ssi, templatetag, trans, widthratio, with
+*Supported tags*: autoescape, block, comment, cycle, extends, filter, firstof, for, if, ifequal, ifnotequal, include, now, spaceless, ssi, templatetag, trans, widthratio, with
 
 
-_Unsupported tags_: csrf_token, ifchanged, regroup, spaceless, url
+_Unsupported tags_: csrf_token, ifchanged, regroup, url
 
 
 *Supported filters*: add, addslashes, capfirst, center, cut, date, default, default_if_none, dictsort, dictsortreversed, divisibleby, escape, escapejs, filesizeformat, first, fix_ampersands, floatformat, force_escape, format_integer, format_number, get_digit, join, last, length, length_is, linebreaks, linebreaksbr, linenumbers, ljust, lower, make_list, phonenumeric, pluralize, pprint, random, random_num, random_range, removetags, rjust, safe, safeseq, slice, slugify, stringformat, striptags, time, timesince, timeuntil, title, truncatewords, truncatewords_html, unordered_list, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap, yesno
 *Supported filters*: add, addslashes, capfirst, center, cut, date, default, default_if_none, dictsort, dictsortreversed, divisibleby, escape, escapejs, filesizeformat, first, fix_ampersands, floatformat, force_escape, format_integer, format_number, get_digit, join, last, length, length_is, linebreaks, linebreaksbr, linenumbers, ljust, lower, make_list, phonenumeric, pluralize, pprint, random, random_num, random_range, removetags, rjust, safe, safeseq, slice, slugify, stringformat, striptags, time, timesince, timeuntil, title, truncatewords, truncatewords_html, unordered_list, upper, urlencode, urlize, urlizetrunc, wordcount, wordwrap, yesno
 
 

+ 9 - 0
src/erlydtl_compiler.erl

@@ -513,6 +513,8 @@ body_ast(DjangoParseTree, Context, TreeWalker) ->
                 ifelse_ast({'expr', "ne", Arg1, Arg2}, IfAstInfo, ElseAstInfo, Context, TreeWalker2);                    
                 ifelse_ast({'expr', "ne", Arg1, Arg2}, IfAstInfo, ElseAstInfo, Context, TreeWalker2);                    
             ({'include', {string_literal, _, File}}, TreeWalkerAcc) ->
             ({'include', {string_literal, _, File}}, TreeWalkerAcc) ->
                 include_ast(unescape_string_literal(File), Context, TreeWalkerAcc);
                 include_ast(unescape_string_literal(File), Context, TreeWalkerAcc);
+            ({'spaceless', Contents}, TreeWalkerAcc) ->
+                spaceless_ast(Contents, Context, TreeWalkerAcc);
             ({'ssi', Arg}, TreeWalkerAcc) ->
             ({'ssi', Arg}, TreeWalkerAcc) ->
                 ssi_ast(Arg, Context, TreeWalkerAcc);
                 ssi_ast(Arg, Context, TreeWalkerAcc);
             ({'string', _Pos, String}, TreeWalkerAcc) -> 
             ({'string', _Pos, String}, TreeWalkerAcc) -> 
@@ -976,6 +978,13 @@ ssi_ast(FileName, Context, TreeWalker) ->
                 erl_syntax:atom(read_file),
                 erl_syntax:atom(read_file),
                 [erl_syntax:atom(Mod), erl_syntax:atom(Fun), Ast]), Info}, TreeWalker1}.
                 [erl_syntax:atom(Mod), erl_syntax:atom(Fun), Ast]), Info}, TreeWalker1}.
 
 
+spaceless_ast(Contents, Context, TreeWalker) ->
+    {{Ast, Info}, TreeWalker1} = body_ast(Contents, Context, TreeWalker),
+    {{erl_syntax:application(
+                erl_syntax:atom(erlydtl_runtime),
+                erl_syntax:atom(spaceless),
+                [Ast]), Info}, TreeWalker1}.
+
 unescape_string_literal(String) ->
 unescape_string_literal(String) ->
     unescape_string_literal(string:strip(String, both, 34), [], noslash).
     unescape_string_literal(string:strip(String, both, 34), [], noslash).
 
 

+ 7 - 0
src/erlydtl_parser.yrl

@@ -97,6 +97,8 @@ Nonterminals
     CustomTag
     CustomTag
     Args
     Args
 
 
+    SpacelessBlock
+
     SSITag
     SSITag
 
 
     TransTag    
     TransTag    
@@ -134,6 +136,7 @@ Terminals
     endif_keyword
     endif_keyword
     endifequal_keyword
     endifequal_keyword
     endifnotequal_keyword
     endifnotequal_keyword
+    endspaceless_keyword
     endwith_keyword
     endwith_keyword
     extends_keyword
     extends_keyword
     filter_keyword
     filter_keyword
@@ -152,6 +155,7 @@ Terminals
     or_keyword
     or_keyword
     open_tag
     open_tag
     open_var
     open_var
+    spaceless_keyword
     ssi_keyword
     ssi_keyword
     string_literal
     string_literal
     string
     string
@@ -200,6 +204,7 @@ Elements -> Elements IfEqualBlock : '$1' ++ ['$2'].
 Elements -> Elements IfNotEqualBlock : '$1' ++ ['$2'].
 Elements -> Elements IfNotEqualBlock : '$1' ++ ['$2'].
 Elements -> Elements IncludeTag : '$1' ++ ['$2'].
 Elements -> Elements IncludeTag : '$1' ++ ['$2'].
 Elements -> Elements NowTag : '$1' ++ ['$2'].
 Elements -> Elements NowTag : '$1' ++ ['$2'].
+Elements -> Elements SpacelessBlock : '$1' ++ ['$2'].
 Elements -> Elements SSITag : '$1' ++ ['$2'].
 Elements -> Elements SSITag : '$1' ++ ['$2'].
 Elements -> Elements TemplatetagTag : '$1' ++ ['$2'].
 Elements -> Elements TemplatetagTag : '$1' ++ ['$2'].
 Elements -> Elements TransTag : '$1' ++ ['$2'].
 Elements -> Elements TransTag : '$1' ++ ['$2'].
@@ -297,6 +302,8 @@ IfNotEqualBraced -> open_tag ifnotequal_keyword IfNotEqualExpression Value close
 IfNotEqualExpression -> Value : '$1'.
 IfNotEqualExpression -> Value : '$1'.
 EndIfNotEqualBraced -> open_tag endifnotequal_keyword close_tag.
 EndIfNotEqualBraced -> open_tag endifnotequal_keyword close_tag.
 
 
+SpacelessBlock -> open_tag spaceless_keyword close_tag Elements open_tag endspaceless_keyword close_tag : {spaceless, '$4'}.
+
 SSITag -> open_tag ssi_keyword Value close_tag : {ssi, '$3'}.
 SSITag -> open_tag ssi_keyword Value close_tag : {ssi, '$3'}.
 
 
 TemplatetagTag -> open_tag templatetag_keyword Templatetag close_tag : {templatetag, '$3'}.
 TemplatetagTag -> open_tag templatetag_keyword Templatetag close_tag : {templatetag, '$3'}.

+ 7 - 0
src/erlydtl_runtime.erl

@@ -193,6 +193,13 @@ cycle(NamesTuple, Counters) when is_tuple(NamesTuple) ->
 widthratio(Numerator, Denominator, Scale) ->
 widthratio(Numerator, Denominator, Scale) ->
     round(Numerator / Denominator * Scale).
     round(Numerator / Denominator * Scale).
 
 
+spaceless(Contents) ->
+    Contents1 = lists:flatten(Contents),
+    Contents2 = re:replace(Contents1, "^\s+<", "<", [{return,list}]),
+    Contents3 = re:replace(Contents2, ">\s+$", ">", [{return,list}]),
+    Contents4 = re:replace(Contents3, ">\s+<", "><", [global, {return,list}]),
+    Contents4.
+
 read_file(Module, Function, FileName) ->
 read_file(Module, Function, FileName) ->
     FileName = filename:absname(FileName),
     FileName = filename:absname(FileName),
     {ok, Binary} = Module:Function(FileName),
     {ok, Binary} = Module:Function(FileName),

+ 1 - 1
src/erlydtl_scanner.erl

@@ -90,7 +90,7 @@ scan([], Scanned, _, in_text) ->
 
 
                             %TODO "regroup", 
                             %TODO "regroup", 
                             
                             
-                            %TODO "spaceless", "endspaceless", 
+                            "spaceless", "endspaceless", 
                             
                             
                             "ssi", 
                             "ssi", 
                             
                             

+ 5 - 0
tests/src/erlydtl_unittests.erl

@@ -889,6 +889,11 @@ tests() ->
                 [],
                 [],
                 <<"baz">>}
                 <<"baz">>}
         ]},
         ]},
+    {"spaceless", [
+            {"Beginning", <<"{% spaceless %}    <b>foo</b>{% endspaceless %}">>, [], <<"<b>foo</b>">>},
+            {"Middle", <<"{% spaceless %}<b>foo</b>  <b>bar</b>{% endspaceless %}">>, [], <<"<b>foo</b><b>bar</b>">>},
+            {"End", <<"{% spaceless %}<b>foo</b>  {% endspaceless %}">>, [], <<"<b>foo</b>">>}
+        ]},
     {"templatetag", [
     {"templatetag", [
             {"openblock", <<"{% templatetag openblock %}">>, [], <<"{%">>},
             {"openblock", <<"{% templatetag openblock %}">>, [], <<"{%">>},
             {"closeblock", <<"{% templatetag closeblock %}">>, [], <<"%}">>},
             {"closeblock", <<"{% templatetag closeblock %}">>, [], <<"%}">>},