mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-01 09:51:39 -05:00
Merge pull request '[PORT] Enable no-jquery/no-parse-html-literal
and fix violation (gitea#31684)' (#4719) from gusted/forgejo-gt-31684 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/4719 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
commit
0851aca863
4 changed files with 44 additions and 13 deletions
|
@ -460,7 +460,7 @@ rules:
|
||||||
no-jquery/no-param: [2]
|
no-jquery/no-param: [2]
|
||||||
no-jquery/no-parent: [0]
|
no-jquery/no-parent: [0]
|
||||||
no-jquery/no-parents: [2]
|
no-jquery/no-parents: [2]
|
||||||
no-jquery/no-parse-html-literal: [0]
|
no-jquery/no-parse-html-literal: [2]
|
||||||
no-jquery/no-parse-html: [2]
|
no-jquery/no-parse-html: [2]
|
||||||
no-jquery/no-parse-json: [2]
|
no-jquery/no-parse-json: [2]
|
||||||
no-jquery/no-parse-xml: [2]
|
no-jquery/no-parse-xml: [2]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {htmlEscape} from 'escape-goat';
|
import {htmlEscape} from 'escape-goat';
|
||||||
import {createCodeEditor} from './codeeditor.js';
|
import {createCodeEditor} from './codeeditor.js';
|
||||||
import {hideElem, showElem} from '../utils/dom.js';
|
import {hideElem, showElem, createElementFromHTML} from '../utils/dom.js';
|
||||||
import {initMarkupContent} from '../markup/content.js';
|
import {initMarkupContent} from '../markup/content.js';
|
||||||
import {attachRefIssueContextPopup} from './contextpopup.js';
|
import {attachRefIssueContextPopup} from './contextpopup.js';
|
||||||
import {POST} from '../modules/fetch.js';
|
import {POST} from '../modules/fetch.js';
|
||||||
|
@ -9,7 +9,9 @@ import {POST} from '../modules/fetch.js';
|
||||||
function initEditPreviewTab($form) {
|
function initEditPreviewTab($form) {
|
||||||
const $tabMenu = $form.find('.tabular.menu');
|
const $tabMenu = $form.find('.tabular.menu');
|
||||||
$tabMenu.find('.item').tab();
|
$tabMenu.find('.item').tab();
|
||||||
const $previewTab = $tabMenu.find(`.item[data-tab="${$tabMenu.data('preview')}"]`);
|
const $previewTab = $tabMenu.find(
|
||||||
|
`.item[data-tab="${$tabMenu.data('preview')}"]`,
|
||||||
|
);
|
||||||
if ($previewTab.length) {
|
if ($previewTab.length) {
|
||||||
$previewTab.on('click', async function () {
|
$previewTab.on('click', async function () {
|
||||||
const $this = $(this);
|
const $this = $(this);
|
||||||
|
@ -24,12 +26,17 @@ function initEditPreviewTab($form) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('mode', mode);
|
formData.append('mode', mode);
|
||||||
formData.append('context', context);
|
formData.append('context', context);
|
||||||
formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val());
|
formData.append(
|
||||||
|
'text',
|
||||||
|
$form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val(),
|
||||||
|
);
|
||||||
formData.append('file_path', $treePathEl.val());
|
formData.append('file_path', $treePathEl.val());
|
||||||
try {
|
try {
|
||||||
const response = await POST($this.data('url'), {data: formData});
|
const response = await POST($this.data('url'), {data: formData});
|
||||||
const data = await response.text();
|
const data = await response.text();
|
||||||
const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`);
|
const $previewPanel = $form.find(
|
||||||
|
`.tab[data-tab="${$tabMenu.data('preview')}"]`,
|
||||||
|
);
|
||||||
renderPreviewPanelContent($previewPanel, data);
|
renderPreviewPanelContent($previewPanel, data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error:', error);
|
console.error('Error:', error);
|
||||||
|
@ -96,8 +103,14 @@ export function initRepoEditor() {
|
||||||
const value = parts[i];
|
const value = parts[i];
|
||||||
if (i < parts.length - 1) {
|
if (i < parts.length - 1) {
|
||||||
if (value.length) {
|
if (value.length) {
|
||||||
$(`<span class="section"><a href="#">${htmlEscape(value)}</a></span>`).insertBefore($(this));
|
$editFilename[0].before(
|
||||||
$('<div class="breadcrumb-divider">/</div>').insertBefore($(this));
|
createElementFromHTML(
|
||||||
|
`<span class="section"><a href="#">${htmlEscape(value)}</a></span>`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
$editFilename[0].before(
|
||||||
|
createElementFromHTML(`<div class="breadcrumb-divider">/</div>`),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$(this).val(value);
|
$(this).val(value);
|
||||||
|
@ -113,7 +126,11 @@ export function initRepoEditor() {
|
||||||
const $section = $('.breadcrumb span.section');
|
const $section = $('.breadcrumb span.section');
|
||||||
|
|
||||||
// Jump back to last directory once the filename is empty
|
// Jump back to last directory once the filename is empty
|
||||||
if (e.code === 'Backspace' && getCursorPosition($(this)) === 0 && $section.length > 0) {
|
if (
|
||||||
|
e.code === 'Backspace' &&
|
||||||
|
getCursorPosition($(this)) === 0 &&
|
||||||
|
$section.length > 0
|
||||||
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const $divider = $('.breadcrumb .breadcrumb-divider');
|
const $divider = $('.breadcrumb .breadcrumb-divider');
|
||||||
const value = $section.last().find('a').text();
|
const value = $section.last().find('a').text();
|
||||||
|
@ -164,11 +181,13 @@ export function initRepoEditor() {
|
||||||
commitButton?.addEventListener('click', (e) => {
|
commitButton?.addEventListener('click', (e) => {
|
||||||
// A modal which asks if an empty file should be committed
|
// A modal which asks if an empty file should be committed
|
||||||
if (!$editArea.val()) {
|
if (!$editArea.val()) {
|
||||||
$('#edit-empty-content-modal').modal({
|
$('#edit-empty-content-modal')
|
||||||
|
.modal({
|
||||||
onApprove() {
|
onApprove() {
|
||||||
$('.edit.form').trigger('submit');
|
$('.edit.form').trigger('submit');
|
||||||
},
|
},
|
||||||
}).modal('show');
|
})
|
||||||
|
.modal('show');
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -296,3 +296,10 @@ export function replaceTextareaSelection(textarea, text) {
|
||||||
textarea.dispatchEvent(new CustomEvent('change', {bubbles: true, cancelable: true}));
|
textarea.dispatchEvent(new CustomEvent('change', {bubbles: true, cancelable: true}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Warning: Do not enter any unsanitized variables here
|
||||||
|
export function createElementFromHTML(htmlString) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.innerHTML = htmlString.trim();
|
||||||
|
return div.firstChild;
|
||||||
|
}
|
||||||
|
|
5
web_src/js/utils/dom.test.js
Normal file
5
web_src/js/utils/dom.test.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import {createElementFromHTML} from './dom.js';
|
||||||
|
|
||||||
|
test('createElementFromHTML', () => {
|
||||||
|
expect(createElementFromHTML('<a>foo<span>bar</span></a>').outerHTML).toEqual('<a>foo<span>bar</span></a>');
|
||||||
|
});
|
Loading…
Reference in a new issue