// 
// These javascript functions get loaded into ALL datacom web pages.
// Add and modify functions with care!
//

var ua = navigator.userAgent.toLowerCase();
var msIE = ((ua.indexOf('msie') != -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1)); 

// Add a "trim" function to Javascript's string object type
String.prototype.trim = function() {
    // Strip leading and trailing white-space
    return this.replace(/^\s*|\s*$/g, "");
}


//
// Hide or display an object
//
function toggleBox(id) {
    if(document.layers) {    //NN4+
        if (document.layers[id].visibility == "show") {
            document.layers[id].visibility = "hide";
        } else {
            document.layers[id].visibility = "show";
        }
    }
    else if(document.getElementById) {     //gecko(NN6) + IE 5+
        var obj = document.getElementById(id);
        if (obj.style.visibility == "visible" || obj.style.display == "block") {
            obj.style.visibility = "hidden";
            obj.style.display = "none";
        } else {
            obj.style.visibility = "visible";
            obj.style.display = "block";
        }
    }
    else if(document.all) {  // IE 4
        if (document.all[id].style.visibility == "visible" || document.all[id].style.display == "block") {
            document.all[id].style.visibility = "hidden";
            document.all[id].style.display = "none";
        } else {
            document.all[id].style.visibility = "visible";
            document.all[id].style.display = "block";
        }
    }
}


// Remove an element
function removeElement(name) {
    var remove = document.getElementById(name);
    if (remove) {
        var parent = remove.parentNode;
        parent.removeChild(remove);
    }
}



// Taken from mail.google.com and modified
function el(id) {
    if (document.getElementById) {  // Gecko (NN6, Firefox, IE 5+)
        return document.getElementById(id);
    }
    else if (window[id]) {
        return window[id];
    }
    return null;
}



// Read a cookie's value
function getcookie(cookiename) {
    var cookiestring=""+document.cookie;
    var index1=cookiestring.indexOf(cookiename);
    if (index1==-1 || cookiename=="") return ""; 
    var index2=cookiestring.indexOf(';',index1);
    if (index2==-1) index2=cookiestring.length; 
    return unescape(cookiestring.substring(index1+cookiename.length+1,index2));
}




///////////////////////////////////////////////////////////////////////////////
// Function: ts_form_okd(form_element, event)
// Description:
//   Designed to be called from a winc forms' onKeyDown function.
//   Handles a few special keys:
//   * On <enter>  it calls the form's onSubmit() function
//   * On <escape> it calls the form's my_escape() function if you've defined one
//   * On <tab>    it inserts four spaces if it's a textarea
//
// Example: <form onKeyDown="return ts_form_okd(this, event);" onSubmit="do something here...">
//
// Common Key Codes
//    8 = backspace
//    9 = tab
//   13 = enter
//   16 = shift
//   17 = ctrl
//   18 = alt
//   27 = esc
//   37 = left arrow
//   38 = up arrow
//   39 = right arrow
//   40 = down arrow
//   46 = delete
//////////////////////////////////////////////////////////////////////////////
function ts_form_okd(element, ev) {
    if (!ev) ev = window.event;
    // Turn "element" into _form if it's not already an element
    if (typeof(element) == 'string') var _form = el(element);
    else var _form = element;
    if (!_form) return false;
    
    // Get the element that the person is typing into
    var _target = false;
    if (ev.target)           _target = ev.target;
    else if (ev.srcElement)  _target = ev.srcElement;
    if (_target.nodeType==3) _target = _target.parentNode; // Defeat Safari bug
    
    // Get the key they just pressed
    var code = ev.keyCode;
    //el('editor_title').innerHTML = code;
    if (code) {
        // <ENTER>
        if (code == 13) {
            // Don't submit the form if they hit enter while in a <textarea> tag
            if (_target.tagName == 'TEXTAREA') return true;
            
            // If it's an auto-suggest field, don't submit the form
            if (typeof(_target.suggest_onkeydown) == 'function') jconsole("NOTICE => Not submitting form because you're in an auto-suggest field", 1);
            
            // Submit the form
            else {
                jconsole("NOTICE => Submitting form from ts_form_okd() because you hit enter", 1);
                _form.onsubmit(ev);
            }
            return false;
        }
        
        // <ESC>
        if (code == 27) {
            if (typeof(_form.my_escape) == 'function') {
                _form.my_escape(ev);
                return false;
            }
        }

        // <TAB>
        if (code == 9) {
            // If it's a <textarea> tag, insert spaces instead of tabbing out of the textarea
            if (_target.tagName == 'TEXTAREA') {
                edInsertContent(_target, '    ');
                return false;
            }
        }
        
    }
    return true;
};




// Extracted from http://alexking.org/blog/2004/06/03/js-quicktags-under-lgpl
function edInsertContent(element, myValue) {
    if (typeof(element) == 'string') var _myField = el(element);
    else var _myField = element;
    
    //IE support
    if (document.selection) {
        _myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
        _myField.focus();
    }
    //MOZILLA/NETSCAPE support
    else if (_myField.selectionStart || _myField.selectionStart == '0') {
        var startPos = _myField.selectionStart;
        var endPos = _myField.selectionEnd;
        var scrollTop = _myField.scrollTop;
        _myField.value = _myField.value.substring(0, startPos)
                      + myValue 
                      + _myField.value.substring(endPos, _myField.value.length);
        _myField.focus();
        _myField.selectionStart = startPos + myValue.length;
        _myField.selectionEnd = startPos + myValue.length;
        _myField.scrollTop = scrollTop;
    } else {
        _myField.value += myValue;
        _myField.focus();
    }
};






///////////////////////////////////////////////////////////////////////////////
// Function: ts_overlay(element, [option, value, option, value ... ])
// Description:
//   Creates a div overlay over any element.
//   Creates a second div for content if you specify something in the content
//   parameter, and loads that content into it.
//
// Input:
//     element         id of, or element object for, the element to be overlayed
//     The rest of the parameters should come in key/value pairs. There are
//     several options that can be passed in, here is a list.
//       OPTION        DEFAULT          DESCRIPTION
//       ------        -------          -----------
//       id            (auto)           Override the default element id for the new overlay div
//       javascript    ''               Execute this javascript after overlay creation
//       onclose       ''               Execute this javascript after closing the overlay
//       content       ''               If specified, a content div is also created. This variable
//                                      should contain Text, HTML, or an element reference to display
//                                      in this content div. The content div's ID will be the id
//                                      parameter above + _content.
//       overlay_mode  (auto)           Overlay mode, 'auto', 'visible' or 'all'. Auto will overlay
//                                      all content if the parent is document.body or if the element
//                                      we're overlaying is absolutely positioned. Only a valid option
//                                      if a manual width or height has not been specified.
//                                      Has something to do with if it's scrolled content or not.
//       // Overlay div parameters (these should be ignored in most cases!)
//       o_class       'promo_overlay_v2' Any valid css class name
//       o_height      (auto)           Manual overlay height (in pixels)
//       o_width       (auto)           Manual overlay width (in pixels)
//       o_zIndex      50               Manual overlay zIndex
//       // Content div parameters (these should be ignored in most cases!)
//       c_id          id+'_content'    Manual element id for the content div
//       c_class       'overlay_content' Any valid css class name
//       c_height      (auto)           Manual content height (in pixels)
//       c_width       (auto)           Manual content width (in pixels)
//       c_zIndex      55               Manual content zIndex
//       c_close_icon  false            Add a close icon to the content div after inserting content
//       c_position    'north'          Positioning of the content div: north, center
//
// Examples:
//   * Overlay a div named 'container'
//         ts_overlay('container');
//   * Overlay a div named 'container' and display a top-centered message that says "Hi there!"
//         ts_overlay('container', 'content', 'Hi there!');
//   * Overlay a the entire web-page and display a centered message that says "Hi there!" and has a close icon
//         ts_overlay(document.body, 'content', 'Hi there!', 'c_position', 'center', 'c_close_icon', true);
//   * Overlay the "my_winc" div with an overlay div named "my_winc_overlay, and copy the innerHTML
//     of "div_with_my_content" into the new overlay.
//         ts_overlay('my_winc', 'id', 'my_winc_overlay', 'content', el('div_with_my_content'));
//
// NOTES:
//   * Close an overlay with: el(overlay_id).close();
//   * Read overlay options from: el(overlay_id).options.X
//   * Created by BZ after msg_box and loading_overlay. Use this function,
//     the msg_box and popover functions are all being depricated or
//     re-written to use this function.
//
// NOTICE:
//   Don't call this function unless you've already closed the body tag of your
//   document.  If you try to do so before the final </body> tag, it will cause
//   an error in IE.  See the details here: http://support.microsoft.com/default.aspx/kb/927917
//
///////////////////////////////////////////////////////////////////////////////
function ts_overlay(element) {
    // Turn "element" into _e
    if (typeof(element) == 'string') var _e = el(element);
    else var _e = element;
    if (!_e) return false;
    
    // Setup a few other vars we use below
    var options = new Object;
    var now = new Date();
    var timestamp = now.getTime();
    var extraCss = '';
    var x_offset = 0;
    var y_offset = 0;
    
    // Define default options
    options['id']           = 'overlay_' + timestamp;
    options['content']      = '';              // Content to display
    options['javascript']   = '';              // Execute this javascript after creation
    options['onclose']      = '';              // Execute this javascript after closing the overlay
    options['overlay_mode'] = 'auto';          // Overlay mode, 'auto', 'visible' or 'all'
    options['o_class']      = 'promo_overlay_v2'; // Any valid css class name
    options['o_width']      = 'auto';          // Manual width (in pixels)
    options['o_height']     = 'auto';          // Manual width (in pixels)
    options['o_zIndex']     = 50;              // Manual zIndex
    options['c_id']         = 'auto';          // Manual element id for the content div
    options['c_class']      = 'overlay_content'; // Any valid css class name
    options['c_width']      = 'auto';          // Manual width (in pixels)
    options['c_height']     = 'auto';          // Manual width (in pixels)
    options['c_zIndex']     = 55;              // Manual zIndex
    options['c_close_icon'] = false;           // Add a close icon to the content div after inserting content
    options['c_position']   = 'north';         // Position for the content div's position
    
    // Load in the options from the function call
    // (this is a sweet way to pass key=value pairs into a function!)
    for (var i = 1; i < arguments.length; i += 2)
        options[arguments[i]] = arguments[i + 1];
    
    // Set a default content id .. do it here because it's based on options.id which might have been set
    if (options.c_id == 'auto') options.c_id = options.id+'_content';
    
    // Figure out which overlay mode to use
    if (options.overlay_mode == 'auto') {
        options.overlay_mode = 'visible';
        if (_e == document.body) options.overlay_mode = 'all';
        if (get_style(_e, 'position') == 'absolute') {
            options.overlay_mode = 'all';
        }
    }
    
    // If we happen to be overlaying a winc, get a handle to the table that contains the title and close image and get it's height
    var ttt = 0;
    var _ttt = el(_e.id+'_title_table');
    if (_ttt) ttt = parseInt(_ttt.offsetHeight);
    
    // Calculate an overlay width if we need to
    if (options.o_width == 'auto') {
        options.o_width = _e.offsetWidth;
        if (options.overlay_mode == 'all') {
            options.tmp = _e.scrollWidth;
            if (options.tmp > options.o_width) options.o_width = options.tmp;
        }
    }
    
    // Calculate an overlay height if we need to
    if (options.o_height == 'auto') {
        options.o_height = _e.offsetHeight;
        if (options.overlay_mode == 'all') {
            options.tmp = _e.scrollHeight;
            if (options.tmp > options.o_height) options.o_height = options.tmp;
        }
        // If we're overlaying a winc, remove its height from our custom height
        if (ttt) {
            options.o_height = options.o_height - ttt;
            y_offset += ttt;
        }
    }
    
    // If the parent we're overlaying is not absolutly positioned, we need to move our div a little...
    //if (!_e.style.position) { // If _e is a positioned element
    //var _child = first(_e);
    //if (!_child) jconsole('WARNING => ts_overlay() called, and the element being overlayed has no children!!', 0);
    //if (_child && _e.offsetParent == _child.offsetParent) { // If _e is a positioned element
    // If _e is a positioned element
    var p = get_style(_e, 'position');
    if (p != 'absolute' && p != 'fixed' && p != 'relative') {
        // IE Bug:
        // If you're placing an overlay on a div that's relativly positioned, and it happens to
        // have scrolled content in it, IE just totally get's confused and none of the calculations
        // seem to work right anymore.
        if (browser.isIE && parseInt(_e.scrollHeight) > parseInt(_e.offsetHeight)) {
            jconsole('DEBUG => ts_overlay() Overlaying a non-positioned element, but skipping offset calculations because of IE bug', 1);
            jconsole('DEBUG => ts_overlay() '+_e.scrollHeight+' != '+_e.offsetHeight, 3);
        }
        else {
            jconsole('DEBUG => ts_overlay() Overlaying a non-positioned element', 1);
            y_offset += calcOffset(_e, 'offsetTop');
            x_offset += calcOffset(_e, 'offsetLeft');
        }
    }
    else jconsole('DEBUG => ts_overlay() Overlaying a '+p+' positioned element', 1);
    
    // If we calculated an x or y offset, add it to extraCss;
    if (x_offset != 0) extraCss += "left:"+x_offset+"px;";
    if (y_offset != 0) extraCss += "top:"+y_offset+"px;";
    jconsole('DEBUG => ts_overlay() overlay offset: at top:'+y_offset+' left:'+x_offset, 3);
    
    // Build our overlay div
    _e.scrollTop = 0; // FIXME: Do we really need to do this? Can it put it back to where it was when it's done?
    var overlay = '<div id="'+options.id+'" class="'+options.o_class+'" style="width:'+options.o_width+'px; height:'+options.o_height+'px; z-index:'+options.o_zIndex+'; '+extraCss+'"></div>';
    append(_e, overlay);
    
    // Assign this variable to simplify life of outside objects using this overlay
    el(options.id).options = options;
    
    // If we're supposed to put content into it, let's do that now
    if (options.content) {
        var offsetX = 0; // offsetLeft
        var offsetY = 0; // offsetTop
        extraCss = '';
        
        // Calculate an overlay width if we need to
        if (options.c_width == 'auto') {
            options.c_width = _e.offsetWidth;
            if (options.overlay_mode == 'all') {
                options.tmp = _e.scrollWidth;
                if (options.tmp > options.c_width) options.c_width = options.tmp;
            }
        }
        
        // Only set a height if the user provided one - default is let it be dynamic for the content div
        if (options.c_height != 'auto') {
            extraCss += 'height: '+options.c_height+'px;';
        }
        
        // Build our overlay content div (visibility:hidden until we un-hide it later...)
        var content_div = '<div id="'+options.c_id+'" class="'+options.c_class+'" style="visibility: hidden; width:'+options.c_width+'px; '+extraCss+' z-index:'+options.c_zIndex+';"></div>';
        append(_e, content_div);
        
        // Put the content provided into the div
        if (typeof(options.content) == 'string')
            el(options.c_id).innerHTML = options.content;
        else if (typeof(options.content.innerHTML) == 'string')
            el(options.c_id).innerHTML = options.content.innerHTML;
        
        // Position the content div (currently only "north" permitted)
        switch (options.c_position) {
            case 'north':
                offsetX = parseInt(_e.offsetWidth / 2) - parseInt(el(options.c_id).offsetWidth / 2);
                offsetY = 15 + ttt;
                break;
            case 'center':
                offsetX = parseInt(_e.offsetWidth / 2) - parseInt(el(options.c_id).offsetWidth / 2);
                offsetY = parseInt(_e.offsetHeight / 2) - parseInt(el(options.c_id).offsetHeight / 2) + ttt;
                break;
            break;
        }
        if (x_offset != 0) offsetX += x_offset;
        if (y_offset != 0) offsetY += y_offset;
        jconsole('DEBUG => ts_overlay() Positioning overlay content: '+options.c_position+ ' at top:'+offsetY+' left:'+offsetX, 3);
        el(options.c_id).style.top = offsetY+'px';
        el(options.c_id).style.left = offsetX+'px';
        
        // Append a close icon if we were supposed to
        if (options.c_close_icon) ts_overlay_close_icon(options.id);
        
        // Unhide it now that it's all built and positioned
        el(options.c_id).style.visibility = 'visible';
    }
    
    // Let's setup an overlay "close()" function.
    // This function can be called to close the overlay and it's associated content div.
    el(options.id).close = function() {
        if (this.options.c_id) removeElement(this.options.c_id);
        if (this.options.id) removeElement(this.options.id);
        if (this.options.onclose) eval(this.options.onclose);
        return false;
    };
    
    // Run any javascript if there is any to run
    if (options.javascript != '') eval(options.javascript);
    
    // Debugging:
    //var alert_msg = "overlay mode: "+options.overlay_mode+"<br />height: "+options.o_height+"px<br />final width: "+options.o_width+"px");
    //var alert_div = '<div id="'+options.c_id+'_alert" style="width:200px; background-color: white; color: black; position:absolute; top:300; left:0; z-index:100;">'+alert_msg'+</div>';
    //append(el(options.id), alert_div);
    
    return true;
};






///////////////////////////////////////////////////////////////////////////////
// Function: ts_overlay_close_icon(overlay_id)
// Description:
//   Adds a nice close icon to an overlay & content div combo created with the
//   ts_overlay() function. Typically called automatically from the ts_overlay()
//   function when the c_close_icon == true, but may be called manually too.
//
// Input:
//   overlay_id    id of the overlay created with ts_overlay()
//                 Needed because the overlay has a .close() function we call.
//////////////////////////////////////////////////////////////////////////////
function ts_overlay_close_icon(overlay_id) {
    // Validate input is all strings
    if (typeof(overlay_id) != 'string') return false;
    if (!el(overlay_id)) return false;
    var content_id = el(overlay_id).options.c_id;
    if (!el(content_id)) return false;
    // Append a close icon
    append(el(content_id), '<div style="position: absolute; top: -8px; right: -8px;"><img style="cursor: pointer;" alt="Close" title="Close" onClick="el(\''+overlay_id+'\').close(); return false;" src="/images/close.png" border="0" height="30" width="30" /></div>');
};







///////////////////////////////////////////////////////////////////////////////
// Function: ts_alert(msg, [element_id])
// TSheets' replacement for alert();
// Overlays either document.body (or the specified element_id) with a
// a nicely formatted message-box.
//////////////////////////////////////////////////////////////////////////////
function ts_alert(msg, parent_id) {
    if (!parent_id) parent_id = document.body;
    removeElement('ts_alert_overlay_content'); removeElement('ts_alert_overlay');
    // Prepare msg for insertion into html
    msg = htmlentities(msg, 'ENT_QUOTES');
    msg = msg.replace(/\\n/g, "<br />");
    var content =
        '<table cellspacing="0" border="0" cellpadding="0" style="margin: 5px 0px 8px 0px;"><tr>'+
            '<td><img src="/images/silk/error.png" border="0" height="16" width="16" /></td>'+
            '<td style="padding: 2px 0px 0px 6px;">'+msg+'</td>'+
        '</tr></table>'+
        '<div class="buttons" style="text-align: right;">'+
            '<button id="ts_alert_ok_button" class="save" onClick="el(\'ts_alert_overlay\').close();"'+
            '><img src="/images/silk/tick.png" border="0" height="16" width="16" />  Ok  </button>'+
        '</div>';
    content = '<div class="overlay_content_box" style="background-color: #fef496; border-color: #FAC11F;">'+content+'</div>';
    ts_overlay(parent_id, 'id', 'ts_alert_overlay', 'content', content, 'c_width', 330, 'c_close_icon', true, 'c_position', 'center');
    // If enter or escape is pressed, close the overlay
    el('ts_alert_ok_button').onkeydown = function(ev) {
        if (!ev) ev = event;
        var code = ev.keyCode;
        if (code && (code == 13 || code == 27)) {
            el('ts_alert_overlay').close();
        }
    };
    el('ts_alert_ok_button').focus();
};



// Let's use ts_alert() to replace the default alert() functionality
// If you passan element id/name as a second argument to this function, only that element will be overlayed.
window.alert = function(msg) {
    var parent_id = false;
    if (arguments.length > 1) parent_id = arguments[1];
    ts_alert(msg, parent_id);
};






/////////////////////////////////////////////////////////////////////
// JS equivelent of PHP's htmlentities function.
// Downloaded from http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_htmlentities/
/////////////////////////////////////////////////////////////////////
function htmlentities (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: nobbler
    // +    tweaked by: Jack
    // +   bugfixed by: Onno Marsman
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: get_html_translation_table
    // *     example 1: htmlentities('Kevin & van Zonneveld');
    // *     returns 1: 'Kevin &amp; van Zonneveld'
    // *     example 2: htmlentities("foo'bar","ENT_QUOTES");
    // *     returns 2: 'foo&#039;bar'
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    if (false === (histogram = this.get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    return tmp_str;
};







/////////////////////////////////////////////////////////////////////
// Generates a lookup table of html entities to real characters
// Supporting function for htmlentities();
// Downloaded from http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_get_html_translation_table/
/////////////////////////////////////////////////////////////////////
function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // +   bugfixed by: Alex
    // +   bugfixed by: Marco
    // +   bugfixed by: madipta
    // +   improved by: KELAN
    // +   improved by: Brett Zamir (http://brettz9.blogspot.com)
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}

    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};

    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    useTable     = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';

    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw Error("Table: "+useTable+' not supported');
        // return false;
    }

    // ascii decimals for better compatibility
    entities['38'] = '&amp;';
    if (useQuoteStyle !== 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle === 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }
    entities['60'] = '&lt;';
    entities['62'] = '&gt;';

    if (useTable === 'HTML_ENTITIES') {
      entities['160'] = '&nbsp;';
      entities['161'] = '&iexcl;';
      entities['162'] = '&cent;';
      entities['163'] = '&pound;';
      entities['164'] = '&curren;';
      entities['165'] = '&yen;';
      entities['166'] = '&brvbar;';
      entities['167'] = '&sect;';
      entities['168'] = '&uml;';
      entities['169'] = '&copy;';
      entities['170'] = '&ordf;';
      entities['171'] = '&laquo;';
      entities['172'] = '&not;';
      entities['173'] = '&shy;';
      entities['174'] = '&reg;';
      entities['175'] = '&macr;';
      entities['176'] = '&deg;';
      entities['177'] = '&plusmn;';
      entities['178'] = '&sup2;';
      entities['179'] = '&sup3;';
      entities['180'] = '&acute;';
      entities['181'] = '&micro;';
      entities['182'] = '&para;';
      entities['183'] = '&middot;';
      entities['184'] = '&cedil;';
      entities['185'] = '&sup1;';
      entities['186'] = '&ordm;';
      entities['187'] = '&raquo;';
      entities['188'] = '&frac14;';
      entities['189'] = '&frac12;';
      entities['190'] = '&frac34;';
      entities['191'] = '&iquest;';
      entities['192'] = '&Agrave;';
      entities['193'] = '&Aacute;';
      entities['194'] = '&Acirc;';
      entities['195'] = '&Atilde;';
      entities['196'] = '&Auml;';
      entities['197'] = '&Aring;';
      entities['198'] = '&AElig;';
      entities['199'] = '&Ccedil;';
      entities['200'] = '&Egrave;';
      entities['201'] = '&Eacute;';
      entities['202'] = '&Ecirc;';
      entities['203'] = '&Euml;';
      entities['204'] = '&Igrave;';
      entities['205'] = '&Iacute;';
      entities['206'] = '&Icirc;';
      entities['207'] = '&Iuml;';
      entities['208'] = '&ETH;';
      entities['209'] = '&Ntilde;';
      entities['210'] = '&Ograve;';
      entities['211'] = '&Oacute;';
      entities['212'] = '&Ocirc;';
      entities['213'] = '&Otilde;';
      entities['214'] = '&Ouml;';
      entities['215'] = '&times;';
      entities['216'] = '&Oslash;';
      entities['217'] = '&Ugrave;';
      entities['218'] = '&Uacute;';
      entities['219'] = '&Ucirc;';
      entities['220'] = '&Uuml;';
      entities['221'] = '&Yacute;';
      entities['222'] = '&THORN;';
      entities['223'] = '&szlig;';
      entities['224'] = '&agrave;';
      entities['225'] = '&aacute;';
      entities['226'] = '&acirc;';
      entities['227'] = '&atilde;';
      entities['228'] = '&auml;';
      entities['229'] = '&aring;';
      entities['230'] = '&aelig;';
      entities['231'] = '&ccedil;';
      entities['232'] = '&egrave;';
      entities['233'] = '&eacute;';
      entities['234'] = '&ecirc;';
      entities['235'] = '&euml;';
      entities['236'] = '&igrave;';
      entities['237'] = '&iacute;';
      entities['238'] = '&icirc;';
      entities['239'] = '&iuml;';
      entities['240'] = '&eth;';
      entities['241'] = '&ntilde;';
      entities['242'] = '&ograve;';
      entities['243'] = '&oacute;';
      entities['244'] = '&ocirc;';
      entities['245'] = '&otilde;';
      entities['246'] = '&ouml;';
      entities['247'] = '&divide;';
      entities['248'] = '&oslash;';
      entities['249'] = '&ugrave;';
      entities['250'] = '&uacute;';
      entities['251'] = '&ucirc;';
      entities['252'] = '&uuml;';
      entities['253'] = '&yacute;';
      entities['254'] = '&thorn;';
      entities['255'] = '&yuml;';
    }
    
    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
};







///////////////////////////////////////////////////////////////////////////////
// Function: jconsole(string msg, int level)
//   msg   = Message you would like to display
//   level = debug level that has to be reached before this message would be displayed.
//
//   Logs a message to the TSheets javascript console if level is less than
//   or equal to the level selected in the console.
//////////////////////////////////////////////////////////////////////////////
function jconsole(msg, level) {
    if (!level) level = 1;
    var _e = el('admin_js_console_content');
    if (_e) {
        if (level <= el('admin_js_console_debug').value) {
            // Prepare msg for insertion into html
            msg = htmlentities(msg, 'ENT_QUOTES');
            msg = msg.replace(/\\n/g, "<br />");
            var now = new Date();
            var months = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Aug','Nov','Dec');
            var hours = now.getHours();
            if (hours < 10) hours = '0'+hours;
            var minutes = now.getMinutes();
            if (minutes < 10) minutes = '0'+minutes;
            var seconds = now.getSeconds();
            if (seconds < 10) seconds = '0'+seconds;
            var date = months[now.getMonth()]+' '+now.getDate()+' '+hours+':'+minutes+':'+seconds+' ';
            msg = '<div>'+date+msg+'</div>';
            
            // For deciding if we should add a border or not
            var timestamp = now.getTime();
            var add_border = false;
            
            // Insert a new div with the debug message
            var _first_div = first(_e);
            
            // There's already stuff in the console
            if (_first_div) {
                // If the last entry was more than 3 seconds ago, put a border in for easy reading
                if (_first_div.ctime < (timestamp - 3000)) add_border = true;
                put_before(_e, _first_div, msg);
            }
            // This is the first entry in the console
            else {
                append(_e, msg);
            }
            // Set the ctime on the new row
            first(_e).ctime = timestamp;
            if (add_border) first(_e).style.borderBottom = "5px solid #f0f0f0";
            if (browser.isIE && parseInt(_e.offsetHeight) > 250) _e.style.height = '250px';
        }
    }
};








