// Popup-related functions

// Warning when navigating away from changed form {{{
formWarning = true;
formChanged = false;
function formWarn() {
// Warn user
    if (formWarning && formChanged) {
        return 'If you click OK, any changes will be lost.';
    }
}
window.onbeforeunload = formWarn;
// }}}

openWindowsArray = Array();
function windowOpenOrFocus(url, windowname, options) { // {{{
    // Open new window or bring to focus if it's already open

    // If it already exists, give it focus
    if (openWindowsArray[windowname] &&
            openWindowsArray[windowname].open &&
            !openWindowsArray[windowname].closed) {
        openWindowsArray[windowname].focus();
    }

    // Create new window and remember it
    else {
        openWindowsArray[windowname] =
            window.open(url, windowname, options);
    }

} // }}}

// Set to true when page becomes fully loaded
loaded = false;
function onLoadCallback() { // {{{
// Loaded by all pages
    loaded = 1;
} // }}}

function popLeftAdj(w, fraction) { // {{{
// Pass in width, returns suggested left coordinate
// fraction is "1/2" for middle, "1/3" for first third, etc.
// (centered relative to current window)

    // Default to middle
    if (isNaN(fraction))
      fraction = 0.5;

    // Sensible default if all else fails
    useLeft = 25;

    // Find center width (Netscape)
    if (window.outerWidth) {
        if (!isNaN(window.screenX))
            useLeft = window.screenX;
        if (window.outerWidth > 0)
            useLeft += Math.floor((window.outerWidth*fraction) - (w/2));
    }

    // Find center width (IE)
    else {
        if (!isNaN(window.screenLeft))
            useLeft = window.screenLeft;
        if (document.body.offsetWidth > 0)
            useLeft += Math.floor((document.body.offsetWidth*fraction) - (w/2));
    }

    // Nudge back if we go too far right or down
    if (screen.availWidth > 0) {
        if ((useLeft + w) > screen.availWidth)
            useLeft -= (useLeft + w) - screen.availWidth;
    }

    // Make sure we don't go negative
    if (useLeft < 0) useLeft = 0;

    return useLeft;

} // }}}

function popTopAdj(h, fraction) { // {{{
// Pass in height, returns suggested top coordinate
// fraction is "1/2" for middle, "1/3" for first third, etc.
// (centered relative to current window)

    // Default to middle
    if (isNaN(fraction))
        fraction = 0.5;

    // Sensible default if all else fails
    useTop = 25;

    // Find center height (Netscape)
    if (window.outerHeight) {
        if (!isNaN(window.screenY))
            useTop = window.screenY;
        if (window.outerHeight > 0)
            useTop += Math.floor((window.outerHeight*fraction) - (h/2));
    }

    // Find center height (IE)
    else {
        if (!isNaN(window.screenTop))
            useTop = window.screenTop;
        if (document.body.offsetHeight > 0)
            useTop += Math.floor((document.body.offsetHeight*fraction) - (h/2));
    }

    // Nudge back if we go too far right or down
    if (screen.availHeight > 0) {
        if ((useTop + h) > screen.availHeight)
            useTop -= (useTop + h) - screen.availHeight;
    }

    // Make sure we don't go negative
    if (useTop < 0) useTop = 0;

    return useTop;

} // }}}

function popWidthAdj(w, fraction) { // {{{
// Pass in width, returns fraction of available screen width if it won't fit

    // Use 90% if not specified
    if (isNaN(fraction) || fraction > 1 || fraction <= 0)
        fraction = 0.9;

    if (screen.availWidth > 0) {
        if (w > (screen.availWidth * fraction))
            w = screen.availWidth * fraction;
    }

    return w;
} // }}}

function popHeightAdj(h, fraction) { // {{{
// Pass in height, returns fraction of available screen height if it won't fit

    // Use 90% if not specified
    if (isNaN(fraction) || fraction > 1 || fraction <= 0)
        fraction = 0.9;

    if (screen.availHeight > 0) {
        if (h > (screen.availHeight * fraction))
          h = screen.availHeight * fraction;
    }

    return h;
} // }}}

function csvString2Hash(str) { // {{{
// Convert '10,25' into
//   myHash[10] = true
//   myHash[25] = true

    myArray = str.split(',');
    myHash  = Array();
    for (x=0; x<myArray.length; x++) {
        myHash[csvArray[x]] = true;
    }

    return myHash;
} // }}}

function select2csvStrings(selectId, win) { // {{{
// Returns object with two Array() member variables:
// csvKeysString
// csvValsString

    s = idOf(selectId, win);
    r = new Object();
    r.csvKeysString = '';
    r.csvValsString = '(none)';

    // If we have a select field
    if (s) {
        csvKeysArray = Array();
        csvValsArray = Array();

        for (x=0; x<s.options.length; x++) {
            if (s.options[x].selected) {
                csvKeysArray.push(s.options[x].value);
                csvValsArray.push(s.options[x].text);
            }
        }

        // Make csv strings
        if (csvKeysArray.length) {
            r.csvKeysString = csvKeysArray.join(',');
            r.csvValsString = csvValsArray.join(', ');
        }
    }

    return r;

} // }}}

function setSelectFromCsvString(str, selectId, win) { // {{{
// Sets multi select from comma separated string

    s = idOf(selectId, win);

    if (s) {
        // Put into hash for easy lookup
        csvArray = str.split(',');
        csvHash  = Array();
        for (x=0; x<csvArray.length; x++) {
            csvHash[csvArray[x]] = true;
        }

        // Loop over select values
        for (x=0; x<s.options.length; x++) {
            if (csvHash[s.options[x].value] == true)
                s.options[x].selected = true;
            else
                s.options[x].selected = false;
        }
    }

} // }}}

function checkboxes2csvStrings(formId, keyPrefix, valPrefix, win) { // {{{
// Returns object with two Array() member variables:
// csvKeysString
// csvValsString
//
// e.g.
// With this HTML:
//  <input type="checkbox" id="id_123" />
//  <input type="hidden" id="text_123" value="Description 3" />
//  <input type="checkbox" id="id_124" />
//  <input type="hidden" id="text_124" value="Description 4" />
//
// This call:
//  obj = checkboxes2csvStrings('myform', 'id_', 'text_');
//
// Could create:
//  obj.csvKeysString = "123,124"
//  obj.csvValsString = "Description 3, Description 4"

    f = idOf(formId, win);
    r = new Object();
    r.csvKeysString = '';
    r.csvValsString = '(none)';

    // If we have a form
    if (f && f.elements) {
        csvKeysArray = Array();
        csvValsArray = Array();

        for (x=0; x<f.elements.length; x++) {
            // Find all the checkboxes
            if (f.elements[x].type == "checkbox" && f.elements[x].checked) {

                // Only consider if it has the right prefix
                if (keyPrefix.length) {
                    keyPrefixCompare = f.elements[x].id.substr(0, keyPrefix.length);
                    if (keyPrefix != keyPrefixCompare) continue;
                }

                // Suffix
                key = f.elements[x].id.substr(keyPrefix.length, 99);

                // Suffix is the key
                csvKeysArray.push(key);

                // Value is possibly stored in neighboring input field
                valPrefixField = idOf(valPrefix + key);
                if (valPrefixField)
                    csvValsArray.push(valPrefixField.value);
            }
        }

        // Make csv strings
        if (csvKeysArray.length) {
            r.csvKeysString = csvKeysArray.join(',');
            r.csvValsString = csvValsArray.join(', ');
        }

    }

    return r;

} // }}}

function setCheckboxesFromCsvString(str, keyPrefix, win) { // {{{
// Checks checkboxes from string like this: '123,124'
//
// e.g.
// With this HTML:
//  <input type="checkbox" id="id_123" />
//  <input type="checkbox" id="id_124" />
//
// Call:
//  setCheckboxesFromCsvString('123,124', 'id_');

    csvArray = str.split(',');

    for (x=0; x<csvArray.length; x++) {
        if (idOf(keyPrefix + csvArray[x], win).type == "checkbox")
            idOf(keyPrefix + csvArray[x], win).checked = true;
    }

} // }}}

function setInputValue(inputId, newValue, win) { // {{{
// Sets input or textarea field to string
// Doesn't generate error if doesn't exist

    i = idOf(inputId, win);

    if (i) {
        i.value = newValue;
    }
} // }}}

// For setInterval call to reloadAndCloseCallback
reloadAndCloseTimes      = 0; // Number of times to check
reloadAndCloseCallbackId = 0; // ID of timer
reloadAndCloseWin        = 0; // Window ID (usually window.opener)
reloadAndCloseDoScroll   = 0;
function reloadAndCloseCallback(closeSelf, Y) { // {{{
// Support function called on interval

    // Only do this a finite number of times
    reloadAndCloseTimes--;

    // Make sure we're operating on a valid window
    if (reloadAndCloseWin) {

        reloadAndCloseWinLoadedTruth = false;
        try {
            reloadAndCloseWinLoadedTruth = reloadAndCloseWin.loaded;
        } catch(e) { }

        // Return if not ready and still counting down
        if (!reloadAndCloseWinLoadedTruth && reloadAndCloseTimes > 0) return;

        // Stop calling this function now
        if (reloadAndCloseCallbackId)
            clearInterval(reloadAndCloseCallbackId);

        // Scroll window
        if (reloadAndCloseDoScroll && reloadAndCloseWinLoadedTruth && reloadAndCloseWin.scrollTo)
            reloadAndCloseWin.scrollTo(0, Y);

        // Set focus
        if (closeSelf)
            reloadAndCloseWin.focus();
    }

    // Close
    if (closeSelf)
        window.close();

} // }}}

function getScrollY(win) { // {{{
// Compatibly gets the offset scrolled down from the top

    Y = 0;

    // Netscape, Mozilla
    if( typeof(win.pageYOffset) == 'number' ) {
        Y = win.pageYOffset;

    // DOM
    } else if ( win.document.body && win.document.body.scrollTop ) {
        Y = win.document.body.scrollTop;

    // IE6 standards compliant
    } else if ( win.document.documentElement &&
            win.document.documentElement.scrollTop ) {
        Y = win.document.documentElement.scrollTop;
    }

    return Y;

} // }}}

function reloadAndClose(win, closeSelf, scrollPolls, url, forceLocation) { // {{{
// Reloads window (typically window.opener), scrolls back into position
// scrollPolls is number of times to poll for window to scroll into position
//   (1 every 1/10 of a second, 0 to turn off, -1 not to reload at all)
// Optionally closes self

    // If window is still there
    if (win) {

        reloadAndCloseWin = win;

        // If we're checking the location
        // and location doesn't match
        // and we're forcing win to load that url
        resetLocationTruth = url && url.length;
        try {
            resetLocationTruth = resetLocationTruth && win.location != url;
        } catch (e) { }

        if (resetLocationTruth && forceLocation)
            win.location = url;

        // If we're checking the window's location and not forcing
        // Or we're not checking the window's location
        else if (!resetLocationTruth) {

            // Get current scroll position
            if (scrollPolls > 0)
                Y = getScrollY(win);
            else
                Y = 0;

            // Don't reload at all if we were told not to
            if (scrollPolls != -1) {
                win.location.reload();
                realoadAndCloseDoScroll = 1;
            } else {
                realoadAndCloseDoScroll = 0;
            }

            // If we have somewhere to scroll to, set timer and watch
            if (scrollPolls > 0 && Y > 0) {

                // Clear previous if there's still one going
                if (reloadAndCloseCallbackId)
                clearInterval(reloadAndCloseCallbackId);

                // Set number of times to check for window being done loading
                reloadAndCloseTimes = scrollPolls;

                // 10 second max
                if (reloadAndCloseTimes > 100)
                reloadAndCloseTimes = 300;

                // Set timer
                reloadAndCloseCallbackId =
                setInterval("reloadAndCloseCallback(" + closeSelf + ", " + Y + ");", 100);

                return;
            }
        }

    }

    // Call callback directly without an actual timer if we fell through
    reloadAndCloseCallback(closeSelf, 0);

} // }}}

function popupCentered(url, w, h, options, windowname) {/*{{{*/
    l = popLeftAdj(w, 0.5);
    t = popTopAdj(h, 0.5);

    if (options != '')
        options = ',' + options;

    if (typeof windowname == 'undefined')
        windowname = '_blank';

    windowOpenOrFocus(url, windowname, 'left='+l+',top='+t+',width='+w+',height='+h+options);

    return false;
}/*}}}*/

// vim: set fdm=marker:
