Attachment 'text_html.py.diff'
Download 1 --- MoinMoin/formatter/text_html.py.orig 2005-12-04 07:37:54.000000000 -0500
2 +++ MoinMoin/formatter/text_html.py 2006-01-12 14:47:02.000000000 -0500
3 @@ -67,35 +67,144 @@
4 # lang is inherited from content div
5 return {}
6
7 - attr = {'lang': lang, 'dir': i18n.getDirection(lang),}
8 + attr = {'xml:lang': lang, 'lang': lang, 'dir': i18n.getDirection(lang),}
9 return attr
10
11 - def formatAttributes(self, attr=None):
12 - """ Return formatted attributes string
13 + # These are all the (X)HTML attributes that can be on any element,
14 + # excluding lang, xml:lang, and class -- because they are handled
15 + # as special cases.
16 + _common_attrs = ['accesskey','dir','disabled','id','style','tabindex','title','xmlns']
17 +
18 + def formatAttributes(self, attr=None, allowed_attrs=None, **kw):
19 + """ Return HTML attributes formatted as a single string.
20
21 @param attr: dict containing keys and values
22 - @rtype: string ?
23 + @param allowed_attrs: A list of allowable attribute names
24 + @param **kw: other arbitrary attributes expressed as keyword arguments.
25 + @rtype: string
26 @return: formated attributes or empty string
27 +
28 + If a list of keyword arguments is provided, you should use
29 + '__' (double underscore) in place of a ':' (such as
30 + "xml__lang" in place of "xml:lang". Also use "content_type"
31 + instead of "type".
32 +
33 + You can optionally use "html__" as a prefix to any standard
34 + HTML attribute which you want ignored with other non-HTML
35 + formatters, or to avoid Python keyword (like "for").
36 +
37 + As special cases use "content_type" for "type",
38 + "http_equiv" for "http-equiv", and "z_index" for "z-index".
39 +
40 + Setting a keyword to None rather than a string (or string
41 + coercible) value will remove that attribute from the list.
42 +
43 + If the list of allowed_attrs is provided, then an error is
44 + raised if an attribute is encountered that is not in that list
45 + (or is not a common attribute which is always allowed or is
46 + not in another XML namespace using the double-underscore
47 + syntax).
48 """
49 - if attr:
50 - attr = [' %s="%s"' % (k, v) for k, v in attr.items()]
51 + if attr is None:
52 + attr = {}
53 + # Handle special cases in passed-in attribute dict
54 + for old, new in [('content_type','type'), ('http_equiv','http-equiv'),
55 + ('z_index','z-index')]:
56 + if attr.has_key(old):
57 + attr[new] = attr[old]
58 + del attr[old]
59 +
60 + if attr.has_key('css_class'):
61 + attr['class'] = attr['css_class']
62 + del attr['css_class']
63 +
64 + # Parse the keyword argument list
65 + for kwname, val in kw.items():
66 + kwname.replace('__',':')
67 + if kwname[:5]=='html:':
68 + kwname = kwname[5:] # Strip off "html:" prefix
69 +
70 + if kwname[:2]=='on' and len(kwname)>2:
71 + # Event handlers such as onclick, allow all of them,
72 + # and convert to lowercase as the standard says.
73 + kwname = kwname.lower()
74 + elif kwname=='content_type':
75 + # Special case because 'type' is used for other purposes
76 + kwname = 'type'
77 + elif kwname=='http_equiv': # Special case because of hyphen
78 + kwname = 'http-equiv'
79 + elif kwname=='z_index': # Special case because of hyphen
80 + kwname = 'z-index'
81 + elif kwname in ('class','css','css_class'):
82 + # Append all css classes together rather than replace.
83 + # Accept "css" and "css_class" for backwards compatibility in this wiki.
84 + if attr.has_key('class'):
85 + attr['class'] = '%s %s' % (attr['class'], val)
86 + else:
87 + attr['class'] = val
88 + continue
89 + elif kwname=='style':
90 + # Append styles together rather than replace
91 + if attr.has_key('style'):
92 + attr['style'] = '%s; %s' % (attr['style'],val)
93 + else:
94 + attr['style'] = val
95 + continue
96 + elif kwname=='lang' or kwname=='xml:lang':
97 + # Make lang and xml:lang always the same and both present
98 + attr['lang'] = val
99 + attr['xml:lang'] = val
100 + continue
101 + elif kwname in self._common_attrs:
102 + pass
103 + elif ':' in kwname:
104 + # Allow all xml namespace-qualified attributes
105 + pass
106 + elif not allowed_attrs or kwname in allowed_attrs:
107 + pass
108 + else:
109 + # Unknown attribute
110 + e='Illegal HTML attribute "%s" passed to formatter' % kwname
111 + raise ValueError(e)
112 +
113 + if val is None:
114 + del attr[kwname]
115 + else:
116 + attr[kwname] = val
117 +
118 + if attr.has_key('alt') and not attr.has_key('title'):
119 + # Force title attribute if also has an alt
120 + attr['title'] = attr['alt']
121 +
122 + if attr.has_key('lang') and not attr.has_key('xml:lang'):
123 + attr['xml:lang'] = attr['lang']
124 +
125 + if len(attr) > 0:
126 + attr = [' %s="%s"' % (k, wikiutil.escape(v,1))
127 + for k, v in attr.items() if v]
128 return ''.join(attr)
129 return ''
130
131 # TODO: use set when we require Python 2.3
132 # TODO: The list is not complete, add missing from dtd
133 - _blocks = 'p div pre table tr td ol ul dl li dt dd h1 h2 h3 h4 h5 h6 hr form'
134 + _blocks = 'p div pre table tbody thead tfoot tr th td ol ul dl li dt dd h1 h2 h3 h4 h5 h6 hr form'
135 _blocks = dict(zip(_blocks.split(), [1] * len(_blocks)))
136 + _self_closing_tags = ['base','br','frame','hr','img','input','isindex','link','meta','param']
137
138 - def open(self, tag, newline=False, attr=None):
139 + def open(self, tag, newline=False, attr=None, allowed_attrs=None, **kw):
140 """ Open a tag with optional attributes
141
142 @param tag: html tag, string
143 - @param newline: render tag on a separate line
144 - @parm attr: dict with tag attributes
145 + @param newline: render tag so following data is on a separate line
146 + @param attr: dict with tag attributes
147 + @param allowed_attrs: list of allowed attributes for this element
148 + @param kw: arbitrary attributes and values
149 @rtype: string ?
150 - @return: open tag with attributes
151 + @return: open tag with attributes as a string
152 """
153 + self_close=''
154 + if tag in self._self_closing_tags:
155 + self_close=' /'
156 if tag in self._blocks:
157 # Block elements
158 result = []
159 @@ -106,25 +215,33 @@
160 attributes.update(attr)
161
162 # Format
163 - attributes = self.formatAttributes(attributes)
164 - result.append('<%s%s>' % (tag, attributes))
165 + attributes = self.formatAttributes(attributes, allowed_attrs=allowed_attrs, **kw)
166 + result.append('<%s%s%s>' % (tag, attributes, self_close))
167 if newline:
168 result.append('\n')
169 return ''.join(result)
170 else:
171 # Inline elements
172 # Add to inlineStack
173 - self._inlineStack.append(tag)
174 + if not self_close:
175 + # Only push on stack if we expect a close-tag later
176 + self._inlineStack.append(tag)
177 # Format
178 - return '<%s%s>' % (tag, self.formatAttributes(attr))
179 -
180 + return '<%s%s%s>' % (tag,
181 + self.formatAttributes(attr, allowed_attrs, **kw),
182 + self_close)
183 +
184 def close(self, tag, newline=False):
185 """ Close tag
186
187 @param tag: html tag, string
188 - @rtype: string ?
189 - @return: closing tag
190 + @param newline: render tag so following data is on a separate line
191 + @rtype: string
192 + @return: closing tag as a string
193 """
194 + if tag in self._self_closing_tags:
195 + # This tag was already closed
196 + return ''
197 if tag in self._blocks:
198 # Block elements
199 # Close all tags in inline stack
200 @@ -137,7 +254,9 @@
201 # Format with newline
202 if newline:
203 result.append('\n')
204 - result.append('</%s>\n' % (tag))
205 + result.append('</%s>' % (tag))
206 + if newline:
207 + result.append('\n')
208 return ''.join(result)
209 else:
210 # Inline elements
211 @@ -150,7 +269,7 @@
212
213 # Public methods ###################################################
214
215 - def startContent(self, content_id='content', **kwargs):
216 + def startContent(self, content_id='content', newline=True, **kw):
217 """ Start page content div """
218
219 # Setup id
220 @@ -163,11 +282,12 @@
221 # Use the content language
222 attr = self.langAttr(self.request.content_lang)
223 attr['id'] = content_id
224 - result.append(self.open('div', newline=1, attr=attr))
225 + result.append(self.open('div', newline=newline, attr=attr,
226 + allowed_attrs=['align'], **kw))
227 result.append(self.anchordef(aid))
228 return ''.join(result)
229
230 - def endContent(self):
231 + def endContent(self,newline=True):
232 """ Close page content div """
233
234 # Setup id
235 @@ -182,7 +302,7 @@
236
237 result = []
238 result.append(self.anchordef(aid))
239 - result.append(self.close('div', newline=1))
240 + result.append(self.close('div', newline=newline))
241 return ''.join(result)
242
243 def lang(self, on, lang_name):
244 @@ -205,7 +325,7 @@
245 def sysmsg(self, on, **kw):
246 tag = 'div'
247 if on:
248 - return self.open(tag, attr={'class': 'message'})
249 + return self.open(tag, attr={'class': 'message'}, **kw)
250 return self.close(tag)
251
252 # Links ##############################################################
253 @@ -259,41 +379,95 @@
254 # unescaped=1 was changed to 0 to make interwiki links with pages with umlauts (or other non-ascii) work
255
256 def url(self, on, url=None, css=None, **kw):
257 - """
258 + """ Inserts an <a> element.
259 +
260 + Call once with on=1 to start the link, and again with on=0
261 + to end it (no other arguments are needed when on==0).
262 +
263 Keyword params:
264 - title - <a> title attribute
265 - attrs - just include those <a> attrs "as is"
266 + url - the URL to link to; will go through Wiki URL mapping.
267 + type - icon type: one of "www" or "mailto" to use that icon
268 + css - a space-separated list of CSS classes
269 + attrs - just include this string verbatim inside
270 + the <a> element; can be used for arbitrary attrs
271 """
272 + if not on:
273 + return self.close('a')
274 + attrs = self.langAttr()
275 +
276 + # Handle the URL mapping
277 + if url is None and kw.has_key('href'):
278 + url = kw['href']
279 + del kw['href']
280 if url is not None:
281 url = wikiutil.mapURL(self.request, url)
282 - title = kw.get('title', None)
283 - attrs = kw.get('attrs', None)
284 + attrs['href'] = url
285 +
286 + if css:
287 + attrs['class'] = css
288 +
289 + if kw.has_key('type'): # Icon type
290 + icon_type = kw['type']
291 + del kw['type']
292 + else:
293 + icon_type = None
294 +
295 + if kw.has_key('attrs'):
296 + # for backwards compatibility, raw pre-formated attribute string
297 + extra_attrs = kw['attrs']
298 + del kw['attrs']
299 + else:
300 + extra_attrs = None
301 +
302 + # create link
303 if on:
304 - str = '<a'
305 - if css:
306 - str = '%s class="%s"' % (str, css)
307 - if title:
308 - str = '%s title="%s"' % (str, title)
309 - if attrs:
310 - str = '%s %s' % (str, attrs)
311 - str = '%s href="%s">' % (str, wikiutil.escape(url, 1))
312 + str = self.open('a', attr=attrs, **kw)
313 + if extra_attrs:
314 + # insert this into the tag (messy)
315 + if str[-2:]=='/>':
316 + str = '%s %s />' % (str[:-2], extra_attrs)
317 + else:
318 + str = '%s %s>' % (str[:-1], extra_attrs)
319 else:
320 - str = '</a>'
321 + str = self.close('a')
322 +
323 + if icon_type=='www':
324 + str = '%s%s ' % (str, self.icon("www"))
325 + elif icon_type=='mailto':
326 + str = '%s%s ' % (str, self.icon('mailto'))
327 return str
328
329 def anchordef(self, id):
330 - #return '<a id="%s"></a>' % (id, ) # this breaks PRE sections for IE
331 - # do not add a \n here, it breaks pre sections with line_anchordef
332 - return '<span id="%s" class="anchor"></span>' % (id, )
333 + """Inserts an element with an id attribute, used as an anchor
334 + for link references.
335 + """
336 + return '<span id="%s" class="anchor"></span>' % wikiutil.escape(id, 1)
337
338 def line_anchordef(self, lineno):
339 return self.anchordef("line-%d" % lineno)
340
341 - def anchorlink(self, on, name='', id=None):
342 - extra = ''
343 - if id:
344 - extra = ' id="%s"' % id
345 - return ['<a href="#%s"%s>' % (name, extra), '</a>'][not on]
346 + def anchorlink(self, on, name='', **kw):
347 + """Inserts an <a> link pointing to an anchor within the same
348 + document. Call once with on=1 to start the link, and a
349 + second time with on=0 to end it. No other arguments are
350 + needed on the second call.
351 +
352 + The name argument should be the same as the id provided to the
353 + anchordef() method, or some other elment. The id argument, if
354 + provided, is instead the id of this link itself and not of the
355 + element the link references.
356 + """
357 +
358 + attrs = self.langAttr()
359 + if name:
360 + attrs['href'] = '#%s' % name
361 + if kw.has_key('href'):
362 + del kw['href']
363 + if on:
364 + str = self.open('a', attr=attrs, **kw)
365 + else:
366 + str = self.close('a')
367 + return str
368
369 def line_anchorlink(self, on, lineno=0):
370 return self.anchorlink(on, name="line-%d" % lineno)
371 @@ -415,46 +589,55 @@
372
373 # Inline ###########################################################
374
375 - def strong(self, on):
376 + def strong(self, on, **kw):
377 + """Creates an HTML <strong> element.
378 +
379 + Call once with on=1 to start the region, and a second time
380 + with on=0 to end it.
381 +
382 + Any other keyword argument represents other standard HTML
383 + attributes of the <strong> element. Use an "xml_" prefix
384 + for the keyword in place of "xml:" (such as xml_lang="en").
385 + """
386 tag = 'strong'
387 if on:
388 - return self.open(tag)
389 + return self.open(tag, allowed_attrs=[], **kw)
390 return self.close(tag)
391
392 - def emphasis(self, on):
393 + def emphasis(self, on, **kw):
394 tag = 'em'
395 if on:
396 - return self.open(tag)
397 + return self.open(tag, allowed_attrs=[], **kw)
398 return self.close(tag)
399
400 - def underline(self, on):
401 + def underline(self, on, **kw):
402 tag = 'span'
403 if on:
404 - return self.open(tag, attr={'class': 'u'})
405 + return self.open(tag, attr={'class': 'u'}, allowed_attrs=[], **kw)
406 return self.close(tag)
407
408 - def highlight(self, on):
409 + def highlight(self, on, **kw):
410 tag = 'strong'
411 if on:
412 - return self.open(tag, attr={'class': 'highlight'})
413 + return self.open(tag, attr={'class': 'highlight'}, allowed_attrs=[], **kw)
414 return self.close(tag)
415
416 - def sup(self, on):
417 + def sup(self, on, **kw):
418 tag = 'sup'
419 if on:
420 - return self.open(tag)
421 + return self.open(tag, allowed_attrs=[], **kw)
422 return self.close(tag)
423
424 - def sub(self, on):
425 + def sub(self, on, **kw):
426 tag = 'sub'
427 if on:
428 - return self.open(tag)
429 + return self.open(tag, allowed_attrs=[], **kw)
430 return self.close(tag)
431
432 - def strike(self, on):
433 + def strike(self, on, **kw):
434 tag = 'strike'
435 if on:
436 - return self.open(tag)
437 + return self.open(tag, allowed_attrs=[], **kw)
438 return self.close(tag)
439
440 def code(self, on, **kw):
441 @@ -462,34 +645,34 @@
442 # Maybe we don't need this, because we have tt will be in inlineStack.
443 self._in_code = on
444 if on:
445 - return self.open(tag)
446 + return self.open(tag, allowed_attrs=[], **kw)
447 return self.close(tag)
448
449 - def small(self, on):
450 + def small(self, on, **kw):
451 tag = 'small'
452 if on:
453 - return self.open(tag)
454 + return self.open(tag, allowed_attrs=[], **kw)
455 return self.close(tag)
456
457 - def big(self, on):
458 + def big(self, on, **kw):
459 tag = 'big'
460 if on:
461 - return self.open(tag)
462 + return self.open(tag, allowed_attrs=[], **kw)
463 return self.close(tag)
464
465
466 # Block elements ####################################################
467
468 - def preformatted(self, on, attr=None):
469 + def preformatted(self, on, **kw):
470 FormatterBase.preformatted(self, on)
471 tag = 'pre'
472 if on:
473 - return self.open(tag, newline=1, attr=attr)
474 + return self.open(tag, newline=1, **kw)
475 return self.close(tag)
476
477 # Use by code area
478 _toggleLineNumbersScript = """
479 -<script type="text/JavaScript">
480 +<script type="text/javascript">
481 function isnumbered(obj) {
482 return obj.childNodes.length && obj.firstChild.childNodes.length && obj.firstChild.firstChild.className == 'LineNumber';
483 }
484 @@ -562,7 +745,7 @@
485 if self._code_area_state[1] >= 0:
486 toggleLineNumbersLink = r'''
487 <script type="text/javascript">
488 -document.write('<a href="#" onClick="return togglenumber(\'%s\', %d, %d);" \
489 +document.write('<a href="#" onclick="return togglenumber(\'%s\', %d, %d);" \
490 class="codenumbers">Toggle line numbers<\/a>');
491 </script>
492 ''' % (self._code_area_state[0], self._code_area_state[2], self._code_area_state[3])
493 @@ -605,9 +788,9 @@
494 def linebreak(self, preformatted=1):
495 if self._in_code_area:
496 preformatted = 1
497 - return ['\n', '<br>\n'][not preformatted]
498 + return ['\n', '<br />\n'][not preformatted]
499
500 - def paragraph(self, on):
501 + def paragraph(self, on, **kw):
502 if self._terse:
503 return ''
504 FormatterBase.paragraph(self, on)
505 @@ -615,14 +798,14 @@
506 self._in_li = self._in_li + 1
507 tag = 'p'
508 if on:
509 - return self.open(tag)
510 - return self.close(tag)
511 + return self.open(tag,**kw)
512 + return self.close(tag) + '\n'
513
514 - def rule(self, size=None):
515 + def rule(self, size=None, **kw):
516 if size:
517 # Add hr class: hr1 - hr6
518 - return self.open('hr', newline=1, attr={'class': 'hr%d' % size})
519 - return self.open('hr', newline=1)
520 + return self.open('hr', newline=1, attr={'class': 'hr%d' % size}, **kw)
521 + return self.open('hr', newline=1, **kw)
522
523 def icon(self, type):
524 return self.request.theme.make_icon(type)
525 @@ -634,9 +817,20 @@
526 href = self.request.theme.img_url(img)
527 return self.image(src=href, alt=text, width=str(w), height=str(h))
528
529 + def image(self, src=None, **kw):
530 + if src:
531 + kw['src']=src
532 + return self.open('img',**kw)
533 +
534 # Lists ##############################################################
535
536 - def number_list(self, on, type=None, start=None):
537 + _list_stack=[]
538 + def _indent_list(self):
539 + if not self._list_stack:
540 + return ''
541 + return '\n' + ' '*len(self._list_stack)
542 +
543 + def number_list(self, on, type=None, start=None, **kw):
544 tag = 'ol'
545 if on:
546 attr = {}
547 @@ -644,49 +838,52 @@
548 attr['type'] = type
549 if start is not None:
550 attr['start'] = start
551 - return self.open(tag, newline=1, attr=attr)
552 - return self.close(tag)
553 + tagstr = self.open(tag, newline=0, attr=attr, **kw)
554 + self._list_stack.append(tag)
555 + return self._indent_list() + tagstr + '\n'
556 + else:
557 + self._list_stack.pop()
558 + tagstr = self.close(tag)
559 + return self._indent_list() + tagstr
560
561 - def bullet_list(self, on):
562 + def bullet_list(self, on, **kw):
563 tag = 'ul'
564 if on:
565 - return self.open(tag, newline=1)
566 - return self.close(tag)
567 + tagstr = self.open(tag, newline=0, **kw)
568 + self._list_stack.append(tag)
569 + return self._indent_list() + tagstr + '\n'
570 + else:
571 + self._list_stack.pop()
572 + tagstr = self.close(tag)
573 + return self._indent_list() + tagstr
574
575 def listitem(self, on, **kw):
576 """ List item inherit its lang from the list. """
577 tag = 'li'
578 self._in_li = on != 0
579 if on:
580 - attr = {}
581 - css_class = kw.get('css_class', None)
582 - if css_class:
583 - attr['class'] = css_class
584 - style = kw.get('style', None)
585 - if style:
586 - attr['style'] = style
587 - return self.open(tag, attr=attr)
588 - return self.close(tag)
589 + return ' ' + self.open(tag, **kw)
590 + return self.close(tag) + '\n'
591
592 - def definition_list(self, on):
593 + def definition_list(self, on, **kw):
594 tag = 'dl'
595 if on:
596 - return self.open(tag, newline=1)
597 + return self.open(tag, newline=1, **kw)
598 return self.close(tag)
599
600 - def definition_term(self, on):
601 + def definition_term(self, on, **kw):
602 tag = 'dt'
603 if on:
604 - return self.open(tag)
605 - return self.close(tag)
606 + return self.open(tag, **kw)
607 + return self.close(tag) + '\n'
608
609 - def definition_desc(self, on):
610 + def definition_desc(self, on, **kw):
611 tag = 'dd'
612 if on:
613 - return self.open(tag)
614 - return self.close(tag)
615 + return ' ' + self.open(tag, **kw)
616 + return self.close(tag) + '\n'
617
618 - def heading(self, on, depth, id = None, **kw):
619 + def heading(self, on, depth, **kw):
620 # remember depth of first heading, and adapt counting depth accordingly
621 if not self._base_depth:
622 self._base_depth = depth
623 @@ -722,11 +919,8 @@
624 number = '.'.join(map(str, self.request._fmt_hd_counters[self._show_section_numbers-1:]))
625 if number: number += ". "
626
627 - attr = {}
628 - if id:
629 - attr['id'] = id
630 # Add space before heading, easier to check source code
631 - result = '\n' + self.open('h%d' % heading_depth, attr=attr)
632 + result = '\n' + self.open('h%d' % heading_depth, **kw)
633
634 # TODO: convert this to readable code
635 if self.request.user.show_topbottom:
636 @@ -795,7 +989,7 @@
637 return result
638
639
640 - def table(self, on, attrs=None):
641 + def table(self, on, attrs=None, **kw):
642 """ Create table
643
644 @param on: start table
645 @@ -814,36 +1008,53 @@
646 attrs = {}
647 else:
648 attrs = self._checkTableAttr(attrs, 'table')
649 - result.append(self.open('table', newline=1, attr=attrs))
650 + result.append(self.open('table', newline=1, attr=attrs,
651 + allowed_attrs=self._allowed_table_attrs['table'],
652 + **kw))
653 + result.append(self.open('tbody', newline=1))
654 else:
655 - # Close table then div
656 + # Close tbody, table, and then div
657 + result.append(self.close('tbody'))
658 result.append(self.close('table'))
659 result.append(self.close('div'))
660
661 return ''.join(result)
662
663 - def table_row(self, on, attrs=None):
664 + def table_row(self, on, attrs=None, **kw):
665 tag = 'tr'
666 if on:
667 if not attrs:
668 attrs = {}
669 else:
670 attrs = self._checkTableAttr(attrs, 'row')
671 - return self.open(tag, newline=1, attr=attrs)
672 - return self.close(tag)
673 + return self.open(tag, newline=1, attr=attrs,
674 + allowed_attrs=self._allowed_table_attrs['row'],
675 + **kw)
676 + return self.close(tag) + '\n'
677
678 - def table_cell(self, on, attrs=None):
679 + def table_cell(self, on, attrs=None, **kw):
680 tag = 'td'
681 if on:
682 if not attrs:
683 attrs = {}
684 else:
685 attrs = self._checkTableAttr(attrs, '')
686 - return self.open(tag, newline=1, attr=attrs)
687 - return self.close(tag)
688 -
689 - def escapedText(self, text):
690 - return wikiutil.escape(text)
691 + return ' ' + self.open(tag, attr=attrs,
692 + allowed_attrs=self._allowed_table_attrs[''],
693 + **kw)
694 + return self.close(tag) + '\n'
695 +
696 + def text(self, text, **kw):
697 + txt = FormatterBase.text( self, text, **kw )
698 + if len(kw)>0:
699 + return self.open('span',**kw) + txt + self.close('span')
700 + return txt
701 +
702 + def escapedText(self, text, **kw):
703 + txt = wikiutil.escape(text)
704 + if len(kw)>0:
705 + return self.open('span',**kw) + txt + self.close('span')
706 + return txt
707
708 def rawHTML(self, markup):
709 return markup
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.