Use link in UI which returned a relative url but not html_url which contains an absolute url (#21986)

partially fix #19345

This PR add some `Link` methods for different objects. The `Link`
methods are not different from `HTMLURL`, they are lack of the absolute
URL. And most of UI `HTMLURL` have been replaced to `Link` so that users
can visit them from a different domain or IP.

This PR also introduces a new javascript configuration
`window.config.reqAppUrl` which is different from `appUrl` which is
still an absolute url but the domain has been replaced to the current
requested domain.
forgejo
Lunny Xiao 1 year ago committed by GitHub
parent 189d5b7045
commit 769be877f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -223,6 +223,49 @@ func (a *Action) GetRepoAbsoluteLink() string {
return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName())
}
// GetCommentHTMLURL returns link to action comment.
func (a *Action) GetCommentHTMLURL() string {
return a.getCommentHTMLURL(db.DefaultContext)
}
func (a *Action) loadComment(ctx context.Context) (err error) {
if a.CommentID == 0 || a.Comment != nil {
return nil
}
a.Comment, err = issues_model.GetCommentByID(ctx, a.CommentID)
return err
}
func (a *Action) getCommentHTMLURL(ctx context.Context) string {
if a == nil {
return "#"
}
_ = a.loadComment(ctx)
if a.Comment != nil {
return a.Comment.HTMLURL()
}
if len(a.GetIssueInfos()) == 0 {
return "#"
}
// Return link to issue
issueIDString := a.GetIssueInfos()[0]
issueID, err := strconv.ParseInt(issueIDString, 10, 64)
if err != nil {
return "#"
}
issue, err := issues_model.GetIssueByID(ctx, issueID)
if err != nil {
return "#"
}
if err = issue.LoadRepo(ctx); err != nil {
return "#"
}
return issue.HTMLURL()
}
// GetCommentLink returns link to action comment.
func (a *Action) GetCommentLink() string {
return a.getCommentLink(db.DefaultContext)
@ -232,11 +275,9 @@ func (a *Action) getCommentLink(ctx context.Context) string {
if a == nil {
return "#"
}
if a.Comment == nil && a.CommentID != 0 {
a.Comment, _ = issues_model.GetCommentByID(ctx, a.CommentID)
}
_ = a.loadComment(ctx)
if a.Comment != nil {
return a.Comment.HTMLURL()
return a.Comment.Link()
}
if len(a.GetIssueInfos()) == 0 {
return "#"
@ -257,7 +298,7 @@ func (a *Action) getCommentLink(ctx context.Context) string {
return "#"
}
return issue.HTMLURL()
return issue.Link()
}
// GetBranch returns the action's repository branch.

@ -36,7 +36,7 @@ func TestAction_GetRepoLink(t *testing.T) {
expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
assert.Equal(t, expected, action.GetRepoLink())
assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink())
assert.Equal(t, comment.HTMLURL(), action.GetCommentLink())
assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL())
}
func TestGetFeeds(t *testing.T) {

@ -459,6 +459,22 @@ func (n *Notification) HTMLURL() string {
return ""
}
// Link formats a relative URL-string to the notification
func (n *Notification) Link() string {
switch n.Source {
case NotificationSourceIssue, NotificationSourcePullRequest:
if n.Comment != nil {
return n.Comment.Link()
}
return n.Issue.Link()
case NotificationSourceCommit:
return n.Repository.Link() + "/commit/" + url.PathEscape(n.CommitID)
case NotificationSourceRepository:
return n.Repository.Link()
}
return ""
}
// APIURL formats a URL-string to the notification
func (n *Notification) APIURL() string {
return setting.AppURL + "api/v1/notifications/threads/" + strconv.FormatInt(n.ID, 10)

@ -391,21 +391,40 @@ func (c *Comment) HTMLURL() string {
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
return c.Issue.HTMLURL() + c.hashLink()
}
// Link formats a relative URL-string to the issue-comment
func (c *Comment) Link() string {
err := c.LoadIssue(db.DefaultContext)
if err != nil { // Silently dropping errors :unamused:
log.Error("LoadIssue(%d): %v", c.IssueID, err)
return ""
}
err = c.Issue.LoadRepo(db.DefaultContext)
if err != nil { // Silently dropping errors :unamused:
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
return c.Issue.Link() + c.hashLink()
}
func (c *Comment) hashLink() string {
if c.Type == CommentTypeCode {
if c.ReviewID == 0 {
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
return "/files#" + c.HashTag()
}
if c.Review == nil {
if err := c.LoadReview(); err != nil {
log.Warn("LoadReview(%d): %v", c.ReviewID, err)
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
return "/files#" + c.HashTag()
}
}
if c.Review.Type <= ReviewTypePending {
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
return "/files#" + c.HashTag()
}
}
return fmt.Sprintf("%s#%s", c.Issue.HTMLURL(), c.HashTag())
return "#" + c.HashTag()
}
// APIURL formats a API-string to the issue-comment
@ -708,8 +727,8 @@ func (c *Comment) UnsignedLine() uint64 {
return uint64(c.Line)
}
// CodeCommentURL returns the url to a comment in code
func (c *Comment) CodeCommentURL() string {
// CodeCommentLink returns the url to a comment in code
func (c *Comment) CodeCommentLink() string {
err := c.LoadIssue(db.DefaultContext)
if err != nil { // Silently dropping errors :unamused:
log.Error("LoadIssue(%d): %v", c.IssueID, err)
@ -720,7 +739,7 @@ func (c *Comment) CodeCommentURL() string {
log.Error("loadRepo(%d): %v", c.Issue.RepoID, err)
return ""
}
return fmt.Sprintf("%s/files#%s", c.Issue.HTMLURL(), c.HashTag())
return fmt.Sprintf("%s/files#%s", c.Issue.Link(), c.HashTag())
}
// LoadPushCommits Load push commits

@ -419,7 +419,7 @@ func (issue *Issue) HTMLURL() string {
return fmt.Sprintf("%s/%s/%d", issue.Repo.HTMLURL(), path, issue.Index)
}
// Link returns the Link URL to this issue.
// Link returns the issue's relative URL.
func (issue *Issue) Link() string {
var path string
if issue.IsPull {

@ -759,8 +759,8 @@ func GetPullRequestsByHeadBranch(ctx context.Context, headBranch string, headRep
return prs, nil
}
// GetBaseBranchHTMLURL returns the HTML URL of the base branch
func (pr *PullRequest) GetBaseBranchHTMLURL() string {
// GetBaseBranchLink returns the relative URL of the base branch
func (pr *PullRequest) GetBaseBranchLink() string {
if err := pr.LoadBaseRepo(db.DefaultContext); err != nil {
log.Error("LoadBaseRepo: %v", err)
return ""
@ -768,11 +768,11 @@ func (pr *PullRequest) GetBaseBranchHTMLURL() string {
if pr.BaseRepo == nil {
return ""
}
return pr.BaseRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
return pr.BaseRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.BaseBranch)
}
// GetHeadBranchHTMLURL returns the HTML URL of the head branch
func (pr *PullRequest) GetHeadBranchHTMLURL() string {
// GetHeadBranchLink returns the relative URL of the head branch
func (pr *PullRequest) GetHeadBranchLink() string {
if pr.Flow == PullRequestFlowAGit {
return ""
}
@ -784,7 +784,7 @@ func (pr *PullRequest) GetHeadBranchHTMLURL() string {
if pr.HeadRepo == nil {
return ""
}
return pr.HeadRepo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
return pr.HeadRepo.Link() + "/src/branch/" + util.PathEscapeSegments(pr.HeadBranch)
}
// UpdateAllowEdits update if PR can be edited from maintainers

@ -65,7 +65,7 @@ type PackageFileDescriptor struct {
// PackageWebLink returns the package web link
func (pd *PackageDescriptor) PackageWebLink() string {
return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
}
// FullWebLink returns the package version web link

@ -116,6 +116,7 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) {
return err
}
// Link returns the project's relative URL.
func (p *Project) Link() string {
if p.OwnerID > 0 {
err := p.LoadOwner(db.DefaultContext)

@ -130,6 +130,11 @@ func (r *Release) HTMLURL() string {
return r.Repo.HTMLURL() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
}
// Link the relative url for a release on the web UI. release must have attributes loaded
func (r *Release) Link() string {
return r.Repo.Link() + "/releases/tag/" + util.PathEscapeSegments(r.TagName)
}
// IsReleaseExist returns true if release with given tag name already exists.
func IsReleaseExist(ctx context.Context, repoID int64, tagName string) (bool, error) {
if len(tagName) == 0 {

@ -480,7 +480,7 @@ func (repo *Repository) RepoPath() string {
return RepoPath(repo.OwnerName, repo.Name)
}
// Link returns the repository link
// Link returns the repository relative url
func (repo *Repository) Link() string {
return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name)
}

@ -63,6 +63,7 @@ type Repository struct {
Language string `json:"language"`
LanguagesURL string `json:"languages_url"`
HTMLURL string `json:"html_url"`
Link string `json:"link"`
SSHURL string `json:"ssh_url"`
CloneURL string `json:"clone_url"`
OriginalURL string `json:"original_url"`

@ -73,7 +73,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio
var content, desc, title string
link := &feeds.Link{Href: act.GetCommentLink()}
link := &feeds.Link{Href: act.GetCommentHTMLURL()}
// title
title = act.ActUser.DisplayName() + " "

@ -339,8 +339,8 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) {
ctx.Data["HeadTarget"] = pull.MustHeadUserName(ctx) + "/" + pull.HeadRepo.Name + ":" + pull.HeadBranch
}
ctx.Data["BaseTarget"] = pull.BaseBranch
ctx.Data["HeadBranchHTMLURL"] = pull.GetHeadBranchHTMLURL()
ctx.Data["BaseBranchHTMLURL"] = pull.GetBaseBranchHTMLURL()
ctx.Data["HeadBranchLink"] = pull.GetHeadBranchLink()
ctx.Data["BaseBranchLink"] = pull.GetBaseBranchLink()
}
// PrepareMergedViewPullInfo show meta information for a merged pull request view page

@ -569,6 +569,7 @@ func SearchRepo(ctx *context.Context) {
Mirror: repo.IsMirror,
Stars: repo.NumStars,
HTMLURL: repo.HTMLURL(),
Link: repo.Link(),
Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
}
}

@ -13,13 +13,13 @@
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
<h4 class="ui top attached normal header">
<span class="file">
<a rel="nofollow" href="{{$repo.HTMLURL}}">{{$repo.FullName}}</a>
<a rel="nofollow" href="{{$repo.Link}}">{{$repo.FullName}}</a>
{{if $repo.IsArchived}}
<span class="ui basic label">{{$.locale.Tr "repo.desc.archived"}}</span>
{{end}}
- {{.Filename}}
</span>
<a class="ui basic tiny button" rel="nofollow" href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
<a class="ui basic tiny button" rel="nofollow" href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{.Filename | PathEscapeSegments}}">{{$.locale.Tr "repo.diff.view_file"}}</a>
</h4>
<div class="ui attached table segment">
<div class="file-body file-code code-view">
@ -28,7 +28,7 @@
<tr>
<td class="lines-num">
{{range .LineNumbers}}
<a href="{{$repo.HTMLURL}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
<a href="{{$repo.Link}}/src/commit/{{$result.CommitID | PathEscape}}/{{$result.Filename | PathEscapeSegments}}#L{{.}}"><span>{{.}}</span></a>
{{end}}
</td>
<td class="lines-code chroma"><code class="code-inner">{{.FormattedLines | Safe}}</code></td>

@ -8,7 +8,7 @@
<title>{{.Subject}}</title>
</head>
{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.HTMLURL) (Escape .Issue.Repo.FullName)}}
{{$repo_url := printf "<a href='%s'>%s</a>" (Escape .Issue.Repo.Link) (Escape .Issue.Repo.FullName)}}
{{$link := printf "<a href='%s'>#%d</a>" (Escape .Link) .Issue.Index}}
<body>
<p>

@ -20,11 +20,11 @@
{{if eq .ActionName "push"}}
<p>
{{if .Comment.IsForcePush}}
{{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.OldCommit}}
{{$oldCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.Link .Comment.OldCommit}}
{{$oldShortSha := ShortSha .Comment.OldCommit}}
{{$oldCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $oldCommitUrl) (Escape $oldShortSha)}}
{{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.HTMLURL .Comment.NewCommit}}
{{$newCommitUrl := printf "%s/commit/%s" .Comment.Issue.PullRequest.BaseRepo.Link .Comment.NewCommit}}
{{$newShortSha := ShortSha .Comment.NewCommit}}
{{$newCommitLink := printf "<a href='%[1]s'><b>%[2]s</b></a>" (Escape $newCommitUrl) (Escape $newShortSha)}}
@ -72,7 +72,7 @@
<ul>
{{range .Comment.Commits}}
<li>
<a href="{{$.Comment.Issue.PullRequest.BaseRepo.HTMLURL}}/commit/{{.ID}}">
<a href="{{$.Comment.Issue.PullRequest.BaseRepo.Link}}/commit/{{.ID}}">
{{ShortSha .ID.String}}
</a> - {{.Summary}}
</li>

@ -11,8 +11,8 @@
</head>
{{$release_url := printf "<a href='%s'>%s</a>" (.Release.HTMLURL | Escape) (.Release.TagName | Escape)}}
{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.HTMLURL | Escape) (.Release.Repo.FullName | Escape)}}
{{$release_url := printf "<a href='%s'>%s</a>" (.Release.Link | Escape) (.Release.TagName | Escape)}}
{{$repo_url := printf "<a href='%s'>%s</a>" (.Release.Repo.Link | Escape) (.Release.Repo.FullName | Escape)}}
<body>
<p>
{{.locale.Tr "mail.release.new.text" .Release.Publisher.Name $release_url $repo_url | Str2html}}

@ -28,7 +28,7 @@
{{$hasRepositoryAccess = index $.RepositoryAccessMap .Repository.ID}}
{{end}}
{{if $hasRepositoryAccess}}
{{$.locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.HTMLURL (.Repository.FullName | Escape) | Safe}}
{{$.locale.Tr "packages.published_by_in" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) .Repository.Link (.Repository.FullName | Escape) | Safe}}
{{else}}
{{$.locale.Tr "packages.published_by" $timeStr .Creator.HomeLink (.Creator.GetDisplayName | Escape) | Safe}}
{{end}}
@ -41,7 +41,7 @@
{{svg "octicon-package" 32}}
<h2>{{.locale.Tr "packages.empty"}}</h2>
{{if and .Repository .CanWritePackages}}
{{$packagesUrl := URLJoin .Owner.HTMLURL "-" "packages"}}
{{$packagesUrl := URLJoin .Owner.HomeLink "-" "packages"}}
<p>{{.locale.Tr "packages.empty.repo" $packagesUrl | Safe}}</p>
{{end}}
<p>{{.locale.Tr "packages.empty.documentation" | Safe}}</p>

@ -11,7 +11,7 @@
<div>
{{$timeStr := TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.locale}}
{{if .HasRepositoryAccess}}
{{.locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.HTMLURL (.PackageDescriptor.Repository.FullName | Escape) | Safe}}
{{.locale.Tr "packages.published_by_in" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) .PackageDescriptor.Repository.Link (.PackageDescriptor.Repository.FullName | Escape) | Safe}}
{{else}}
{{.locale.Tr "packages.published_by" $timeStr .PackageDescriptor.Creator.HomeLink (.PackageDescriptor.Creator.GetDisplayName | Escape) | Safe}}
{{end}}
@ -41,7 +41,7 @@
<div class="ui relaxed list">
<div class="item">{{svg .PackageDescriptor.Package.Type.SVGName 16 "mr-3"}} {{.PackageDescriptor.Package.Type.Name}}</div>
{{if .HasRepositoryAccess}}
<div class="item">{{svg "octicon-repo" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.HTMLURL}}">{{.PackageDescriptor.Repository.FullName}}</a></div>
<div class="item">{{svg "octicon-repo" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.Link}}">{{.PackageDescriptor.Repository.FullName}}</a></div>
{{end}}
<div class="item">{{svg "octicon-calendar" 16 "mr-3"}} {{TimeSinceUnix .PackageDescriptor.Version.CreatedUnix $.locale}}</div>
<div class="item">{{svg "octicon-download" 16 "mr-3"}} {{.PackageDescriptor.Version.DownloadCount}}</div>
@ -91,7 +91,7 @@
<div class="ui divider"></div>
<div class="ui relaxed list">
{{if .HasRepositoryAccess}}
<div class="item">{{svg "octicon-issue-opened" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.HTMLURL}}/issues">{{.locale.Tr "repo.issues"}}</a></div>
<div class="item">{{svg "octicon-issue-opened" 16 "mr-3"}} <a href="{{.PackageDescriptor.Repository.Link}}/issues">{{.locale.Tr "repo.issues"}}</a></div>
{{end}}
{{if .CanWritePackages}}
<div class="item">{{svg "octicon-tools" 16 "mr-3"}} <a href="{{.Link}}/settings">{{.locale.Tr "repo.settings"}}</a></div>

@ -96,13 +96,13 @@
</a>
{{end}}
{{else}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="vm ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
<a href="{{.LatestPullRequest.Issue.Link}}" class="vm ref-issue">{{if not .LatestPullRequest.IsSameRepo}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
{{if .LatestPullRequest.HasMerged}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label purple large label vm">{{svg "octicon-git-merge" 16 "mr-2"}}{{$.locale.Tr "repo.pulls.merged"}}</a>
<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label purple large label vm">{{svg "octicon-git-merge" 16 "mr-2"}}{{$.locale.Tr "repo.pulls.merged"}}</a>
{{else if .LatestPullRequest.Issue.IsClosed}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label red large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.closed_title"}}</a>
<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label red large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.closed_title"}}</a>
{{else}}
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui text-label green large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.open_title"}}</a>
<a href="{{.LatestPullRequest.Issue.Link}}" class="ui text-label green large label vm">{{svg "octicon-git-pull-request" 16 "mr-2"}}{{$.locale.Tr "repo.issues.open_title"}}</a>
{{end}}
{{end}}
</td>

@ -151,7 +151,7 @@
{{end}}
</div>
{{else}}
<table class="chroma" data-new-comment-url="{{$.Issue.HTMLURL}}/files/reviews/new_comment" data-path="{{$file.Name}}">
<table class="chroma" data-new-comment-url="{{$.Issue.Link}}/files/reviews/new_comment" data-path="{{$file.Name}}">
{{if $.IsSplitStyle}}
{{template "repo/diff/section_split" dict "file" . "root" $}}
{{else}}
@ -191,7 +191,7 @@
<div class="ui comment form">
<div class="ui top attached tabular menu">
<a class="active write item">{{$.locale.Tr "write"}}</a>
<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
<a class="preview item" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
</div>
<div class="ui bottom attached active write tab segment">
<textarea class="review-textarea js-quick-submit" tabindex="1" name="content"></textarea>

@ -1,5 +1,5 @@
{{if and $.root.SignedUserID (not $.Repository.IsArchived)}}
<form class="ui form {{if $.hidden}}hide comment-form comment-form-reply{{end}}" action="{{$.root.Issue.HTMLURL}}/files/reviews/comments" method="post">
<form class="ui form {{if $.hidden}}hide comment-form comment-form-reply{{end}}" action="{{$.root.Issue.Link}}/files/reviews/comments" method="post">
{{$.root.CsrfTokenHtml}}
<input type="hidden" name="origin" value="{{if $.root.PageIsPullFiles}}diff{{else}}timeline{{end}}">
<input type="hidden" name="latest_commit_id" value="{{$.root.AfterCommitID}}"/>
@ -11,7 +11,7 @@
<input type="hidden" name="diff_base_cid">
<div class="ui top tabular menu" data-write="write" data-preview="preview">
<a class="active item" data-tab="write">{{$.root.locale.Tr "write"}}</a>
<a class="item" data-tab="preview" data-url="{{$.root.Repository.HTMLURL}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.locale.Tr "preview"}}</a>
<a class="item" data-tab="preview" data-url="{{$.root.Repository.Link}}/markdown" data-context="{{$.root.RepoLink}}">{{$.root.locale.Tr "preview"}}</a>
</div>
<div class="field">
<div class="ui active tab" data-tab="write">

@ -31,13 +31,13 @@
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
<a class="active item" data-tab="write">{{svg "octicon-code"}} {{if .IsNewFile}}{{.locale.Tr "repo.editor.new_file"}}{{else}}{{.locale.Tr "repo.editor.edit_file"}}{{end}}</a>
{{if not .IsNewFile}}
<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.locale.Tr "preview"}}</a>
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL}}" data-preview-file-modes="{{.PreviewableFileModes}}" data-markdown-mode="gfm">{{svg "octicon-eye"}} {{.locale.Tr "preview"}}</a>
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | PathEscapeSegments}}/{{.TreePath | PathEscapeSegments}}" data-context="{{.BranchLink}}">{{svg "octicon-diff"}} {{.locale.Tr "repo.editor.preview_changes"}}</a>
{{end}}
</div>
<div class="ui bottom attached active tab segment" data-tab="write">
<textarea id="edit_area" name="content" class="hide" data-id="repo-{{.Repository.Name}}-{{.TreePath}}"
data-url="{{.Repository.HTMLURL}}/markdown"
data-url="{{.Repository.Link}}/markdown"
data-context="{{.RepoLink}}"
data-markdown-file-exts="{{.MarkdownFileExts}}"
data-line-wrap-extensions="{{.LineWrapExtensions}}">

@ -217,7 +217,7 @@
{{end}}
{{if or (.Permission.CanRead $.UnitTypeWiki) (.Permission.CanRead $.UnitTypeExternalWiki)}}
<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.HTMLURL)))}} target="_blank" rel="noopener noreferrer" {{end}}>
<a class="{{if .PageIsWiki}}active {{end}}item" href="{{.RepoLink}}/wiki" {{if and (.Permission.CanRead $.UnitTypeExternalWiki) (not (HasPrefix ((.Repository.MustGetUnit $.Context $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL) (.Repository.Link)))}} target="_blank" rel="noopener noreferrer" {{end}}>
{{svg "octicon-book"}} {{.locale.Tr "repo.wiki"}}
</a>
{{end}}

@ -16,11 +16,11 @@
{{else}}
<div class="ui top tabular menu" data-write="write" data-preview="preview">
<a class="active item" data-tab="write">{{.locale.Tr "write"}}</a>
<a class="item" data-tab="preview" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{.locale.Tr "preview"}}</a>
<a class="item" data-tab="preview" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}">{{.locale.Tr "preview"}}</a>
</div>
<div class="field">
<div class="ui bottom active tab" data-tab="write">
<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.Repo.RepoLink}}">
<textarea id="content" class="edit_area js-quick-submit" name="content" tabindex="4" data-id="issue-{{.RepoName}}" data-url="{{.Repository.Link}}/markdown" data-context="{{.Repo.RepoLink}}">
{{- if .BodyQuery}}{{.BodyQuery}}{{else if .IssueTemplate}}{{.IssueTemplate}}{{else if .PullRequestTemplate}}{{.PullRequestTemplate}}{{else}}{{.content}}{{end -}}
</textarea>
</div>

@ -198,7 +198,7 @@
<div class="ui comment form">
<div class="ui top tabular menu">
<a class="active write item">{{$.locale.Tr "write"}}</a>
<a class="preview item" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
<a class="preview item" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
</div>
<div class="field">
<div class="ui bottom active tab write">

@ -123,7 +123,7 @@
{{template "shared/user/avatarlink" .Poster}}
<span class="text grey muted-links">
{{template "shared/user/authorlink" .Poster}}
{{$link := printf "%s/commit/%s" $.Repository.HTMLURL ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
{{$link := printf "%s/commit/%s" $.Repository.Link ($.Issue.PullRequest.MergedCommitID|PathEscape)}}
{{if eq $.Issue.PullRequest.Status 3}}
{{$.locale.Tr "repo.issues.manually_pull_merged_at" ($link|Escape) (ShortSha $.Issue.PullRequest.MergedCommitID) ($.BaseTarget|Escape) $createdStr | Str2html}}
{{else}}
@ -329,7 +329,7 @@
<div class="detail">
{{svg "octicon-plus"}}
<span class="text grey muted-links">
<a href="{{.DependentIssue.HTMLURL}}">
<a href="{{.DependentIssue.Link}}">
{{if eq .DependentIssue.RepoID .Issue.RepoID}}
#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
{{else}}
@ -352,7 +352,7 @@
<div class="detail">
<span class="text grey muted-links">{{svg "octicon-trash"}}</span>
<span class="text grey muted-links">
<a href="{{.DependentIssue.HTMLURL}}">
<a href="{{.DependentIssue.Link}}">
{{if eq .DependentIssue.RepoID .Issue.RepoID}}
#{{.DependentIssue.Index}} {{.DependentIssue.Title}}
{{else}}
@ -476,7 +476,7 @@
{{$resolveDoer := (index $comms 0).ResolveDoer}}
{{$isNotPending := (not (eq (index $comms 0).Review.Type 0))}}
<div class="df ac">
<a href="{{(index $comms 0).CodeCommentURL}}" class="file-comment ml-3 word-break">{{$filename}}</a>
<a href="{{(index $comms 0).CodeCommentLink}}" class="file-comment ml-3 word-break">{{$filename}}</a>
{{if $invalid}}
<span class="ui label basic small ml-3">
{{$.locale.Tr "repo.issues.review.outdated"}}

@ -6,11 +6,11 @@
<div class="menu">
{{$referenceUrl := ""}}
{{if .issue}}
{{$referenceUrl = Printf "%s#%s" .ctx.Issue.HTMLURL .item.HashTag}}
{{$referenceUrl = Printf "%s#%s" .ctx.Issue.Link .item.HashTag}}
{{else}}
{{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.HTMLURL .item.HashTag}}
{{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.Link .item.HashTag}}
{{end}}
<div class="item context" data-clipboard-text="{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.copy_link"}}</div>
<div class="item context" data-clipboard-text-type="url" data-clipboard-text="{{AppSubUrl}}{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.copy_link"}}</div>
<div class="item context 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.UnitIssuesGlobalDisabled}}
<div class="item context 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="{{$referenceUrl}}">{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}</div>

@ -133,7 +133,7 @@
{{if .Issue.PullRequest.HasMerged}}
<div class="item text">
{{if .Issue.PullRequest.MergedCommitID}}
{{$link := printf "%s/commit/%s" $.Repository.HTMLURL (.Issue.PullRequest.MergedCommitID|PathEscape)}}
{{$link := printf "%s/commit/%s" $.Repository.Link (.Issue.PullRequest.MergedCommitID|PathEscape)}}
{{if eq $.Issue.PullRequest.Status 3}}
{{$.locale.Tr "repo.pulls.manually_merged_as" ($link|Escape) (ShortSha .Issue.PullRequest.MergedCommitID) | Safe}}
{{else}}

@ -35,13 +35,13 @@
{{if .Issue.IsPull}}
{{$headHref := .HeadTarget|Escape}}
{{if .HeadBranchHTMLURL}}
{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchHTMLURL | Escape) $headHref}}
{{if .HeadBranchLink}}
{{$headHref = printf "<a href=\"%s\">%s</a>" (.HeadBranchLink | Escape) $headHref}}
{{end}}
{{$headHref = printf "%s <a class=\"tooltip\" data-content=\"%s\" data-clipboard-text=\"%s\">%s</a>" $headHref (.locale.Tr "copy_branch") (.HeadTarget | Escape) (svg "octicon-copy" 14)}}
{{$baseHref := .BaseTarget|Escape}}
{{if .BaseBranchHTMLURL}}
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchHTMLURL | Escape) $baseHref}}
{{if .BaseBranchLink}}
{{$baseHref = printf "<a href=\"%s\">%s</a>" (.BaseBranchLink | Escape) $baseHref}}
{{end}}
{{if .Issue.PullRequest.HasMerged}}
{{$mergedStr:= TimeSinceUnix .Issue.PullRequest.MergedUnix $.locale}}

@ -242,7 +242,7 @@
{{end}}
<div class="right floated">
{{range .Assignees}}
<a class="tooltip" target="_blank" href="{{.HTMLURL}}" data-content="{{$.locale.Tr "repo.projects.board.assigned_to"}} {{.Name}}">{{avatar . 28 "mini mr-3"}}</a>
<a class="tooltip" target="_blank" href="{{.HomeLink}}" data-content="{{$.locale.Tr "repo.projects.board.assigned_to"}} {{.Name}}">{{avatar . 28 "mini mr-3"}}</a>
{{end}}
</div>
</div>

@ -48,7 +48,7 @@
<label>{{.locale.Tr "repo.release.content"}}</label>
<div class="ui top tabular menu" data-write="write" data-preview="preview">
<a class="active write item" data-tab="write">{{$.locale.Tr "write"}}</a>
<a class="preview item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
<a class="preview item" data-tab="preview" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
</div>
<div class="ui bottom active tab" data-tab="write">
<textarea name="content">{{.content}}</textarea>

@ -110,10 +110,11 @@
</table>
<div class="code-line-menu ui vertical pointing menu tippy-target">
{{if $.Permission.CanRead $.UnitTypeIssues}}
{{/* FIXME: Here we use HTMLURL but not link, see https://github.com/go-gitea/gitea/pull/21986/files#r1096532186*/}}
<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/"}}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" rel="nofollow noindex">{{.locale.Tr "repo.issues.context.reference_issue"}}</a>
{{end}}
<a class="item view_git_blame" href="{{.Repository.HTMLURL}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.view_git_blame"}}</a>
<a class="item copy-line-permalink" data-url="{{.Repository.HTMLURL}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
<a class="item view_git_blame" href="{{.Repository.Link}}/blame/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.view_git_blame"}}</a>
<a class="item copy-line-permalink" data-url="{{.Repository.Link}}/src/commit/{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.locale.Tr "repo.file_copy_permalink"}}</a>
</div>
{{end}}
{{end}}

@ -21,11 +21,11 @@
</div>
<div class="ui top attached tabular menu previewtabs" data-write="write" data-preview="preview">
<a class="active item" data-tab="write">{{.locale.Tr "write"}}</a>
<a class="item" data-tab="preview" data-url="{{$.Repository.HTMLURL}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
<a class="item" data-tab="preview" data-url="{{$.Repository.Link}}/markdown" data-context="{{$.RepoLink}}">{{$.locale.Tr "preview"}}</a>
</div>
<div class="field content" data-loading="{{.locale.Tr "loading"}}">
<div class="ui bottom active tab" data-tab="write">
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.HTMLURL}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.locale.Tr "repo.wiki.welcome"}}{{end}}</textarea>
<textarea class="js-quick-submit" id="edit_area" name="content" data-id="wiki-{{.title}}" data-url="{{.Repository.Link}}/markdown" data-context="{{.RepoLink}}">{{if .PageIsWikiEdit}}{{.content}}{{else}}{{.locale.Tr "repo.wiki.welcome"}}{{end}}</textarea>
</div>
</div>
<div class="field">

@ -34,7 +34,7 @@
</div>
<div class="issue-item-main f1 fc df">
<div class="issue-item-top-row">
<a class="title tdn issue-title" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a>
<a class="title tdn issue-title" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">{{RenderEmoji .Title | RenderCodeBlock}}</a>
{{if .IsPull}}
{{if (index $.CommitStatuses .PullRequest.ID)}}
{{template "repo/commit_statuses" dict "Status" (index $.CommitLastStatus .PullRequest.ID) "Statuses" (index $.CommitStatuses .PullRequest.ID) "root" $}}
@ -47,7 +47,7 @@
</span>
</div>
<div class="desc issue-item-bottom-row df ac fw my-1">
<a class="index ml-0 mr-2" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
<a class="index ml-0 mr-2" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
{{if eq $.listType "dashboard"}}
{{.Repo.FullName}}#{{.Index}}
{{else}}
@ -65,7 +65,7 @@
{{if .IsPull}}
<div class="branches df ac">
<div class="branch">
<a href="{{.PullRequest.BaseRepo.HTMLURL}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
<a href="{{.PullRequest.BaseRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.BaseBranch}}">
{{/* inline to remove the spaces between spans */}}
{{if ne .RepoID .PullRequest.BaseRepoID}}<span class="truncated-name">{{.PullRequest.BaseRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.BaseBranch}}</span>
</a>
@ -73,7 +73,7 @@
{{svg "gitea-double-chevron-left" 12 "mx-1"}}
{{if .PullRequest.HeadRepo}}
<div class="branch">
<a href="{{.PullRequest.HeadRepo.HTMLURL}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
<a href="{{.PullRequest.HeadRepo.Link}}/src/branch/{{PathEscapeSegments .PullRequest.HeadBranch}}">
{{/* inline to remove the spaces between spans */}}
{{if ne .RepoID .PullRequest.HeadRepoID}}<span class="truncated-name">{{.PullRequest.HeadRepo.OwnerName}}</span>:{{end}}<span class="truncated-name">{{.PullRequest.HeadBranch}}</span>
</a>
@ -159,7 +159,7 @@
</div>
<div class="issue-item-icon-right text grey">
{{if .NumComments}}
<a class="tdn muted" href="{{if .HTMLURL}}{{.HTMLURL}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
<a class="tdn muted" href="{{if .Link}}{{.Link}}{{else}}{{$.Link}}/{{.Index}}{{end}}">
{{svg "octicon-comment" 16 "mr-2"}}{{.NumComments}}
</a>
{{end}}

@ -19098,6 +19098,10 @@
"type": "string",
"x-go-name": "LanguagesURL"
},
"link": {
"type": "string",
"x-go-name": "Link"
},
"mirror": {
"type": "boolean",
"x-go-name": "Mirror"

@ -127,7 +127,7 @@
<div v-if="repos.length" class="ui attached table segment rounded-bottom">
<ul class="repo-owner-name-list">
<li v-for="repo in repos" :class="{'private': repo.private || repo.internal}">
<a class="repo-list-link df ac sb" :href="repo.html_url">
<a class="repo-list-link df ac sb" :href="repo.link">
<div class="item-name df ac f1 mr-2">
<component v-bind:is="repoIcon(repo)" size="16" class="mr-2"></component>
<div class="text bold truncate ml-1">${repo.full_name}</div>

@ -35,7 +35,7 @@
{{$issue := .Issue}}
{{$repo := .Repository}}
<tr id="notification_{{.ID}}">
<td class="collapsing" data-href="{{.HTMLURL}}">
<td class="collapsing" data-href="{{.Link}}">
{{if eq .Status 3}}
<span class="blue">{{svg "octicon-pin"}}</span>
{{else if not $issue}}
@ -58,8 +58,8 @@
{{end}}
{{end}}
</td>
<td class="eleven wide" data-href="{{.HTMLURL}}">
<a class="item" href="{{.HTMLURL}}">
<td class="eleven wide" data-href="{{.Link}}">
<a class="item" href="{{.Link}}">
{{if $issue}}
#{{$issue.Index}} - {{$issue.Title}}
{{else}}

@ -1,4 +1,5 @@
import {showTemporaryTooltip} from '../modules/tippy.js';
import {toAbsoluteUrl} from '../utils.js';
const {copy_success, copy_error} = window.config.i18n;
@ -50,7 +51,11 @@ export function initGlobalCopyToClipboardListener() {
// in case <button data-clipboard-text><svg></button>, so we just search
// up to 3 levels for performance
for (let i = 0; i < 3 && target; i++) {
const text = target.getAttribute('data-clipboard-text') || document.querySelector(target.getAttribute('data-clipboard-target'))?.value;
let txt = target.getAttribute('data-clipboard-text');
if (txt && target.getAttribute('data-clipboard-text-type') === 'url') {
txt = toAbsoluteUrl(txt);
}
const text = txt || document.querySelector(target.getAttribute('data-clipboard-target'))?.value;
if (text) {
e.preventDefault();

@ -2,4 +2,5 @@ window.config = {
csrfToken: 'test-csrf-token-123456',
pageData: {},
i18n: {},
appSubUrl: '',
};

@ -133,3 +133,10 @@ export function convertImage(blob, mime) {
}
});
}
export function toAbsoluteUrl(relUrl) {
if (relUrl.startsWith('http://') || relUrl.startsWith('https://')) {
return relUrl;
}
return `${window.location.origin}${relUrl}`;
}

@ -2,6 +2,7 @@ import {expect, test} from 'vitest';
import {
basename, extname, isObject, uniq, stripTags, joinPaths, parseIssueHref,
prettyNumber, parseUrl, translateMonth, translateDay, blobToDataURI,
toAbsoluteUrl,
} from './utils.js';
test('basename', () => {
@ -136,3 +137,8 @@ test('blobToDataURI', async () => {
const blob = new Blob([JSON.stringify({test: true})], {type: 'application/json'});
expect(await blobToDataURI(blob)).toEqual('data:application/json;base64,eyJ0ZXN0Ijp0cnVlfQ==');
});
test('toAbsoluteUrl', () => {
expect(toAbsoluteUrl('')).toEqual('http://localhost:3000');
expect(toAbsoluteUrl('/user/repo')).toEqual('http://localhost:3000/user/repo');
});

Loading…
Cancel
Save