mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-14 07:20:44 +00:00
Merge branch 'main' into feat/add-oauth-management-to-api-for-iac-tooling
This commit is contained in:
commit
cf3d746afc
@ -81,6 +81,10 @@ var microcmdUserCreate = &cli.Command{
|
||||
Name: "restricted",
|
||||
Usage: "Make a restricted user account",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "fullname",
|
||||
Usage: `The full, human-readable name of the user`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -191,6 +195,7 @@ func runCreateUser(c *cli.Context) error {
|
||||
Passwd: password,
|
||||
MustChangePassword: mustChangePassword,
|
||||
Visibility: visibility,
|
||||
FullName: c.String("fullname"),
|
||||
}
|
||||
|
||||
overwriteDefault := &user_model.CreateUserOverwriteOptions{
|
||||
|
@ -50,17 +50,17 @@ func TestAdminUserCreate(t *testing.T) {
|
||||
assert.Equal(t, check{IsAdmin: false, MustChangePassword: false}, createCheck("u5", "--must-change-password=false"))
|
||||
})
|
||||
|
||||
createUser := func(name, args string) error {
|
||||
return app.Run(strings.Fields(fmt.Sprintf("./gitea admin user create --username %s --email %s@gitea.local %s", name, name, args)))
|
||||
createUser := func(name string, args ...string) error {
|
||||
return app.Run(append([]string{"./gitea", "admin", "user", "create", "--username", name, "--email", name + "@gitea.local"}, args...))
|
||||
}
|
||||
|
||||
t.Run("UserType", func(t *testing.T) {
|
||||
reset()
|
||||
assert.ErrorContains(t, createUser("u", "--user-type invalid"), "invalid user type")
|
||||
assert.ErrorContains(t, createUser("u", "--user-type bot --password 123"), "can only be set for individual users")
|
||||
assert.ErrorContains(t, createUser("u", "--user-type bot --must-change-password"), "can only be set for individual users")
|
||||
assert.ErrorContains(t, createUser("u", "--user-type", "invalid"), "invalid user type")
|
||||
assert.ErrorContains(t, createUser("u", "--user-type", "bot", "--password", "123"), "can only be set for individual users")
|
||||
assert.ErrorContains(t, createUser("u", "--user-type", "bot", "--must-change-password"), "can only be set for individual users")
|
||||
|
||||
assert.NoError(t, createUser("u", "--user-type bot"))
|
||||
assert.NoError(t, createUser("u", "--user-type", "bot"))
|
||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u"})
|
||||
assert.Equal(t, user_model.UserTypeBot, u.Type)
|
||||
assert.Empty(t, u.Passwd)
|
||||
@ -75,7 +75,7 @@ func TestAdminUserCreate(t *testing.T) {
|
||||
|
||||
// using "--access-token" only means "all" access
|
||||
reset()
|
||||
assert.NoError(t, createUser("u", "--random-password --access-token"))
|
||||
assert.NoError(t, createUser("u", "--random-password", "--access-token"))
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
|
||||
accessToken := unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "gitea-admin"})
|
||||
@ -85,7 +85,7 @@ func TestAdminUserCreate(t *testing.T) {
|
||||
|
||||
// using "--access-token" with name & scopes
|
||||
reset()
|
||||
assert.NoError(t, createUser("u", "--random-password --access-token --access-token-name new-token-name --access-token-scopes read:issue,read:user"))
|
||||
assert.NoError(t, createUser("u", "--random-password", "--access-token", "--access-token-name", "new-token-name", "--access-token-scopes", "read:issue,read:user"))
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &user_model.User{}))
|
||||
assert.Equal(t, 1, unittest.GetCount(t, &auth_model.AccessToken{}))
|
||||
accessToken = unittest.AssertExistsAndLoadBean(t, &auth_model.AccessToken{Name: "new-token-name"})
|
||||
@ -98,23 +98,38 @@ func TestAdminUserCreate(t *testing.T) {
|
||||
|
||||
// using "--access-token-name" without "--access-token"
|
||||
reset()
|
||||
err = createUser("u", "--random-password --access-token-name new-token-name")
|
||||
err = createUser("u", "--random-password", "--access-token-name", "new-token-name")
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
|
||||
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
|
||||
|
||||
// using "--access-token-scopes" without "--access-token"
|
||||
reset()
|
||||
err = createUser("u", "--random-password --access-token-scopes read:issue")
|
||||
err = createUser("u", "--random-password", "--access-token-scopes", "read:issue")
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
|
||||
assert.ErrorContains(t, err, "access-token-name and access-token-scopes flags are only valid when access-token flag is set")
|
||||
|
||||
// empty permission
|
||||
reset()
|
||||
err = createUser("u", "--random-password --access-token --access-token-scopes public-only")
|
||||
err = createUser("u", "--random-password", "--access-token", "--access-token-scopes", "public-only")
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &user_model.User{}))
|
||||
assert.Equal(t, 0, unittest.GetCount(t, &auth_model.AccessToken{}))
|
||||
assert.ErrorContains(t, err, "access token does not have any permission")
|
||||
})
|
||||
|
||||
t.Run("UserFields", func(t *testing.T) {
|
||||
reset()
|
||||
assert.NoError(t, createUser("u-FullNameWithSpace", "--random-password", "--fullname", "First O'Middle Last"))
|
||||
unittest.AssertExistsAndLoadBean(t, &user_model.User{
|
||||
Name: "u-FullNameWithSpace",
|
||||
LowerName: "u-fullnamewithspace",
|
||||
FullName: "First O'Middle Last",
|
||||
Email: "u-FullNameWithSpace@gitea.local",
|
||||
})
|
||||
|
||||
assert.NoError(t, createUser("u-FullNameEmpty", "--random-password", "--fullname", ""))
|
||||
u := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: "u-fullnameempty"})
|
||||
assert.Empty(t, u.FullName)
|
||||
})
|
||||
}
|
||||
|
@ -86,20 +86,15 @@ func (r *GlodmarkRender) highlightingRenderer(w util.BufWriter, c highlighting.C
|
||||
preClasses += " is-loading"
|
||||
}
|
||||
|
||||
err := r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<pre class="%s">`, preClasses)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// include language-x class as part of commonmark spec, "chroma" class is used to highlight the code
|
||||
// the "display" class is used by "js/markup/math.ts" to render the code element as a block
|
||||
// the "math.ts" strictly depends on the structure: <pre class="code-block is-loading"><code class="language-math display">...</code></pre>
|
||||
err = r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<code class="chroma language-%s display">`, languageStr)
|
||||
err := r.ctx.RenderInternal.FormatWithSafeAttrs(w, `<div class="code-block-container code-overflow-scroll"><pre class="%s"><code class="chroma language-%s display">`, preClasses, languageStr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
_, err := w.WriteString("</code></pre>")
|
||||
_, err := w.WriteString("</code></pre></div>")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ files=ファイル
|
||||
|
||||
error=エラー
|
||||
error404=アクセスしようとしたページは<strong>存在しない</strong>か、閲覧が<strong>許可されていません</strong>。
|
||||
error503=サーバーはリクエストを完了できませんでした。 後でもう一度お試しください。
|
||||
go_back=戻る
|
||||
invalid_data=無効なデータ: %v
|
||||
|
||||
@ -730,6 +731,8 @@ public_profile=公開プロフィール
|
||||
biography_placeholder=自己紹介してください!(Markdownを使うことができます)
|
||||
location_placeholder=おおよその場所を他の人と共有
|
||||
profile_desc=あなたのプロフィールが他のユーザーにどのように表示されるかを制御します。あなたのプライマリメールアドレスは、通知、パスワードの回復、WebベースのGit操作に使用されます。
|
||||
password_username_disabled=ユーザー名の変更は許可されていません。詳細はサイト管理者にお問い合わせください。
|
||||
password_full_name_disabled=フルネームの変更は許可されていません。詳細はサイト管理者にお問い合わせください。
|
||||
full_name=フルネーム
|
||||
website=Webサイト
|
||||
location=場所
|
||||
@ -924,6 +927,9 @@ permission_not_set=設定なし
|
||||
permission_no_access=アクセス不可
|
||||
permission_read=読み取り
|
||||
permission_write=読み取りと書き込み
|
||||
permission_anonymous_read=匿名の読み込み
|
||||
permission_everyone_read=全員の読み込み
|
||||
permission_everyone_write=全員の書き込み
|
||||
access_token_desc=選択したトークン権限に応じて、関連する<a %s>API</a>ルートのみに許可が制限されます。 詳細は<a %s>ドキュメント</a>を参照してください。
|
||||
at_least_one_permission=トークンを作成するには、少なくともひとつの許可を選択する必要があります
|
||||
permissions_list=許可:
|
||||
@ -1136,6 +1142,7 @@ transfer.no_permission_to_reject=この移転を拒否する権限がありま
|
||||
|
||||
desc.private=プライベート
|
||||
desc.public=公開
|
||||
desc.public_access=公開アクセス
|
||||
desc.template=テンプレート
|
||||
desc.internal=内部
|
||||
desc.archived=アーカイブ
|
||||
@ -1544,6 +1551,7 @@ issues.filter_project=プロジェクト
|
||||
issues.filter_project_all=すべてのプロジェクト
|
||||
issues.filter_project_none=プロジェクトなし
|
||||
issues.filter_assignee=担当者
|
||||
issues.filter_assignee_no_assignee=担当者なし
|
||||
issues.filter_assignee_any_assignee=担当者あり
|
||||
issues.filter_poster=作成者
|
||||
issues.filter_user_placeholder=ユーザーを検索
|
||||
@ -1647,6 +1655,8 @@ issues.label_archived_filter=アーカイブされたラベルを表示
|
||||
issues.label_archive_tooltip=アーカイブされたラベルは、ラベルによる検索時のサジェストからデフォルトで除外されます。
|
||||
issues.label_exclusive_desc=ラベル名を <code>スコープ/アイテム</code> の形にすることで、他の <code>スコープ/</code> ラベルと排他的になります。
|
||||
issues.label_exclusive_warning=イシューやプルリクエストのラベル編集では、競合するスコープ付きラベルは解除されます。
|
||||
issues.label_exclusive_order=ソート順
|
||||
issues.label_exclusive_order_tooltip=同じスコープ内の排他的なラベルは、この数値順にソートされます。
|
||||
issues.label_count=ラベル %d件
|
||||
issues.label_open_issues=オープン中のイシュー %d件
|
||||
issues.label_edit=編集
|
||||
@ -2129,6 +2139,12 @@ contributors.contribution_type.deletions=削除
|
||||
settings=設定
|
||||
settings.desc=設定では、リポジトリの設定を管理することができます。
|
||||
settings.options=リポジトリ
|
||||
settings.public_access=公開アクセス
|
||||
settings.public_access_desc=外部からの訪問者のアクセス権限について、このリポジトリのデフォルト設定を上書きします。
|
||||
settings.public_access.docs.not_set=設定なし: 公開アクセス権限はありません。訪問者の権限は、リポジトリの公開範囲とメンバーの権限に従います。
|
||||
settings.public_access.docs.anonymous_read=匿名の読み込み: ログインしていないユーザーは読み取り権限でユニットにアクセスできます。
|
||||
settings.public_access.docs.everyone_read=全員の読み込み: すべてのログインユーザーは読み取り権限でユニットにアクセスできます。イシュー/プルリクエストユニットの読み取り権限は、ユーザーが新しいイシュー/プルリクエストを作成できることを意味します。
|
||||
settings.public_access.docs.everyone_write=全員の書き込み: すべてのログインユーザーに書き込み権限があります。Wikiユニットのみがこの権限をサポートします。
|
||||
settings.collaboration=共同作業者
|
||||
settings.collaboration.admin=管理者
|
||||
settings.collaboration.write=書き込み
|
||||
@ -2719,6 +2735,7 @@ branch.restore_success=ブランチ "%s" を復元しました。
|
||||
branch.restore_failed=ブランチ "%s" の復元に失敗しました。
|
||||
branch.protected_deletion_failed=ブランチ "%s" は保護されています。 削除できません。
|
||||
branch.default_deletion_failed=ブランチ "%s" はデフォルトブランチです。 削除できません。
|
||||
branch.default_branch_not_exist=デフォルトブランチ "%s" がありません。
|
||||
branch.restore=ブランチ "%s" の復元
|
||||
branch.download=ブランチ "%s" をダウンロード
|
||||
branch.rename=ブランチ名 "%s" を変更
|
||||
|
@ -193,7 +193,7 @@ func getWikiPage(ctx *context.APIContext, wikiName wiki_service.WebPath) *api.Wi
|
||||
}
|
||||
|
||||
// get commit count - wiki revisions
|
||||
commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename)
|
||||
commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.DefaultWikiBranch, pageFilename)
|
||||
|
||||
// Get last change information.
|
||||
lastCommit, err := wikiRepo.GetCommitByPath(pageFilename)
|
||||
@ -432,7 +432,7 @@ func ListPageRevisions(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// get commit count - wiki revisions
|
||||
commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename)
|
||||
commitsCount, _ := wikiRepo.FileCommitsCount(ctx.Repo.Repository.DefaultWikiBranch, pageFilename)
|
||||
|
||||
page := ctx.FormInt("page")
|
||||
if page <= 1 {
|
||||
@ -442,7 +442,7 @@ func ListPageRevisions(ctx *context.APIContext) {
|
||||
// get Commit Count
|
||||
commitsHistory, err := wikiRepo.CommitsByFileAndRange(
|
||||
git.CommitsByFileAndRangeOptions{
|
||||
Revision: "master",
|
||||
Revision: ctx.Repo.Repository.DefaultWikiBranch,
|
||||
File: pageFilename,
|
||||
Page: page,
|
||||
})
|
||||
@ -486,7 +486,7 @@ func findWikiRepoCommit(ctx *context.APIContext) (*git.Repository, *git.Commit)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
commit, err := wikiRepo.GetBranchCommit("master")
|
||||
commit, err := wikiRepo.GetBranchCommit(ctx.Repo.Repository.DefaultWikiBranch)
|
||||
if err != nil {
|
||||
if git.IsErrNotExist(err) {
|
||||
ctx.APIErrorNotFound(err)
|
||||
|
71
templates/devtest/markup-render.tmpl
Normal file
71
templates/devtest/markup-render.tmpl
Normal file
@ -0,0 +1,71 @@
|
||||
{{template "devtest/devtest-header"}}
|
||||
<div class="page-content devtest ui container">
|
||||
{{$longCode := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"}}
|
||||
<div class="tw-flex">
|
||||
<div class="tw-w-[50%] tw-p-4">
|
||||
<div class="markup render-content">
|
||||
Inline <code>code</code> content
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="markup render-content">
|
||||
<p>content before</p>
|
||||
<pre><code>Very long line with no code block or container: {{$longCode}}</code></pre>
|
||||
<p>content after</p>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="markup render-content">
|
||||
<p>content before</p>
|
||||
<div class="code-block-container code-overflow-wrap">
|
||||
<pre class="code-block"><code>Very long line with wrap: {{$longCode}}</code></pre>
|
||||
</div>
|
||||
<p>content after</p>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="markup render-content">
|
||||
<p>content before</p>
|
||||
<div class="code-block-container code-overflow-scroll">
|
||||
<pre class="code-block"><code>Short line in scroll container</code></pre>
|
||||
</div>
|
||||
<div class="code-block-container code-overflow-scroll">
|
||||
<pre class="code-block"><code>Very long line with scroll: {{$longCode}}</code></pre>
|
||||
</div>
|
||||
<p>content after</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tw-w-[50%] tw-p-4">
|
||||
<div class="markup render-content">
|
||||
<p>content before</p>
|
||||
<div class="code-block-container">
|
||||
<pre class="code-block"><code class="language-math">
|
||||
\lim\limits_{n\rightarrow\infty}{\left(1+\frac{1}{n}\right)^n}
|
||||
</code></pre>
|
||||
</div>
|
||||
<p>content after</p>
|
||||
</div>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<div class="markup render-content">
|
||||
<p>content before</p>
|
||||
<div class="code-block-container">
|
||||
<pre class="code-block"><code class="language-mermaid is-loading">
|
||||
graph LR
|
||||
A[Square Rect] -- Link text --> B((Circle))
|
||||
A --> C(Round Rect)
|
||||
B --> D{Rhombus}
|
||||
C --> D
|
||||
</code></pre>
|
||||
</div>
|
||||
<p>content after</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "devtest/devtest-footer"}}
|
@ -8,9 +8,9 @@
|
||||
{{$referenceUrl := printf "%s#%s" $.Issue.Link $comment.HashTag}}
|
||||
<div class="conversation-holder" data-path="{{$comment.TreePath}}" data-side="{{if lt $comment.Line 0}}left{{else}}right{{end}}" data-idx="{{$comment.UnsignedLine}}">
|
||||
{{if $resolved}}
|
||||
<div class="ui attached header resolved-placeholder tw-flex tw-items-center tw-justify-between">
|
||||
<div class="ui grey text tw-flex tw-items-center tw-flex-wrap tw-gap-1">
|
||||
{{svg "octicon-check" 16 "icon tw-mr-1"}}
|
||||
<div class="resolved-placeholder">
|
||||
<div class="flex-text-block tw-flex-wrap grey text">
|
||||
{{svg "octicon-check"}}
|
||||
<b>{{$resolveDoer.Name}}</b> {{ctx.Locale.Tr "repo.issues.review.resolved_by"}}
|
||||
{{if $invalid}}
|
||||
<!--
|
||||
@ -22,14 +22,12 @@
|
||||
</a>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="tw-flex tw-items-center tw-gap-2">
|
||||
<button id="show-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="ui tiny labeled button show-outdated tw-flex tw-items-center">
|
||||
{{svg "octicon-unfold" 16 "tw-mr-2"}}
|
||||
{{ctx.Locale.Tr "repo.issues.review.show_resolved"}}
|
||||
<div class="flex-text-block">
|
||||
<button id="show-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="btn tiny show-outdated">
|
||||
{{svg "octicon-unfold" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.issues.review.show_resolved"}}
|
||||
</button>
|
||||
<button id="hide-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="ui tiny labeled button hide-outdated tw-flex tw-items-center tw-hidden">
|
||||
{{svg "octicon-fold" 16 "tw-mr-2"}}
|
||||
{{ctx.Locale.Tr "repo.issues.review.hide_resolved"}}
|
||||
<button id="hide-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="btn tiny hide-outdated tw-hidden">
|
||||
{{svg "octicon-fold" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.issues.review.hide_resolved"}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div>
|
||||
{{if or $invalid $resolved}}
|
||||
<button id="show-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="{{if not $resolved}}tw-hidden {{end}}ui compact labeled button show-outdated tw-flex tw-items-center">
|
||||
<button id="show-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="{{if not $resolved}}tw-hidden{{end}} btn tiny show-outdated">
|
||||
{{svg "octicon-unfold" 16 "tw-mr-2"}}
|
||||
{{if $resolved}}
|
||||
{{ctx.Locale.Tr "repo.issues.review.show_resolved"}}
|
||||
@ -25,7 +25,7 @@
|
||||
{{ctx.Locale.Tr "repo.issues.review.show_outdated"}}
|
||||
{{end}}
|
||||
</button>
|
||||
<button id="hide-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="{{if $resolved}}tw-hidden {{end}}ui compact labeled button hide-outdated tw-flex tw-items-center">
|
||||
<button id="hide-outdated-{{$comment.ID}}" data-comment="{{$comment.ID}}" class="{{if $resolved}}tw-hidden {{end}} btn tiny hide-outdated">
|
||||
{{svg "octicon-fold" 16 "tw-mr-2"}}
|
||||
{{if $resolved}}
|
||||
{{ctx.Locale.Tr "repo.issues.review.hide_resolved"}}
|
||||
|
@ -3,18 +3,18 @@
|
||||
{{template "repo/header" .}}
|
||||
{{$title := .title}}
|
||||
<div class="ui container">
|
||||
<div class="ui stackable grid">
|
||||
<div class="ui eight wide column">
|
||||
<div class="ui header">
|
||||
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}">{{if .revision}}<span>{{.revision}}</span> {{end}}{{svg "octicon-home"}}</a>
|
||||
<div class="ui dividing header flex-text-block tw-flex-wrap tw-justify-between">
|
||||
<div class="flex-text-block">
|
||||
<a class="ui basic button tw-px-3" title="{{ctx.Locale.Tr "repo.wiki.back_to_wiki"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}">{{svg "octicon-home"}}</a>
|
||||
<div class="tw-flex-1 gt-ellipsis">
|
||||
{{$title}}
|
||||
<div class="ui sub header tw-break-anywhere">
|
||||
<div class="ui sub header gt-ellipsis">
|
||||
{{$timeSince := DateUtils.TimeSince .Author.When}}
|
||||
{{ctx.Locale.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui eight wide column tw-text-right">
|
||||
<div>
|
||||
{{template "repo/clone_panel" .}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -33,7 +33,7 @@
|
||||
<div class="ui dividing header">
|
||||
<div class="flex-text-block tw-flex-wrap tw-justify-end">
|
||||
<div class="flex-text-block tw-flex-1 tw-min-w-[300px]">
|
||||
<a class="file-revisions-btn ui basic button" title="{{ctx.Locale.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" >{{if .CommitCount}}<span>{{.CommitCount}}</span> {{end}}{{svg "octicon-history"}}</a>
|
||||
<a class="ui basic button tw-px-3 tw-gap-3" title="{{ctx.Locale.Tr "repo.wiki.file_revision"}}" href="{{.RepoLink}}/wiki/{{.PageURL}}?action=_revision" >{{if .CommitCount}}<span>{{.CommitCount}}</span> {{end}}{{svg "octicon-history"}}</a>
|
||||
<div class="tw-flex-1 gt-ellipsis">
|
||||
{{$title}}
|
||||
<div class="ui sub header gt-ellipsis">
|
||||
|
@ -1,6 +1,6 @@
|
||||
{{- /* we do not need to set for/id here, global aria init code will add them automatically */ -}}
|
||||
<label>{{.LabelText}}</label>
|
||||
<input class="avatar-file-with-cropper" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
|
||||
<input class="avatar-file-with-cropper" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp" data-global-init="initAvatarUploader">
|
||||
{{- /* the cropper-panel must be next sibling of the input "avatar" */ -}}
|
||||
<div class="cropper-panel tw-hidden">
|
||||
<div class="tw-my-2">{{ctx.Locale.Tr "settings.cropper_prompt"}}</div>
|
||||
|
@ -224,6 +224,7 @@ progress::-moz-progress-bar {
|
||||
}
|
||||
|
||||
.unselectable,
|
||||
.btn,
|
||||
.button,
|
||||
.lines-num,
|
||||
.lines-commit,
|
||||
|
@ -1,8 +1,3 @@
|
||||
.markup .code-block,
|
||||
.markup .mermaid-block {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.markup .code-copy {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
@ -28,8 +23,8 @@
|
||||
background: var(--color-secondary-dark-1) !important;
|
||||
}
|
||||
|
||||
.markup .code-block:hover .code-copy,
|
||||
.markup .mermaid-block:hover .code-copy {
|
||||
.markup .code-block-container:hover .code-copy,
|
||||
.markup .code-block:hover .code-copy {
|
||||
visibility: visible;
|
||||
animation: fadein 0.2s both;
|
||||
}
|
||||
|
@ -443,13 +443,25 @@
|
||||
}
|
||||
|
||||
.markup pre > code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.markup .code-block,
|
||||
.markup .code-block-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.markup .code-block-container.code-overflow-wrap pre > code {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markup .code-block-container.code-overflow-scroll pre {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.markup .code-block-container.code-overflow-scroll pre > code {
|
||||
white-space: pre;
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
|
||||
.markup .highlight {
|
||||
@ -470,16 +482,11 @@
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.markup pre {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.markup pre code,
|
||||
.markup pre tt {
|
||||
display: inline;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
@ -522,20 +529,6 @@
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
|
||||
.file-revisions-btn {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-bottom: 2px !important;
|
||||
padding: 11px !important;
|
||||
margin-right: 10px !important;
|
||||
}
|
||||
|
||||
.file-revisions-btn i {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.markup-content-iframe {
|
||||
display: block;
|
||||
border: none;
|
||||
|
@ -352,6 +352,14 @@ a.btn:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.btn.tiny {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.btn.small {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* By default, Fomantic UI doesn't support "bordered" buttons group, but Gitea would like to use it.
|
||||
And the default buttons always have borders now (not the same as Fomantic UI's default buttons, see above).
|
||||
It needs some tricks to tweak the left/right borders with active state */
|
||||
|
@ -92,6 +92,10 @@
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .item:focus {
|
||||
background: var(--color-hover);
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .item.active {
|
||||
background: var(--color-active);
|
||||
}
|
||||
|
||||
|
@ -1784,12 +1784,12 @@ tbody.commit-list {
|
||||
.resolved-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px !important;
|
||||
padding: 8px !important;
|
||||
font-weight: var(--font-weight-normal) !important;
|
||||
border: 1px solid var(--color-secondary) !important;
|
||||
border-radius: var(--border-radius) !important;
|
||||
margin: 4px !important;
|
||||
justify-content: space-between;
|
||||
margin: 4px;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--color-secondary);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--color-box-header);
|
||||
}
|
||||
|
||||
.resolved-placeholder + .comment-code-cloud {
|
||||
|
@ -1,11 +1,3 @@
|
||||
.show-outdated,
|
||||
.hide-outdated {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.ui.button.add-code-comment {
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
@ -59,11 +51,6 @@
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.show-outdated:hover,
|
||||
.hide-outdated:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.comment-code-cloud {
|
||||
padding: 0.5rem 1rem !important;
|
||||
position: relative;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import {checkAppUrl} from '../common-page.ts';
|
||||
import {hideElem, queryElems, showElem, toggleElem} from '../../utils/dom.ts';
|
||||
import {POST} from '../../modules/fetch.ts';
|
||||
import {initAvatarUploaderWithCropper} from '../comp/Cropper.ts';
|
||||
import {fomanticQuery} from '../../modules/fomantic/base.ts';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
@ -23,8 +22,6 @@ export function initAdminCommon(): void {
|
||||
initAdminUser();
|
||||
initAdminAuthentication();
|
||||
initAdminNotice();
|
||||
|
||||
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||
}
|
||||
|
||||
function initAdminUser() {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {initCompLabelEdit} from './comp/LabelEdit.ts';
|
||||
import {queryElems, toggleElem} from '../utils/dom.ts';
|
||||
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||
import {toggleElem} from '../utils/dom.ts';
|
||||
|
||||
export function initCommonOrganization() {
|
||||
if (!document.querySelectorAll('.organization').length) {
|
||||
@ -14,6 +13,4 @@ export function initCommonOrganization() {
|
||||
|
||||
// Labels
|
||||
initCompLabelEdit('.page-content.organization.settings.labels');
|
||||
|
||||
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import {showGlobalErrorMessage} from '../bootstrap.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
import {queryElems} from '../utils/dom.ts';
|
||||
import {registerGlobalInitFunc, registerGlobalSelectorFunc} from '../modules/observer.ts';
|
||||
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||
|
||||
const {appUrl} = window.config;
|
||||
|
||||
@ -80,6 +81,10 @@ export function initGlobalTabularMenu() {
|
||||
fomanticQuery('.ui.menu.tabular:not(.custom) .item').tab();
|
||||
}
|
||||
|
||||
export function initGlobalAvatarUploader() {
|
||||
registerGlobalInitFunc('initAvatarUploader', initAvatarUploaderWithCropper);
|
||||
}
|
||||
|
||||
// for performance considerations, it only uses performant syntax
|
||||
function attachInputDirAuto(el: Partial<HTMLInputElement | HTMLTextAreaElement>) {
|
||||
if (el.type !== 'hidden' &&
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {svg} from '../svg.ts';
|
||||
import {createTippy} from '../modules/tippy.ts';
|
||||
import {clippie} from 'clippie';
|
||||
import {toAbsoluteUrl} from '../utils.ts';
|
||||
import {addDelegatedEventListener} from '../utils/dom.ts';
|
||||
|
||||
@ -43,7 +42,8 @@ function selectRange(range: string): Element {
|
||||
if (!copyPermalink) return;
|
||||
let link = copyPermalink.getAttribute('data-url');
|
||||
link = `${link.replace(/#L\d+$|#L\d+-L\d+$/, '')}#${anchor}`;
|
||||
copyPermalink.setAttribute('data-url', link);
|
||||
copyPermalink.setAttribute('data-clipboard-text', link);
|
||||
copyPermalink.setAttribute('data-clipboard-text-type', 'url');
|
||||
};
|
||||
|
||||
const rangeFields = range ? range.split('-') : [];
|
||||
@ -138,8 +138,4 @@ export function initRepoCodeView() {
|
||||
};
|
||||
onHashChange();
|
||||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
addDelegatedEventListener(document, 'click', '.copy-line-permalink', (el) => {
|
||||
clippie(toAbsoluteUrl(el.getAttribute('data-url')));
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ import {minimatch} from 'minimatch';
|
||||
import {createMonaco} from './codeeditor.ts';
|
||||
import {onInputDebounce, queryElems, toggleClass, toggleElem} from '../utils/dom.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||
import {initRepoSettingsBranchesDrag} from './repo-settings-branches.ts';
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
|
||||
@ -149,6 +148,4 @@ export function initRepoSettings() {
|
||||
initRepoSettingsSearchTeamBox();
|
||||
initRepoSettingsGitHook();
|
||||
initRepoSettingsBranchesDrag();
|
||||
|
||||
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
import {hideElem, queryElems, showElem} from '../utils/dom.ts';
|
||||
import {initAvatarUploaderWithCropper} from './comp/Cropper.ts';
|
||||
import {hideElem, showElem} from '../utils/dom.ts';
|
||||
|
||||
export function initUserSettings() {
|
||||
if (!document.querySelector('.user.settings.profile')) return;
|
||||
|
||||
queryElems(document, '.avatar-file-with-cropper', initAvatarUploaderWithCropper);
|
||||
|
||||
const usernameInput = document.querySelector<HTMLInputElement>('#username');
|
||||
if (!usernameInput) return;
|
||||
usernameInput.addEventListener('input', function () {
|
||||
|
@ -60,7 +60,7 @@ import {initColorPickers} from './features/colorpicker.ts';
|
||||
import {initAdminSelfCheck} from './features/admin/selfcheck.ts';
|
||||
import {initOAuth2SettingsDisableCheckbox} from './features/oauth2-settings.ts';
|
||||
import {initGlobalFetchAction} from './features/common-fetch-action.ts';
|
||||
import {initFootLanguageMenu, initGlobalDropdown, initGlobalInput, initGlobalTabularMenu, initHeadNavbarContentToggle} from './features/common-page.ts';
|
||||
import {initFootLanguageMenu, initGlobalAvatarUploader, initGlobalDropdown, initGlobalInput, initGlobalTabularMenu, initHeadNavbarContentToggle} from './features/common-page.ts';
|
||||
import {initGlobalButtonClickOnEnter, initGlobalButtons, initGlobalDeleteButton} from './features/common-button.ts';
|
||||
import {initGlobalComboMarkdownEditor, initGlobalEnterQuickSubmit, initGlobalFormDirtyLeaveConfirm} from './features/common-form.ts';
|
||||
import {callInitFunctions} from './modules/init.ts';
|
||||
@ -72,6 +72,7 @@ initSubmitEventPolyfill();
|
||||
onDomReady(() => {
|
||||
const initStartTime = performance.now();
|
||||
const initPerformanceTracer = callInitFunctions([
|
||||
initGlobalAvatarUploader,
|
||||
initGlobalDropdown,
|
||||
initGlobalTabularMenu,
|
||||
initGlobalFetchAction,
|
||||
|
@ -15,6 +15,8 @@ export function initMarkupCodeCopy(elMarkup: HTMLElement): void {
|
||||
const btn = makeCodeCopyButton();
|
||||
// remove final trailing newline introduced during HTML rendering
|
||||
btn.setAttribute('data-clipboard-text', el.textContent.replace(/\r?\n$/, ''));
|
||||
el.after(btn);
|
||||
// we only want to use `.code-block-container` if it exists, no matter `.code-block` exists or not.
|
||||
const btnContainer = el.closest('.code-block-container') ?? el.closest('.code-block');
|
||||
btnContainer.append(btn);
|
||||
});
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export function queryElemChildren<T extends Element>(parent: Element | ParentNod
|
||||
}
|
||||
|
||||
// it works like parent.querySelectorAll: all descendants are selected
|
||||
// in the future, all "queryElems(document, ...)" should be refactored to use a more specific parent
|
||||
// in the future, all "queryElems(document, ...)" should be refactored to use a more specific parent if the targets are not for page-level components.
|
||||
export function queryElems<T extends HTMLElement>(parent: Element | ParentNode, selector: string, fn?: ElementsCallback<T>): ArrayLikeIterable<T> {
|
||||
return applyElemsCallback<T>(parent.querySelectorAll(selector), fn);
|
||||
}
|
||||
@ -360,7 +360,11 @@ export function querySingleVisibleElem<T extends HTMLElement>(parent: Element, s
|
||||
export function addDelegatedEventListener<T extends HTMLElement, E extends Event>(parent: Node, type: string, selector: string, listener: (elem: T, e: E) => Promisable<void>, options?: boolean | AddEventListenerOptions) {
|
||||
parent.addEventListener(type, (e: Event) => {
|
||||
const elem = (e.target as HTMLElement).closest(selector);
|
||||
if (!elem || !parent.contains(elem)) return;
|
||||
// It strictly checks "parent contains the target elem" to avoid side effects of selector running on outside the parent.
|
||||
// Keep in mind that the elem could have been removed from parent by other event handlers before this event handler is called.
|
||||
// For example: tippy popup item, the tippy popup could be hidden and removed from DOM before this.
|
||||
// It is caller's responsibility make sure the elem is still in parent's DOM when this event handler is called.
|
||||
if (!elem || (parent !== document && !parent.contains(elem))) return;
|
||||
listener(elem as T, e as E);
|
||||
}, options);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user