~roselandgoose: 2 Create new hyphae from /edit start localizing errors in mutators.go 10 files changed, 124 insertions(+), 43 deletions(-)
+ "cannot_create": "Cannot create Hypha named", Do not capitalize. + "cannot_create": "TODO: translate(Cannot create Hypha named)", That would be: Нельзя создать гифу, которая называется + "delete_empty": "TODO: translate(Cannot delete an empty hypha)", That would be: Нельзя удалить пустую гифу + "rename_empty": "TODO: translate(Cannot rename an empty hypha)", That would be: Нельзя переименовать пустую гифу
This patch series has been inactive for a long time. Are you still on it?
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~bouncepaw/mycorrhiza-devel/patches/37591/mbox | git am -3Learn more about email & git
From: Rosie K Languet <rkl@rosiesworkshop.net> This modifies handlerEdit to include a Name input field when one is not given in the url. It starts implementing the first part of bouncepaw's first bullet point: https://github.com/bouncepaw/mycorrhiza/issues/124#issuecomment-1219453093 --- hypview/hypview.go | 6 ++++-- hypview/view_edit.html | 38 ++++++++++++++++++++++++++------------ static/default.css | 13 +++++++++++-- util/util.go | 18 +++++++++++++++--- viewutil/err.go | 20 ++++++++------------ viewutil/viewutil.go | 14 ++++++++++++++ web/mutators.go | 30 +++++++++++++++++++++++++++--- 7 files changed, 105 insertions(+), 34 deletions(-) diff --git a/hypview/hypview.go b/hypview/hypview.go index ea705db..e25621b 100644 --- a/hypview/hypview.go +++ b/hypview/hypview.go @@ -16,9 +16,11 @@ var ( fs embed.FS ruTranslation = ` {{define "editing hypha"}}Редактирование {{beautifulName .}}{{end}} -{{define "editing [[hypha]]"}}Редактирование <a href="/hypha/{{.}}">{{beautifulName .}}</a>{{end}} -{{define "creating [[hypha]]"}}Создание <a href="/hypha/{{.}}">{{beautifulName .}}</a>{{end}} +{{define "editing [[hypha]]"}}Редактирование <a class="edit-form__name" href="/hypha/{{.}}">{{beautifulName .}}</a>{{end}} +{{define "create"}}Создать{{end}} +{{define "creating [[hypha]]"}}Создание <a class="edit-form__name" href="/hypha/{{.}}">{{beautifulName .}}</a>{{end}} {{define "you're creating a new hypha"}}Вы создаёте новую гифу.{{end}} +{{define "new hypha name"}}Новое название{{end}} {{define "describe your changes"}}Опишите ваши правки{{end}} {{define "save"}}Сохранить{{end}} {{define "preview"}}Предпросмотр{{end}} diff --git a/hypview/view_edit.html b/hypview/view_edit.html index 1bec2fe..fe5b5cb 100644 --- a/hypview/view_edit.html +++ b/hypview/view_edit.html @@ -42,31 +42,45 @@ <script src="/static/toolbar.js"></script> {{end}} +{{/* this defines <title> */}} {{define "editing hypha"}}Edit {{beautifulName .}}{{end}} {{define "previewing hypha"}}Preview of {{beautifulName .}}{{end}} {{define "title"}} -{{- if .Preview -}} - {{template "previewing hypha" .HyphaName}} -{{- else -}} - {{template "editing hypha" .HyphaName}} -{{- end -}} + {{- if .Preview -}} + {{template "previewing hypha" .HyphaName}} + {{- else -}} + {{template "editing hypha" .HyphaName}} + {{- end -}} {{end}} + {{define "body"}} <main class="main-width edit {{if .Preview}}edit_with-preview{{else}}edit_no-preview{{end}}"> <form method="post" class="edit-form" action="/upload-text/{{.HyphaName}}"> <h1 class="edit__title"> {{if .IsNew}} - {{block "creating [[hypha]]" .HyphaName}} - Create <a href="/hypha/{{.}}">{{beautifulName .}}</a> + {{if ne .HyphaName ""}} + {{block "creating [[hypha]]" .HyphaName}} + {{block "create" .}}Create{{end}} <a class="edit-form__name" href="/hypha/{{.}}">{{beautifulName .}}</a> + {{end}} + {{else}} + {{template "create"}} + <input + id="name" + type="text" + name="name" + required + class="edit-form__message-zone edit-form__name-field edit-form__name" + placeholder="{{block "new hypha name" .}}New hypha name{{end}}" + aria-label="{{template "new hypha name" .}}"> {{end}} {{else}} {{block "editing [[hypha]]" .HyphaName}} - Edit <a href="/hypha/{{.}}">{{beautifulName .}}</a> + Edit <a class="edit-form__name" href="/hypha/{{.}}">{{beautifulName .}}</a> {{end}} {{end}} </h1> <textarea name="text" class="edit-form__textarea" autofocus>{{.Content}}</textarea> - <p class="edit-form__message-zone"> + <div class="edit-form__message-zone"> <input id="text" type="text" @@ -75,8 +89,8 @@ value="{{.Message}}" placeholder="{{block "describe your changes" .}}Describe your changes{{end}}" aria-label="{{template "describe your changes" .}}"> - </p> - <p class="edit-form__buttons"> + </div> + <div class="edit-form__buttons"> <button type="submit" name="action" class="btn btn_accent edit-form__save" value="save"> {{template "save" .}} </button> @@ -86,7 +100,7 @@ <a href="/hypha/{{.HyphaName}}" class="btn btn_weak"> {{template "cancel" .}} </a> - </p> + </div> </form> {{if .Preview}} <p class="warning"> diff --git a/static/default.css b/static/default.css index de717cb..0986c93 100644 --- a/static/default.css +++ b/static/default.css @@ -93,10 +93,19 @@ textarea {font-size:16px; font-family: inherit; line-height: 150%; } .edit_no-preview { height: 90vh; } .edit_with-preview .edit-form { height: 90vh; } -.edit__title { margin-top: 0; } +.edit__title { + margin-top: 0; + display: flex; + flex-direction: row; + align-items: center; + justify-content: start; +} +.edit-form .edit-form__name { margin: 0.25em; } +.edit-form .edit-form__name-field { margin: 0.25em; margin-left: .5em; } .edit__preview { border: 2px dashed #ddd; padding: 10px; margin: 0 -10px; } .edit-form__textarea { width: 100%; height: 80vh; min-height: 4rem; } -.edit-form p { margin: .25rem 0; } +.edit-form div { margin: .25rem 0; } +.edit-form__message-zone { font-size:16px; font-weight: normal; } .edit-form__message { width: 100%; margin: 0.25em 0; } .edit-form__save { font-weight: bold; } .edit-toolbar__buttons, .edit-toolbar__help { margin: .5rem; } diff --git a/util/util.go b/util/util.go index a00230c..04fac06 100644 --- a/util/util.go +++ b/util/util.go @@ -71,16 +71,28 @@ func IsProfileName(hyphaName string) bool { return strings.HasPrefix(hyphaName, cfg.UserHypha+"/") && strings.Count(hyphaName, "/") == 1 } -// HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". + // HyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". When the url contains no hypha name, the configured HomeHypha is returned. func HyphaNameFromRq(rq *http.Request, actions ...string) string { + name := OptionalHyphaNameFromRq(rq, actions...) + if name == "" { + log.Println("HyphaNameFromRq: this request is invalid, fall back to home hypha") + return cfg.HomeHypha + } + return name +} + +// OptionalHyphaNameFromRq extracts hypha name from http request. You have to also pass the action which is embedded in the url or several actions. For url /hypha/hypha, the action would be "hypha". +func OptionalHyphaNameFromRq(rq *http.Request, actions ...string) string { p := rq.URL.Path for _, action := range actions { if strings.HasPrefix(p, "/"+action+"/") { return CanonicalName(strings.TrimPrefix(p, "/"+action+"/")) } + if p == "/"+action { + break + } } - log.Println("HyphaNameFromRq: this request is invalid, fall back to home hypha") - return cfg.HomeHypha + return CanonicalName("") } // FormData is a convenient struct for passing user input and errors to HTML diff --git a/viewutil/err.go b/viewutil/err.go index 4620709..f0b37bc 100644 --- a/viewutil/err.go +++ b/viewutil/err.go @@ -11,18 +11,14 @@ import ( func HttpErr(meta Meta, status int, name, errMsg string) { meta.W.(http.ResponseWriter).Header().Set("Content-Type", mime.TypeByExtension(".html")) meta.W.(http.ResponseWriter).WriteHeader(status) - fmt.Fprint( - meta.W, - Base( - meta, - "Error", - fmt.Sprintf( - `<main class="main-width"><p>%s. <a href="/hypha/%s">%s<a></p></main>`, - errMsg, - name, - meta.Lc.Get("ui.error_go_back"), - ), - map[string]string{}, + WriteBase( + meta, + "Error", + fmt.Sprintf( + `<main class="main-width"><p>%s. <a href="/hypha/%s">%s<a></p></main>`, + errMsg, + name, + meta.Lc.Get("ui.error_go_back"), ), ) } diff --git a/viewutil/viewutil.go b/viewutil/viewutil.go index 25de03b..fbe4da7 100644 --- a/viewutil/viewutil.go +++ b/viewutil/viewutil.go @@ -130,6 +130,20 @@ func Base(meta Meta, title, body string, bodyAttributes map[string]string, headE return w.String() } +// TODO: get rid of this +func WriteBase(meta Meta, title, innerHTML string) error { + _, err := fmt.Fprint( + meta.W, + Base( + meta, + title, + innerHTML, + nil, + ), + ) + return err +} + func CopyEnRuWith(fsys fs.FS, filename, ruTranslation string) Chain { return en(copyEnWith(fsys, filename)). ru(template.Must(copyRuWith(fsys, filename).Parse(ruTranslation))) diff --git a/web/mutators.go b/web/mutators.go index e85ddda..ecabcac 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -1,6 +1,7 @@ package web import ( + "fmt" "git.sr.ht/~bouncepaw/mycomarkup/v5" "html/template" "log" @@ -22,7 +23,7 @@ import ( ) func initMutators(r *mux.Router) { - r.PathPrefix("/edit/").HandlerFunc(handlerEdit) + r.PathPrefix("/edit").HandlerFunc(handlerEdit) r.PathPrefix("/rename/").HandlerFunc(handlerRename).Methods("GET", "POST") r.PathPrefix("/delete/").HandlerFunc(handlerDelete).Methods("GET", "POST") r.PathPrefix("/remove-media/").HandlerFunc(handlerRemoveMedia).Methods("GET", "POST") @@ -145,7 +146,7 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { lc = l18n.FromRequest(rq) meta = viewutil.MetaFrom(w, rq) - hyphaName = util.HyphaNameFromRq(rq, "edit") + hyphaName = util.OptionalHyphaNameFromRq(rq, "edit") h = hyphae.ByName(hyphaName) isNew bool @@ -179,10 +180,33 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { u = user.FromRequest(rq) meta = viewutil.MetaFrom(w, rq) - hyphaName = util.HyphaNameFromRq(rq, "upload-text") + hyphaName = util.OptionalHyphaNameFromRq(rq, "upload-text") + ) + + nameInURL := (hyphaName != "") + if !nameInURL { + hyphaName = util.CanonicalName(rq.PostFormValue("name")) + } + + var ( h = hyphae.ByName(hyphaName) _, isNew = h.(*hyphae.EmptyHypha) + ) + if !nameInURL && !isNew { + w.Header().Set("Content-Type", "text/html;charset=utf-8") + w.WriteHeader(http.StatusConflict) + viewutil.WriteBase(meta, "Error", + fmt.Sprintf( + `<main class="main-width"><p>Cannot create Hypha named %[1]s; <a href="%[1]s">Name already taken.</a></p></main>`, + hyphaName, + ), + // ToDo localize + ) + return + } + + var ( textData = rq.PostFormValue("text") action = rq.PostFormValue("action") message = rq.PostFormValue("message") -- 2.34.5
Hello! Sorry for the late review. I was testing if you have resolved the issues from the previous version of the patch. Quoting my previous message here:
Indeed, you now show an error, but the hypha still becomes emptied.
From: Rosie K Languet <rkl@rosiesworkshop.net> This commit moves some non-localized error strings into l18n/en/ui.json with somewhat sensible keys. There are entries in the corresponding ru/ file which need to be translated. grep -rn "TODO: translate(.*)" l18n/ --- l18n/en/ui.json | 5 +++++ l18n/ru/ui.json | 5 +++++ web/mutators.go | 18 +++++++++--------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/l18n/en/ui.json b/l18n/en/ui.json index 8350b05..66e5bfc 100644 --- a/l18n/en/ui.json +++ b/l18n/en/ui.json @@ -25,6 +25,10 @@ "error_text_fetch": "Could not fetch text data", "error_try_again": "Try again", "error_go_back": "Go back to the hypha.", + + "cannot_create": "Cannot create Hypha named", + "delete_empty": "Cannot delete an empty hypha", + "rename_empty": "Cannot rename an empty hypha", "ask_rename": "Rename %s", "rename_to": "New name", @@ -38,6 +42,7 @@ "rename_badname_tip": "Invalid new name. Names cannot contain characters {{.chars}}.", "act_no_media": "No media", + "act_no_media_remove": "no media to remove", "act_no_media_tip": "Cannot remove media because this is not a media hypha", "act_norights": "Not enough rights", "act_notexist": "Does not exist", diff --git a/l18n/ru/ui.json b/l18n/ru/ui.json index 05b3c3a..6c363b6 100644 --- a/l18n/ru/ui.json +++ b/l18n/ru/ui.json @@ -26,6 +26,10 @@ "random_no_hyphae": "В этой вики нет гиф", "random_no_hyphae_tip": "Невозможно отобразить случайную гифу, потому что вики не содержит ни одной гифы", + "cannot_create": "TODO: translate(Cannot create Hypha named)", + "delete_empty": "TODO: translate(Cannot delete an empty hypha)", + "rename_empty": "TODO: translate(Cannot rename an empty hypha)", + "error": "Ошибка", "error_text_fetch": "Не удалось получить текстовые данные", "error_try_again": "Попробуйте ещё раз", @@ -43,6 +47,7 @@ "rename_badname_tip": "Новое название некорректно. Названия не могут содержать символы {{.chars}}.", "act_no_media": "Нет медиа", + "act_no_media_remove": "TODO: translate(no media to remove)", "act_no_media_tip": "Невозможно убрать медиа, потому что медиа нету", "act_norights": "Недостаточно прав", "act_notexist": "Не существует", diff --git a/web/mutators.go b/web/mutators.go index ecabcac..bee8137 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -41,7 +41,7 @@ func handlerRemoveMedia(w http.ResponseWriter, rq *http.Request) { meta = viewutil.MetaFrom(w, rq) ) if !u.CanProceed("remove-media") { - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no rights") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), meta.Lc.Get("ui.act_norights")) return } if rq.Method == "GET" { @@ -50,7 +50,7 @@ func handlerRemoveMedia(w http.ResponseWriter, rq *http.Request) { } switch h := h.(type) { case *hyphae.EmptyHypha, *hyphae.TextualHypha: - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no media to remove") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), meta.Lc.Get("ui.no_media_remove")) return case *hyphae.MediaHypha: if err := shroom.RemoveMedia(u, h); err != nil { @@ -71,15 +71,14 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) { if !u.CanProceed("delete") { log.Printf("%s has no rights to delete ‘%s’\n", u.Name, h.CanonicalName()) - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), meta.Lc.Get("ui.act_norights")) return } switch h.(type) { case *hyphae.EmptyHypha: log.Printf("%s tries to delete empty hypha ‘%s’\n", u.Name, h.CanonicalName()) - // TODO: localize - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), meta.Lc.Get("ui.delete_empty")) return } @@ -108,13 +107,13 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) { switch h.(type) { case *hyphae.EmptyHypha: log.Printf("%s tries to rename empty hypha ‘%s’", u.Name, h.CanonicalName()) - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot rename an empty hypha") // TODO: localize + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), lc.Get("ui.rename_empty")) return } if !u.CanProceed("rename") { log.Printf("%s has no rights to rename ‘%s’\n", u.Name, h.CanonicalName()) - viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), lc.Get("ui.act_norights")) return } @@ -198,10 +197,11 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { w.WriteHeader(http.StatusConflict) viewutil.WriteBase(meta, "Error", fmt.Sprintf( - `<main class="main-width"><p>Cannot create Hypha named %[1]s; <a href="%[1]s">Name already taken.</a></p></main>`, + `<main class="main-width"><p>%[1]s %[2]s; <a href="%[2]s">%[3]s.</a></p></main>`, + meta.Lc.Get("ui.cannot_create"), hyphaName, + meta.Lc.Get("ui.rename_taken"), ), - // ToDo localize ) return } -- 2.34.5
+ "cannot_create": "Cannot create Hypha named", Do not capitalize. + "cannot_create": "TODO: translate(Cannot create Hypha named)", That would be: Нельзя создать гифу, которая называется + "delete_empty": "TODO: translate(Cannot delete an empty hypha)", That would be: Нельзя удалить пустую гифу + "rename_empty": "TODO: translate(Cannot rename an empty hypha)", That would be: Нельзя переименовать пустую гифу