/*
  popupmenu.js - simple JavaScript popup menu library.

  Copyright (C) 2008 Jiro Nishiguchi <jiro@cpan.org> All rights reserved.
  This is free software with ABSOLUTELY NO WARRANTY.

  You can redistribute it and/or modify it under the modified BSD license.

  Usage:
    var popup = new PopupMenu();
    popup.add(menuText, function(target){ ... });
    popup.addSeparator();
    popup.bind('targetElement');
    popup.bind(); // target is document;
*/

/*
  Modifications:
  
  2008-05-09 -tr-:
    - Opera 9+ compatibility
    - Default style can be overridden by CSS classes: 
      -- '.popupmenu' : menu box
      -- '.popupitem' : menu item (not selected)
      -- '.popupselected' : selected menu item
      -- '.popuptitle' : menu title
    - Click outside the menu hides it, without previous call of "bind" method
    - plus function to display menu: showmenu()
    - New menu item type: title - popup.addTitle(titleText);
*/

var PopupMenu = function() {
    this.init();
}
PopupMenu.SEPARATOR = 'PopupMenu.SEPARATOR';
PopupMenu.TITLE     = 'PopupMenu.TITLE'; // added -tr-
PopupMenu.current = null;
PopupMenu.addEventListener = function(element, name, observer, capture) {
    if (typeof element == 'string') {
        element = document.getElementById(element);
    }
    if (element.addEventListener) {
        element.addEventListener(name, observer, capture);
    } else if (element.attachEvent) {
        element.attachEvent('on' + name, observer);
    }
};
PopupMenu.prototype = {
    init: function() {
        this.items  = [];
        this.width  = 0;
        this.height = 0;
    },
    setSize: function(width, height) {
        this.width  = width;
        this.height = height;
        if (this.element) {
            var self = this;
            with (this.element.style) {
                if (self.width)  width  = self.width  + 'px';
                if (self.height) height = self.height + 'px';
            }
        }
    },
    bind: function(element) {
        var self = this;
        if (!element) {
            element = document;
        } else if (typeof element == 'string') {
            element = document.getElementById(element);
        }
        this.target = element;
        this.target.oncontextmenu = function(e) {
            self.show.call(self, e);
            return false;
        };
        var listener = function() { self.hide.call(self) };
        PopupMenu.addEventListener(document, 'click', listener, true);
    },
    add: function(text, callback) {
        this.items.push({ text: text, callback: callback });
    },
    addSeparator: function() {
        this.items.push(PopupMenu.SEPARATOR);
    },
    setPos: function(e) {
        if (!this.element) return;
        if (!e) e = window.event;
                var x, y;
        if (window.opera) {
            x = e.clientX;
            y = e.clientY;
        } else if (document.all) {
            x = document.body.scrollLeft + e.clientX; // mod'd -tr- event.clientX;
            y = document.body.scrollTop + e.clientY;  // mod'd -tr- event.clientY;
        } else if (document.layers || document.getElementById) {
            x = e.pageX;
            y = e.pageY;
        }
        this.element.style.top  = y + 'px';
        this.element.style.left = x + 'px';
    },
    show: function(e) {
        if (PopupMenu.current && PopupMenu.current != this) return;
        PopupMenu.current = this;
        if (this.element) {
            this.setPos(e);
            this.element.style.display = '';
        } else {
            this.element = this.createMenu(this.items);
            this.setPos(e);
            document.body.appendChild(this.element);
        }
    },
    hide: function() {
        PopupMenu.current = null;
        if (this.element) this.element.style.display = 'none';
    },
    createMenu: function(items) {
        var self = this;
        var menu = document.createElement('div');
        menu.className = 'popupmenu'; // added -tr-
        
        with (menu.style) {
            if (self.width)  width  = self.width  + 'px';
            if (self.height) height = self.height + 'px';
            border     = "1px solid gray";
            /* del'd -tr- CSS can't override colors if set (?!)
            background = '#FFFFFF';
            color      = '#000000';
            */
            position   = 'absolute';
            display    = 'block';
            padding    = '2px';
            cursor     = 'default';
        }
        for (var i = 0; i < items.length; i++) {
            var item;
            if (items[i] == PopupMenu.SEPARATOR) {
                item = this.createSeparator();
            /* del'd
            } else {
                item = this.createItem(items[i]);
            }
            */
            /* added -tr- */
              }
            else 
              {
               if (items[i].type == PopupMenu.TITLE) 
                 {
                  item = this.createTitle(items[i]);
                 }
               else
                 item = this.createItem(items[i]);
              }
            /* ended -tr- */
            menu.appendChild(item);
        }
        /* added -tr- : click hides menu without previous call of "bind" method */
        PopupMenu.addEventListener(document, 'click', function() { self.hide.call(self) }, true);
        /* ended -tr- */
        return menu;
    },
    createItem: function(item) {
        var self = this;
        var elem = document.createElement('div');
        elem.style.padding = '4px';
        elem.className  = 'popupitem'; // added -tr-
        var callback = item.callback;
        PopupMenu.addEventListener(elem, 'click', function(_callback) {
            return function() {
                self.hide();
                _callback(self.target);
            };
        }(callback), true);
        PopupMenu.addEventListener(elem, 'mouseover', function(e) {
            // elem.style.background = '#B6BDD2'; // del'd -tr-
            elem.className = 'popupselected';   // add'd -tr-
        }, true);
        PopupMenu.addEventListener(elem, 'mouseout', function(e) {
            // elem.style.background = '#FFFFFF'; // del'd -tr-
            elem.className = 'popupitem';   // add'd -tr-
        }, true);
        /* del'd -tr: replace with Opera compatible solutuion
        elem.appendChild(document.createTextNode(item.text)); 
        */
        /* added -tr- : Opera 9+ comapatibility - use 'A' child element instead of text node */
        newElem = document.createElement("a");
        newElem.innerHTML = item.text;
        elem.appendChild(newElem);
        /* ended -tr */
        return elem;
    },
    createSeparator: function() {
        var sep = document.createElement('div');
        sep.className = 'popupseparator'; // added -tr-
        with (sep.style) {
            borderTop = '1px dotted #CCCCCC';
            fontSize  = '0px';
            height    = '0px';
        }
        return sep;
    }
    /* added -tr- */
    ,
    addTitle: function(text) {
        this.items.push( { text: text, type : PopupMenu.TITLE} );
    },
    createTitle: function(item) {
        var ttl = document.createElement('div');
        ttl.className = 'popuptitle'; 
        ttl.appendChild(document.createTextNode(item.text));
        return ttl;
    }
    /* ended -tr- */
    
};

/*
  =========================================================================
  showmenu() -tr-
  Funtion: displays directly a popupmenu (without binding it) at event or object position
  Parameters: 
    objMenu - 'PopupMenu' object variable for the menu to show
    objEvent - 'event' object variable of the envoking event (especially cursor position in it)
    idObj - ID of an object to get position if objEvent is null
    defPos - default position {X: X, y: X} if navigator (eg. IE) does not support absolute position of objects
*/
function showmenu(objMenu, objEvent, idObj, defPos)
{

  if (PopupMenu.current)
    PopupMenu.current.hide.call(PopupMenu.current, null);
  if (idObj && !objEvent)
    {
      var objId = document.getElementById(idObj);
      // objEvent = { pageX: objId.x, pageY: objId.y, clientX: objId.x, clientY: objId.y };
      if (objId.x)
        { // Firefox etc.
         objEvent = { pageX: objId.x, pageY: objId.y, clientX: objId.x, clientY: objId.y };
        }
      else
        { // Internet Explorer etc.
         var ofsXY = 0;
         if (navigator.userAgent.indexOf('MSIE') > 0) ofsXY = 5;
         objEvent = { pageX: defPos.x + ofsXY, pageY: defPos.y + ofsXY, clientX: defPos.x + ofsXY, clientY: defPos.y + ofsXY};
        }
    }
  if (objMenu && objEvent)
    objMenu.show.call(objMenu, objEvent);
}
