aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js/features/repo-legacy.ts
diff options
context:
space:
mode:
Diffstat (limited to 'web_src/js/features/repo-legacy.ts')
-rw-r--r--web_src/js/features/repo-legacy.ts415
1 files changed, 415 insertions, 0 deletions
diff --git a/web_src/js/features/repo-legacy.ts b/web_src/js/features/repo-legacy.ts
new file mode 100644
index 0000000000..b26803c76d
--- /dev/null
+++ b/web_src/js/features/repo-legacy.ts
@@ -0,0 +1,415 @@
+import $ from 'jquery';
+import {
+ initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete,
+ initRepoIssueComments, initRepoIssueDependencyDelete, initRepoIssueReferenceIssue,
+ initRepoIssueTitleEdit, initRepoIssueWipToggle,
+ initRepoPullRequestUpdate, updateIssuesMeta, initIssueTemplateCommentEditors, initSingleCommentEditor,
+} from './repo-issue.ts';
+import {initUnicodeEscapeButton} from './repo-unicode-escape.ts';
+import {svg} from '../svg.ts';
+import {htmlEscape} from 'escape-goat';
+import {initRepoBranchTagSelector} from '../components/RepoBranchTagSelector.vue';
+import {
+ initRepoCloneLink, initRepoCommonBranchOrTagDropdown, initRepoCommonFilterSearchDropdown,
+} from './repo-common.ts';
+import {initCitationFileCopyContent} from './citation.ts';
+import {initCompLabelEdit} from './comp/LabelEdit.ts';
+import {initRepoDiffConversationNav} from './repo-diff.ts';
+import {initCompReactionSelector} from './comp/ReactionSelector.ts';
+import {initRepoSettingBranches} from './repo-settings.ts';
+import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.ts';
+import {initRepoPullRequestCommitStatus} from './repo-issue-pr-status.ts';
+import {hideElem, queryElemChildren, showElem} from '../utils/dom.ts';
+import {POST} from '../modules/fetch.ts';
+import {initRepoIssueCommentEdit} from './repo-issue-edit.ts';
+
+// if there are draft comments, confirm before reloading, to avoid losing comments
+function reloadConfirmDraftComment() {
+ const commentTextareas = [
+ document.querySelector('.edit-content-zone:not(.tw-hidden) textarea'),
+ document.querySelector('#comment-form textarea'),
+ ];
+ for (const textarea of commentTextareas) {
+ // Most users won't feel too sad if they lose a comment with 10 chars, they can re-type these in seconds.
+ // But if they have typed more (like 50) chars and the comment is lost, they will be very unhappy.
+ if (textarea && textarea.value.trim().length > 10) {
+ textarea.parentElement.scrollIntoView();
+ if (!window.confirm('Page will be reloaded, but there are draft comments. Continuing to reload will discard the comments. Continue?')) {
+ return;
+ }
+ break;
+ }
+ }
+ window.location.reload();
+}
+
+export function initRepoCommentForm() {
+ const $commentForm = $('.comment.form');
+ if (!$commentForm.length) return;
+
+ if ($commentForm.find('.field.combo-editor-dropzone').length) {
+ // at the moment, if a form has multiple combo-markdown-editors, it must be an issue template form
+ initIssueTemplateCommentEditors($commentForm);
+ } else if ($commentForm.find('.combo-markdown-editor').length) {
+ // it's quite unclear about the "comment form" elements, sometimes it's for issue comment, sometimes it's for file editor/uploader message
+ initSingleCommentEditor($commentForm);
+ }
+
+ function initBranchSelector() {
+ const elSelectBranch = document.querySelector('.ui.dropdown.select-branch');
+ if (!elSelectBranch) return;
+
+ const urlUpdateIssueRef = elSelectBranch.getAttribute('data-url-update-issueref');
+ const $selectBranch = $(elSelectBranch);
+ const $branchMenu = $selectBranch.find('.reference-list-menu');
+ $branchMenu.find('.item:not(.no-select)').on('click', async function (e) {
+ e.preventDefault();
+ const selectedValue = this.getAttribute('data-id'); // eg: "refs/heads/my-branch"
+ const selectedText = this.getAttribute('data-name'); // eg: "my-branch"
+ if (urlUpdateIssueRef) {
+ // for existing issue, send request to update issue ref, and reload page
+ try {
+ await POST(urlUpdateIssueRef, {data: new URLSearchParams({ref: selectedValue})});
+ window.location.reload();
+ } catch (error) {
+ console.error(error);
+ }
+ } else {
+ // for new issue, only update UI&form, do not send request/reload
+ const selectedHiddenSelector = this.getAttribute('data-id-selector');
+ document.querySelector(selectedHiddenSelector).value = selectedValue;
+ elSelectBranch.querySelector('.text-branch-name').textContent = selectedText;
+ }
+ });
+ $selectBranch.find('.reference.column').on('click', function () {
+ hideElem($selectBranch.find('.scrolling.reference-list-menu'));
+ showElem(this.getAttribute('data-target'));
+ queryElemChildren(this.parentNode, '.branch-tag-item', (el) => el.classList.remove('active'));
+ this.classList.add('active');
+ return false;
+ });
+ }
+
+ initBranchSelector();
+
+ // List submits
+ function initListSubmits(selector, outerSelector) {
+ const $list = $(`.ui.${outerSelector}.list`);
+ const $noSelect = $list.find('.no-select');
+ const $listMenu = $(`.${selector} .menu`);
+ let hasUpdateAction = $listMenu.data('action') === 'update';
+ const items = {};
+
+ $(`.${selector}`).dropdown({
+ 'action': 'nothing', // do not hide the menu if user presses Enter
+ fullTextSearch: 'exact',
+ async onHide() {
+ hasUpdateAction = $listMenu.data('action') === 'update'; // Update the var
+ if (hasUpdateAction) {
+ // TODO: Add batch functionality and make this 1 network request.
+ const itemEntries = Object.entries(items);
+ for (const [elementId, item] of itemEntries) {
+ await updateIssuesMeta(
+ item['update-url'],
+ item.action,
+ item['issue-id'],
+ elementId,
+ );
+ }
+ if (itemEntries.length) {
+ reloadConfirmDraftComment();
+ }
+ }
+ },
+ });
+
+ $listMenu.find('.item:not(.no-select)').on('click', function (e) {
+ e.preventDefault();
+ if ($(this).hasClass('ban-change')) {
+ return false;
+ }
+
+ hasUpdateAction = $listMenu.data('action') === 'update'; // Update the var
+
+ const clickedItem = this; // eslint-disable-line unicorn/no-this-assignment
+ const scope = this.getAttribute('data-scope');
+
+ $(this).parent().find('.item').each(function () {
+ if (scope) {
+ // Enable only clicked item for scoped labels
+ if (this.getAttribute('data-scope') !== scope) {
+ return true;
+ }
+ if (this !== clickedItem && !$(this).hasClass('checked')) {
+ return true;
+ }
+ } else if (this !== clickedItem) {
+ // Toggle for other labels
+ return true;
+ }
+
+ if ($(this).hasClass('checked')) {
+ $(this).removeClass('checked');
+ $(this).find('.octicon-check').addClass('tw-invisible');
+ if (hasUpdateAction) {
+ if (!($(this).data('id') in items)) {
+ items[$(this).data('id')] = {
+ 'update-url': $listMenu.data('update-url'),
+ action: 'detach',
+ 'issue-id': $listMenu.data('issue-id'),
+ };
+ } else {
+ delete items[$(this).data('id')];
+ }
+ }
+ } else {
+ $(this).addClass('checked');
+ $(this).find('.octicon-check').removeClass('tw-invisible');
+ if (hasUpdateAction) {
+ if (!($(this).data('id') in items)) {
+ items[$(this).data('id')] = {
+ 'update-url': $listMenu.data('update-url'),
+ action: 'attach',
+ 'issue-id': $listMenu.data('issue-id'),
+ };
+ } else {
+ delete items[$(this).data('id')];
+ }
+ }
+ }
+ });
+
+ // TODO: Which thing should be done for choosing review requests
+ // to make chosen items be shown on time here?
+ if (selector === 'select-reviewers-modify' || selector === 'select-assignees-modify') {
+ return false;
+ }
+
+ const listIds = [];
+ $(this).parent().find('.item').each(function () {
+ if ($(this).hasClass('checked')) {
+ listIds.push($(this).data('id'));
+ $($(this).data('id-selector')).removeClass('tw-hidden');
+ } else {
+ $($(this).data('id-selector')).addClass('tw-hidden');
+ }
+ });
+ if (!listIds.length) {
+ $noSelect.removeClass('tw-hidden');
+ } else {
+ $noSelect.addClass('tw-hidden');
+ }
+ $($(this).parent().data('id')).val(listIds.join(','));
+ return false;
+ });
+ $listMenu.find('.no-select.item').on('click', function (e) {
+ e.preventDefault();
+ if (hasUpdateAction) {
+ (async () => {
+ await updateIssuesMeta(
+ $listMenu.data('update-url'),
+ 'clear',
+ $listMenu.data('issue-id'),
+ '',
+ );
+ reloadConfirmDraftComment();
+ })();
+ }
+
+ $(this).parent().find('.item').each(function () {
+ $(this).removeClass('checked');
+ $(this).find('.octicon-check').addClass('tw-invisible');
+ });
+
+ if (selector === 'select-reviewers-modify' || selector === 'select-assignees-modify') {
+ return false;
+ }
+
+ $list.find('.item').each(function () {
+ $(this).addClass('tw-hidden');
+ });
+ $noSelect.removeClass('tw-hidden');
+ $($(this).parent().data('id')).val('');
+ });
+ }
+
+ // Init labels and assignees
+ initListSubmits('select-label', 'labels');
+ initListSubmits('select-assignees', 'assignees');
+ initListSubmits('select-assignees-modify', 'assignees');
+ initListSubmits('select-reviewers-modify', 'assignees');
+
+ function selectItem(select_id, input_id) {
+ const $menu = $(`${select_id} .menu`);
+ const $list = $(`.ui${select_id}.list`);
+ const hasUpdateAction = $menu.data('action') === 'update';
+
+ $menu.find('.item:not(.no-select)').on('click', function () {
+ $(this).parent().find('.item').each(function () {
+ $(this).removeClass('selected active');
+ });
+
+ $(this).addClass('selected active');
+ if (hasUpdateAction) {
+ (async () => {
+ await updateIssuesMeta(
+ $menu.data('update-url'),
+ '',
+ $menu.data('issue-id'),
+ $(this).data('id'),
+ );
+ reloadConfirmDraftComment();
+ })();
+ }
+
+ let icon = '';
+ if (input_id === '#milestone_id') {
+ icon = svg('octicon-milestone', 18, 'tw-mr-2');
+ } else if (input_id === '#project_id') {
+ icon = svg('octicon-project', 18, 'tw-mr-2');
+ } else if (input_id === '#assignee_id') {
+ icon = `<img class="ui avatar image tw-mr-2" alt="avatar" src=${$(this).data('avatar')}>`;
+ }
+
+ $list.find('.selected').html(`
+ <a class="item muted sidebar-item-link" href="${htmlEscape(this.getAttribute('data-href'))}">
+ ${icon}
+ ${htmlEscape(this.textContent)}
+ </a>
+ `);
+
+ $(`.ui${select_id}.list .no-select`).addClass('tw-hidden');
+ $(input_id).val($(this).data('id'));
+ });
+ $menu.find('.no-select.item').on('click', function () {
+ $(this).parent().find('.item:not(.no-select)').each(function () {
+ $(this).removeClass('selected active');
+ });
+
+ if (hasUpdateAction) {
+ (async () => {
+ await updateIssuesMeta(
+ $menu.data('update-url'),
+ '',
+ $menu.data('issue-id'),
+ $(this).data('id'),
+ );
+ reloadConfirmDraftComment();
+ })();
+ }
+
+ $list.find('.selected').html('');
+ $list.find('.no-select').removeClass('tw-hidden');
+ $(input_id).val('');
+ });
+ }
+
+ // Milestone, Assignee, Project
+ selectItem('.select-project', '#project_id');
+ selectItem('.select-milestone', '#milestone_id');
+ selectItem('.select-assignee', '#assignee_id');
+}
+
+export function initRepository() {
+ if (!$('.page-content.repository').length) return;
+
+ initRepoBranchTagSelector('.js-branch-tag-selector');
+
+ // Options
+ if ($('.repository.settings.options').length > 0) {
+ // Enable or select internal/external wiki system and issue tracker.
+ $('.enable-system').on('change', function () {
+ if (this.checked) {
+ $($(this).data('target')).removeClass('disabled');
+ if (!$(this).data('context')) $($(this).data('context')).addClass('disabled');
+ } else {
+ $($(this).data('target')).addClass('disabled');
+ if (!$(this).data('context')) $($(this).data('context')).removeClass('disabled');
+ }
+ });
+ $('.enable-system-radio').on('change', function () {
+ if (this.value === 'false') {
+ $($(this).data('target')).addClass('disabled');
+ if ($(this).data('context') !== undefined) $($(this).data('context')).removeClass('disabled');
+ } else if (this.value === 'true') {
+ $($(this).data('target')).removeClass('disabled');
+ if ($(this).data('context') !== undefined) $($(this).data('context')).addClass('disabled');
+ }
+ });
+ const $trackerIssueStyleRadios = $('.js-tracker-issue-style');
+ $trackerIssueStyleRadios.on('change input', () => {
+ const checkedVal = $trackerIssueStyleRadios.filter(':checked').val();
+ $('#tracker-issue-style-regex-box').toggleClass('disabled', checkedVal !== 'regexp');
+ });
+ }
+
+ // Labels
+ initCompLabelEdit('.repository.labels');
+
+ // Milestones
+ if ($('.repository.new.milestone').length > 0) {
+ $('#clear-date').on('click', () => {
+ $('#deadline').val('');
+ return false;
+ });
+ }
+
+ // Repo Creation
+ if ($('.repository.new.repo').length > 0) {
+ $('input[name="gitignores"], input[name="license"]').on('change', () => {
+ const gitignores = $('input[name="gitignores"]').val();
+ const license = $('input[name="license"]').val();
+ if (gitignores || license) {
+ document.querySelector('input[name="auto_init"]').checked = true;
+ }
+ });
+ }
+
+ // Compare or pull request
+ const $repoDiff = $('.repository.diff');
+ if ($repoDiff.length) {
+ initRepoCommonBranchOrTagDropdown('.choose.branch .dropdown');
+ initRepoCommonFilterSearchDropdown('.choose.branch .dropdown');
+ }
+
+ initRepoCloneLink();
+ initCitationFileCopyContent();
+ initRepoSettingBranches();
+
+ // Issues
+ if ($('.repository.view.issue').length > 0) {
+ initRepoIssueCommentEdit();
+
+ initRepoIssueBranchSelect();
+ initRepoIssueTitleEdit();
+ initRepoIssueWipToggle();
+ initRepoIssueComments();
+
+ initRepoDiffConversationNav();
+ initRepoIssueReferenceIssue();
+
+ initRepoIssueCommentDelete();
+ initRepoIssueDependencyDelete();
+ initRepoIssueCodeCommentCancel();
+ initRepoPullRequestUpdate();
+ initCompReactionSelector();
+
+ initRepoPullRequestMergeForm();
+ initRepoPullRequestCommitStatus();
+ }
+
+ // Pull request
+ const $repoComparePull = $('.repository.compare.pull');
+ if ($repoComparePull.length > 0) {
+ // show pull request form
+ $repoComparePull.find('button.show-form').on('click', function (e) {
+ e.preventDefault();
+ hideElem($(this).parent());
+
+ const $form = $repoComparePull.find('.pullrequest-form');
+ showElem($form);
+ });
+ }
+
+ initUnicodeEscapeButton();
+}