Zim

Merge lp:~fenryxo/zim/templates-pagemenu into lp:~jaap.karssenberg/zim/pyzim

Proposed by Jiří Janoušek
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
Reviewer Review Type Date Requested Status
Jaap Karssenberg Approve
Review via email: mp+60616@code.launchpad.net

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://tmp.doublej.cz/pagemenu/

To post a comment you must log in.
Revision history for this message
Jaap Karssenberg (jaap.karssenberg) wrote :

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.

Revision history for this message
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.

Revision history for this message
Jiří Janoušek (fenryxo) wrote :

The branch is ready for the review again. The test suite probably needs to be polished.

Revision history for this message
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

review: Approve
Revision history for this message
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.

Revision history for this message
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://tmp.doublej.cz/pagemenu /Help/Export.html ) Or if I'm
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://code.launchpad.net/~janousek.jiri/zim/templates-pagemenu/+merge/60616
> You are the owner of lp:~janousek.jiri/zim/templates-pagemenu.
>

Revision history for this message
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://tmp.doublej.cz/pagemenu /Help/Export.html ) Or if I'm
> 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

Revision history for this message
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://tmp.doublej.cz/pagemenu /Help/Export.html ) Or if I'm
>> 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://code.launchpad.net/~janousek.jiri/zim/templates-pagemenu/+merge/60616
> You are the owner of lp:~janousek.jiri/zim/templates-pagemenu.
>

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'data/manual/Help/Templates.txt'
--- data/manual/Help/Templates.txt 2011-04-06 20:00:02 +0000
+++ data/manual/Help/Templates.txt 2011-05-16 21:27:32 +0000
@@ -56,31 +56,31 @@
5656
57'''57'''
58zim.version # version of zim58zim.version # version of zim
59notebook.name # name of the notebook
5960
60page.name # complete page name61page.name # complete page name
61page.namespace # namespace62page.namespace # namespace
62page.basename # last part of the page name63page.basename # last part of the page name
63page.title # 64page.title # first heading in the page or the basename
65page.heading # first heading in the page
66page.body # content of the page (without the leading heading)
67page.links # list of page objects for pages linked in this page
68page.backlinks # list of page objects for pages linking to this page
69page.properties # dict with page properties
70
71# These special pages have the same properties as the 'page' object
72pages.index # the index page generated when exporting
73pages.home # the home page
74pages.next # the next page in the index (if any)
75pages.previous # the previous page in the index (if any)
76
77options # dict where format specific options can be set
64'''78'''
65''first heading in the page or the basename''79
66''page.heading # first heading in the page''
67''page.body # content of the page (without the leading heading)''
68''page.links # list of page objects for pages linked in this page''
69''page.backlinks # ''''list of page objects for pages linking to this page''
70''page.properties # dict with page properties''
71
72''# These special pages have the same properties as the 'page' object''
73''pages.index # the index page generated when exporting''
74''pages.home # the home page''
75''pages.next # the next page in the index (if any)''
76''pages.previous # the previous page in the index (if any)''
77
78''options # dict where format specific options can be set''
7980
80Functions available:81Functions available:
8182
82'''83* ''url(link)'' - turns a zim link into an URL
83url(link) # turns a zim link into an URL84* ''strftime(template, date)'' - format a date
84strftime(template, date) # format a date85* ''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)''
85'''
8686
8787
=== added file 'data/templates/html/With_Menu.html'
--- data/templates/html/With_Menu.html 1970-01-01 00:00:00 +0000
+++ data/templates/html/With_Menu.html 2011-05-16 21:27:32 +0000
@@ -0,0 +1,73 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2<html>
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <title>[% page.title %]</title>
6 <meta name='Generator' content='Zim [% zim.version %]'>
7 <style type='text/css'>
8 a { text-decoration: none }
9 a:hover { text-decoration: underline }
10 a:active { text-decoration: underline }
11 strike { color: grey }
12 u { text-decoration: none;
13 background-color: yellow }
14 tt { color: #2e3436; }
15 pre { color: #2e3436;
16 margin-left: 20px }
17 h1 { text-align: center;
18 color: #4e9a06 }
19 h2 { color: #4e9a06 }
20 h3 { color: #4e9a06 }
21 h4 { color: #4e9a06 }
22 h5 { color: #4e9a06 }
23 span.insen { color: grey }
24 .page { max-width: 1000px;}
25 .menu{
26 float:left; width: 300px;
27 }
28
29 .content { padding-left: 320px;}
30 .notebook{font-variant: small-caps;
31 color:#4e9a06;
32 padding: 0px 20px;}
33 hr{clear:both;}
34 </style>
35
36 </head>
37 <body>
38 <div class="page">
39 <div class="heading">
40 <h1><a href="[% url(pages.home.name) %]" class="notebook">[% notebook.name %]:</a>
41
42
43 [% IF page.properties.type == 'namespace-index' -%]
44 Document Index</h1>
45 [%- ELSE -%]
46 [% page.heading %]</h1>
47 [%- END %]
48 </div>
49 <hr>
50 <div class="menu">
51 [% menu(page) %]
52 </div>
53 <div class="content">
54 <!-- Wiki content -->
55 [% page.body %]
56
57 <!-- End wiki content -->
58 </div>
59 <hr>
60 <!-- Backlinks -->
61 <div class="footer">
62 [% IF page.backlinks -%] Backlinks:
63 [%- FOREACH link = page.backlinks -%]
64 <a href='[% url(link) %]'>[% link.name %]</a></li>
65 [%- END -%]
66 [%- ELSE -%]
67 No backlinks to this page.
68 [%- END %]
69 <!-- End Backlinks -->
70 </div>
71 </div>
72 </body>
73</html>
074
=== modified file 'tests/data/notebook-wiki.xml'
--- tests/data/notebook-wiki.xml 2011-04-05 20:11:51 +0000
+++ tests/data/notebook-wiki.xml 2011-05-16 21:27:32 +0000
@@ -312,4 +312,15 @@
312[[Linking:Foo:Bar]]312[[Linking:Foo:Bar]]
313[[Dus]]313[[Dus]]
314</page>314</page>
315<page name="Parent">For page.menu template variable test</page>
316<page name="Parent:Son">For page.menu template variable test</page>
317<page name="Parent:Son:Grandson">For page.menu template variable test</page>
318<page name="Parent:Son:Granddaughter">For page.menu template variable test</page>
319<page name="Parent:Daughter">For page.menu template variable test</page>
320<page name="Parent:Daughter:Grandson">For page.menu template variable test</page>
321<page name="Parent:Daughter:Granddaughter">For page.menu template variable test</page>
322<page name="Parent:Daughter:SomeOne:Foo">For page.menu template variable test</page>
323<page name="Parent:Daughter:SomeOne:Bar">For page.menu template variable test</page>
324<page name="Parent:Child:Grandchild">For page.menu template variable test</page>
325
315</pagelist>326</pagelist>
316327
=== modified file 'tests/parsing.py'
--- tests/parsing.py 2011-04-02 12:36:48 +0000
+++ tests/parsing.py 2011-05-16 21:27:32 +0000
@@ -17,6 +17,11 @@
17 list = ['"foo bar"', ',', r'"\"foooo bar\""', 'dusss', 'ja']17 list = ['"foo bar"', ',', r'"\"foooo bar\""', 'dusss', 'ja']
18 result = split_quoted_strings(string, unescape=False)18 result = split_quoted_strings(string, unescape=False)
19 self.assertEquals(result, list)19 self.assertEquals(result, list)
20
21 string = r'''"foo bar", False, True'''
22 list = ['foo bar', ',', 'False', ',', 'True']
23 result = split_quoted_strings(string)
24 self.assertEquals(result, list)
2025
21 def testParseDate(self):26 def testParseDate(self):
22 '''Test parsing dates'''27 '''Test parsing dates'''
2328
=== modified file 'tests/templates.py'
--- tests/templates.py 2011-05-14 11:08:50 +0000
+++ tests/templates.py 2011-05-16 21:27:32 +0000
@@ -14,6 +14,7 @@
14 TemplateParam, TemplateDict, TemplateFunction, PageProxy14 TemplateParam, TemplateDict, TemplateFunction, PageProxy
15from zim.notebook import Notebook, Path15from zim.notebook import Notebook, Path
16import zim.formats16import zim.formats
17from zim.parsing import link_type
1718
1819
19class TestTemplateParam(tests.TestCase):20class TestTemplateParam(tests.TestCase):
@@ -159,14 +160,14 @@
159 input = u'''\160 input = u'''\
160Version [% zim.version %]161Version [% zim.version %]
161<title>[% page.title %]</title>162<title>[% page.title %]</title>
162<h1>[% page.name %]</h1>163<h1>[% notebook.name %]: [% page.name %]</h1>
163<h2>[% page.heading %]</h2>164<h2>[% page.heading %]</h2>
164[% page.body %]165[% page.body %]
165'''166'''
166 wantedresult = u'''\167 wantedresult = u'''\
167Version %s168Version %s
168<title>Page Heading</title>169<title>Page Heading</title>
169<h1>FooBar</h1>170<h1>Unnamed Notebook: FooBar</h1>
170<h2>Page Heading</h2>171<h2>Page Heading</h2>
171<p>172<p>
172<strong>foo bar !</strong><br>173<strong>foo bar !</strong><br>
@@ -190,7 +191,213 @@
190 tree = template.process_to_parsetree(notebook, page) # No linker !191 tree = template.process_to_parsetree(notebook, page) # No linker !
191 self.assertEqual(tree.find('h').text, u'Some New None existing page')192 self.assertEqual(tree.find('h').text, u'Some New None existing page')
192193
193194class TestTemplatePageMenu(tests.TestCase):
195 def runTest(self):
196 # menu(root, collapse, ignore_empty)
197 data = (
198# Test default settings
199(u"[% menu() %]", '''\
200<ul>
201<li><a href="page://Parent" title="Parent">Parent</a></li>
202<ul>
203<li><strong>Daughter</strong></li>
204<ul>
205<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
206<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
207</ul>
208<li><a href="page://Parent:Son" title="Son">Son</a></li>
209</ul>
210<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li>
211<li><a href="page://TODOList" title="TODOList">TODOList</a></li>
212<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li>
213</ul>
214'''),
215# Collapsing turned off
216(u"[% menu(':', FALSE, TRUE) %]", '''\
217<ul>
218<li><a href="page://Parent" title="Parent">Parent</a></li>
219<ul>
220<li><strong>Daughter</strong></li>
221<ul>
222<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
223<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
224</ul>
225<li><a href="page://Parent:Son" title="Son">Son</a></li>
226<ul>
227<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li>
228<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li>
229</ul>
230</ul>
231<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li>
232<li><a href="page://TODOList" title="TODOList">TODOList</a></li>
233<ul>
234<li><a href="page://TODOList:bar" title="bar">bar</a></li>
235<li><a href="page://TODOList:foo" title="foo">foo</a></li>
236</ul>
237<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li>
238<ul>
239<li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li>
240<li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li>
241</ul>
242</ul>
243'''),
244# Empty pages are not ignored
245(u"[% menu(':', TRUE, FALSE) %]", '''\
246<ul>
247<li><a href="page://Bar" title="Bar">Bar</a></li>
248<li><a href="page://foo" title="foo">foo</a></li>
249<li><a href="page://Linking" title="Linking">Linking</a></li>
250<li><a href="page://Parent" title="Parent">Parent</a></li>
251<ul>
252<li><a href="page://Parent:Child" title="Child">Child</a></li>
253<li><strong>Daughter</strong></li>
254<ul>
255<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
256<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
257<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li>
258</ul>
259<li><a href="page://Parent:Son" title="Son">Son</a></li>
260</ul>
261<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li>
262<li><a href="page://Test" title="Test">Test</a></li>
263<li><a href="page://TODOList" title="TODOList">TODOList</a></li>
264<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li>
265<li><a href="page://utf8" title="utf8">utf8</a></li>
266</ul>
267'''),
268# Both
269(u"[% menu(':', FALSE, FALSE) %]", '''\
270<ul>
271<li><a href="page://Bar" title="Bar">Bar</a></li>
272<li><a href="page://foo" title="foo">foo</a></li>
273<ul>
274<li><a href="page://foo:bar" title="bar">bar</a></li>
275</ul>
276<li><a href="page://Linking" title="Linking">Linking</a></li>
277<ul>
278<li><a href="page://Linking:Dus" title="Dus">Dus</a></li>
279<ul>
280<li><a href="page://Linking:Dus:Ja" title="Ja">Ja</a></li>
281</ul>
282<li><a href="page://Linking:Foo" title="Foo">Foo</a></li>
283<ul>
284<li><a href="page://Linking:Foo:Bar" title="Bar">Bar</a></li>
285<ul>
286<li><a href="page://Linking:Foo:Bar:Baz" title="Baz">Baz</a></li>
287</ul>
288</ul>
289</ul>
290<li><a href="page://Parent" title="Parent">Parent</a></li>
291<ul>
292<li><a href="page://Parent:Child" title="Child">Child</a></li>
293<ul>
294<li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li>
295</ul>
296<li><strong>Daughter</strong></li>
297<ul>
298<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
299<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
300<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li>
301<ul>
302<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li>
303<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li>
304</ul>
305</ul>
306<li><a href="page://Parent:Son" title="Son">Son</a></li>
307<ul>
308<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li>
309<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li>
310</ul>
311</ul>
312<li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li>
313<li><a href="page://Test" title="Test">Test</a></li>
314<ul>
315<li><a href="page://Test:foo" title="foo">foo</a></li>
316<ul>
317<li><a href="page://Test:foo:bar" title="bar">bar</a></li>
318</ul>
319<li><a href="page://Test:Foo Bar" title="Foo Bar">Foo Bar</a></li>
320<ul>
321<li><a href="page://Test:Foo Bar:Dus Ja Hmm" title="Dus Ja Hmm">Dus Ja Hmm</a></li>
322</ul>
323<li><a href="page://Test:tags" title="tags">tags</a></li>
324<li><a href="page://Test:wiki" title="wiki">wiki</a></li>
325</ul>
326<li><a href="page://TODOList" title="TODOList">TODOList</a></li>
327<ul>
328<li><a href="page://TODOList:bar" title="bar">bar</a></li>
329<li><a href="page://TODOList:foo" title="foo">foo</a></li>
330</ul>
331<li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li>
332<ul>
333<li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li>
334<li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li>
335</ul>
336<li><a href="page://utf8" title="utf8">utf8</a></li>
337<ul>
338<li><a href="page://utf8:αβγ" title="αβγ">αβγ</a></li>
339<li><a href="page://utf8:בדיקה" title="בדיקה">בדיקה</a></li>
340<ul>
341<li><a href="page://utf8:בדיקה:טכניון" title="טכניון">טכניון</a></li>
342<ul>
343<li><a href="page://utf8:בדיקה:טכניון:הנדסת מכונות" title="הנדסת מכונות">הנדסת מכונות</a></li>
344<li><a href="page://utf8:בדיקה:טכניון:מדעי המחשב" title="מדעי המחשב">מדעי המחשב</a></li>
345</ul>
346</ul>
347<li><a href="page://utf8:中文" title="中文">中文</a></li>
348</ul>
349</ul>
350'''),
351# Let's chenge the root
352(u"[% menu(page, FALSE) %]", '''\
353<ul>
354<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
355<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
356</ul>
357'''),
358(u"[% menu(page.name, FALSE, FALSE) %]", '''\
359<ul>
360<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
361<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
362<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li>
363<ul>
364<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li>
365<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li>
366</ul>
367</ul>
368'''),
369(u"[% menu(page.namespace, FALSE, FALSE) %]", '''\
370<ul>
371<li><a href="page://Parent:Child" title="Child">Child</a></li>
372<ul>
373<li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li>
374</ul>
375<li><strong>Daughter</strong></li>
376<ul>
377<li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li>
378<li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li>
379<li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li>
380<ul>
381<li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li>
382<li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li>
383</ul>
384</ul>
385<li><a href="page://Parent:Son" title="Son">Son</a></li>
386<ul>
387<li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li>
388<li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li>
389</ul>
390</ul>
391'''),
392)
393
394 notebook = notebook = tests.new_notebook()
395 page = notebook.get_page(Path(':Parent:Daughter'))
396 for input, wantedresult in data:
397 result = Template(input, 'html', linker=StubLinker()).process(notebook, page)
398 self.assertEqual(result, wantedresult.splitlines(True))
399
400
194401
195class StubLinker(object):402class StubLinker(object):
196403
197404
=== modified file 'zim/parsing.py'
--- zim/parsing.py 2011-05-13 05:44:02 +0000
+++ zim/parsing.py 2011-05-16 21:27:32 +0000
@@ -12,7 +12,8 @@
12 word_re = Re(r'''12 word_re = Re(r'''
13 ( '(\\'|[^'])*' | # single quoted word13 ( '(\\'|[^'])*' | # single quoted word
14 "(\\"|[^"])*" | # double quoted word14 "(\\"|[^"])*" | # double quoted word
15 \S+ # word without spaces15 [^\s,]+ | # word without spaces and commas
16 , # comma
16 )''', re.X)17 )''', re.X)
17 string = string.strip()18 string = string.strip()
18 words = []19 words = []
1920
=== modified file 'zim/templates.py'
--- zim/templates.py 2011-05-13 05:44:02 +0000
+++ zim/templates.py 2011-05-16 21:27:32 +0000
@@ -71,8 +71,9 @@
71from zim.fs import File71from zim.fs import File
72from zim.config import data_dirs72from zim.config import data_dirs
73from zim.parsing import Re, TextBuffer, split_quoted_strings, unescape_quoted_string, is_path_re73from zim.parsing import Re, TextBuffer, split_quoted_strings, unescape_quoted_string, is_path_re
74from zim.formats import ParseTree, Element74from zim.formats import ParseTree, Element, TreeBuilder
75from zim.index import LINK_DIR_BACKWARD75from zim.index import LINK_DIR_BACKWARD
76from zim.notebook import Path
7677
77logger = logging.getLogger('zim.templates')78logger = logging.getLogger('zim.templates')
7879
@@ -198,7 +199,6 @@
198 '''199 '''
199 if not isinstance(dict, TemplateDict):200 if not isinstance(dict, TemplateDict):
200 dict = TemplateDict(dict)201 dict = TemplateDict(dict)
201
202 output = TextBuffer(self.tokens.process(dict))202 output = TextBuffer(self.tokens.process(dict))
203 return output.get_lines()203 return output.get_lines()
204204
@@ -334,7 +334,11 @@
334 'pages': pages,334 'pages': pages,
335 'strftime': StrftimeFunction(),335 'strftime': StrftimeFunction(),
336 'url': TemplateFunction(self.url),336 'url': TemplateFunction(self.url),
337 'options': options337 'options': options,
338 'notebook': {'name' : notebook.name},
339 'menu' : MenuFunction(notebook, page, self.format, self.linker, options),
340 # helpers that allow to write TRUE instead of 'TRUE' in template functions
341 'TRUE' : 'True', 'FALSE' : 'False',
338 }342 }
339343
340 if self.linker:344 if self.linker:
@@ -625,6 +629,109 @@
625 else:629 else:
626 raise AssertionError, 'Not a datetime object: %s', date630 raise AssertionError, 'Not a datetime object: %s', date
627631
632class MenuFunction(TemplateFunction):
633 '''Template function wrapper for strftime'''
634
635 def __init__(self, notebook, page, format, linker, options):
636 self._notebook = notebook
637 self._page = page
638 self._format = format
639 self._linker = linker
640 self._options = options
641
642
643 def __call__(self, dict, root=':', collapse=True, ignore_empty=True):
644 builder = TreeBuilder()
645 level = self._page.name.count(':')
646 home = Path(self._notebook.config['Notebook']['home'])
647
648 # TODO: Some logic to parse boolean template function params
649 if isinstance(collapse, (TemplateParam, TemplateLiteral, basestring)):
650 collapse = (str(collapse).strip().lower() == 'true')
651 if isinstance(ignore_empty, (TemplateParam, TemplateLiteral, basestring)):
652 ignore_empty = (str(ignore_empty).strip().lower() == 'true')
653
654 # [% menu(page) %] vs [% menu(page.name) %]
655 if isinstance(root, PageProxy): root = root.name
656 #~ print "!!! ROOT, ", root
657
658 def add_namespace(path):
659 mylevel = path.name.count(':')
660
661 if collapse:
662 # Menu doesn't show whole tree, but only pages related to the current page.
663 if mylevel > level:
664 # "path" is more nested then the current page
665 return
666 elif level == mylevel:
667 # "path" has same level as current page
668 if not self._page.name == path.name and path.name:
669 # Show only children of the current page or namespace pages
670 return
671 elif not self._page.name.startswith(path.name):
672 # "path" is less nested, show only children of the ancestors
673 # of the current page
674 return
675
676 #~ print "!!! path & level", path, mylevel
677 pagelist = list(self._notebook.index.list_pages(path))
678 # find home page
679 for page in pagelist:
680 if page.name == home.name:
681 home_page = page
682 break
683 else:
684 # home page not in list
685 home_page = None
686
687 # home page will be first item
688 if not home_page is None:
689 pagelist.remove(home_page)
690 pagelist.insert(0, home_page)
691
692 builder.start('ul')
693 for page in pagelist:
694 if ignore_empty and not page.hascontent:
695 #~ print "!!! skip page", page
696 continue
697 builder.start('li')
698 text = page.basename
699
700 if self._page.name == page.name:
701 # Current page is marked with the strong style
702 builder.start('strong')
703 builder.data(text)
704 builder.end('strong')
705 else:
706 # links to other pages
707 builder.start('link', {'type': 'page', 'href': page.name})
708 builder.data(text)
709 builder.end('link')
710 builder.end('li')
711 if page.haschildren:
712 add_namespace(page) # recurs
713 builder.end('ul')
714
715 builder.start('page')
716 add_namespace(Path(root))
717 builder.end('page')
718
719 tree = ParseTree(builder.close())
720 if not tree:
721 return None
722
723 #~ print "!!!", tree.tostring()
724
725 format = self._format
726 linker = self._linker
727 if linker:
728 linker.set_path(self._page)
729
730 dumper = format.Dumper(
731 linker=linker,
732 template_options=self._options )
733
734 return ''.join(dumper.dump(tree))
628735
629class TemplateDict(object):736class TemplateDict(object):
630 '''Object behaving like a dict for storing values of template parameters.737 '''Object behaving like a dict for storing values of template parameters.
@@ -751,7 +858,7 @@
751 for link in blinks:858 for link in blinks:
752 source = self._notebook.get_page(link.source)859 source = self._notebook.get_page(link.source)
753 yield PageProxy(self._notebook, source, self._format, self._linker, self._options)860 yield PageProxy(self._notebook, source, self._format, self._linker, self._options)
754861
755862
756class ParseTreeProxy(object):863class ParseTreeProxy(object):
757864