angular.module('ui.bootstrap.contextMenu', [])
-.service('CustomService', function () {
- "use strict";
-
- return {
- initialize: function (item) {
- console.log("got here", item);
- }
- }
-
-})
-.directive('contextMenu', ["$parse", "$q", "CustomService", "$sce", function ($parse, $q, custom, $sce) {
-
- var contextMenus = [];
- var $currentContextMenu = null;
- var defaultItemText = "New Item";
-
- var removeContextMenus = function (level) {
- /// <summary>Remove context menu.</summary>
- while (contextMenus.length && (!level || contextMenus.length > level)) {
- contextMenus.pop().remove();
- }
- if (contextMenus.length == 0 && $currentContextMenu) {
- $currentContextMenu.remove();
- }
- };
-
-
- var processTextItem = function ($scope, item, text, event, model, $promises, nestedMenu, $) {
- "use strict";
-
- var $a = $('<a>');
- $a.css("padding-right", "8px");
- $a.attr({ tabindex: '-1', href: '#' });
-
- if (typeof item[0] === 'string') {
- text = item[0];
- }
- else if (typeof item[0] === "function") {
- item[0].call($scope, $scope, event, model);
- } else if (typeof item.text !== "undefined") {
- text = item.text;
- }
-
- var $promise = $q.when(text);
- $promises.push($promise);
- $promise.then(function (text) {
- $a.text(text);
- if (nestedMenu) {
- $a.css("cursor", "default");
- $a.append($('<strong style="font-family:monospace;font-weight:bold;float:right;">></strong>'));
- }
- });
-
- return $a;
-
- };
-
- var processItem = function ($scope, event, model, item, $ul, $li, $promises, $q, $, level) {
- /// <summary>Process individual item</summary>
- "use strict";
- var nestedMenu = angular.isArray(item[1])
- ? item[1] : angular.isArray(item[2])
- ? item[2] : angular.isArray(item[3])
- ? item[3] : null;
-
- // if html property is not defined, fallback to text, otherwise use default text
- // if first item in the item array is a function then invoke .call()
- // if first item is a string, then text should be the string.
-
- var text = defaultItemText;
- if (typeof item[0] === 'string' || typeof item.text !== "undefined") {
- text = processTextItem($scope, item, text, event, model, $promises, nestedMenu, $);
- }
- else if (typeof item.html !== "undefined") {
- // leave styling open to dev
- text = item.html
- }
-
- $li.append(text);
-
-
-
-
- // if item is object, and has enabled prop invoke the prop
- // els if fallback to item[2]
-
- var isEnabled = function () {
- if (typeof item.enabled !== "undefined") {
- return item.enabled.call($scope, $scope, event, model, text);
- } else if (typeof item[2] === "function") {
- return item[2].call($scope, $scope, event, model, text);
- } else {
- return true;
- }
- };
-
- registerEnabledEvents($scope, isEnabled(), item, $ul, $li, nestedMenu, model, text, event, $, level);
- };
-
- var handlePromises = function ($ul, level, event, $promises) {
- /// <summary>
- /// calculate if drop down menu would go out of screen at left or bottom
- /// calculation need to be done after element has been added (and all texts are set; thus thepromises)
- /// to the DOM the get the actual height
- /// </summary>
- "use strict";
- $q.all($promises).then(function () {
- if (level === 0) {
- var topCoordinate = event.pageY;
- var menuHeight = angular.element($ul[0]).prop('offsetHeight');
- var winHeight = event.view.innerHeight;
- if (topCoordinate > menuHeight && winHeight - topCoordinate < menuHeight) {
- topCoordinate = event.pageY - menuHeight;
- }
-
- var leftCoordinate = event.pageX;
- var menuWidth = angular.element($ul[0]).prop('offsetWidth');
- var winWidth = event.view.innerWidth;
- if (leftCoordinate > menuWidth && winWidth - leftCoordinate < menuWidth) {
- leftCoordinate = event.pageX - menuWidth;
- }
-
- $ul.css({
- display: 'block',
- position: 'absolute',
- left: leftCoordinate + 'px',
- top: topCoordinate + 'px'
- });
- }
- });
-
- };
-
- var registerEnabledEvents = function ($scope, enabled, item, $ul, $li, nestedMenu, model, text, event, $, level) {
- /// <summary>If item is enabled, register various mouse events.</summary>
- if (enabled) {
- var openNestedMenu = function ($event) {
- removeContextMenus(level + 1);
- var ev = {
- pageX: event.pageX + $ul[0].offsetWidth - 1,
- pageY: $ul[0].offsetTop + $li[0].offsetTop - 3
- };
- renderContextMenu($scope, ev, nestedMenu, model, level + 1);
- };
-
- $li.on('click', function ($event) {
- $event.preventDefault();
- $scope.$apply(function () {
- if (nestedMenu) {
- openNestedMenu($event);
- } else {
- $(event.currentTarget).removeClass('context');
- removeContextMenus();
-
- if (angular.isFunction(item[1])) {
- item[1].call($scope, $scope, event, model, text)
- } else {
- item.click.call($scope, $scope, event, model, text);
- }
- }
- });
- });
-
- $li.on('mouseover', function ($event) {
- $scope.$apply(function () {
- if (nestedMenu) {
- openNestedMenu($event);
- }
- });
- });
- } else {
- $li.on('click', function ($event) {
- $event.preventDefault();
- });
- $li.addClass('disabled');
- }
-
- };
-
-
- var renderContextMenu = function ($scope, event, options, model, level) {
- /// <summary>Render context menu recursively.</summary>
- if (!level) { level = 0; }
+.directive('contextMenu', ["$parse", function ($parse) {
+ var renderContextMenu = function ($scope, event, options, model) {
if (!$) { var $ = angular.element; }
$(event.currentTarget).addClass('context');
var $contextMenu = $('<div>');
- if ($currentContextMenu) {
- $contextMenu = $currentContextMenu;
- } else {
- $currentContextMenu = $contextMenu;
- }
$contextMenu.addClass('dropdown clearfix');
var $ul = $('<ul>');
$ul.addClass('dropdown-menu');
display: 'block',
position: 'absolute',
left: event.pageX + 'px',
- top: event.pageY + 'px',
- "z-index": 10000
+ top: event.pageY + 'px'
});
-
- var $promises = [];
-
- angular.forEach(options, function (item) {
-
+ angular.forEach(options, function (item, i) {
var $li = $('<li>');
if (item === null) {
$li.addClass('divider');
- } else if (typeof item[0] === "object") {
- custom.initialize($li, item);
} else {
- processItem($scope, event, model, item, $ul, $li, $promises, $q, $, level);
+ var $a = $('<a>');
+ $a.attr({ tabindex: '-1', href: '#' });
+ var text = typeof item[0] == 'string' ? item[0] : item[0].call($scope, $scope, event, model);
+ $a.text(text);
+ $li.append($a);
+ var enabled = angular.isDefined(item[2]) ? item[2].call($scope, $scope, event, text, model) : true;
+ if (enabled) {
+ $li.on('click', function ($event) {
+ $event.preventDefault();
+ $scope.$apply(function () {
+ $(event.currentTarget).removeClass('context');
+ $contextMenu.remove();
+ item[1].call($scope, $scope, event, model);
+ });
+ });
+ } else {
+ $li.on('click', function ($event) {
+ $event.preventDefault();
+ });
+ $li.addClass('disabled');
+ }
}
$ul.append($li);
});
zIndex: 9999
});
$(document).find('body').append($contextMenu);
-
- handlePromises($ul, level, event, $promises);
-
$contextMenu.on("mousedown", function (e) {
if ($(e.target).hasClass('dropdown')) {
$(event.currentTarget).removeClass('context');
- removeContextMenus();
+ $contextMenu.remove();
}
}).on('contextmenu', function (event) {
$(event.currentTarget).removeClass('context');
event.preventDefault();
- removeContextMenus(level);
+ $contextMenu.remove();
});
-
- $scope.$on("$destroy", function () {
- removeContextMenus();
- });
-
- contextMenus.push($ul);
};
return function ($scope, element, attrs) {
element.on('contextmenu', function (event) {