mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-03 08:55:10 +02:00
Merge branch 'main' into add-file-tree-to-file-view-page
This commit is contained in:
@@ -147,7 +147,7 @@ function clearMergeMessage() {
|
||||
</template>
|
||||
</span>
|
||||
</button>
|
||||
<div class="ui dropdown icon button" @click.stop="showMergeStyleMenu = !showMergeStyleMenu" v-if="mergeStyleAllowedCount>1">
|
||||
<div class="ui dropdown icon button" @click.stop="showMergeStyleMenu = !showMergeStyleMenu">
|
||||
<svg-icon name="octicon-triangle-down" :size="14"/>
|
||||
<div class="menu" :class="{'show':showMergeStyleMenu}">
|
||||
<template v-for="msd in mergeForm.mergeStyles">
|
||||
|
||||
@@ -38,6 +38,8 @@ function initRepoDiffFileViewToggle() {
|
||||
}
|
||||
|
||||
function initRepoDiffConversationForm() {
|
||||
// FIXME: there could be various different form in a conversation-holder (for example: reply form, edit form).
|
||||
// This listener is for "reply form" only, it should clearly distinguish different forms in the future.
|
||||
addDelegatedEventListener<HTMLFormElement, SubmitEvent>(document, 'submit', '.conversation-holder form', async (form, e) => {
|
||||
e.preventDefault();
|
||||
const textArea = form.querySelector<HTMLTextAreaElement>('textarea');
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
import $ from 'jquery';
|
||||
import {svg} from '../svg.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {showElem} from '../utils/dom.ts';
|
||||
import {createElementFromHTML, showElem} from '../utils/dom.ts';
|
||||
import {parseIssuePageInfo} from '../utils.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
|
||||
let i18nTextEdited;
|
||||
let i18nTextOptions;
|
||||
let i18nTextDeleteFromHistory;
|
||||
let i18nTextDeleteFromHistoryConfirm;
|
||||
let i18nTextEdited: string;
|
||||
let i18nTextOptions: string;
|
||||
let i18nTextDeleteFromHistory: string;
|
||||
let i18nTextDeleteFromHistoryConfirm: string;
|
||||
|
||||
function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleHtml) {
|
||||
let $dialog = $('.content-history-detail-dialog');
|
||||
if ($dialog.length) return;
|
||||
|
||||
$dialog = $(`
|
||||
function showContentHistoryDetail(issueBaseUrl: string, commentId: string, historyId: string, itemTitleHtml: string) {
|
||||
const elDetailDialog = createElementFromHTML(`
|
||||
<div class="ui modal content-history-detail-dialog">
|
||||
${svg('octicon-x', 16, 'close icon inside')}
|
||||
<div class="header tw-flex tw-items-center tw-justify-between">
|
||||
@@ -29,8 +26,11 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
||||
</div>
|
||||
<div class="comment-diff-data is-loading"></div>
|
||||
</div>`);
|
||||
$dialog.appendTo($('body'));
|
||||
$dialog.find('.dialog-header-options').dropdown({
|
||||
document.body.append(elDetailDialog);
|
||||
const elOptionsDropdown = elDetailDialog.querySelector('.ui.dropdown.dialog-header-options');
|
||||
const $fomanticDialog = fomanticQuery(elDetailDialog);
|
||||
const $fomanticDropdownOptions = fomanticQuery(elOptionsDropdown);
|
||||
$fomanticDropdownOptions.dropdown({
|
||||
showOnFocus: false,
|
||||
allowReselection: true,
|
||||
async onChange(_value, _text, $item) {
|
||||
@@ -46,7 +46,7 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
||||
const resp = await response.json();
|
||||
|
||||
if (resp.ok) {
|
||||
$dialog.modal('hide');
|
||||
$fomanticDialog.modal('hide');
|
||||
} else {
|
||||
showErrorToast(resp.message);
|
||||
}
|
||||
@@ -60,10 +60,10 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
||||
}
|
||||
},
|
||||
onHide() {
|
||||
$(this).dropdown('clear', true);
|
||||
$fomanticDropdownOptions.dropdown('clear', true);
|
||||
},
|
||||
});
|
||||
$dialog.modal({
|
||||
$fomanticDialog.modal({
|
||||
async onShow() {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
@@ -74,25 +74,25 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
||||
const response = await GET(url);
|
||||
const resp = await response.json();
|
||||
|
||||
const commentDiffData = $dialog.find('.comment-diff-data')[0];
|
||||
commentDiffData?.classList.remove('is-loading');
|
||||
const commentDiffData = elDetailDialog.querySelector('.comment-diff-data');
|
||||
commentDiffData.classList.remove('is-loading');
|
||||
commentDiffData.innerHTML = resp.diffHtml;
|
||||
// there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden.
|
||||
if (resp.canSoftDelete) {
|
||||
showElem($dialog.find('.dialog-header-options'));
|
||||
showElem(elOptionsDropdown);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
},
|
||||
onHidden() {
|
||||
$dialog.remove();
|
||||
$fomanticDialog.remove();
|
||||
},
|
||||
}).modal('show');
|
||||
}
|
||||
|
||||
function showContentHistoryMenu(issueBaseUrl, $item, commentId) {
|
||||
const $headerLeft = $item.find('.comment-header-left');
|
||||
function showContentHistoryMenu(issueBaseUrl: string, elCommentItem: Element, commentId: string) {
|
||||
const elHeaderLeft = elCommentItem.querySelector('.comment-header-left');
|
||||
const menuHtml = `
|
||||
<div class="ui dropdown interact-fg content-history-menu" data-comment-id="${commentId}">
|
||||
• ${i18nTextEdited}${svg('octicon-triangle-down', 14, 'dropdown icon')}
|
||||
@@ -100,9 +100,12 @@ function showContentHistoryMenu(issueBaseUrl, $item, commentId) {
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
$headerLeft.find(`.content-history-menu`).remove();
|
||||
$headerLeft.append($(menuHtml));
|
||||
$headerLeft.find('.dropdown').dropdown({
|
||||
elHeaderLeft.querySelector(`.ui.dropdown.content-history-menu`)?.remove(); // remove the old one if exists
|
||||
elHeaderLeft.append(createElementFromHTML(menuHtml));
|
||||
|
||||
const elDropdown = elHeaderLeft.querySelector('.ui.dropdown.content-history-menu');
|
||||
const $fomanticDropdown = fomanticQuery(elDropdown);
|
||||
$fomanticDropdown.dropdown({
|
||||
action: 'hide',
|
||||
apiSettings: {
|
||||
cache: false,
|
||||
@@ -110,7 +113,7 @@ function showContentHistoryMenu(issueBaseUrl, $item, commentId) {
|
||||
},
|
||||
saveRemoteData: false,
|
||||
onHide() {
|
||||
$(this).dropdown('change values', null);
|
||||
$fomanticDropdown.dropdown('change values', null);
|
||||
},
|
||||
onChange(value, itemHtml, $item) {
|
||||
if (value && !$item.find('[data-history-is-deleted=1]').length) {
|
||||
@@ -124,9 +127,9 @@ export async function initRepoIssueContentHistory() {
|
||||
const issuePageInfo = parseIssuePageInfo();
|
||||
if (!issuePageInfo.issueNumber) return;
|
||||
|
||||
const $itemIssue = $('.repository.issue .timeline-item.comment.first'); // issue(PR) main content
|
||||
const $comments = $('.repository.issue .comment-list .comment'); // includes: issue(PR) comments, review comments, code comments
|
||||
if (!$itemIssue.length && !$comments.length) return;
|
||||
const elIssueDescription = document.querySelector('.repository.issue .timeline-item.comment.first'); // issue(PR) main content
|
||||
const elComments = document.querySelectorAll('.repository.issue .comment-list .comment'); // includes: issue(PR) comments, review comments, code comments
|
||||
if (!elIssueDescription && !elComments.length) return;
|
||||
|
||||
const issueBaseUrl = `${issuePageInfo.repoLink}/issues/${issuePageInfo.issueNumber}`;
|
||||
|
||||
@@ -139,13 +142,13 @@ export async function initRepoIssueContentHistory() {
|
||||
i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm;
|
||||
i18nTextOptions = resp.i18n.textOptions;
|
||||
|
||||
if (resp.editedHistoryCountMap[0] && $itemIssue.length) {
|
||||
showContentHistoryMenu(issueBaseUrl, $itemIssue, '0');
|
||||
if (resp.editedHistoryCountMap[0] && elIssueDescription) {
|
||||
showContentHistoryMenu(issueBaseUrl, elIssueDescription, '0');
|
||||
}
|
||||
for (const [commentId, _editedCount] of Object.entries(resp.editedHistoryCountMap)) {
|
||||
if (commentId === '0') continue;
|
||||
const $itemComment = $(`#issuecomment-${commentId}`);
|
||||
showContentHistoryMenu(issueBaseUrl, $itemComment, commentId);
|
||||
const elIssueComment = document.querySelector(`#issuecomment-${commentId}`);
|
||||
if (elIssueComment) showContentHistoryMenu(issueBaseUrl, elIssueComment, commentId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
|
||||
@@ -30,6 +30,9 @@ async function tryOnEditContent(e) {
|
||||
|
||||
const saveAndRefresh = async (e) => {
|
||||
e.preventDefault();
|
||||
// we are already in a form, do not bubble up to the document otherwise there will be other "form submit handlers"
|
||||
// at the moment, the form submit event conflicts with initRepoDiffConversationForm (global '.conversation-holder form' event handler)
|
||||
e.stopPropagation();
|
||||
renderContent.classList.add('is-loading');
|
||||
showElem(renderContent);
|
||||
hideElem(editContentZone);
|
||||
|
||||
@@ -5,7 +5,7 @@ import {initIssueSidebarComboList} from './repo-issue-sidebar-combolist.ts';
|
||||
|
||||
function initBranchSelector() {
|
||||
// TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl"
|
||||
const elSelectBranch = document.querySelector('.ui.dropdown.select-branch');
|
||||
const elSelectBranch = document.querySelector('.ui.dropdown.select-branch.branch-selector-dropdown');
|
||||
if (!elSelectBranch) return;
|
||||
|
||||
const urlUpdateIssueRef = elSelectBranch.getAttribute('data-url-update-issueref');
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import $ from 'jquery';
|
||||
import {
|
||||
initRepoCommentFormAndSidebar,
|
||||
initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete,
|
||||
@@ -15,7 +14,7 @@ import {initCompReactionSelector} from './comp/ReactionSelector.ts';
|
||||
import {initRepoSettings} 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 {hideElem, queryElemChildren, queryElems, showElem} from '../utils/dom.ts';
|
||||
import {initRepoIssueCommentEdit} from './repo-issue-edit.ts';
|
||||
import {initRepoMilestone} from './repo-milestone.ts';
|
||||
import {initRepoNew} from './repo-new.ts';
|
||||
@@ -29,47 +28,20 @@ function initRepoBranchTagSelector(selector: string) {
|
||||
}
|
||||
|
||||
export function initBranchSelectorTabs() {
|
||||
const elSelectBranch = document.querySelector('.ui.dropdown.select-branch');
|
||||
if (!elSelectBranch) return;
|
||||
|
||||
$(elSelectBranch).find('.reference.column').on('click', function () {
|
||||
hideElem($(elSelectBranch).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;
|
||||
});
|
||||
}
|
||||
|
||||
function initRepoCommonBranchOrTagDropdown(selector: string) {
|
||||
$(selector).each(function () {
|
||||
const $dropdown = $(this);
|
||||
$dropdown.find('.reference.column').on('click', function () {
|
||||
hideElem($dropdown.find('.scrolling.reference-list-menu'));
|
||||
showElem($($(this).data('target')));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initRepoCommonFilterSearchDropdown(selector: string) {
|
||||
const $dropdown = $(selector);
|
||||
if (!$dropdown.length) return;
|
||||
|
||||
$dropdown.dropdown({
|
||||
fullTextSearch: 'exact',
|
||||
selectOnKeydown: false,
|
||||
onChange(_text, _value, $choice) {
|
||||
if ($choice[0].getAttribute('data-url')) {
|
||||
window.location.href = $choice[0].getAttribute('data-url');
|
||||
}
|
||||
},
|
||||
message: {noResults: $dropdown[0].getAttribute('data-no-results')},
|
||||
});
|
||||
const elSelectBranches = document.querySelectorAll('.ui.dropdown.select-branch');
|
||||
for (const elSelectBranch of elSelectBranches) {
|
||||
queryElems(elSelectBranch, '.reference.column', (el) => el.addEventListener('click', () => {
|
||||
hideElem(elSelectBranch.querySelectorAll('.scrolling.reference-list-menu'));
|
||||
showElem(el.getAttribute('data-target'));
|
||||
queryElemChildren(el.parentNode, '.branch-tag-item', (el) => el.classList.remove('active'));
|
||||
el.classList.add('active');
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export function initRepository() {
|
||||
if (!$('.page-content.repository').length) return;
|
||||
const pageContent = document.querySelector('.page-content.repository');
|
||||
if (!pageContent) return;
|
||||
|
||||
initRepoBranchTagSelector('.js-branch-tag-selector');
|
||||
initRepoCommentFormAndSidebar();
|
||||
@@ -79,19 +51,12 @@ export function initRepository() {
|
||||
initRepoMilestone();
|
||||
initRepoNew();
|
||||
|
||||
// Compare or pull request
|
||||
const $repoDiff = $('.repository.diff');
|
||||
if ($repoDiff.length) {
|
||||
initRepoCommonBranchOrTagDropdown('.choose.branch .dropdown');
|
||||
initRepoCommonFilterSearchDropdown('.choose.branch .dropdown');
|
||||
}
|
||||
|
||||
initRepoCloneButtons();
|
||||
initCitationFileCopyContent();
|
||||
initRepoSettings();
|
||||
|
||||
// Issues
|
||||
if ($('.repository.view.issue').length > 0) {
|
||||
if (pageContent.matches('.page-content.repository.view.issue')) {
|
||||
initRepoIssueCommentEdit();
|
||||
|
||||
initRepoIssueBranchSelect();
|
||||
@@ -112,18 +77,5 @@ export function initRepository() {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,80 @@
|
||||
import $ from 'jquery';
|
||||
import {hideElem, showElem, toggleElem} from '../utils/dom.ts';
|
||||
import {htmlEscape} from 'escape-goat';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
|
||||
function initRepoNewTemplateSearch(form: HTMLFormElement) {
|
||||
const inputRepoOwnerUid = form.querySelector<HTMLInputElement>('#uid');
|
||||
const elRepoTemplateDropdown = form.querySelector<HTMLInputElement>('#repo_template_search');
|
||||
const inputRepoTemplate = form.querySelector<HTMLInputElement>('#repo_template');
|
||||
const elTemplateUnits = form.querySelector('#template_units');
|
||||
const elNonTemplate = form.querySelector('#non_template');
|
||||
const checkTemplate = function () {
|
||||
const hasSelectedTemplate = inputRepoTemplate.value !== '' && inputRepoTemplate.value !== '0';
|
||||
toggleElem(elTemplateUnits, hasSelectedTemplate);
|
||||
toggleElem(elNonTemplate, !hasSelectedTemplate);
|
||||
};
|
||||
inputRepoTemplate.addEventListener('change', checkTemplate);
|
||||
checkTemplate();
|
||||
|
||||
const $dropdown = fomanticQuery(elRepoTemplateDropdown);
|
||||
const onChangeOwner = function () {
|
||||
$dropdown.dropdown('setting', {
|
||||
apiSettings: {
|
||||
url: `${appSubUrl}/repo/search?q={query}&template=true&priority_owner_id=${inputRepoOwnerUid.value}`,
|
||||
onResponse(response) {
|
||||
const results = [];
|
||||
results.push({name: '', value: ''}); // empty item means not using template
|
||||
for (const tmplRepo of response.data) {
|
||||
results.push({
|
||||
name: htmlEscape(tmplRepo.repository.full_name),
|
||||
value: String(tmplRepo.repository.id),
|
||||
});
|
||||
}
|
||||
$dropdown.fomanticExt.onResponseKeepSelectedItem($dropdown, inputRepoTemplate.value);
|
||||
return {results};
|
||||
},
|
||||
cache: false,
|
||||
},
|
||||
});
|
||||
};
|
||||
inputRepoOwnerUid.addEventListener('change', onChangeOwner);
|
||||
onChangeOwner();
|
||||
}
|
||||
|
||||
export function initRepoNew() {
|
||||
// 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<HTMLInputElement>('input[name="auto_init"]').checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
const pageContent = document.querySelector('.page-content.repository.new-repo');
|
||||
if (!pageContent) return;
|
||||
|
||||
const form = document.querySelector<HTMLFormElement>('.new-repo-form');
|
||||
const inputGitIgnores = form.querySelector<HTMLInputElement>('input[name="gitignores"]');
|
||||
const inputLicense = form.querySelector<HTMLInputElement>('input[name="license"]');
|
||||
const inputAutoInit = form.querySelector<HTMLInputElement>('input[name="auto_init"]');
|
||||
const updateUiAutoInit = () => {
|
||||
inputAutoInit.checked = Boolean(inputGitIgnores.value || inputLicense.value);
|
||||
};
|
||||
inputGitIgnores.addEventListener('change', updateUiAutoInit);
|
||||
inputLicense.addEventListener('change', updateUiAutoInit);
|
||||
updateUiAutoInit();
|
||||
|
||||
const inputRepoName = form.querySelector<HTMLInputElement>('input[name="repo_name"]');
|
||||
const inputPrivate = form.querySelector<HTMLInputElement>('input[name="private"]');
|
||||
const updateUiRepoName = () => {
|
||||
const helps = form.querySelectorAll(`.help[data-help-for-repo-name]`);
|
||||
hideElem(helps);
|
||||
let help = form.querySelector(`.help[data-help-for-repo-name="${CSS.escape(inputRepoName.value)}"]`);
|
||||
if (!help) help = form.querySelector(`.help[data-help-for-repo-name=""]`);
|
||||
showElem(help);
|
||||
const repoNamePreferPrivate = {'.profile': false, '.profile-private': true};
|
||||
const preferPrivate = repoNamePreferPrivate[inputRepoName.value];
|
||||
// inputPrivate might be disabled because site admin "force private"
|
||||
if (preferPrivate !== undefined && !inputPrivate.closest('.disabled, [disabled]')) {
|
||||
inputPrivate.checked = preferPrivate;
|
||||
}
|
||||
};
|
||||
inputRepoName.addEventListener('input', updateUiRepoName);
|
||||
updateUiRepoName();
|
||||
|
||||
initRepoNewTemplateSearch(form);
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import $ from 'jquery';
|
||||
import {htmlEscape} from 'escape-goat';
|
||||
import {hideElem, showElem} from '../utils/dom.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
|
||||
export function initRepoTemplateSearch() {
|
||||
const $repoTemplate = $('#repo_template');
|
||||
const checkTemplate = function () {
|
||||
const $templateUnits = $('#template_units');
|
||||
const $nonTemplate = $('#non_template');
|
||||
if ($repoTemplate.val() !== '' && $repoTemplate.val() !== '0') {
|
||||
showElem($templateUnits);
|
||||
hideElem($nonTemplate);
|
||||
} else {
|
||||
hideElem($templateUnits);
|
||||
showElem($nonTemplate);
|
||||
}
|
||||
};
|
||||
$repoTemplate.on('change', checkTemplate);
|
||||
checkTemplate();
|
||||
|
||||
const changeOwner = function () {
|
||||
$('#repo_template_search')
|
||||
.dropdown({
|
||||
apiSettings: {
|
||||
url: `${appSubUrl}/repo/search?q={query}&template=true&priority_owner_id=${$('#uid').val()}`,
|
||||
onResponse(response) {
|
||||
const filteredResponse = {success: true, results: []};
|
||||
filteredResponse.results.push({
|
||||
name: '',
|
||||
value: '',
|
||||
});
|
||||
// Parse the response from the api to work with our dropdown
|
||||
$.each(response.data, (_r, repo) => {
|
||||
filteredResponse.results.push({
|
||||
name: htmlEscape(repo.repository.full_name),
|
||||
value: repo.repository.id,
|
||||
});
|
||||
});
|
||||
return filteredResponse;
|
||||
},
|
||||
cache: false,
|
||||
},
|
||||
|
||||
fullTextSearch: true,
|
||||
});
|
||||
};
|
||||
$('#uid').on('change', changeOwner);
|
||||
changeOwner();
|
||||
}
|
||||
Vendored
+2
-1
@@ -36,8 +36,9 @@ declare module 'swagger-ui-dist/swagger-ui-es-bundle.js' {
|
||||
}
|
||||
|
||||
interface JQuery {
|
||||
api: any, // fomantic
|
||||
areYouSure: any, // jquery.are-you-sure
|
||||
fomanticExt: any; // fomantic extension
|
||||
api: any, // fomantic
|
||||
dimmer: any, // fomantic
|
||||
dropdown: any; // fomantic
|
||||
modal: any; // fomantic
|
||||
|
||||
@@ -35,7 +35,6 @@ import {initRepoEllipsisButton, initCommitStatuses} from './features/repo-commit
|
||||
import {initRepoTopicBar} from './features/repo-home.ts';
|
||||
import {initViewFileTreeSidebar} from './features/repo-view-file-tree-sidebar.ts';
|
||||
import {initAdminCommon} from './features/admin/common.ts';
|
||||
import {initRepoTemplateSearch} from './features/repo-template.ts';
|
||||
import {initRepoCodeView} from './features/repo-code.ts';
|
||||
import {initSshKeyFormParser} from './features/sshkey-helper.ts';
|
||||
import {initUserSettings} from './features/user-settings.ts';
|
||||
@@ -194,7 +193,6 @@ onDomReady(() => {
|
||||
initRepoPullRequestReview,
|
||||
initRepoRelease,
|
||||
initRepoReleaseNew,
|
||||
initRepoTemplateSearch,
|
||||
initRepoTopicBar,
|
||||
initViewFileTreeSidebar,
|
||||
initRepoWikiForm,
|
||||
|
||||
@@ -11,9 +11,10 @@ import {svg} from '../svg.ts';
|
||||
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
||||
|
||||
export function initGiteaFomantic() {
|
||||
// our extensions
|
||||
$.fn.fomanticExt = {};
|
||||
// Silence fomantic's error logging when tabs are used without a target content element
|
||||
$.fn.tab.settings.silent = true;
|
||||
|
||||
// By default, use "exact match" for full text search
|
||||
$.fn.dropdown.settings.fullTextSearch = 'exact';
|
||||
// Do not use "cursor: pointer" for dropdown labels
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import $ from 'jquery';
|
||||
import {generateAriaId} from './base.ts';
|
||||
import type {FomanticInitFunction} from '../../types.ts';
|
||||
import {queryElems} from '../../utils/dom.ts';
|
||||
|
||||
const ariaPatchKey = '_giteaAriaPatchDropdown';
|
||||
const fomanticDropdownFn = $.fn.dropdown;
|
||||
@@ -9,6 +10,7 @@ const fomanticDropdownFn = $.fn.dropdown;
|
||||
export function initAriaDropdownPatch() {
|
||||
if ($.fn.dropdown === ariaDropdownFn) throw new Error('initAriaDropdownPatch could only be called once');
|
||||
$.fn.dropdown = ariaDropdownFn;
|
||||
$.fn.fomanticExt.onResponseKeepSelectedItem = onResponseKeepSelectedItem;
|
||||
(ariaDropdownFn as FomanticInitFunction).settings = fomanticDropdownFn.settings;
|
||||
}
|
||||
|
||||
@@ -351,3 +353,19 @@ export function hideScopedEmptyDividers(container: Element) {
|
||||
if (item.nextElementSibling?.matches('.divider')) hideDivider(item);
|
||||
}
|
||||
}
|
||||
|
||||
function onResponseKeepSelectedItem(dropdown: typeof $|HTMLElement, selectedValue: string) {
|
||||
// There is a bug in fomantic dropdown when using "apiSettings" to fetch data
|
||||
// * when there is a selected item, the dropdown insists on hiding the selected one from the list:
|
||||
// * in the "filter" function: ('[data-value="'+value+'"]').addClass(className.filtered)
|
||||
//
|
||||
// When user selects one item, and click the dropdown again,
|
||||
// then the dropdown only shows other items and will select another (wrong) one.
|
||||
// It can't be easily fix by using setTimeout(patch, 0) in `onResponse` because the `onResponse` is called before another `setTimeout(..., timeLeft)`
|
||||
// Fortunately, the "timeLeft" is controlled by "loadingDuration" which is always zero at the moment, so we can use `setTimeout(..., 10)`
|
||||
const elDropdown = (dropdown instanceof HTMLElement) ? dropdown : dropdown[0];
|
||||
setTimeout(() => {
|
||||
queryElems(elDropdown, `.menu .item[data-value="${CSS.escape(selectedValue)}"].filtered`, (el) => el.classList.remove('filtered'));
|
||||
$(elDropdown).dropdown('set selected', selectedValue ?? '');
|
||||
}, 10);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ test('parseIssueNewHref', () => {
|
||||
expect(parseIssueNewHref('/owner/repo/issues/new')).toEqual({ownerName: 'owner', repoName: 'repo', pathType: 'issues'});
|
||||
expect(parseIssueNewHref('/owner/repo/issues/new?query')).toEqual({ownerName: 'owner', repoName: 'repo', pathType: 'issues'});
|
||||
expect(parseIssueNewHref('/sub/owner/repo/issues/new#hash')).toEqual({ownerName: 'owner', repoName: 'repo', pathType: 'issues'});
|
||||
expect(parseIssueNewHref('/sub/owner/repo/compare/feature/branch-1...fix/branch-2')).toEqual({ownerName: 'owner', repoName: 'repo', pathType: 'pulls'});
|
||||
});
|
||||
|
||||
test('parseUrl', () => {
|
||||
|
||||
+3
-2
@@ -39,8 +39,9 @@ export function parseIssueHref(href: string): IssuePathInfo {
|
||||
|
||||
export function parseIssueNewHref(href: string): IssuePathInfo {
|
||||
const path = (href || '').replace(/[#?].*$/, '');
|
||||
const [_, ownerName, repoName, pathType, indexString] = /([^/]+)\/([^/]+)\/(issues|pulls)\/new/.exec(path) || [];
|
||||
return {ownerName, repoName, pathType, indexString};
|
||||
const [_, ownerName, repoName, pathTypeField] = /([^/]+)\/([^/]+)\/(issues\/new|compare\/.+\.\.\.)/.exec(path) || [];
|
||||
const pathType = pathTypeField.startsWith('issues/new') ? 'issues' : 'pulls';
|
||||
return {ownerName, repoName, pathType};
|
||||
}
|
||||
|
||||
export function parseIssuePageInfo(): IssuePageInfo {
|
||||
|
||||
Reference in New Issue
Block a user