angular-context-menu
Version:
Angular component containing context menu for web application.
160 lines (134 loc) • 5.3 kB
JavaScript
(function(){
var contextMenu, contextMenuController, templateString;
this.templateString =
'<div ng-transclude></div>' +
'<div class="context-menu">' +
' <div class="context-menu-item" ng-repeat="item in items"' +
' ng-class="{ \'separator-context-menu\': item.separator, \'disabled-context-menu-item\': item.disabled, submenu: item.submenu && item.submenu.length}" ng-click="callback(item)">' +
' <div ng-if="!item.separator" class="context-menu" ng-include="\'menu.html\'"></div>' +
' <div ng-if="!item.separator" class="context-menu-icon"><i ng-if="item.icon" class="fa {{item.icon}} aria-hidden="true"></i></div>' +
' {{ item.name }}' +
' <div ng-if="item.submenu" class="context-menu-arrow"><i class="fa fa-caret-right"></i></div> ' +
' </div>' +
' </div>' +
'</div>' +
'<script type="text/ng-template" id="menu.html">' +
' <div class="context-menu-item" ng-repeat="item in item.submenu"' +
' ng-class="{ \'separator-context-menu\': item.separator, \'disabled-context-menu-item\': item.disabled, submenu: item.submenu && item.submenu.length}" ng-click="callback(item)">' +
' <div ng-if="!item.separator" class="context-menu" ng-include="\'menu.html\'"></div>' +
' <div ng-if="!item.separator" class="context-menu-icon"><i ng-if="item.icon" class="fa {{item.icon}} aria-hidden="true"></i></div>' +
' {{ item.name }}' +
' <div ng-if="item.submenu" class="context-menu-arrow"><i class="fa fa-caret-right"></i></div> ' +
' </div>' +
' </div>' +
'</script>';
this.contextMenuController = function(scope, elem, attr){
var randomId = Math.random().toString(36).substring(7);
elem.addClass("context-menu-trigger" + randomId);
elem.ready(function(){
initJQuery(randomId);
});
scope.callback = function(item){
if(item.separator || (item.submenu && item.submenu.length) || !item.callback){
return;
}
item.callback();
};
};
this.contextMenu = function(){
return {
scope: {
items: '=ngContextMenu'
},
link: this.contextMenuController,
restrict: 'A',
template: this.templateString,
transclude: true
};
};
function initJQuery(randomId){
var direction = 0;
var documentWidth = $(document).width();
var documentHeight = $(document).height();
var contextMenu = $('.context-menu-trigger' + randomId + ' > .context-menu');
$('.context-menu-trigger' + randomId).contextmenu(function(e){
e.preventDefault();
contextMenu.css('display', 'block');
var menuWidth = contextMenu.outerWidth();
var menuXPosition = contextMenu.offset().left;
if(e.pageX + menuWidth < documentWidth){
contextMenu.css('left', e.pageX + 'px');
} else {
var newXPosition = documentWidth - menuWidth;
contextMenu.css('left', newXPosition + 'px');
}
var mouseYPosition = e.pageY;
var menuHeight = contextMenu.outerHeight();
if(mouseYPosition + menuHeight < documentHeight){
contextMenu.css('top', e.pageY + 10 + 'px');
} else {
var newYPosition = documentHeight - menuHeight;
contextMenu.css('top', newYPosition + 'px');
}
});
$(document).click(function(e){
if(!$(e.target).is('.disabled')){
direction = 0;
contextMenu.css('display', 'none');
}
});
$(window).resize(function(e){
documentWidth = $(document).width();
documentHeight = $(document).height();
contextMenu.css('display', 'none');
});
$('.context-menu-item.submenu').hover(function(e){
var currentVisibleSubmenu = $('.context-menu-item.submenu:hover > .context-menu').last();
var hoveredMenuItem = $('.context-menu-item.submenu:hover').last();
var hoveredMenuItemWidth = hoveredMenuItem.outerWidth();
var subMenuWidth = $(e.target).children().width();
var hoveredMenuItemXPosition = hoveredMenuItem.offset().left;
if ($(e.target).children().html() === currentVisibleSubmenu.html()) {
direction = 0;
if(subMenuWidth + hoveredMenuItemWidth + hoveredMenuItemXPosition > documentWidth){
direction = 1;
}
}
if(!direction){
currentVisibleSubmenu.css('left', hoveredMenuItemWidth + 'px');
} else {
currentVisibleSubmenu.css('left', "-" + subMenuWidth + 'px');
}
var hoveredMenuItemYPosition = hoveredMenuItem.position().top;
currentVisibleSubmenu.css('top', hoveredMenuItemYPosition + 'px');
}, function(e){
});
}
angular.module('ngContextMenu', [])
.directive('ngContextMenu', this.contextMenu);
})();
/* Example item array with submenu, disabled menu-item, separators
*
* [
* {
* name: 'item 1',
* submenu: [
* {
* name: 'item 1.1',
* icon: 'address-book',
* disabled: true,
* },
* {
* name: 'item 1.2',
* submenu: [
* {
* name: 'item 1.2.1',
* }
* ]
* }
* ]
* },
* ]
*
*
*/