// Functions for use with the GLS Avenue system
// 2004/10/12

function findObject(name) {
  // find an object by name or id
  var obj = document[name];
  var i;
  if (!obj && document.all) {
    obj=document.all[name];
  }
  for (i=0; !obj && i<document.forms.length; i++) {
    obj=document.forms[i][name];
  }
  if (!obj && document.layers) {
    for(i=0; !obj && i<document.layers.length;i++) {
      obj=document.layers[i].document[name];
    }
  }
  if (!obj && document.getElementById) {
    obj=document.getElementById(name);
  }
  return obj;
}

function getEventSource(event) {
  // get the source of an event
  var eventSource;
  if (! event) {
    event = window.event;
  }
  if (event) {
    if (event.target) {
      eventSource = event.target;
    } else if (event.srcElement) {
      eventSource = event.srcElement;
    }
    if (eventSource && eventSource.nodeType==3) {
      // From quirksmode: apparent Safari bug: 
      eventSource = eventSource.parentNode;
    }
  }
  return eventSource;
}

function getEventSourceContainer(event) {
  // get the TEXTAREA or ContentEditable DIV containing the source of an event
  var eventSource = getEventSource(event);
  var el = eventSource;
  var i=100;
  while (i-- >0 && el && el.tagName != 'TEXTAREA'
         && !(el.tagName == 'DIV' && isContentEditableDiv(el))) {
    el = el.parentNode;
  }
  if (el && i>0) {
    eventSource = el;
  }
  return eventSource;
}
  

var formChanged;

function registerChange() {
  // register a change in a form input value
  formChanged = true;
}

function registerReset() {
  // reset change registrations
  formChanged = false;
}

function checkForUnsavedChanges() {
  // Check whether a form contains unsaved changes (inputs that have been 
  // changed), before f.i. following a link to another page
  if (formChanged) {
    if (typeof(langDiscardChangesWarning) == 'undefined') {
      langDiscardChangesWarning = 
        'Changes have not yet been commited. Discard changes?';
    }
    return confirm(langDiscardChangesWarning);
  } else {
    return true;
  }
}

function checkHtmlCheckboxes() {
  if (typeof(langHtmlCheckboxWarning) == 'undefined') {
    langHtmlCheckboxWarning = 'The HTML checkbox is used to indicate whether the corresponding input field CURRENTLY contains HTML-code. If the checkbox is unchecked, the contents will be HTML-encoded for display, so that viewers will see the exact textyou entered. If the checkbox is checked, the system will make no further effort to turn the contents into HTML for display, since it already is HTML: viewers will see your code as interpreted by their browser. Are you sure you want to check/uncheck this box?';
  }
  return confirm(langHtmlCheckboxWarning);
}

function confirmDeleteAndCheck() {
  // Check whether the current form contains unsaved instructions, AS WELL AS
  // whether the user really indended to activate a link to a delete action
  if (formChanged) {
    if (typeof(langDiscardChangesWarning) == 'undefined') {
      langDiscardChangesWarning = 
        'Changes have not yet been commited. Discard changes?';
    }
    if (! confirm(langDiscardChangesWarning)) {
      return false;
    }
  }

  if (typeof(langDeleteWarning) == 'undefined') {
    langDeleteWarning = 'Are you sure you wish to delete this item?';
  }
  return(confirm(langDeleteWarning));
}

function setToolbarButton(name, state) {
  var btn=findObject(name);
  if (btn.disabled && state) {
    btn.disabled=false;
    //btn.style.display='inline';
    btn.onclick=btn.storeOnClick;
    btn.onmousedown=btn.storeOnMouseDown;
    btn.onmouseup=btn.storeOnMouseUp;
    btn.onmouseout=btn.storeOnMouseOut;
    btn.src=btn.storeSrc;
  } else if (!btn.disabled && !state) {
    btn.disabled=true;
    //btn.style.display='none';
    btn.storeOnClick=btn.onclick;
    btn.storeOnMouseDown=btn.onmousedown;
    btn.storeOnMouseUp=btn.onmouseup;
    btn.storeOnMouseOut=btn.onmouseout;
    btn.storeSrc=btn.src;
    btn.onclick=null;
    btn.onmousedown=null;
    btn.onmouseup=null;
    btn.onmouseout=null;
    btn.src=btn.src.replace(/(_pressed|_disabled)?\.gif/, '_disabled.gif');
  }
}

var cacheActiveElement, cacheSelectedRange;
var buttonBarActive = false;

function setToolbarButtons() {
  // set buttons of the toolbar to states determined by the current editfield
  // As of yet, the only affected button is the 'insertNextPart' button,
  // which should only be enabled for fields having the allowMultipleParts
  // attribute
  if (cacheActiveElement) {
    setToolbarButton('InsertNextPart', cacheActiveElement.allowMultipleParts 
        || (cacheActiveElement.getAttribute
        && cacheActiveElement.getAttribute('allowMultipleParts'))
        || (cacheActiveElement.hasAttribute
        && cacheActiveElement.hasAttribute('allowMultipleParts')));
    setToolbarButton('JustifyLeft', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('JustifyCenter', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('JustifyRight', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Copy', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Cut', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Paste', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Del', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Numbering', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Bullets', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Indent', cacheActiveElement.tagName!='TEXTAREA');
    setToolbarButton('Outdent', cacheActiveElement.tagName!='TEXTAREA');
  }
}

function storeCacheActiveElement(event) {
  // Store the active element and the position of the selection or
  // insertion point, so they is available when handling pressed 
  // toolbar button (normally, the active selection would then 
  // consist of the toolbar button itself, which is not very useful).
  // This function is normally called during the handling  of the
  // onBlur event: however, on IE it is called during the handling of
  // the onBeforeDeactivate event, as the position of the insertion
  // point is no longer available at onBlur.
  var cacheActiveElement2 = getEventSourceContainer(event);
  if (cacheActiveElement2) {
    cacheActiveElement = cacheActiveElement2;
    if (document.selection) {
      cacheSelectedRange = document.selection.createRange();
    } else {
      cacheSelectedRange = false;
    }
  }
}

var delayedHideToolbarId;
function delayedHideToolbar(event) {
  // When leaving a contentEditable DIV, hide the toolbar
  // When leaving a contentEditable DIV to click on the toolbar,
  // don't hide it, but remember the previous selection/insertion point
  if (cacheActiveElement && cacheActiveElement.tagName!='TEXTAREA') {
    cancelHideToolbar();
    formChanged = true; // usually doesn't work in onChange handler
  }
  if (event && event.toElement) {
    // IE only: check whether we're moving towards another contenteditable Div
    // If so, don't hide the toolbar
    // Note that if we're moving between elements in the same contentEditable
    // Div, the onfocus event on that Div doesn't trigger, and the onClick
    // event occasionally doesn't bubble upwards, so this helps.
    var el = event.toElement;
    while(el && !isContentEditableDiv(el)) {
      el = el.parentNode;
    }
    if (el) {
      cancelHideToolbar();
      return true;
    }
  }

  if (!delayedHideToolbarId) {
    delayedHideToolbarId = window.setTimeout('hideToolbar()', 200);
  }
  return true;
}

function storeCacheActiveElementAndHideToolbar(event) {
  storeCacheActiveElement(event);
  delayedHideToolbar(event);
}

function cancelHideToolbar() {
  if (delayedHideToolbarId) {
    window.clearTimeout(delayedHideToolbarId);
    delayedHideToolbarId = false;
  }
  return true;
}

function delayedCancelHideToolbar() {
  cancelHideToolbar();
  window.setTimeout('cancelHideToolbar()', 100);
}


function hideToolbar() {
  // Hide the toolbar. Note that this happens .2 seconds after an onblur
  // event on a contenteditable DIV or TEXTAREA, and is canceled if
  // an onfocus event occurs on a contenteditable DIV or TEXTAREA, or 
  // an onclick event the toolbar itself
  buttonBarActive = false;
  var buttonBar = findObject('buttonbar');
  if (buttonBar) {
    buttonBar.style.visibility = 'hidden';
  }
  //cacheActiveElement = false;
  //cacheSelectedRange = false;
}

function showToolbar(event) {
  if (arguments.length>=2 && !arguments[0]) {
    cacheActiveElement = arguments[1];
  } else {
    cacheActiveElement = getEventSourceContainer(event);
    if (cacheActiveElement && document.selection) {
      cacheSelectedRange = document.selection.createRange();
    } else {
      cacheSelectedRange = false;
    }
  }
  if (cacheActiveElement && cacheActiveElement.tagName=='TEXTAREA') {
    var name=cacheActiveElement.name;
    var el2 = findObject(cacheActiveElement.name+'Html');
    if (!(el2 && el2.checked)) {
      return true;
    }
  }
  delayedCancelHideToolbar();
  buttonBarActive = true;
  var buttonBar = findObject('buttonbar');
  if (buttonBar) {
    buttonBar.style.visibility = 'visible';
    setToolbarButtons();
  }
  return true;
}



function restoreSelection() {
  if (cacheActiveElement) {
    // return to last contentEditable DIV (probably left it to press button)
    //    if (document.activeElement != cacheActiveElement) {
    if (cacheActiveElement.setActive) {
      cacheActiveElement.setActive();
    } else if (cacheActiveElement.focus) {
      cacheActiveElement.focus();
    }
    if (cacheSelectedRange) {
      cacheSelectedRange.select();
    }
  }
}

function addTagsToTextArea(el, startTag, endTag) {
  // reset focus from button to textarea field:
  // important for IE fetch-selection mechanism
  el.focus();
  var selectedText, selectStart, selectEnd, selectionRange;
  if (document.selection && document.selection.createRange) {
    // IE: use document.selection
    selectionRange = document.selection.createRange();
    selectedText = selectionRange.text;
  } else if (typeof(el.selectionEnd)!='undefined') {
    // Mozilla: use el.selectionStart & el.selectionEnd
    selectedText = el.value.substring(el.selectionStart, el.selectionEnd);
  } else {
    // other browser: append tags to end of textarea and quit
    el.value = el.value + startTag + endTag;
    return;
  }
  if (! startTag) {
    // insert end tag and move to position after end tag
    selectedText = selectedText + endTag;
    selectStart = selectEnd = selectedText.length;
  } else if (! selectedText) {
    // insert start and end tag and move to position in between
    selectedText = startTag + selectedText + endTag;
    selectStart = selectEnd = startTag.length;
  } else if (startTag==selectedText.substring(0, startTag.length)
      && endTag==selectedText.substring(selectedText.length-endTag.length)) {
    // remove start and end tags and reselect resulting contents
    selectedText = selectedText.substring(
        startTag.length, selectedText.length-endTag.length);
    selectStart = 0;
    selectEnd = selectedText.length;
  } else {
    // add start and end tags and reselect resulting contents
    selectedText = startTag + selectedText + endTag;
    selectStart = 0;
    selectEnd = selectedText.length;
  }
  if (document.selection && document.selection.createRange) {
    // IE: use document.selection
    selectionRange = document.selection.createRange();
    selectionRange.text = selectedText;
    selectionRange.collapse(false);
    selectionRange.moveStart('character', selectStart-selectedText.length);
    selectionRange.moveEnd('character', selectEnd-selectedText.length);
    selectionRange.select();
  } else {
    // Mozilla: use el.selectionStart & el.selectionEnd
    var selectionStart = el.selectionStart;
    var preText = el.value.substring(0, selectionStart);
    var postText = el.value.substring(el.selectionEnd);
    el.value = preText + selectedText + postText;
    el.selectionStart = selectionStart + selectStart;
    el.selectionEnd = selectionStart + selectEnd;
  }
}

function doCommand(cmd) {
  // Perform a button action, f.i. to make the current text selection Bold
  // inside a contentEditable DIV
  cancelHideToolbar();
  restoreSelection();
  if (!cacheActiveElement) {
    // window.alert('No element selected');
  } else if (cacheActiveElement.tagName=='TEXTAREA') {
    // TEXTAREA field
    switch(cmd) {
    case 'Bold':
      addTagsToTextArea(cacheActiveElement, '<b>', '</b>');
      break;
    case 'Italic':
      addTagsToTextArea(cacheActiveElement, '<i>', '</i>');
      break;
    case 'Underline':
      addTagsToTextArea(cacheActiveElement, '<u>', '</u>');
      break;
    default:
      window.alert("'"+cmd+"' not implemented in PlainEdit mode");
      break;
    }
  } else if (document.selection) {
    // IE ContentEditable field
    document.execCommand(cmd, false, null);
  } else {
    // Mozile ContentEditable field
    switch(cmd) {
    case 'Bold':
      window.getSelection().toggleTextStyle('font-weight', 'bold', '400');
            break;
    case 'Italic':
      window.getSelection().toggleTextStyle('font-style', 'italic', 'normal');
            break;
    case 'Underline':
      window.getSelection().toggleTextStyle('text-decoration', 'underline', 'none');
      break;
    case 'InsertOrderedList':
      window.getSelection().toggleListLines("OL", "UL");
      break;
    case 'InsertUnorderedList':
      window.getSelection().toggleListLines("UL", "OL");
      break;
    case 'Indent':
      window.getSelection().indentLines();
      break;
    case 'Outdent':
      window.getSelection().outdentLines();
      break;
    case 'JustifyLeft':
      window.getSelection().styleLines("text-align", "left");
      break;
    case 'JustifyRight':
      window.getSelection().styleLines("text-align", "right");
      break;
    case 'JustifyCenter':
      window.getSelection().styleLines("text-align", "center");
      break;
    case 'Copy':
      window.getSelection().copy();
      break;
    case 'Cut':
      window.getSelection().cut();
      break;
    case 'Paste':
      var clipboard = mozilla.getClipboard();
      // HTML comes first.
      var text = clipboard.getData(MozClipboard.TEXT_FLAVOR);
      if (text) {
        window.getSelection().paste();
      } else {
        callDialog('pastetext', '36em', '24em');
      }
      break;
    case 'Delete':
      //window.getSelection().deleteSelection();
      window.getSelection().deleteFromDocument();
      break;

    default:
      window.alert("'"+cmd+"' not implemented for Mozile HTMLEdit mode");
      break;
    }
  }
}

function dump_props(obj) {
  // debug routine: dump properties of object. Probably IE only
  var result = "";
  for (var i in obj) {
    if (String(obj[i]).length <= 30) {
      result += i + " = " + obj[i] + "\n";
    }
  }
  return result;
}



function storeEditableRegions() {
// This function transfers the contents of contentEditable DIV areas to
// hidden form fields. It is part of the HTML-Edit system which is used 
// when browsers which can handle contentEditable fields are detected
// (currently only MSIE5.5 or above).

  // Get form to be worked with

  var frm;
  if (arguments.length>0) {
    frm = arguments[0];
  } else {
    frm = document.forms["editform"];
  }

  // Search for contentEditable DIV's with nonempty names
  var els = frm.getElementsByTagName("DIV");
  for (var i=0; i<els.length; i++) {
    var el = els[i];
    var name = el.name;
    if (!name) {
      name = el.id;
    }
    if (name && isContentEditableDiv(el)) {
      // Fetch and adapt contents of el (removing anchor icons etc.)
      var text = el.innerHTML;
      text = text.replace(/<a name=[^>]*> *<\/a>/ig, '');
      text = text.replace(/<img[^>]*anchorImage[^>]*>/ig, '');
      text = text.replace(/(<br>$|<br \/>| |&nbsp;)+$/ig, '');
      // Transfer the content of el to a HIDDEN form input with the same name
      var el1;
      if (frm[name]) {
        el1 = frm[name];
      } else {
        for (var j=0; j<frm.elements.length; j++) {
          if (frm.elements[j].name==name) {
            el1=frm.elements[j];
            break;
          }
        }
      }
      if (el1) {
        // If such an element already exists (presumably as a result of a 
        // previous call to this routine), update its contents.
        el1.value = text;
      } else {
        // Otherwise, create it, and the corresponding xxxHtml element
        var el2 = document.createElement('input');
        el2.setAttribute('type', 'hidden');
        el2.setAttribute('name', name);
        el2.value = text;
        frm.appendChild(el2);
        el2 = document.createElement('input');
        el2.setAttribute('type', 'hidden');
        if (name.match(/\]$/)) {
          el2.setAttribute('name', name.replace(/\]$/, 'Html]'));
        } else {
          el2.setAttribute('name', name+'Html');
        }
        el2.value = 'checked';
        frm.appendChild(el2);
      }
    }
  }
}

function isEmpty(inputObj) {
  // return true if field is empty
  switch(inputObj.type) {
    case "text":
    case "textarea":
    case "hidden":
    case "file":
    case "password":
      return (inputObj.value == "");
    case "select-one":
      if (inputObj.selectedIndex < 0) {
        return true;
      } else {
        var optObj = inputObj.options[inputObj.selectedIndex];
        return ((typeof(optObj.value)=="undefined" ? optObj.text : optObj.value)=="");
      }
    case "select-multiple":
      return (inputObj.selectedIndex < 0);
    case "checkbox":
    case "radio":
      return (! inputObj.checked);
    default:
      if (inputObj.length) { // radiobutton group
        for(var i=0; i<inputObj.length; i++) {
          if (inputObj[i].checked) {
            return false;
          }
        }
        return true;
      }
      return false;
  }
}

function checkRequired(frm, fields, i0) {
  var missing = new Array;
  for(var i=i0; i<fields.length; i++) {
    var inputName = fields[i];
    var el;
    if (frm[inputName]) {
      el = frm[inputName];
    } else {
      for (var j=0; j<frm.elements.length; j++) {
        if (frm.elements[j].name==inputName) {
          el=frm.elements[j];
          break;
        }
      }
    }
    if (typeof(el)=="undefined") {
      var els = document.getElementsByName(inputName);
      el = els[0];
    }
    if (typeof(el)=="undefined") {
      window.alert("Checking for nonexisting field '" + inputName  + "'\n"
          + "(programming error?)");
    } else {
      if (isEmpty(el)) {
        var inputLongName = inputName;
        if (typeof(el.title)!='undefined' && el.title.match(/\S/)) {
          inputLongName = el.title;
        } else if (el.length && el[0] && typeof(el[0].title)!='undefined'
            && el[0].title.match(/\S/)) {
          inputLongName = el[0].title;
        }
        // push() doesn't work in Mac/IE
        missing[missing.length]=inputLongName;
      }
    }
  }
  return missing;
}

function checkForm() {
  // This routine performs all actions necessary before submitting a form,
  // including tranferring all contentEditable DIV's to HIDDEN form inputs
  // and checking for required fields.
  // Syntax: checkForm(formvar, 'requiredField1', 'requiredField2', ...)
  // The form parameter usually gets value 'this', and can be omitted if
  // the form in question is named 'editform'.

  var frm;
  var i0=0;
  if (typeof(arguments[0]) != "object") {
    frm = document.forms["editform"];
  } else {
    frm = arguments[0];
    i0 = 1;
  }
  storeEditableRegions(frm);
  var missing = checkRequired(frm, arguments, i0);
  if (missing.length>0) {
    if (missing.length>1) {
      if (typeof(langNoValuesEnteredWarning)  == 'undefined') {
        langNoValuesEnteredWarning =
            'You didn\'t enter any values for the following fields';
      }
      window.alert(langNoValuesEnteredWarning + ': ' + missing.join(", "));
    } else {
      if (typeof(langNoValueEnteredWarning)  == 'undefined') {
        langNoValueEnteredWarning = 
            'You didn\'t enter a value for the field';
      }
      window.alert(langNoValueEnteredWarning + ': ' + missing[0]);
    }
    return false;
  }
  return true;
}


var checkStampStatus = 0;
var checkStampForm;
var checkStampImage;


function checkStamp(frm, type, stamp, idfield) {
  if (checkStampStatus) {
    var res=window.confirm('Abort the check for overwriting updated files?');
    if (res && checkStampStatus) {
      checkStampStatus = 0;
      return true;
    } else {
      return false;
    }
  } else if (!stamp) {
    return true;
  } else if (typeof(frm[idfield])=='undefined') {
    return true;
  } else if (! frm[idfield].value) {
    return true;
  } else {
    checkStampStatus = 1;
    checkStampForm = frm;
    checkStampImage = new Image;
    checkStampImage.onload=checkStampOK;
    checkStampImage.onerror=checkStampError;
    checkStampImage.src = wwwroot 
        + '/index.php?action=checkstamp' + type
        + '&timestamp=' + stamp 
        + '&' + idfield+'='+frm[idfield].value
        + '&random=' + Math.random();
    return false;
  }
}

function checkStampOK() {
  checkStampStatus = 0;
  checkStampForm.submit(); // Should not trigger submit handlers
  return false;
}

function checkStampError() {
  checkStampStatus = 0;
  var res=window.confirm('Warning: item has been edited. Overwrite?');
  if (res) {
    checkStampForm.submit();
    return false;
  }
  res = window.confirm('Open changed item contents in new window?');
  if (res) {
    window.open(window.location.href);
  }
  return false;
}

function callDialog(dialog, dialogWidth, dialogHeight) {
  cancelHideToolbar();
  restoreSelection();
  if (window.showModalDialog) {
    window.showModalDialog(wwwroot+"/editor/"+dialog+".html", window,
        "dialogWidth:"+ dialogWidth + "; dialogHeight:" + dialogHeight
        + "; help: no; status: no");
  } else {
    if (dialogWidth.match(/em/i)) {
      dialogWidth=dialogWidth.replace(/[a-z]/ig, '')*18;
    } else if (dialogWidth.match(/ex/i)) {
      dialogWidth=dialogWidth.replace(/[a-z]/ig, '')*10;
    } else {
      dialogWidth=dialogWidth.replace(/[a-z]/ig, '');
    }
    if (dialogHeight.match(/em/i)) {
      dialogHeight=dialogHeight.replace(/[a-z]/ig, '')*18;
    } else if (dialogHeight.match(/ex/i)) {
      dialogHeight=dialogHeight.replace(/[a-z]/ig, '')*10;
    } else {
      dialogHeight=dialogHeight.replace(/[a-z]/ig, '');
    }
    window.open(wwwroot+'/editor/'+dialog+'.html', '_blank', ''
        + 'width='+dialogWidth+',height='+dialogHeight+','
        + 'directories=no,location=no,menubar=no,resizable=no,scrollbars=no'
        + ',status=no,personalbar=no,toolbar=0,dependent=yes'
    );
  }
}

function processDialogResultValue(resultValue) {
  var keepSelection = (arguments.length>=3 && arguments[2]);
  var el=cacheActiveElement;
  var selectionRange, el2;
  if (el.tagName=='TEXTAREA') {
    if (document.selection && document.selection.createRange) {
      // IE TextArea
      // Use selectionRange to replace selection
      selectionRange = document.selection.createRange();
      var selectionSize = (selectionRange.text ? resultValue.length : 0);
      if (keepSelection) {
        resultValue = selectionRange.text + resultValue;
        selectionSize=0;
      }
      selectionRange.text = resultValue;
      selectionRange.collapse(false);
      selectionRange.moveStart('character', -selectionSize);
      selectionRange.select();
    } else if (typeof(el.selectionEnd)!='undefined') {
      // Mozilla TextArea selection
      // use el.selectionStart & el.selectionEnd to replace selection
      var selectionStart = el.selectionStart;
      var selectionEnd = el.selectionEnd;
      var preText = el.value.substring(0, selectionStart);
      var postText = el.value.substring(selectionEnd);
      var selectedText = el.value.substring(selectionStart, selectionEnd);
      if (keepSelection) {
        resultValue = selectedText + resultValue;
      }
      el.value = preText + resultValue + postText;
      el.selectionEnd = selectionStart+resultValue.length;
      if (selectionStart==selectionEnd && !keepSelection) {
        el.selectionStart = el.selectionEnd;
      }
    } else {
      // TextArea selection for some other browser
      // Append text to end of textarea
      el.value = el.value + resultValue;
    }

  } else if (arguments.length>=2 && arguments[1] && arguments[1].outerHTML) {
    // Second function parameter is selected object. Replace as whole
    if (keepSelection) {
      arguments[1].outerHTML = arguments[1].outerHTML + resultValue;
    } else {
      arguments[1].outerHTML = resultValue;
    }

  } else if (document.selection && document.selection.createRange) {
    // IE ContentEditable DIV
    // Use selectionRange replace
    selectionRange = document.selection.createRange();
    if (keepSelection) {
      if (selectionRange.length==1) {
        el2 = selectionRange.item(0);
        selectionRange = document.body.createTextRange();
        selectionRange.moveToElementText(el2);
      }
      selectionRange.collapse(false);
    }
    if (selectionRange.length==1) {
      el2 = selectionRange.item(0);
      el2.outerHTML=resultValue;
    } else if (selectionRange.htmlText.match(/<TR/i)
        && !selectionRange.htmlText.match(/<TABLE/i)) {
      // Can't pasteHTML partial tables, so paste whole table
      el2 = selectionRange.parentElement();
      while(el2 && el2.tagName!='TABLE') {
        el2 = el2.parentNode;
      }
      if (el2) {
        el2.outerHTML=resultValue;
      }
    } else {
      selectionRange.pasteHTML(resultValue);
    }
    // pasteHTML loses selection, so can't select new text
    // also, have to reset onclick handler for newly created objects
    var els2 = el.childNodes;
    for (i=0; i<els2.length; i++) {
      el2 = els2[i];
      if (el2.tagName && ! el2.onclick) {
        els2[i].onclick = delayedCancelHideToolbar;
      }
      if (el2.tagName && ! el2.onfocus) {
        els2[i].onfocus = showToolbar;
      }
    }

  } else if (window.getSelection) {
    // Mozilla ContentEditable DIV
    var frag = document.createElement('DIV');
    frag.innerHTML=resultValue;
    var selection = window.getSelection();
    if (! keepSelection && selection && ! selection.isCollapsed) {
      //selection.deleteSelection();
      selection.deleteFromDocument();
    }
    selectionRange = selection.getEditableRange(true);
    el2 = frag.firstChild;
    while(el2) {
      selectionRange.lastInsertionPoint.insertNode(el2);
      selectionRange.__clearTextBoundaries(); //cleanup code from Mozile
      selectionRange.setEndAfter(el2);
      el2 = frag.firstChild;
    }
    if (keepSelection) {
      selectionRange.selectInsertionPoint(selectionRange.lastInsertionPoint);
    }
    selectionRange.__clearTextBoundaries(); //cleanup code from Mozile
    selection.selectEditableRange(selectionRange);
  } else {
    // ContentEditable DIV on other browser
    window.alert('Sorry, interacting with ContentEditable DIVs has not yet been implemented for your browser');
  }

}

function getSelectionHtml() {
  var el = cacheActiveElement;
  if (document.selection) {
    var selectionRange = document.selection.createRange();
    if (selectionRange.htmlText) {
      return selectionRange.htmlText;
    } else if (selectionRange.length==1 && selectionRange.item(0).outerHTML){
      return selectionRange.item(0).outerHTML;
    } else if (selectionRange.text) {
      return selectionRange.text;
    } else {
      return '';
    }
  } else if (typeof(el.selectionEnd)!='undefined') {
    return el.value.substring(el.selectionStart, el.selectionEnd);
  } else if (window.getSelection) {
    var frag = document.createElement('DIV');
    frag.appendChild(window.getSelection().getEditableRange().cloneContents());
    return frag.innerHTML;
  } else {
    return '';
  }
}

function getSelectedNode() {
  // Find element with specified tag (or one of specified tags) and attribute
  // that is contained in or overlapping selection, select it, and return it. 
  // Arguments are tagnames, possibly postfixed by ':attributename' to
  // indicate that only tags with the specified attribute are to be considered.
  if (!cacheActiveElement || !cacheActiveElement.getElementsByTagName) {
    return false;
  }
  var els = new Array;
  var i, j, k, tagName, attribute, el, el2;
  // Get matching tags
  for(i=0; i<arguments.length; i++) {
    var arg=arguments[i];
    var argSpec = arg.split(':');
    tagName = argSpec[0];
    var attrSpec = new Array;
    for(k=1; k<argSpec.length; k++) {
      if (argSpec[k]) {
        attrSpec[attrSpec.length] = argSpec[k].split('=');
        if (document.selection && attrSpec[attrSpec.length-1][0]=='class') {
          attrSpec[attrSpec.length-1][0]='className';
        }
      }
    }

    var els2 = cacheActiveElement.getElementsByTagName(tagName);
    if (els2) {
      for(j=0; j<els2.length; j++) {
        el2 = els2[j];
        var ok=true;
        for(k=0; k<attrSpec.length && ok; k++) {
          var attrName = attrSpec[k][0];
          if (attrSpec[k].length==1) {
            ok = ok && (
                (el2.getAttribute && el2.getAttribute(attrName))
                || (el2.hasAttribute && el2.hasAttribute(attrName)));
          } else {
            var attrVal = attrSpec[k][1];
            ok = ok && (
                (el2.getAttribute && el2.getAttribute(attrName)==attrVal)
                || (el2.hasAttribute && el2.hasAttribute(attrName)==attrVal));
          }
        }
        if (ok) {
          els[els.length]=el2;
        }
      }
    }
  }
  if (els.length==0) {
    return false;
  }
  // Get selected range
  var selectionRange, el2Range;
  if (document.selection) {
    selectionRange = document.selection.createRange();
    if (selectionRange.length==1) {
      el = selectionRange.item(0);
      selectionRange = document.body.createTextRange();
      selectionRange.moveToElementText(el);
      // selects content of element, not element as a whole. If I could
      // find a way to do the latter instead, it would make some things a
      // lot simpler.

    }
    el2Range = document.body.createTextRange();
  } else if (window.getSelection) {
    selectionRange = window.getSelection().getEditableRange();
    el2Range = document.createRange();
  } else {
    return false;
  }
  el = false;
  var done = false;
  for(i=0; i<els.length && !done; i++) {
    el2 = els[i];
    // check whether element is contained in or overlapping selection
    // Note that IE and Mozilla have small differences&reversals in syntax
    if (document.selection) {
      el2Range.moveToElementText(el2);
      if (selectionRange.compareEndPoints('StartToStart',el2Range)<=0 &&
          selectionRange.compareEndPoints('EndToEnd', el2Range)>=0) {
        el = el2; // el2 is contained in selection
        done = true;
      } else if (
          selectionRange.compareEndPoints('StartToEnd', el2Range)<=0 &&
          selectionRange.compareEndPoints('EndToStart', el2Range)>=0) {
        el = el2; // el2 overlaps selection
      }
    } else {
      el2Range.selectNode(el2);
      if (selectionRange.compareBoundaryPoints(Range.START_TO_START,el2Range)
          <=0 &&
          selectionRange.compareBoundaryPoints(Range.END_TO_END, el2Range)>=0)
          {
        el = el2; // el2 is contained in selection
        done = true;
      } else if (
          selectionRange.compareBoundaryPoints(Range.END_TO_START, el2Range)<=0
          &&
          selectionRange.compareBoundaryPoints(Range.START_TO_END, el2Range)>=0
          ) {
        el = el2; // el2 overlaps selection
      }
    }
  }
  setSelectedNode(el);
  return el;
}

function setSelectedNode(el) {
    // set selection to element
  var selectionRange;
  if (el) {
    if (window.document.selection) {
      selectionRange=document.body.createTextRange();
      selectionRange.moveToElementText(el);
      selectionRange.select();
    } else {
      selectionRange = document.createRange();
      selectionRange.selectNode(el);
      selectionRange.__clearTextBoundaries(); //cleanup code from Mozile
      window.getSelection().selectEditableRange(selectionRange);
    }
  }
}

function isContentEditableDiv(el) {
  return (el.contentEditable && el.contentEditable != 'inherit') 
      || (el.getAttribute && el.getAttribute('contentEditable')
      && el.getAttribute('contentEditable')!='inherit')
      || (el.hasAttribute && el.hasAttribute('contentEditable')
      && el.hasAttribute('contentEditable')!='inherit');
}

function initContentEditableDivs() {
  // Get form to be worked with
  // Search for contentEditable DIV's with nonempty names
  var buttonBar = findObject('buttonbar');
  var el, el2, name;
  if (buttonBar) {
    buttonBar.style.visibility = 'hidden';
    buttonBar.onclick = delayedCancelHideToolbar;
  }
  var els = document.getElementsByTagName("DIV");
  var i,j;
  for (i=0; i<els.length; i++) {
    el = els[i];
    name = el.name;
    if (!name) {
      name = el.id;
    }
    if (name && isContentEditableDiv(el)) {
      if (! el.innerHTML.match(/\S/)) {
        el.innerHTML = '<br />';
      }
      if (! el.tabindex) {
        el.tabindex = 0;
      }
      if (document.selection) {
        el.onbeforedeactivate = storeCacheActiveElement;
        el.onblur = delayedHideToolbar;
      } else {
        el.onblur = storeCacheActiveElementAndHideToolbar;
      }
      el.onclick = delayedCancelHideToolbar;
      el.onfocus = showToolbar;
      if (el==document.activeElement) {
        showToolbar(false, el);
      }
      var els2 = el.getElementsByTagName("OBJECT");
      for (j=0; j<els2.length; j++) {
        el2 = els2[j];
        el2.onfocus = showToolbar;
        if (el2==document.activeElement) {
          showToolbar(false, el);
        }
      }
      els2 = el.getElementsByTagName("A");
      for (j=0; j<els2.length; j++) {
        el2 = els2[j];
        if (el2.name && ! el2.innerHtml) {
          el2.innerHTML = '<img id="anchorImage" src="'+wwwroot+'/images/anchor.gif">';
        }
      }
    }
  }
  els = document.getElementsByTagName("TEXTAREA");
  for (i=0; i<els.length; i++) {
    el = els[i];
    name = el.name;
    if (!name) {
      name = el.id;
    }
    if (findObject(name+'Html')) {
      if (document.selection) {
        el.onbeforedeactivate = storeCacheActiveElement;
        el.onblur = delayedHideToolbar;
      } else {
        el.onblur = storeCacheActiveElementAndHideToolbar;
      }
      el.onfocus = showToolbar;
      if (el==document.activeElement) {
        showToolbar(false, el);
      }
    }
  }
}

function showPreview() {
  // This routine performs all actions necessary to generate a preview
  // Basically, it fakes a form submission, suitably adjusted

  var frm, actionValue;
  var i0=0;
  if (typeof(arguments[0]) != "object") {
    frm = document.forms["editform"];
  } else {
    frm = arguments[0];
    i0++;
  }
  if (typeof(arguments[i0]) != 'string') {
    actionValue = frm.elements["action"].value.replace(/^submit/, "preview");
  } else {
    actionValue = arguments[i0];
    i0++;
  }
  storeEditableRegions(frm);

  var oldAction = frm.attributes 
      ? frm.attributes.getNamedItem("action").nodeValue 
      : frm.getAttribute("action");
  var oldActionValue = frm.elements["action"].value;
  //var oldMethod = frm.getAttribute("method");
  var oldTarget = frm.getAttribute("target");
  var oldEnctype = frm.getAttribute("enctype");

  if (frm.attributes) {
    frm.attributes.getNamedItem("action").nodeValue = wwwroot+"/index.php";
  } else {
    frm.setAttribute("action", wwwroot + "/index.php");
  }
  frm.elements["action"].value = actionValue;
  //frm.setAttribute("method", "get");
  frm.setAttribute("target", "_blank");
  frm.setAttribute("enctype", "");

  frm.submit();

  if (frm.attributes) {
    frm.attributes.getNamedItem("action").nodeValue = oldAction;
  } else {
    frm.setAttribute("action", oldAction);
  }
  frm.elements["action"].value = oldActionValue;
  //frm.setAttribute("method", oldMethod);
  frm.setAttribute("target", oldTarget);
  frm.setAttribute("enctype", oldEnctype);

  return false;
}

function prepCommand() {
// left over from prevous versions.
}

// Functions to manipulate TEXTAREA's

function doBBCode(tag, isSmiley) {
// implement phpMyAdmin's BBCode buttons (sort of)
  if (typeof(bbCodeField)=='undefined') {
    if (document.selection) {
      var selectionRange = document.selection.createRange();
      if (selectionRange && selectionRange.parentElement
          && selectionRange.parentElement.tagName == 'TEXTAREA') {
        bbCodeField = selectionRange.parentElement;
      }
    }
  }
  if (typeof(bbCodeField)=='undefined') {
    els = document.getElementsByTagName('TEXTAREA');
    if (els.length==0) {
      return;
    }
    bbCodeField = els[0];
  }
  if (typeof(isSmiley)!='undefined' && isSmiley) {
    addTagsToTextArea(bbCodeField, '', tag);
  } else {
    addTagsToTextArea(bbCodeField, '['+tag+']', '[/'+tag+']');
  }
}


function setBBCodeField(el) {
// Note active textarea field for later use with BBCode buttons
  bbCodeField = el;
}

// Preload all images indicated by 'preloadSrc=xxx' attributes in IMG tags
// The template-engine has transformed these attributes in a call to
// preloadImages2
var preloadedImages2 = new Array();
var preloadedSrcs2 = new Array();
function preloadImages2() {
  if (arguments.length>0 && document.images) {
    for(var i=0; i<arguments.length; i++) {
      if (arguments[i]) {
        var j = preloadedSrcs2.length;
        preloadedSrcs2[j] = arguments[i];
      }
    }
    window.setTimeout('preloadImages2b()', 200); // Timing sort-of 'body onLoad'
  }
}

function preloadImages2b() {
  if (preloadedSrcs2.length>preloadedImages2.length) {
    for(var i =preloadedImages2.length; i<preloadedSrcs2.length; i++) {
      preloadedImages2[i] = new Image;
      preloadedImages2[i].src = preloadedSrcs2[i];
    }
  }
}

// Display a different part of a parted field
function showPart(fieldname, delta, maxCount) {
  var partIdElement = findObject(fieldname+'PartId');
  var oldPartId = parseInt(partIdElement.innerHTML);
  var oldPart = findObject(fieldname+'Part'+oldPartId);
  var newPartId = oldPartId + delta;
  var newPart = findObject(fieldname+'Part'+newPartId);
  if (oldPart && newPart) {
    var oldPart_style = (document.layers)?oldPart:oldPart.style;
    oldPart_style.display = 'none';
    var newPart_style = (document.layers)?newPart:newPart.style;
    newPart_style.display = 'block';
    partIdElement.innerHTML = newPartId;
    var prevPart = findObject(fieldname+'PartPrev');
    if (prevPart) {
      var prevPart_style = (document.layers)?prevPart:prevPart.style;
      prevPart_style.display = (newPartId<=1 ? 'none' : 'inline');
    }
    var nextPart = findObject(fieldname+'PartNext');
    if (nextPart) {
      var nextPart_style = (document.layers)?nextPart:nextPart.style;
      nextPart_style.display = (newPartId>=maxCount ? 'none' : 'inline');
    }
  }
}

