Files
ace-step-ui/audiomass-editor/src/contextmenu.js
T

205 lines
5.4 KiB
JavaScript
Executable File

(function ( win, doc, PKAE ) {
'use strict';
var activeMenu = [],
namespace = win,
contextStorage = {},
_id = 0;
var closeEvent = [ 'mousedown', 'touchup' ];
/**
* Goes through every single context instance and terminates
* it.
**/
var closeContext = function ( e, force ) {
if (!e) return ;
if (activeMenu.length === 0) return ;
var el = e.target || e.srcElement;
if (!el || el.className.indexOf('_action') === -1 || force)
{
var l = activeMenu.length;
while (l--) terminate (activeMenu[ l ]);
activeMenu = [];
}
},
/**
* Go through every children element of the context el,
* and remove all listeners and added attributes, then remove it
* from the dom also
**/
terminate = function( e ) {
var children = e.currentMenu.getElementsByTagName('*'),
len = children.length;
while( len-- )
children[ len ].parentNode.removeChild( children[ len ] );
e.currentMenu.removeEventListener( closeEvent, stopPropagation );
doc.body.removeChild( e.currentMenu );
e.currentMenu = null;
return false;
},
/** stop propagation func, so that we don't have to use anonymous funcs **/
stopPropagation = function(e){ e.stopPropagation(); },
openContext = function( e, x, y ) {
closeContext(null);
activeMenu.push( e );
//go through all the options and make the div
var div = doc.createElement('div'),
a,
marginOffset = 4,
opts = e.options,
leftOffset = x - marginOffset,
topOffset = y - marginOffset,
width = 0, height = 0;
div.className = "pk_contextMenu " + e.menuClass;
div.id = e.token;
for( var i = 0, len = opts.length; i < len; ++i ) {
if( opts[ i ].isHTML )
{
a = doc.createElement('div');
a.innerHTML = opts[ i ].isHTML;
div.appendChild( a );
}
else {
a = doc.createElement('a');
a.className = 'pk_ctx_action';
a.cnt = 1;
a.innerHTML = opts[ i ].name;
a.callback = opts[ i ].callback;
a.addEventListener( 'click', a.callback, false );
div.appendChild( a );
}
}
e.currentMenu = div;
div.addEventListener( closeEvent, stopPropagation, false );
doc.body.appendChild( div );
width = div.offsetWidth;
height = div.offsetHeight;
if( win.innerWidth < ( leftOffset + width ) && win.innerHeight < ( topOffset + height ) )
div.style.cssText = "top:" + ( topOffset - height ) + "px;left:" + ( leftOffset - width ) + "px;";
else if( win.innerWidth < ( leftOffset + width ) )
div.style.cssText = "top:" + ( topOffset ) + "px;left:" + ( leftOffset - width ) + "px;";
else if( win.innerHeight < ( topOffset + height ) )
div.style.cssText = "top:" + ( topOffset - height ) + "px;left:" + ( leftOffset ) + "px;";
else
div.style.cssText = "top:" + ( topOffset ) + "px;left:" + ( leftOffset ) + "px;";
if (e.onOpen) {
e.onOpen ( e, div );
}
return false;
},
openMenu = function( e )
{
if (e) {
e.preventDefault();
e.stopPropagation();
}
else {
e = {pageX:0, pageY:0};
}
// ----
var instance = getInstance ( this );
var pageX = e.pageX || e.clientX + doc.documentElement.scrollLeft;
var pageY = e.pageY || e.clientY + doc.documentElement.scrollTop;
if (!instance) return false;
instance.curr_target = e.target || e.srcElement;
openContext ( instance, pageX, pageY );
},
getInstance = function( elem ) {
return contextStorage[ elem.getAttribute( 'data-token' ) ];
};
/**
* Context Menu Constructor
**/
var contextMenu = namespace.contextMenu = function( elem, options ) {
if (!(this instanceof contextMenu)) return new contextMenu( elem, options );
if (!options) options = {};
var open_events = ['contextmenu', 'longpress'];
this.elem = elem;
this.options = [];
this.menuClass = options.className || 'pk_open';
this.curr_target = null;
// modified context menu to open only when double click + no movement
// if (elem) elem.addEventListener( 'contextmenu', openMenu, false );
if (elem) elem.addEventListener( 'pk_ctxmn', openMenu, false );
this.token = ++_id;
if (elem) elem.setAttribute( 'data-token', this.token );
contextStorage[ this.token ] = this;
};
/**
* Wrapper to the private openMenu function
**/
contextMenu.prototype.open = function( e ) {
openMenu.call( this.elem, e );
};
contextMenu.prototype.close = function( e ) {
closeContext();
};
contextMenu.prototype.openWithToken = function( token, x, y ) {
openContext( contextStorage[ token ], x||0, y||0 );
};
/**
* Closes context and removes it fully
**/
contextMenu.prototype.destroy = function() {
// this.elem.removeEventListener( 'contextmenu', openMenu );
this.elem.removeEventListener( 'pk_ctxmn', openMenu );
closeContext();
contextStorage[ this.token ] = null;
return false;
},
/**
* Adds option
* @param string name of the option
* @param function to run when its chosen
* @param if this is set, then append the HTML instead of its name in its position
* @param initialization code to run when the object is appended to the dom
**/
contextMenu.prototype.addOption = function( name, callback, isHTML ) {
var q = this;
this.options.push({ "name" : name, "callback" : function( e ) {
callback && callback( q, q._open );
closeContext( q, true );
},
"isHTML" : isHTML
});
};
// todo touch controls too? ####
doc.addEventListener( closeEvent[0], closeContext, false );
doc.addEventListener( 'killCTX', closeContext, false );
PKAE._deps.ContextMenu = contextMenu;
})( window, document, PKAudioEditor );