Merge lp:~fenryxo/zim/templates-pagemenu into lp:~jaap.karssenberg/zim/pyzim
- templates-pagemenu
- Merge into pyzim
Status: | Merged |
---|---|
Merged at revision: | 408 |
Proposed branch: | lp:~fenryxo/zim/templates-pagemenu |
Merge into: | lp:~jaap.karssenberg/zim/pyzim |
Diff against target: |
580 lines (+431/-27) 7 files modified
data/manual/Help/Templates.txt (+19/-19) data/templates/html/With_Menu.html (+73/-0) tests/data/notebook-wiki.xml (+11/-0) tests/parsing.py (+5/-0) tests/templates.py (+210/-3) zim/parsing.py (+2/-1) zim/templates.py (+111/-4) |
To merge this branch: | bzr merge lp:~fenryxo/zim/templates-pagemenu |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jaap Karssenberg | Approve | ||
Review via email: mp+60616@code.launchpad.net |
Commit message
Description of the change
This branch contains 3 features:
1) notebook.name template variable
2) page.menu template variable: Page menu is a tree-style menu like index, but branches not related to current page are collapsed.
3) New template using both notebook.name & page.menu
Basic test coverage and manual update included.
I've prepared an example - manual exported with the new template - see http://
Jaap Karssenberg (jaap.karssenberg) wrote : | # |
Jiří Janoušek (fenryxo) wrote : | # |
What a good idea :-) I can imagine additional paramethers
* starting path
* limit of nesting
I'll focus on it at the weekend.
Jiří Janoušek (fenryxo) wrote : | # |
The branch is ready for the review again. The test suite probably needs to be polished.
Jaap Karssenberg (jaap.karssenberg) wrote : | # |
Thanks, looks better this way. Will have a look at the test cases when merging.
FYI: will be offline from this Friday for about a week and a bit - will probably not have time to merge all your branched before then. But have will attend to it when I'm back.
-- Jaap
Jaap Karssenberg (jaap.karssenberg) wrote : | # |
Did some rework and afraid that changed how the options work. But it is more in line now with the index page that can be generated, so I propose keeping it like this. If you really want the style you had before maybe we can add a "sparse" option ?
* collapse now mimics the standard index, so it shows all of the toplevel pages and pages in any expanded sub page
* hide_empty now only hides pages that don't have content OR children, this is needed because otherwise namspaces were the parent has no text disappear.
Jiří Janoušek (fenryxo) wrote : | # |
2011/6/6 Jaap Karssenberg <email address hidden>:
> Did some rework and afraid that changed how the options work. But it is more in line now with the index page that can be generated, so I propose keeping it like this. If you really want the style you had before maybe we can add a "sparse" option ?
>
> * collapse now mimics the standard index, so it shows all of the toplevel pages and pages in any expanded sub page
If I understand it correctly, collapse works like the original example
(e.g. http://
missing something, can you put somewhere similar example output?
> * hide_empty now only hides pages that don't have content OR children, this is needed because otherwise namspaces were the parent has no text disappear.
The hide_empty option was intended to prevent creating links to
non-existing pages. But the proper solution could be to create little
index pages listing child nodes (like in WWWInterface).
> --
> https:/
> You are the owner of lp:~janousek.jiri/zim/templates-pagemenu.
>
Jaap Karssenberg (jaap.karssenberg) wrote : | # |
2011/6/6 Jiří Janoušek <email address hidden>
> > * collapse now mimics the standard index, so it shows all of the toplevel
> pages and pages in any expanded sub page
>
> If I understand it correctly, collapse works like the original example
> (e.g. http://
> missing something, can you put somewhere similar example output?
>
>
Yes, for two level depth the behavior is the same. However it now keeps
showing the top level also for deeper nested pages.
> > * hide_empty now only hides pages that don't have content OR children,
> this is needed because otherwise namspaces were the parent has no text
> disappear.
>
> The hide_empty option was intended to prevent creating links to
> non-existing pages. But the proper solution could be to create little
> index pages listing child nodes (like in WWWInterface).
>
Maybe we need to check common code between IndexPage and this function.
-- Jaap
Jiří Janoušek (fenryxo) wrote : | # |
2011/6/6 Jaap Karssenberg <email address hidden>:
> 2011/6/6 Jiří Janoušek <email address hidden>
>
>> > * collapse now mimics the standard index, so it shows all of the toplevel
>> pages and pages in any expanded sub page
>>
>
>
>> If I understand it correctly, collapse works like the original example
>> (e.g. http://
>> missing something, can you put somewhere similar example output?
>>
>>
> Yes, for two level depth the behavior is the same. However it now keeps
> showing the top level also for deeper nested pages
My code should keep top level too (unless a different starting
namespace is explicitly given). If not, it's a mistake, not purpose.
>> > * hide_empty now only hides pages that don't have content OR children,
>> this is needed because otherwise namspaces were the parent has no text
>> disappear.
>>
>> The hide_empty option was intended to prevent creating links to
>> non-existing pages. But the proper solution could be to create little
>> index pages listing child nodes (like in WWWInterface).
>>
>
> Maybe we need to check common code between IndexPage and this function.
The menu function is based on IndexPage code, but I think IndexPage
doesn't require extra logic from menu (home page order manipulation,
current page in bold, ...). It should get starting namespace and level
limit to be usable as a page body for empty pages with children.
> -- Jaap
>
> --
> https:/
> You are the owner of lp:~janousek.jiri/zim/templates-pagemenu.
>
Preview Diff
1 | === modified file 'data/manual/Help/Templates.txt' |
2 | --- data/manual/Help/Templates.txt 2011-04-06 20:00:02 +0000 |
3 | +++ data/manual/Help/Templates.txt 2011-05-16 21:27:32 +0000 |
4 | @@ -56,31 +56,31 @@ |
5 | |
6 | ''' |
7 | zim.version # version of zim |
8 | +notebook.name # name of the notebook |
9 | |
10 | page.name # complete page name |
11 | page.namespace # namespace |
12 | page.basename # last part of the page name |
13 | -page.title # |
14 | +page.title # first heading in the page or the basename |
15 | +page.heading # first heading in the page |
16 | +page.body # content of the page (without the leading heading) |
17 | +page.links # list of page objects for pages linked in this page |
18 | +page.backlinks # list of page objects for pages linking to this page |
19 | +page.properties # dict with page properties |
20 | + |
21 | +# These special pages have the same properties as the 'page' object |
22 | +pages.index # the index page generated when exporting |
23 | +pages.home # the home page |
24 | +pages.next # the next page in the index (if any) |
25 | +pages.previous # the previous page in the index (if any) |
26 | + |
27 | +options # dict where format specific options can be set |
28 | ''' |
29 | -''first heading in the page or the basename'' |
30 | -''page.heading # first heading in the page'' |
31 | -''page.body # content of the page (without the leading heading)'' |
32 | -''page.links # list of page objects for pages linked in this page'' |
33 | -''page.backlinks # ''''list of page objects for pages linking to this page'' |
34 | -''page.properties # dict with page properties'' |
35 | - |
36 | -''# These special pages have the same properties as the 'page' object'' |
37 | -''pages.index # the index page generated when exporting'' |
38 | -''pages.home # the home page'' |
39 | -''pages.next # the next page in the index (if any)'' |
40 | -''pages.previous # the previous page in the index (if any)'' |
41 | - |
42 | -''options # dict where format specific options can be set'' |
43 | + |
44 | |
45 | Functions available: |
46 | |
47 | -''' |
48 | -url(link) # turns a zim link into an URL |
49 | -strftime(template, date) # format a date |
50 | -''' |
51 | +* ''url(link)'' - turns a zim link into an URL |
52 | +* ''strftime(template, date)'' - format a date |
53 | +* ''menu(namespace, collapse, ignore_empty)'' - creates a tree-style menu starting with given namespace (''":"'' by default). ''collapse'' can be ''TRUE'' (only branches related to the current page are visible, //default value//) or ''FALSE'' (all branches are visible). ''ignore_empty'' can be ''TRUE'' (empty pages are ignored, //default value//) or ''FALSE''. Example: ''menu(page.namespace, TRUE, FALSE)'' |
54 | |
55 | |
56 | === added file 'data/templates/html/With_Menu.html' |
57 | --- data/templates/html/With_Menu.html 1970-01-01 00:00:00 +0000 |
58 | +++ data/templates/html/With_Menu.html 2011-05-16 21:27:32 +0000 |
59 | @@ -0,0 +1,73 @@ |
60 | +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
61 | +<html> |
62 | + <head> |
63 | + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
64 | + <title>[% page.title %]</title> |
65 | + <meta name='Generator' content='Zim [% zim.version %]'> |
66 | + <style type='text/css'> |
67 | + a { text-decoration: none } |
68 | + a:hover { text-decoration: underline } |
69 | + a:active { text-decoration: underline } |
70 | + strike { color: grey } |
71 | + u { text-decoration: none; |
72 | + background-color: yellow } |
73 | + tt { color: #2e3436; } |
74 | + pre { color: #2e3436; |
75 | + margin-left: 20px } |
76 | + h1 { text-align: center; |
77 | + color: #4e9a06 } |
78 | + h2 { color: #4e9a06 } |
79 | + h3 { color: #4e9a06 } |
80 | + h4 { color: #4e9a06 } |
81 | + h5 { color: #4e9a06 } |
82 | + span.insen { color: grey } |
83 | + .page { max-width: 1000px;} |
84 | + .menu{ |
85 | + float:left; width: 300px; |
86 | + } |
87 | + |
88 | + .content { padding-left: 320px;} |
89 | + .notebook{font-variant: small-caps; |
90 | + color:#4e9a06; |
91 | + padding: 0px 20px;} |
92 | + hr{clear:both;} |
93 | + </style> |
94 | + |
95 | + </head> |
96 | + <body> |
97 | + <div class="page"> |
98 | + <div class="heading"> |
99 | + <h1><a href="[% url(pages.home.name) %]" class="notebook">[% notebook.name %]:</a> |
100 | + |
101 | + |
102 | + [% IF page.properties.type == 'namespace-index' -%] |
103 | + Document Index</h1> |
104 | + [%- ELSE -%] |
105 | + [% page.heading %]</h1> |
106 | + [%- END %] |
107 | + </div> |
108 | + <hr> |
109 | + <div class="menu"> |
110 | + [% menu(page) %] |
111 | + </div> |
112 | + <div class="content"> |
113 | + <!-- Wiki content --> |
114 | + [% page.body %] |
115 | + |
116 | + <!-- End wiki content --> |
117 | + </div> |
118 | + <hr> |
119 | + <!-- Backlinks --> |
120 | + <div class="footer"> |
121 | + [% IF page.backlinks -%] Backlinks: |
122 | + [%- FOREACH link = page.backlinks -%] |
123 | + <a href='[% url(link) %]'>[% link.name %]</a></li> |
124 | + [%- END -%] |
125 | + [%- ELSE -%] |
126 | + No backlinks to this page. |
127 | + [%- END %] |
128 | + <!-- End Backlinks --> |
129 | + </div> |
130 | + </div> |
131 | + </body> |
132 | +</html> |
133 | |
134 | === modified file 'tests/data/notebook-wiki.xml' |
135 | --- tests/data/notebook-wiki.xml 2011-04-05 20:11:51 +0000 |
136 | +++ tests/data/notebook-wiki.xml 2011-05-16 21:27:32 +0000 |
137 | @@ -312,4 +312,15 @@ |
138 | [[Linking:Foo:Bar]] |
139 | [[Dus]] |
140 | </page> |
141 | +<page name="Parent">For page.menu template variable test</page> |
142 | +<page name="Parent:Son">For page.menu template variable test</page> |
143 | +<page name="Parent:Son:Grandson">For page.menu template variable test</page> |
144 | +<page name="Parent:Son:Granddaughter">For page.menu template variable test</page> |
145 | +<page name="Parent:Daughter">For page.menu template variable test</page> |
146 | +<page name="Parent:Daughter:Grandson">For page.menu template variable test</page> |
147 | +<page name="Parent:Daughter:Granddaughter">For page.menu template variable test</page> |
148 | +<page name="Parent:Daughter:SomeOne:Foo">For page.menu template variable test</page> |
149 | +<page name="Parent:Daughter:SomeOne:Bar">For page.menu template variable test</page> |
150 | +<page name="Parent:Child:Grandchild">For page.menu template variable test</page> |
151 | + |
152 | </pagelist> |
153 | |
154 | === modified file 'tests/parsing.py' |
155 | --- tests/parsing.py 2011-04-02 12:36:48 +0000 |
156 | +++ tests/parsing.py 2011-05-16 21:27:32 +0000 |
157 | @@ -17,6 +17,11 @@ |
158 | list = ['"foo bar"', ',', r'"\"foooo bar\""', 'dusss', 'ja'] |
159 | result = split_quoted_strings(string, unescape=False) |
160 | self.assertEquals(result, list) |
161 | + |
162 | + string = r'''"foo bar", False, True''' |
163 | + list = ['foo bar', ',', 'False', ',', 'True'] |
164 | + result = split_quoted_strings(string) |
165 | + self.assertEquals(result, list) |
166 | |
167 | def testParseDate(self): |
168 | '''Test parsing dates''' |
169 | |
170 | === modified file 'tests/templates.py' |
171 | --- tests/templates.py 2011-05-14 11:08:50 +0000 |
172 | +++ tests/templates.py 2011-05-16 21:27:32 +0000 |
173 | @@ -14,6 +14,7 @@ |
174 | TemplateParam, TemplateDict, TemplateFunction, PageProxy |
175 | from zim.notebook import Notebook, Path |
176 | import zim.formats |
177 | +from zim.parsing import link_type |
178 | |
179 | |
180 | class TestTemplateParam(tests.TestCase): |
181 | @@ -159,14 +160,14 @@ |
182 | input = u'''\ |
183 | Version [% zim.version %] |
184 | <title>[% page.title %]</title> |
185 | -<h1>[% page.name %]</h1> |
186 | +<h1>[% notebook.name %]: [% page.name %]</h1> |
187 | <h2>[% page.heading %]</h2> |
188 | [% page.body %] |
189 | ''' |
190 | wantedresult = u'''\ |
191 | Version %s |
192 | <title>Page Heading</title> |
193 | -<h1>FooBar</h1> |
194 | +<h1>Unnamed Notebook: FooBar</h1> |
195 | <h2>Page Heading</h2> |
196 | <p> |
197 | <strong>foo bar !</strong><br> |
198 | @@ -190,7 +191,213 @@ |
199 | tree = template.process_to_parsetree(notebook, page) # No linker ! |
200 | self.assertEqual(tree.find('h').text, u'Some New None existing page') |
201 | |
202 | - |
203 | +class TestTemplatePageMenu(tests.TestCase): |
204 | + def runTest(self): |
205 | + # menu(root, collapse, ignore_empty) |
206 | + data = ( |
207 | +# Test default settings |
208 | +(u"[% menu() %]", '''\ |
209 | +<ul> |
210 | +<li><a href="page://Parent" title="Parent">Parent</a></li> |
211 | +<ul> |
212 | +<li><strong>Daughter</strong></li> |
213 | +<ul> |
214 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
215 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
216 | +</ul> |
217 | +<li><a href="page://Parent:Son" title="Son">Son</a></li> |
218 | +</ul> |
219 | +<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> |
220 | +<li><a href="page://TODOList" title="TODOList">TODOList</a></li> |
221 | +<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> |
222 | +</ul> |
223 | +'''), |
224 | +# Collapsing turned off |
225 | +(u"[% menu(':', FALSE, TRUE) %]", '''\ |
226 | +<ul> |
227 | +<li><a href="page://Parent" title="Parent">Parent</a></li> |
228 | +<ul> |
229 | +<li><strong>Daughter</strong></li> |
230 | +<ul> |
231 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
232 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
233 | +</ul> |
234 | +<li><a href="page://Parent:Son" title="Son">Son</a></li> |
235 | +<ul> |
236 | +<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
237 | +<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> |
238 | +</ul> |
239 | +</ul> |
240 | +<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> |
241 | +<li><a href="page://TODOList" title="TODOList">TODOList</a></li> |
242 | +<ul> |
243 | +<li><a href="page://TODOList:bar" title="bar">bar</a></li> |
244 | +<li><a href="page://TODOList:foo" title="foo">foo</a></li> |
245 | +</ul> |
246 | +<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> |
247 | +<ul> |
248 | +<li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li> |
249 | +<li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li> |
250 | +</ul> |
251 | +</ul> |
252 | +'''), |
253 | +# Empty pages are not ignored |
254 | +(u"[% menu(':', TRUE, FALSE) %]", '''\ |
255 | +<ul> |
256 | +<li><a href="page://Bar" title="Bar">Bar</a></li> |
257 | +<li><a href="page://foo" title="foo">foo</a></li> |
258 | +<li><a href="page://Linking" title="Linking">Linking</a></li> |
259 | +<li><a href="page://Parent" title="Parent">Parent</a></li> |
260 | +<ul> |
261 | +<li><a href="page://Parent:Child" title="Child">Child</a></li> |
262 | +<li><strong>Daughter</strong></li> |
263 | +<ul> |
264 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
265 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
266 | +<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> |
267 | +</ul> |
268 | +<li><a href="page://Parent:Son" title="Son">Son</a></li> |
269 | +</ul> |
270 | +<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> |
271 | +<li><a href="page://Test" title="Test">Test</a></li> |
272 | +<li><a href="page://TODOList" title="TODOList">TODOList</a></li> |
273 | +<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> |
274 | +<li><a href="page://utf8" title="utf8">utf8</a></li> |
275 | +</ul> |
276 | +'''), |
277 | +# Both |
278 | +(u"[% menu(':', FALSE, FALSE) %]", '''\ |
279 | +<ul> |
280 | +<li><a href="page://Bar" title="Bar">Bar</a></li> |
281 | +<li><a href="page://foo" title="foo">foo</a></li> |
282 | +<ul> |
283 | +<li><a href="page://foo:bar" title="bar">bar</a></li> |
284 | +</ul> |
285 | +<li><a href="page://Linking" title="Linking">Linking</a></li> |
286 | +<ul> |
287 | +<li><a href="page://Linking:Dus" title="Dus">Dus</a></li> |
288 | +<ul> |
289 | +<li><a href="page://Linking:Dus:Ja" title="Ja">Ja</a></li> |
290 | +</ul> |
291 | +<li><a href="page://Linking:Foo" title="Foo">Foo</a></li> |
292 | +<ul> |
293 | +<li><a href="page://Linking:Foo:Bar" title="Bar">Bar</a></li> |
294 | +<ul> |
295 | +<li><a href="page://Linking:Foo:Bar:Baz" title="Baz">Baz</a></li> |
296 | +</ul> |
297 | +</ul> |
298 | +</ul> |
299 | +<li><a href="page://Parent" title="Parent">Parent</a></li> |
300 | +<ul> |
301 | +<li><a href="page://Parent:Child" title="Child">Child</a></li> |
302 | +<ul> |
303 | +<li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li> |
304 | +</ul> |
305 | +<li><strong>Daughter</strong></li> |
306 | +<ul> |
307 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
308 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
309 | +<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> |
310 | +<ul> |
311 | +<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> |
312 | +<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> |
313 | +</ul> |
314 | +</ul> |
315 | +<li><a href="page://Parent:Son" title="Son">Son</a></li> |
316 | +<ul> |
317 | +<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
318 | +<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> |
319 | +</ul> |
320 | +</ul> |
321 | +<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> |
322 | +<li><a href="page://Test" title="Test">Test</a></li> |
323 | +<ul> |
324 | +<li><a href="page://Test:foo" title="foo">foo</a></li> |
325 | +<ul> |
326 | +<li><a href="page://Test:foo:bar" title="bar">bar</a></li> |
327 | +</ul> |
328 | +<li><a href="page://Test:Foo Bar" title="Foo Bar">Foo Bar</a></li> |
329 | +<ul> |
330 | +<li><a href="page://Test:Foo Bar:Dus Ja Hmm" title="Dus Ja Hmm">Dus Ja Hmm</a></li> |
331 | +</ul> |
332 | +<li><a href="page://Test:tags" title="tags">tags</a></li> |
333 | +<li><a href="page://Test:wiki" title="wiki">wiki</a></li> |
334 | +</ul> |
335 | +<li><a href="page://TODOList" title="TODOList">TODOList</a></li> |
336 | +<ul> |
337 | +<li><a href="page://TODOList:bar" title="bar">bar</a></li> |
338 | +<li><a href="page://TODOList:foo" title="foo">foo</a></li> |
339 | +</ul> |
340 | +<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> |
341 | +<ul> |
342 | +<li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li> |
343 | +<li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li> |
344 | +</ul> |
345 | +<li><a href="page://utf8" title="utf8">utf8</a></li> |
346 | +<ul> |
347 | +<li><a href="page://utf8:αβγ" title="αβγ">αβγ</a></li> |
348 | +<li><a href="page://utf8:בדיקה" title="בדיקה">בדיקה</a></li> |
349 | +<ul> |
350 | +<li><a href="page://utf8:בדיקה:טכניון" title="טכניון">טכניון</a></li> |
351 | +<ul> |
352 | +<li><a href="page://utf8:בדיקה:טכניון:הנדסת מכונות" title="הנדסת מכונות">הנדסת מכונות</a></li> |
353 | +<li><a href="page://utf8:בדיקה:טכניון:מדעי המחשב" title="מדעי המחשב">מדעי המחשב</a></li> |
354 | +</ul> |
355 | +</ul> |
356 | +<li><a href="page://utf8:中文" title="中文">中文</a></li> |
357 | +</ul> |
358 | +</ul> |
359 | +'''), |
360 | +# Let's chenge the root |
361 | +(u"[% menu(page, FALSE) %]", '''\ |
362 | +<ul> |
363 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
364 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
365 | +</ul> |
366 | +'''), |
367 | +(u"[% menu(page.name, FALSE, FALSE) %]", '''\ |
368 | +<ul> |
369 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
370 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
371 | +<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> |
372 | +<ul> |
373 | +<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> |
374 | +<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> |
375 | +</ul> |
376 | +</ul> |
377 | +'''), |
378 | +(u"[% menu(page.namespace, FALSE, FALSE) %]", '''\ |
379 | +<ul> |
380 | +<li><a href="page://Parent:Child" title="Child">Child</a></li> |
381 | +<ul> |
382 | +<li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li> |
383 | +</ul> |
384 | +<li><strong>Daughter</strong></li> |
385 | +<ul> |
386 | +<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
387 | +<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> |
388 | +<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> |
389 | +<ul> |
390 | +<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> |
391 | +<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> |
392 | +</ul> |
393 | +</ul> |
394 | +<li><a href="page://Parent:Son" title="Son">Son</a></li> |
395 | +<ul> |
396 | +<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> |
397 | +<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> |
398 | +</ul> |
399 | +</ul> |
400 | +'''), |
401 | +) |
402 | + |
403 | + notebook = notebook = tests.new_notebook() |
404 | + page = notebook.get_page(Path(':Parent:Daughter')) |
405 | + for input, wantedresult in data: |
406 | + result = Template(input, 'html', linker=StubLinker()).process(notebook, page) |
407 | + self.assertEqual(result, wantedresult.splitlines(True)) |
408 | + |
409 | + |
410 | |
411 | class StubLinker(object): |
412 | |
413 | |
414 | === modified file 'zim/parsing.py' |
415 | --- zim/parsing.py 2011-05-13 05:44:02 +0000 |
416 | +++ zim/parsing.py 2011-05-16 21:27:32 +0000 |
417 | @@ -12,7 +12,8 @@ |
418 | word_re = Re(r''' |
419 | ( '(\\'|[^'])*' | # single quoted word |
420 | "(\\"|[^"])*" | # double quoted word |
421 | - \S+ # word without spaces |
422 | + [^\s,]+ | # word without spaces and commas |
423 | + , # comma |
424 | )''', re.X) |
425 | string = string.strip() |
426 | words = [] |
427 | |
428 | === modified file 'zim/templates.py' |
429 | --- zim/templates.py 2011-05-13 05:44:02 +0000 |
430 | +++ zim/templates.py 2011-05-16 21:27:32 +0000 |
431 | @@ -71,8 +71,9 @@ |
432 | from zim.fs import File |
433 | from zim.config import data_dirs |
434 | from zim.parsing import Re, TextBuffer, split_quoted_strings, unescape_quoted_string, is_path_re |
435 | -from zim.formats import ParseTree, Element |
436 | +from zim.formats import ParseTree, Element, TreeBuilder |
437 | from zim.index import LINK_DIR_BACKWARD |
438 | +from zim.notebook import Path |
439 | |
440 | logger = logging.getLogger('zim.templates') |
441 | |
442 | @@ -198,7 +199,6 @@ |
443 | ''' |
444 | if not isinstance(dict, TemplateDict): |
445 | dict = TemplateDict(dict) |
446 | - |
447 | output = TextBuffer(self.tokens.process(dict)) |
448 | return output.get_lines() |
449 | |
450 | @@ -334,7 +334,11 @@ |
451 | 'pages': pages, |
452 | 'strftime': StrftimeFunction(), |
453 | 'url': TemplateFunction(self.url), |
454 | - 'options': options |
455 | + 'options': options, |
456 | + 'notebook': {'name' : notebook.name}, |
457 | + 'menu' : MenuFunction(notebook, page, self.format, self.linker, options), |
458 | + # helpers that allow to write TRUE instead of 'TRUE' in template functions |
459 | + 'TRUE' : 'True', 'FALSE' : 'False', |
460 | } |
461 | |
462 | if self.linker: |
463 | @@ -625,6 +629,109 @@ |
464 | else: |
465 | raise AssertionError, 'Not a datetime object: %s', date |
466 | |
467 | +class MenuFunction(TemplateFunction): |
468 | + '''Template function wrapper for strftime''' |
469 | + |
470 | + def __init__(self, notebook, page, format, linker, options): |
471 | + self._notebook = notebook |
472 | + self._page = page |
473 | + self._format = format |
474 | + self._linker = linker |
475 | + self._options = options |
476 | + |
477 | + |
478 | + def __call__(self, dict, root=':', collapse=True, ignore_empty=True): |
479 | + builder = TreeBuilder() |
480 | + level = self._page.name.count(':') |
481 | + home = Path(self._notebook.config['Notebook']['home']) |
482 | + |
483 | + # TODO: Some logic to parse boolean template function params |
484 | + if isinstance(collapse, (TemplateParam, TemplateLiteral, basestring)): |
485 | + collapse = (str(collapse).strip().lower() == 'true') |
486 | + if isinstance(ignore_empty, (TemplateParam, TemplateLiteral, basestring)): |
487 | + ignore_empty = (str(ignore_empty).strip().lower() == 'true') |
488 | + |
489 | + # [% menu(page) %] vs [% menu(page.name) %] |
490 | + if isinstance(root, PageProxy): root = root.name |
491 | + #~ print "!!! ROOT, ", root |
492 | + |
493 | + def add_namespace(path): |
494 | + mylevel = path.name.count(':') |
495 | + |
496 | + if collapse: |
497 | + # Menu doesn't show whole tree, but only pages related to the current page. |
498 | + if mylevel > level: |
499 | + # "path" is more nested then the current page |
500 | + return |
501 | + elif level == mylevel: |
502 | + # "path" has same level as current page |
503 | + if not self._page.name == path.name and path.name: |
504 | + # Show only children of the current page or namespace pages |
505 | + return |
506 | + elif not self._page.name.startswith(path.name): |
507 | + # "path" is less nested, show only children of the ancestors |
508 | + # of the current page |
509 | + return |
510 | + |
511 | + #~ print "!!! path & level", path, mylevel |
512 | + pagelist = list(self._notebook.index.list_pages(path)) |
513 | + # find home page |
514 | + for page in pagelist: |
515 | + if page.name == home.name: |
516 | + home_page = page |
517 | + break |
518 | + else: |
519 | + # home page not in list |
520 | + home_page = None |
521 | + |
522 | + # home page will be first item |
523 | + if not home_page is None: |
524 | + pagelist.remove(home_page) |
525 | + pagelist.insert(0, home_page) |
526 | + |
527 | + builder.start('ul') |
528 | + for page in pagelist: |
529 | + if ignore_empty and not page.hascontent: |
530 | + #~ print "!!! skip page", page |
531 | + continue |
532 | + builder.start('li') |
533 | + text = page.basename |
534 | + |
535 | + if self._page.name == page.name: |
536 | + # Current page is marked with the strong style |
537 | + builder.start('strong') |
538 | + builder.data(text) |
539 | + builder.end('strong') |
540 | + else: |
541 | + # links to other pages |
542 | + builder.start('link', {'type': 'page', 'href': page.name}) |
543 | + builder.data(text) |
544 | + builder.end('link') |
545 | + builder.end('li') |
546 | + if page.haschildren: |
547 | + add_namespace(page) # recurs |
548 | + builder.end('ul') |
549 | + |
550 | + builder.start('page') |
551 | + add_namespace(Path(root)) |
552 | + builder.end('page') |
553 | + |
554 | + tree = ParseTree(builder.close()) |
555 | + if not tree: |
556 | + return None |
557 | + |
558 | + #~ print "!!!", tree.tostring() |
559 | + |
560 | + format = self._format |
561 | + linker = self._linker |
562 | + if linker: |
563 | + linker.set_path(self._page) |
564 | + |
565 | + dumper = format.Dumper( |
566 | + linker=linker, |
567 | + template_options=self._options ) |
568 | + |
569 | + return ''.join(dumper.dump(tree)) |
570 | |
571 | class TemplateDict(object): |
572 | '''Object behaving like a dict for storing values of template parameters. |
573 | @@ -751,7 +858,7 @@ |
574 | for link in blinks: |
575 | source = self._notebook.get_page(link.source) |
576 | yield PageProxy(self._notebook, source, self._format, self._linker, self._options) |
577 | - |
578 | + |
579 | |
580 | class ParseTreeProxy(object): |
581 |
I like the idea - maybe we should not put it in the "page" namespace. How about exposing this as a function to the template ? That way you can (later) add parameters to control the style (folded vs unfolded etc.) and make it a bit more powerful.