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.
  • [get | view] (2006-01-12 20:03:22, 4.3 KB) [[attachment:base.py.diff]]
  • [get | view] (2006-01-12 20:03:35, 4.0 KB) [[attachment:dom_xml.py.diff]]
  • [get | view] (2006-01-19 20:12:28, 67.9 KB) [[attachment:formatter-patch-r4.diff]]
  • [get | view] (2006-01-16 20:11:38, 58.7 KB) [[attachment:formatter-patch.diff]]
  • [get | view] (2006-01-12 20:03:43, 2.0 KB) [[attachment:text_gedit.py.diff]]
  • [get | view] (2006-01-12 20:03:51, 25.7 KB) [[attachment:text_html.py.diff]]
  • [get | view] (2006-01-12 20:03:58, 3.7 KB) [[attachment:text_plain.py.diff]]
  • [get | view] (2006-01-12 20:04:06, 4.0 KB) [[attachment:text_xml.py.diff]]
  • [get | view] (2006-01-12 20:04:11, 5.1 KB) [[attachment:xml_docbook.py.diff]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.