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.

repo-diff.js 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import $ from 'jquery';
  2. import {initCompReactionSelector} from './comp/ReactionSelector.js';
  3. import {initRepoIssueContentHistory} from './repo-issue-content.js';
  4. import {validateTextareaNonEmpty} from './comp/EasyMDE.js';
  5. import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles} from './pull-view-file.js';
  6. import {initTooltip} from '../modules/tippy.js';
  7. const {csrfToken} = window.config;
  8. export function initRepoDiffReviewButton() {
  9. const $reviewBox = $('#review-box');
  10. const $counter = $reviewBox.find('.review-comments-counter');
  11. $(document).on('click', 'button[name="is_review"]', (e) => {
  12. const $form = $(e.target).closest('form');
  13. $form.append('<input type="hidden" name="is_review" value="true">');
  14. // Watch for the form's submit event.
  15. $form.on('submit', () => {
  16. const num = parseInt($counter.attr('data-pending-comment-number')) + 1 || 1;
  17. $counter.attr('data-pending-comment-number', num);
  18. $counter.text(num);
  19. // Force the browser to reflow the DOM. This is to ensure that the browser replay the animation
  20. $reviewBox.removeClass('pulse');
  21. $reviewBox.width();
  22. $reviewBox.addClass('pulse');
  23. });
  24. });
  25. }
  26. export function initRepoDiffFileViewToggle() {
  27. $('.file-view-toggle').on('click', function () {
  28. const $this = $(this);
  29. $this.parent().children().removeClass('active');
  30. $this.addClass('active');
  31. const $target = $($this.data('toggle-selector'));
  32. $target.parent().children().addClass('hide');
  33. $target.removeClass('hide');
  34. });
  35. }
  36. export function initRepoDiffConversationForm() {
  37. $(document).on('submit', '.conversation-holder form', async (e) => {
  38. e.preventDefault();
  39. const $form = $(e.target);
  40. const $textArea = $form.find('textarea');
  41. if (!validateTextareaNonEmpty($textArea)) {
  42. return;
  43. }
  44. const formDataString = String(new URLSearchParams(new FormData($form[0])));
  45. const $newConversationHolder = $(await $.post($form.attr('action'), formDataString));
  46. const {path, side, idx} = $newConversationHolder.data();
  47. $newConversationHolder.find('.tooltip').each(function () {
  48. initTooltip(this);
  49. });
  50. $form.closest('.conversation-holder').replaceWith($newConversationHolder);
  51. if ($form.closest('tr').data('line-type') === 'same') {
  52. $(`[data-path="${path}"] a.add-code-comment[data-idx="${idx}"]`).addClass('invisible');
  53. } else {
  54. $(`[data-path="${path}"] a.add-code-comment[data-side="${side}"][data-idx="${idx}"]`).addClass('invisible');
  55. }
  56. $newConversationHolder.find('.dropdown').dropdown();
  57. initCompReactionSelector($newConversationHolder);
  58. });
  59. $(document).on('click', '.resolve-conversation', async function (e) {
  60. e.preventDefault();
  61. const comment_id = $(this).data('comment-id');
  62. const origin = $(this).data('origin');
  63. const action = $(this).data('action');
  64. const url = $(this).data('update-url');
  65. const data = await $.post(url, {_csrf: csrfToken, origin, action, comment_id});
  66. if ($(this).closest('.conversation-holder').length) {
  67. const conversation = $(data);
  68. $(this).closest('.conversation-holder').replaceWith(conversation);
  69. conversation.find('.dropdown').dropdown();
  70. initCompReactionSelector(conversation);
  71. } else {
  72. window.location.reload();
  73. }
  74. });
  75. }
  76. export function initRepoDiffConversationNav() {
  77. // Previous/Next code review conversation
  78. $(document).on('click', '.previous-conversation', (e) => {
  79. const $conversation = $(e.currentTarget).closest('.comment-code-cloud');
  80. const $conversations = $('.comment-code-cloud:not(.hide)');
  81. const index = $conversations.index($conversation);
  82. const previousIndex = index > 0 ? index - 1 : $conversations.length - 1;
  83. const $previousConversation = $conversations.eq(previousIndex);
  84. const anchor = $previousConversation.find('.comment').first().attr('id');
  85. window.location.href = `#${anchor}`;
  86. });
  87. $(document).on('click', '.next-conversation', (e) => {
  88. const $conversation = $(e.currentTarget).closest('.comment-code-cloud');
  89. const $conversations = $('.comment-code-cloud:not(.hide)');
  90. const index = $conversations.index($conversation);
  91. const nextIndex = index < $conversations.length - 1 ? index + 1 : 0;
  92. const $nextConversation = $conversations.eq(nextIndex);
  93. const anchor = $nextConversation.find('.comment').first().attr('id');
  94. window.location.href = `#${anchor}`;
  95. });
  96. }
  97. // Will be called when the show more (files) button has been pressed
  98. function onShowMoreFiles() {
  99. initRepoIssueContentHistory();
  100. initViewedCheckboxListenerFor();
  101. countAndUpdateViewedFiles();
  102. }
  103. export function doLoadMoreFiles(link, diffEnd, callback) {
  104. const url = `${link}?skip-to=${diffEnd}&file-only=true`;
  105. loadMoreFiles(url, callback);
  106. }
  107. function loadMoreFiles(url, callback) {
  108. const $target = $('a#diff-show-more-files');
  109. if ($target.hasClass('disabled')) {
  110. callback();
  111. return;
  112. }
  113. $target.addClass('disabled');
  114. $.ajax({
  115. type: 'GET',
  116. url,
  117. }).done((resp) => {
  118. if (!resp) {
  119. $target.removeClass('disabled');
  120. callback(resp);
  121. return;
  122. }
  123. $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children());
  124. // By simply rerunning the script we add the new data to our existing
  125. // pagedata object. this triggers vue and the filetree and filelist will
  126. // render the new elements.
  127. $('body').append($(resp).find('script#diff-data-script'));
  128. onShowMoreFiles();
  129. callback(resp);
  130. }).fail(() => {
  131. $target.removeClass('disabled');
  132. callback();
  133. });
  134. }
  135. export function initRepoDiffShowMore() {
  136. $(document).on('click', 'a#diff-show-more-files', (e) => {
  137. e.preventDefault();
  138. const $target = $(e.target);
  139. loadMoreFiles($target.data('href'), () => {});
  140. });
  141. $(document).on('click', 'a.diff-load-button', (e) => {
  142. e.preventDefault();
  143. const $target = $(e.target);
  144. if ($target.hasClass('disabled')) {
  145. return;
  146. }
  147. $target.addClass('disabled');
  148. const url = $target.data('href');
  149. $.ajax({
  150. type: 'GET',
  151. url,
  152. }).done((resp) => {
  153. if (!resp) {
  154. $target.removeClass('disabled');
  155. return;
  156. }
  157. $target.parent().replaceWith($(resp).find('#diff-file-boxes .diff-file-body .file-body').children());
  158. onShowMoreFiles();
  159. }).fail(() => {
  160. $target.removeClass('disabled');
  161. });
  162. });
  163. }