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 6.5KB

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