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

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