/**
* @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);