// Lots of functions for notes, holdings and labels.

/* 
   Some functions can present language-dependent text if you remember
   to set tkl_lang in the Javascript environment like this:
   <script xml:lang="da" >document.tkl_lang='da';</script>
   <script xml:lang="en" >document.tkl_lang='en';</script>
   preferably directly *before* you call any .js file!
*/

function validateText(select) {
  if (select.match(/[<\&]/)) {
    if($tkl_lang == 'da') {
      alert('HUSK: Man må ikke bruge < eller &');
    } else {
      alert('NOTE: Do not use < or & in this input');
    }
    return false; // there is a forbidden char
  } else {
    return true; // no forbidden char found
  }
}


function untity(htmlstr) {
  // replace numeric entities by true codes.
  return htmlstr.replace(/\&\#(\d+);/g,
                         function(y,x) {return String.fromCharCode(x);})
}


function isvaliddirname(elm)
{
  // Check if input does not contain chars I don't want to have in
  // Unix dirnames. See tkl-movekba/handler.pl for a regex in line
  // with this one.

  var re = new RegExp("^[A-Za-z0-9-_!.:+=]*$");
  if(elm.value.match(re)) {
    return true;
  } else {
    alert('Navn må kun indeholde de følgende karakterer:\nA-Z a-z 0-9 - _ ! . : + =');
    return false;
  }
}

function toggleElement(elementid, state)
{
  // toggle element visibility
  obj = document.getElementById(elementid);
  obj.style.display = (obj.style.display=="none" ? "block" : "none");
}


function checkall(field)
{
  // check all checkboxes of a certain name
  for(i = 0; i < field.length; i++) {
    field[i].checked = true;
  }
}

function uncheckall(field)
{
  // uncheck all checkboxes of a certain name
  for(i = 0; i < field.length; i++) {
    field[i].checked = false;
  }
}


function reload_wait(doc) {
  // reload a document, typically window.opener.document, and try to
  // restore its scroll position in a crossbrowser fashion. Addresses
  // the problem that the document load-and-parse must be complete
  // before we can set its properties.

  // BUGS
  // Seems to be broken in FF, although the basic concept works
  // there, and I see no errors.
  //
  // Still doesn't work in IE when a really large doc is loaded.
  

  var pos;
  pos = doc.body.scrollTop;
  doc.location.reload();
  // this idle loop should wait for an event, if only I knew what
  // event...
  while(!doc.body) { }
  doc.body.scrollTop = pos;
}


function lookup(evt, wheretoid,wherefromid, xpos,ypos, horsize,versize) 
{
  // Present a lookup list (in a popup) made from elements in the
  // wherefromid element, which should look like:
  //
  //  <div id="picklist" style="display: none">
  //    <span title="key1">blabla for key 1</span>
  //    <span title="key2">blabla for key 2</span>
  //    <span title="key3">blabla for key 3</span>
  //  </div>
  //
  // The inner elements must be <span>.
  // When the user clicks on an element, its key gets pasted as the
  // .value of wheretoid. Normally wheretoid will point to a text box
  // in a form

  // This is an adaptation of Roel's own prototype. Picking goes as
  // follows depending on what the user typed in the input box
  // (oldvalue):
  // - oldvalue is empty: show whole list
  // - oldvalue matches exactly 1 entry: silently return
  // - oldvalue matches more than 1 entry: show matches
  // - oldvalue matches none: say so and show whole list.

  // This thing has been made more KSS-specific than its very generic
  // protoype. It specifically filters RS-sentences.
 
  // NB: Roel has done some experiments with ways of manipulating the
  // window just created by window.open() using DOM methods only
  // (rather than series of write()s), but these only seem to work
  // properly in Mozilla5 (Firefox). Details on request.

  // Browser workaround. Yuck.
  var whatkey;
  if(evt.which)
  {
    whatkey = evt.which;    // Expunger
  } else if(evt.keyCode) {
    whatkey = evt.keyCode;  // Netschaap
  }

  /*
  if(whatkey != 9)
  {
    return true;
  }
  */

  var whereto  = document.getElementById(wheretoid);
  var picklist = document.getElementById(wherefromid);
  var oldvalue = whereto.value.toUpperCase();

  // First see if we must open a popup at all.

  var allspan = picklist.getElementsByTagName('span');

  // Build an 'index' of entries in allspan that match current entry
  // (empy oldvalue matches all)

  var matches = new Array;
  var howmany = 0;

  for(var i=0; i < allspan.length; i++) {
    var ttl = allspan[i].title;
    if(ttl.indexOf(oldvalue) == 0)
    {
      matches[howmany] = i;
      howmany++;
    }
  }

  if(howmany == 1) {
    return true;
  }

  // Ok, we should open a popup.

  xpos = xpos == null ? 200 : xpos;
  ypos = ypos == null ? 300 : ypos;
  horsize = horsize == null ? 500 : horsize;
  versize = versize == null ? 280 : versize;

  var l = window.open('', 'sniff', 'height=' + versize + ',width=' + horsize + ',scrollbars=1' +
                      ',left=' + xpos + ',top=' + ypos);
  // l.moveTo(xpos,ypos);
  var wd=l.document;

  // make 'whereto' available as "global" var for scripts (esp. event
  // handlers) called from within l
  // See quirk comment inside for loop!
  l.whereto = whereto;

  wd.writeln('<html>');
  wd.writeln('<head>');
  wd.writeln('<style type="text/css">');
  wd.writeln('* { font-family: verdana, arial, helvetica, sans; font-size: 10px; }');
  wd.writeln('');
  wd.writeln('td        { vertical-align: top; border-bottom: 1px solid black; }');
  wd.writeln('.odd-row  { background-color: #ebe9e4; }');
  wd.writeln('.even-row { /* nothing special */ }');
  wd.writeln('tr        { border-bottom: 1px solid black; }');
  wd.writeln('');
  wd.writeln('');
  wd.writeln('');
  wd.writeln('</style>');
  wd.writeln('</head>');
  wd.writeln('<body>');
  // wd.writeln('<body onblur="window.close();">');
  // By letting this window close if someone clicks elsewhere, we
  // prevent it from accidentally getting hidden behind another
  // one. Unfortunately it's broken in IE6 (i.e. triggers at an
  // unjustified time)

  if(howmany == 0) {
    wd.writeln('<p>');
    document.tkl_lang == 'en' && wd.writeln('No entry in list starts with "' +  oldvalue + '". Please pick one of the following:');
    document.tkl_lang == 'da' && wd.writeln('Ingen entry i listen begynder med "' +  oldvalue + '". Venligst vælg én af de følgende:');
    wd.writeln('</p>');
    // This looks silly, but heck
    for(var i=0; i < allspan.length; i++) {
      matches[i] = i;
    }
  }

  //window.finished = false;
  wd.writeln('<table>');
  for(var i=0; i < matches.length; i++) {
    var key   = allspan[matches[i]].title;
    var value = allspan[matches[i]].firstChild.nodeValue;

    // Hmmm, I have to repeat this inside this block? Why?
    l.whereto = whereto;

    // variant 1:
    var onclick = "whereto.value = '" + key + "';  window.close();";

    // variant 2:
    //var templ = "window.opener.document.getElementById('WHERETOID').value = 'KEY';";
    //var onclick = templ.replace('WHERETOID', wheretoid);
    //onclick =     onclick.replace('KEY', key);

    // Vain experiment with using a flag and suspending this JS thread:
    //var onclick = "whereto.value = '" + key + "';  window.opener.finished=true;";

    // Remember that the event handlers invoked from within window l
    // have l as their context, i.e. their global vars are those
    // from l.

    // This doesn't combine well with setting bgColor, and setting
    // style dynamically in IE is crapped
    //var rowclass;
    //rowclass = (i % 2 == 1) ? 'class="odd-row"' : 'class="even-row"';

    wd.writeln('<tr onmouseover="this.bgColor=\'cyan\';" onmouseout="this.bgColor=\'white\';">');
    //wd.writeln('<td onclick="' + onclick + '">');
    //wd.writeln(key);
    //wd.writeln('</td>');
    wd.writeln('<td onclick="' + onclick + '">');    
    wd.writeln(value);
    wd.writeln('</td>');
    wd.writeln('</tr>');
  }
  wd.writeln('</table>');

  wd.writeln('</body>\n</html>');
  wd.close();

  // Part of aforementioned Experiment with using a flag to 'stay' in
  // this execution thread until the user has chosen. 

  // Troublesome because JS does not have a true sleep() or wait().

  //while(!window.finished)
  //{
  //  window.status = whereto.value;
  //}

  return true;
}


function rslookup(e, wheretoid,wherefromid, xpos,ypos, horsize,versize) 
{
  // Almost the same as lookup, but specialised (i.e. dumbified) for
  // the RS-dropdown box in the label module.

  // Browser workaround. Yuck.
  var whatkey;
  if(e.which)
  {
    whatkey = e.which;    // Expunger
  } else if(e.keyCode) {
    whatkey = e.keyCode;  // Netschaap
  }

  if(whatkey != 9)
  {
    return true;
  }

  var whereto  = document.getElementById(wheretoid);
  var picklist = document.getElementById(wherefromid);
  var oldvalue = whereto.value.toUpperCase();

  // RS: ignore empty field
  if(oldvalue == '')
  {
    return true;
  }

  // First see if we must open a popup at all.

  var allspan = picklist.getElementsByTagName('span');

  // Build an 'index' of entries in allspan that match current entry
  // (empy oldvalue matches all)

  var matches = new Array;
  var howmany = 0;
  var onlymatch;

  for(var i=0; i < allspan.length; i++) 
  {
    var ttl = allspan[i].title;
    if(ttl.indexOf(oldvalue) == 0)
    {
      matches[howmany] = i;
      howmany++;
      onlymatch = ttl;
    }
  }

  if(howmany == 1)
  {
    // This match may be unique-but-not-complete, so:
    whereto.value = onlymatch;
    return true;
  } else if (howmany == 0) {
    return true;
  }

  // Ok, we should open a popup.

  xpos = xpos == null ? 200 : xpos;
  ypos = ypos == null ? 300 : ypos;
  horsize = horsize == null ? 500 : horsize;
  versize = versize == null ? 280 : versize;

  var l = window.open('', 'sniff', 'height=' + versize + ',width=' + horsize + ',scrollbars=1' +
                      ',left=' + xpos + ',top=' + ypos);
  // l.moveTo(xpos,ypos);
  var wd=l.document;

  // make 'whereto' available as "global" var for scripts (esp. event
  // handlers) called from within l
  // See quirk comment inside for loop!
  l.whereto = whereto;

  wd.writeln('<html>');
  wd.writeln('<head>');
  wd.writeln('<style type="text/css">');
  wd.writeln('* { font-family: verdana, arial, helvetica, sans; font-size: 10px; }');
  wd.writeln('');
  wd.writeln('td        { vertical-align: top; border-bottom: 1px solid black; }');
  wd.writeln('.odd-row  { background-color: #ebe9e4; }');
  wd.writeln('.even-row { /* nothing special */ }');
  wd.writeln('tr        { border-bottom: 1px solid black; }');
  wd.writeln('');
  wd.writeln('');
  wd.writeln('');
  wd.writeln('</style>');
  wd.writeln('</head>');
  wd.writeln('<body>');
  // wd.writeln('<body onblur="window.close();">');
  // By letting this window close if someone clicks elsewhere, we
  // prevent it from accidentally getting hidden behind another
  // one. Unfortunately it's broken in IE6 (i.e. triggers at an
  // unjustified time)

  if(howmany == 0)
  {
    wd.writeln('<p>');
    document.tkl_lang == 'en' && wd.writeln('No entry in list starts with "' +  oldvalue + '". Please pick one of the following:');
    document.tkl_lang == 'da' && wd.writeln('Ingen entry i listen begynder med "' +  oldvalue + '". Venligst vælg én af de følgende:');
    wd.writeln('</p>');
    // This looks silly, but heck
    for(var i=0; i < allspan.length; i++)
    {
      matches[i] = i;
    }
  }

  //window.finished = false;
  wd.writeln('<table>');
  for(var i=0; i < matches.length; i++) 
  {
    var key   = allspan[matches[i]].title;
    var value = allspan[matches[i]].firstChild.nodeValue;

    // Hmmm, I have to repeat this inside this block? Why?
    l.whereto = whereto;

    // variant 1:
    var onclick = "whereto.value = '" + key + "';  window.close();";

    // variant 2:
    //var templ = "window.opener.document.getElementById('WHERETOID').value = 'KEY';";
    //var onclick = templ.replace('WHERETOID', wheretoid);
    //onclick =     onclick.replace('KEY', key);

    // Vain experiment with using a flag and suspending this JS thread:
    //var onclick = "whereto.value = '" + key + "';  window.opener.finished=true;";

    // Remember that the event handlers invoked from within window l
    // have l as their context, i.e. their global vars are those
    // from l.

    // This doesn't combine well with setting bgColor, and setting
    // style dynamically in IE is crapped
    //var rowclass;
    //rowclass = (i % 2 == 1) ? 'class="odd-row"' : 'class="even-row"';

    wd.writeln('<tr onmouseover="this.bgColor=\'cyan\';" onmouseout="this.bgColor=\'white\';">');
    //wd.writeln('<td onclick="' + onclick + '">');
    //wd.writeln(key);
    //wd.writeln('</td>');
    wd.writeln('<td onclick="' + onclick + '">');    
    wd.writeln(value);
    wd.writeln('</td>');
    wd.writeln('</tr>');
    
  }
  wd.writeln('</table>');

  wd.writeln('</body>\n</html>');
  wd.close();

  // Part of aforementioned Experiment with using a flag to 'stay' in
  // this execution thread until the user has chosen. 

  // Troublesome because JS does not have a true sleep() or wait().

  //while(!window.finished)
  //{
  //  window.status = whereto.value;
  //}

  return true;
}


function choose_pictogram(file, imgid)
{
  // show relevant warning pictogram when choosing graphics from radio object
  // Give the img element where this should go an id number starting with 1.


  // document.images[imgid-1].src=file;
  elm = document.getElementById(imgid);
  elm.src=file;
  return true;
}

// Cookie functions (snatched from quirksmode.org)

function createCookie(name,value,days) {
  if (days) {
    var date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    var expires = "; expires="+date.toGMTString();
  }
  else var expires = "";
  document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  }
  return null;
}

function eraseCookie(name) {
  createCookie(name,"",-1);
}


function indexOf(arr, val) {
  // Generic handiness for finding a value in an array (only FF
  // currently has a Array.indexOf)
  for (i = 0; i < arr.length; i++) {
    if (arr[i] == val) { return i; }
  }
  return -1;
}


function alternate(id, oddstyle, evenstyle) {
  // a DHTML table row alternator. Actually works faster than setting
  // fixed odd/even styles on a large list. However, this should be
  // executed from body/@onload to take effect, I think.

  var table = document.getElementById(id);
  if(!table) {
    return;
  }

  var rows = table.getElementsByTagName("tr");
  for(i = 0; i < rows.length; i++) {
    if(i % 2 == 0) {
      if(evenstyle) { rows[i].className = evenstyle; }
    } else {
      if(oddstyle) { rows[i].className = oddstyle; }
    }
  }
}


/* Calendar picker courtesy of Denis Gritcyuk */

// Title: Timestamp picker
// Description: See the demo at url
// URL: http://us.geocities.com/tspicker/
// Script featured on: http://javascriptkit.com/script/script2/timestamp.shtml
// Version: 1.0
// Date: 12-05-2001 (mm-dd-yyyy)
// Author: Denis Gritcyuk <denis@softcomplex.com>; <tspicker@yahoo.com>
// Notes: Permission given to use this script in any kind of applications if
//    header lines are left unchanged. Feel free to contact the author
//    for feature requests and/or donations

// 200604 Roel de Cock: adapted for kemibrug.dk.

function show_calendar(str_target, str_datetime) {
  var arr_months = ["January", "February", "March", "April", "May", "June",
                    "July", "August", "September", "October", "November", "December"];
  var week_days = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
  var n_weekstart = 1; // day week starts from (normally 0 or 1)

  var dt_datetime = (str_datetime == null || str_datetime =="" ?  new Date() : str2dt(str_datetime));
  var dt_prev_month = new Date(dt_datetime);
  dt_prev_month.setMonth(dt_datetime.getMonth()-1);
  var dt_next_month = new Date(dt_datetime);
  dt_next_month.setMonth(dt_datetime.getMonth()+1);
  var dt_firstday = new Date(dt_datetime);
  dt_firstday.setDate(1);
  dt_firstday.setDate(1-(7+dt_firstday.getDay()-n_weekstart)%7);
  var dt_lastday = new Date(dt_next_month);
  dt_lastday.setDate(0);
        
  // html generation (feel free to tune it for your particular application)
  // print calendar header
  var str_buffer = new String 
    (
     "<html>\n"+
     "<head>\n"+
     "  <title>Calendar</title>\n"+
     "</head>\n"+
     "<body bgcolor=\"white\">\n"+
     "<table class=\"clsOTable\" cellspacing=\"0\" border=\"0\" width=\"100%\">\n"+
     "<tr><td bgcolor=\"#4682B4\">\n"+
     "<table cellspacing=\"1\" cellpadding=\"3\" border=\"0\" width=\"100%\">\n"+
     "<tr>\n <td bgcolor=\"#4682B4\"><a href=\"javascript:window.opener.show_calendar('"+
     str_target+"', '"+ dt2dtstr(dt_prev_month)+"'+document.cal.time.value);\">"+
     "<img src=\"ts_prev.gif\" width=\"16\" height=\"16\" border=\"0\""+
     " alt=\"previous month\">"+
     "</a></td>\n"+
     "       <td bgcolor=\"#4682B4\" colspan=\"5\">"+
     "<font color=\"white\" face=\"tahoma, verdana\" size=\"2\">"
     +arr_months[dt_datetime.getMonth()]+" "+dt_datetime.getFullYear()+"</font></td>\n"+
     "  <td bgcolor=\"#4682B4\" align=\"right\"><a href=\"javascript:window.opener.show_calendar('"
     +str_target+"', '"+dt2dtstr(dt_next_month)+"'+document.cal.time.value);\">"+
     "<img src=\"ts_next.gif\" width=\"16\" height=\"16\" border=\"0\""+
     " alt=\"next month\"></a></td>\n</tr>\n"
     );

  var dt_current_day = new Date(dt_firstday);
  // print weekdays titles
  str_buffer += "<tr>\n";
  for (var n=0; n<7; n++)
    str_buffer += " <td bgcolor=\"#87CEFA\">"+
      "<font color=\"white\" face=\"tahoma, verdana\" size=\"2\">"+
      week_days[(n_weekstart+n)%7]+"</font></td>\n";
  // print calendar table
  str_buffer += "</tr>\n";
  while (dt_current_day.getMonth() == dt_datetime.getMonth() ||
         dt_current_day.getMonth() == dt_firstday.getMonth()) {
    // print row heder
    str_buffer += "<tr>\n";
    for (var n_current_wday=0; n_current_wday<7; n_current_wday++) {
      if (dt_current_day.getDate() == dt_datetime.getDate() &&
          dt_current_day.getMonth() == dt_datetime.getMonth())
        // print current date
        str_buffer += " <td bgcolor=\"#FFB6C1\" align=\"right\">";
      else if (dt_current_day.getDay() == 0 || dt_current_day.getDay() == 6)
        // weekend days
        str_buffer += " <td bgcolor=\"#DBEAF5\" align=\"right\">";
      else
        // print working days of current month
        str_buffer += " <td bgcolor=\"white\" align=\"right\">";

      if (dt_current_day.getMonth() == dt_datetime.getMonth())
        // print days of current month
        str_buffer += "<a href=\"javascript:window.opener."+str_target+
          // RdC ".value='"+dt2dtstr(dt_current_day)+"'+document.cal.time.value; window.close();\">"+
          ".value='"+dt2dtstr(dt_current_day)+"'; window.close();\">"+
          "<font color=\"black\" face=\"tahoma, verdana\" size=\"2\">";
      else 
        // print days of other months
        str_buffer += "<a href=\"javascript:window.opener."+str_target+
          // RdC ".value='"+dt2dtstr(dt_current_day)+"'+document.cal.time.value; window.close();\">"+
          ".value='"+dt2dtstr(dt_current_day)+"'; window.close();\">"+
          "<font color=\"gray\" face=\"tahoma, verdana\" size=\"2\">";
      str_buffer += dt_current_day.getDate()+"</font></a></td>\n";
      dt_current_day.setDate(dt_current_day.getDate()+1);
    }
    // print row footer
    str_buffer += "</tr>\n";
  }
  // print calendar footer
  str_buffer +=
    "<form name=\"cal\">\n<tr><td colspan=\"7\" bgcolor=\"#87CEFA\">"+
    "<font color=\"White\" face=\"tahoma, verdana\" size=\"2\">"+
    "Time: <input type=\"text\" name=\"time\" value=\""+dt2tmstr(dt_datetime)+
    "\" size=\"8\" maxlength=\"8\"></font></td></tr>\n</form>\n" +
    "</table>\n" +
    "</tr>\n</td>\n</table>\n" +
    "</body>\n" +
    "</html>\n";

  var vWinCal = window.open("", "Calendar", 
                            "width=200,height=250,status=no,resizable=yes,top=200,left=200");
  vWinCal.opener = self;
  var calc_doc = vWinCal.document;
  calc_doc.write (str_buffer);
  calc_doc.close();
}

// datetime parsing and formatting routines. modify them if you wish other datetime format
function str2dt (str_datetime) {
  //var re_date = /^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/;
  var re_date = /^(\d+)\-(\d+)\-(\d+)$/;
  if (!re_date.exec(str_datetime))
    return alert("Invalid Datetime format: "+ str_datetime);
  //return (new Date (RegExp.$3, RegExp.$2-1, RegExp.$1, RegExp.$5, RegExp.$6));
  return (new Date (RegExp.$3, RegExp.$2-1, RegExp.$1));
}

function dt2dtstr (dt_datetime) {
  var dayno   = dt_datetime.getDate();
  var monthno = dt_datetime.getMonth()+1;
  if(dayno < 10)   { dayno = '0' + dayno; }
  if(monthno < 10) { monthno = '0' + monthno; }
  return new String(dayno + '-' + monthno + '-' + dt_datetime.getFullYear());
  //  return (new String (
  //  dt_datetime.getDate()+"-"+(dt_datetime.getMonth()+1)+"-"+dt_datetime.getFullYear()+" "));
}

function dt2tmstr (dt_datetime) {
  return (new String (
    dt_datetime.getHours()+":"+dt_datetime.getMinutes()+":"+dt_datetime.getSeconds()));
}

/* end calendar picker code */


/* insert chars at caret (cursor) from http://pastebin.parentnode.org/78 */

function insertAtCaret(obj, text) {
  if(document.selection) {
    obj.focus();

    var orig = obj.value.replace(/\r\n/g, "\n");
    var range = document.selection.createRange();

    if(range.parentElement() != obj) {
      return false;
    }

    range.text = text;
    var actual = tmp = obj.value.replace(/\r\n/g, "\n");

    for(var diff = 0; diff < orig.length; diff++) {
      if(orig.charAt(diff) != actual.charAt(diff)) break;
    }

    for(var index = 0, start = 0; 
        tmp.match(text) 
          && (tmp = tmp.replace(text, "")) 
          && index <= diff; 
        index = start + text.length
        ) {
      start = actual.indexOf(text, index);
    }
  } else if(obj.selectionStart) {
    var start = obj.selectionStart;
    var end   = obj.selectionEnd;

    obj.value = obj.value.substr(0, start) 
      + text 
      + obj.value.substr(end, obj.value.length);
  }
		
  if(start != null) {
    setCaretTo(obj, start + text.length);
  } else {
    obj.value += text;
  }
}
	
function setCaretTo(obj, pos) {
  if(obj.createTextRange) {
    var range = obj.createTextRange();
    range.move('character', pos);
    range.select();
  } else if(obj.selectionStart) {
    obj.focus();
    obj.setSelectionRange(pos, pos);
  }
}

/* insertatcaret end */

/* some code to facilitate use of insertAtCaret */

function insAtId(fieldid, str) {
  var field = document.getElementById(fieldid);
  insertAtCaret(field,str);
  return false;
}

/* character insertion bar using insAtId/insertAtCaret */

function charbar(options) {
  // Creates a button bar that inserts text in a designated text
  // field; unlike makebar this uses insAtId/insertatcaret and does
  // not use graphical icons.
  //
  // The 'bar' itself consists of the separate buttons, each of which
  // is contained in a <span> with user-specified class name and/or
  // style.  To group the buttons in a sensible manner, the call to
  // makebar() should preferably enclosed in another <div> or <span>.

  // 'options' is an object with the properties:
  //   motherID     where the newly created nodes should be appendChild'ed
  //   targetID     where the text inserts should go (prolly a text or textarea)
  //   buttonStyle  (opt) a style to be inserted with each button
  //   buttonClass  (opt) classname for each button
  // The remainder of the arguments should be Array objects with each containing 
  // the elements:
  //   (icon, inserttext, tooltip) icon text, text to be inserted, tooltip

  motherID    = options.motherID || false;
  targetID    = options.targetID || false;
  buttonStyle = options.buttonStyle || false;
  buttonClass = options.buttonClass || false;

  //var target = document.getElementById(targetID);

  for(var i=1; i < arguments.length; i++) {
    var icon    = untity(arguments[i][0]);
    var instext = untity(arguments[i][1]);
    var tooltip = arguments[i][2];

    var elm = document.createElement('span');
    var txt = document.createTextNode(icon);
    elm.appendChild(txt);
    // doesn't work in IE6: elm.setAttribute('class', buttonClass);
    elm.className = buttonClass;
    elm.instext = instext; // solves a context problem in onclick function ref
    elm.onclick = function(evt) { insAtId(targetID,this.instext) };
    elm.title = tooltip;
    // TODO set style... will simply setting the attribute work in IE?

    // This is mainly for IE6 which doesn't do :hover
    elm.onmouseover = function() { this.style.background = 'lightblue'; }
    elm.onmouseout  = function() { this.style.background = ''; }

    mother = document.getElementById(motherID);
    mother.appendChild(elm);
  }

  return;
}

