Tables.js



  • When I saw tables.js in source control of a project i'm working on i knew that a WTF was going to come out of it.
    I was hoping for a nice javascript WTF that printed out some tables dynamically or something. I found something much more Brilant though, beleive it or not with tables.js it is possible to have tables with alternating colours (or stripey tables as they call it) without writing a single line of CSS or bgcolor attribute.
    Yes, beleive or not, this 70 line javascript can prevent you writing around 10 characters of HTML. I espeacially like the optional variable called requiredStripeClass. Get it while it's hot:

    <!--
     onload = function() { stripeAll ('stripe') };

     var requiredStripeClass = 'stripe'; //optional variable, defining the class which is required to "stripe" a table. If empty or null, all tables will be "striped"
    var evenColor = '#ffffff';
    var oddColor = '#edf3fe';
     
      // this function is needed to work around
      // a bug in IE related to element attributes
      function hasClass(obj) {
         var result = false;
         if (obj.getAttributeNode("class") != null) {
             result = obj.getAttributeNode("class").value;
         }
         return result;
      }  
      function stripeObj(obj) {
        var even = false;
     
        // if arguments are provided to specify the colours
        // of the even &amp; odd rows, then use the them;
        // otherwise use the following defaults:
        var evenColor = arguments[1] ? arguments[1] : "#ffffff";
        var oddColor = arguments[2] ? arguments[2] : "#edf3fe";
     
        var table = obj;
        if (! table) { return; }
       
        var tbodies = table.getElementsByTagName("tbody");
       
        for (var h = 0; h < tbodies.length; h++) {
          var trs = tbodies[h].getElementsByTagName("tr");
          for (var i = 0; i < trs.length; i++) {
            // avoid rows that have a class attribute
            // or backgroundColor style
            if (! hasClass(trs[i]) &&
                ! trs[i].style.backgroundColor) {
              var tds = trs[i].getElementsByTagName("td");
              for (var j = 0; j < tds.length; j++) {
                var mytd = tds[j];
                // avoid cells that have a class attribute
                // or backgroundColor style
                if (! hasClass(mytd) &&
                    ! mytd.style.backgroundColor) {
                  mytd.style.backgroundColor =
                    even ? evenColor : oddColor;
                }
              }
            }
            even =  ! even;
          }
        }
      }
    function stripeAll(){ //stripe all tables, OR all tables containing the "requiredStripeClass" class
        tList = document.getElementsByTagName('table');
        var t;
        if((typeof evenColor == 'undefined'))
            evenColor = null;
        if((typeof oddColor == 'undefined'))
            oddColor = null;
        for(var x = 0; x < tList.length; x++){
            t = tList[x];
            if((typeof requiredStripeClass != 'undefined') && (requiredStripeClass != null) && (requiredStripeClass != '')){
                if(hasClass(t) == requiredStripeClass)
                    stripeObj(t, evenColor, oddColor);
            }
            else
                stripeObj(t, evenColor, oddColor);
        }
    }

    Brillant!



  • @alias said:

    When I saw tables.js in source control of a project i'm working on i knew that a WTF was going to come out of it.
    I was hoping for a nice javascript WTF that printed out some tables dynamically or something. I found something much more Brilant though, beleive it or not with tables.js it is possible to have tables with alternating colours (or stripey tables as they call it) without writing a single line of CSS or bgcolor attribute.
    Yes, beleive or not, this 70 line javascript can prevent you writing around 10 characters of HTML. I espeacially like the optional variable called requiredStripeClass. Get it while it's hot:

    <!--
     onload = function() { stripeAll ('stripe') };

     var requiredStripeClass = 'stripe'; //optional variable, defining the class which is required to "stripe" a table. If empty or null, all tables will be "striped"
    var evenColor = '#ffffff';
    var oddColor = '#edf3fe';
     
      // this function is needed to work around
      // a bug in IE related to element attributes
      function hasClass(obj) {
         var result = false;
         if (obj.getAttributeNode("class") != null) {
             result = obj.getAttributeNode("class").value;
         }
         return result;
      }  
      function stripeObj(obj) {
        var even = false;
     
        // if arguments are provided to specify the colours
        // of the even &amp; odd rows, then use the them;
        // otherwise use the following defaults:
        var evenColor = arguments[1] ? arguments[1] : "#ffffff";
        var oddColor = arguments[2] ? arguments[2] : "#edf3fe";
     
        var table = obj;
        if (! table) { return; }
       
        var tbodies = table.getElementsByTagName("tbody");
       
        for (var h = 0; h < tbodies.length; h++) {
          var trs = tbodies[h].getElementsByTagName("tr");
          for (var i = 0; i < trs.length; i++) {
            // avoid rows that have a class attribute
            // or backgroundColor style
            if (! hasClass(trs[i]) &&
                ! trs[i].style.backgroundColor) {
              var tds = trs[i].getElementsByTagName("td");
              for (var j = 0; j < tds.length; j++) {
                var mytd = tds[j];
                // avoid cells that have a class attribute
                // or backgroundColor style
                if (! hasClass(mytd) &&
                    ! mytd.style.backgroundColor) {
                  mytd.style.backgroundColor =
                    even ? evenColor : oddColor;
                }
              }
            }
            even =  ! even;
          }
        }
      }
    function stripeAll(){ //stripe all tables, OR all tables containing the "requiredStripeClass" class
        tList = document.getElementsByTagName('table');
        var t;
        if((typeof evenColor == 'undefined'))
            evenColor = null;
        if((typeof oddColor == 'undefined'))
            oddColor = null;
        for(var x = 0; x < tList.length; x++){
            t = tList[x];
            if((typeof requiredStripeClass != 'undefined') && (requiredStripeClass != null) && (requiredStripeClass != '')){
                if(hasClass(t) == requiredStripeClass)
                    stripeObj(t, evenColor, oddColor);
            }
            else
                stripeObj(t, evenColor, oddColor);
        }
    }

    Brillant!

    This script comes from A List Apart, you can read the ALA article on Zebra Tables by David F. Miller to have more informations about it.

    I usually add classes to my tables though, instead of adding the colors inline, and as a result I have much less checks to make aka much smaller scripts.



  • I don't understand the objection to this script. If you're not using JavaScript to apply stripes to tables that have a given CSS class applied to them, then how else could you do it?

    If the site is outputting blocks of HTML which were manually inputted by an author, then the author has to manually apply colors to alternating rows of the table, which makes future editing virtually impossible. If the site is parsing some other format and outputting HTML, it still has to make a special case for data tables and have funky server-side code to write alternating background colors. Either way, it results in messy HTML being sent to the client.

    Having Javascript on the client side find selected tables and stripe them seems to make a lot more sense. And it fails gracefully. Is there some other way to do it that we're missing? A CSS-only solution?

    Addendum: Don't reassign document.onload the way this script does. If you have many scripts that try to do this, they clobber each other. Instead, look at how prototype.js registers event handlers and do something similar.



  • I agree; aside from maybe-possibly-overengineering, there's no WTF.  If you're not doing serverside code, there's no other way to do this, and even if you are doing serverside code, you would have to put in extra code for each table that you want to change the alternating colors for.  With this .js, all you have to do is add a class onto the table.

    # of lines of code or whatnot isn't really an issue, since it's not like you're writing or debugging it.  Do you prefer to write your own SMTP mail sender in 50 lines of code instead of using one built into the framework that's undoubtedly thousands of lines of code?



  • @alias said:

    Yes, beleive or not, this 70 line javascript can prevent you writing around 10 characters of HTML. I espeacially like the optional variable called requiredStripeClass. Get it while it's hot:

    As someone who knows only very basic HTML, and little more about web pages, how would one go about alternating table colors in 10 characters?



  • OK so the intent of it isn't too much of a wtf, but check these gems out...

    @alias said:


     onload = function() { stripeAll ('stripe') };
    ...
    function stripeAll(){


    Clearly the code went through a few alterations, and someone didn't spot the obvious...

    @alias said:

      // this function is needed to work around
      // a bug in IE related to element attributes


    Yes... IE can have null nodes and null attributes, I wouldn't call it a bug...

    @alias said:

      function hasClass(obj) {
    ....
             result = obj.getAttributeNode("class").value;


    ...great name for a function... I'm thinking of calling my file-opening function 'isFileNotFound()'



    dashdashspace



  • How to do this in the future when all modern browsers know CSS3:

    http://www.w3.org/TR/2001/CR-css3-selectors-20011113/#structural-pseudos


    ... now that would be a cool thing to have right now. No more strange javascript hacks.



  • Good ol' CSS3.


    Too bad we won't be able to use any of it until 2009. Browsers, see. Maybe Opera.



  • @Brendan Kidwell said:

    I don't understand the objection to this script. If you're not using JavaScript to apply stripes to tables that have a given CSS class applied to them, then how else could you do it?

    An HTML element can have multiple classes.

    @versatilia said:
    @alias said:

      function hasClass(obj) {
    ....
             result = obj.getAttributeNode("class").value;


    ...great name for a function...

    Uh what? This function is called hasClass because it checks if the object has a "class" attribute, this is javascript so "null", "false" or "0" are all considered false in a boolean context while everything else is "true" e.g., if "result" is null then "hasClass" will be considered false in a boolean context while it will be considered true if a node or value is returned.

    And the bug in MSIE is that Internet Explorer generates empty attributes (attributes with a null value, really) for every single standard attribute defined on nodes. Other browsers just don't define the attribute in the first place.

    The result is that while you can just check if the attribute exists in other browsers MSIE requires you to check the attribute's value.



  • @masklinn said:

    @Brendan Kidwell said:
    I don't understand the objection to this script. If you're not using JavaScript to apply stripes to tables that have a given CSS class applied to them, then how else could you do it?

    An HTML element can have multiple classes.

    Uhm, what? Either you don't understand my comment or I don't understand yours.

    Yes, an HTML element can have multiple classes.

    Either you need apply different classes to alternating rows of a table, and they are picked up by selectors that set colors, OR you need to use Javascript to set those alternating classes for children of a (table.Striped) at render time. I think we all agree that these two ideas and CSS3 are the only ways. I'm saying that that Javascript is the only way that doesn't suck.




  • I think that javascript sucks slightly more than just adding the classes, whether the HTML is generated via ASP/PHP/etc or manually written via copy&paste.

    There are true usability benefits to striping a table, and I've come to rarely photoshop-design a table of much data without that striping, so I consider it a kind of basic design practice.

    I prefer if that functionality is provided via robust CSS, rather than JS.


    That said, I did use JS once to take the crappy auto-generated HTML output of a thirdparty data-mangler program, and format it slightly, and then, hee hee hee, "scroll" the table's rows one by one, moving the top row to the bottom every couple seconds.


Log in to reply