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. 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 breaks 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.

   1 '''
   2 A collection of useful custom tag classes for use with the albatross library.
   3 
   4 To make these available, simply pass the class object to the
   5 register_tagclasses() member of the application object.
   6 
   7 E.g.:
   8 
   9         import itgatags
  10 
  11         ....
  12         class MyApp(SimpleApp):
  13             def __init__(self):
  14                 SimpleApp.__init__(self,......)
  15                 for page_class in (.......):
  16                     self .register_page(page_class.name, page_class())
  17                 for tag_class in (itgatags.TR,):
  18                     self .register_tagclasses(tag_class)
  19 
  20 
  21 
  22 '''
  23 
  24 from albatross.tags import ExprAttrMixin
  25 from albatross import EnclosingTag
  26 
  27 class TR(EnclosingTag, ExprAttrMixin):
  28     '''
  29     <alx-tr expr="..." classes="alt1,alt2,alt3"> ... </alx-tr>
  30 
  31     Similar to <tr>, except that it evaluates expr (which must be an
  32     integer) and then chooses a "class=" attribute for the <tr> tag
  33     from those listed in the "classes" arg by taking "<expr> % <# of
  34     classes>".  <expr> is often "i.index()" where i is an iterator
  35     created by <al-for>.
  36 
  37     This is useful for having rows of the table with alternating or
  38     successive styles.  Elements of the "classes" list may be empty
  39     (i.e. "alt1,") or the empty string ("alt1,'',alt2") which will
  40     produce a <tr> without a "class=" attribute.
  41 
  42     "classes" may be omitted and defaults to ",alt" (i.e. alternating
  43     normal and "class=alt" styles.  Naturally, you will need some sort
  44     of stylesheet definitions for these classes.
  45 
  46     Example:
  47     <table>
  48      <al-for iter="i" expr="...">
  49       <alx-tr expr="i.index()" classes=",alt1,,alt2">
  50        <td><al-value expr="i.value().name">.......</td>
  51       </alx-tr>
  52      </al-for>
  53     </table>
  54     This will produce a table where the odd rows are normal, but the
  55     2nd and 4th rows have special class (and hence presumably special
  56     formatting).
  57     
  58     <alx-tr counter="name" classes="'',alt1,alt2"> ... </alx-tr>
  59 
  60     Similar to the above, but instead of evaluating an expression,
  61     this uses a counter with the given name in the ctx.locals space
  62     (creating it with the value 0 if necessary).  The counter will be
  63     incremented after it is used.  This is useful if a single table
  64     contains rows from multiple <al-for> tags, or summary lines at the
  65     bottom, or similar.  It can also count the number of rows for you!
  66 
  67     Example:
  68     <table>
  69      <al-for iter="i" expr="...">
  70       <alx-tr counter="row">
  71        <td><al-value expr="i.value().name">.......</td>
  72       </alx-tr>
  73      </al-for>
  74      <alx-tr counter="row">
  75       <td>TOTAL:........</dt>
  76      <alx-tr>
  77     </table>
  78     <al-value expr="row"> Rows Added.
  79     
  80     Using a counter rather than the iterator.index() method ensures
  81     that the TOTAL row has the appropriate and consistant class
  82     attribute.
  83     
  84     '''
  85     name = 'alx-tr'
  86 
  87     def __init__(self, ctx, filename, line_num, attribs):
  88         EnclosingTag.__init__(self, ctx, filename, line_num, attribs)
  89         if self.has_attrib('expr'):
  90             self.compile_expr()
  91             self.counter = ''
  92         elif self.has_attrib('counter'):
  93             self.counter = self.get_attrib('counter')
  94         else:
  95             self.raise_error('missing "counter" or "expr" attribute')
  96         if self.has_attrib('classes'):
  97             cs = self.get_attrib('classes')
  98             self.classes = []
  99             for c in cs.split(','):
 100                 if c == "''" or c == '""':
 101                     c = ''
 102                 self.classes.append(c)
 103         else:
 104             self.classes = ['', 'alt']
 105 
 106     def to_html(self, ctx):
 107         if self.counter:
 108             if ctx.has_value(self.counter):
 109                 val = ctx.get_value(self.counter)
 110             else:
 111                 val = 0
 112         else:                           # expr
 113             val = int(ctx.eval_expr(self.expr))
 114 
 115         cls = self.classes[val % len(self.classes)]
 116         if cls:
 117             ctx.write_content('<tr class="%s">' % cls)
 118         else:
 119             ctx.write_content('<tr>')
 120 
 121         self.content.to_html(ctx)
 122         ctx.write_content('</tr>\n')
 123 
 124         if self.counter:
 125             ctx.set_value(self.counter, val + 1)


Nice. Another approach, although not as simple to read as the custom tag, uses the standard <al-lookup>.

<al-lookup name="classes">
  <al-item expr="0">class1</al-item>
  <al-item expr="1">class2</al-item>
</al-lookup>
 
<table>
  <al-for iter="iter" expr="a_list">
    <tr class="<al-value expr="iter.index()%2" lookup="classes"/>">
      <td><al-value expr="i.value()"/></td>
    </tr>
  </al-for>
</table>

<al-lookup> may be better under some circumstances since it doesn't mess around with the HTML and doesn't assume that you always want to set the class (sometimes you might want to change the 'style' attribute).

-- Matt