code.gitea.io/gitea@v1.21.7/web_src/js/features/repo-issue-content.js (about) 1 import $ from 'jquery'; 2 import {svg} from '../svg.js'; 3 import {showErrorToast} from '../modules/toast.js'; 4 5 const {appSubUrl, csrfToken} = window.config; 6 let i18nTextEdited; 7 let i18nTextOptions; 8 let i18nTextDeleteFromHistory; 9 let i18nTextDeleteFromHistoryConfirm; 10 11 function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleHtml) { 12 let $dialog = $('.content-history-detail-dialog'); 13 if ($dialog.length) return; 14 15 $dialog = $(` 16 <div class="ui modal content-history-detail-dialog"> 17 ${svg('octicon-x', 16, 'close icon inside')} 18 <div class="header gt-df gt-ac gt-sb"> 19 <div>${itemTitleHtml}</div> 20 <div class="ui dropdown dialog-header-options gt-mr-5 gt-hidden"> 21 ${i18nTextOptions} 22 ${svg('octicon-triangle-down', 14, 'dropdown icon')} 23 <div class="menu"> 24 <div class="item red text" data-option-item="delete">${i18nTextDeleteFromHistory}</div> 25 </div> 26 </div> 27 </div> 28 <div class="comment-diff-data is-loading"></div> 29 </div>`); 30 $dialog.appendTo($('body')); 31 $dialog.find('.dialog-header-options').dropdown({ 32 showOnFocus: false, 33 allowReselection: true, 34 onChange(_value, _text, $item) { 35 const optionItem = $item.data('option-item'); 36 if (optionItem === 'delete') { 37 if (window.confirm(i18nTextDeleteFromHistoryConfirm)) { 38 $.post(`${issueBaseUrl}/content-history/soft-delete?comment_id=${commentId}&history_id=${historyId}`, { 39 _csrf: csrfToken, 40 }).done((resp) => { 41 if (resp.ok) { 42 $dialog.modal('hide'); 43 } else { 44 showErrorToast(resp.message); 45 } 46 }); 47 } 48 } else { // required by eslint 49 showErrorToast(`unknown option item: ${optionItem}`); 50 } 51 }, 52 onHide() { 53 $(this).dropdown('clear', true); 54 } 55 }); 56 $dialog.modal({ 57 onShow() { 58 $.ajax({ 59 url: `${issueBaseUrl}/content-history/detail?comment_id=${commentId}&history_id=${historyId}`, 60 data: { 61 _csrf: csrfToken, 62 }, 63 }).done((resp) => { 64 $dialog.find('.comment-diff-data').removeClass('is-loading').html(resp.diffHtml); 65 // there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden. 66 if (resp.canSoftDelete) { 67 $dialog.find('.dialog-header-options').removeClass('gt-hidden'); 68 } 69 }); 70 }, 71 onHidden() { 72 $dialog.remove(); 73 }, 74 }).modal('show'); 75 } 76 77 function showContentHistoryMenu(issueBaseUrl, $item, commentId) { 78 const $headerLeft = $item.find('.comment-header-left'); 79 const menuHtml = ` 80 <div class="ui dropdown interact-fg content-history-menu" data-comment-id="${commentId}"> 81 • ${i18nTextEdited}${svg('octicon-triangle-down', 14, 'dropdown icon')} 82 <div class="menu"> 83 </div> 84 </div>`; 85 86 $headerLeft.find(`.content-history-menu`).remove(); 87 $headerLeft.append($(menuHtml)); 88 $headerLeft.find('.dropdown').dropdown({ 89 action: 'hide', 90 apiSettings: { 91 cache: false, 92 url: `${issueBaseUrl}/content-history/list?comment_id=${commentId}`, 93 }, 94 saveRemoteData: false, 95 onHide() { 96 $(this).dropdown('change values', null); 97 }, 98 onChange(value, itemHtml, $item) { 99 if (value && !$item.find('[data-history-is-deleted=1]').length) { 100 showContentHistoryDetail(issueBaseUrl, commentId, value, itemHtml); 101 } 102 }, 103 }); 104 } 105 106 export function initRepoIssueContentHistory() { 107 const issueIndex = $('#issueIndex').val(); 108 if (!issueIndex) return; 109 110 const $itemIssue = $('.repository.issue .timeline-item.comment.first'); // issue(PR) main content 111 const $comments = $('.repository.issue .comment-list .comment'); // includes: issue(PR) comments, review comments, code comments 112 if (!$itemIssue.length && !$comments.length) return; 113 114 const repoLink = $('#repolink').val(); 115 const issueBaseUrl = `${appSubUrl}/${repoLink}/issues/${issueIndex}`; 116 117 $.ajax({ 118 url: `${issueBaseUrl}/content-history/overview`, 119 data: { 120 _csrf: csrfToken, 121 }, 122 }).done((resp) => { 123 i18nTextEdited = resp.i18n.textEdited; 124 i18nTextDeleteFromHistory = resp.i18n.textDeleteFromHistory; 125 i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm; 126 i18nTextOptions = resp.i18n.textOptions; 127 128 if (resp.editedHistoryCountMap[0] && $itemIssue.length) { 129 showContentHistoryMenu(issueBaseUrl, $itemIssue, '0'); 130 } 131 for (const [commentId, _editedCount] of Object.entries(resp.editedHistoryCountMap)) { 132 if (commentId === '0') continue; 133 const $itemComment = $(`#issuecomment-${commentId}`); 134 showContentHistoryMenu(issueBaseUrl, $itemComment, commentId); 135 } 136 }); 137 }