[albatross-users] Our first custom tag

Gregory Bond gnb at itga.com.au
Mon Nov 11 11:11:53 EST 2002


We have an informal in-house style that says alternating rows of table data 
should have different background colors, so that it is easy to keep track of 
which row is which.  This is done by alternating the "class" attribute of each 
"<tr>" tag.  (Most of our existing intranet is built with HTMLgen, which is 
kind-of "inside-out" compared to Albatross, in that it is a program to 
generate HTML, rather than an HTML file containing program-like elements.  
Things like alternating class attributes is easy to do in this style of 
system.)

In trying to use Albatross, I wound up doing lots of code like
	<al-if expr="i.index() % 2">
		<tr>
	<al-else>
		<tr class="alt">
	</al-if>

Not only is this ugly to look at and a lot to type, it really messes with the
head of the HTML editor (I use xemacs) and buggers the indentation.

So we wrote an extension tag <alx-tr> to hide all this nastyness.  I include 
it here in case anyone else finds it interesting.

[To the Albatross team: Feel free to make this part of the official
distribution.  This might also make a good case study in custom tags for the
manual!]



#! /usr/local/bin/python
'''
A collection of useful custom tag classes for use with the albatross library.

To make these available, simply pass the class object to the
register_tagclasses() member of the application object.

E.g.:

	import itgatags

	....
	class MyApp(SimpleApp):
	    def __init__(self):
		SimpleApp.__init__(self,......)
		for page_class in (.......):
		    self .register_page(page_class.name, page_class())
		for tag_class in (itgatags.TR,):
		    self .register_tagclasses(tag_class)



'''

from albatross.tags import ExprAttrMixin
from albatross import EnclosingTag

class TR(EnclosingTag, ExprAttrMixin):
    '''
    <alx-tr expr="..." classes="alt1,alt2,alt3"> ... </alx-tr>

    Similar to <tr>, except that it evaluates expr (which must be an
    integer) and then chooses a "class=" attribute for the <tr> tag
    from those listed in the "classes" arg by taking "<expr> % <# of
    classes>".  <expr> is often "i.index()" where i is an iterator
    created by <al-for>.

    This is useful for having rows of the table with alternating or
    successive styles.  Elements of the "classes" list may be empty
    (i.e. "alt1,") or the empty string ("alt1,'',alt2") which will
    produce a <tr> without a "class=" attribute.

    "classes" may be omitted and defaults to ",alt" (i.e. alternating
    normal and "class=alt" styles.  Naturally, you will need some sort
    of stylesheet definitions for these classes.

    Example:
    <table>
     <al-for iter="i" expr="...">
      <alx-tr expr="i.index()" classes=",alt1,,alt2">
       <td><al-value expr="i.value().name">.......</td>
      </alx-tr>
     </al-for>
    </table>
    This will produce a table where the odd rows are normal, but the
    2nd and 4th rows have special class (and hence presumably special
    formatting).
    
    <alx-tr counter="name" classes="'',alt1,alt2"> ... </alx-tr>

    Similar to the above, but instead of evaluating an expression,
    this uses a counter with the given name in the ctx.locals space
    (creating it with the value 0 if necessary).  The counter will be
    incremented after it is used.  This is useful if a single table
    contains rows from multiple <al-for> tags, or summary lines at the
    bottom, or similar.  It can also count the number of rows for you!

    Example:
    <table>
     <al-for iter="i" expr="...">
      <alx-tr name="row">
       <td><al-value expr="i.value().name">.......</td>
      </alx-tr>
     </al-for>
     <alx-tr name="row">
      <td>TOTAL:........</dt>
     <alx-tr>
    </table>
    <al-value expr="row"> Rows Added.
    
    Using a counter rather than the iterator.index() method ensures
    that the TOTAL row has the appropriate and consistant class
    attribute.
    
    '''
    name = 'alx-tr'

    def __init__(self, ctx, filename, line_num, attribs):
        EnclosingTag.__init__(self, ctx, filename, line_num, attribs)
        if self.has_attrib('expr'):
            self.compile_expr()
	    self.counter = ''
	elif self.has_attrib('counter'):
	    self.counter = self.get_attrib('counter')
	else:
            self.raise_error('missing "counter" or "expr" attribute')
	if self.has_attrib('classes'):
	    cs = self.get_attrib('classes')
	    self.classes = []
	    for c in cs.split(','):
		if c == "''" or c == '""':
		    c = ''
		self.classes.append(c)
	else:
	    self.classes = ['', 'alt']
	    
    def to_html(self, ctx):
	if self.counter:
	    if ctx.has_value(self.counter):
		val = ctx.get_value(self.counter)
	    else:
		val = 0
	else:				# expr
	    val = int(ctx.eval_expr(self.expr))

	cls = self.classes[val % len(self.classes)]
	if cls:
	    ctx.write_content('<tr class="%s">' % cls)
	else:
	    ctx.write_content('<tr>')

	self.content.to_html(ctx)
	ctx.write_content('</tr>\n')

	if self.counter:
	    ctx.set_value(self.counter, val + 1)







More information about the Albatross-users mailing list