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.0KB

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