mirror of
https://github.com/go-gitea/gitea.git
synced 2025-03-12 04:58:21 +03:00
move view-as dropdown to sidebar
This commit is contained in:
parent
0202a09105
commit
93e7a010c3
@ -272,8 +272,16 @@ func isQueryParamEmpty(v any) bool {
|
||||
// It omits the nil, false, zero int/int64 and empty string values,
|
||||
// because they are default empty values for "ctx.FormXxx" calls.
|
||||
// If 0 or false need to be included, use string values: "0" and "false".
|
||||
// Build rules:
|
||||
// * Even parameters: always build as query string: a=b&c=d
|
||||
// * Odd parameters:
|
||||
// * * {"/anything", param-pairs...} => "/?param-paris"
|
||||
// * * {"anything?old-params", new-param-pairs...} => "anything?old-params&new-param-paris"
|
||||
// * * Otherwise: {"old¶ms", new-param-pairs...} => "old¶ms&new-param-paris"
|
||||
// * * Other behaviors are undefined yet.
|
||||
func QueryBuild(a ...any) template.URL {
|
||||
var reqPath, s string
|
||||
hasTrailingSep := false
|
||||
if len(a)%2 == 1 {
|
||||
if v, ok := a[0].(string); ok {
|
||||
s = v
|
||||
@ -282,9 +290,15 @@ func QueryBuild(a ...any) template.URL {
|
||||
} else {
|
||||
panic("QueryBuild: invalid argument")
|
||||
}
|
||||
if s1, s2, ok := strings.Cut(s, "?"); ok {
|
||||
reqPath = s1 + "?"
|
||||
s = s2
|
||||
hasTrailingSep = s != "&" && strings.HasSuffix(s, "&")
|
||||
if strings.HasPrefix(s, "/") || strings.Contains(s, "?") {
|
||||
if s1, s2, ok := strings.Cut(s, "?"); ok {
|
||||
reqPath = s1 + "?"
|
||||
s = s2
|
||||
} else {
|
||||
reqPath += s + "?"
|
||||
s = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := len(a) % 2; i < len(a); i += 2 {
|
||||
@ -327,11 +341,21 @@ func QueryBuild(a ...any) template.URL {
|
||||
s = s[:pos1] + s[pos2:]
|
||||
}
|
||||
}
|
||||
if s != "" && s != "&" && s[len(s)-1] == '&' {
|
||||
if s != "" && s[len(s)-1] == '&' && !hasTrailingSep {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
if reqPath != "" {
|
||||
s = reqPath + s
|
||||
if s == "" {
|
||||
s = reqPath
|
||||
if s != "?" {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
} else {
|
||||
if s[0] == '&' {
|
||||
s = s[1:]
|
||||
}
|
||||
s = reqPath + s
|
||||
}
|
||||
}
|
||||
return template.URL(s)
|
||||
}
|
||||
|
@ -124,29 +124,48 @@ func TestQueryBuild(t *testing.T) {
|
||||
assert.Equal(t, "", string(QueryBuild()))
|
||||
assert.Equal(t, "", string(QueryBuild("a", nil, "b", false, "c", 0, "d", "")))
|
||||
assert.Equal(t, "a=1&b=true", string(QueryBuild("a", 1, "b", "true")))
|
||||
|
||||
// path with query parameters
|
||||
assert.Equal(t, "/?k=1", string(QueryBuild("/", "k", 1)))
|
||||
assert.Equal(t, "/", string(QueryBuild("/?k=a", "k", 0)))
|
||||
|
||||
// no path but question mark with query parameters
|
||||
assert.Equal(t, "?k=1", string(QueryBuild("?", "k", 1)))
|
||||
assert.Equal(t, "path?a=b&k=1", string(QueryBuild("path?a=b", "k", 1)))
|
||||
assert.Equal(t, "?", string(QueryBuild("?", "k", 0)))
|
||||
assert.Equal(t, "path?k=1", string(QueryBuild("path?", "k", 1)))
|
||||
assert.Equal(t, "path", string(QueryBuild("path?", "k", 0)))
|
||||
|
||||
// only query parameters
|
||||
assert.Equal(t, "&k=1", string(QueryBuild("&", "k", 1)))
|
||||
assert.Equal(t, "&a=b&k=1", string(QueryBuild("&a=b", "k", 1)))
|
||||
assert.Equal(t, "", string(QueryBuild("&", "k", 0)))
|
||||
assert.Equal(t, "", string(QueryBuild("&k=a", "k", 0)))
|
||||
assert.Equal(t, "", string(QueryBuild("k=a&", "k", 0)))
|
||||
assert.Equal(t, "a=1&b=2", string(QueryBuild("a=1", "b", 2)))
|
||||
assert.Equal(t, "&a=1&b=2", string(QueryBuild("&a=1", "b", 2)))
|
||||
assert.Equal(t, "a=1&b=2&", string(QueryBuild("a=1&", "b", 2)))
|
||||
})
|
||||
|
||||
t.Run("replace", func(t *testing.T) {
|
||||
assert.Equal(t, "a=1&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", 1)))
|
||||
assert.Equal(t, "a=b&c=1&e=f", string(QueryBuild("a=b&c=d&e=f", "c", 1)))
|
||||
assert.Equal(t, "a=b&c=d&e=1", string(QueryBuild("a=b&c=d&e=f", "e", 1)))
|
||||
assert.Equal(t, "a=b&c=d&e=f&k=1", string(QueryBuild("a=b&c=d&e=f", "k", 1)))
|
||||
})
|
||||
|
||||
t.Run("replace-&", func(t *testing.T) {
|
||||
assert.Equal(t, "&a=1&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", 1)))
|
||||
assert.Equal(t, "&a=b&c=1&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", 1)))
|
||||
assert.Equal(t, "&a=b&c=d&e=1", string(QueryBuild("&a=b&c=d&e=f", "e", 1)))
|
||||
assert.Equal(t, "&a=b&c=d&e=f&k=1", string(QueryBuild("&a=b&c=d&e=f", "k", 1)))
|
||||
})
|
||||
|
||||
t.Run("delete", func(t *testing.T) {
|
||||
assert.Equal(t, "c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", "")))
|
||||
assert.Equal(t, "a=b&e=f", string(QueryBuild("a=b&c=d&e=f", "c", "")))
|
||||
assert.Equal(t, "a=b&c=d", string(QueryBuild("a=b&c=d&e=f", "e", "")))
|
||||
assert.Equal(t, "a=b&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "k", "")))
|
||||
})
|
||||
|
||||
t.Run("delete-&", func(t *testing.T) {
|
||||
assert.Equal(t, "&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", "")))
|
||||
assert.Equal(t, "&a=b&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", "")))
|
||||
|
@ -2864,6 +2864,9 @@ teams.invite.title = You have been invited to join team <strong>%s</strong> in o
|
||||
teams.invite.by = Invited by %s
|
||||
teams.invite.description = Please click the button below to join the team.
|
||||
|
||||
view_as_public_hint = You are viewing the README a public user.
|
||||
view_as_member_hint = You are viewing the README a member of this organization.
|
||||
|
||||
[admin]
|
||||
maintenance = Maintenance
|
||||
dashboard = Dashboard
|
||||
|
@ -5,27 +5,6 @@
|
||||
<div class="ui container">
|
||||
<div class="ui mobile reversed stackable grid">
|
||||
<div class="ui {{if .ShowMemberAndTeamTab}}eleven wide{{end}} column">
|
||||
{{if or .ProfileReadmeContent}}
|
||||
{{if and .ShowMemberAndTeamTab .HasPublicProfileReadme .HasPrivateProfileReadme}}
|
||||
<div class="ui small secondary filter menu">
|
||||
<div id="org-home-view-as-dropdown" class="item ui small dropdown jump">
|
||||
<span class="text">
|
||||
{{svg "octicon-eye" 14}}
|
||||
View as: {{if not .IsViewerMember}}{{ctx.Locale.Tr "settings.visibility.public"}}{{else}}{{ctx.Locale.Tr "org.members.member"}}{{end}}
|
||||
</span>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
<a href="{{QueryBuild $.CurrentURL "view_as" "public"}}" class="item {{if not .IsViewerMember}}selected{{end}}">
|
||||
{{svg "octicon-check" 14 (Iif (not .IsViewerMember) "" "tw-invisible")}} {{ctx.Locale.Tr "settings.visibility.public"}}
|
||||
</a>
|
||||
<a href="{{QueryBuild $.CurrentURL "view_as" "member"}}" class="item {{if .IsViewerMember}}selected{{end}}">
|
||||
{{svg "octicon-check" 14 (Iif .IsViewerMember "" "tw-invisible")}} {{ctx.Locale.Tr "org.members.member"}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{if .ProfileReadmeContent}}
|
||||
<div id="readme_profile" class="markup">{{.ProfileReadmeContent}}</div>
|
||||
{{end}}
|
||||
@ -45,6 +24,31 @@
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
{{end}}
|
||||
|
||||
{{if and .ShowMemberAndTeamTab .HasPublicProfileReadme .HasPrivateProfileReadme}}
|
||||
<div class="tw-my-4">
|
||||
<div id="org-home-view-as-dropdown" class="ui dropdown jump">
|
||||
<span class="text">
|
||||
{{svg "octicon-eye"}}
|
||||
View as: {{if not .IsViewerMember}}{{ctx.Locale.Tr "settings.visibility.public"}}{{else}}{{ctx.Locale.Tr "org.members.member"}}{{end}}
|
||||
</span>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
{{/* TODO: does it really need to use CurrentURL with query parameters? Why not construct a new link with clear parameters */}}
|
||||
<a href="{{QueryBuild $.CurrentURL "view_as" "public"}}" class="item {{if not .IsViewerMember}}selected{{end}}">
|
||||
{{svg "octicon-check" 14 (Iif (not .IsViewerMember) "" "tw-invisible")}} {{ctx.Locale.Tr "settings.visibility.public"}}
|
||||
</a>
|
||||
<a href="{{QueryBuild $.CurrentURL "view_as" "member"}}" class="item {{if .IsViewerMember}}selected{{end}}">
|
||||
{{svg "octicon-check" 14 (Iif .IsViewerMember "" "tw-invisible")}} {{ctx.Locale.Tr "org.members.member"}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tw-my-2">
|
||||
{{if .IsViewerMember}}{{ctx.Locale.Tr "org.view_as_member_hint"}}{{else}}{{ctx.Locale.Tr "org.view_as_public_hint"}}{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if .NumMembers}}
|
||||
<h4 class="ui top attached header tw-flex">
|
||||
<strong class="tw-flex-1">{{ctx.Locale.Tr "org.members"}}</strong>
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package integration
|
||||
|
Loading…
x
Reference in New Issue
Block a user