| 
     
  
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html> 
  <head> 
    <title>Table Sorter Proof of Concept</title> 
 
    <style type="text/css"> 
table { 
  width: 80%; 
  margin: 1em auto; 
  border-collapse: collapse; 
} 
 
thead th, 
tfoot th { 
  padding: 0.5em; 
  text-align: left; 
  border: 1px solid black; 
  background-color: #AAF; 
} 
 
tfoot td { 
  border-top: 1px solid black; 
} 
 
tbody td { 
  padding: 0.5em; 
  border-left: 1px solid black; 
  border-right: 1px solid black; 
} 
 
tbody tr.odd { 
  background-color: #DDF; 
} 
 
td.numeric, 
th.numeric { 
  text-align: right; 
} 
 
    </style> 
        <!-- common.js --> 
    <script type='text/javascript'> 
    /** 
 * addEvent written by Dean Edwards, 2005 
 * with input from Tino Zijdel 
 * 
 * http://dean.edwards.name/weblog/2005/10/add-event/ 
 **/ 
function addEvent(element, type, handler) { 
  // assign each event handler a unique ID 
  if (!handler.$$guid) handler.$$guid = addEvent.guid++; 
  // create a hash table of event types for the element 
  if (!element.events) element.events = {}; 
  // create a hash table of event handlers for each element/event pair 
  var handlers = element.events[type]; 
  if (!handlers) { 
    handlers = element.events[type] = {}; 
    // store the existing event handler (if there is one) 
    if (element["on" + type]) { 
      handlers[0] = element["on" + type]; 
    } 
  } 
  // store the event handler in the hash table 
  handlers[handler.$$guid] = handler; 
  // assign a global event handler to do all the work 
  element["on" + type] = handleEvent; 
}; 
// a counter used to create unique IDs 
addEvent.guid = 1; 
 
function removeEvent(element, type, handler) { 
  // delete the event handler from the hash table 
  if (element.events && element.events[type]) { 
    delete element.events[type][handler.$$guid]; 
  } 
}; 
 
function handleEvent(event) { 
  var returnValue = true; 
  // grab the event object (IE uses a global event object) 
  event = event || fixEvent(window.event); 
  // get a reference to the hash table of event handlers 
  var handlers = this.events[event.type]; 
  // execute each event handler 
  for (var i in handlers) { 
    this.$$handleEvent = handlers[i]; 
    if (this.$$handleEvent(event) === false) { 
      returnValue = false; 
    } 
  } 
  return returnValue; 
}; 
 
function fixEvent(event) { 
  // add W3C standard event methods 
  event.preventDefault = fixEvent.preventDefault; 
  event.stopPropagation = fixEvent.stopPropagation; 
  return event; 
}; 
fixEvent.preventDefault = function() { 
  this.returnValue = false; 
}; 
fixEvent.stopPropagation = function() { 
  this.cancelBubble = true; 
}; 
 
// end from Dean Edwards 
 
 
/** 
 * Creates an Element for insertion into the DOM tree. 
 * From http://simon.incutio.com/archive/2003/06/15/javascriptWithXML 
 * 
 * @param element the element type to be created. 
 *        e.g. ul (no angle brackets) 
 **/ 
function createElement(element) { 
  if (typeof document.createElementNS != 'undefined') { 
    return document.createElementNS('http://www.w3.org/1999/xhtml', element); 
  } 
  if (typeof document.createElement != 'undefined') { 
    return document.createElement(element); 
  } 
  return false; 
} 
 
/** 
 * "targ" is the element which caused this function to be called 
 * from http://www.quirksmode.org/js/events_properties.html 
 **/ 
function getEventTarget(e) { 
  var targ; 
  if (!e) { 
    e = window.event; 
  } 
  if (e.target) { 
    targ = e.target; 
  } else if (e.srcElement) { 
    targ = e.srcElement; 
  } 
  if (targ.nodeType == 3) { // defeat Safari bug 
    targ = targ.parentNode; 
  } 
 
  return targ; 
} 
 
 
    </script> 
    <!-- css.js --> 
    <script type='text/javascript'> 
/** 
 * Written by Neil Crosby.  
 * http://www.workingwith.me.uk/ 
 * 
 * Use this wherever you want, but please keep this comment at the top of this file. 
 * 
 * Copyright (c) 2006 Neil Crosby 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy  
 * of this software and associated documentation files (the "Software"), to deal  
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
 * copies of the Software, and to permit persons to whom the Software is  
 * furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in  
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
 * SOFTWARE. 
 **/ 
var css = { 
  /** 
   * Returns an array containing references to all elements 
   * of a given tag type within a certain node which have a given class 
   * 
   * @param node    the node to start from  
   *          (e.g. document,  
   *              getElementById('whateverStartpointYouWant') 
   *          ) 
   * @param searchClass the class we're wanting 
   *          (e.g. 'some_class') 
   * @param tag     the tag that the found elements are allowed to be 
   *          (e.g. '*', 'div', 'li') 
   **/ 
  getElementsByClass : function(node, searchClass, tag) { 
    var classElements = new Array(); 
    var els = node.getElementsByTagName(tag); 
    var elsLen = els.length; 
    var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)"); 
     
     
    for (var i = 0, j = 0; i < elsLen; i++) { 
      if (this.elementHasClass(els[i], searchClass) ) { 
        classElements[j] = els[i]; 
        j++; 
      } 
    } 
    return classElements; 
  }, 
 
 
  /** 
   * PRIVATE.  Returns an array containing all the classes applied to this 
   * element. 
   * 
   * Used internally by elementHasClass(), addClassToElement() and  
   * removeClassFromElement(). 
   **/ 
  privateGetClassArray: function(el) { 
    return el.className.split(' ');  
  }, 
 
  /** 
   * PRIVATE.  Creates a string from an array of class names which can be used  
   * by the className function. 
   * 
   * Used internally by addClassToElement(). 
   **/ 
  privateCreateClassString: function(classArray) { 
    return classArray.join(' '); 
  }, 
 
  /** 
   * Returns true if the given element has been assigned the given class. 
   **/ 
  elementHasClass: function(el, classString) { 
    if (!el) { 
      return false; 
    } 
     
    var regex = new RegExp('\\b'+classString+'\\b'); 
    if (el.className.match(regex)) { 
      return true; 
    } 
 
    return false; 
  }, 
 
  /** 
   * Adds classString to the classes assigned to the element with id equal to 
   * idString. 
   **/ 
  addClassToId: function(idString, classString) { 
    this.addClassToElement(document.getElementById(idString), classString); 
  }, 
 
  /** 
   * Adds classString to the classes assigned to the given element. 
   * If the element already has the class which was to be added, then 
   * it is not added again. 
   **/ 
  addClassToElement: function(el, classString) { 
    var classArray = this.privateGetClassArray(el); 
 
    if (this.elementHasClass(el, classString)) { 
      return; // already has element so don't need to add it 
    } 
 
    classArray.push(classString); 
 
    el.className = this.privateCreateClassString(classArray); 
  }, 
 
  /** 
   * Removes the given classString from the list of classes assigned to the 
   * element with id equal to idString 
   **/ 
  removeClassFromId: function(idString, classString) { 
    this.removeClassFromElement(document.getElementById(idString), classString); 
  }, 
 
  /** 
   * Removes the given classString from the list of classes assigned to the 
   * given element.  If the element has the same class assigned to it twice,  
   * then only the first instance of that class is removed. 
   **/ 
  removeClassFromElement: function(el, classString) { 
    var classArray = this.privateGetClassArray(el); 
 
    for (x in classArray) { 
      if (classString == classArray[x]) { 
        classArray[x] = ''; 
        break; 
      } 
    } 
 
    el.className = this.privateCreateClassString(classArray); 
  } 
}     
    </script> 
    <!-- standardista-table-sorting.js --> 
    <script type='text/javascript'> 
/** 
 * Written by Neil Crosby.  
 * http://www.workingwith.me.uk/articles/scripting/standardista_table_sorting 
 * 
 * This module is based on Stuart Langridge's "sorttable" code.  Specifically,  
 * the determineSortFunction, sortCaseInsensitive, sortDate, sortNumeric, and 
 * sortCurrency functions are heavily based on his code.  This module would not 
 * have been possible without Stuart's earlier outstanding work. 
 * 
 * Use this wherever you want, but please keep this comment at the top of this file. 
 * 
 * Copyright (c) 2006 Neil Crosby 
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy  
 * of this software and associated documentation files (the "Software"), to deal  
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
 * copies of the Software, and to permit persons to whom the Software is  
 * furnished to do so, subject to the following conditions: 
 * 
 * The above copyright notice and this permission notice shall be included in  
 * all copies or substantial portions of the Software. 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
 * SOFTWARE. 
 **/ 
var standardistaTableSorting = { 
 
  that: false, 
  isOdd: false, 
 
  sortColumnIndex : -1, 
  lastAssignedId : 0, 
  newRows: -1, 
  lastSortedTable: -1, 
 
  /** 
   * Initialises the Standardista Table Sorting module 
   **/ 
  init : function() { 
    // first, check whether this web browser is capable of running this script 
    if (!document.getElementsByTagName) { 
      return; 
    } 
     
    this.that = this; 
     
    this.run(); 
     
  }, 
   
  /** 
   * Runs over each table in the document, making it sortable if it has a class 
   * assigned named "sortable" and an id assigned. 
   **/ 
  run : function() { 
    var tables = document.getElementsByTagName("table"); 
     
    for (var i=0; i < tables.length; i++) { 
      var thisTable = tables[i]; 
       
      if (css.elementHasClass(thisTable, 'sortable')) { 
        this.makeSortable(thisTable); 
      } 
    } 
  }, 
   
  /** 
   * Makes the given table sortable. 
   **/ 
  makeSortable : function(table) { 
   
    // first, check if the table has an id.  if it doesn't, give it one 
    if (!table.id) { 
      table.id = 'sortableTable'+this.lastAssignedId++; 
    } 
     
    // if this table does not have a thead, we don't want to know about it 
    if (!table.tHead || !table.tHead.rows || 0 == table.tHead.rows.length) { 
      return; 
    } 
     
    // we'll assume that the last row of headings in the thead is the row that  
    // wants to become clickable 
    var row = table.tHead.rows[table.tHead.rows.length - 1]; 
     
    for (var i=0; i < row.cells.length; i++) { 
     
      // create a link with an onClick event which will  
      // control the sorting of the table 
      var linkEl = createElement('a'); 
      linkEl.href = '#'; 
      linkEl.onclick = this.headingClicked; 
      linkEl.setAttribute('columnId', i); 
      linkEl.title = 'Click to sort'; 
       
      // move the current contents of the cell that we're  
      // hyperlinking into the hyperlink 
      var innerEls = row.cells[i].childNodes; 
      for (var j = 0; j < innerEls.length; j++) { 
        linkEl.appendChild(innerEls[j]); 
      } 
       
      // and finally add the new link back into the cell 
      row.cells[i].appendChild(linkEl); 
 
      var spanEl = createElement('span'); 
      spanEl.className = 'tableSortArrow'; 
      spanEl.appendChild(document.createTextNode('\u00A0\u00A0')); 
      row.cells[i].appendChild(spanEl); 
 
    } 
   
    if (css.elementHasClass(table, 'autostripe')) { 
      this.isOdd = false; 
      var rows = table.tBodies[0].rows; 
     
      // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones 
      for (var i=0;i<rows.length;i++) {  
        this.doStripe(rows[i]); 
      } 
    } 
  }, 
   
  headingClicked: function(e) { 
     
    var that = standardistaTableSorting.that; 
     
    // linkEl is the hyperlink that was clicked on which caused 
    // this method to be called 
    var linkEl = getEventTarget(e); 
     
    // directly outside it is a td, tr, thead and table 
    var td     = linkEl.parentNode; 
    var tr     = td.parentNode; 
    var thead  = tr.parentNode; 
    var table  = thead.parentNode; 
     
    // if the table we're looking at doesn't have any rows 
    // (or only has one) then there's no point trying to sort it 
    if (!table.tBodies || table.tBodies[0].rows.length <= 1) { 
      return false; 
    } 
 
    // the column we want is indicated by td.cellIndex 
    var column = linkEl.getAttribute('columnId') || td.cellIndex; 
    //var column = td.cellIndex; 
     
    // find out what the current sort order of this column is 
    var arrows = css.getElementsByClass(td, 'tableSortArrow', 'span'); 
    var previousSortOrder = ''; 
    if (arrows.length > 0) { 
      previousSortOrder = arrows[0].getAttribute('sortOrder'); 
    } 
     
    // work out how we want to sort this column using the data in the first cell 
    // but just getting the first cell is no good if it contains no data 
    // so if the first cell just contains white space then we need to track 
    // down until we find a cell which does contain some actual data 
    var itm = '' 
    var rowNum = 0; 
    while ('' == itm && rowNum < table.tBodies[0].rows.length) { 
      itm = that.getInnerText(table.tBodies[0].rows[rowNum].cells[column]); 
      rowNum++; 
    } 
    var sortfn = that.determineSortFunction(itm); 
 
    // if the last column that was sorted was this one, then all we need to  
    // do is reverse the sorting on this column 
    if (table.id == that.lastSortedTable && column == that.sortColumnIndex) { 
      newRows = that.newRows; 
      newRows.reverse(); 
    // otherwise, we have to do the full sort 
    } else { 
      that.sortColumnIndex = column; 
      var newRows = new Array(); 
 
      for (var j = 0; j < table.tBodies[0].rows.length; j++) {  
        newRows[j] = table.tBodies[0].rows[j];  
      } 
 
      newRows.sort(sortfn); 
    } 
 
    that.moveRows(table, newRows); 
    that.newRows = newRows; 
    that.lastSortedTable = table.id; 
     
    // now, give the user some feedback about which way the column is sorted 
     
    // first, get rid of any arrows in any heading cells 
    var arrows = css.getElementsByClass(tr, 'tableSortArrow', 'span'); 
    for (var j = 0; j < arrows.length; j++) { 
      var arrowParent = arrows[j].parentNode; 
      arrowParent.removeChild(arrows[j]); 
 
      if (arrowParent != td) { 
        spanEl = createElement('span'); 
        spanEl.className = 'tableSortArrow'; 
        spanEl.appendChild(document.createTextNode('\u00A0\u00A0')); 
        arrowParent.appendChild(spanEl); 
      } 
    } 
     
    // now, add back in some feedback  
    var spanEl = createElement('span'); 
    spanEl.className = 'tableSortArrow'; 
    if (null == previousSortOrder || '' == previousSortOrder || 'DESC' == previousSortOrder) { 
      spanEl.appendChild(document.createTextNode(' \u2191')); 
      spanEl.setAttribute('sortOrder', 'ASC'); 
    } else { 
      spanEl.appendChild(document.createTextNode(' \u2193')); 
      spanEl.setAttribute('sortOrder', 'DESC'); 
    } 
     
    td.appendChild(spanEl); 
     
    return false; 
  }, 
 
  getInnerText : function(el) { 
     
    if ('string' == typeof el || 'undefined' == typeof el) { 
      return el; 
    } 
     
    if (el.innerText) { 
      return el.innerText;  // Not needed but it is faster 
    } 
 
    var str = el.getAttribute('standardistaTableSortingInnerText'); 
    if (null != str && '' != str) { 
      return str; 
    } 
    str = ''; 
 
    var cs = el.childNodes; 
    var l = cs.length; 
    for (var i = 0; i < l; i++) { 
      // 'if' is considerably quicker than a 'switch' statement,  
      // in Internet Explorer which translates up to a good time  
      // reduction since this is a very often called recursive function 
      if (1 == cs[i].nodeType) { // ELEMENT NODE 
        str += this.getInnerText(cs[i]); 
        break; 
      } else if (3 == cs[i].nodeType) { //TEXT_NODE 
        str += cs[i].nodeValue; 
        break; 
      } 
    } 
     
    // set the innertext for this element directly on the element 
    // so that it can be retrieved early next time the innertext 
    // is requested 
    el.setAttribute('standardistaTableSortingInnerText', str); 
     
    return str; 
  }, 
 
  determineSortFunction : function(itm) { 
     
    var sortfn = this.sortCaseInsensitive; 
     
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/)) { 
      sortfn = this.sortDate; 
    } 
    if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) { 
      sortfn = this.sortDate; 
    } 
    if (itm.match(/^[£$]/)) { 
      sortfn = this.sortCurrency; 
    } 
    if (itm.match(/^\d?\.?\d+$/)) { 
      sortfn = this.sortNumeric; 
    } 
    if (itm.match(/^[+-]?\d*\.?\d+([eE]-?\d+)?$/)) { 
      sortfn = this.sortNumeric; 
    } 
        if (itm.match(/^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/)) { 
            sortfn = this.sortIP; 
       } 
 
    return sortfn; 
  }, 
   
  sortCaseInsensitive : function(a, b) { 
    var that = standardistaTableSorting.that; 
     
    var aa = that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase(); 
    var bb = that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase(); 
    if (aa==bb) { 
      return 0; 
    } else if (aa<bb) { 
      return -1; 
    } else { 
      return 1; 
    } 
  }, 
   
  sortDate : function(a,b) { 
    var that = standardistaTableSorting.that; 
 
    // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX 
    var aa = that.getInnerText(a.cells[that.sortColumnIndex]); 
    var bb = that.getInnerText(b.cells[that.sortColumnIndex]); 
     
    var dt1, dt2, yr = -1; 
     
    if (aa.length == 10) { 
      dt1 = aa.substr(6,4)+aa.substr(3,2)+aa.substr(0,2); 
    } else { 
      yr = aa.substr(6,2); 
      if (parseInt(yr) < 50) {  
        yr = '20'+yr;  
      } else {  
        yr = '19'+yr;  
      } 
      dt1 = yr+aa.substr(3,2)+aa.substr(0,2); 
    } 
     
    if (bb.length == 10) { 
      dt2 = bb.substr(6,4)+bb.substr(3,2)+bb.substr(0,2); 
    } else { 
      yr = bb.substr(6,2); 
      if (parseInt(yr) < 50) {  
        yr = '20'+yr;  
      } else {  
        yr = '19'+yr;  
      } 
      dt2 = yr+bb.substr(3,2)+bb.substr(0,2); 
    } 
     
    if (dt1==dt2) { 
      return 0; 
    } else if (dt1<dt2) { 
      return -1; 
    } 
    return 1; 
  }, 
 
  sortCurrency : function(a,b) {  
    var that = standardistaTableSorting.that; 
 
    var aa = that.getInnerText(a.cells[that.sortColumnIndex]).replace(/[^0-9.]/g,''); 
    var bb = that.getInnerText(b.cells[that.sortColumnIndex]).replace(/[^0-9.]/g,''); 
    return parseFloat(aa) - parseFloat(bb); 
  }, 
 
  sortNumeric : function(a,b) {  
    var that = standardistaTableSorting.that; 
 
    var aa = parseFloat(that.getInnerText(a.cells[that.sortColumnIndex])); 
    if (isNaN(aa)) {  
      aa = 0; 
    } 
    var bb = parseFloat(that.getInnerText(b.cells[that.sortColumnIndex]));  
    if (isNaN(bb)) {  
      bb = 0; 
    } 
    return aa-bb; 
  }, 
 
  makeStandardIPAddress : function(val) { 
    var vals = val.split('.'); 
 
    for (x in vals) { 
      val = vals[x]; 
 
      while (3 > val.length) { 
        val = '0'+val; 
      } 
      vals[x] = val; 
    } 
 
    val = vals.join('.'); 
 
    return val; 
  }, 
 
  sortIP : function(a,b) {  
    var that = standardistaTableSorting.that; 
 
    var aa = that.makeStandardIPAddress(that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase()); 
    var bb = that.makeStandardIPAddress(that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase()); 
    if (aa==bb) { 
      return 0; 
    } else if (aa<bb) { 
      return -1; 
    } else { 
      return 1; 
    } 
  }, 
 
  moveRows : function(table, newRows) { 
    this.isOdd = false; 
 
    // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones 
    for (var i=0;i<newRows.length;i++) {  
      var rowItem = newRows[i]; 
 
      this.doStripe(rowItem); 
 
      table.tBodies[0].appendChild(rowItem);  
    } 
  }, 
   
  doStripe : function(rowItem) { 
    if (this.isOdd) { 
      css.addClassToElement(rowItem, 'odd'); 
    } else { 
      css.removeClassFromElement(rowItem, 'odd'); 
    } 
     
    this.isOdd = !this.isOdd; 
  } 
 
} 
 
function standardistaTableSortingInit() { 
  standardistaTableSorting.init(); 
} 
 
addEvent(window, 'load', standardistaTableSortingInit)     
    </script> 
  </head> 
  <body> 
 
    <table class='sortable autostripe'> 
      <thead> 
        <tr> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
          <th>Heading</th> 
        </tr> 
      </thead> 
      <tbody> 
        <script> 
          for (var i=0; i < 100; i++) { 
 
            var number = Math.round(Math.random()*1000); 
 
            var day   = (1 + Math.round(Math.random()*30)); 
            if (day < 10) { 
              day = '0' + day; 
            } 
            var month = (1 + Math.round(Math.random()*11)); 
            if (month < 10) { 
              month = '0' + month; 
            } 
            var year  = (1990 + Math.round(Math.random()*16)); 
 
            var pennies = (1 + Math.round(Math.random()*99)); 
            if (pennies < 10) { 
              pennies = '0' + pennies; 
            } 
 
            var pounds = (1 + Math.round(Math.random()*1500)); 
 
            var date = day + '/' + month + '/' + year; 
 
            document.write("<tr>"); 
            document.write("<td>"+number+"</td>"); 
            document.write("<td>"+date+"</td>"); 
            document.write("<td>$"+pounds+'.'+pennies+"</td>"); 
            document.write("<td>"+number+"</td>"); 
            document.write("<td>"+date+"</td>"); 
            document.write("<td>$"+pounds+'.'+pennies+"</td>"); 
            document.write("<td>"+number+"</td>"); 
            document.write("<td>"+date+"</td>"); 
            document.write("</tr>"); 
          } 
        </script> 
      </tbody> 
    </table> 
 
 
  </body> 
</html> 
            
          
   
    
    |