1 """
2 MoinMoin - Modified Include macro
3
4 This macro includes the formatted content of the given page(s). See
5
6 http://purl.net/wiki/moinmaster/HelpOnMacros/Include
7
8 for detailed docs.
9
10 @copyright: 2011 Eric Thrift
11 2000-2004 Juergen Hermann <jh@web.de>,
12 2000-2001 Richard Jones <richard@bizarsoftware.com.au>
13 @license: GNU GPL, see COPYING for details.
14 """
15 def _getParent(pagename):
16 """ Return parent of pagename.
17 """
18 pos = pagename.rfind('/')
19 if pos >= 0:
20 return pagename[:pos]
21 return None
22
23 Dependencies = ["time"]
24
25 generates_headings = True
26
27 import re, StringIO, string, time
28 from MoinMoin import wikiutil, action
29 from MoinMoin.Page import Page
30 from MoinMoin.action import AttachFile
31
32 _sysmsg = '<p><strong class="%s">%s</strong></p>'
33
34
35 _arg_heading = r'(?P<heading>,)\s*(|(?P<hquote>[\'"])(?P<htext>.+?)(?P=hquote))'
36 _arg_level = r',\s*(?P<level>\d*)'
37 _arg_from = r'(,\s*from=(?P<fquote>[\'"])(?P<from>.+?)(?P=fquote))?'
38 _arg_to = r'(,\s*to=(?P<tquote>[\'"])(?P<to>.+?)(?P=tquote))?'
39 _arg_sort = r'(,\s*sort=(?P<sort>(ascending|descending)))?'
40 _arg_items = r'(,\s*items=(?P<items>\d+))?'
41 _arg_skipitems = r'(,\s*skipitems=(?P<skipitems>\d+))?'
42 _arg_titlesonly = r'(,\s*(?P<titlesonly>titlesonly))?'
43 _arg_editlink = r'(,\s*(?P<editlink>editlink))?'
44 _args_re_pattern = r'^(?P<name>[^,]+)(%s(%s)?%s%s%s%s%s%s%s)?$' % (
45 _arg_heading, _arg_level, _arg_from, _arg_to, _arg_sort, _arg_items,
46 _arg_skipitems, _arg_titlesonly, _arg_editlink)
47
48 _title_re = r"^(?P<heading>\s*(?P<hmarker>=+)\s.*\s(?P=hmarker))$"
49
50
51 def extract_titles(body, title_re):
52 titles = []
53 for title, _ in title_re.findall(body):
54 h = title.strip()
55 level = 1
56 while h[level:level+1] == '=':
57 level += 1
58 title_text = h[level:-level].strip()
59 titles.append((title_text, level))
60 return titles
61
62 def execute(macro, text, args_re=re.compile(_args_re_pattern), title_re=re.compile(_title_re, re.M)):
63 request = macro.request
64 _ = request.getText
65
66 if request.mode_getpagelinks:
67 return ''
68
69
70 args = text and args_re.match(text)
71 if not args:
72 return (_sysmsg % ('error', _('Invalid include arguments "%s"!')) % (text, ))
73
74
75 result = []
76 print_mode = request.action in ("print", "format")
77 this_page = macro.formatter.page
78 if not hasattr(this_page, '_macroInclude_pagelist'):
79 this_page._macroInclude_pagelist = {}
80
81
82 inc_name = wikiutil.AbsPageName(this_page.page_name, args.group('name'))
83 pagelist = [inc_name]
84 if inc_name.startswith("^"):
85 try:
86 inc_match = re.compile(inc_name)
87 except re.error:
88 pass
89 else:
90
91 pagelist = request.rootpage.getPageList(filter=inc_match.match)
92 count = len(pagelist)
93
94
95 pagelist.sort()
96 sort_dir = args.group('sort')
97 if sort_dir == 'descending':
98 pagelist.reverse()
99
100 max_items = 40
101 maxvar = args.group("items")
102
103
104 total = int(count)
105
106
107 if maxvar:
108 max_items = int(maxvar)
109
110 skipitems = 0
111 if args.group("skipitems"):
112 skipitems = int(args.group("skipitems"))
113
114 cur_item = 0
115
116
117 m_skipitems = skipitems
118 enditem = (m_skipitems + max_items)
119 if enditem > int(count):
120 enditem = int(count)
121 startitem = (m_skipitems + 1)
122 if int(count) == 0:
123 result.append(_("<b>There are no comments yet on this topic!</b>"))
124 else:
125 result.append(_("<b>Showing comments %s - %s of %s</b>") % (str(startitem), str(enditem), str(count)))
126
127 titlesonly = args.group('titlesonly')
128 editlink = args.group('editlink')
129 result.append('<table class="forum">')
130
131
132 for inc_name in pagelist:
133 cur_item += 1
134 if not request.user.may.read(inc_name):
135 continue
136 if inc_name in this_page._macroInclude_pagelist:
137 result.append(u'<p><strong class="error">Recursive include of "%s" forbidden</strong></p>' % (inc_name, ))
138 continue
139 if skipitems:
140 skipitems -= 1
141 continue
142 if cur_item > enditem:
143 continue
144 fmt = macro.formatter.__class__(request, is_included=True)
145 fmt._base_depth = macro.formatter._base_depth
146 inc_page = Page(request, inc_name, formatter=fmt)
147 if not inc_page.exists():
148 continue
149 inc_page._macroInclude_pagelist = this_page._macroInclude_pagelist
150
151
152 body = inc_page.get_raw_body() + '\n'
153 from_pos = 0
154 to_pos = -1
155 from_re = args.group('from')
156 if from_re:
157 try:
158 from_match = re.compile(from_re, re.M).search(body)
159 except re.error:
160
161 from_match = re.compile(re.escape(from_re), re.M).search(body)
162 if from_match:
163 from_pos = from_match.end()
164 else:
165 result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % from_re)
166 to_re = args.group('to')
167 if to_re:
168 try:
169 to_match = re.compile(to_re, re.M).search(body, from_pos)
170 except re.error:
171 to_match = re.compile(re.escape(to_re), re.M).search(body, from_pos)
172 if to_match:
173 to_pos = to_match.start()
174 else:
175 result.append(_sysmsg % ('warning', 'Include: ' + _('Nothing found for "%s"!')) % to_re)
176
177 if titlesonly:
178 levelstack = []
179 for title, level in extract_titles(body[from_pos:to_pos], title_re):
180 if levelstack:
181 if level > levelstack[-1]:
182 result.append(macro.formatter.bullet_list(1))
183 levelstack.append(level)
184 else:
185 while levelstack and level < levelstack[-1]:
186 result.append(macro.formatter.bullet_list(0))
187 levelstack.pop()
188 if not levelstack or level != levelstack[-1]:
189 result.append(macro.formatter.bullet_list(1))
190 levelstack.append(level)
191 else:
192 result.append(macro.formatter.bullet_list(1))
193 levelstack.append(level)
194 result.append(macro.formatter.listitem(1))
195 result.append(inc_page.link_to(request, title))
196 result.append(macro.formatter.listitem(0))
197 while levelstack:
198 result.append(macro.formatter.bullet_list(0))
199 levelstack.pop()
200 continue
201
202 if from_pos or to_pos != -1:
203 inc_page.set_raw_body(body[from_pos:to_pos], modified=True)
204
205
206
207 if not hasattr(request, "_Include_backto"):
208 request._Include_backto = this_page.page_name
209
210
211 level = None
212 if args.group('heading') and args.group('hquote'):
213 heading = args.group('htext') or inc_page.split_title()
214 level = 1
215 if args.group('level'):
216 level = int(args.group('level'))
217 if print_mode:
218 result.append(macro.formatter.heading(1, level) +
219 macro.formatter.text(heading) +
220 macro.formatter.heading(0, level))
221 else:
222 url = inc_page.url(request)
223 result.extend([
224 macro.formatter.heading(1, level, id=heading),
225 macro.formatter.url(1, url, css="include-heading-link"),
226 macro.formatter.text(heading),
227 macro.formatter.url(0),
228 macro.formatter.heading(0, level),
229 ])
230
231
232 this_page._macroInclude_pagelist[inc_name] = \
233 this_page._macroInclude_pagelist.get(inc_name, 0) + 1
234
235
236
237 m = re.match(r".*/[C]([0-9]*)(([^@]*)@([^@]*))", inc_page.page_name)
238 post_timestamp = float(int(m.group(1)))
239 post_timestamp = time.localtime(post_timestamp)
240 post_time = time.strftime("%c", post_timestamp)
241 post_editor = m.group(2)
242 post_editor_name = m.group(3)
243 post_editor_location = m.group(4)
244
245 '''
246 # This doesn't work with synchronization since edit log data are lost
247
248 info = inc_page.lastEditInfo()
249 info2 = inc_page.edit_info()
250
251 editor = string.split(info2['editor'], ":")
252 editor = editor[-1]
253
254 if editor == "localhost":
255 editor = "AnonymousUser"
256 '''
257 avatarurl = AttachFile.getAttachUrl(post_editor, "avatar.jpg", request)
258
259 result.append('<tr><td class="forumposterinfo">')
260 result.append('<img src="%s" alt="%s" class="avatar">' % (
261 wikiutil.escape(avatarurl, 1),
262 wikiutil.escape("", 1)))
263 result.append('<span class="editor"><a href="')
264 result.append(post_editor)
265 result.append('">')
266 result.append(post_editor_name)
267 result.append(" @ ")
268 result.append(post_editor_location)
269 result.append("</a></span>")
270 result.append(post_time)
271 result.append("<br>")
272 result.append(inc_page.link_to(request, '[%s]' % (_('permalink'), ), css_class="include-page-link"))
273
274
275
276 result.append("</td><td>")
277
278
279
280
281
282
283 strfile = StringIO.StringIO()
284 request.redirect(strfile)
285 try:
286 inc_page.send_page(content_only=True,
287 omit_footnotes=True,
288 count_hit=False)
289 result.append(strfile.getvalue())
290 result.append("</td></tr>")
291 finally:
292 request.redirect()
293
294
295 if this_page._macroInclude_pagelist[inc_name] > 1:
296 this_page._macroInclude_pagelist[inc_name] = \
297 this_page._macroInclude_pagelist[inc_name] - 1
298 else:
299 del this_page._macroInclude_pagelist[inc_name]
300
301
302 result.append("</table>")
303 prevskip = (m_skipitems - max_items)
304 if prevskip < 1:
305 prevskip = 0
306 if m_skipitems > 0:
307
308
309 result.append(
310 this_page.link_to(request, '< %s' % (_('Previous'), ), css_class="prev-link", querystr={'action': 'supplementation', 'skipitems': prevskip, 'items': max_items}),
311 )
312 result.append(" ")
313
314 if enditem < int(count):
315 result.append(
316 this_page.link_to(request, '%s >' % (_('Next'), ), css_class="next-link", querystr={'action': 'supplementation', 'skipitems': enditem, 'items': max_items} )
317
318 )
319
320
321
322
323
324 return ''.join(result)
325
326