From 636b6eaf2aa987c2fe530aafdbb9f50a2f58afa5 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 25 Aug 2023 07:26:32 +0200 Subject: [PATCH 01/12] Focus editor on "Write" tab click (#26714) Focus the editor when clicking the "Write" tab. Works for both Textarea and EasyMDE. Does for some reason not work without the `requestAnimationFrame`. --- web_src/js/features/comp/ComboMarkdownEditor.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.js b/web_src/js/features/comp/ComboMarkdownEditor.js index 9826f2f2bf24..d486c5830acc 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.js +++ b/web_src/js/features/comp/ComboMarkdownEditor.js @@ -135,6 +135,12 @@ class ComboMarkdownEditor { $panelPreviewer.attr('data-tab', `markdown-previewer-${elementIdCounter}`); elementIdCounter++; + $tabEditor[0].addEventListener('click', () => { + requestAnimationFrame(() => { + this.focus(); + }); + }); + $tabs.tab(); this.previewUrl = $tabPreviewer.attr('data-preview-url'); From ee9e83b230981437acf8c331e93a41cdc95af443 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 25 Aug 2023 14:47:59 +0800 Subject: [PATCH 02/12] Remove incorrect CSS helper classes (#26712) --- templates/repo/diff/conversation.tmpl | 2 +- templates/user/auth/captcha.tmpl | 10 +++++----- web_src/css/form.css | 26 +++++++++++++------------- web_src/css/helpers.css | 6 ------ web_src/css/org.css | 6 ++---- 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/templates/repo/diff/conversation.tmpl b/templates/repo/diff/conversation.tmpl index ce344794ea78..639dd9cd040b 100644 --- a/templates/repo/diff/conversation.tmpl +++ b/templates/repo/diff/conversation.tmpl @@ -37,7 +37,7 @@ {{template "repo/diff/comments" dict "root" $ "comments" .comments}} -
+
{{else if eq .CaptchaType "mcaptcha"}} -
- {{.locale.Tr "captcha"}} -
-
+
+ +
+
{{else if eq .CaptchaType "cfturnstile"}} -
+
{{end}}{{end}} diff --git a/web_src/css/form.css b/web_src/css/form.css index 9527ef9d461f..1bd1920955a6 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -179,8 +179,7 @@ textarea:focus, #create-page-form form .header { padding-left: 280px !important; } - #create-page-form form .inline.field > label, - #create-page-form form .inline.field.captcha-field > span { + #create-page-form form .inline.field > label { text-align: right; width: 250px !important; word-wrap: break-word; @@ -206,6 +205,13 @@ textarea:focus, } } +.m-captcha-style { + width: 100%; + height: 5em; + vertical-align: middle; + display: inline-block; +} + @media (min-width: 768px) { .g-recaptcha-style, .h-captcha-style { @@ -219,6 +225,9 @@ textarea:focus, width: 302px !important; height: 76px !important; } + .m-captcha-style { + width: 50%; + } } @media (max-height: 575px) { @@ -271,13 +280,7 @@ textarea:focus, .user.reset.password form .inline.field > label, .user.link-account form .inline.field > label, .user.signin form .inline.field > label, - .user.signup form .inline.field > label, - .user.activate form .inline.field.captcha-field > span, - .user.forgot.password form .inline.field.captcha-field > span, - .user.reset.password form .inline.field.captcha-field > span, - .user.link-account form .inline.field.captcha-field > span, - .user.signin form .inline.field.captcha-field > span, - .user.signup form .inline.field.captcha-field > span { + .user.signup form .inline.field > label { text-align: right; width: 250px !important; word-wrap: break-word; @@ -421,10 +424,7 @@ textarea:focus, } .repository.new.repo form .inline.field > label, .repository.new.migrate form .inline.field > label, - .repository.new.fork form .inline.field > label, - .repository.new.repo form .inline.field.captcha-field > span, - .repository.new.migrate form .inline.field.captcha-field > span, - .repository.new.fork form .inline.field.captcha-field > span { + .repository.new.fork form .inline.field > label { text-align: right; width: 250px !important; word-wrap: break-word; diff --git a/web_src/css/helpers.css b/web_src/css/helpers.css index 35b5d3c97e52..17a89ebfb7e2 100644 --- a/web_src/css/helpers.css +++ b/web_src/css/helpers.css @@ -273,12 +273,6 @@ Gitea's private styles use `g-` prefix. .gt-font-17 { font-size: 17px !important } .gt-font-18 { font-size: 18px !important } -@media (max-width: 767.98px) { - .gt-db-small { display: block !important; } - .gt-w-100-small { width: 100% !important; } - .gt-js-small { justify-content: flex-start !important; } -} - /* gt-hidden must be placed after all other "display: xxx !important" classes to win the chance do not use: diff --git a/web_src/css/org.css b/web_src/css/org.css index 4bb3b0cd579c..061d30bef2c9 100644 --- a/web_src/css/org.css +++ b/web_src/css/org.css @@ -13,8 +13,7 @@ #create-page-form form .header { padding-left: 280px !important; } - #create-page-form form .inline.field > label, - #create-page-form form .inline.field.captcha-field > span { + #create-page-form form .inline.field > label { text-align: right; width: 250px !important; word-wrap: break-word; @@ -59,8 +58,7 @@ .organization.new.org form .header { padding-left: 280px !important; } - .organization.new.org form .inline.field > label, - .organization.new.org form .inline.field.captcha-field > span { + .organization.new.org form .inline.field > label { text-align: right; width: 250px !important; word-wrap: break-word; From 412e5c0946fc5b83456685bc2fb1aed682228f57 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Fri, 25 Aug 2023 19:07:42 +0800 Subject: [PATCH 03/12] Make web context initialize correctly for different cases (#26726) The web context (modules/context.Context) is quite complex, it's difficult for the callers to initialize correctly. This PR introduces a `NewWebContext` function, to make sure the web context have the same behavior for different cases. --- modules/context/context.go | 41 +++++++++++++++---------- modules/context/package.go | 6 ++-- modules/test/context_tests.go | 16 +++++----- routers/install/install.go | 10 +----- routers/web/repo/actions/actions.go | 2 +- routers/web/repo/helper.go | 7 ++--- routers/web/repo/helper_test.go | 7 ++--- routers/web/repo/issue.go | 6 ++-- routers/web/repo/pull.go | 2 +- routers/web/repo/release.go | 4 +-- services/markup/processorhelper_test.go | 3 +- 11 files changed, 50 insertions(+), 54 deletions(-) diff --git a/modules/context/context.go b/modules/context/context.go index 98c1a9bdb670..47ad310b095a 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -107,6 +107,29 @@ func GetValidateContext(req *http.Request) (ctx *ValidateContext) { return ctx } +func NewTemplateContextForWeb(ctx *Context) TemplateContext { + tmplCtx := NewTemplateContext(ctx) + tmplCtx["Locale"] = ctx.Base.Locale + tmplCtx["AvatarUtils"] = templates.NewAvatarUtils(ctx) + return tmplCtx +} + +func NewWebContext(base *Base, render Render, session session.Store) *Context { + ctx := &Context{ + Base: base, + Render: render, + Session: session, + + Cache: mc.GetCache(), + Link: setting.AppSubURL + strings.TrimSuffix(base.Req.URL.EscapedPath(), "/"), + Repo: &Repository{PullRequest: &PullRequest{}}, + Org: &Organization{}, + } + ctx.TemplateContext = NewTemplateContextForWeb(ctx) + ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}} + return ctx +} + // Contexter initializes a classic context for a request. func Contexter() func(next http.Handler) http.Handler { rnd := templates.HTMLRenderer() @@ -127,21 +150,8 @@ func Contexter() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { base, baseCleanUp := NewBaseContext(resp, req) - ctx := &Context{ - Base: base, - Cache: mc.GetCache(), - Link: setting.AppSubURL + strings.TrimSuffix(req.URL.EscapedPath(), "/"), - Render: rnd, - Session: session.GetSession(req), - Repo: &Repository{PullRequest: &PullRequest{}}, - Org: &Organization{}, - } defer baseCleanUp() - - // TODO: "install.go" also shares the same logic, which should be refactored to a general function - ctx.TemplateContext = NewTemplateContext(ctx) - ctx.TemplateContext["Locale"] = ctx.Locale - ctx.TemplateContext["AvatarUtils"] = templates.NewAvatarUtils(ctx) + ctx := NewWebContext(base, rnd, session.GetSession(req)) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this @@ -172,8 +182,7 @@ func Contexter() func(next http.Handler) http.Handler { } } - // prepare an empty Flash message for current request - ctx.Flash = &middleware.Flash{DataStore: ctx, Values: url.Values{}} + // if there are new messages in the ctx.Flash, write them into cookie ctx.Resp.Before(func(resp ResponseWriter) { if val := ctx.Flash.Encode(); val != "" { middleware.SetSiteCookie(ctx.Resp, CookieNameFlash, val, 0) diff --git a/modules/context/package.go b/modules/context/package.go index be50e0a991ee..c0813fb2da6b 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -154,12 +154,10 @@ func PackageContexter() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { base, baseCleanUp := NewBaseContext(resp, req) - ctx := &Context{ - Base: base, - Render: renderer, // it is still needed when rendering 500 page in a package handler - } defer baseCleanUp() + // it is still needed when rendering 500 page in a package handler + ctx := NewWebContext(base, renderer, nil) ctx.Base.AppendContextValue(WebContextKey, ctx) next.ServeHTTP(ctx.Resp, ctx.Req) }) diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 92d7f8b22bab..83e6117bcf33 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -45,14 +45,12 @@ func MockContext(t *testing.T, reqPath string) (*context.Context, *httptest.Resp resp := httptest.NewRecorder() req := mockRequest(t, reqPath) base, baseCleanUp := context.NewBaseContext(resp, req) + _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later base.Data = middleware.GetContextData(req.Context()) base.Locale = &translation.MockLocale{} - ctx := &context.Context{ - Base: base, - Render: &mockRender{}, - Flash: &middleware.Flash{Values: url.Values{}}, - } - _ = baseCleanUp // during test, it doesn't need to do clean up. TODO: this can be improved later + + ctx := context.NewWebContext(base, &MockRender{}, nil) + ctx.Flash = &middleware.Flash{Values: url.Values{}} chiCtx := chi.NewRouteContext() ctx.Base.AppendContextValue(chi.RouteCtxKey, chiCtx) @@ -148,13 +146,13 @@ func LoadGitRepo(t *testing.T, ctx *context.Context) { assert.NoError(t, err) } -type mockRender struct{} +type MockRender struct{} -func (tr *mockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) { +func (tr *MockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) { return nil, nil } -func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error { +func (tr *MockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error { if resp, ok := w.(http.ResponseWriter); ok { resp.WriteHeader(status) } diff --git a/routers/install/install.go b/routers/install/install.go index 99ea7b0738c9..66a9e1f0023f 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -60,17 +60,9 @@ func Contexter() func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { base, baseCleanUp := context.NewBaseContext(resp, req) - ctx := &context.Context{ - Base: base, - Flash: &middleware.Flash{}, - Render: rnd, - Session: session.GetSession(req), - } defer baseCleanUp() - ctx.TemplateContext = context.NewTemplateContext(ctx) - ctx.TemplateContext["Locale"] = ctx.Locale - + ctx := context.NewWebContext(base, rnd, session.GetSession(req)) ctx.AppendContextValue(context.WebContextKey, ctx) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) ctx.Data.MergeFrom(middleware.ContextData{ diff --git a/routers/web/repo/actions/actions.go b/routers/web/repo/actions/actions.go index b0f4b6f8971d..6284d21463f3 100644 --- a/routers/web/repo/actions/actions.go +++ b/routers/web/repo/actions/actions.go @@ -191,7 +191,7 @@ func List(ctx *context.Context) { ctx.Error(http.StatusInternalServerError, err.Error()) return } - ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx, actors) + ctx.Data["Actors"] = repo.MakeSelfOnTop(ctx.Doer, actors) ctx.Data["StatusInfoList"] = actions_model.GetStatusInfoList(ctx) diff --git a/routers/web/repo/helper.go b/routers/web/repo/helper.go index fb5ada1bdb47..f8cdefdc8ef9 100644 --- a/routers/web/repo/helper.go +++ b/routers/web/repo/helper.go @@ -7,16 +7,15 @@ import ( "sort" "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" ) -func MakeSelfOnTop(ctx *context.Context, users []*user.User) []*user.User { - if ctx.Doer != nil { +func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { + if doer != nil { sort.Slice(users, func(i, j int) bool { if users[i].ID == users[j].ID { return false } - return users[i].ID == ctx.Doer.ID // if users[i] is self, put it before others, so less=true + return users[i].ID == doer.ID // if users[i] is self, put it before others, so less=true }) } return users diff --git a/routers/web/repo/helper_test.go b/routers/web/repo/helper_test.go index 226e2e81f4dd..978758e77fd7 100644 --- a/routers/web/repo/helper_test.go +++ b/routers/web/repo/helper_test.go @@ -7,21 +7,20 @@ import ( "testing" "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/context" "github.com/stretchr/testify/assert" ) func TestMakeSelfOnTop(t *testing.T) { - users := MakeSelfOnTop(&context.Context{}, []*user.User{{ID: 2}, {ID: 1}}) + users := MakeSelfOnTop(nil, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 2, users[0].ID) - users = MakeSelfOnTop(&context.Context{Doer: &user.User{ID: 1}}, []*user.User{{ID: 2}, {ID: 1}}) + users = MakeSelfOnTop(&user.User{ID: 1}, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 1, users[0].ID) - users = MakeSelfOnTop(&context.Context{Doer: &user.User{ID: 2}}, []*user.User{{ID: 2}, {ID: 1}}) + users = MakeSelfOnTop(&user.User{ID: 2}, []*user.User{{ID: 2}, {ID: 1}}) assert.Len(t, users, 2) assert.EqualValues(t, 2, users[0].ID) } diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 9a2add14524c..b8b5a2dff26d 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -331,7 +331,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) handleTeamMentions(ctx) if ctx.Written() { @@ -535,7 +535,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) handleTeamMentions(ctx) } @@ -3625,7 +3625,7 @@ func issuePosters(ctx *context.Context, isPullList bool) { } } - posters = MakeSelfOnTop(ctx, posters) + posters = MakeSelfOnTop(ctx.Doer, posters) resp := &userSearchResponse{} resp.Results = make([]*userSearchInfo, len(posters)) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index e3854779fe25..e697a0d5b6b1 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -956,7 +956,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) handleTeamMentions(ctx) if ctx.Written() { diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 957cf56972ce..138df4585760 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -349,7 +349,7 @@ func NewRelease(ctx *context.Context) { ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) upload.AddUploadContext(ctx, "release") @@ -538,7 +538,7 @@ func EditRelease(ctx *context.Context) { ctx.ServerError("GetRepoAssignees", err) return } - ctx.Data["Assignees"] = MakeSelfOnTop(ctx, assigneeUsers) + ctx.Data["Assignees"] = MakeSelfOnTop(ctx.Doer, assigneeUsers) ctx.HTML(http.StatusOK, tplReleaseNew) } diff --git a/services/markup/processorhelper_test.go b/services/markup/processorhelper_test.go index 2f48e03b22bf..d83e10903fdc 100644 --- a/services/markup/processorhelper_test.go +++ b/services/markup/processorhelper_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/models/user" gitea_context "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/test" "github.com/stretchr/testify/assert" ) @@ -41,7 +42,7 @@ func TestProcessorHelper(t *testing.T) { assert.NoError(t, err) base, baseCleanUp := gitea_context.NewBaseContext(httptest.NewRecorder(), req) defer baseCleanUp() - giteaCtx := &gitea_context.Context{Base: base} + giteaCtx := gitea_context.NewWebContext(base, &test.MockRender{}, nil) assert.True(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPublic)) assert.False(t, ProcessorHelper().IsUsernameMentionable(giteaCtx, userPrivate)) From 7b05d66e600f465d283a63f125e6202eb8faac30 Mon Sep 17 00:00:00 2001 From: Viktor Suprun Date: Fri, 25 Aug 2023 22:15:21 +1100 Subject: [PATCH 04/12] Fixed text overflow in dropdown menu (#26694) Fixes #26622 ![image](https://github.com/go-gitea/gitea/assets/683358/168b7e4d-97ba-4b5f-a5f5-33ee67e8b4be) Co-authored-by: Giteabot --- web_src/css/repo.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 414bd1d201f4..7a24f46702f0 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -162,6 +162,11 @@ left: 0; } +.repository .filter.menu .ui.dropdown .menu .item { + overflow: hidden; + text-overflow: ellipsis; +} + .repository .select-label .desc { padding-left: 23px; } From 21b8ec29aaa141981e7ca49855e7f25822efec05 Mon Sep 17 00:00:00 2001 From: silverwind Date: Fri, 25 Aug 2023 15:47:27 +0200 Subject: [PATCH 05/12] Add `eslint-plugin-vue-scoped-css` (#26720) Adds [eslint-plugin-vue-scoped-css](https://github.com/future-architect/eslint-plugin-vue-scoped-css) and fixes discovered issues which are: - 1 unused selector - 3 selectors with `.full.height` parent in a `