// Functions for use with the GLS Avenue system
// 2008/08/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 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;
}

// Functions to check for missing form fields

function isEmpty(inputObj) {
  // This function returns true if the input field is empty
  // Once we are sure of the getFieldValue function
  // this code can be replaced by
  //   var value=getFieldValue(inputObj);
  //   if (typeof(value)=='undefined') {
  //     return true;
  //   } else {
  //     return value=='';
  //   }
  if (typeof(inputObj)=='string') {
    var el=findObject(inputObj);
    if (!el) {
      window.alert(inputObj);
    }
    inputObj = el;
  }
  // return true if field is empty
  switch(typeof(inputObj.type)=='undefined'?'':inputObj.type) {
    case "text":
    case "textarea":
    case "hidden":
    case "file":
    case "password":
      return (inputObj.value==="");
    case "select-one":
      // If nothing is selected, counts as empty
      if (inputObj.selectedIndex < 0) {
        return true;
      }
      // If selected object has value != "", counts as nonempty.
      // Unfortunately, if optObj.value="", on IE6 this mayindicate that
      // the option has either no value attribute or an empty value
      // attribute, with no way to distinguish between the two,
      // so this only works one way
      var optObj = inputObj.options[inputObj.selectedIndex];
      if (typeof(optObj.value)!="undefined") {
        if (optObj.value) {
          return false;
        }
      }
      // If a visibly empty option was selected, counts as empty
      if (optObj.text==="") {
        return true;
      }
      // If the first element was selected, and it has text but no
      // (or an empty) value attribute, counts as empty
      if (inputObj.selectedIndex===0) {
        return true;
      }
      return false;
    case "select-multiple":
      return (inputObj.selectedIndex < 0);
    case "checkbox":
    case "radio":
      return (! inputObj.checked);
    default:
      if (typeof(inputObj.length)=='undefined') {
        return false;
      }
      // radiobutton group, or multiple fields with the same name
      for(var i=0; i<inputObj.length; i++) {
        if (typeof(inputObj[i])=='object') {
          if (! isEmpty(inputObj[i])) {
            return false;
          }
        }
      }
      return true;
  }
}

function getFieldValue(inputObj) {
  // This function returns the value of a form field
  var i, el, values, optObj;
  if (typeof(inputObj)=='string') {
    el=findObject(inputObj);
    if (!el) {
      window.alert(inputObj);
    }
    inputObj = el;
  }
  switch(typeof(inputObj.type)=='undefined'?'':inputObj.type) {
    case "text":
    case "textarea":
    case "hidden":
    case "file":
    case "password":
      return inputObj.value;
    case "select-one":
      // If nothing is selected, counts as empty
      if (inputObj.selectedIndex < 0) {
        return '';
      }
      // If selected object has value != "", use that value
      // Unfortunately, if optObj.value="", on IE6 this may indicate that
      // the option has either no value attribute or an empty value
      // attribute, with no way to distinguish between the two,
      // so this only works one way. To compensate, we designate that a
      // first element with no value set counts as empty
      optObj = inputObj.options[inputObj.selectedIndex];
      if (typeof(optObj.value)!="undefined") {
        if (optObj.value || inputObj.selectedIndex===0) {
          return optObj.value;
        }
      }
      // Use object text as value
      return optObj.text;
    case "checkbox":
    case "radio":
      return inputObj.checked ? inputObj.value : undefined;
    case "select-multiple":
      if (inputObj.selectedIndex<0) {
        return undefined;
      }
      values=new Array();
      for(i=0; i<inputObj.options.length; i++) {
        optObj = inputObj.options[i];
        if (optObj.selected) {
          if (typeof(optObj.value)!="undefined") {
            if (optObj.value || i===0) {
              values.push(optObj.value);
              continue;
            }
          }
          values.push(optObj.text);
        }
      }
      return values.length ? values : undefined;
    default:
      if (typeof(inputObj.length)=='undefined') {
        return inputObj.value;
      }
      // radiobutton group, or multiple fields with the same name
      values=new Array();
      for(i=0; i<inputObj.length; i++) {
        if (typeof(inputObj[i])=='object') {
          values.push(getFieldValue(inputObj[i]));
        }
      }
      return values.length ? values : undefined;
  }
}

var missingRequiredFields = new Array();
function checkRequired(frm, fields, i0) {
  // This function is given a list of fieldnames or fieldname specifications
  // For all fieldnames specified, it checks whether the named form field
  // has nonempty contents. It returns a list of titles (or names if no
  // title is available) of all empty fields, for reporting to the user.
  // Notes:
  // - Groups of fields with the same name are treated as one, and count as
  //   nonempty if any one of them is nonempty.
  // - In a fieldname specification, the strings '[any]' and '[all]' stand
  //   for arbitrary bracket-enclosed hash indexes. In the first case,
  //   only a single field matching the fieldname specification is required
  //   to be nonempty, in the latter case all such fields are.
  var i, j, k, inputName, el;
  var missing = new Array();
  missingRequiredFields=new Array();
  // Group all form fields by name
  var elementsByName = new Object;
  for (k=0; k<frm.elements.length; k++) {
    el = frm.elements[k];
    if (!elementsByName[el.name]) {
      elementsByName[el.name] = new Array;
    }
    elementsByName[el.name][elementsByName[el.name].length] = el;
  }
  for(i=i0; i<fields.length; i++) {
    var inputName0 = fields[i];
    // Collect all fieldnames matching inputName0
    var inputNames = new Array();
    var checkAll = false;
    if (elementsByName[inputName0]) {
      inputNames[0] = inputName0;
    } else if (inputName0.match(/\[(all|any)\]/)) {
      // The field does not exist as such, but the inputName0 specified
      // is a pattern rather than a literal name
      checkAll = inputName0.match(/\[all\]/);
      var inputNamePattern = new RegExp('^'
          +inputName0.replace(/([\\^$*+?.{}()|\[\]])/g, '\\$1')
          .replace(/\\\[(all|any)\\\]/gi, '\\[[^\\[\\]]*\\]')+'$');
      var useDefaultChecked = false;
      var inputNameDefault;
      for (inputName in elementsByName) {
        if (inputName.match(inputNamePattern)) {
          if (inputName.match(/\[default\]/)) {
            // This is a default input field, only relevant if some
            // other input field has its useDefault checkbox checked
            inputNameDefault = inputName;
            continue;
          }
          if (inputName.match(/\[variantContents\]/)) {
            useDefaultCheckbox = frm[
                inputName.replace(/\[variantContents\]/, '[useDefault]')];
            if (useDefaultCheckbox) {
              if (useDefaultCheckbox.checked) {
                // This input field has its useDefault checkbox checked
                useDefaultChecked = true;
                continue;
              }
            }
          }
          inputNames[inputNames.length] = inputName;
        }
      }
      if (useDefaultChecked && inputNameDefault) {
        // Add the default input field because some other
        // input field has its useDefault checkbox checked
        inputNames[inputNames.length] = inputNameDefault;
      }
    }

    if (inputNames.length===0) {
      window.alert("Checking for nonexisting field '" + inputName0  + "'\n"
          + "(programming error?)");
    } else {
      // Check any/all form fields for nonempty contents
      for(j=0; j<inputNames.length; j++) {
        inputName = inputNames[j];
        var els = elementsByName[inputName];
        for(k=0; k<els.length; k++) {
          if (!isEmpty(els[k])) {
            break;
          }
        }
        if (k<els.length) {
          // At least one input field with this name is nonempty
          if (checkAll) {
            continue; // check others matching this inputName0
          } else {
            break; // we are done with this inputName0
          }
        }
        if (checkAll || j==inputNames.length-1) {
          el = els[0];
          if (checkAll) {
            inputName = inputName
                .replace(/\[variantContents\].*/, '');
          } else {
            inputName = inputName
                .replace(/Variants\[.*\]\[variantContents\].*/, '');
          }
          var inputLongName;
          // Report a nonempty form field
          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;
          } else {
            inputLongName = inputName.replace(/\[\]/, '');
          }
          // push() doesn't work in Mac/IE
          missing[missing.length]=inputLongName;
          missingRequiredFields[missingRequiredFields.length] = inputName;
        }
      }
    }
  }
  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;
  }
  if (window.storeEditableRegions && window.storeEditableRegions !==null) {
    // Store contenteditable DIV's if code for this has been loaded
    // from admin.js
    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;
  }
  if (frm.actionStamp && frm.actionStamp.value) {
    setActionReloadUrl(frm);
  }
  if (!frm.target || frm.target=='_self' || frm.target=='_top') {
    showWaitIcon();
  }
  formChanged = false;
  return true;
}

function checkValidEmail(inputName) {
  // This function checks an email address for validity
  var el=findObject(inputName);
  if (el && el.value && !el.value
      .match(/^ *[a-zA-Z0-9_.-]+@([a-zA-Z0-9_-]+\.)+[a-zA-Z0-9]+ *$/)) {
    window.alert('Please enter a valid email address for field \''
        +(el.title && el.title.match(/\S/) ? el.title : inputName) + '\'');
    return false;
  }
  return true;
}

function setActionReloadUrl(frm) {
  if (frm.actionStamp && frm.actionStamp.value) {
    var today = new Date();
    frm.actionStamp.value = frm.actionStamp.value.replace(/-\d+$/, '')
        + '-' + today.getTime();
    setCookie('actionStampConfirm', frm.actionStamp.value, false, '/');
    if (!frm.actionReloadUrl && fullPageRelUrl) {
      var el = document.createElement('input');
      el.setAttribute('type', 'hidden');
      el.setAttribute('name', 'actionReloadUrl');
      var url=fullPageRelUrl.replace(/\w+Id=&/, '').replace(/&\w+Id=$/, '');
      if (typeof(rootMode)!='undefined') {
        url+='&rootMode='+rootMode;
      }
      el.value=url;
      frm.appendChild(el);
    }
  }
}

// Functions to guard against leaving an unsubmitted form by clicking on a link

var formChanged = false;

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

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


function checkForUnsavedChanges(event) {
  // Check whether a form contains unsaved changes (inputs that have been 
  // changed), before f.i. following a link to another page
  var isBeforeUnload = false;
  if (event && event.type=='beforeunload') {
    isBeforeUnload = true;
  } else if (window.event && window.event.type=='beforeunload') {
    isBeforeUnload = true;
  }
  var warning = 'Changes have not yet been commited. Discard changes?';
  if (typeof(langDiscardChangesWarning) != 'undefined' && !isBeforeUnload) {
    warning = langDiscardChangesWarning;
  }
  if (isBeforeUnload) {
    if (formChanged) {
      return ''; // OnBeforeUnload confirmation dialog created by browser
    } else {
      return undefined; // No message
    }
  } else {
    if (formChanged) {
      if (!confirm(warning)) {
        return false;
      } else {
        formChanged = false;// Prevent 2nd confirmation dialog at beforeunload
        return true;
      }
    } else {
      return true;
    }
  }
}

function confirmDelete() {
  // Check whether the user really intended to perform a delete action
  if (typeof(langDeleteWarning) == 'undefined') {
    langDeleteWarning = 'Are you sure you wish to delete this item?';
  }
  return(confirm(langDeleteWarning));
}

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 (checkForUnsavedChanges()) {
    formChanged = false;
    return confirmDelete();
  } else {
    return false;
  }
}

// Functions to manipulate TEXTAREA's

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;
  }
}

var bbCodeField;
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') {
    var 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;
}


// Functions for preloading all images given as arguments
// The template engine has created a call to this function for
// all images with a 'preloadSrc=xxx' attribute
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];
    }
  }
}

// Function for handling parted fields

function showPart(fieldname, newPartId) {
  // Display a different part of a parted field
  var partIdElement = findObject(fieldname+'PartId');
  if (partIdElement) {
	  var oldPartId = parseInt(partIdElement.innerHTML);
    var oldPart = findObject(fieldname+'Part'+oldPartId);
    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 ? 'inline' : 'none');
      }
      var nextPart = findObject(fieldname+'PartNext');
      if (nextPart) {
        var nextPart_style = (document.layers)?nextPart:nextPart.style;
        var nextnextPart = findObject(fieldname+'Part'+(newPartId+1));
        nextPart_style.display = (nextnextPart ? 'inline' : 'none');
      }
    }
  }
}

function showPartOffset(fieldname, delta) {
  // Display a different part of a parted field, by offset
  var partIdElement = findObject(fieldname+'PartId');
  if (partIdElement) {
    showPart(fieldname, parseInt(partIdElement.innerHTML)+delta);
  }
}

function showPartForAnchor(anchorname) {
  // Display the part of a parted field containing the named anchor
  var els = document.getElementsByName(anchorname);
  for(var i=0; i<els.length; i++) {
    if (els[i].tagName=='A') {
      var el=els[i];
      while(el) {
        if (el.id && el.id.match(/(.*)Part(\d+)/)) {
          showPart(RegExp.$1, parseInt(RegExp.$2));
        }
        el=el.parentNode;
      }
    }
  }
}         

// Function for mouseovers of buttons
function setButton(btnName, image, className) {
  // btnName is id of button
  // image is source of image to be loaded in button
  // className is class to be assigned to button
  // If btnName is not an image, the image parameter may be omitted
  // If btnName has no class, the class may be assigned to btnName's parent
  var btn = findObject(btnName);
  if (btn !==null) {
    if (btn.src) {
      btn.src = wwwroot+'/images/'+image;
    }
    if (btn.className && btn.className!='png') {
      if (className) {
        btn.className = className;
      } else if (!btn.src) {
        btn.className = image.replace(/.*\/|\.[^\/]*$/, '');
      }
    } else if (btn.parentNode.className) {
      if (className) {
        btn.parentNode.className = className;
      } else if (!btn.src) {
        btn.parentNode.className = image.replace(/.*\/|\.[^\/]*$/, '');
      }
    }
  }
}

// Functions to set/get cookies
function getCookie(name) {
  if (!name || !document.cookie) {
    return null;
  }
  var start = document.cookie.indexOf('; '+name+'=');
  if (start!=-1) {
    start+=name.length+3;
  } else {
    start=document.cookie.indexOf(name+'=');
    if (start===0) {
      start=name.length+1;
    } else {
      return null;
    }
  }
  var end = document.cookie.indexOf(';',start);
  if (end == -1) {
    end = document.cookie.length;
  }
  return myUnescape(document.cookie.substring(start,end));
}

function setCookie(name,value,expires,path,domain,secure) {
  var cookieString = name + "=" + myEscape(value)
      + ((expires) ? ";expires=" + expires.toGMTString() : "")
      + ((path) ? ";path=" + path : "")
      + ((domain) ? ";domain=" + domain : "")
      + ((secure) ? ";secure" : "");
  document.cookie = cookieString;
}

function deleteCookie(name,path,domain,secure) {
  var cookieString = name + "="
      + ";expires=Fri, 27 Jul 2001 02:47:11 UTC"
      + ((path) ? ";path=" + path : "")
      + ((domain) ? ";domain=" + domain : "")
      + ((secure) ? ";secure" : "");
  document.cookie = cookieString;
}

var partialPageHash='';
var historyIframe=false;
var historyIframeLoading=false;
var historyIframeNextHash='';
var partialPageLoadUsed=false;
var hashCheckHandler;
partialPageHash=getPartialPageHash(window.location.href);
/*
// Replaced by code in standard.ihtml, which also takes into account
// the state of historyiframe.ihtml
if (window.location.hash.match(/^#URI=/)) {
  if (window.location.hash.substr(5)==partialPageHash) {
    window.location.hash='';
  } else {
    hashCheckHandler = setInterval('doHashCheck()', 1000);
  }
}
*/
var currentPartialPageLoadHref='';
var currentPartialPageLoadNoScrollJump=null;
var currentPartialPageLoadRequest=null;
var currentPartialPageLoadTargetId=null;
/*
Vars:
noScrollJump
*/

function getPartialPageHash(href) {
  if (href.match(/%[0-9A-F][0-9A-F]/)) {
    href=myUnescape(href);
  }
  href=href.replace(/#.*/, '');
  if (href.match(/^\w+:\/\//)) {
    var basehost = location.protocol+'//'+location.host;
    if (href.substr(0,basehost.length+1)==basehost+'/') {
      href=href.substr(basehost.length);
    } else {
      return false;
    }
  }
  if (href.match(/^\//)) {
    if (href.substr(0,wwwroot.length+1)==wwwroot+'/') {
      href=href.substr(wwwroot.length+1);
    } else {
      return false;
    }
  }
  if (href.match(/^historyiframe.html\//)) {
    return href.replace(/.*historyiframe.html\//, '');
  } else if (href.match(/^(\w+\/index.php|index.php|historyiframe.html|Admin\/)\?/)) {
    return href.replace(/.*\?/, '?');
  } else if (href.match(/^[^\x00-\x1F.\s+?%:;!#&<>''""\\]*(\?|$)/)) {
    return href;
  } else {
    return false;
  }
}

function tryPartialPageLoad(href0, noScrollJump, targetId) {
  // Reload the pagecontents element of the page
  if (noPartialPageLoads || !href0) {
    return true;
  }
  var ua = navigator.userAgent.toLowerCase();
  if (ua.match(/firefox\/1.0.7/)) { // Firefox 1.0.7 has a bug
    return true;
  }
  var el=findObject('pagecontents');
  if (!el) { // partialpageload div not yet available
    if (!hashCheckHandler) {
      // Start checking for hash-changes caused by back/forward buttons
      // (only relevant if invoked by explicit doHashCheck() call).
      hashCheckHandler = setInterval('doHashCheck()', 1000);
    }
    return true;
  }
  var href=href0;
  if (!href.match(/^\w+:\/\/|^\//)) {
    href=window.location.pathname.replace(/\/[^\/]*$/, '/')+href;
  }
  href=href.replace(/^\/\//, '/');
  if (getPartialPageHash(href)===false) {
    return true;
  }
  var targetAnchor='';
  if (href.match(/#(.*)/)) {
    targetAnchor=RegExp.$1;
    href=href.replace(/#(.*)/, '');
    if (getPartialPageHash(href)==partialPageHash
        && !currentPartialPageLoadRequest) {
      window.location.hash=targetAnchor;
      return false;
    }
  }
  if (currentPartialPageLoadRequest) {
    // There is already a partial page load in progress
    if (currentPartialPageLoadHref.replace(/#(.*)/, '')==href) {
      // Re-request of the partial page load in currently progress
      currentPartialPageLoadHref=href+(targetAnchor?'#'+targetAnchor:'');
      return false;
    }
    // Abort partial page load in progress
    var oldPartialPageLoadRequest=currentPartialPageLoadRequest;
    currentPartialPageLoadRequest=null;
    oldPartialPageLoadRequest.abort();
    hideProgressCursor();
  }
  showProgressCursor();
  // Store current 'real location' as hash in browser history if necessary
  var hash=window.location.hash;
  if (!hash.match(/^#URI=/)) {
    hash='#URI='+myEscape(partialPageHash);
    if (ua.indexOf('opera')>=0) {
      // Opera has weird timing with location.replace: it is executed
      // _after_ later hash assignments. Avoid it at the cost of creating
      // a double history entry
      window.location.hash=hash;
    } else {
      window.location.replace(window.location.href.replace(/#.*/, '')+hash);
    }
  }
  if (!historyIframe && window.ActiveXObject) {
    // Create historyIframe for IE to store browsing history
    if (document.getElementById('historyIframe')) {
      historyIframe=document.getElementById('historyIframe');
    } else {
      historyIframe=document.createElement("iframe");
      historyIframe.id="historyIframe";
      document.body.appendChild(historyIframe);
      historyIframe.style.visibility='hidden';
      historyIframe.style.width='1px';
      historyIframe.style.height='1px';
      historyIframe.style.position='absolute';
      historyIframe.style.right='0px';
      historyIframe.style.bottom='0px';
    }
    try {
      if (!historyIframe.contentWindow.location.href.match(/\?|historyiframe.html\//)) {
        historyIframe.contentWindow.location.replace(wwwroot+'/historyiframe.html'
         +(partialPageHash.match(/^\?/)?'':'/')+partialPageHash);
        historyIframeLoading=true;
      }
    } catch(e) {
      historyIframe.contentWindow.location.replace(wwwroot+'/historyiframe.html'
       +(partialPageHash.match(/^\?/)?'':'/')+partialPageHash);
      historyIframeLoading=true;
    }
  }
  // Fetch content to be put into pagecontents element
  var request;
  if (window.XMLHttpRequest || !window.ActiveXObject) {
    request = new XMLHttpRequest();
  } else if (ua.indexOf('msie 5') == -1) {
    request = new ActiveXObject("Msxml2.XMLHTTP");
  } else {
    request = new ActiveXObject("Microsoft.XMLHTTP");
  }
  currentPartialPageLoadRequest=request;
  currentPartialPageLoadHref=href+(targetAnchor?'#'+targetAnchor:'');
  currentPartialPageLoadNoScrollJump=noScrollJump;
  currentPartialPageLoadTargetId=targetId;
  request.onreadystatechange=finishPartialPageLoad;
  request.open("GET", href+(href.match(/\?/)?'&':'?')+'doPartialLoad=1'+(mainTemplate?'&checkTemplate='+mainTemplate:''),true);
  request.send(null);
  return false;
}

function finishPartialPageLoad() {
  //  if (!request) {    request=this; }
  request=currentPartialPageLoadRequest;
  if (!request || !request.readyState) {
    return;
  }
  var el, el2, el_style, el2_style, el3, targetId, h, w, i, newLocation,
     statusCode, targetAnchor, href, noScrollJump, anchorText, doScrollTo,
     anchorElement, doFullPartialPageLoad, newDoc, firstPartialPageLoad, hash,
     hash2, scripts, script1, script2;
  if (request.readyState==2) {
    targetId=currentPartialPageLoadTargetId;
    if (targetId) {
      el2=document.getElementById(targetId);
      if (el2 && el2.innerHTML) {
        el2_style=(document.layers?el2:el2.style);
        h=el2.offsetHeight;
        el2.offsetWidth;
        el2.innerHTML='Loading page, please wait...'
            + '<img align="right" src="'+wwwroot+'/images/wait-icon.gif">';
        if (h) {
          el2_style.height=(h+'px');
        }
        if (w) {
          el2_style.width=(w+'px');
        }
      }
    } else {
      el=findObject('pagecontents');
      if (el && el.innerHTML) {
        el.innerHTML='Loading page, please wait...'
            + '<img align="right" src="'+wwwroot+'/images/wait-icon.gif">';
      }
    }
  }
  if (request.readyState<4) {
    return;
  }
  currentPartialPageLoadRequest=null;
  el=findObject('pagecontents');
  newLocation=null;
  statusCode=0;
  try {
    statusCode=request.status;
  } catch(e) {
    statusCode=-1;
  }
  if (statusCode!=200) {
    newLocation=currentPartialPageLoadHref;
  } else if (request.getResponseHeader("X-Avenue-Reload")) {
    newLocation=request.getResponseHeader("X-Avenue-Reload");
  } else if (!request.getResponseHeader("Content-Type").match(/text\/html/)
      || request.getResponseHeader("X-Avenue-Partial")!="1"
      || request.responseText===null
      || request.responseText==='') {
    newLocation=currentPartialPageLoadHref;
  } else {
    // Display fetched pagecontents element
    targetAnchor='';
    href=currentPartialPageLoadHref;
    noScrollJump=currentPartialPageLoadNoScrollJump;
    if (href.match(/#(.*)/)) {
      targetAnchor=RegExp.$1;
      href=href.replace(/#(.*)/, '');
    }
    if (request.getResponseHeader("X-Avenue-Location")) {
      href=request.getResponseHeader("X-Avenue-Location");
    }
    partialPageHash=getPartialPageHash(href);
    if (typeof(noScrollJump)=='undefined' && typeof(noScrollJumps)!='undefined') {
      noScrollJump=noScrollJumps;
    }
    anchorText='';
    doScrollTo=false;
    if (!targetAnchor) {
      if (typeof(noScrollJump)=='undefined' || !noScrollJump) {
        anchorText='<a name="URI='+myEscape(partialPageHash)+'"></a>';
      } else if (noScrollJump=='top') {
        doScrollTo=true;
      } else if (noScrollJump.match && noScrollJump.match(/[a-z]/i)) {
        // For some reason, this code does not work on IE6
        anchorElement=document.getElementById(noScrollJump);
        if (anchorElement) {
          anchorElement.name='URI='+myEscape(partialPageHash);
        }
      }
    }
    doFullPartialPageLoad=true;
    targetId=currentPartialPageLoadTargetId;
    if (targetId) {
      el2=document.getElementById(targetId);
      if (el2 && document.createElement) {
        newDoc=document.createElement('DIV');
        newDoc.innerHTML=request.responseText;
        if (newDoc.innerHTML) {
          el2.id=undefined;
          newDoc.style.display='none';
          document.body.appendChild(newDoc);
          el3=document.getElementById(targetId);
          if (el3) {
            el2.parentNode.insertBefore(el3, el2);
            el2.parentNode.removeChild(el2);
            el=el3;
            doFullPartialPageLoad=false;
          } else {
            el2.id=targetId;
          }
          document.body.removeChild(newDoc);
        }
      }
    }
    if (doFullPartialPageLoad) {
      el.innerHTML=anchorText+request.responseText;
      if (doScrollTo) {
        window.scrollTo(0,0);
      }
    }
    if (doFullPartialPageLoad && !el.innerHTML) { // Error! (occurs in Safari)
      newLocation=currentPartialPageLoadHref;
    } else {
      // Note success
      firstPartialPageLoad = !partialPageLoadUsed;
      partialPageLoadUsed=true;
      if (!window.onbeforeunload) {
        notePartialReload();
      }
    // Store new 'real location' as hash in browser history
      hash=window.location.hash;
      hash2=hash.substr(5);
      if (!hash2.match(/[?\/]/) || hash2.match(/%[0-9A-F][0-9A-F]/)) {
        hash2=myUnescape(hash2);
      }
      if (hash2!=partialPageHash) {
        hash='#URI='+myEscape(partialPageHash);
        window.location.hash=hash;
        if (historyIframe && historyIframeNextHash!=partialPageHash) {
          try {
            if (historyIframe.contentWindow.location.href!=
                location.protocol+'//'+location.host
                +wwwroot+'/historyiframe.html'
                +(partialPageHash.match(/^\?/)?'':'/')+partialPageHash) {
              if (historyIframeLoading) {
                historyIframeNextHash=partialPageHash;
              } else {
                historyIframe.contentWindow.location.reload(
                    wwwroot+'/historyiframe.html'
                    +(partialPageHash.match(/^\?/)?'':'/')+partialPageHash);
              }
            }
          } catch(e) {
            if (historyIframeLoading) {
              historyIframeNextHash=partialPageHash;
            } else {
              historyIframe.contentWindow.location.reload(
                  wwwroot+'/historyiframe.html'
                  +(partialPageHash.match(/^\?/)?'':'/')+partialPageHash);
            }
          }
        }
      }
      // Inner scripts must be explicitly re-added in order to be executed
      scripts = document.body.getElementsByTagName('SCRIPT');
      for(i=0; i<scripts.length; i++) {
        if(scripts[i].id
            && scripts[i].id.match(/^partialPageAppended[0-9]+$/)){
          scripts[i].parentNode.removeChild(scripts[i]);
        }
      }
      scripts = el.getElementsByTagName('SCRIPT');
      for(i=0; i<scripts.length; i++) {
        script1 = scripts[i];
        script2 = document.createElement('script');
        script2.type = script1.type;
        if (script1.src) {
          script2.src = script1.src;
        } else {
          script2.text = script1.text;
        }
        script2.id='partialPageAppended'+i;
        document.body.appendChild(script2);
      }
      if (targetAnchor) {
        window.location.hash=targetAnchor;
      }
      if (!hashCheckHandler) {
        // Start checking for hash-changes caused by back/forward buttons
        hashCheckHandler = setInterval('doHashCheck()', 1000);
      }
    }
  }
  hideProgressCursor();
  if (newLocation) { // We have to do a full page load
    clearInterval(hashCheckHandler);
    hashCheckHandler=null;
    window.location=newLocation;
  }
}

function doHashCheck() {
  var hash=window.location.hash;
  if (hash.match(/^#URI=/)) {
    var hash2=hash.substr(5);
    if (!hash2.match(/[?\/]/) || hash2.match(/%[0-9A-F][0-9A-F]/)) {
      hash2=myUnescape(hash2);
    }
    if (hash2!=partialPageHash) {
      tryPartialPageLoad((hash2.match(/^\?/)?'index.php':(hash2.match(/^\//)?'':wwwroot+'/'))+hash2);
    }
  }
}

function notePartialReload() {
  if (partialPageLoadUsed) {
    setCookie('partialReload', Math.random(), 0, wwwroot+'/');
  }
}
deleteCookie('partialReload', wwwroot+'/');

function convertFormToHref(frm) {
  // This function converts a form's form fields into an URL, in order
  // to attempt to load it with a partial-page-load
  if (frm.target && frm.target!=='_self' && frm.target!=='') {
    // Targeted form. We don't try this
    return undefined;
  }
  if (frm.method && frm.method!=='get' && frm.method!=='') {
    // POST form. We can try it as long as it is outfitted with an actionStamp
    if (frm.actionStamp && frm.actionStamp.value) {
      setActionReloadUrl(frm);
    } else {
      return undefined;
    }
  }
  var action = frm.attributes
      ? frm.attributes.getNamedItem("action").nodeValue
      : frm.getAttribute("action");
  if (!action) {
    return undefined;
  }
  var queryParameters = new Array();
  if (!(document.defaultCharset && document.defaultCharset.match(/UTF.*8/i))
      && !(document.characterSet && document.characterSet.match(/UTF.*8/i))
      && !(document.charset && document.charset.match(/UTF.*8/i))) {
    // Javascript will encode query parameters as UTF8, but page might not
    // be UTF8: tell Avenue the charset so that it can decode the queryparams
    queryParameters.push('encoding=utf8');
  }
  if (frm.method && frm.method!=='get' && frm.method!=='') {
    queryParameters.push('isConvertedForm=1');
  }
  var i,k;
  for (k=0; k<frm.elements.length; k++) {
    var el=frm.elements[k];
    if (typeof(el.name)=='undefined') {
      continue;
    }
    if (el.name==='') {
      continue;
    }
    if (typeof(el.type)!='undefined' && el.type=='submit') {
		 continue;
	 }
    var value=getFieldValue(el);
    if (typeof(value)=='undefined') {
      continue;
    }
    if (typeof(value)=='array') {
      for(i=0; i<value.length; i++) {
        queryParameters.push(encodeURIComponent(el.name)+'='+encodeURIComponent(value[i]));
      }
    } else {
      if (el.type=='file' && value) {
        // File upload! Can't do that with partial page reloads
        return undefined;
      }
      queryParameters.push(encodeURIComponent(el.name)+'='+encodeURIComponent(value));
    }
  }
  if (queryParameters.length>0) {
    if (action.match(/\?/)) {
      action=action+'&'+queryParameters.join('&');
    } else {
      action=action+'?'+queryParameters.join('&');
    }
  }
  if (action.length>65000) {
    return undefined;
  } else {
    return action;
  }
}

function unwrapWrappedObjects(wrapTag) {
  // This function unwraps objects wrapped in a NOSCRIPT tag
  // (to activate multimedia files for IE hampered by EOLAS patent)
  if (typeof(wrapTag)=='undefined') {
    wrapTag='noscript';
  }
  var els = document.getElementsByTagName(wrapTag);
  var title=document.title; // weird browser bug: title gets altered
  for(var i=els.length-1; i>=0; i--) {
    var el = els[i];
    if (el.parentNode && el.className && el.className=='objectwrapper') {
      var el2 = document.createElement('DIV');
      el2.innerHTML = el.innerHTML;
      while(el2.firstChild) {
        el.parentNode.insertBefore(el2.firstChild, el);
      }
      el.parentNode.removeChild(el);
    }
  }
  document.title=title;
}

var pCursorSheet, pCursorRule, pCursorRuleSize=0;
function showProgressCursor() {
  document.body.style.cursor='progress';
  if (!pCursorSheet && document.styleSheets && document.styleSheets.length) {
    pCursorSheet = document.styleSheets[0];
    pCursorRule = pCursorSheet.cssRules?pCursorSheet.cssRules.length:pCursorSheet.rules.length;
  }
  if (pCursorSheet && pCursorRuleSize===0) {
    if (pCursorSheet.insertRule) {
      // Set cursor on link tag through stylesheet rules
      // Note that Firefox does not register onmouseout events during a
      // XMLHttpRequest, so the link-cursor-style is the style used for
      // the cursor during the entire onmouseout event
      pCursorSheet.insertRule('a, a:link, a:active, a:visited, a:hover, input, body  { cursor: progress; }', pCursorRule);
      pCursorRuleSize=1;
    } else if (pCursorSheet.addRule) {
      pCursorSheet.addRule('a', 'cursor: progress;', pCursorRule);
      pCursorSheet.addRule('a:link', 'cursor: progress;', pCursorRule+1);
      pCursorSheet.addRule('a:active', 'cursor: progress;', pCursorRule+2);
      pCursorSheet.addRule('a:visited', 'cursor: progress;', pCursorRule+3);
      pCursorSheet.addRule('a:hover', 'cursor: progress;', pCursorRule+4);
      pCursorSheet.addRule('input', 'cursor: progress;', pCursorRule+5);
      pCursorSheet.addRule('body', 'cursor: progress;', pCursorRule+6);
      pCursorRuleSize=7;
    }
  }
}

function hideProgressCursor() {
  document.body.style.cursor='auto';
  if (pCursorSheet && pCursorRuleSize) {
    for(var i=pCursorRule+pCursorRuleSize-1; i>=pCursorRule; i--) {
      if (pCursorSheet.deleteRule) {
        pCursorSheet.deleteRule(i);
      } else if (pCursorSheet.removeRule) {
        pCursorSheet.removeRule(i);
      }
    }
    pCursorRuleSize=0;
  }
}

// General 'load and run code from server' function with callback parameter
// Code adapted from example in PHP Architect
function loadCodeFromServer(scriptname, params, callback) {
  var head = document.getElementsByTagName('head').item(0);
  var oldhead = document.getElementById('loadedScript');
  if (oldhead) {
    head.removeChild(oldhead);
  }
  var script = document.createElement('script');
  script.src = scriptname + (callback ? '?callback='+callback+(params ? '&'+params : '') : (params ? '?'+params : ''));
  script.type = 'text/javascript';
  script.defer = true;
  script.id = 'loadedScript';
  head.appendChild(script);
}

function openCalendar(dateField, restrictToFuture) {
  // Popup calendar for date/time inputs
  var url=wwwroot+'/editor/calendar.html?field='+myEscape(dateField)
      +(restrictToFuture?'&restrictToFuture=1':'');
  if (window.showModalDialog) {
    window.showModalDialog(url, window,
        'dialogWidth:200px; dialogHeight:250px; help: no; status: no');
  } else {
    window.open(url, 'calendar',
        'width=200,height=250,dependent=yes,directories=no,location=no,'
        + 'menubar=no,resizable=no,scrollbars=no,status=no,personalbar=no'
        + ',toolbar=0');
  }
  return false;
}

function showWaitIcon() {
  var el, icon, mode=1;
  if (document.getElementById('waiticon')) {
    icon = document.getElementById('waiticon');
    icon_style = (document.layers)?icon:icon.style;
    icon_style.display='';
    icon_style.visibility='visible';
  } else {
    icon = document.createElement('img');
    icon.id='waiticon';
    icon.src = wwwroot+'/images/wait-icon.gif';
    icon.align='right';
    el = document.getElementById('submitButton');
    if (!el) {
      var els = document.getElementsByTagName('INPUT');
      for (var i=0; i<els.length; i++) {
        if (els[i].type && els[i].type=='submit') {
          el=els[i];
          break;
        }
      }
    }
    if (el) {
      el.parentNode.insertBefore(icon, el);
    } else if (document.getElementById('pagecontents')) {
      el = document.getElementById('pagecontents');
      el.insertBefore(icon, el.firstChild);
    } else {
      el = document.body;
      el.insertBefore(icon, el.firstChild);
    }
  }
}

function myEscape(str) {
  if (encodeURIComponent) {
    return encodeURIComponent(str);
  } else {
    return escape(str);
  }
}

function myUnescape(str) {
  if (decodeURIComponent && !str.match(/%u/)) {
    return decodeURIComponent(str);
  } else {
    return unescape(str);
  }
}
