/** * @author Ryan Johnson * @copyright 2008 PersonalGrid Corporation * @package LivePipe UI * @license MIT * @url http://livepipe.net/control/contextmenu * @require prototype.js, livepipe.js */ /*global window, document, Prototype, Class, Event, $, $A, $R, Control, $value */ if(typeof(Prototype) == "undefined") { throw "Control.ContextMenu requires Prototype to be loaded."; } if(typeof(Object.Event) == "undefined") { throw "Control.ContextMenu requires Object.Event to be loaded."; } Control.ContextMenu = Class.create({ initialize: function(container,options){ Control.ContextMenu.load(); this.options = Object.extend({ leftClick: false, disableOnShiftKey: true, disableOnAltKey: true, selectedClassName: 'selected', activatedClassName: 'activated', animation: true, animationCycles: 2, animationLength: 300, delayCallback: true },options || {}); this.activated = false; this.items = this.options.items || []; this.container = $(container); this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'),function(event){ if(!Control.ContextMenu.enabled || Prototype.Browser.Opera && !event.ctrlKey) { return; } this.open(event); }.bindAsEventListener(this)); }, open: function(event){ if(Control.ContextMenu.current && !Control.ContextMenu.current.close()) { return; } if(this.notify('beforeOpen',event) === false) { return false; } this.buildMenu(); if(this.items.length === 0){ this.close(event); return false; } this.clicked = Event.element(event); Control.ContextMenu.current = this; Control.ContextMenu.positionContainer(event); Control.ContextMenu.container.show(); if(this.notify('afterOpen',event) === false) { return false; } event.stop(); return true; }, close: function(event){ if(event) { event.stop(); } if(this.notify('beforeClose') === false) { return false; } Control.ContextMenu.current = false; this.activated = false; Control.ContextMenu.container.removeClassName(this.options.activatedClassName); Control.ContextMenu.container.select('li').invoke('stopObserving'); Control.ContextMenu.container.hide(); Control.ContextMenu.container.update(''); if(this.notify('afterClose') === false) { return false; } return true; }, buildMenu: function(){ var list = document.createElement('ul'); Control.ContextMenu.container.appendChild(list); this.items.each(function(item){ if(!(!item.condition || item.condition && item.condition() !== false)) { return; } var item_container = $(document.createElement('li')); item_container.update($value(item.label)); list.appendChild(item_container); item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled'); item_container.observe('mousedown',function(event,item){ if(!$value(item.enabled)) { return event.stop(); } this.activated = $value(item.label); }.bindAsEventListener(this,item)); item_container.observe('click',this.selectMenuItem.bindAsEventListener(this,item,item_container)); item_container.observe('contextmenu',this.selectMenuItem.bindAsEventListener(this,item,item_container)); }.bind(this)); }, addItem: function(params){ if (!('enabled' in params)) { params.enabled = true; } this.items.push(params); return this; }, destroy: function(){ this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu'); this.items = []; }, selectMenuItem: function(event,item,item_container){ if(!$value(item.enabled)) { return event.stop(); } if(!this.activated || this.activated == $value(item.label)){ if(this.options.animation){ Control.ContextMenu.container.addClassName(this.options.activatedClassName); $A($R(0,this.options.animationCycles * 2)).each(function(i){ window.setTimeout(function(){ item_container.toggleClassName(this.options.selectedClassName); }.bind(this),i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10)); }.bind(this)); window.setTimeout(function(){ if(this.close() && this.options.delayCallback) { item.callback(this.clicked); } }.bind(this),this.options.animationLength); if(!this.options.delayCallback) { item.callback(this.clicked); } }else if(this.close()) { item.callback(this.clicked); } } event.stop(); return false; } }); Object.extend(Control.ContextMenu,{ loaded: false, capture_all: false, menus: [], current: false, enabled: false, offset: 4, load: function(capture_all){ if(Control.ContextMenu.loaded) { return; } Control.ContextMenu.loaded = true; if(typeof(capture_all) == 'undefined') { capture_all = false; } Control.ContextMenu.capture_all = capture_all; Control.ContextMenu.container = $(document.createElement('div')); Control.ContextMenu.container.id = 'control_contextmenu'; Control.ContextMenu.container.style.position = 'absolute'; Control.ContextMenu.container.style.zIndex = 99999; Control.ContextMenu.container.hide(); document.body.appendChild(Control.ContextMenu.container); Control.ContextMenu.enable(); }, enable: function(){ Control.ContextMenu.enabled = true; Event.observe(document.body,'click',Control.ContextMenu.onClick); if(Control.ContextMenu.capture_all) { Event.observe(document.body,'contextmenu',Control.ContextMenu.onContextMenu); } }, disable: function(){ Event.stopObserving(document.body,'click',Control.ContextMenu.onClick); if(Control.ContextMenu.capture_all) { Event.stopObserving(document.body,'contextmenu',Control.ContextMenu.onContextMenu); } }, onContextMenu: function(event){ event.stop(); return false; }, onClick: function(){ if(Control.ContextMenu.current) { Control.ContextMenu.current.close(); } }, positionContainer: function(event){ var dimensions = Control.ContextMenu.container.getDimensions(); var top = Event.pointerY(event); var left = Event.pointerX(event); var bottom = dimensions.height + top; var right = dimensions.width + left; var viewport_dimensions = document.viewport.getDimensions(); var viewport_scroll_offsets = document.viewport.getScrollOffsets(); if(bottom > viewport_dimensions.height + viewport_scroll_offsets.top) { top -= bottom - ((viewport_dimensions.height + viewport_scroll_offsets.top) - Control.ContextMenu.offset); } if(right > viewport_dimensions.width + viewport_scroll_offsets.left) { left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); } Control.ContextMenu.container.setStyle({ top: top + 'px', left: left + 'px' }); } }); Object.Event.extend(Control.ContextMenu);