You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

context_menu.js 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /* Redmine - project management software
  2. Copyright (C) 2006-2020 Jean-Philippe Lang */
  3. var contextMenuObserving;
  4. function contextMenuRightClick(event) {
  5. var target = $(event.target);
  6. if (target.is('a:not(.js-contextmenu)')) {return;}
  7. var tr = target.closest('.hascontextmenu').first();
  8. if (tr.length < 1) {return;}
  9. event.preventDefault();
  10. if (!contextMenuIsSelected(tr)) {
  11. contextMenuUnselectAll();
  12. contextMenuAddSelection(tr);
  13. contextMenuSetLastSelected(tr);
  14. }
  15. contextMenuShow(event);
  16. }
  17. function contextMenuClick(event) {
  18. var target = $(event.target);
  19. var lastSelected;
  20. if (target.is('a') && target.hasClass('submenu')) {
  21. event.preventDefault();
  22. return;
  23. }
  24. contextMenuHide();
  25. if (target.is('a') || target.is('img')) { return; }
  26. if (event.which == 1 || (navigator.appVersion.match(/\bMSIE\b/))) {
  27. var tr = target.closest('.hascontextmenu').first();
  28. if (tr.length > 0) {
  29. // a row was clicked
  30. if (target.is('td.checkbox')) {
  31. // the td containing the checkbox was clicked, toggle the checkbox
  32. target = target.find('input').first();
  33. target.prop("checked", !target.prop("checked"));
  34. }
  35. if (target.is('input')) {
  36. // a checkbox may be clicked
  37. if (target.prop('checked')) {
  38. tr.addClass('context-menu-selection');
  39. } else {
  40. tr.removeClass('context-menu-selection');
  41. }
  42. } else {
  43. if (event.ctrlKey || event.metaKey) {
  44. contextMenuToggleSelection(tr);
  45. } else if (event.shiftKey) {
  46. lastSelected = contextMenuLastSelected();
  47. if (lastSelected.length) {
  48. var toggling = false;
  49. $('.hascontextmenu').each(function(){
  50. if (toggling || $(this).is(tr)) {
  51. contextMenuAddSelection($(this));
  52. }
  53. if ($(this).is(tr) || $(this).is(lastSelected)) {
  54. toggling = !toggling;
  55. }
  56. });
  57. } else {
  58. contextMenuAddSelection(tr);
  59. }
  60. } else {
  61. contextMenuUnselectAll();
  62. contextMenuAddSelection(tr);
  63. }
  64. contextMenuSetLastSelected(tr);
  65. }
  66. } else {
  67. // click is outside the rows
  68. if (target.is('a') && (target.hasClass('disabled') || target.hasClass('submenu'))) {
  69. event.preventDefault();
  70. } else if (target.is('.toggle-selection') || target.is('.ui-dialog *') || $('#ajax-modal').is(':visible')) {
  71. // nop
  72. } else {
  73. contextMenuUnselectAll();
  74. }
  75. }
  76. }
  77. }
  78. function contextMenuCreate() {
  79. if ($('#context-menu').length < 1) {
  80. var menu = document.createElement("div");
  81. menu.setAttribute("id", "context-menu");
  82. menu.setAttribute("style", "display:none;");
  83. document.getElementById("content").appendChild(menu);
  84. }
  85. }
  86. function contextMenuShow(event) {
  87. var mouse_x = event.pageX;
  88. var mouse_y = event.pageY;
  89. var mouse_y_c = event.clientY;
  90. var render_x = mouse_x;
  91. var render_y = mouse_y;
  92. var dims;
  93. var menu_width;
  94. var menu_height;
  95. var window_width;
  96. var window_height;
  97. var max_width;
  98. var max_height;
  99. var url;
  100. $('#context-menu').css('left', (render_x + 'px'));
  101. $('#context-menu').css('top', (render_y + 'px'));
  102. $('#context-menu').html('');
  103. url = $(event.target).parents('form').first().data('cm-url');
  104. if (url == null) {alert('no url'); return;}
  105. $.ajax({
  106. url: url,
  107. data: $(event.target).parents('form').first().serialize(),
  108. success: function(data, textStatus, jqXHR) {
  109. $('#context-menu').html(data);
  110. menu_width = $('#context-menu').width();
  111. menu_height = $('#context-menu').height();
  112. max_width = mouse_x + 2*menu_width;
  113. max_height = mouse_y_c + menu_height;
  114. var ws = window_size();
  115. window_width = ws.width;
  116. window_height = ws.height;
  117. /* display the menu above and/or to the left of the click if needed */
  118. if (max_width > window_width) {
  119. render_x -= menu_width;
  120. $('#context-menu').addClass('reverse-x');
  121. } else {
  122. $('#context-menu').removeClass('reverse-x');
  123. }
  124. if (max_height > window_height) {
  125. render_y -= menu_height;
  126. $('#context-menu').addClass('reverse-y');
  127. // adding class for submenu
  128. if (mouse_y_c < 325) {
  129. $('#context-menu .folder').addClass('down');
  130. }
  131. } else {
  132. // adding class for submenu
  133. if (window_height - mouse_y_c < 345) {
  134. $('#context-menu .folder').addClass('up');
  135. }
  136. $('#context-menu').removeClass('reverse-y');
  137. }
  138. if (render_x <= 0) render_x = 1;
  139. if (render_y <= 0) render_y = 1;
  140. $('#context-menu').css('left', (render_x + 'px'));
  141. $('#context-menu').css('top', (render_y + 'px'));
  142. $('#context-menu').show();
  143. //if (window.parseStylesheets) { window.parseStylesheets(); } // IE
  144. }
  145. });
  146. }
  147. function contextMenuSetLastSelected(tr) {
  148. $('.cm-last').removeClass('cm-last');
  149. tr.addClass('cm-last');
  150. }
  151. function contextMenuLastSelected() {
  152. return $('.cm-last').first();
  153. }
  154. function contextMenuUnselectAll() {
  155. $('input[type=checkbox].toggle-selection').prop('checked', false);
  156. $('.hascontextmenu').each(function(){
  157. contextMenuRemoveSelection($(this));
  158. });
  159. $('.cm-last').removeClass('cm-last');
  160. }
  161. function contextMenuHide() {
  162. $('#context-menu').hide();
  163. }
  164. function contextMenuToggleSelection(tr) {
  165. if (contextMenuIsSelected(tr)) {
  166. contextMenuRemoveSelection(tr);
  167. } else {
  168. contextMenuAddSelection(tr);
  169. }
  170. }
  171. function contextMenuAddSelection(tr) {
  172. tr.addClass('context-menu-selection');
  173. contextMenuCheckSelectionBox(tr, true);
  174. contextMenuClearDocumentSelection();
  175. }
  176. function contextMenuRemoveSelection(tr) {
  177. tr.removeClass('context-menu-selection');
  178. contextMenuCheckSelectionBox(tr, false);
  179. }
  180. function contextMenuIsSelected(tr) {
  181. return tr.hasClass('context-menu-selection');
  182. }
  183. function contextMenuCheckSelectionBox(tr, checked) {
  184. tr.find('input[type=checkbox]').prop('checked', checked);
  185. }
  186. function contextMenuClearDocumentSelection() {
  187. // TODO
  188. if (document.selection) {
  189. document.selection.empty(); // IE
  190. } else {
  191. window.getSelection().removeAllRanges();
  192. }
  193. }
  194. function contextMenuInit() {
  195. contextMenuCreate();
  196. contextMenuUnselectAll();
  197. if (!contextMenuObserving) {
  198. $(document).click(contextMenuClick);
  199. $(document).contextmenu(contextMenuRightClick);
  200. $(document).on('click', '.js-contextmenu', contextMenuRightClick);
  201. contextMenuObserving = true;
  202. }
  203. }
  204. function toggleIssuesSelection(el) {
  205. var checked = $(this).prop('checked');
  206. var boxes = $(this).parents('table').find('input[name=ids\\[\\]]');
  207. boxes.prop('checked', checked).parents('.hascontextmenu').toggleClass('context-menu-selection', checked);
  208. }
  209. function window_size() {
  210. var w;
  211. var h;
  212. if (window.innerWidth) {
  213. w = window.innerWidth;
  214. h = window.innerHeight;
  215. } else if (document.documentElement) {
  216. w = document.documentElement.clientWidth;
  217. h = document.documentElement.clientHeight;
  218. } else {
  219. w = document.body.clientWidth;
  220. h = document.body.clientHeight;
  221. }
  222. return {width: w, height: h};
  223. }
  224. $(document).ready(function(){
  225. contextMenuInit();
  226. $('input[type=checkbox].toggle-selection').on('change', toggleIssuesSelection);
  227. });