mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-31 16:06:49 +00:00
fix: correct full url when using sub-path (#38712)
fix #38708 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
This commit is contained in:
@@ -78,7 +78,7 @@ func (c TemplateContext) CurrentWebBanner() *setting.WebBannerType {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppFullLink returns a full URL link with AppSubURL for the given app link (no AppSubURL)
|
||||
// AppFullLink returns a full URL link with AppSubURL for the given app link
|
||||
// If no link is given, it returns the current app full URL with sub-path but without trailing slash (that's why it is not named as AppURL)
|
||||
func (c TemplateContext) AppFullLink(link ...string) template.URL {
|
||||
s := httplib.GuessCurrentAppURL(c.parentContext())
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
{{/*FIXME: the "HasSourceRenderedToggle" is never set on blame page, it should mean "whether the file is renderable".
|
||||
If the file is renderable, then it must has the "display=source" parameter to make sure the file view page shows the source code, then line number works. */}}
|
||||
{{if $.Permission.CanRead ctx.Consts.RepoUnitTypeIssues}}
|
||||
<a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
<a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.HTMLURL ctx}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
{{end}}
|
||||
<a class="item copy-line-permalink" role="menuitem" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{ctx.Locale.Tr "repo.file_copy_permalink"}}</a>
|
||||
</div>
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
{{svg "octicon-kebab-horizontal"}}
|
||||
</a>
|
||||
<div class="menu">
|
||||
{{$referenceLink := ""}}
|
||||
{{if .issue}}
|
||||
{{$referenceLink = printf "%s#%s" ctx.RootData.Issue.Link .item.HashTag}}
|
||||
{{$issueHTMLURL := ctx.RootData.Issue.HTMLURL ctx}}
|
||||
{{$referenceHTMLURL := ""}}
|
||||
{{if .issue}}{{/* boolean value: is issue */}}
|
||||
{{$referenceHTMLURL = printf "%s#%s" $issueHTMLURL .item.HashTag}}
|
||||
{{else}}
|
||||
{{$referenceLink = printf "%s/files#%s" ctx.RootData.Issue.Link .item.HashTag}}
|
||||
{{$referenceHTMLURL = printf "%s/files#%s" $issueHTMLURL .item.HashTag}}
|
||||
{{end}}
|
||||
<div class="item context js-aria-clickable" data-clipboard-text="{{ctx.AppFullLink}}{{$referenceLink}}">{{ctx.Locale.Tr "repo.issues.context.copy_link"}}</div>
|
||||
<div class="item context js-aria-clickable" data-clipboard-text="{{$referenceHTMLURL}}">{{ctx.Locale.Tr "repo.issues.context.copy_link"}}</div>
|
||||
<div class="item context js-aria-clickable" data-clipboard-target="#{{.item.HashTag}}-raw">{{ctx.Locale.Tr "repo.issues.context.copy_source"}}</div>
|
||||
{{if ctx.RootData.IsSigned}}
|
||||
{{$needDivider := false}}
|
||||
@@ -17,7 +18,7 @@
|
||||
{{$needDivider = true}}
|
||||
<div class="item context js-aria-clickable quote-reply {{if .diff}}quote-reply-diff{{end}}" data-target="{{.item.HashTag}}-raw">{{ctx.Locale.Tr "repo.issues.context.quote_reply"}}</div>
|
||||
{{if not ctx.Consts.RepoUnitTypeIssues.UnitGlobalDisabled}}
|
||||
<div class="item context js-aria-clickable reference-issue" data-target="{{.item.HashTag}}-raw" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-poster-username="{{.item.Poster.Name}}" data-reference="{{$referenceLink}}">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</div>
|
||||
<div class="item context js-aria-clickable reference-issue" data-target="{{.item.HashTag}}-raw" data-modal="#reference-issue-modal" data-poster="{{.item.Poster.GetDisplayName}}" data-poster-username="{{.item.Poster.Name}}" data-reference="{{$referenceHTMLURL}}">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</div>
|
||||
{{end}}
|
||||
{{if or ctx.RootData.Permission.IsAdmin .IsCommentPoster ctx.RootData.HasIssuesOrPullsWritePermission}}
|
||||
<div class="divider"></div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="ui secondary segment tw-font-mono">
|
||||
{{$gitRemoteName := ctx.RootData.SystemConfig.Repository.GitGuideRemoteName.Value ctx}}
|
||||
{{if eq $pull.Flow 0}}
|
||||
<div>git fetch -u {{if ne $pull.HeadRepo.ID $pull.BaseRepo.ID}}{{ctx.AppFullLink $pull.HeadRepo.Link}}{{else}}{{$gitRemoteName}}{{end}} {{$pull.HeadBranch}}:{{$localBranch}}</div>
|
||||
<div>git fetch -u {{if ne $pull.HeadRepo.ID $pull.BaseRepo.ID}}{{$pull.HeadRepo.HTMLURL ctx}}{{else}}{{$gitRemoteName}}{{end}} {{$pull.HeadBranch}}:{{$localBranch}}</div>
|
||||
{{else}}
|
||||
<div>git fetch -u {{$gitRemoteName}} {{$pull.GetGitHeadRefName}}:{{$localBranch}}</div>
|
||||
{{end}}
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
<button class="ui dropdown basic compact jump button tw-px-3" data-tooltip-content="{{ctx.Locale.Tr "repo.more_operations"}}">
|
||||
{{svg "octicon-kebab-horizontal"}}
|
||||
<div class="menu">
|
||||
<a class="item" data-clipboard-text="{{ctx.AppFullLink}}{{.Repository.Link}}/src/commit/{{.CommitID}}/{{PathEscapeSegments .TreePath}}">
|
||||
<a class="item" data-clipboard-text="{{.Repository.HTMLURL ctx}}/src/commit/{{.CommitID}}/{{PathEscapeSegments .TreePath}}">
|
||||
{{svg "octicon-link" 16}}{{ctx.Locale.Tr "repo.file_copy_permalink"}}
|
||||
</a>
|
||||
{{if and (not $.DisableDownloadSourceArchives) $.RefFullName}}
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
|
||||
<div class="code-line-menu tippy-target">
|
||||
{{if $.Permission.CanRead ctx.Consts.RepoUnitTypeIssues}}
|
||||
<a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
<a class="item ref-in-new-issue" role="menuitem" data-url-issue-new="{{.RepoLink}}/issues/new" data-url-param-body-link="{{.Repository.HTMLURL ctx}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}" rel="nofollow noindex">{{ctx.Locale.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
{{end}}
|
||||
<a class="item view_git_blame" role="menuitem" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{ctx.Locale.Tr "repo.view_git_blame"}}</a>
|
||||
<a class="item copy-line-permalink" role="menuitem" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}{{if $.HasSourceRenderedToggle}}?display=source{{end}}">{{ctx.Locale.Tr "repo.file_copy_permalink"}}</a>
|
||||
|
||||
@@ -744,10 +744,9 @@ func TestIssueReferenceURL(t *testing.T) {
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
|
||||
// the "reference" uses relative URLs, then JS code will convert them to absolute URLs for current origin, in case users are using multiple domains
|
||||
ref, _ := htmlDoc.Find(`.timeline-item.comment.issue-content-comment .reference-issue`).Attr("data-reference")
|
||||
assert.Equal(t, "/user2/repo1/issues/1#issue-1", ref)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/issues/1#issue-1", ref)
|
||||
|
||||
ref, _ = htmlDoc.Find(`.timeline-item.comment:not(.issue-content-comment) .reference-issue`).Attr("data-reference")
|
||||
assert.Equal(t, "/user2/repo1/issues/1#issuecomment-2", ref)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/issues/1#issuecomment-2", ref)
|
||||
}
|
||||
|
||||
@@ -580,7 +580,7 @@ func testGeneratedSourceLink(t *testing.T) {
|
||||
|
||||
dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
|
||||
assert.True(t, exists)
|
||||
assert.Equal(t, "/user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
|
||||
assert.Equal(t, setting.AppURL+"user2/repo1/src/commit/65f1bf27bc3bf70f64657658635e66094edbcb4d/README.md?display=source", dataURL)
|
||||
})
|
||||
|
||||
t.Run("Non-Rendered file", func(t *testing.T) {
|
||||
@@ -597,7 +597,7 @@ func testGeneratedSourceLink(t *testing.T) {
|
||||
|
||||
dataURL, exists = doc.doc.Find(".ref-in-new-issue").Attr("data-url-param-body-link")
|
||||
assert.True(t, exists)
|
||||
assert.Equal(t, "/user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
|
||||
assert.Equal(t, setting.AppURL+"user27/repo49/src/commit/aacbdfe9e1c4b47f60abe81849045fa4e96f1d75/test/test.txt", dataURL)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {svg} from '../svg.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {toAbsoluteUrl} from '../utils.ts';
|
||||
import {addDelegatedEventListener} from '../utils/dom.ts';
|
||||
|
||||
function changeHash(hash: string) {
|
||||
@@ -24,7 +23,7 @@ function selectRange(range: string): Element | null {
|
||||
if (!refInNewIssue) return;
|
||||
const urlIssueNew = refInNewIssue.getAttribute('data-url-issue-new');
|
||||
const urlParamBodyLink = refInNewIssue.getAttribute('data-url-param-body-link')!;
|
||||
const issueContent = `${toAbsoluteUrl(urlParamBodyLink)}#${anchor}`; // the default content for issue body
|
||||
const issueContent = `${urlParamBodyLink}#${anchor}`; // the default content for issue body
|
||||
refInNewIssue.setAttribute('href', `${urlIssueNew}?body=${encodeURIComponent(issueContent)}`);
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
} from '../utils/dom.ts';
|
||||
import {setFileFolding} from './file-fold.ts';
|
||||
import {ComboMarkdownEditor, getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
|
||||
import {toAbsoluteUrl} from '../utils.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {initRepoIssueSidebar} from './repo-issue-sidebar.ts';
|
||||
@@ -329,7 +328,7 @@ export function initRepoIssueReferenceIssue() {
|
||||
const target = el.getAttribute('data-target');
|
||||
const content = document.querySelector(`#${target}`)?.textContent ?? '';
|
||||
const poster = el.getAttribute('data-poster-username');
|
||||
const reference = toAbsoluteUrl(el.getAttribute('data-reference')!);
|
||||
const reference = el.getAttribute('data-reference')!;
|
||||
const modalSelector = el.getAttribute('data-modal')!;
|
||||
const modal = document.querySelector(modalSelector)!;
|
||||
const textarea = modal.querySelector<HTMLTextAreaElement>('textarea[name="content"]')!;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
dirname, basename, extname, formatBytes, isObject, stripTags, parseIssueHref,
|
||||
translateMonth, translateDay, blobToDataURI,
|
||||
toAbsoluteUrl, encodeURLEncodedBase64, decodeURLEncodedBase64, isImageFile, isVideoFile, parseRepoOwnerPathInfo,
|
||||
encodeURLEncodedBase64, decodeURLEncodedBase64, isImageFile, isVideoFile, parseRepoOwnerPathInfo,
|
||||
} from './utils.ts';
|
||||
|
||||
test('dirname', () => {
|
||||
@@ -88,16 +88,6 @@ test('blobToDataURI', async () => {
|
||||
expect(await blobToDataURI(blob)).toEqual('data:application/json;base64,eyJ0ZXN0Ijp0cnVlfQ==');
|
||||
});
|
||||
|
||||
test('toAbsoluteUrl', () => {
|
||||
expect(toAbsoluteUrl('//host/dir')).toEqual('http://host/dir');
|
||||
expect(toAbsoluteUrl('https://host/dir')).toEqual('https://host/dir');
|
||||
|
||||
expect(toAbsoluteUrl('')).toEqual('http://localhost:3000');
|
||||
expect(toAbsoluteUrl('/user/repo')).toEqual('http://localhost:3000/user/repo');
|
||||
|
||||
expect(() => toAbsoluteUrl('path')).toThrow('unsupported');
|
||||
});
|
||||
|
||||
test('encodeURLEncodedBase64, decodeURLEncodedBase64', () => {
|
||||
const encoder = new TextEncoder();
|
||||
const uint8array = encoder.encode.bind(encoder);
|
||||
|
||||
@@ -142,19 +142,6 @@ export function convertImage(blob: Blob, mime: string): Promise<Blob> {
|
||||
});
|
||||
}
|
||||
|
||||
export function toAbsoluteUrl(url: string): string {
|
||||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||
return url;
|
||||
}
|
||||
if (url.startsWith('//')) {
|
||||
return `${window.location.protocol}${url}`; // it's also a somewhat absolute URL (with the current scheme)
|
||||
}
|
||||
if (url && !url.startsWith('/')) {
|
||||
throw new Error('unsupported url, it should either start with / or http(s)://');
|
||||
}
|
||||
return `${window.location.origin}${url}`;
|
||||
}
|
||||
|
||||
/** Encode an Uint8Array into a URLEncoded base64 string. */
|
||||
export function encodeURLEncodedBase64(uint8Array: Uint8Array): string {
|
||||
return btoa(Array.from(uint8Array, (byte) => String.fromCharCode(byte)).join(''))
|
||||
|
||||
Reference in New Issue
Block a user