mirror of
https://github.com/go-gitea/gitea.git
synced 2025-12-30 05:47:30 +01:00
Add pull request files line selections
This commit is contained in:
parent
688430e3ce
commit
1ec71e877c
@ -11,7 +11,7 @@
|
||||
</td>
|
||||
{{else}}
|
||||
{{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$.FileNameHash}}L{{$line.LeftIdx}}"{{end}}></span></td>
|
||||
<td class="lines-escape lines-escape-old">{{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-old">
|
||||
@ -27,7 +27,7 @@
|
||||
<code class="code-inner"></code>
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"{{if $line.RightIdx}} id="diff-{{$.FileNameHash}}R{{$line.RightIdx}}"{{end}}></span></td>
|
||||
<td class="lines-escape lines-escape-new">{{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker=""></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-new">
|
||||
@ -65,8 +65,8 @@
|
||||
{{if eq .GetType 4}}
|
||||
<td colspan="2" class="lines-num">{{$line.RenderBlobExcerptButtons $.FileNameHash $diffBlobExcerptData}}</td>
|
||||
{{else}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$.FileNameHash}}L{{$line.LeftIdx}}"{{end}}></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$.FileNameHash}}R{{$line.RightIdx}}{{end}}"{{if $line.RightIdx}} id="diff-{{$.FileNameHash}}R{{$line.RightIdx}}"{{end}}></span></td>
|
||||
{{end}}
|
||||
{{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}}
|
||||
<td class="lines-escape">{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}</td>
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
{{$match := index $section.Lines $line.Match}}
|
||||
{{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line ctx.Locale}}{{end}}
|
||||
{{- $rightDiff := ""}}{{if $match.RightIdx}}{{$rightDiff = $section.GetComputedInlineDiffFor $match ctx.Locale}}{{end}}
|
||||
<td class="lines-num lines-num-old del-code" data-line-num="{{$line.LeftIdx}}"><span rel="diff-{{$file.NameHash}}L{{$line.LeftIdx}}"></span></td>
|
||||
<td class="lines-num lines-num-old del-code" data-line-num="{{$line.LeftIdx}}"><span rel="diff-{{$file.NameHash}}L{{$line.LeftIdx}}" id="diff-{{$file.NameHash}}L{{$line.LeftIdx}}"></span></td>
|
||||
<td class="lines-escape del-code lines-escape-old">{{if $line.LeftIdx}}{{if $leftDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $leftDiff}}"></button>{{end}}{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-old del-code"><span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
|
||||
<td class="lines-code lines-code-old del-code">
|
||||
@ -39,7 +39,7 @@
|
||||
<code class="code-inner"></code>
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="lines-num lines-num-new add-code" data-line-num="{{if $match.RightIdx}}{{$match.RightIdx}}{{end}}"><span rel="{{if $match.RightIdx}}diff-{{$file.NameHash}}R{{$match.RightIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-new add-code" data-line-num="{{if $match.RightIdx}}{{$match.RightIdx}}{{end}}"><span rel="{{if $match.RightIdx}}diff-{{$file.NameHash}}R{{$match.RightIdx}}{{end}}"{{if $match.RightIdx}} id="diff-{{$file.NameHash}}R{{$match.RightIdx}}"{{end}}></span></td>
|
||||
<td class="lines-escape add-code lines-escape-new">{{if $match.RightIdx}}{{if $rightDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $rightDiff}}"></button>{{end}}{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-new add-code">{{if $match.RightIdx}}<span class="tw-font-mono" data-type-marker="{{$match.GetLineTypeMarker}}"></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-new add-code">
|
||||
@ -56,7 +56,7 @@
|
||||
</td>
|
||||
{{else}}
|
||||
{{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$file.NameHash}}L{{$line.LeftIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$file.NameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$file.NameHash}}L{{$line.LeftIdx}}"{{end}}></span></td>
|
||||
<td class="lines-escape lines-escape-old">{{if $line.LeftIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-old">
|
||||
@ -71,7 +71,7 @@
|
||||
<code class="code-inner"></code>
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$file.NameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$file.NameHash}}R{{$line.RightIdx}}{{end}}"{{if $line.RightIdx}} id="diff-{{$file.NameHash}}R{{$line.RightIdx}}"{{end}}></span></td>
|
||||
<td class="lines-escape lines-escape-new">{{if $line.RightIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}<button class="toggle-escape-button btn interact-bg" title="{{template "repo/diff/escape_title" dict "diff" $inlineDiff}}"></button>{{end}}{{end}}</td>
|
||||
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="tw-font-mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
|
||||
<td class="lines-code lines-code-new">
|
||||
|
||||
@ -19,8 +19,8 @@
|
||||
<td colspan="2" class="lines-num"></td>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$file.NameHash}}L{{$line.LeftIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$file.NameHash}}R{{$line.RightIdx}}{{end}}"></span></td>
|
||||
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$file.NameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$file.NameHash}}L{{$line.LeftIdx}}"{{end}}></span></td>
|
||||
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{$file.NameHash}}R{{$line.RightIdx}}{{end}}"{{if $line.RightIdx}} id="diff-{{$file.NameHash}}R{{$line.RightIdx}}"{{end}}></span></td>
|
||||
{{end}}
|
||||
{{$inlineDiff := $section.GetComputedInlineDiffFor $line ctx.Locale -}}
|
||||
<td class="lines-escape">
|
||||
|
||||
@ -985,6 +985,14 @@ td .commit-summary {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff .lines-num[data-line-num] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff .lines-num[data-line-num]:hover {
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff tbody tr .lines-type-marker {
|
||||
width: 10px;
|
||||
min-width: 10px;
|
||||
@ -996,6 +1004,26 @@ td .commit-summary {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff tr.active .lines-num,
|
||||
.repository .diff-file-box .code-diff tr.active .lines-escape,
|
||||
.repository .diff-file-box .code-diff tr.active .lines-type-marker,
|
||||
.repository .diff-file-box .code-diff tr.active .lines-code {
|
||||
background: var(--color-highlight-bg);
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff tr.active .lines-num {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff tr.active .lines-num::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 2px;
|
||||
height: 100%;
|
||||
background: var(--color-highlight-fg);
|
||||
}
|
||||
|
||||
.repository .diff-file-box .code-diff-split .tag-code .lines-code code.code-inner {
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
|
||||
@ -12,6 +12,130 @@ import {invertFileFolding} from './file-fold.ts';
|
||||
import {parseDom, sleep} from '../utils.ts';
|
||||
import {registerGlobalSelectorFunc} from '../modules/observer.ts';
|
||||
|
||||
const diffLineNumberCellSelector = '#diff-file-boxes .code-diff td.lines-num[data-line-num]';
|
||||
const diffAnchorSuffixRegex = /([LR])(\d+)$/;
|
||||
const diffHashRangeRegex = /^(diff-[0-9a-f]+)([LR]\d+)(?:-([LR]\d+))?$/i;
|
||||
|
||||
type DiffAnchorSide = 'L' | 'R';
|
||||
type DiffAnchorInfo = {anchor: string, fragment: string, side: DiffAnchorSide, line: number};
|
||||
type DiffSelectionState = DiffAnchorInfo & {container: HTMLElement};
|
||||
|
||||
let diffSelectionStart: DiffSelectionState | null = null;
|
||||
|
||||
function changeHash(hash: string) {
|
||||
if (window.history.pushState) {
|
||||
window.history.pushState(null, null, hash);
|
||||
} else {
|
||||
window.location.hash = hash;
|
||||
}
|
||||
}
|
||||
|
||||
function parseDiffAnchor(anchor: string | null): DiffAnchorInfo | null {
|
||||
if (!anchor || !anchor.startsWith('diff-')) return null;
|
||||
const suffixMatch = diffAnchorSuffixRegex.exec(anchor);
|
||||
if (!suffixMatch) return null;
|
||||
const line = Number.parseInt(suffixMatch[2]);
|
||||
if (Number.isNaN(line)) return null;
|
||||
const fragment = anchor.slice(0, -suffixMatch[0].length);
|
||||
const side = suffixMatch[1] as DiffAnchorSide;
|
||||
return {anchor, fragment, side, line};
|
||||
}
|
||||
|
||||
function applyDiffLineSelection(container: HTMLElement, fragment: string, side: DiffAnchorSide, startLine: number, endLine: number, options?: {updateHash?: boolean}): boolean {
|
||||
const minLine = Math.min(startLine, endLine);
|
||||
const maxLine = Math.max(startLine, endLine);
|
||||
const selector = `.code-diff td.lines-num span[id^="${CSS.escape(fragment)}"]`;
|
||||
const spans = Array.from(container.querySelectorAll<HTMLSpanElement>(selector));
|
||||
const matches = spans.filter((span) => {
|
||||
const info = parseDiffAnchor(span.id);
|
||||
if (!info || info.side !== side) return false;
|
||||
return info.line >= minLine && info.line <= maxLine;
|
||||
});
|
||||
if (!matches.length) return false;
|
||||
|
||||
for (const tr of document.querySelectorAll('.code-diff tr.active')) {
|
||||
tr.classList.remove('active');
|
||||
}
|
||||
for (const span of matches) {
|
||||
span.closest('tr')?.classList.add('active');
|
||||
}
|
||||
|
||||
if (options?.updateHash !== false) {
|
||||
const startAnchor = `${fragment}${side}${minLine}`;
|
||||
const endAnchor = `${fragment}${side}${maxLine}`;
|
||||
const hashValue = minLine === maxLine ? startAnchor : `${startAnchor}-${endAnchor}`;
|
||||
changeHash(`#${hashValue}`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
type DiffHashRange = {fragment: string, side: DiffAnchorSide, startLine: number, endLine: number};
|
||||
|
||||
function parseDiffHashRange(hashValue: string): DiffHashRange | null {
|
||||
if (!hashValue.startsWith('diff-')) return null;
|
||||
const match = diffHashRangeRegex.exec(hashValue);
|
||||
if (!match) return null;
|
||||
const startInfo = parseDiffAnchor(`${match[1]}${match[2]}`);
|
||||
if (!startInfo) return null;
|
||||
let endLine = startInfo.line;
|
||||
if (match[3]) {
|
||||
const endInfo = parseDiffAnchor(`${match[1]}${match[3]}`);
|
||||
if (!endInfo || endInfo.side !== startInfo.side) {
|
||||
return {fragment: startInfo.fragment, side: startInfo.side, startLine: startInfo.line, endLine: startInfo.line};
|
||||
}
|
||||
endLine = endInfo.line;
|
||||
}
|
||||
return {
|
||||
fragment: startInfo.fragment,
|
||||
side: startInfo.side,
|
||||
startLine: startInfo.line,
|
||||
endLine,
|
||||
};
|
||||
}
|
||||
|
||||
function highlightDiffSelectionFromHash() {
|
||||
const {hash} = window.location;
|
||||
if (!hash || !hash.startsWith('#diff-')) return;
|
||||
const range = parseDiffHashRange(hash.substring(1));
|
||||
if (!range) return;
|
||||
const targetId = `${range.fragment}${range.side}${range.startLine}`;
|
||||
const target = document.querySelector<HTMLElement>(`#${CSS.escape(targetId)}`);
|
||||
if (!target) return;
|
||||
const container = target.closest<HTMLElement>('.diff-file-box');
|
||||
if (!container) return;
|
||||
applyDiffLineSelection(container, range.fragment, range.side, range.startLine, range.endLine, {updateHash: false});
|
||||
diffSelectionStart = null;
|
||||
}
|
||||
|
||||
function handleDiffLineNumberClick(cell: HTMLElement, e: MouseEvent) {
|
||||
const span = cell.querySelector<HTMLSpanElement>('span[id^="diff-"]');
|
||||
const info = parseDiffAnchor(span?.id ?? null);
|
||||
if (!info) return;
|
||||
const container = cell.closest<HTMLElement>('.diff-file-box');
|
||||
if (!container) return;
|
||||
|
||||
let rangeStart: DiffAnchorInfo = info;
|
||||
if (e.shiftKey && diffSelectionStart &&
|
||||
diffSelectionStart.container === container &&
|
||||
diffSelectionStart.fragment === info.fragment &&
|
||||
diffSelectionStart.side === info.side) {
|
||||
rangeStart = diffSelectionStart;
|
||||
}
|
||||
|
||||
if (applyDiffLineSelection(container, rangeStart.fragment, rangeStart.side, rangeStart.line, info.line)) {
|
||||
diffSelectionStart = {...info, container};
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
}
|
||||
|
||||
function initDiffLineSelection() {
|
||||
addDelegatedEventListener<HTMLElement, MouseEvent>(document, 'click', diffLineNumberCellSelector, (cell, e) => {
|
||||
handleDiffLineNumberClick(cell, e);
|
||||
});
|
||||
window.addEventListener('hashchange', highlightDiffSelectionFromHash);
|
||||
highlightDiffSelectionFromHash();
|
||||
}
|
||||
|
||||
function initRepoDiffFileBox(el: HTMLElement) {
|
||||
// switch between "rendered" and "source", for image and CSV files
|
||||
queryElems(el, '.file-view-toggle', (btn) => btn.addEventListener('click', () => {
|
||||
@ -283,6 +407,7 @@ export function initRepoDiffView() {
|
||||
initDiffHeaderPopup();
|
||||
initViewedCheckboxListenerFor();
|
||||
initExpandAndCollapseFilesButton();
|
||||
initDiffLineSelection();
|
||||
initRepoDiffHashChangeListener();
|
||||
|
||||
registerGlobalSelectorFunc('#diff-file-boxes .diff-file-box', initRepoDiffFileBox);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user