//
// Copyright (c) 2002 ComponentOne L.L.C. All rights reserved.
// Version 1.0.20023.4
//
// Implementation notes:
//
// Two kinds of elements are involved in menu tracking logic: menus
// and menu items. Both kinds are HTML elements, menu items are
// contained in menus in HTML (in the current realization menu items
// are immediate children of menus, and that fact is significant for
// the functioning of the system). Menu items may contain nested
// elements but these are opaque to the menu tracking. Submenus are
// NOT nested inside their parent items or menus in HTML.
//
// A form may contain several root (always shown) menus. Only one root
// menu can be active at a time (an active menu is the one with a
// selected item and/or an open submenu; if there is a selected item
// and an open menu, both must belong to the same root). At any given
// moment, the global c1c_active_menu variable contains the currently
// active root menu, or null if there is none.
//
// A menu can have zero or one selected item. In each menu, the member
// c1_sel_item points to that item, or is null if the menu does not
// have a selected item at the moment.
//
// A menu can have at most one item with an open submenu. Most often,
// this is the selected item, but that need not be true always. In
// each menu, c1_menu_item points to the item with the currently open
// submenu, or is null if there is none.
//
// Items with associated submenus have c1_submenu_id specified in HTML
// which does not change and contains the id of the submenu element.
// If an item has a submenu open, it has a member c1_submenu pointing
// to that menu. In the menu, menu.c1_parent_item points back to the
// item.
//
// List of custom element attributes used by this code:
//
// Static (should be present in html):
//   - menu.c1_horz (true/false)
//   - menu.c1_sel_item_styles
//   - menu.c1_item_styles
//   - item.c1_submenu_id
//   - item.c1_sel_item_styles
//   - item.c1_item_styles
//   - item.c1_img_src
//   - item.c1_img_sel_src
//   - item.c1_status
//
// Dynamic (created at runtime):
//   - menu.c1_menu_item
//   - menu.c1_sel_item
//   - menu.c1_parent_item
//   - item.c1_submenu
//   - item.c1_img
//   - item.c1_img_sel
//

// the currently active root menu
var c1c_active_menu = null;

// mousedown handler for outside of menus clicks
function c1c_doc_onmousedown(ev)
{
    var src = null;
    if (ev.srcElement)
        src = ev.srcElement;
    else if (ev.target)
        src = ev.target;
    // ignore mouse down on menus (handled by c1c_onmousedown)
    while (src && src.parentNode) {
        if (src.c1_submenu || c1c_getattr(src, 'c1_submenu_id'))
            return;
        src = src.parentNode;
    }
    // remove any popup menus, unselect items
    popdown_and_unselect(c1c_active_menu);
    c1c_active_menu = null;
}

// this function is attached to mousedown of menu items
// that do not have other handlers (postback or script)
function c1c_onmousedown(ev, item)
{
    c1c_onmouseover(ev, item);
}

// mouseover for menu items
function c1c_onmouseover(ev, item)
{
    var src = null;
    if (ev.srcElement)
        src = ev.srcElement;
    else if (ev.target)
        src = ev.target;
    if (src != item && !c1c_object_contains(item, src))
        return;
    c1c_select_item(item);
}

// mouseout for menu items
function c1c_onmouseout(ev, item)
{
    var tgt;
    if (ev.relatedTarget)
        tgt = ev.relatedTarget;
    else if (ev.toElement)
        tgt = ev.toElement;
    if (!tgt || (tgt != item.c1_submenu && !c1c_object_contains(item.c1_submenu, tgt))) {
        c1c_unselect_item(item);
    }
}

function c1c_select_item(item)
{
    var menu = item.parentNode;
    // if the currently selected item is the same as the new selection, nothing to do
    if (menu.c1_sel_item == item)
        return;
    // otherwise, if there is a selected item, unselect it
    if (menu.c1_sel_item)
        c1c_unselect_item(menu.c1_sel_item);
    // if there is an open submenu, hide it
    if (menu.c1_menu_item && menu.c1_menu_item != item)
        c1c_popdown_item_menu(menu.c1_menu_item)
    // show item status message
    var st = c1c_getattr(item, 'c1_status');
    if (st)
        window.status = st;
    // if we're selecting an item in a root menu,
    if (!menu.c1_parent_item) {
        // ..and there is a selected item in another root menu, unselect it and hide any menus
        if (c1c_active_menu && c1c_active_menu != menu) {
            popdown_and_unselect(c1c_active_menu);
            c1c_active_menu = null;
        }
    }
    else {
        // make sure the parent item is selected
        if (menu.c1_parent_item.parentNode.c1_sel_item != menu.c1_parent_item)
            c1c_select_item(menu.c1_parent_item);
    }
    // if the item to be selected has a submenu, show it
    c1c_popup_item_menu(item);
    // redraw the item to be selected using selected style
    c1c_hilite_item(item, true);
    // store the new selected item in its menu
    menu.c1_sel_item = item;
    // update the global c1c_active_menu var if needed.
    if (c1c_active_menu == null)
        c1c_active_menu = menu;
}

function c1c_unselect_item(item)
{
    // if the item has an open submenu, hide it
    if (item.c1_submenu) {
        if (window.setTimeout)
            window.setTimeout('c1c_popdown_item_menu_delayed("' + item.id + '")', 500);
        else
            c1c_popdown_item_menu(item);
    }
    // redraw item in normal style
    c1c_hilite_item(item, false);
    // remove status
    if (c1c_getattr(item, 'c1_status'))
        window.status = '';
    // store the fact that there is no selection in the menu
    if (item.parentNode.c1_sel_item == item)
        item.parentNode.c1_sel_item = null;
    // update the global c1c_active_menu var if needed.
    if (c1c_active_menu == item.parentNode && !c1c_active_menu.c1_menu_item)
        c1c_active_menu = null;
}

// pops up item's submenu
function c1c_popup_item_menu(item)
{
    var submenu_id = c1c_getattr(item, 'c1_submenu_id');
    if (submenu_id) {
        var submenu = document.getElementById(submenu_id);
        if (submenu) {
            c1c_show_submenu(item, submenu);
            item.c1_submenu = submenu;
            submenu.c1_parent_item = item;
            item.parentNode.c1_menu_item = item;
        }
    }
}

function c1c_popdown_item_menu_delayed(id)
{
    var item = document.getElementById(id);
    if (item && item.parentNode.c1_sel_item != item)
        c1c_popdown_item_menu(item);
}

// pops down item's submenu
function c1c_popdown_item_menu(item)
{
    var submenu = item.c1_submenu;
    if (submenu) {
        // recursively unselect and pop down all nested menus
        if (submenu.c1_menu_item)
            c1c_popdown_item_menu(submenu.c1_menu_item);
        if (submenu.c1_sel_item)
            c1c_unselect_item(submenu.c1_sel_item);
        c1c_hide_submenu(submenu);
        submenu.c1_parent_item = null;
        item.c1_submenu = null;
        item.parentNode.c1_menu_item = null;
        // update the global c1c_active_menu var if needed.
        if (c1c_active_menu == item.parentNode && !c1c_active_menu.c1_sel_item)
            c1c_active_menu = null;
    }
}

function popdown_and_unselect(menu)
{
    // remove any popup menus, remove selection.
    if (menu) {
        if (menu.c1_menu_item)
            c1c_popdown_item_menu(menu.c1_menu_item);
        if (menu.c1_sel_item)
            c1c_unselect_item(menu.c1_sel_item);
    }
}

// ---- none of the functions below deal with menu tracking logic ----

function c1c_hilite_item(item, on)
{
    if (on) {
        // styles
        c1c_add_styles(item, c1c_getattr(item.parentNode, 'c1_sel_item_styles'));
        c1c_add_styles(item, c1c_getattr(item, 'c1_sel_item_styles'));
        // image
        if (!item.c1_img && c1c_getattr(item, 'c1_img_src') && c1c_getattr(item, 'c1_img_sel_src')) {
            item.c1_img = new Image;
            item.c1_img.src = c1c_getattr(item, 'c1_img_src');
            item.c1_img_sel = new Image;
            item.c1_img_sel.src = c1c_getattr(item, 'c1_img_sel_src');
        }
        if (item.c1_img) {
            if (item.childNodes)
                item.childNodes[0].childNodes[0].src = item.c1_img_sel.src;
            else {
                item.getElementsByTagName('IMG')[0].src = item.c1_img_sel.src;
            }
        }
    }
    else {
        // styles
        c1c_remove_styles(item, c1c_getattr(item, 'c1_sel_item_styles'));
        c1c_remove_styles(item, c1c_getattr(item.parentNode, 'c1_sel_item_styles'));
        c1c_add_styles(item, c1c_getattr(item.parentNode, 'c1_item_styles'));
        c1c_add_styles(item, c1c_getattr(item, 'c1_item_styles'));
        // image
        if (item.c1_img) {
            if (item.childNodes)
                item.childNodes[0].childNodes[0].src = item.c1_img.src;
            else
                item.getElementsByTagName('IMG')[0].src = item.c1_img.src;
        }
    }
}

function c1c_show_submenu(item, submenu)
{
    submenu.style.visibility = 'visible';
    var tx, ty;
    if (c1c_getattr(item.parentNode, 'c1_horz')) {
        tx = c1c_offset_x(item);
        ty = c1c_offset_y(item) + item.offsetHeight;
    }
    else {
        tx = c1c_offset_x(item) + item.offsetWidth;
        ty = c1c_offset_y(item);
    }
    submenu.style.left = tx;
    submenu.style.top = ty;
}

function c1c_hide_submenu(submenu)
{
    submenu.style.visibility = 'hidden';
}

// function c1c_menu_contains(menu, el)
// {
//     if (!menu || !el)
//         return false;
//     else if (c1c_object_contains(menu, el))
//         return true;
//     else if (menu.c1_sel_item)
//         return c1c_menu_contains(menu.c1_sel_item.c1_submenu, el)
//     else
//         return false;
// }

function c1c_getattr(obj, att)
{
    if (obj.getAttribute)
        return obj.getAttribute(att);
    if (obj.attributes) {
        var a = obj.attributes[att];
        if (a) return a.value;
    } else
        return obj[att];
}

// returns true if obj contains elem inside its tree
function c1c_object_contains(obj, elem)
{
    if (!obj)
        return null;
    else if (obj.contains)
        return obj.contains(elem);
    else
        return _c1c_object_contains(obj, elem);
}

function _c1c_object_contains(obj, elem)
{
    if (!obj)
        return null;
    var i;
    if (!obj.childNodes)
        return false;
    for (i = 0; i < obj.childNodes.length; ++i) {
        var child = obj.childNodes[i];
        if (elem == child)
            return true;
        else if (_c1c_object_contains(child, elem))
            return true;
    }
    return false;
}

function c1c_offset_x(o)
{
    if (typeof(o) != 'object' || o == null)
        return 0;
    else
        return o.offsetLeft + c1c_offset_x(o.offsetParent);
}

function c1c_offset_y(o)
{
    if (typeof(o) != 'object' || o == null)
        return 0;
    else
        return o.offsetTop + c1c_offset_y(o.offsetParent);
}

function c1c_add_styles(el, style_str)
{
    if (!style_str)
        return;
    var kvs = style_str.split(';');
    for (var i = 0; i < kvs.length; ++i) {
        var kv = kvs[i].split(':');
        if (kv.length == 2) {
            if (kv[0] == 'className')
                el.className = kv[1];
            else
                el.style[kv[0]] = kv[1];
        }
    }
}

function c1c_remove_styles(el, style_str)
{
    if (!style_str)
        return;
    var kvs = style_str.split(';');
    for (var i = 0; i < kvs.length; ++i) {
        var kv = kvs[i].split(':');
        if (kv.length == 2) {
            if (kv[0] == 'className')
                el.className = '';
            else
                el.style[kv[0]] = '';
        }
    }
}

// ---- end of file. ----
