// select.js

// display tabular input as a single row

// 2006-01-06 djh v1.00	First working and documented version

/*
  Copyright (c) 2006 Dave Howorth

  djh@cpan.org

This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or (at
your option) any later version.

This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
General Public License for more details.

    http://www.gnu.org/copyleft/lesser.txt
*/

// ------------------------------------------------------

  // Redisplay the table when some event occurs on either a select box
  // or one of its options
  function selected(object, event, keys)
  {
    var val
    var sel
    if (object instanceof HTMLSelectElement) {
      sel = object
      var i = object.selectedIndex
      var opt = object.options[i]
      val = opt.value
    }
    else if (object instanceof HTMLOptionElement) {
      sel = object.parentNode
      val = object.value
    }
    else
      alert("wasn't expecting " + this)

    var table = sel.nextSibling
    hideTable(table, keys, val)
  }


  function hideTable(table, keys, viz_key)
  {
    // make the table invisble
    for (var i = 0; i < table.rows.length; i++) {
      row = table.rows[i]
      if (row.innerHTML.search( /<th>/ ) == -1) {
        row.style.display = 'none'
      }
    }

    // redisplay one of the rows if required
    // 'keys' is an associative array mapping record id to table row number
    if (viz_key) {
      var viz_row = keys[viz_key]
      table.rows[viz_row].style.display = ''
    }
  }


  // Create a selector instead of a column of radio buttons for one table
  function selector_init(div)
  {
    if (div.className != 'selector') alert('BUG 1')

    // Get the table within the div
    var tables = div.getElementsByTagName('table')
    if (tables.length != 1) alert('BUG 2')
    var table = tables.item(0)

    // Create a select box to accompany the table
    var sel = document.createElement('select')
    var s   = sel.options.length
    div.insertBefore(sel, table)

    // Populate selector with options generated from table
    // .
    // The option.value needs to be the id of the record, in order for
    // the form submission to work properly
    // .
    // The option.text is the value of the record's Name column, if any
    // and otherwise, its id (obtained from the radio button's value)

    // Regular expressions to parse the table
    var TH = /th/i
    var TD = /td/i
    var INPUT = /input/i

    // Working variables for row iteration
    var header		// HTML header row object	   - used to delete ..
    var radio_hdr	// Header cell above radio buttons - .. the radio col
    var label_col	// Column number for label field
    var t = table.rows.length
    var keys = { }	// map from record id to row number

    for (var i = 0; i < t; i++) {			// Scan each row

      // Working variables for column iteration
      var row	= table.rows[i]
      var val	= ''	// string to be used as option's value
      var label = ''	// string to be used as option's text

      for (var j = 0; j < row.cells.length; j++) {	// Scan each col

        var cell = row.cells[j]
	var tag  = cell.tagName

	if (tag.match(TH)) {			// Process header
	  header = row
	  // try to match 'name' header and remember column number for label
	  if (cell.innerHTML.match(/name/i)) label_col = j
	}
	else if (tag.match(TD)) {		// Process other rows
	  var first
	  if (cell.firstChild) first = cell.firstChild
	  // If this is the Name column, use it to label the option
	  if (j == label_col) {
	    label = cell.innerHTML
	  }
	  // If this is a radio input, extract details and delete it
	  else if (first && first.tagName && first.tagName.match(INPUT)
		&& first.type == 'radio') {
	    // Use the radio box to provide ...
	    val		= first.value	// ... the option's value and ...
	    sel.name	= first.name	// ... the select's name
	    keys[val]	= i		// Map record id to row number
	    if (!label) label = val	// Default label is record id
	    row.removeChild(cell)	// Delete the button from the page
	    radio_hdr = header.cells[j]	// Remember where the column header is
	  }
	}
	else alert('BUG: unexpected tagName=' + cell.tagName)

      } // end for j (cols)

      if (tag.match(TH)) continue	// don't make option for header row!
      if (! val  ) alert('BUG: row ' + i + ' has no defined value')
      if (! label) label = val		// default label is id

      // Create the option and set its attributes
      opt = new Option
      opt.value = val
      opt.text  = label
      sel.options[s++] = opt

    } // end for i (rows)

    // Delete the header cell above the radio buttons
    if (radio_hdr) header.removeChild(radio_hdr)

    // Create a closure to encapsulate the id to row mapping
    var handler = function (event) { selected(this, event, keys) }

    // Watch events on selector and options
    //sel.onkeyup = handler
    sel.onblur  = handler
    for (var i = 0; i < sel.options.length; i++) {
      opt = sel.options[i]
      opt.onmouseover = handler
    }

    sel.selectedIndex = 0	// Select first item
    var opt = sel.options[0]
    val = opt.value
    
    hideTable(table, keys, val)	// display correct line of table
  }


  // Look through all the div elements on the page, identify those with
  // class = selector and set up select widgets for the tables within them
  function scan_divs()
  {
    var divs = document.getElementsByTagName('div')
    for (var i = 0; i < divs.length; i++) {
      var div = divs.item(i)
      if (div.className == 'selector') selector_init(div)
    }
  }


  // This is called by the onload event
  function init()
  {
    scan_divs()
  }

// end of select.js

