/*
sccsid = '@(#) 1.39 wt/wtp/htdocs/scripts/generalUI_3.js, wtcode, jtimedev 8/25/06 17:59:47'

## 
## (C) COPYRIGHT Journyx, Inc 1997-2006
## All Rights Reserved
## Licensed Materials - Property of Journyx, Inc.
## 

ALL DEVELOPERS READ!!

If you need to reference or include this file, you must use the wtdoc.jsfiles
variable. As documented in defect 10392, there have been problems in the past
with browsers caching js files, so we need to change the name of this file 
before *each* public release. 

This means you need to change the file name in CMVC using File -Rename and 
you need to change the file name in wtdoc.jsfiles before this file is released 
in any maintenance release / patch, or in a general product release.

File-specific comments follow.

*********************************

 User-Interface related functions for Journyx Timesheet for all
 screens.

 This JS file is included and initialized on EVERY page!

 Put general-purpose non-interface things in jsgenlib.js.

 */

    
// Uncomment the line below to suppress errors in Internet Explorer    
// window.onerror = function (err, url, line) { return true; }  // don't show browser errors - mostly for IE4

JXDoPositionMainTables = 0;  // set in jtgui.pyc
JXCalendarInitiallyShown = 0; // overriden in toolbar.pyc
JXToolbarCalendarInitialized = 0;


function fncPageInit() {
  fncAdjustPrimaryContentHeight();
  fncPageOnload();
  fncMaybeFocusOnSearch();
}


// Most pages have an onResize set to fncAdjustPrimaryContentHeight
// For jtgui (Entry Screen) pages only, we combine that one plus another (jtguiOnLoad) 
// into a single function to be called on browser resize.
// This fixes vertical height issues when resizing a popup entry screen (timekeeping etc)
function fncJTGUIonresize() {
  jtguiOnLoad();
  fncAdjustPrimaryContentHeight();  
}


function fncPageStateChange() { 
  // jtgui (time entry) pages set the JXDoPositionMainTables variable.
  if (JXDoPositionMainTables) {
	window.onresize = fncJTGUIonresize;
	jtguiOnLoad();  // defined in timeTables.js
  }  
  // If an onresize handler is not already set, use fncAdjustPrimaryContentHeight
  if (bad(window.onresize)) {
	window.onresize = fncAdjustPrimaryContentHeight;
  }
}



function fncPageOnload() {
  maybeInitializeCalendar();  
  fncPageStateChange();
  try {
	maybeCollapseColumns();
  } catch(e) { } // ignore errors from messing with columns 
}

/*
 * Collapse any columns that were previously collapsed  (it's saved in a cookie)
 *
 */
function maybeCollapseColumns() {
  var toggle_columns_list = window.toggle_columns_list;
  if (bad(toggle_columns_list)) { return false; }

  for (var col_i = 0; col_i < toggle_columns_list.length; col_i++) {
	strSection = toggle_columns_list[col_i];	
	section_cookie_name = fncGetToggleColumnCookieName(strSection);
	section_pref = readCookie(section_cookie_name);
	
	if (!section_pref) {
	  continue;   // there's no cookie set, don't mess with it.
	}

	current_state = fncToggleColumn_getCurrentState(strSection);

	// Currently when the page initially loads the columns are always
	// set 'on' by the server, but this should handle cases where the
	// server sets it initially off.

	if ((current_state == "on") && (section_pref != '1') ||
		(current_state == "off") && (section_pref != '0')) {
	  // false here means, don't change the cookie 
	  fncMainTableToggleColumn(strSection, false);
	}

  }

  return true;
}


function maybeInitializeCalendar () {
  // JXCalendarInitiallyShown is defined and initialized in javascript generated
  // directly in wtlib/toolbar.py (and given on all pages even if no toolbar)
  if (JXCalendarInitiallyShown) {
	initializeToolbarCalendar(); // this function is defined in calendar-setup.js
  }
}


//
// Adjust the 'primary content' area to have the appropriate height --
// take up as much space as available.
//
// This is a total hack!  We need a better way to do this.  Since this
// isn't a natural part of the page rendering, it appears 'jumpy'
// especially on slower computers.
//
// We can't just set height: 100% in CSS, because 100% refers to the
// containing block, not the 'available' height.  There is no concept
// of '100% of available height' in CSS.
//
function fncAdjustPrimaryContentHeight() {

  var ViewFrame = document.getElementById('idPrimaryContent');
  ViewFrame.style.height = null;

  var Orig_ViewFrameHeight = fncGetHeight('idPrimaryContent');
  
  var PrimaryContainerHeight = fncGetHeight('idMainPageContainerTD');

  var PrimaryTabsHeight = 0;
  var TabSubNavHeight = 0;
  var StatusErrorHelpHeight = 0;

  
  if (document.getElementById('idPrimaryTabs')) {
	PrimaryTabsHeight = fncGetHeight('idPrimaryTabs');
  }
  if (document.getElementById('idTabSubNav')) {
	TabSubNavHeight = fncGetHeight('idTabSubNav');
  }
  if (document.getElementById('idStatusErrorHelp')) {
	StatusErrorHelpHeight = fncGetHeight('idStatusErrorHelp');
  }
  var combined_heights =  PrimaryTabsHeight + TabSubNavHeight + StatusErrorHelpHeight;
 
  var extra_padding = 12; // arbitrary fudge factor
  
  var new_height = PrimaryContainerHeight - combined_heights - extra_padding;
 
  // idPrimaryContent height should be the height of idPrimaryContainer
  // minus the combined heights of:
  //   idPrimaryTabs   idTabSubNav  idStatusErrorHelp
  
  if (Orig_ViewFrameHeight < new_height) {
	//    window.alert("Setting height to " + new_height + " because Orig_ViewFrameHeight " + Orig_ViewFrameHeight + " is less.\n" + 
	  //				 "PrimaryContainerHeight: " + PrimaryContainerHeight + " PrimaryTabsHeight: "+ PrimaryTabsHeight + 
	  //				 " TabSubNavHeight:" + TabSubNavHeight + " StatusErrorHelpHeight:" + StatusErrorHelpHeight);

    ViewFrame.style.height =  new_height + "px";

  }
}

function fncSwitchClass(oElement,strNewClass,strMatchClass) {
  if (typeof(oElement) != "undefined" && oElement !== null) {
    if (strMatchClass.length > 0) {
      if (oElement.className == strMatchClass) {
        oElement.className = strNewClass;
      }
    }
    else {
      oElement.className = strNewClass;
    }
  }
}

////
// Returns true if 'target' is contained somewhere inside the container element.
//
function fncDOMElementIsContained(container, target) {
  var isContained = false;

  while (target) {
	if (container == target) {
	  isContained = true;
	  break;
	}
	try {
	  target = target.parentNode;
	} catch(E) {
	  target = null;
	}
  }
  return isContained;

}

function fncGetMouseEventPositionX (e) {
  if (!e) var e = window.event;

  var posx = 0;
  if (e.pageX) {
	posx = e.pageX;
  }
  else if (e.clientX) {
	posx = e.clientX + document.body.scrollLeft- document.body.clientLeft ;
  }
  return posx;
}


function fncGetMouseEventPositionY (e) {
  if (!e) var e = window.event;

  var posy = 0;
  if (e.pageY) {
	posy = e.pageY;
  }
  else if (e.clientY) {
	posy = e.clientY + document.body.scrollTop - document.body.clientTop;
  }
  return posy;
}


function fncGetAbsoluteX(oObjectToGetPosition) {
  // Utility function to get the absolute X-coordinate of an object on the page
  var intCoords = {x: 0};
  while (oObjectToGetPosition) {
    intCoords.x += oObjectToGetPosition.offsetLeft;
    oObjectToGetPosition = oObjectToGetPosition.offsetParent;
  }
  return intCoords.x;
}

function fncGetAbsoluteY(oObjectToGetPosition) {
  // Utility function to get the absolute Y-coordinate of an object on the page
  var intCoords = {y: 0};
  while (oObjectToGetPosition) {
    intCoords.y += oObjectToGetPosition.offsetTop;	
    oObjectToGetPosition = oObjectToGetPosition.offsetParent;
  }
  return intCoords.y;
}


// 
// for either fncGetWidth or fncGetHeight, strObject can either be a
// string element ID (used with getElementById) or the element itself.
//
function fncGetWidth(strObject) {
  if (!strObject) { return null; } 

  if (bad(strObject.nodeType)) {
	strObject = document.getElementById(strObject);
  }
  return strObject.offsetWidth;
  // return strObject.clientWidth;
}

function fncGetHeight(strObject) {
  if (!strObject) { return null; } 

  if (bad(strObject.nodeType)) {
	strObject = document.getElementById(strObject);
  }
  return strObject.offsetHeight;
  //return strObject.clientHeight;
}

// Obsolete implementation follows - doesn't allow either strings or objects.
/*
function fncGetWidth(strObjectID) {
  return document.getElementById(strObjectID).offsetWidth;
}

function fncGetHeight(strObjectID) {
  return document.getElementById(strObjectID).offsetHeight;
}
*/


// ***********************************
// List Box Transfer Scripts

function fncListTransferSelected(strSourceListID,strTargetListID,blnResortTarget) {
  oSourceList = document.getElementById(strSourceListID);
  oTargetList = document.getElementById(strTargetListID);

  var i;
  
  if (oSourceList !== null && oTargetList !== null) {
    for (i=0; i<oSourceList.options.length; i++) {
      if (oSourceList.options[i].selected) {
        intSelectedIndex=i;  //nit.selectedIndex
        itemText=oSourceList.options[intSelectedIndex].text;
        itemValue=oSourceList.options[intSelectedIndex].value;
        
        oNewItem=new Option(itemText, itemValue);   
                   
        newIndex = oTargetList.options.length;
        oTargetList.options[newIndex]=oNewItem;
      }
    }

    i = 0;
    while (i < oSourceList.options.length) {
      if (oSourceList.options[i].selected) { 
        oSourceList.options[i]=null;
      }
      else {
        i = i + 1;
      }
    }
    
    if (blnResortTarget) {
      fncListSort(oTargetList);
    }
  }
}


function fncListTransferAll(strSourceListID,strTargetListID,blnResortTarget) {
  oSourceList = document.getElementById(strSourceListID);
  oTargetList = document.getElementById(strTargetListID);
  
  if (oSourceList !== null && oTargetList !== null) {
    for (var i=0; i<oSourceList.options.length; i++) {
      itemText=oSourceList.options[i].text;
      itemValue=oSourceList.options[i].value;
      
      oNewItem=new Option(itemText, itemValue);   
                 
      newIndex = oTargetList.options.length;
      oTargetList.options[newIndex]=oNewItem;
    }

    i = 0;
    while (i < oSourceList.options.length) {
      oSourceList.options[i]=null;
    }
    
    if (blnResortTarget) {
      fncListSort(oTargetList);
    }
  }
}


function fncListItemOrder(strListID,strDirection) {
  var strDelimiter = "^|^";
  var intSelectedIndex;
  var i, j;  // loop indexes
  var astrOptions;
  
  oList = document.getElementById(strListID);  
  
  if (oList !== null) {
    if (fncListNumSelected(oList) == 1) {
      var aobjNewList = new Array(oList.length);
      intSelectedIndex = oList.selectedIndex;
      
      if (strDirection == "up" && oList.selectedIndex > 0) {     
        
        for (i=0;i<oList.selectedIndex-1;i++) {
          aobjNewList[i] = oList.options[i].text + strDelimiter + oList.options[i].value;
        }
        
        aobjNewList[i] = oList.options[i+1].text + strDelimiter + oList.options[i+1].value;
        aobjNewList[i+1] = oList.options[i].text + strDelimiter + oList.options[i].value;
        
        for (i=oList.selectedIndex+1;i<oList.length;i++) {
          aobjNewList[i] = oList.options[i].text + strDelimiter + oList.options[i].value;
        }
        
        i = 0;
        while (i < oList.options.length) {
          oList.options[i]=null;
        }
        
        for (j=0;j<aobjNewList.length;j++) {
          astrOptions = aobjNewList[j].split(strDelimiter);
          oNewItem=new Option(astrOptions[0], astrOptions[1]);   
          oList.options[oList.options.length]=oNewItem;
        }
        
        oList.options[intSelectedIndex-1].selected = true;
      
      }
      
      if (strDirection == "down" && oList.selectedIndex < oList.length-1) {     
        
        for (i=0;i<oList.selectedIndex;i++) {
          aobjNewList[i] = oList.options[i].text + strDelimiter + oList.options[i].value;
        }
        
        aobjNewList[i] = oList.options[i+1].text + strDelimiter + oList.options[i+1].value;
        aobjNewList[i+1] = oList.options[i].text + strDelimiter + oList.options[i].value;
        
        for (i=oList.selectedIndex+2;i<oList.length;i++) {
          aobjNewList[i] = oList.options[i].text + strDelimiter + oList.options[i].value;
        }
                
        i = 0;
        while (i < oList.options.length) {
          oList.options[i]=null;
        }
        
        for (j=0;j<aobjNewList.length;j++) {
          astrOptions = aobjNewList[j].split(strDelimiter);
          oNewItem=new Option(astrOptions[0], astrOptions[1]);   
          oList.options[oList.options.length]=oNewItem;
        }
        
        oList.options[intSelectedIndex+1].selected = true;
      }
    }
  }
}


function fncListSortText(a,b) {
  return a.text!=b.text ? a.text<b.text ? -1 : 1 : 0; 
}

function fncListSort(oList) {
  var intNumItems = oList.options.length;
  var aobjItems = new Array(intNumItems);
  var i;
  for (i=0; i<intNumItems; i++ ) {
    aobjItems[i] = new Option(oList.options[i].text,oList.options[i].value);
  }
  aobjItems.sort(fncListSortText);
  for (i=0; i<intNumItems; i++ ) {
    oList.options[i] = new Option(aobjItems[i].text,aobjItems[i].value);
  }
}

function fncListNumSelected(oList) {
  var intNumSelected = 0;
  for (var i=0; i<oList.options.length; i++ ) {
    if (oList.options[i].selected) {
      intNumSelected++;
    }
  }
  return intNumSelected;
}		      


/*
 *
 * Given a list of input IDs, disable them.
 *
 * You can pass in anything that has the 'disabled' property.
 *
 * See also the equivelent fncEnableInputs and fncToggleInputsEnabled functions.
 *
 */
function fncDisableInputs(inputsIDList) {
  for (var i=0; i < inputsIDList.length; i++) {
     var the_element = document.getElementById(inputsIDList[i]);
     the_element.disabled=true;
  }
  return true;
}

function fncEnableInputs(inputsIDList) {
  for (var i=0; i < inputsIDList.length; i++) {
     var the_element = document.getElementById(inputsIDList[i]);
     the_element.disabled=false;
  }
  return true;
}

/*
 * Toggles the 'disabled' property for the given list of elements.
 *
 * If it was disabled before, it will now be enabled.  Likewise if it
 * was enabled before, it will now be disabled.
 *
 * Each element is considered separately, they are not enabled or
 * disabled as a group.
 *
 * No error handling here if you give a bad ID or the element doesn't 
 * have a disabled property. 
 * 
 */
function fncToggleInputsEnabled(inputsIDList) {
  for (var i=0; i < inputsIDList.length; i++) {
     var the_element = document.getElementById(inputsIDList[i]);
     if (the_element.disabled) {
         the_element.disabled = false;
         // window.alert("Toggling " + the_element + " to ENABLED.");
     } 
     else {
         the_element.disabled = true;
         // window.alert("Toggling " + the_element + " to DISABLED.");
     }
  }
  return true;
}


/*
 * fncSyncOtherSelects(select_element)
 *
 * meant to be called from an onChange of any SELECT input that might
 * be repeated elsewhere on the page.  Changes all other selects of the
 * same name to have the same selected values as the current input.
 *
 *
 * IMPORTANT NOTE! If the other selects with the same name happen to
 * have different values, those will be OBLITERATED!  The entire value
 * list (selected and unselected) will be copied from the given SELECT.
 *
 * Warning, this can be pretty slow with massive selects, such as the
 * "Go To Page" select on a search results screen with thousands of
 * pages.  Perhaps there is a better way to implement this.
 *
 */
function fncSyncOtherSelects(select_element) {

  var other_selects = document.getElementsByName(select_element.name);
  for (i = 0; i < other_selects.length; i++) {
    var a_select = other_selects[i];

	if (a_select != select_element) {

      a_select.options.length = 0;

      // add the new options, overwriting whatever was there.
      for (i_opt = 0; i_opt < select_element.options.length; i_opt++) {
        orig_opt = select_element.options[i_opt];
        var new_opt = new Option(orig_opt.text, orig_opt.value);
        if (orig_opt.selected) {
          new_opt.selected = true;
        }
        a_select.options[i_opt] = new_opt;
      }
	}
  }
  return true; // allow the change
}




var report_popup_options = 'menubar=yes,resizable=yes,scrollbars=yes';
var usePopupReport = '&makebuttons=0';  // add to the popup report URL to let the server know it's being shown in a popup window.

// This function is used from the onClick of the 'View As' button from
// the Report View (showrpt.pyc) screen.  It determines whether to
// launch the report inline or as a popup.
//
function fncReportViewButton(formName, viewParam) {

  var myForm = document.getElementsByName(formName)[0];

  selectedThing=myForm.outputtype.options[myForm.outputtype.selectedIndex].value;

  // Show regular 'html' and 'cube' reports inline (no popup.)
  //
  if ((selectedThing=='html')||(selectedThing=='cube')) {

	if (selectedThing=='cube') {
	  myForm.owc_version.value = getOWCversion();
	}

	// return true;
	myForm.submit();
	return true;
  }

  var finalURL = 'showrpt.pyc?' + viewParam + '&fromTimeSheet=' + myForm.fromTimeSheet.value;
  finalURL = finalURL + '&outputtype='+ selectedThing + usePopupReport;

  // window.alert('Opening URL: ' + finalURL);
  window.open(finalURL, '_blank', report_popup_options);

  return false;
}


// XXX TODO: the ABOVE function is used from showrpt.pyc, and the
// BELOW function is used from wtrptlist (the Report search screen.)
// It would be good to unify these two functions at some point...
// They are separate now because they have different CGI destinations
// and different parameters.  Ultimately they do similar things though
// so maybe there is a way to unify them.
//
function fncRunReportFromSearch(reportId) {
  var report_search = document.forms.report_search;
  var out_type = report_search.outputtype.value;

  var save_or_display = report_search.savereport[getRadio(report_search.savereport)].value;
  
  var save_report_only = false;  
  if (save_or_display == '0') {
	save_report_only = true;
  }

  // If we're saving the report, check for a blank saved report name.
  if (save_report_only || (save_or_display == '1')) {
	var saved_rep_name = report_search.description.value;

	if (!saved_rep_name) {
	  window.alert('You must give a description for the saved report output.');
	  return false;
	}
  }

  // A 'regular HTML' or cube report is run in-line, not as a popup. 
  var runReport = 'Run Report'; // XXX TODO: must match POPUP_RUNBUTTON in wtrptlist.py 
  if (save_report_only || 
	  out_type == 'html' || 
	  out_type == 'cube') {

	if (out_type == 'cube') {
	  report_search.owc_version.value = getOWCversion();
	}

	report_search.rpt.value = reportId;
	report_search.runreport.value = runReport; 
	report_search.submit();
	return false;
  }

  var finalURL = 'wtrptlist.pyc?' + 'savereport=' + save_or_display + '&runreport=' + escape(runReport) + '&rpt=' + escape(reportId) ;
  finalURL = finalURL + '&fromTimeSheet=0&outputtype='+ out_type + usePopupReport;

  // window.alert('Opening URL: ' + finalURL);

  window.open(finalURL, '_blank', report_popup_options);	
  return false;
}


// See comments above. And yet a third one for repman.py
//
function fncRunRReportFromSearch(reportId, encodeddata) {
  var report_search = document.forms.report_search;
  var out_type = report_search.outputtype.value;
 
  // A 'regular HTML' or cube report is run in-line, not as a popup. 
  var runReport = 'Run Report'; // XXX TODO: must match POPUP_RUNBUTTON in wtrptlist.py 
  // Are we coming from the search screen or from the view_as button after going 
  // previous or next?

  var fromsearch = 0;
  var save_or_display;

  if (out_type == 'html' || out_type == 'cube') {

	if (out_type == 'cube') {
	  report_search.owc_version.value = getOWCversion();
	}

	report_search.rpt.value = reportId;
	report_search.runreport.value = runReport; 
	report_search.submit();
	return false;
  }

  if (typeof(report_search.savereport) != "undefined" && report_search.savereport !== null) {
	fromsearch = 1;
	if (report_search.savereport.checked === true) {
  		save_or_display = 1;
	} else {
  		save_or_display = 0;
	}
  	var saved_report_name = report_search.description.value;
  } else {
  	save_or_display = 0;
  }

  //var finalURL = 'rreport.pyc?outputtype=' + out_type + '&savereport=' + save_or_display ;
  //finalURL = finalURL + '&' + 'description=' + saved_report_name + '&' + encodeddata;
  var finalURL = 'rreport.pyc?outputtype=' + out_type + '&' + encodeddata + '&savereport=' + save_or_display;
  if (fromsearch == 1) {
  	finalURL = finalURL + '&' + 'description=' + saved_report_name;
  }

  window.open(finalURL, '_blank', report_popup_options);	
  return false;
}

/*
 * If the page has a SimpleSearch-based search form, focus on
 * the main search input.  Intended to be run on page load.
 * This func is not in StandardSearchScreen.js because it
 * should be called from every page load even if the screen doesn't
 * have a Search UI.
 *
 */
function fncMaybeFocusOnSearch() {

  searchInputs = [
				  'gen_searchTerm',   /* SimpleSearch derived */
				  'USERNAME',         /* older Search derived */
				  'PROJECTNAME',      /* ditto for the rest - comes from self.SRCHNAME in usersearch.py*/
				  'TASKNAME',
				  'PAYTYPENAME',
				  'BILLTYPENAME',
				  'EXPENSENAME',
				  'EXPENSESOURCENAME',
				  'EXPENSECURRENCYNAME',
				  'MILEAGEREASONNAME',
				  'MILEAGEVEHICLENAME',
				  'MILEAGEMEASUREMENTNAME'
				  ];

  for (var i_inpName =0; i_inpName < searchInputs.length; i_inpName++) {
	var inpName = searchInputs[i_inpName];
	var myInputCol = document.getElementsByName(inpName);
	if (!bad(myInputCol) && (myInputCol.length > 0)) {
	  for (var i_input = 0; i_input < myInputCol.length; i_input++) {
		var myInput = myInputCol[i_input];
		try {
		  myInput.focus();
		} catch (e) {} // do nothing on error
		return;
	  }	
	}	
  }		
  return;
}


/*
 * fncToggleCollapsibleTable
 *
 * Toggles the state (open/closed) of a collapsibleTable
 *
 * You must supply the ID of both the inner body (TBODY) and the Arrow image in the caption
 *
 */
function fncToggleCollapsibleTable(caller, bodyID, arrowID) {

  // change the tooltip as appropriate
  if (getIdProperty(bodyID,"display") == "none") {
	// It was collapsed already
	caller.title = "Hide Area";
  } else {
	caller.title = "Expand Area";
  }

  toggleDisplay(bodyID);
  toggleArrow(arrowID);
}


/*
 * fncOpenPopupLink
 *
 * called by the onClick of wtdoc.Href when 'target' is set 
 * This actually opens the window and returns a reference to it.
 *
 * This is also a general purpose hook to perform any special
 * javascript check upon clicking a popup link.  Currently it doesn't
 * do anything special.
 *
 */
function fncOpenPopupLink(thisHref, event, target, winname, opts) {

  if (thisHref.disabled === true) {
	return false;
  }

  var new_win = window.open(target,winname,opts+';');
  return new_win;
}


/*
 * fncChkModFromMemLink - check if records are modified when clicking
 * on a memorized entry link.
 *
 * Called from jtgui links to confirm entry screen record changes when
 * clicking the M symbol to create/edit a memorized entry.
 * 
 * param openRowNum tells the function which row number we're coming from.
 * 
 */
function fncChkModFromMemLink(openRowNum) {

  if (thingshavechanged == 1) {
	var confMsg = 'Records were modified since last save.  Press OK to save now.';
	if (confirm(confMsg)) {
	  thingshavechanged=0;
	  window.document.persist_form.openrowforedit.value=openRowNum;
	  window.document.persist_form.alsosave.value='yes';
	  window.document.persist_form.submit();
	} 
	else { 
	  return false;
	}
  }
  else {
	thingshavechanged=0;
	window.document.persist_form.openrowforedit.value=openRowNum;
	window.document.persist_form.submit();
  } 
  return false;
}
