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 | 56 | 56 | ||
6 | 57 | ''' | 57 | ''' |
7 | 58 | zim.version # version of zim | 58 | zim.version # version of zim |
8 | 59 | notebook.name # name of the notebook | ||
9 | 59 | 60 | ||
10 | 60 | page.name # complete page name | 61 | page.name # complete page name |
11 | 61 | page.namespace # namespace | 62 | page.namespace # namespace |
12 | 62 | page.basename # last part of the page name | 63 | page.basename # last part of the page name |
14 | 63 | page.title # | 64 | page.title # first heading in the page or the basename |
15 | 65 | page.heading # first heading in the page | ||
16 | 66 | page.body # content of the page (without the leading heading) | ||
17 | 67 | page.links # list of page objects for pages linked in this page | ||
18 | 68 | page.backlinks # list of page objects for pages linking to this page | ||
19 | 69 | page.properties # dict with page properties | ||
20 | 70 | |||
21 | 71 | # These special pages have the same properties as the 'page' object | ||
22 | 72 | pages.index # the index page generated when exporting | ||
23 | 73 | pages.home # the home page | ||
24 | 74 | pages.next # the next page in the index (if any) | ||
25 | 75 | pages.previous # the previous page in the index (if any) | ||
26 | 76 | |||
27 | 77 | options # dict where format specific options can be set | ||
28 | 64 | ''' | 78 | ''' |
43 | 65 | ''first heading in the page or the basename'' | 79 | |
30 | 66 | ''page.heading # first heading in the page'' | ||
31 | 67 | ''page.body # content of the page (without the leading heading)'' | ||
32 | 68 | ''page.links # list of page objects for pages linked in this page'' | ||
33 | 69 | ''page.backlinks # ''''list of page objects for pages linking to this page'' | ||
34 | 70 | ''page.properties # dict with page properties'' | ||
35 | 71 | |||
36 | 72 | ''# These special pages have the same properties as the 'page' object'' | ||
37 | 73 | ''pages.index # the index page generated when exporting'' | ||
38 | 74 | ''pages.home # the home page'' | ||
39 | 75 | ''pages.next # the next page in the index (if any)'' | ||
40 | 76 | ''pages.previous # the previous page in the index (if any)'' | ||
41 | 77 | |||
42 | 78 | ''options # dict where format specific options can be set'' | ||
44 | 79 | 80 | ||
45 | 80 | Functions available: | 81 | Functions available: |
46 | 81 | 82 | ||
51 | 82 | ''' | 83 | * ''url(link)'' - turns a zim link into an URL |
52 | 83 | url(link) # turns a zim link into an URL | 84 | * ''strftime(template, date)'' - format a date |
53 | 84 | strftime(template, date) # format a date | 85 | * ''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)'' |
50 | 85 | ''' | ||
54 | 86 | 86 | ||
55 | 87 | 87 | ||
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 | 1 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | ||
61 | 2 | <html> | ||
62 | 3 | <head> | ||
63 | 4 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||
64 | 5 | <title>[% page.title %]</title> | ||
65 | 6 | <meta name='Generator' content='Zim [% zim.version %]'> | ||
66 | 7 | <style type='text/css'> | ||
67 | 8 | a { text-decoration: none } | ||
68 | 9 | a:hover { text-decoration: underline } | ||
69 | 10 | a:active { text-decoration: underline } | ||
70 | 11 | strike { color: grey } | ||
71 | 12 | u { text-decoration: none; | ||
72 | 13 | background-color: yellow } | ||
73 | 14 | tt { color: #2e3436; } | ||
74 | 15 | pre { color: #2e3436; | ||
75 | 16 | margin-left: 20px } | ||
76 | 17 | h1 { text-align: center; | ||
77 | 18 | color: #4e9a06 } | ||
78 | 19 | h2 { color: #4e9a06 } | ||
79 | 20 | h3 { color: #4e9a06 } | ||
80 | 21 | h4 { color: #4e9a06 } | ||
81 | 22 | h5 { color: #4e9a06 } | ||
82 | 23 | span.insen { color: grey } | ||
83 | 24 | .page { max-width: 1000px;} | ||
84 | 25 | .menu{ | ||
85 | 26 | float:left; width: 300px; | ||
86 | 27 | } | ||
87 | 28 | |||
88 | 29 | .content { padding-left: 320px;} | ||
89 | 30 | .notebook{font-variant: small-caps; | ||
90 | 31 | color:#4e9a06; | ||
91 | 32 | padding: 0px 20px;} | ||
92 | 33 | hr{clear:both;} | ||
93 | 34 | </style> | ||
94 | 35 | |||
95 | 36 | </head> | ||
96 | 37 | <body> | ||
97 | 38 | <div class="page"> | ||
98 | 39 | <div class="heading"> | ||
99 | 40 | <h1><a href="[% url(pages.home.name) %]" class="notebook">[% notebook.name %]:</a> | ||
100 | 41 | |||
101 | 42 | |||
102 | 43 | [% IF page.properties.type == 'namespace-index' -%] | ||
103 | 44 | Document Index</h1> | ||
104 | 45 | [%- ELSE -%] | ||
105 | 46 | [% page.heading %]</h1> | ||
106 | 47 | [%- END %] | ||
107 | 48 | </div> | ||
108 | 49 | <hr> | ||
109 | 50 | <div class="menu"> | ||
110 | 51 | [% menu(page) %] | ||
111 | 52 | </div> | ||
112 | 53 | <div class="content"> | ||
113 | 54 | <!-- Wiki content --> | ||
114 | 55 | [% page.body %] | ||
115 | 56 | |||
116 | 57 | <!-- End wiki content --> | ||
117 | 58 | </div> | ||
118 | 59 | <hr> | ||
119 | 60 | <!-- Backlinks --> | ||
120 | 61 | <div class="footer"> | ||
121 | 62 | [% IF page.backlinks -%] Backlinks: | ||
122 | 63 | [%- FOREACH link = page.backlinks -%] | ||
123 | 64 | <a href='[% url(link) %]'>[% link.name %]</a></li> | ||
124 | 65 | [%- END -%] | ||
125 | 66 | [%- ELSE -%] | ||
126 | 67 | No backlinks to this page. | ||
127 | 68 | [%- END %] | ||
128 | 69 | <!-- End Backlinks --> | ||
129 | 70 | </div> | ||
130 | 71 | </div> | ||
131 | 72 | </body> | ||
132 | 73 | </html> | ||
133 | 0 | 74 | ||
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 | 312 | [[Linking:Foo:Bar]] | 312 | [[Linking:Foo:Bar]] |
139 | 313 | [[Dus]] | 313 | [[Dus]] |
140 | 314 | </page> | 314 | </page> |
141 | 315 | <page name="Parent">For page.menu template variable test</page> | ||
142 | 316 | <page name="Parent:Son">For page.menu template variable test</page> | ||
143 | 317 | <page name="Parent:Son:Grandson">For page.menu template variable test</page> | ||
144 | 318 | <page name="Parent:Son:Granddaughter">For page.menu template variable test</page> | ||
145 | 319 | <page name="Parent:Daughter">For page.menu template variable test</page> | ||
146 | 320 | <page name="Parent:Daughter:Grandson">For page.menu template variable test</page> | ||
147 | 321 | <page name="Parent:Daughter:Granddaughter">For page.menu template variable test</page> | ||
148 | 322 | <page name="Parent:Daughter:SomeOne:Foo">For page.menu template variable test</page> | ||
149 | 323 | <page name="Parent:Daughter:SomeOne:Bar">For page.menu template variable test</page> | ||
150 | 324 | <page name="Parent:Child:Grandchild">For page.menu template variable test</page> | ||
151 | 325 | |||
152 | 315 | </pagelist> | 326 | </pagelist> |
153 | 316 | 327 | ||
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 | 17 | list = ['"foo bar"', ',', r'"\"foooo bar\""', 'dusss', 'ja'] | 17 | list = ['"foo bar"', ',', r'"\"foooo bar\""', 'dusss', 'ja'] |
159 | 18 | result = split_quoted_strings(string, unescape=False) | 18 | result = split_quoted_strings(string, unescape=False) |
160 | 19 | self.assertEquals(result, list) | 19 | self.assertEquals(result, list) |
161 | 20 | |||
162 | 21 | string = r'''"foo bar", False, True''' | ||
163 | 22 | list = ['foo bar', ',', 'False', ',', 'True'] | ||
164 | 23 | result = split_quoted_strings(string) | ||
165 | 24 | self.assertEquals(result, list) | ||
166 | 20 | 25 | ||
167 | 21 | def testParseDate(self): | 26 | def testParseDate(self): |
168 | 22 | '''Test parsing dates''' | 27 | '''Test parsing dates''' |
169 | 23 | 28 | ||
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 | 14 | TemplateParam, TemplateDict, TemplateFunction, PageProxy | 14 | TemplateParam, TemplateDict, TemplateFunction, PageProxy |
175 | 15 | from zim.notebook import Notebook, Path | 15 | from zim.notebook import Notebook, Path |
176 | 16 | import zim.formats | 16 | import zim.formats |
177 | 17 | from zim.parsing import link_type | ||
178 | 17 | 18 | ||
179 | 18 | 19 | ||
180 | 19 | class TestTemplateParam(tests.TestCase): | 20 | class TestTemplateParam(tests.TestCase): |
181 | @@ -159,14 +160,14 @@ | |||
182 | 159 | input = u'''\ | 160 | input = u'''\ |
183 | 160 | Version [% zim.version %] | 161 | Version [% zim.version %] |
184 | 161 | <title>[% page.title %]</title> | 162 | <title>[% page.title %]</title> |
186 | 162 | <h1>[% page.name %]</h1> | 163 | <h1>[% notebook.name %]: [% page.name %]</h1> |
187 | 163 | <h2>[% page.heading %]</h2> | 164 | <h2>[% page.heading %]</h2> |
188 | 164 | [% page.body %] | 165 | [% page.body %] |
189 | 165 | ''' | 166 | ''' |
190 | 166 | wantedresult = u'''\ | 167 | wantedresult = u'''\ |
191 | 167 | Version %s | 168 | Version %s |
192 | 168 | <title>Page Heading</title> | 169 | <title>Page Heading</title> |
194 | 169 | <h1>FooBar</h1> | 170 | <h1>Unnamed Notebook: FooBar</h1> |
195 | 170 | <h2>Page Heading</h2> | 171 | <h2>Page Heading</h2> |
196 | 171 | <p> | 172 | <p> |
197 | 172 | <strong>foo bar !</strong><br> | 173 | <strong>foo bar !</strong><br> |
198 | @@ -190,7 +191,213 @@ | |||
199 | 190 | tree = template.process_to_parsetree(notebook, page) # No linker ! | 191 | tree = template.process_to_parsetree(notebook, page) # No linker ! |
200 | 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') |
201 | 192 | 193 | ||
203 | 193 | 194 | class TestTemplatePageMenu(tests.TestCase): | |
204 | 195 | def runTest(self): | ||
205 | 196 | # menu(root, collapse, ignore_empty) | ||
206 | 197 | data = ( | ||
207 | 198 | # Test default settings | ||
208 | 199 | (u"[% menu() %]", '''\ | ||
209 | 200 | <ul> | ||
210 | 201 | <li><a href="page://Parent" title="Parent">Parent</a></li> | ||
211 | 202 | <ul> | ||
212 | 203 | <li><strong>Daughter</strong></li> | ||
213 | 204 | <ul> | ||
214 | 205 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
215 | 206 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
216 | 207 | </ul> | ||
217 | 208 | <li><a href="page://Parent:Son" title="Son">Son</a></li> | ||
218 | 209 | </ul> | ||
219 | 210 | <li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> | ||
220 | 211 | <li><a href="page://TODOList" title="TODOList">TODOList</a></li> | ||
221 | 212 | <li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> | ||
222 | 213 | </ul> | ||
223 | 214 | '''), | ||
224 | 215 | # Collapsing turned off | ||
225 | 216 | (u"[% menu(':', FALSE, TRUE) %]", '''\ | ||
226 | 217 | <ul> | ||
227 | 218 | <li><a href="page://Parent" title="Parent">Parent</a></li> | ||
228 | 219 | <ul> | ||
229 | 220 | <li><strong>Daughter</strong></li> | ||
230 | 221 | <ul> | ||
231 | 222 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
232 | 223 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
233 | 224 | </ul> | ||
234 | 225 | <li><a href="page://Parent:Son" title="Son">Son</a></li> | ||
235 | 226 | <ul> | ||
236 | 227 | <li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
237 | 228 | <li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> | ||
238 | 229 | </ul> | ||
239 | 230 | </ul> | ||
240 | 231 | <li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> | ||
241 | 232 | <li><a href="page://TODOList" title="TODOList">TODOList</a></li> | ||
242 | 233 | <ul> | ||
243 | 234 | <li><a href="page://TODOList:bar" title="bar">bar</a></li> | ||
244 | 235 | <li><a href="page://TODOList:foo" title="foo">foo</a></li> | ||
245 | 236 | </ul> | ||
246 | 237 | <li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> | ||
247 | 238 | <ul> | ||
248 | 239 | <li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li> | ||
249 | 240 | <li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li> | ||
250 | 241 | </ul> | ||
251 | 242 | </ul> | ||
252 | 243 | '''), | ||
253 | 244 | # Empty pages are not ignored | ||
254 | 245 | (u"[% menu(':', TRUE, FALSE) %]", '''\ | ||
255 | 246 | <ul> | ||
256 | 247 | <li><a href="page://Bar" title="Bar">Bar</a></li> | ||
257 | 248 | <li><a href="page://foo" title="foo">foo</a></li> | ||
258 | 249 | <li><a href="page://Linking" title="Linking">Linking</a></li> | ||
259 | 250 | <li><a href="page://Parent" title="Parent">Parent</a></li> | ||
260 | 251 | <ul> | ||
261 | 252 | <li><a href="page://Parent:Child" title="Child">Child</a></li> | ||
262 | 253 | <li><strong>Daughter</strong></li> | ||
263 | 254 | <ul> | ||
264 | 255 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
265 | 256 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
266 | 257 | <li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> | ||
267 | 258 | </ul> | ||
268 | 259 | <li><a href="page://Parent:Son" title="Son">Son</a></li> | ||
269 | 260 | </ul> | ||
270 | 261 | <li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> | ||
271 | 262 | <li><a href="page://Test" title="Test">Test</a></li> | ||
272 | 263 | <li><a href="page://TODOList" title="TODOList">TODOList</a></li> | ||
273 | 264 | <li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> | ||
274 | 265 | <li><a href="page://utf8" title="utf8">utf8</a></li> | ||
275 | 266 | </ul> | ||
276 | 267 | '''), | ||
277 | 268 | # Both | ||
278 | 269 | (u"[% menu(':', FALSE, FALSE) %]", '''\ | ||
279 | 270 | <ul> | ||
280 | 271 | <li><a href="page://Bar" title="Bar">Bar</a></li> | ||
281 | 272 | <li><a href="page://foo" title="foo">foo</a></li> | ||
282 | 273 | <ul> | ||
283 | 274 | <li><a href="page://foo:bar" title="bar">bar</a></li> | ||
284 | 275 | </ul> | ||
285 | 276 | <li><a href="page://Linking" title="Linking">Linking</a></li> | ||
286 | 277 | <ul> | ||
287 | 278 | <li><a href="page://Linking:Dus" title="Dus">Dus</a></li> | ||
288 | 279 | <ul> | ||
289 | 280 | <li><a href="page://Linking:Dus:Ja" title="Ja">Ja</a></li> | ||
290 | 281 | </ul> | ||
291 | 282 | <li><a href="page://Linking:Foo" title="Foo">Foo</a></li> | ||
292 | 283 | <ul> | ||
293 | 284 | <li><a href="page://Linking:Foo:Bar" title="Bar">Bar</a></li> | ||
294 | 285 | <ul> | ||
295 | 286 | <li><a href="page://Linking:Foo:Bar:Baz" title="Baz">Baz</a></li> | ||
296 | 287 | </ul> | ||
297 | 288 | </ul> | ||
298 | 289 | </ul> | ||
299 | 290 | <li><a href="page://Parent" title="Parent">Parent</a></li> | ||
300 | 291 | <ul> | ||
301 | 292 | <li><a href="page://Parent:Child" title="Child">Child</a></li> | ||
302 | 293 | <ul> | ||
303 | 294 | <li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li> | ||
304 | 295 | </ul> | ||
305 | 296 | <li><strong>Daughter</strong></li> | ||
306 | 297 | <ul> | ||
307 | 298 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
308 | 299 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
309 | 300 | <li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> | ||
310 | 301 | <ul> | ||
311 | 302 | <li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> | ||
312 | 303 | <li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> | ||
313 | 304 | </ul> | ||
314 | 305 | </ul> | ||
315 | 306 | <li><a href="page://Parent:Son" title="Son">Son</a></li> | ||
316 | 307 | <ul> | ||
317 | 308 | <li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
318 | 309 | <li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> | ||
319 | 310 | </ul> | ||
320 | 311 | </ul> | ||
321 | 312 | <li><a href="page://roundtrip" title="roundtrip">roundtrip</a></li> | ||
322 | 313 | <li><a href="page://Test" title="Test">Test</a></li> | ||
323 | 314 | <ul> | ||
324 | 315 | <li><a href="page://Test:foo" title="foo">foo</a></li> | ||
325 | 316 | <ul> | ||
326 | 317 | <li><a href="page://Test:foo:bar" title="bar">bar</a></li> | ||
327 | 318 | </ul> | ||
328 | 319 | <li><a href="page://Test:Foo Bar" title="Foo Bar">Foo Bar</a></li> | ||
329 | 320 | <ul> | ||
330 | 321 | <li><a href="page://Test:Foo Bar:Dus Ja Hmm" title="Dus Ja Hmm">Dus Ja Hmm</a></li> | ||
331 | 322 | </ul> | ||
332 | 323 | <li><a href="page://Test:tags" title="tags">tags</a></li> | ||
333 | 324 | <li><a href="page://Test:wiki" title="wiki">wiki</a></li> | ||
334 | 325 | </ul> | ||
335 | 326 | <li><a href="page://TODOList" title="TODOList">TODOList</a></li> | ||
336 | 327 | <ul> | ||
337 | 328 | <li><a href="page://TODOList:bar" title="bar">bar</a></li> | ||
338 | 329 | <li><a href="page://TODOList:foo" title="foo">foo</a></li> | ||
339 | 330 | </ul> | ||
340 | 331 | <li><a href="page://TrashMe" title="TrashMe">TrashMe</a></li> | ||
341 | 332 | <ul> | ||
342 | 333 | <li><a href="page://TrashMe:sub page 1" title="sub page 1">sub page 1</a></li> | ||
343 | 334 | <li><a href="page://TrashMe:sub page 2" title="sub page 2">sub page 2</a></li> | ||
344 | 335 | </ul> | ||
345 | 336 | <li><a href="page://utf8" title="utf8">utf8</a></li> | ||
346 | 337 | <ul> | ||
347 | 338 | <li><a href="page://utf8:αβγ" title="αβγ">αβγ</a></li> | ||
348 | 339 | <li><a href="page://utf8:בדיקה" title="בדיקה">בדיקה</a></li> | ||
349 | 340 | <ul> | ||
350 | 341 | <li><a href="page://utf8:בדיקה:טכניון" title="טכניון">טכניון</a></li> | ||
351 | 342 | <ul> | ||
352 | 343 | <li><a href="page://utf8:בדיקה:טכניון:הנדסת מכונות" title="הנדסת מכונות">הנדסת מכונות</a></li> | ||
353 | 344 | <li><a href="page://utf8:בדיקה:טכניון:מדעי המחשב" title="מדעי המחשב">מדעי המחשב</a></li> | ||
354 | 345 | </ul> | ||
355 | 346 | </ul> | ||
356 | 347 | <li><a href="page://utf8:中文" title="中文">中文</a></li> | ||
357 | 348 | </ul> | ||
358 | 349 | </ul> | ||
359 | 350 | '''), | ||
360 | 351 | # Let's chenge the root | ||
361 | 352 | (u"[% menu(page, FALSE) %]", '''\ | ||
362 | 353 | <ul> | ||
363 | 354 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
364 | 355 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
365 | 356 | </ul> | ||
366 | 357 | '''), | ||
367 | 358 | (u"[% menu(page.name, FALSE, FALSE) %]", '''\ | ||
368 | 359 | <ul> | ||
369 | 360 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
370 | 361 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
371 | 362 | <li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> | ||
372 | 363 | <ul> | ||
373 | 364 | <li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> | ||
374 | 365 | <li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> | ||
375 | 366 | </ul> | ||
376 | 367 | </ul> | ||
377 | 368 | '''), | ||
378 | 369 | (u"[% menu(page.namespace, FALSE, FALSE) %]", '''\ | ||
379 | 370 | <ul> | ||
380 | 371 | <li><a href="page://Parent:Child" title="Child">Child</a></li> | ||
381 | 372 | <ul> | ||
382 | 373 | <li><a href="page://Parent:Child:Grandchild" title="Grandchild">Grandchild</a></li> | ||
383 | 374 | </ul> | ||
384 | 375 | <li><strong>Daughter</strong></li> | ||
385 | 376 | <ul> | ||
386 | 377 | <li><a href="page://Parent:Daughter:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
387 | 378 | <li><a href="page://Parent:Daughter:Grandson" title="Grandson">Grandson</a></li> | ||
388 | 379 | <li><a href="page://Parent:Daughter:SomeOne" title="SomeOne">SomeOne</a></li> | ||
389 | 380 | <ul> | ||
390 | 381 | <li><a href="page://Parent:Daughter:SomeOne:Bar" title="Bar">Bar</a></li> | ||
391 | 382 | <li><a href="page://Parent:Daughter:SomeOne:Foo" title="Foo">Foo</a></li> | ||
392 | 383 | </ul> | ||
393 | 384 | </ul> | ||
394 | 385 | <li><a href="page://Parent:Son" title="Son">Son</a></li> | ||
395 | 386 | <ul> | ||
396 | 387 | <li><a href="page://Parent:Son:Granddaughter" title="Granddaughter">Granddaughter</a></li> | ||
397 | 388 | <li><a href="page://Parent:Son:Grandson" title="Grandson">Grandson</a></li> | ||
398 | 389 | </ul> | ||
399 | 390 | </ul> | ||
400 | 391 | '''), | ||
401 | 392 | ) | ||
402 | 393 | |||
403 | 394 | notebook = notebook = tests.new_notebook() | ||
404 | 395 | page = notebook.get_page(Path(':Parent:Daughter')) | ||
405 | 396 | for input, wantedresult in data: | ||
406 | 397 | result = Template(input, 'html', linker=StubLinker()).process(notebook, page) | ||
407 | 398 | self.assertEqual(result, wantedresult.splitlines(True)) | ||
408 | 399 | |||
409 | 400 | |||
410 | 194 | 401 | ||
411 | 195 | class StubLinker(object): | 402 | class StubLinker(object): |
412 | 196 | 403 | ||
413 | 197 | 404 | ||
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 | 12 | word_re = Re(r''' | 12 | word_re = Re(r''' |
419 | 13 | ( '(\\'|[^'])*' | # single quoted word | 13 | ( '(\\'|[^'])*' | # single quoted word |
420 | 14 | "(\\"|[^"])*" | # double quoted word | 14 | "(\\"|[^"])*" | # double quoted word |
422 | 15 | \S+ # word without spaces | 15 | [^\s,]+ | # word without spaces and commas |
423 | 16 | , # comma | ||
424 | 16 | )''', re.X) | 17 | )''', re.X) |
425 | 17 | string = string.strip() | 18 | string = string.strip() |
426 | 18 | words = [] | 19 | words = [] |
427 | 19 | 20 | ||
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 | 71 | from zim.fs import File | 71 | from zim.fs import File |
433 | 72 | from zim.config import data_dirs | 72 | from zim.config import data_dirs |
434 | 73 | from zim.parsing import Re, TextBuffer, split_quoted_strings, unescape_quoted_string, is_path_re | 73 | from zim.parsing import Re, TextBuffer, split_quoted_strings, unescape_quoted_string, is_path_re |
436 | 74 | from zim.formats import ParseTree, Element | 74 | from zim.formats import ParseTree, Element, TreeBuilder |
437 | 75 | from zim.index import LINK_DIR_BACKWARD | 75 | from zim.index import LINK_DIR_BACKWARD |
438 | 76 | from zim.notebook import Path | ||
439 | 76 | 77 | ||
440 | 77 | logger = logging.getLogger('zim.templates') | 78 | logger = logging.getLogger('zim.templates') |
441 | 78 | 79 | ||
442 | @@ -198,7 +199,6 @@ | |||
443 | 198 | ''' | 199 | ''' |
444 | 199 | if not isinstance(dict, TemplateDict): | 200 | if not isinstance(dict, TemplateDict): |
445 | 200 | dict = TemplateDict(dict) | 201 | dict = TemplateDict(dict) |
446 | 201 | |||
447 | 202 | output = TextBuffer(self.tokens.process(dict)) | 202 | output = TextBuffer(self.tokens.process(dict)) |
448 | 203 | return output.get_lines() | 203 | return output.get_lines() |
449 | 204 | 204 | ||
450 | @@ -334,7 +334,11 @@ | |||
451 | 334 | 'pages': pages, | 334 | 'pages': pages, |
452 | 335 | 'strftime': StrftimeFunction(), | 335 | 'strftime': StrftimeFunction(), |
453 | 336 | 'url': TemplateFunction(self.url), | 336 | 'url': TemplateFunction(self.url), |
455 | 337 | 'options': options | 337 | 'options': options, |
456 | 338 | 'notebook': {'name' : notebook.name}, | ||
457 | 339 | 'menu' : MenuFunction(notebook, page, self.format, self.linker, options), | ||
458 | 340 | # helpers that allow to write TRUE instead of 'TRUE' in template functions | ||
459 | 341 | 'TRUE' : 'True', 'FALSE' : 'False', | ||
460 | 338 | } | 342 | } |
461 | 339 | 343 | ||
462 | 340 | if self.linker: | 344 | if self.linker: |
463 | @@ -625,6 +629,109 @@ | |||
464 | 625 | else: | 629 | else: |
465 | 626 | raise AssertionError, 'Not a datetime object: %s', date | 630 | raise AssertionError, 'Not a datetime object: %s', date |
466 | 627 | 631 | ||
467 | 632 | class MenuFunction(TemplateFunction): | ||
468 | 633 | '''Template function wrapper for strftime''' | ||
469 | 634 | |||
470 | 635 | def __init__(self, notebook, page, format, linker, options): | ||
471 | 636 | self._notebook = notebook | ||
472 | 637 | self._page = page | ||
473 | 638 | self._format = format | ||
474 | 639 | self._linker = linker | ||
475 | 640 | self._options = options | ||
476 | 641 | |||
477 | 642 | |||
478 | 643 | def __call__(self, dict, root=':', collapse=True, ignore_empty=True): | ||
479 | 644 | builder = TreeBuilder() | ||
480 | 645 | level = self._page.name.count(':') | ||
481 | 646 | home = Path(self._notebook.config['Notebook']['home']) | ||
482 | 647 | |||
483 | 648 | # TODO: Some logic to parse boolean template function params | ||
484 | 649 | if isinstance(collapse, (TemplateParam, TemplateLiteral, basestring)): | ||
485 | 650 | collapse = (str(collapse).strip().lower() == 'true') | ||
486 | 651 | if isinstance(ignore_empty, (TemplateParam, TemplateLiteral, basestring)): | ||
487 | 652 | ignore_empty = (str(ignore_empty).strip().lower() == 'true') | ||
488 | 653 | |||
489 | 654 | # [% menu(page) %] vs [% menu(page.name) %] | ||
490 | 655 | if isinstance(root, PageProxy): root = root.name | ||
491 | 656 | #~ print "!!! ROOT, ", root | ||
492 | 657 | |||
493 | 658 | def add_namespace(path): | ||
494 | 659 | mylevel = path.name.count(':') | ||
495 | 660 | |||
496 | 661 | if collapse: | ||
497 | 662 | # Menu doesn't show whole tree, but only pages related to the current page. | ||
498 | 663 | if mylevel > level: | ||
499 | 664 | # "path" is more nested then the current page | ||
500 | 665 | return | ||
501 | 666 | elif level == mylevel: | ||
502 | 667 | # "path" has same level as current page | ||
503 | 668 | if not self._page.name == path.name and path.name: | ||
504 | 669 | # Show only children of the current page or namespace pages | ||
505 | 670 | return | ||
506 | 671 | elif not self._page.name.startswith(path.name): | ||
507 | 672 | # "path" is less nested, show only children of the ancestors | ||
508 | 673 | # of the current page | ||
509 | 674 | return | ||
510 | 675 | |||
511 | 676 | #~ print "!!! path & level", path, mylevel | ||
512 | 677 | pagelist = list(self._notebook.index.list_pages(path)) | ||
513 | 678 | # find home page | ||
514 | 679 | for page in pagelist: | ||
515 | 680 | if page.name == home.name: | ||
516 | 681 | home_page = page | ||
517 | 682 | break | ||
518 | 683 | else: | ||
519 | 684 | # home page not in list | ||
520 | 685 | home_page = None | ||
521 | 686 | |||
522 | 687 | # home page will be first item | ||
523 | 688 | if not home_page is None: | ||
524 | 689 | pagelist.remove(home_page) | ||
525 | 690 | pagelist.insert(0, home_page) | ||
526 | 691 | |||
527 | 692 | builder.start('ul') | ||
528 | 693 | for page in pagelist: | ||
529 | 694 | if ignore_empty and not page.hascontent: | ||
530 | 695 | #~ print "!!! skip page", page | ||
531 | 696 | continue | ||
532 | 697 | builder.start('li') | ||
533 | 698 | text = page.basename | ||
534 | 699 | |||
535 | 700 | if self._page.name == page.name: | ||
536 | 701 | # Current page is marked with the strong style | ||
537 | 702 | builder.start('strong') | ||
538 | 703 | builder.data(text) | ||
539 | 704 | builder.end('strong') | ||
540 | 705 | else: | ||
541 | 706 | # links to other pages | ||
542 | 707 | builder.start('link', {'type': 'page', 'href': page.name}) | ||
543 | 708 | builder.data(text) | ||
544 | 709 | builder.end('link') | ||
545 | 710 | builder.end('li') | ||
546 | 711 | if page.haschildren: | ||
547 | 712 | add_namespace(page) # recurs | ||
548 | 713 | builder.end('ul') | ||
549 | 714 | |||
550 | 715 | builder.start('page') | ||
551 | 716 | add_namespace(Path(root)) | ||
552 | 717 | builder.end('page') | ||
553 | 718 | |||
554 | 719 | tree = ParseTree(builder.close()) | ||
555 | 720 | if not tree: | ||
556 | 721 | return None | ||
557 | 722 | |||
558 | 723 | #~ print "!!!", tree.tostring() | ||
559 | 724 | |||
560 | 725 | format = self._format | ||
561 | 726 | linker = self._linker | ||
562 | 727 | if linker: | ||
563 | 728 | linker.set_path(self._page) | ||
564 | 729 | |||
565 | 730 | dumper = format.Dumper( | ||
566 | 731 | linker=linker, | ||
567 | 732 | template_options=self._options ) | ||
568 | 733 | |||
569 | 734 | return ''.join(dumper.dump(tree)) | ||
570 | 628 | 735 | ||
571 | 629 | class TemplateDict(object): | 736 | class TemplateDict(object): |
572 | 630 | '''Object behaving like a dict for storing values of template parameters. | 737 | '''Object behaving like a dict for storing values of template parameters. |
573 | @@ -751,7 +858,7 @@ | |||
574 | 751 | for link in blinks: | 858 | for link in blinks: |
575 | 752 | source = self._notebook.get_page(link.source) | 859 | source = self._notebook.get_page(link.source) |
576 | 753 | yield PageProxy(self._notebook, source, self._format, self._linker, self._options) | 860 | yield PageProxy(self._notebook, source, self._format, self._linker, self._options) |
578 | 754 | 861 | ||
579 | 755 | 862 | ||
580 | 756 | class ParseTreeProxy(object): | 863 | class ParseTreeProxy(object): |
581 | 757 | 864 |
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.