Adding new components with portal-FE-common
[portal.git] / portal-FE-common / src / app / pages / functional-menu / jqTreeContextMenu.js
1 (function ($) {
2         if (!$.fn.tree) {
3                 throw "Error jqTree is not loaded.";
4         }
5
6         $.fn.jqTreeContextMenu = function (menuElement, callbacks) {
7                 //
8                 // TODO:
9                 // * Make sure the useContextMenu option is set in jqTree, either complain or set it automatically
10                 // * Make menu fade in/out
11                 //
12                 var self = this;
13                 var $el = this;
14
15                 // The jQuery object of the menu div.
16                 var $menuEl = menuElement;
17                 
18                 // This hash holds all menu items that should be disabled for a specific node.
19                 var nodeToDisabledMenuItems = {};
20                 
21                 // Hide the menu div.
22                 $menuEl.hide();
23
24                 // Disable system context menu from beeing displayed.
25                 $el.bind("contextmenu", function (e) { 
26                         e.preventDefault();
27                         return false; 
28                 });
29
30                 // Handle the contextmenu event sent from jqTree when user clicks right mouse button.
31                 $el.bind('tree.contextmenu', function (event) {
32                         var x = event.click_event.pageX;
33                         var y = event.click_event.pageY;
34                         var yPadding = 5;
35                         var xPadding = 5;
36                         var menuHeight = $menuEl.height();
37                         var menuWidth = $menuEl.width();
38                         var windowHeight = $(window).height();
39                         var windowWidth = $(window).width();
40                         
41                         if (menuHeight + y + yPadding > windowHeight) {
42                                 // Make sure the whole menu is rendered within the viewport. 
43                                 y = y - menuHeight;
44                         }
45                         if (menuWidth + x + xPadding > windowWidth) {
46                                 // Make sure the whole menu is rendered within the viewport. 
47                                 x = x - menuWidth;
48                         }
49
50                         // Handle disabling and enabling of menu items on specific nodes.
51                         if (Object.keys(nodeToDisabledMenuItems).length > 0) {
52                                 if (event.node.name in nodeToDisabledMenuItems) {
53                                         var nodeName = event.node.name;
54                                         var items = nodeToDisabledMenuItems[nodeName];
55                                         if (items.length === 0) {
56                                                 $menuEl.find('li').addClass('disabled');
57                                                 $menuEl.find('li > a').unbind('click');
58                                         } else {
59                                                 $menuEl.find('li > a').each(function () {
60                                                         $(this).closest('li').removeClass('disabled');
61                                                         var hrefValue = $(this).attr('href');
62                                                         var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
63                                                         if ($.inArray(value, items) > -1) {
64                                                                 $(this).closest('li').addClass('disabled');
65                                                                 $(this).unbind('click');
66                                                         }
67                                                 });     
68                                         }
69                                 } else {
70                                         $menuEl.find('li.disabled').removeClass('disabled');
71                                 }
72                         }
73
74                         // Must call show before we set the offset (offset can not be set on display: none elements).
75                         $menuEl.show();
76
77                         $menuEl.offset({ left: x, top: y });
78
79                         var dismissContextMenu = function () {
80                                 $(document).unbind('click.jqtreecontextmenu');
81                                 $el.unbind('tree.click.jqtreecontextmenu');
82                                 $menuEl.hide();
83                         }
84                         // Make it possible to dismiss context menu by clicking somewhere in the document.
85                         $(document).bind('click.jqtreecontextmenu', function () {
86                                 dismissContextMenu();
87                         });
88
89                         // Dismiss context menu if another node in the tree is clicked.
90                         $el.bind('tree.click.jqtreecontextmenu', function (e) {
91                                 dismissContextMenu();
92                         });
93
94                         // Make selection follow the node that was right clicked on.
95                         var selectedNode = $el.tree('getSelectedNode');
96                         if (selectedNode !== event.node) {
97                                 $el.tree('selectNode', event.node);
98                         }
99
100                         // Handle click on menu items, if it's not disabled.
101                         var menuItems = $menuEl.find('li:not(.disabled) a');
102                         if (menuItems.length !== 0) {
103                                 menuItems.unbind('click');
104                                 menuItems.click(function (e) {
105                                         e.stopImmediatePropagation();
106                                         dismissContextMenu();
107                                         var hrefAnchor = e.currentTarget.attributes.href.nodeValue;
108                                         var funcKey = hrefAnchor.slice(hrefAnchor.indexOf("#") + 1, hrefAnchor.length)
109                                         var callbackFn = callbacks[funcKey];
110                                         if (callbackFn) {
111                                                 callbackFn(event.node);
112                                         }
113                                         return false;
114                                 });
115                         }
116                 });
117                 
118                 this.disable = function () {
119                         if (arguments.length === 0) {
120                                 // Called as: api.disable()
121                                 $menuEl.find('li:not(.disabled)').addClass('disabled');
122                                 $menuEl.find('li a').unbind('click');
123                                 nodeToDisabledMenuItems = {};
124                         } else if (arguments.length === 1) {
125                                 // Called as: api.disable(['edit','remove'])
126                                 var items = arguments[0];
127                                 if (typeof items !== 'object') {
128                                         return;
129                                 }
130                                 $menuEl.find('li > a').each(function () {
131                                         var hrefValue = $(this).attr('href');
132                                         var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
133                                         if ($.inArray(value, items) > -1) {
134                                                 $(this).closest('li').addClass('disabled');
135                                                 $(this).unbind('click');
136                                         }
137                                 });
138                                 nodeToDisabledMenuItems = {};
139                         } else if (arguments.length === 2) {
140                                 // Called as: api.disable(nodeName, ['edit','remove'])
141                                 var nodeName = arguments[0];
142                                 var items = arguments[1];
143                                 nodeToDisabledMenuItems[nodeName] = items;
144                         }
145                 };
146
147                 this.enable = function () {
148                         if (arguments.length === 0) {
149                                 // Called as: api.enable()
150                                 $menuEl.find('li.disabled').removeClass('disabled');
151                                 nodeToDisabledMenuItems = {};
152                         } else if (arguments.length === 1) {
153                                 // Called as: api.enable(['edit','remove'])
154                                 var items = arguments[0];
155                                 if (typeof items !== 'object') {
156                                         return;
157                                 }
158                                 
159                                 $menuEl.find('li > a').each(function () {
160                                         var hrefValue = $(this).attr('href');
161                                         var value = hrefValue.slice(hrefValue.indexOf("#") + 1, hrefValue.length)
162                                         if ($.inArray(value, items) > -1) {
163                                                 $(this).closest('li').removeClass('disabled');
164                                         }
165                                 });
166
167                                 nodeToDisabledMenuItems = {};
168                         } else if (arguments.length === 2) {
169                                 // Called as: api.enable(nodeName, ['edit','remove'])
170                                 var nodeName = arguments[0];
171                                 var items = arguments[1];
172                                 if (items.length === 0) {
173                                         delete nodeToDisabledMenuItems[nodeName];
174                                 } else {
175                                         var disabledItems = nodeToDisabledMenuItems[nodeName];
176                                         for (var i = 0; i < items.length; i++) {
177                                                 var idx = disabledItems.indexOf(items[i]);
178                                                 if (idx > -1) {
179                                                         disabledItems.splice(idx, 1);
180                                                 }
181                                         }
182                                         if (disabledItems.length === 0) {
183                                                 delete nodeToDisabledMenuItems[nodeName];
184                                         } else {
185                                                 nodeToDisabledMenuItems[nodeName] = disabledItems;      
186                                         }
187                                 }
188                                 if (Object.keys(nodeToDisabledMenuItems).length === 0) {
189                                         $menuEl.find('li.disabled').removeClass('disabled');
190                                 }
191                         }
192                 };
193                 return this;
194         };
195 } (jQuery));