mirror of
https://github.com/go-gitea/gitea.git
synced 2026-06-18 19:39:19 +03:00
chore: migrate unescaped-html-literal eslint rule to our repo and fix more cases (#38072)
This commit is contained in:
@@ -848,6 +848,7 @@ table th[data-sortt-desc] .svg {
|
||||
}
|
||||
|
||||
/* this is useful to make a left-right (e.g.: title .... operations) layout with default gap, and it wrap for small widths */
|
||||
.ui.modal .header.flex-left-right,
|
||||
.flex-left-right {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {svg} from '../svg.ts';
|
||||
import {svgRaw} from '../svg.ts';
|
||||
import {html} from '../utils/html.ts';
|
||||
import {copyToClipboardWithFeedback} from '../modules/clipboard.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
@@ -45,10 +45,11 @@ export function generateMarkdownLinkForAttachment(file: Partial<CustomDropzoneFi
|
||||
function addCopyLink(file: Partial<CustomDropzoneFile>) {
|
||||
// Create a "Copy Link" element, to conveniently copy the image or file link as Markdown to the clipboard
|
||||
// The "<a>" element has a hardcoded cursor: pointer because the default is overridden by .dropzone
|
||||
const copyLinkEl = createElementFromHTML<HTMLDivElement>(`
|
||||
<div class="tw-text-center">
|
||||
<a href="#" class="tw-cursor-pointer">${svg('octicon-copy', 14)} Copy link</a>
|
||||
</div>`);
|
||||
const copyLinkEl = createElementFromHTML<HTMLDivElement>(html`
|
||||
<div class="tw-text-center">
|
||||
<a href="#" class="tw-cursor-pointer">${svgRaw('octicon-copy', 14)} Copy link</a>
|
||||
</div>
|
||||
`);
|
||||
copyLinkEl.addEventListener('click', async (e) => {
|
||||
e.preventDefault();
|
||||
await copyToClipboardWithFeedback(copyLinkEl, generateMarkdownLinkForAttachment(file));
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {svg} from '../svg.ts';
|
||||
import {svgRaw} from '../svg.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {createElementFromHTML, showElem} from '../utils/dom.ts';
|
||||
import {parseIssuePageInfo} from '../utils.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
import {hideFomanticModal, showFomanticModal} from '../modules/fomantic/modal.ts';
|
||||
import {html, htmlRaw} from '../utils/html.ts';
|
||||
|
||||
let i18nTextEdited: string;
|
||||
let i18nTextOptions: string;
|
||||
@@ -12,21 +13,22 @@ let i18nTextDeleteFromHistory: string;
|
||||
let i18nTextDeleteFromHistoryConfirm: string;
|
||||
|
||||
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 flex-left-right">
|
||||
<div>${itemTitleHtml}</div>
|
||||
<div class="ui dropdown dialog-header-options tw-mr-8 tw-hidden">
|
||||
${i18nTextOptions}
|
||||
${svg('octicon-triangle-down', 14, 'dropdown icon')}
|
||||
<div class="menu">
|
||||
<div class="item tw-text-red" data-option-item="delete">${i18nTextDeleteFromHistory}</div>
|
||||
const elDetailDialog = createElementFromHTML(html`
|
||||
<div class="ui modal content-history-detail-dialog">
|
||||
${svgRaw('octicon-x', 16, 'close icon inside')}
|
||||
<div class="header flex-left-right">
|
||||
<div>${htmlRaw(itemTitleHtml)}</div>
|
||||
<div class="ui dropdown dialog-header-options tw-mr-8 tw-hidden">
|
||||
${i18nTextOptions}
|
||||
${svgRaw('octicon-triangle-down', 14, 'dropdown icon')}
|
||||
<div class="menu">
|
||||
<div class="item tw-text-red" data-option-item="delete">${i18nTextDeleteFromHistory}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-diff-data is-loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-diff-data is-loading"></div>
|
||||
</div>`);
|
||||
`);
|
||||
document.body.append(elDetailDialog);
|
||||
const elOptionsDropdown = elDetailDialog.querySelector('.ui.dropdown.dialog-header-options')!;
|
||||
const $fomanticDropdownOptions = fomanticQuery(elOptionsDropdown);
|
||||
@@ -93,12 +95,13 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
|
||||
|
||||
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 tw-flex-shrink-0" data-comment-id="${commentId}">
|
||||
• ${i18nTextEdited}${svg('octicon-triangle-down', 14, 'dropdown icon')}
|
||||
<div class="menu">
|
||||
const menuHtml = html`
|
||||
<div class="ui dropdown interact-fg content-history-menu tw-flex-shrink-0" data-comment-id="${commentId}">
|
||||
• ${i18nTextEdited}${svgRaw('octicon-triangle-down', 14, 'dropdown icon')}
|
||||
<div class="menu">
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
`;
|
||||
|
||||
elHeaderLeft.querySelector(`.ui.dropdown.content-history-menu`)?.remove(); // remove the old one if exists
|
||||
elHeaderLeft.append(createElementFromHTML(menuHtml));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {errorMessage} from '../modules/errors.ts';
|
||||
import {htmlEscape} from '../utils/html.ts';
|
||||
import {html, htmlEscape, htmlRaw} from '../utils/html.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {
|
||||
addDelegatedEventListener,
|
||||
@@ -274,15 +274,13 @@ export function initRepoPullRequestReview() {
|
||||
|
||||
let ntr = tr.nextElementSibling;
|
||||
if (!ntr?.classList.contains('add-comment')) {
|
||||
ntr = createElementFromHTML(`
|
||||
<tr class="add-comment" data-line-type="${htmlEscape(lineType)}">
|
||||
${isSplit ? `
|
||||
<td class="add-comment-left" colspan="4"></td>
|
||||
<td class="add-comment-right" colspan="4"></td>
|
||||
` : `
|
||||
<td class="add-comment-left add-comment-right" colspan="5"></td>
|
||||
`}
|
||||
</tr>`);
|
||||
const tdSplit = html`<td class="add-comment-left" colspan="4"></td><td class="add-comment-right" colspan="4"></td>`;
|
||||
const tdUnified = html`<td class="add-comment-left add-comment-right" colspan="5"></td>`;
|
||||
ntr = createElementFromHTML(html`
|
||||
<tr class="add-comment" data-line-type="${lineType}">
|
||||
${isSplit ? htmlRaw(tdSplit) : htmlRaw(tdUnified)}
|
||||
</tr>
|
||||
`);
|
||||
tr.after(ntr);
|
||||
}
|
||||
const td = ntr.querySelector(`.add-comment-${side}`)!;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {htmlEscape} from '../utils/html.ts';
|
||||
import {svg} from '../svg.ts';
|
||||
import {html, htmlEscape, htmlRaw} from '../utils/html.ts';
|
||||
import {svgRaw} from '../svg.ts';
|
||||
import {animateOnce, queryElems, showElem} from '../utils/dom.ts';
|
||||
import Toastify from 'toastify-js'; // don't use "async import", because when network error occurs, the "async import" also fails and nothing is shown
|
||||
import type {Intent} from '../types.ts';
|
||||
@@ -44,9 +44,8 @@ type ToastifyElement = HTMLElement & {_giteaToastifyInstance?: Toast};
|
||||
|
||||
/** See https://github.com/apvarun/toastify-js#api for options */
|
||||
function showToast(message: string, level: Intent, {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast | null {
|
||||
const body = useHtmlBody ? message : htmlEscape(message);
|
||||
const parent = document.querySelector('.ui.dimmer.active') ?? document.body;
|
||||
const duplicateKey = preventDuplicates ? (preventDuplicates === true ? `${level}-${body}` : preventDuplicates) : '';
|
||||
const duplicateKey = preventDuplicates ? (preventDuplicates === true ? `${level}-${message}` : preventDuplicates) : '';
|
||||
|
||||
// prevent showing duplicate toasts with the same level and message, and give visual feedback for end users
|
||||
if (preventDuplicates) {
|
||||
@@ -61,12 +60,13 @@ function showToast(message: string, level: Intent, {gravity, position, duration,
|
||||
}
|
||||
|
||||
const {icon, background, duration: levelDuration} = levels[level ?? 'info'];
|
||||
const bodyHtml = useHtmlBody ? message : htmlEscape(message);
|
||||
const toast = Toastify({
|
||||
selector: parent,
|
||||
text: `
|
||||
<div class='toast-icon'>${svg(icon)}</div>
|
||||
<div class='toast-body'><span class="toast-duplicate-number tw-hidden">1</span>${body}</div>
|
||||
<button class='btn toast-close'>${svg('octicon-x')}</button>
|
||||
text: html`
|
||||
<div class='toast-icon'>${svgRaw(icon)}</div>
|
||||
<div class='toast-body'><span class="toast-duplicate-number tw-hidden">1</span>${htmlRaw(bodyHtml)}</div>
|
||||
<button class='btn toast-close'>${svgRaw('octicon-x')}</button>
|
||||
`,
|
||||
escapeMarkup: false,
|
||||
gravity: gravity ?? 'top',
|
||||
|
||||
@@ -199,6 +199,10 @@ export function svg(name: SvgName, size = 16, classNames?: string | string[]): s
|
||||
return serializeXml(svgNode);
|
||||
}
|
||||
|
||||
export function svgRaw(name: SvgName, size = 16, classNames?: string | string[]) {
|
||||
return htmlRaw(svg(name, size, classNames));
|
||||
}
|
||||
|
||||
export function svgParseOuterInner(name: SvgName) {
|
||||
const svgStr = svgs[name];
|
||||
if (!svgStr) throw new Error(`Unknown SVG icon: ${name}`);
|
||||
|
||||
Reference in New Issue
Block a user