Skip to content

Commit be02e47

Browse files
committed
ifchanged-tag added.
1 parent 1deab40 commit be02e47

6 files changed

Lines changed: 175 additions & 5 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@ Please use the [issue tracker](https://github.com/flosch/pongo2/issues) if you'r
2121

2222
Please also have a look on the [caveats](https://github.com/flosch/pongo2#caveats) and on the [official add-ons](https://github.com/flosch/pongo2#official).
2323

24-
## New in pongo2
24+
## Features (and new in pongo2)
2525

2626
* Entirely rewritten from the ground-up.
27-
* [Easy API to create new filters and tags](http://godoc.org/github.com/flosch/pongo2#RegisterFilter) ([including parsing arguments](http://godoc.org/github.com/flosch/pongo2#Parser)); take a look on an example and the differences between pongo1 and pongo2: [old](https://github.com/flosch/pongo/blob/master/filters.go#L65) and [new](https://github.com/flosch/pongo2/blob/master/filters_builtin.go#L72).
2827
* [Advanced C-like expressions](https://github.com/flosch/pongo2/blob/master/template_tests/expressions.tpl).
2928
* [Complex function calls within expressions](https://github.com/flosch/pongo2/blob/master/template_tests/function_calls_wrapper.tpl).
30-
* Additional features
31-
* Macros (see [template_tests/macro.tpl](https://github.com/flosch/pongo2/blob/master/template_tests/macro.tpl))
29+
* [Easy API to create new filters and tags](http://godoc.org/github.com/flosch/pongo2#RegisterFilter) ([including parsing arguments](http://godoc.org/github.com/flosch/pongo2#Parser))
30+
* Additional features:
31+
* Macros (see [template_tests/macro.tpl](https://github.com/flosch/pongo2/blob/master/template_tests/macro.tpl))
3232

3333
## Recent API changes within pongo2
3434

pongo2_template_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,32 @@ Yep!`,
142142
Text: "<b>hello!</b> there",
143143
},
144144
},
145+
"comments2": []*comment{
146+
&comment{
147+
Author: &user{
148+
Name: "user1",
149+
Validated: true,
150+
},
151+
Date: time2,
152+
Text: "\"pongo2 is nice!\"",
153+
},
154+
&comment{
155+
Author: &user{
156+
Name: "user1",
157+
Validated: true,
158+
},
159+
Date: time1,
160+
Text: "comment2 with <script>unsafe</script> tags in it",
161+
},
162+
&comment{
163+
Author: &user{
164+
Name: "user3",
165+
Validated: false,
166+
},
167+
Date: time1,
168+
Text: "<b>hello!</b> there",
169+
},
170+
},
145171
},
146172
}
147173

tags_ifchanged.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package pongo2
2+
3+
import (
4+
"bytes"
5+
)
6+
7+
type tagIfchangedNode struct {
8+
watched_expr []INodeEvaluator
9+
last_values []*Value
10+
last_content []byte
11+
thenWrapper *NodeWrapper
12+
elseWrapper *NodeWrapper
13+
}
14+
15+
func (node *tagIfchangedNode) Execute(ctx *ExecutionContext, buffer *bytes.Buffer) error {
16+
17+
if len(node.watched_expr) == 0 {
18+
// Check against own rendered body
19+
20+
buf := bytes.NewBuffer(make([]byte, 0, 1024)) // 1 KiB
21+
err := node.thenWrapper.Execute(ctx, buf)
22+
if err != nil {
23+
return err
24+
}
25+
26+
buf_bytes := buf.Bytes()
27+
if !bytes.Equal(node.last_content, buf_bytes) {
28+
// Rendered content changed, output it
29+
buffer.Write(buf_bytes)
30+
node.last_content = buf_bytes
31+
}
32+
} else {
33+
now_values := make([]*Value, 0, len(node.watched_expr))
34+
for _, expr := range node.watched_expr {
35+
val, err := expr.Evaluate(ctx)
36+
if err != nil {
37+
return err
38+
}
39+
now_values = append(now_values, val)
40+
}
41+
42+
// Compare old to new values now
43+
changed := len(node.last_values) == 0
44+
45+
for idx, old_val := range node.last_values {
46+
if !old_val.EqualValueTo(now_values[idx]) {
47+
changed = true
48+
break // we can stop here because ONE value changed
49+
}
50+
}
51+
52+
node.last_values = now_values
53+
54+
if changed {
55+
// Render thenWrapper
56+
err := node.thenWrapper.Execute(ctx, buffer)
57+
if err != nil {
58+
return err
59+
}
60+
} else {
61+
// Render elseWrapper
62+
err := node.elseWrapper.Execute(ctx, buffer)
63+
if err != nil {
64+
return err
65+
}
66+
}
67+
}
68+
69+
return nil
70+
}
71+
72+
func tagIfchangedParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, error) {
73+
ifchanged_node := &tagIfchangedNode{}
74+
75+
for arguments.Remaining() > 0 {
76+
// Parse condition
77+
expr, err := arguments.ParseExpression()
78+
if err != nil {
79+
return nil, err
80+
}
81+
ifchanged_node.watched_expr = append(ifchanged_node.watched_expr, expr)
82+
}
83+
84+
if arguments.Remaining() > 0 {
85+
return nil, arguments.Error("Ifchanged-arguments are malformed.", nil)
86+
}
87+
88+
// Wrap then/else-blocks
89+
wrapper, endargs, err := doc.WrapUntilTag("else", "endifchanged")
90+
if err != nil {
91+
return nil, err
92+
}
93+
ifchanged_node.thenWrapper = wrapper
94+
95+
if endargs.Count() > 0 {
96+
return nil, endargs.Error("Arguments not allowed here.", nil)
97+
}
98+
99+
if wrapper.Endtag == "else" {
100+
// if there's an else in the if-statement, we need the else-Block as well
101+
wrapper, endargs, err = doc.WrapUntilTag("endifchanged")
102+
if err != nil {
103+
return nil, err
104+
}
105+
ifchanged_node.elseWrapper = wrapper
106+
107+
if endargs.Count() > 0 {
108+
return nil, endargs.Error("Arguments not allowed here.", nil)
109+
}
110+
}
111+
112+
return ifchanged_node, nil
113+
}
114+
115+
func init() {
116+
RegisterTag("ifchanged", tagIfchangedParser)
117+
}

tags_spaceless.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
)
77

88
type tagSpacelessNode struct {
9-
wrapper *NodeWrapper
9+
wrapper *NodeWrapper
1010
}
1111

1212
var tagSpacelessRegexp = regexp.MustCompile(`(?U:(<.*>))([\t\n\v\f\r ]+)(?U:(<.*>))`)

template_tests/ifchanged.tpl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{% for comment in complex.comments2 %}
2+
{% ifchanged %}New comment from another user {{ comment.Author.Name }}{% endifchanged %}
3+
{% ifchanged comment.Author.Validated %}
4+
Validated changed to {{ comment.Author.Validated }}
5+
{% else %}
6+
Validated value not changed
7+
{% endifchanged %}
8+
{% ifchanged comment.Author.Name comment.Date %}Comment's author name or date changed{% endifchanged %}
9+
{% endfor %}

template_tests/ifchanged.tpl.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
New comment from another user user1
3+
4+
Validated changed to True
5+
6+
Comment's author name or date changed
7+
8+
9+
10+
Validated value not changed
11+
12+
Comment's author name or date changed
13+
14+
New comment from another user user3
15+
16+
Validated changed to False
17+
18+
Comment's author name or date changed

0 commit comments

Comments
 (0)