popup =
{
  /***************** Служебные функции для работы с DOM ***********************/
  
  // Добавление event handler-а элемента
  domAddEvent : function( el, evname, func )
  {
    if( document.addEventListener ) // gecko-стайл
    {
      el.addEventListener(evname, func, true);
    }
    else if ( document.attachEvent ) // IE-стайл
    {
      el.attachEvent("on" + evname, func);
    }
  },
  
  // Получение координат левого угла элемента относительно тела документа
  domGetOffsetLeft : function ( el )
  {
    var offsetLeft = 0;
    
    for(var offsetParent = el.offsetParent; offsetParent; offsetParent = offsetParent.offsetParent)
    {
      offsetLeft += offsetParent.offsetLeft;
    }
    return offsetLeft + el.offsetLeft;    
  },

  // Получение координат верхнего угла элемента относительно тела документа
  domGetOffsetTop : function ( el )
  {
    var offsetTop = 0;
    
    for(var offsetParent = el.offsetParent; offsetParent; offsetParent = offsetParent.offsetParent)
    {
      offsetTop += offsetParent.offsetTop;
    }
    return offsetTop + el.offsetTop;    
  },
  
  // Получение следующего элемента в дереве документа ( nodeType = 1 )
  // Функция нужна для gecko, который включает в дерево документа
  // текстовые элементы в самых неожиданных местах 
  domGetNextElement : function ( el )
  {
    do
    {
      el = el.nextSibling;
    }
    while( el && el.nodeType != 1 );
    
    return el;
  },
  
  /****************************************************************************/
  
  // Текущее видимое меню
  visibleMenu : null,
  // Handler timeout-а на закрытие меню
  menuHideTimeout : null,

  // Показ всплывающего меню
  show : function( menuId, srcElement )
  {
    // Инициализируем дополнительные события исходного элемента
    popup.installSrcElementEvents( srcElement );
    
    // Инициализируем дополнительные события document.body
    popup.installDocumentEvents();

    // Если меню, которое следует показать не является текущим -
    // скроем текущее меню и назначим новое меню текущим
    if( ! popup.isVisibleMenu( menuId ) )
    {
      popup.hideVisibleMenu();
      popup.setVisibleMenu( menuId, srcElement );
    }
    
    // Отпозиционируем меню
    popup.positionCurrentVisibleMenu();
    
    popup.showVisibleMenu();
  },
  
  // Показ текущего меню
  showVisibleMenu : function()
  {
     if( ! popup.visibleMenu ) return;
     popup.visibleMenu.style.visibility = 'visible';
  },
  
  // Позиционирование текущего видимого меню
  positionCurrentVisibleMenu : function()
  {
    // Проверим, есть ли видимое меню
    if( ! popup.visibleMenu ) return;
    // Проверим наличие начальной ширины и srcElement у текущего меню
    if( ! popup.visibleMenu.initialWidth || ! popup.visibleMenu.srcElement ) return;

    // Координаты и ширина меню    
    var left, top, width;

    // Вычислим ширину меню 
    // width = (popup.visibleMenu.srcElement.offsetWidth + 6) > popup.visibleMenu.initialWidth ? (popup.visibleMenu.srcElement.offsetWidth + 6) : popup.visibleMenu.initialWidth;
    width = popup.visibleMenu.initialWidth;

    // Вычислим координату X меню
    // Если srcElement — последний пункт меню - позиционируем 
    // по его правому краю, иначе - по левому.
    if( popup.isLastMenuItem( popup.visibleMenu.srcElement ) )
      left = popup.domGetOffsetLeft( popup.visibleMenu.srcElement ) + 3 + popup.visibleMenu.srcElement.offsetWidth - width; 
    else
      left = popup.domGetOffsetLeft( popup.visibleMenu.srcElement ) - 3;

    // Откорректируем координату X, если меню вылазит за раницу экрана справа       
    if( left + width > document.body.clientWidth + document.body.scrollLeft )
      left = document.body.clientWidth + document.body.scrollLeft - width;
    
    // Вычислим координату Y
    top = popup.domGetOffsetTop( popup.visibleMenu.srcElement ) + popup.visibleMenu.srcElement.offsetHeight - 1;

    // Установим значения CSS аттрибутов
    popup.visibleMenu.style.top = top + 'px';
    popup.visibleMenu.style.left = left + 'px';
    popup.visibleMenu.style.width = width + 'px'; 
  },
  
  // Установка видимого меню
  setVisibleMenu : function( id, srcElement )
  {
    // Получим объект - меню
    var menu = document.getElementById( id );
    
    if( menu )
    {
      // Установим начальную ширину меню
      if( ! menu.initialWidth )
        menu.initialWidth = menu.offsetWidth;
      
      // Установим srcElement меню
      menu.srcElement = srcElement;
      
      // Установим дополнительные обработчики событий меню
      popup.installMenuEvents( menu );
      
      // Назначим меню      
      popup.visibleMenu = menu;
    }
  },
  
  // Проверка видимости меню с указанным идентификатором и srcElement
  isVisibleMenu : function( id )
  {
    if( ! popup.visibleMenu )
      return false;
    
    if( popup.visibleMenu.getAttribute( 'id' ) != id )
      return false;
    
    return true;    
  },
  
  // Отмена скрытия текущего меню по таймауту 
  cancelMenuHide : function ()
  {
    if( popup.menuHideTimeout )
    {
      clearTimeout( popup.menuHideTimeout );
    }
    popup.menuHideTimeout = null;
  },
  
  // Инициализация событий srcElement-а popup-а  
  installSrcElementEvents : function( el )
  {
    if( el.getAttribute( 'popupEventsInstalled' ) != 1 )
    {
      popup.domAddEvent( el, 'mouseout', popup.initMenuHide );
      popup.domAddEvent( el, 'mousemove', popup.cancelMenuHide );
      el.setAttribute( 'popupEventsInstalled', 1 );
    }
  },
  
  // Инициализация событий popup-меню
  installMenuEvents : function( el )
  {
    if( el.getAttribute( 'popupEventsInstalled' ) != 1 )
    {
      popup.domAddEvent( el, 'mouseover', popup.cancelMenuHide );
      popup.domAddEvent( el, 'mouseout', popup.initMenuHide );
      el.setAttribute( 'popupEventsInstalled', 1 );
    }
  },
  
  // Инициализация событий документа
  installDocumentEvents : function()
  {
    if( document.body.getAttribute( 'popupEventsInstalled' ) != 1 )
    {
      window.onresize = popup.positionCurrentVisibleMenu;
    }
  },

  // Установка таймаута скрытия меню
  initMenuHide : function ()
  {
    popup.cancelMenuHide();
      
    popup.menuHideTimeout = setTimeout( popup.hideVisibleMenu, 500 );    
  },
  
  // Очистка таймаута скрытия меню
  cancelMenuHide : function ()
  {
    if( popup.menuHideTimeout )
    {
      clearTimeout( popup.menuHideTimeout );
    }
    popup.menuHideTimeout = null;
  },
  
  // Является ли элемент последним меню
  isLastMenuItem : function ( el )
  {
    el = popup.domGetNextElement( el );
  
    if( el.className == 'r' )
    {
      return true;
    }
    
    return false;
  },
  
  // Скрытие видимого меню (если таковое имеется)
  hideVisibleMenu : function()
  {
    if( popup.visibleMenu )
    {
      popup.visibleMenu.style.visibility = 'hidden';
      popup.visibleMenu.style.left = popup.visibleMenu.style.top = '';
    }
    popup.visibleMenu = null;
  }
};

/*
  Сделано в Студии Метадизайн
  http://metadesign.ru
*/

