// Popup menu
// Version 1.0

/*
container:

the element whose context menu we are creating.

menus:
is an array with a structure like this:
    var menus = [
        { name:  'Cut', action: item, disabled: true },
        { name:  'Copy', action: item, disabled: true },
        { name:  'Paste', action: item, disabled: true },
        { name:  '' }, // if name is '' then it is used as a separator
        { name:  'Select all', action: item, disabled: false }
    ];

setPosition:
    true if you want the popup menu to be in the position of the mouse click
    if you don't want it to change the position, false

objToCall:
If you want the callbacks to be called in some object's context call PopupMenu with that object as objToCall

*/
function PopupMenu(container, menus, setPosition, objToCall) {
    this.container = container;
    this.menus = menus;
    this.openMenuEvent = 'contextmenu';
    if (!objToCall) {
        objToCall = this;
    }
    if (!setPosition) {
        this.setPosition = function() { };
    }
    this.objToCall = objToCall;
    this.create();
}

PopupMenu.prototype.registerElement = function(element, data) {
    if (data) {
        element.popupMenuData = data;
    }
    if (element.tagName.toLowerCase() == 'iframe') {
        DOM.addObjEventListener(this, element.contentWindow.document, this.openMenuEvent, this.open);
    } else {
        DOM.addObjEventListener(this, element, this.openMenuEvent, this.open);
    }
}


// This is here because something might want to execute something before opening the context menu
PopupMenu.prototype.onbeforeopen = function(event) { }

PopupMenu.prototype.create = function() {
    var div, i, containerDiv = document.createElement('div');
    var menuDiv = document.createElement('div');
    
    for (i = 0; i < this.menus.length; i++) {
        div = document.createElement('div');
        if (!this.menus[i].name) { // separator
            div.className = 'separator';
            if (DOM.isIE) {
                var img = document.createElement('img');
                img.width = 1;
                img.height = 1;
                div.appendChild(img);
            }
        } else { // menu item
            div.appendChild(document.createTextNode(this.menus[i].name));
            this.setMenuItemDivDisabled(div, this.menus[i].disabled, this.menus[i].action);
            this.menus[i].div = div;
        }
        menuDiv.appendChild(div);
    }
    menuDiv.style.position = 'absolute';
    menuDiv.style.zIndex = '10000';
    menuDiv.style.display = 'none';
    menuDiv.className = 'popupMenu';
    containerDiv.style.position = 'relative';
    containerDiv.appendChild(menuDiv);
    this.container.parentNode.insertBefore(containerDiv, this.container);
    this.popupMenuDiv = menuDiv;
    this.created = true;
}

PopupMenu.prototype.setMenuItemDivDisabled = function(div, disabled, actionToCall) {
    if (disabled) {
        DOM.addClass(div, 'disabled');
        div.onmouseup = function() { };
        div.onmouseover = function() { };
    } else {
        DOM.removeClass(div, 'disabled');
        div.onmouseup = function(self) { return function() { actionToCall.call(self.objToCall); self.close(); } }(this);
        div.onmouseover = function() { DOM.addClass(div, 'mouse-over') };
        div.onmouseout = function() { DOM.removeClass(div, 'mouse-over') };
    }
}

// Sets or removes the disabled attribute of the menu
PopupMenu.prototype.setDisabled = function(item_id, disabled) {
    var div;
    for (var i = 0; i < this.menus.length; i++) {
        if (item_id == this.menus[i].id) {
            this.setMenuItemDivDisabled(this.menus[i].div, disabled, this.menus[i].action);
            this.menus[i].disabled = disabled;
            break;
        }
    }
}

PopupMenu.prototype.preventClick = function(event) {
    var eventPos = DOM.getPositionFromEvent(event);
    var elementPos = DOM.getPosition(this.popupMenuDiv);
    var scrollPos = DOM.getScrollBarPositions();
    elementPos.x0 = elementPos.x + scrollPos.x
    elementPos.y0 = elementPos.y + scrollPos.y
    elementPos.x1 = elementPos.x + this.popupMenuDiv.offsetWidth + scrollPos.x;
    elementPos.y1 = elementPos.y + this.popupMenuDiv.offsetHeight + scrollPos.y;
    if (DOM.getPositionInsideBoundaries(eventPos, elementPos)) {
        return;
    }
    this.close();
    DOM.preventDefault(event);
    DOM.stopPropagation(event);
}

PopupMenu.prototype.preventKeys = function(event) {
    if (event.keyCode == 27) {
        this.close();
    }
    DOM.preventDefault(event);
    DOM.stopPropagation(event);
}

PopupMenu.prototype.holdEvents = function() {
    var me = this;
    function registerEventsOnFrameAndSubframes(windowObj)
    {
        DOM.addObjEventListener(me, windowObj.document, 'mousedown', me.preventClick);
        DOM.addObjEventListener(me, windowObj.document, 'keypress', me.preventKeys);
        for (var i = 0; i < windowObj.frames.length; i++) {
            registerEventsOnFrameAndSubframes(windowObj.frames[i]);
        }
    }
    registerEventsOnFrameAndSubframes(window.top);
}

PopupMenu.prototype.releaseEvents = function() {
    var me = this;
    function unregisterEventsOnFrameAndSubframes(windowObj)
    {
        DOM.removeObjEventListener(me, windowObj.document, 'mousedown', me.preventClick);
        DOM.removeObjEventListener(me, windowObj.document, 'keypress', me.preventKeys);
        for (var i = 0; i < windowObj.frames.length; i++) {
            unregisterEventsOnFrameAndSubframes(windowObj.frames[i]);
        }
    }
    unregisterEventsOnFrameAndSubframes(window.top);
}

PopupMenu.prototype.setPosition = function(mousePosition) {
    this.popupMenuDiv.style.left = (mousePosition.x) + 'px';
    this.popupMenuDiv.style.top = (mousePosition.y) + 'px';
}

PopupMenu.prototype.open = function(event) {
    this.onbeforeopen(event);
    if (!this.created) {
        this.create();
    }
    var pos = DOM.getPositionFromEvent(event);
    var pagePos = DOM.getScrollBarPositions();
    this.setPosition({ x: pos.x - pagePos.x, y: pos.y - pagePos.y });
            
    this.popupMenuDiv.style.display = '';
    DOM.preventDefault(event);
    DOM.stopPropagation(event);
    this.holdEvents();
}

PopupMenu.prototype.close = function() {
    this.popupMenuDiv.style.display = 'none';
    this.releaseEvents();
}
