/**
 * Script: mootools.ddmenu.99.js
 *  ddmenu is a simple MooTools-based script to create your own context menus
 *
 * License:
 *  MIT-style license.
 *
 * Author:
 * jan angel manolov <email@webhike.de>  <http://netjard.de/lab/ddmenu>
 *
 *  Changelog:
 *  v.1.0 [6/17/08]
 * 	- MooTools 1.2 Ready
 *
 *  v0.99 [6/9/08]
 * 	- the ddmenu works good, no bugs considered since the last update.
 * 	- waiting for the mootools 1.2 release, to get a final version of the ddmenu.
 * 	- url changed to <netjard.de/labs/ddmenu>
 *
 * v.0.2.1 [2/11/08]
 *     Fixes for MooTools 1.2 Beta 2
 *
 * v.0.2 [1/1/08]
 *     Scroll-save, correct positioning
 *     Ctrl and Shift Switches
 *     Fade In
 *     CSS-Styles reworked and adapted
 *     This Demo Page and Google Code registration
 *
 * v.0.1 [11/07]
 *     Initial Version with a basic menu script structure
 *     Event-calls and enableItems(), enableOnlyThisItems() Functions
 *     Adapted the complex when-menu-is-opened events on the System Context Menu Style
 *
 *
 * Use enableThisItemsOnly and enableItems to enable or disable menu items by their ids
 *
 *     enableThisItemsOnly ([item1,item2], true)   	-> disable all other
 *     enableThisItemsOnly (item)                   -> same
 *     enableThisItemsOnly ([item1,item2], false)  	-> enable all other
 *
 *     enableItems ([item1,item2])           		-> enable these items
 *     enableItems (item1)                   		-> same
 *     enableItems ([item1,item2], false)    		-> disable these items
 *     enableItems ()                        		-> enable all items
 *     enableItems (false)                   		-> disable all
 */
var DDMenu = new Class({

    Implements: [Events, Options],
    
    options: {
        onOpen:                 $empty,
        onClose:                $empty,
        onItemSelect:           $empty,
        observe_disabled_items: false,           // Call onItemSelect() on disabled items?
        rightclick_to_open:     false,           // Open menu on rightclick (if browser supports contextmenu-events)
        crtl_switch:            true,            // Allow to switch between default menu and dd
        shift_with_contentmenu: true,  //not ie  // Show default & dd menu together
        fade_in:                true,
        cursorx:                2,               // Distance to cursors-coords
        cursory:                1,
        opacity:                0.95             // Menu transparency
    },
    
    /**
     * @param {Object} menu
     * @param {Object} bindon
     * @param {Object} options
     */
    initialize: function(menu, bindon, options){
    
        this.setOptions(options);
        this.eMenu = $(menu);
        this.eBindon = $(bindon);
        
        this.eMenu.setStyles({
            'position': 'absolute',
            'z-index': 9999,
            'display': 'none'
        });
        
        this.open = this.open.bindWithEvent(this);
        this.close = this.close.bind(this);
        this.preOpenEvent = this.preOpenEvent.bind(this)
        this.menuEvent = this.menuEvent.bindWithEvent(this);
        
        this.clickedElement = $empty;
        
        this.eBindon.addEvents({
            'mousedown': function(){
                this.eBindon.addEvent('contextmenu', $break);
            }.bind(this),
            'mouseup': this.preOpenEvent
        });
        
        //this.eMenu.getElements('li.item a').addEvent('click', $break); //safari bug :(
        $$('#' + menu + ' li a').addEvent('click', $break);
    },
    
    /**
     * @param {Object} event
     */
    preOpenEvent: function(event){

		if (event.shift) 
            this.eBindon.removeEvent('contextmenu', $break);
        else 
            if (this.options.crtl_switch && event.rightClick && event.control) { // Open browser default contextmenu
                this.eBindon.removeEvent('contextmenu', $break);
                return true;
            }
        
        event.preventDefault();
        
        if (this.eMenu.style.display == 'block') 
            this.close(event);
        
        this.clickedElement = $(event.target);
        
		// Si on a choisi le clic-droit comme déclencheur
		if (this.options.rightclick_to_open){
			
	        if (event.rightClick) {
	            if (this.options.crtl_switch && event.control) 
	                return true;
	            else 
	                if (this.options.rightclick_to_open) 
	                    this.open(event);
	        }
			
	        if (event.control) 
	            this.open(event);
	        else 
	            return true;
		}
		
		// Clic gauche comme déclencheur
		else {
			if (event.rightClick)
    	        return true;
			this.open(event);
	        return false;
		}
    },
    
    /**
     * @param {Object} event
     */
    open: function(event){
    
        this.eMenu.setStyles({
            'display': 'block',
            'z-index': 99999,
            'opacity': 0,
            'top': event.page.y + this.options.cursory,
            'left': event.page.x + this.options.cursorx
        });
        
        var coords = {};
        
        //   hauteur relative du menu
        // -        hauteur du scroll
        // +          hauteur du menu
        // --------------------------
        // <      hauteur du document
        (this.eMenu.getPosition().y - $(document.body).getScroll().y + this.eMenu.getSize().y < $(document.body).getSize().y) ? 
			coords.y = event.page.y + this.options.cursory :
			coords.y = event.page.y - this.eMenu.getSize().y + this.options.cursory;
        
        if (coords.y < $(document.body).getScroll().y + 1) 
            coords.y = $(document.body).getScroll().y + 1;
        
        (this.eMenu.getPosition().x - $(document.body).getScroll().x + this.eMenu.getSize().x < $(document.body).getSize().x) ?
			coords.x = event.page.x + this.options.cursorx :
			coords.x = event.page.x - this.eMenu.getSize().x + this.options.cursorx;
        
        if (coords.x < $(document.body).getScroll().x + 1) 
            coords.x = $(document.body).getScroll().x + 1;
        
        if (event.shift) 
            coords.x = event.page.x - this.eMenu.getSize().x - this.options.cursorx;
        
        this.eMenu.setStyles({
            'top': coords.y,
            'left': coords.x
        });
        
        if (this.options.fade_in) {
            var op = this.options.opacity;
            var fadein = new Fx.Morph(this.eMenu, {
                duration: 200
            }).start({
                'opacity': [.32, op]
            });
        }
        else 
            this.eMenu.style.opacity = this.options.opacity;
        
        // IE throws currious blur events
        if (!Browser.Engine.trident) 
            window.addEvent('blur', function(){
                this.close();
            }.bind(this));
        
        document.addEvent('mousedown', this.menuEvent);
        
        this.eMenu.addEvents({
            'contextmenu': function(){
                return false
            },
            'mouseup': this.menuEvent
        });
        
        this.fireEvent('onOpen', [event, this.clickedElement]);
    },
    
    /**
     * @param {Object} event
     */
    menuEvent: function(event){
    
        event.preventDefault();
        
        var item = $(event.target);
        
        if (item == this.eMenu || item == this.eMenu.getElement('ul')) 
            return false;
        
        item = this.ascendTo(item, ['item', 'sepline', 'title']);
        
        if (item === false) {
            this.close(event); //outer event
        }
        else 
            if (item.hasClass('item') && event.type == 'mouseup') {
                if (!(item.getElement('a').hasClass('disabled') && !this.options.observe_disabled_items)) {
                    this.action(item);
                    this.close(event);
                }
            }
    },
    
    /**
     * @param {Object} event
     */
    close: function(event){
    
        this.eMenu.style.display = 'none';
        
        document.removeEvent('mousedown', this.menuEvent);
        window.removeEvent('blur', function(){
            if (!Browser.Engine.trident) 
                this.close()
        }.bind(this));
        this.eMenu.removeEvents();
        
        this.fireEvent('onClose', event);
    },
    
    /**
     * @param {Object} item
     */
    action: function(item){
        //this.clickedElement.focus();
        this.fireEvent('onItemSelect', [item.get('id'), this.clickedElement, this.eBindon]);
        return;
    },
    
    /**
     * @param {Object} el
     * @param {Object} peakto
     */
    ascendTo: function(el, peakto){
    
        if (el == window) 
            return false;
        
        var ascel = el;
        
        while (ascel.get('tag') != 'html') {
        
            for (var i = 0; i < peakto.length; i++) {
                if (ascel.hasClass(peakto[i])) 
                    return ascel;
            }
            ascel = ascel.getParent();
        }
        return false;
    },
    
    /**
     * @param {Object} items
     * @param {Object} enable
     */
    enableThisItemsOnly: function(items, enable){
    
        if (!$chk(enable) && enable != false) 
            enable = true;
        if ($type(items) == 'string') 
            items = [items];
        if (!items.length) 
            return;
        
        (enable == true) ?
			this.eMenu.getElements('li.item a').addClass('disabled') :
			this.eMenu.getElements('li.item a').removeClass('disabled');
        
        items.each(function(item){
            (enable == true) ?
				this.eMenu.getElement('li#' + item + ' a').removeClass('disabled') :
				this.eMenu.getElement('li#' + item + ' a').addClass('disabled');
        }.bind(this));
    },
    
    /**
     * @param {Object} items
     * @param {Object} enable
     */
    enableItems: function(items, enable){
    
        if (!$chk(items) && items != false) 
            items = true;
        
        if ($type(items) == 'boolean') {
            items == true ?
				this.eMenu.getElements('li.item a').removeClass('disabled') :
				this.eMenu.getElements('li.item a').addClass('disabled');
            return;
        }
        
        if (!$chk(enable) && enable != false) 
            enable = true;
        
        if ($type(items) == 'string') 
            items = [items];
        
        items.each(function(item){
            enable == true ?
				this.eMenu.getElement('li#' + item + ' a').removeClass('disabled') :
				this.eMenu.getElement('li#' + item + ' a').addClass('disabled');
        }.bind(this));
    }
});

$break = function(){
    return false;
}

