﻿// JScript File

    // orphan element to hold all detached (collapsed) elements
    var hidden = document.createDocumentFragment();
    hidden.id = "hidden";
        
    // helper function to determine if the page is in quick shipping mode
    function isQuick()
    {
        return (document.location.search == "?quick");
    }
    
    function LogError(message, err)
    {
        try
        {
            if (err.message) message += ": " + err.message;
            else message += String(err); // firefox
            if (window.navigate) window.navigate("../ErrorLog.aspx?error=" + message);
            else window.open("../ErrorLog.aspx?error=" + message); // firefox
        }
        catch(e)
        {
            throw new Error(1, "Error in Utils.js.LogError, message = " + message + ": " + e.message);        
        }
    }
    
    // helper function to return an element (from the document or hidden element)    
    function Element(name)
    {
        try
        {
            if (typeof(name) != "string") return name;
            var e = document.getElementById(name);
            if (e != null) return e;
            if (hidden.getElementById) return hidden.getElementById(name);
            // firefox
            return SearchNode(hidden, name);
        }
        catch(e)
        {
            var id = (typeof(name) == "string" ? name : name.id);
            if (id == null || id == "") id = name.tagName;
            if (id == null) id = "Unknown";
            throw new Error(2, "Error in Utils.js.Element, name = " + id + ": " + e.message);        
        }
    }
    
    function isHidden(name)
    {
        if (typeof(name) != "string") name = name.id;
        return (document.getElementById(name) == null);
    }

    // only to search in hidden with firefox
    function SearchNode(parent, name)
    {
        try
        {
            if (name == "") return null;
            if (parent.id == name) return parent;
            if (parent.nodeType != 1 && parent.nodeType != 11) return null;
            if (!parent.hasChildNodes()) return null;
            var el, k = 0;
            do
            {
                el = SearchNode(parent.childNodes[k++], name);
            }
            while (k < parent.childNodes.length && el == null);
            return el;
        }
        catch(e)
        {
            var id = parent;
            if (id == null) id = "NULL";
            else 
            {
                id = parent.id;
                if (id == null || id == "") id = "Unknown";
            }
            throw new Error(3, "Error in Utils.js.SearchNode, parent = " + id + ", name = " + name + ": " + e.message);        
        }
    }
    
    // helper function to hide an element
    function Collapse(name)
    {
        var node;
        try
        {
            if (isHidden(name))
            {   
                //return;
                node = Element(name);
                if (node.parentNode == hidden) return;
                node.setAttribute("HiddenParent", node.parentNode.id);
                if (node.nextSibling != null) 
                {
                    if (node.nextSibling.id == "") node.nextSibling.id = "sibling" + node.id;
                    node.setAttribute("HiddenBefore", node.nextSibling.id);
                }        
                // checkboxes seem to lose their values when hiding, so they are saved within the node
                if (node.getAttribute("checkboxNames") != null && node.getAttribute("checkboxNames") != "")
                {
                    var names = node.getAttribute("checkboxNames").split("|"), values = "";
                    for (var k = 0; k < names.length; k++)
                        values += (Element(names[k]).checked ? "1" : "0") + "|";
                    node.setAttribute("checkboxValues", values.substring(0, values.length - 1));
                }
                hidden.appendChild(node);
                return;
            }
            
            node = Element(name);
            if (node.parentNode.id == "") node.parentNode.id = "parent" + node.id;
            node.setAttribute("HiddenParent", node.parentNode.id);
            if (node.nextSibling != null) 
            {
                if (node.nextSibling.id == "") node.nextSibling.id = "sibling" + node.id;
                node.setAttribute("HiddenBefore", node.nextSibling.id);
            }        
            // checkboxes seem to lose their values when hiding, so they are saved within the node
            if (node.getAttribute("checkboxNames") != null && node.getAttribute("checkboxNames") != "")
            {
                var names = node.getAttribute("checkboxNames").split("|"), values = "";
                for (var k = 0; k < names.length; k++)
                    values += (Element(names[k]).checked ? "1" : "0") + "|";
                node.setAttribute("checkboxValues", values.substring(0, values.length - 1));
            }
            hidden.appendChild(node);
            //hidden.innerHTML += node.parentNode.innerHTML;
            //node.parentNode.removeChild(node);
            //hidden.appendChild(node.cloneNode(true));
        }
        catch(e)
        {
            throw new Error(4, "Error in Utils.js.Collapse, name = " + node.id + ": " + e.message);        
        }
    }
    
    // helper function to show an element
    function Expand(name)
    {
        var node;
        try
        {
            if (!isHidden(name)) return;
            node = Element(name);
            if (node.getAttribute("HiddenBefore") == null || node.getAttribute("HiddenBefore") == "") Element(node.getAttribute("HiddenParent")).appendChild(node);
            else 
                if (isHidden(node.getAttribute("HiddenBefore"))) Element(node.getAttribute("HiddenParent")).appendChild(node);
                else Element(node.getAttribute("HiddenParent")).insertBefore(node, Element(node.getAttribute("HiddenBefore")));
            if (node.getAttribute("checkboxNames") != null && node.getAttribute("checkboxNames") != "")
            {
                // checkboxes seem to lose their value when hiding, so they are saved within the node
                var names = node.getAttribute("checkboxNames").split("|");
                var values = node.getAttribute("checkboxValues").split("|");
                if (names != null && values != null && names.length == values.length)
                    for (var k = 0; k < names.length; k++)
                        Element(names[k]).checked = (values[k] == "1");
            }
        }
        catch(e)
        {
            throw new Error(5, "Error in Utils.js.Expand, name = " + node.id + ": " + e.message);        
        }
    }
    
    function Enable(name, force)
    {
        EnableDisable(name, true, force);
    }
    
    function Disable(name, force)
    {
        EnableDisable(name, false, force);
    }
    
    // enable or disable nodes (including its children, recursively)
    function EnableDisable(name, enable, force)
    {
        var node = Element(name);
        try
        {
            if (node == null) return;
            if ((node.tagName == "INPUT" && (node.type == "text" || node.type == "button" || node.type == "checkbox" || node.type == "radio")) || node.tagName == "SELECT") 
                if (force)
                {
                    node.disabled = !enable;
                    node.setAttribute("EnableCount", (enable ? "1" : "-1"));
                }
                else
                {
                    var count = parseInt(node.getAttribute("EnableCount"));
                    if (count == null || isNaN(count)) count = 0;
                    if (count == 0 || (Math.abs(count) == 1 && node.disabled == enable)) node.disabled = !enable;
                    node.setAttribute("EnableCount", String((enable ? ++count : --count)));
                }
            else
                for (var k = 0; k < node.childNodes.length; k++)
                    EnableDisable(node.childNodes[k], enable, force);
        }
        catch(e)
        {
            throw new Error(6, "Error in Utils.js.EnableDisable, name = " + node.id + ", enable = " + enable + ", force = " + force + ": " + e.message);
        }
    }
    
    // helper function to clear all textboxes, checkboxes or dropdowns
    function Clear(name)
    {
        var node = Element(name);
        try
        {
            if (node == null) return;
            if (node.tagName == "INPUT")
            {
                if (node.type == "text") node.value = "";
                if (node.type == "checkbox") node.checked = "";
            }
            if (node.tagName == "SELECT") 
                if (node.options.length > 0)
                    if (node.getAttribute("defaultValue") != null && node.getAttribute("defaultValue") != "") node.value = node.getAttribute("defaultValue");
                    else node.selectedIndex = 0;
                else node.selectedIndex = -1;
            for (var k = 0; k < node.childNodes.length; k++)
                Clear(node.childNodes(k));
        }
        catch(e)
        {
            throw new Error(7, "Error in Utils.js.Clear, name = " + node.id + ": " + e.message);        
        }
    }
    
    // helper function to emulate collapse - expand buttons
    function Switch(name)
    {
        var node = Element(name);
        if (node.value == "▼") 
        {
            node.value = "▲";
            node.title = "Hide Details";
            node.setAttribute("Expanded", "1");
        }
        else
        {
            node.value = "▼";
            node.title = "Show Details";
            node.setAttribute("Expanded", "0");
        }
    }
    
    function isExpanded(name)
    {
        var node = Element(name);
        try
        {
            if (node.getAttribute("Expanded") == null || node.getAttribute("Expanded") == "") node.setAttribute("Expanded", (node.value == "▲" ? "1" : "0"));
            return (node.getAttribute("Expanded") == "1");
        }
        catch(e)
        {
            throw new Error(8, "Error in Utils.js.isExpanded, name = " + node.id + ": " + e.message);        
        }
    }
    
    function Show(name)
    {
        Element(name).style.visibility = "visible";
    }
    
    function Hide(name)
    {
        Element(name).style.visibility = "hidden";
    }
    
    function SetImageState(item, state, title)
    {
        var imgSrc, imgTitle;
        if (state == "empty")
        {
            imgSrc = "../images/empty.png";
            imgTitle = "";
        }
        if (state == "new")
        {
            imgSrc = "../images/new.gif";
            imgTitle = "new " + item;
        }
        if (state == "error")
        {
            imgSrc = "../images/error.png";
            imgTitle = title;
        }
        if (state == "wait")
        {
            // imgSrc = "../images/Progress.gif";
            // imgTitle = "please wait, searching " + item + " ...";
        }
        Element("img" + item).src = imgSrc;
        Element("img" + item).title = imgTitle;        
    }
    
    function GetImageState(item)
    {
        var src = Element("img" + item).src;
        if (src.search("/images/Progress.gif") != -1) return "wait";
        if (src.search("/images/empty.png") != -1) return "empty";
        if (src.search("/images/new.gif") != -1) return "new";
        if (src.search("/images/error.png") != -1) return "error";
        return null;
    }
    
    function Validate(element, image, message, expand)
    {
        if (Element(element).value == "")
        {
            if (expand != null && !isExpanded("cmd" + expand + "Details")) Toggle(expand);
            SetImageState(image, "error", message);
            Element(element).focus();
            return false;
        }
        SetImageState(image, "empty", null);
        return true;
    }
    
    function ItemLookup(item)
    {
        try
        {
            SyncCall("Lookup", item, Element("txt" + item).value, "Lookup|" + item); 
            Element("chk" + item + "Save").checked = false;
        }
        catch(e)
        {
            throw new Error(9, "Error in Utils.js.ItemLookup, item = " + item + ": " + e.message);        
        }
    }
    
    function Search(item, url)
    {
        try
        {
            if (Element("cmd" + item + "Search").disabled) return;
            var selected = window.showModalDialog(url, "", "dialogWidth:1024px;dialogHeight:500px");
            Element("txt" + item).value = (selected == undefined ? "" : selected);
            ItemLookup(item);
        }
        catch(e)
        {
            throw new Error(10, "Error in Utils.js.Search, item = " + item + ", url = " + url + ": " + e.message);
        }
    }
    
    function Toggle(item)
    {
        (isExpanded("cmd" + item + "Details") ? Collapse("tbl" + item) : Expand("tbl" + item));
        Switch("cmd" + item + "Details");
    }
    
    // ----------------------------------------------------------------------
    // Javascript form validation routines.
    // Author: Stephen Poley
    //
    // Simple routines to quickly pick up obvious typos.
    // All validation routines return true if executed by an older browser:
    // in this case validation must be left to the server.
    //
    // Update Jun 2005: discovered that reason IE wasn't setting focus was
    // due to an IE timing bug. Added 0.1 sec delay to fix.
    //
    // Update Oct 2005: minor tidy-up: unused parameter removed
    //
    // Update Jun 2006: minor improvements to variable names and layout
    // ----------------------------------------------------------------------

    var nbsp = 160;		// non-breaking space char
    var node_text = 3;	// DOM text node-type
    var emptyString = /^\s*$/ ;
    var global_valfield;	// retain valfield for timer thread

    // --------------------------------------------
    //                  trim
    // Trim leading/trailing whitespace off string
    // --------------------------------------------

    function trim(str)
    {
      return str.replace(/^\s+|\s+$/g, '');
    }

    // --------------------------------------------
    //                  setfocus
    // Delayed focus setting to get around IE bug
    // --------------------------------------------

    function setFocusDelayed()
    {
      global_valfield.focus();
    }

    function setfocus(valfield)
    {
      // save valfield in global variable so value retained when routine exits
      global_valfield = valfield;
      setTimeout( 'setFocusDelayed()', 100 );
    }
    
    // --------------------------------------------
    //            commonCheck
    // Common code for all validation routines to:
    // (a) check for older / less-equipped browsers
    // (b) check if empty fields are required
    // Returns true (validation passed), 
    //         false (validation failed) or 
    //         proceed (don't know yet)
    // --------------------------------------------

    var proceed = 2;  

    function commonCheck    (valfield,   // element to be validated
                             infofield,  // id of element to receive info/error msg
                             required)   // true if required
    {
      if (!document.getElementById) 
        return true;  // not available on this browser - leave validation to the server
      var elem = document.getElementById(infofield);
      if (!elem.firstChild) return true;  // not available on this browser 
      if (elem.firstChild.nodeType != node_text) return true;  // infofield is wrong type of node  

      if (emptyString.test(valfield.value)) {
        if (required) {
          msg (infofield, "error", "ERROR: required");  
          setfocus(valfield);
          return false;
        }
        else {
          msg (infofield, "warn", "");   // OK
          return true;  
        }
      }
      return proceed;
    }


    // --------------------------------------------
    //               validateEmail
    // Validate if e-mail address
    // Returns true if so (and also if could not be executed because of old browser)
    // --------------------------------------------

    function validateEmail  (valfield,   // element to be validated
                             infofield,  // id of element to receive info/error msg
                             required)   // true if required
    {
      var stat = commonCheck (valfield, infofield, required);
      if (stat != proceed) return stat;

      var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
      var email = /^[^@]+@[^@.]+\.[^@]*\w\w$/  ;
      if (!email.test(tfld)) {
        msg (infofield, "error", "ERROR: not a valid e-mail address");
        setfocus(valfield);
        return false;
      }

      var email2 = /^[A-Za-z][\w.-]+@\w[\w.-]+\.[\w.-]*[A-Za-z][A-Za-z]$/  ;
      if (!email2.test(tfld)) 
        msg (infofield, "warn", "Unusual e-mail address - check if correct");
      else
        msg (infofield, "warn", "");
      return true;
    }


    // --------------------------------------------
    //            validateTelnr
    // Validate telephone number
    // Returns true if so (and also if could not be executed because of old browser)
    // Permits spaces, hyphens, brackets and leading +
    // --------------------------------------------

    function validateTelnr  (valfield,   // element to be validated
                             infofield,  // id of element to receive info/error msg
                             required)   // true if required
    {
      var stat = commonCheck (valfield, infofield, required);
      if (stat != proceed) return stat;

      var tfld = trim(valfield.value);  // value of field with whitespace trimmed off
      var telnr = /^\+?[0-9 ()-]+[0-9]$/  ;
      if (!telnr.test(tfld)) {
        msg (infofield, "error", "ERROR: not a valid telephone number. Characters permitted are digits, space ()- and leading +");
        setfocus(valfield);
        return false;
      }

      var numdigits = 0;
      for (var j=0; j<tfld.length; j++)
        if (tfld.charAt(j)>='0' && tfld.charAt(j)<='9') numdigits++;

      if (numdigits<6) {
        msg (infofield, "error", "ERROR: " + numdigits + " digits - too short");
        setfocus(valfield);
        return false;
      }

      if (numdigits>14)
        msg (infofield, "warn", numdigits + " digits - check if correct");
      else { 
        if (numdigits<10)
          msg (infofield, "warn", "Only " + numdigits + " digits - check if correct");
        else
          msg (infofield, "warn", "");
      }
      return true;
    }

    function checkNumber(el) 
    {
      // Make sure IE4 by examining createTextRange method
      if (document.body==null) return true
      if (document.body.createTextRange==null) return true    
      // Convert key code to character
      var key = String.fromCharCode(event.keyCode), dotRelationship, allowDigit
      var checkDot = false
      var allowDigit = false
      // Check if number of digits following decimal point is cached
      if (el._digits==null) {
        // Examine default value (initial value attribute)
        var strNum = el.defaultValue
        // Find the decimal point
        var idx = strNum.indexOf(".")
        // Calculate number of decimal digits
        if (idx>-1) 
          el._digits = strNum.length - idx - 1
        else
          el._digits = -1
      }

      // Make sure a digit or a decimal point
      if (!isNaN(key) || key==".") {
        // Get selection (either insertion point or text selection)
        var selectionRange = document.selection.createRange()
        // Store a copy for use in comparisons
        var tempSel = selectionRange.duplicate()
        // Variable for the input range 
        var inputRange = el.createTextRange()
     
        // Get index of the dot
        var dotPos = el.value.indexOf(".")
       
        // If decimal point, check if new character valid
        if (dotPos > -1) {
          // Locate existing decimal point 
          inputRange.findText(".")
          // When user types decimal, it is only accepted if
          // replacing existing decimal point
          if ((key==".") && (el._digits>-1)) {
            if (tempSel.findText("."))
            // Test if existing decimal in selection
            checkDot = selectionRange.inRange(tempSel)
          } else {
            // Determine whether the selection is before or after the decimal point
            dotRelationship = inputRange.compareEndPoints("EndToStart",selectionRange)
            // Test if new input is an allowable digit
            allowDigit = ((dotRelationship<=0 && (el.value.length - dotPos -1 < 
                el._digits || selectionRange.text.length>0)) || (dotRelationship==1 && key!="."))
          }
        } else {
          // If inserting a decimal, test number of following digits
          if (key==".") 
            tempSel.moveEnd("textEdit",1)          
          allowDigit = (key=="." && (tempSel.text.length - 1 < el._digits)) || !isNaN(key)
        }
      }
      // Return whether the key is allowed
      return (checkDot || allowDigit)
    }
    
    
    
    
    
    
    function _formatDecimal(dig)
    {
        if (dig < 0 || dig == null || isNaN(dig)) dig = 0;
        var power = Math.pow(10, dig);
        var value = String(Math.round(this.valueOf() * power) / power);        
        var pos = value.indexOf('.');
        var fraction = "";
        if (pos >= 0) fraction = value.slice(pos + 1, value.length);
        for (var k = fraction.length; k < dig; k++)
            fraction += "0";
        return addCommas((pos == -1 ? value : value.slice(0, pos))) + (fraction == "" ? "" : "." + fraction);
    }
    Number.prototype.formatDecimal = _formatDecimal;
    
    function _fix(dig) 
    {
        if (dig < 0 || dig == null || isNaN(dig)) dig = 0;
        var power = Math.pow(10, dig);
        return Math.round(this.valueOf() * power) / power;
    }
    Number.prototype.fix = _fix;
    
    function _parseDecimal(dig)
    {
        return parseFloat(this.valueOf()).formatDecimal(dig);
    }
    String.prototype.parseDecimal = _parseDecimal;

    
    // my custom dictionary built on top of array
    Array.prototype.Exists = function (name)
    {
        for (var j = 0; j < this.length; j++)
            if (this[j][0] == name) return true;
        return false;
    }
    Array.prototype.Get = function (name)
    {
        for (var j = 0; j < this.length; j++)
            if (this[j][0] == name) return this[j][1];
        return null;
    }
    Array.prototype.Set = function (name, value)
    {
        for (var j = 0; j < this.length; j++)
            if (this[j][0] == name) 
            {
                this[j][1] = value;
                return;
            }
        this.push(new Array(name, value));
    }
    Array.prototype.Delete = function (name)
    {
        for (var j = 0; j < this.length; j++)
            if (this[j][0] == name) 
            {
                this.splice(j, 1);
                return;
            }
    }


    function OptionsPopup(url, args, width, height)
    {
        var ret = window.showModalDialog(url, args, "dialogWidth:" + width + "px;dialogHeight:" + height + "px;help:no;resizable:yes");
        if (ret == null) return args;
        if (typeof(ret) == "string" && ret == "clear") return null;
        return ret;
    }

    function SetStatus(status, type)
    {
        if (Element("imgInfo") != null) Collapse("imgInfo");
        if (Element("imgFinish") != null) Collapse("imgFinish");
        if (Element("lblStatus") == null) 
        {
            if (type == "error") alert("An internal error has occured: " + status);
            return;
        }
        if (status == null)
        {
            Collapse("imgError");
            Collapse("imgProgress");
            Expand("imgStatus");
            Element("lblStatus").innerHTML = "idle";
        }
        else
        {
            if (type == "error")
            {
                Collapse("imgStatus");
                Collapse("imgProgress");
                Expand("imgError");
                Element("lblStatus").innerHTML = status;
            }
            else 
            {
                Collapse("imgStatus");
                Collapse("imgError");
                Expand("imgProgress");
                if (status == "GroupShip FedEx ") status = "Processing shipment " + String(GroupShipment + 1) + " of " + String(GroupShipments.length);
                Element("lblStatus").innerHTML = status;
            }
        }
    }

    // true if popups are blocked    
    function PopupBlocks()
    {
        var objChild;                           // Window
	    var reWork = new RegExp('object','gi');	// Regular expression
	    try 
	    {
		    objChild = window.open('','child','width=50,height=50,status=no,resizable=yes'); 
		    objChild.close();
	    }
	    catch(e) 
	    { 
	    }
	    return !reWork.test(String(objChild))
    }
