From 88ce77625bb7faf36a415678318599a0812ac889 Mon Sep 17 00:00:00 2001 From: Timur Ismagilov Date: Tue, 11 Jun 2024 02:02:16 +0300 Subject: [PATCH] Migrate templates from hypview: delete, edit, start empty and existing WIP The delete media view was removed, I didn't even know it still existed as a GET. A rudiment. --- categories/view_card.html | 37 ----- hypview/hypview.go | 133 ++---------------- hypview/readers.qtpl | 64 --------- hypview/view_remove_media.html | 22 --- internal/tree/tree.go | 3 +- web/mutators.go | 123 +++++++++------- web/pages.go | 71 ++++++++-- web/readers.go | 87 +++++++----- web/static/default.css | 8 +- .../views/hypha-delete.html | 0 .../views/hypha-edit.html | 0 .../views/hypha-empty.html | 0 web/views/hypha.html | 98 +++++++++++++ 13 files changed, 302 insertions(+), 344 deletions(-) delete mode 100644 hypview/view_remove_media.html rename hypview/view_delete.html => web/views/hypha-delete.html (100%) rename hypview/view_edit.html => web/views/hypha-edit.html (100%) rename hypview/view_empty_hypha.html => web/views/hypha-empty.html (100%) create mode 100644 web/views/hypha.html diff --git a/categories/view_card.html b/categories/view_card.html index f2ea7c8..e69de29 100644 --- a/categories/view_card.html +++ b/categories/view_card.html @@ -1,37 +0,0 @@ -{{define "category card"}} -{{if or .GivenPermissionToModify (len .Categories)}} - {{$hyphaName := .HyphaName}} - {{$givenPermission := .GivenPermissionToModify}} - -{{end}}{{end}} \ No newline at end of file diff --git a/hypview/hypview.go b/hypview/hypview.go index 55d5763..5ec43f1 100644 --- a/hypview/hypview.go +++ b/hypview/hypview.go @@ -4,7 +4,7 @@ import ( "embed" "github.com/bouncepaw/mycorrhiza/internal/backlinks" "github.com/bouncepaw/mycorrhiza/internal/cfg" - viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil" + "github.com/bouncepaw/mycorrhiza/web/viewutil" "html/template" "log" "strings" @@ -14,57 +14,6 @@ var ( //go:embed *.html fs embed.FS ruTranslation = ` -{{define "editing hypha"}}Редактирование {{beautifulName .}}{{end}} -{{define "editing [[hypha]]"}}Редактирование {{beautifulName .}}{{end}} -{{define "creating [[hypha]]"}}Создание {{beautifulName .}}{{end}} -{{define "you're creating a new hypha"}}Вы создаёте новую гифу.{{end}} -{{define "describe your changes"}}Опишите ваши правки{{end}} -{{define "save"}}Сохранить{{end}} -{{define "preview"}}Предпросмотр{{end}} -{{define "previewing hypha"}}Предпросмотр «{{beautifulName .}}»{{end}} -{{define "preview tip"}}Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:{{end}} - -{{define "markup"}}Разметка{{end}} -{{define "link"}}Ссылка{{end}} -{{define "link title"}}Текст{{end}} -{{define "heading"}}Заголовок{{end}} -{{define "bold"}}Жирный{{end}} -{{define "italic"}}Курсив{{end}} -{{define "highlight"}}Выделение{{end}} -{{define "underline"}}Подчеркивание{{end}} -{{define "mono"}}Моноширинный{{end}} -{{define "super"}}Надстрочный{{end}} -{{define "sub"}}Подстрочный{{end}} -{{define "strike"}}Зачёркнутый{{end}} -{{define "rocket"}}Ссылка-ракета{{end}} -{{define "transclude"}}Трансклюзия{{end}} -{{define "hr"}}Гориз. черта{{end}} -{{define "code"}}Код-блок{{end}} -{{define "bullets"}}Маркир. список{{end}} -{{define "numbers"}}Нумер. список{{end}} -{{define "mycomarkup help"}}Подробнее о Микоразметке{{end}} -{{define "actions"}}Действия{{end}} -{{define "current date"}}Текущая дата{{end}} -{{define "current time"}}Текущее время{{end}} -{{define "selflink"}}Ссылка на вас{{end}} - -{{define "empty heading"}}Эта гифа не существует{{end}} -{{define "empty no rights"}}У вас нет прав для создания новых гиф. Вы можете:{{end}} -{{define "empty log in"}}Войти в свою учётную запись, если она у вас есть{{end}} -{{define "empty register"}}Создать новую учётную запись{{end}} -{{define "write a text"}}Написать текст{{end}} -{{define "write a text tip"}}Напишите заметку, дневник, статью, рассказ или иной текст с помощью Микоразметки. Сохраняется полная история правок документа.{{end}} -{{define "write a text writing conventions"}}Не забывайте следовать правилам оформления этой вики, если они имеются.{{end}} -{{define "write a text btn"}}Создать{{end}} -{{define "upload a media"}}Загрузить медиа{{end}} -{{define "upload a media tip"}}Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные можно только скачать и просмотреть локально. Позже вы можете дописать пояснение к этому медиа.{{end}} -{{define "upload a media btn"}}Загрузить{{end}} - -{{define "delete hypha?"}}Удалить {{beautifulName .}}?{{end}} -{{define "delete [[hypha]]?"}}Удалить {{beautifulName .}}?{{end}} -{{define "want to delete?"}}Вы действительно хотите удалить эту гифу?{{end}} -{{define "delete tip"}}Нельзя отменить удаление гифы, но её история останется доступной.{{end}} - {{define "rename hypha?"}}Переименовать {{beautifulName .}}?{{end}} {{define "rename [[hypha]]?"}}Переименовать {{beautifulName .}}?{{end}} {{define "new name"}}Новое название:{{end}} @@ -72,59 +21,26 @@ var ( {{define "rename tip"}}Переименовывайте аккуратно. Документация на английском.{{end}} {{define "leave redirection"}}Оставить перенаправление{{end}} -{{define "remove media from x?"}}Убрать медиа у {{beautifulName .}}?{{end}} -{{define "remove media from [[x]]?"}}Убрать медиа у {{beautifulName .MatchedHyphaName}}?{{end}} -{{define "remove media for real?"}}Вы точно хотите убрать медиа у гифы «{{beautifulName .MatchedHyphaName}}»?{{end}} + ` - chainNaviTitle viewutil2.Chain - chainEditHypha viewutil2.Chain - chainEmptyHypha viewutil2.Chain - chainDeleteHypha viewutil2.Chain - chainRenameHypha viewutil2.Chain - chainRemoveMedia viewutil2.Chain + chainNaviTitle viewutil.Chain + chainRenameHypha viewutil.Chain ) func Init() { - chainNaviTitle = viewutil2.CopyEnRuWith(fs, "view_navititle.html", "") - chainEditHypha = viewutil2.CopyEnRuWith(fs, "view_edit.html", ruTranslation) - chainEmptyHypha = viewutil2.CopyEnRuWith(fs, "view_empty_hypha.html", ruTranslation) - chainDeleteHypha = viewutil2.CopyEnRuWith(fs, "view_delete.html", ruTranslation) - chainRenameHypha = viewutil2.CopyEnRuWith(fs, "view_rename.html", ruTranslation) - chainRemoveMedia = viewutil2.CopyEnRuWith(fs, "view_remove_media.html", ruTranslation) -} - -type editData struct { - *viewutil2.BaseData - HyphaName string - IsNew bool - Content string - Message string - Preview template.HTML -} - -func EditHypha(meta viewutil2.Meta, hyphaName string, isNew bool, content string, message string, preview template.HTML) { - viewutil2.ExecutePage(meta, chainEditHypha, editData{ - BaseData: &viewutil2.BaseData{ - Addr: "/edit/" + hyphaName, - EditScripts: cfg.EditScripts, - }, - HyphaName: hyphaName, - IsNew: isNew, - Content: content, - Message: message, - Preview: preview, - }) + chainNaviTitle = viewutil.CopyEnRuWith(fs, "view_navititle.html", "") + chainRenameHypha = viewutil.CopyEnRuWith(fs, "view_rename.html", ruTranslation) } type renameData struct { - *viewutil2.BaseData + *viewutil.BaseData HyphaName string LeaveRedirectionDefault bool } -func RenameHypha(meta viewutil2.Meta, hyphaName string) { - viewutil2.ExecutePage(meta, chainRenameHypha, renameData{ - BaseData: &viewutil2.BaseData{ +func RenameHypha(meta viewutil.Meta, hyphaName string) { + viewutil.ExecutePage(meta, chainRenameHypha, renameData{ + BaseData: &viewutil.BaseData{ Addr: "/rename/" + hyphaName, }, HyphaName: hyphaName, @@ -132,37 +48,14 @@ func RenameHypha(meta viewutil2.Meta, hyphaName string) { }) } -type deleteRemoveMediaData struct { - *viewutil2.BaseData - HyphaName string -} - -func DeleteHypha(meta viewutil2.Meta, hyphaName string) { - viewutil2.ExecutePage(meta, chainDeleteHypha, deleteRemoveMediaData{ - BaseData: &viewutil2.BaseData{ - Addr: "/delete/" + hyphaName, - }, - HyphaName: hyphaName, - }) -} - -func RemoveMedia(meta viewutil2.Meta, hyphaName string) { - viewutil2.ExecutePage(meta, chainRemoveMedia, deleteRemoveMediaData{ - BaseData: &viewutil2.BaseData{ - Addr: "/remove-media/" + hyphaName, - }, - HyphaName: hyphaName, - }) -} - type emptyHyphaData struct { - Meta viewutil2.Meta + Meta viewutil.Meta HyphaName string AllowRegistration bool UseAuth bool } -func EmptyHypha(meta viewutil2.Meta, hyphaName string) string { +func EmptyHypha(meta viewutil.Meta, hyphaName string) string { var buf strings.Builder if err := chainEmptyHypha.Get(meta).ExecuteTemplate(&buf, "empty hypha card", emptyHyphaData{ Meta: meta, @@ -182,7 +75,7 @@ type naviTitleData struct { HomeHypha string } -func NaviTitle(meta viewutil2.Meta, hyphaName string) string { +func NaviTitle(meta viewutil.Meta, hyphaName string) template.HTML { parts, partsWithParents := naviTitleify(hyphaName) var buf strings.Builder err := chainNaviTitle.Get(meta).ExecuteTemplate(&buf, "navititle", naviTitleData{ diff --git a/hypview/readers.qtpl b/hypview/readers.qtpl index 922cc68..136e42d 100644 --- a/hypview/readers.qtpl +++ b/hypview/readers.qtpl @@ -82,66 +82,6 @@ {% endfunc %} -If `contents` == "", a helpful message is shown instead. - -If you rename .prevnext, change the docs too. -{% func Hypha(meta viewutil.Meta, h hyphae.Hypha, contents string) %} -{% code - subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName()) - lc := meta.Lc -%} -
-
- {% if meta.U.CanProceed("edit") %} - - {% endif %} - - {% if cfg.UseAuth && util.IsProfileName(h.CanonicalName()) && meta.U.Name == strings.TrimPrefix(h.CanonicalName(), cfg.UserHypha + "/") %} - - {% if meta.U.Group == "admin" %} - - {% endif %} - {% endif %} - - {%s= NaviTitle(meta, h.CanonicalName()) %} - {% switch h.(type) %} - {% case *hyphae.EmptyHypha %} - {%s= EmptyHypha(meta, h.CanonicalName()) %} - {% default %} - {%s= contents %} - {% endswitch %} -
-
- {% if prevHyphaName != "" %} - - {% endif %} - {% if nextHyphaName != "" %} - - {% endif %} -
-{% if strings.TrimSpace(subhyphae) != "" %} -
-

{%s lc.Get("ui.subhyphae") %}

- -
-{% endif %} -
- {%= hyphaInfo(meta, h) %} -
-
-{%s= categories.CategoryCard(meta, h.CanonicalName()) %} -{%= viewScripts() %} -{% endfunc %} {% func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) %}
@@ -151,10 +91,6 @@ If you rename .prevnext, change the docs too. {%s= contents %}
-{%= viewScripts() %} -{% endfunc %} - -{% func viewScripts() %} {% for _, scriptPath := range cfg.ViewScripts %} {% endfor %} diff --git a/hypview/view_remove_media.html b/hypview/view_remove_media.html deleted file mode 100644 index 3edd8d8..0000000 --- a/hypview/view_remove_media.html +++ /dev/null @@ -1,22 +0,0 @@ -{{define "remove media from x?"}}Remove media from {{beautifulName .}}?{{end}} -{{define "title"}}{{template "remove media from x?" .HyphaName}}{{end}} -{{define "body"}} -
- -
-{{end}} \ No newline at end of file diff --git a/internal/tree/tree.go b/internal/tree/tree.go index a5aa1b2..05d9ad8 100644 --- a/internal/tree/tree.go +++ b/internal/tree/tree.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/util" + "html/template" "io" "path" "sort" @@ -11,7 +12,7 @@ import ( ) // Tree returns the subhypha matrix as HTML and names of the next and previous hyphae (or empty strings). -func Tree(hyphaName string) (childrenHTML, prev, next string) { +func Tree(hyphaName string) (childrenHTML template.HTML, prev, next string) { var ( root = child{hyphaName, true, make([]child, 0)} descendantPrefix = hyphaName + "/" diff --git a/web/mutators.go b/web/mutators.go index 5502356..75e13ae 100644 --- a/web/mutators.go +++ b/web/mutators.go @@ -2,10 +2,10 @@ package web import ( "git.sr.ht/~bouncepaw/mycomarkup/v5" - hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" - shroom2 "github.com/bouncepaw/mycorrhiza/internal/shroom" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" + "github.com/bouncepaw/mycorrhiza/internal/shroom" "github.com/bouncepaw/mycorrhiza/internal/user" - viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil" + "github.com/bouncepaw/mycorrhiza/web/viewutil" "html/template" "log" "net/http" @@ -24,7 +24,7 @@ func initMutators(r *mux.Router) { 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") + r.PathPrefix("/remove-media/").HandlerFunc(handlerRemoveMedia).Methods("POST") r.PathPrefix("/upload-binary/").HandlerFunc(handlerUploadBinary) r.PathPrefix("/upload-text/").HandlerFunc(handlerUploadText) } @@ -35,24 +35,20 @@ func handlerRemoveMedia(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( u = user.FromRequest(rq) - h = hyphae2.ByName(util.HyphaNameFromRq(rq, "remove-media")) - meta = viewutil2.MetaFrom(w, rq) + h = hyphae.ByName(util.HyphaNameFromRq(rq, "remove-media")) + meta = viewutil.MetaFrom(w, rq) ) if !u.CanProceed("remove-media") { - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no rights") - return - } - if rq.Method == "GET" { - hypview.RemoveMedia(viewutil2.MetaFrom(w, rq), h.CanonicalName()) + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no rights") return } switch h := h.(type) { - case *hyphae2.EmptyHypha, *hyphae2.TextualHypha: - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no media to remove") + case *hyphae.EmptyHypha, *hyphae.TextualHypha: + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no media to remove") return - case *hyphae2.MediaHypha: - if err := shroom2.RemoveMedia(u, h); err != nil { - viewutil2.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error()) + case *hyphae.MediaHypha: + if err := shroom.RemoveMedia(u, h); err != nil { + viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error()) return } } @@ -63,32 +59,36 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( u = user.FromRequest(rq) - h = hyphae2.ByName(util.HyphaNameFromRq(rq, "delete")) - meta = viewutil2.MetaFrom(w, rq) + h = hyphae.ByName(util.HyphaNameFromRq(rq, "delete")) + meta = viewutil.MetaFrom(w, rq) ) if !u.CanProceed("delete") { log.Printf("%s has no rights to delete ‘%s’\n", u.Name, h.CanonicalName()) - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") return } switch h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: log.Printf("%s tries to delete empty hypha ‘%s’\n", u.Name, h.CanonicalName()) // TODO: localize - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot delete an empty hypha") return } if rq.Method == "GET" { - hypview.DeleteHypha(meta, h.CanonicalName()) + _ = pageHyphaDelete.RenderTo( + viewutil.MetaFrom(w, rq), + map[string]any{ + "HyphaName": h.CanonicalName(), + }) return } - if err := shroom2.Delete(u, h.(hyphae2.ExistingHypha)); err != nil { + if err := shroom.Delete(u, h.(hyphae.ExistingHypha)); err != nil { log.Println(err) - viewutil2.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error()) + viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error()) return } http.Redirect(w, rq, "/hypha/"+h.CanonicalName(), http.StatusSeeOther) @@ -99,25 +99,25 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) { var ( u = user.FromRequest(rq) lc = l18n.FromRequest(rq) - h = hyphae2.ByName(util.HyphaNameFromRq(rq, "rename")) - meta = viewutil2.MetaFrom(w, rq) + h = hyphae.ByName(util.HyphaNameFromRq(rq, "rename")) + meta = viewutil.MetaFrom(w, rq) ) switch h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: log.Printf("%s tries to rename empty hypha ‘%s’", u.Name, h.CanonicalName()) - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot rename an empty hypha") // TODO: localize + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "Cannot rename an empty hypha") // TODO: localize return } if !u.CanProceed("rename") { log.Printf("%s has no rights to rename ‘%s’\n", u.Name, h.CanonicalName()) - viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") + viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "No rights") return } var ( - oldHypha = h.(hyphae2.ExistingHypha) + oldHypha = h.(hyphae.ExistingHypha) newName = util.CanonicalName(rq.PostFormValue("new-name")) recursive = rq.PostFormValue("recursive") == "true" leaveRedirections = rq.PostFormValue("redirection") == "true" @@ -128,9 +128,9 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) { return } - if err := shroom2.Rename(oldHypha, newName, recursive, leaveRedirections, u); err != nil { + if err := shroom.Rename(oldHypha, newName, recursive, leaveRedirections, u); err != nil { log.Printf("%s tries to rename ‘%s’: %s", u.Name, oldHypha.CanonicalName(), err.Error()) - viewutil2.HttpErr(meta, http.StatusForbidden, oldHypha.CanonicalName(), lc.Get(err.Error())) // TODO: localize + viewutil.HttpErr(meta, http.StatusForbidden, oldHypha.CanonicalName(), lc.Get(err.Error())) // TODO: localize return } http.Redirect(w, rq, "/hypha/"+newName, http.StatusSeeOther) @@ -142,33 +142,41 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) { var ( u = user.FromRequest(rq) lc = l18n.FromRequest(rq) - meta = viewutil2.MetaFrom(w, rq) + meta = viewutil.MetaFrom(w, rq) hyphaName = util.HyphaNameFromRq(rq, "edit") - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) isNew bool content string err error ) - if err := shroom2.CanEdit(u, h, lc); err != nil { - viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) + if err := shroom.CanEdit(u, h, lc); err != nil { + viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) return } switch h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: isNew = true default: - content, err = hyphae2.FetchMycomarkupFile(h) + content, err = hyphae.FetchMycomarkupFile(h) if err != nil { log.Println(err) - viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, lc.Get("ui.error_text_fetch")) + viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, lc.Get("ui.error_text_fetch")) return } } - hypview.EditHypha(meta, hyphaName, isNew, content, "", "") + _ = pageHyphaEdit.RenderTo( + viewutil.MetaFrom(w, rq), + map[string]any{ + "HyphaName": hyphaName, + "Content": content, + "IsNew": isNew, + "Message": "", + "Preview": "", + }) } // handlerUploadText uploads a new text part for the hypha. @@ -176,11 +184,11 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( u = user.FromRequest(rq) - meta = viewutil2.MetaFrom(w, rq) + meta = viewutil.MetaFrom(w, rq) hyphaName = util.HyphaNameFromRq(rq, "upload-text") - h = hyphae2.ByName(hyphaName) - _, isNew = h.(*hyphae2.EmptyHypha) + h = hyphae.ByName(hyphaName) + _, isNew = h.(*hyphae.EmptyHypha) textData = rq.PostFormValue("text") action = rq.PostFormValue("action") @@ -190,12 +198,21 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) { if action == "preview" { ctx, _ := mycocontext.ContextFromStringInput(textData, mycoopts.MarkupOptions(hyphaName)) preview := template.HTML(mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))) - hypview.EditHypha(meta, hyphaName, isNew, textData, message, preview) + + _ = pageHyphaEdit.RenderTo( + viewutil.MetaFrom(w, rq), + map[string]any{ + "HyphaName": hyphaName, + "Content": textData, + "IsNew": isNew, + "Message": message, + "Preview": preview, + }) return } - if err := shroom2.UploadText(h, []byte(textData), message, u); err != nil { - viewutil2.HttpErr(meta, http.StatusForbidden, hyphaName, err.Error()) + if err := shroom.UploadText(h, []byte(textData), message, u); err != nil { + viewutil.HttpErr(meta, http.StatusForbidden, hyphaName, err.Error()) return } http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) @@ -207,17 +224,17 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { rq.ParseMultipartForm(10 << 20) // Set upload limit var ( hyphaName = util.HyphaNameFromRq(rq, "upload-binary") - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) lc = l18n.FromRequest(rq) file, handler, err = rq.FormFile("binary") - meta = viewutil2.MetaFrom(w, rq) + meta = viewutil.MetaFrom(w, rq) ) if err != nil { - viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) + viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) } - if err := shroom2.CanAttach(u, h, lc); err != nil { - viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) + if err := shroom.CanAttach(u, h, lc); err != nil { + viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) } // If file is not passed: @@ -234,8 +251,8 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) { mime = handler.Header.Get("Content-Type") ) - if err := shroom2.UploadBinary(h, mime, file, u); err != nil { - viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) + if err := shroom.UploadBinary(h, mime, file, u); err != nil { + viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error()) return } http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther) diff --git a/web/pages.go b/web/pages.go index dc9f8aa..57b1879 100644 --- a/web/pages.go +++ b/web/pages.go @@ -3,23 +3,23 @@ package web import ( "embed" "github.com/bouncepaw/mycorrhiza/web/newtmpl" - viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil" + "github.com/bouncepaw/mycorrhiza/web/viewutil" ) //go:embed views/*.html var fs embed.FS var pageOrphans, pageBacklinks, pageUserList, pageChangePassword *newtmpl.Page - -var panelChain, listChain, newUserChain, editUserChain, deleteUserChain viewutil2.Chain +var pageHyphaDelete, pageHyphaEdit, pageHyphaEmpty, pageHypha *newtmpl.Page +var panelChain, listChain, newUserChain, editUserChain, deleteUserChain viewutil.Chain func initPages() { - panelChain = viewutil2.CopyEnRuWith(fs, "views/admin-panel.html", adminTranslationRu) - listChain = viewutil2.CopyEnRuWith(fs, "views/admin-user-list.html", adminTranslationRu) - newUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-new-user.html", adminTranslationRu) - editUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-edit-user.html", adminTranslationRu) - deleteUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-delete-user.html", adminTranslationRu) + panelChain = viewutil.CopyEnRuWith(fs, "views/admin-panel.html", adminTranslationRu) + listChain = viewutil.CopyEnRuWith(fs, "views/admin-user-list.html", adminTranslationRu) + newUserChain = viewutil.CopyEnRuWith(fs, "views/admin-new-user.html", adminTranslationRu) + editUserChain = viewutil.CopyEnRuWith(fs, "views/admin-edit-user.html", adminTranslationRu) + deleteUserChain = viewutil.CopyEnRuWith(fs, "views/admin-delete-user.html", adminTranslationRu) pageOrphans = newtmpl.NewPage(fs, "views/orphans.html", map[string]string{ "orphaned hyphae": "Гифы-сироты", @@ -45,4 +45,59 @@ func initPages() { "password": "Пароль", "submit": "Поменять", }) + pageHyphaDelete = newtmpl.NewPage(fs, "views/hypha-delete.html", map[string]string{ + "delete hypha?": "Удалить {{beautifulName .}}?", + "delete [[hypha]]?": "Удалить {{beautifulName .}}?", + "want to delete?": "Вы действительно хотите удалить эту гифу?", + "delete tip": "Нельзя отменить удаление гифы, но её история останется доступной.", + }) + pageHyphaEdit = newtmpl.NewPage(fs, "views/hypha-edit.html", map[string]string{ + "editing hypha": `Редактирование {{beautifulName .}}`, + "editing [[hypha]]": `Редактирование {{beautifulName .}}`, + "creating [[hypha]]": `Создание {{beautifulName .}}`, + "you're creating a new hypha": `Вы создаёте новую гифу.`, + "describe your changes": `Опишите ваши правки`, + "save": `Сохранить`, + "preview": `Предпросмотр`, + "previewing hypha": `Предпросмотр «{{beautifulName .}}»`, + "preview tip": `Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:`, + + "markup": `Разметка`, + "link": `Ссылка`, + "link title": `Текст`, + "heading": `Заголовок`, + "bold": `Жирный`, + "italic": `Курсив`, + "highlight": `Выделение`, + "underline": `Подчеркивание`, + "mono": `Моноширинный`, + "super": `Надстрочный`, + "sub": `Подстрочный`, + "strike": `Зачёркнутый`, + "rocket": `Ссылка-ракета`, + "transclude": `Трансклюзия`, + "hr": `Гориз. черта`, + "code": `Код-блок`, + "bullets": `Маркир. список`, + "numbers": `Нумер. список`, + "mycomarkup help": `Подробнее о Микоразметке`, + "actions": `Действия`, + "current date": `Текущая дата`, + "current time": `Текущее время`, + "selflink": `Ссылка на вас`, + }) + pageHyphaEmpty = newtmpl.NewPage(fs, "views/hypha-empty.html", map[string]string{ + "empty heading": `Эта гифа не существует`, + "empty no rights": `У вас нет прав для создания новых гиф. Вы можете:`, + "empty log in": `Войти в свою учётную запись, если она у вас есть`, + "empty register": `Создать новую учётную запись`, + "write a text": `Написать текст`, + "write a text tip": `Напишите заметку, дневник, статью, рассказ или иной текст с помощью Микоразметки. Сохраняется полная история правок документа.`, + "write a text writing conventions": `Не забывайте следовать правилам оформления этой вики, если они имеются.`, + "write a text btn": `Создать`, + "upload a media": `Загрузить медиа`, + "upload a media tip": `Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные можно только скачать и просмотреть локально. Позже вы можете дописать пояснение к этому медиа.`, + "upload a media btn": `Загрузить`, + }) + pageHypha = newtmpl.NewPage(fs, "views/hypha.html", map[string]string{}) } diff --git a/web/readers.go b/web/readers.go index 27f79fd..16a058c 100644 --- a/web/readers.go +++ b/web/readers.go @@ -4,14 +4,17 @@ import ( "fmt" "git.sr.ht/~bouncepaw/mycomarkup/v5" "github.com/bouncepaw/mycorrhiza/categories" - views2 "github.com/bouncepaw/mycorrhiza/hypview" + "github.com/bouncepaw/mycorrhiza/hypview" "github.com/bouncepaw/mycorrhiza/internal/backlinks" + "github.com/bouncepaw/mycorrhiza/internal/cfg" "github.com/bouncepaw/mycorrhiza/internal/files" - hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae" + "github.com/bouncepaw/mycorrhiza/internal/hyphae" "github.com/bouncepaw/mycorrhiza/internal/mimetype" + "github.com/bouncepaw/mycorrhiza/internal/tree" "github.com/bouncepaw/mycorrhiza/internal/user" "github.com/bouncepaw/mycorrhiza/mycoopts" - viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil" + "github.com/bouncepaw/mycorrhiza/web/viewutil" + "html/template" "io" "log" "net/http" @@ -59,15 +62,15 @@ func handlerMedia(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( hyphaName = util.HyphaNameFromRq(rq, "media") - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) u = user.FromRequest(rq) lc = l18n.FromRequest(rq) ) util.HTTP200Page(w, - viewutil2.Base( - viewutil2.MetaFrom(w, rq), + viewutil.Base( + viewutil.MetaFrom(w, rq), lc.Get("ui.media_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}), - views2.MediaMenu(rq, h, u), + hypview.MediaMenu(rq, h, u), map[string]string{}, )) } @@ -85,11 +88,11 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) { } var ( hyphaName = util.CanonicalName(slug) - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) ) w.Header().Set("Content-Type", "text/plain; charset=utf-8") switch h := h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") var textContents, err = history.FileAtRevision(mycoFilePath, revHash) @@ -102,7 +105,7 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) { log.Printf("Serving text of ‘%s’ from ‘%s’ at revision ‘%s’\n", hyphaName, mycoFilePath, revHash) w.WriteHeader(http.StatusOK) _, _ = io.WriteString(w, textContents) - case hyphae2.ExistingHypha: + case hyphae.ExistingHypha: if !h.HasTextFile() { log.Printf(`Media hypha ‘%s’ has no text`) w.WriteHeader(http.StatusNotFound) @@ -133,16 +136,16 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { } var ( hyphaName = util.CanonicalName(slug) - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) contents = fmt.Sprintf(`

%s

`, lc.Get("ui.revision_no_text")) textContents string err error mycoFilePath string ) switch h := h.(type) { - case hyphae2.ExistingHypha: + case hyphae.ExistingHypha: mycoFilePath = h.TextFilePath() - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco") } textContents, err = history.FileAtRevision(mycoFilePath, revHash) @@ -151,8 +154,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)) } - page := views2.Revision( - viewutil2.MetaFrom(w, rq), + page := hypview.Revision( + viewutil.MetaFrom(w, rq), h, contents, revHash, @@ -161,8 +164,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { w.WriteHeader(http.StatusOK) _, _ = fmt.Fprint( w, - viewutil2.Base( - viewutil2.MetaFrom(w, rq), + viewutil.Base( + viewutil.MetaFrom(w, rq), lc.Get("ui.revision_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}), page, map[string]string{}, @@ -174,8 +177,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) { func handlerText(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) hyphaName := util.HyphaNameFromRq(rq, "text") - switch h := hyphae2.ByName(hyphaName).(type) { - case hyphae2.ExistingHypha: + switch h := hyphae.ByName(hyphaName).(type) { + case hyphae.ExistingHypha: log.Println("Serving", h.TextFilePath()) w.Header().Set("Content-Type", "text/plain; charset=utf-8") http.ServeFile(w, rq, h.TextFilePath()) @@ -186,12 +189,12 @@ func handlerText(w http.ResponseWriter, rq *http.Request) { func handlerBinary(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) hyphaName := util.HyphaNameFromRq(rq, "binary") - switch h := hyphae2.ByName(hyphaName).(type) { - case *hyphae2.EmptyHypha: - case *hyphae2.TextualHypha: + switch h := hyphae.ByName(hyphaName).(type) { + case *hyphae.EmptyHypha: + case *hyphae.TextualHypha: w.WriteHeader(http.StatusNotFound) log.Printf("Textual hypha ‘%s’ has no media, cannot serve\n", h.CanonicalName()) - case *hyphae2.MediaHypha: + case *hyphae.MediaHypha: log.Println("Serving", h.MediaFilePath()) w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath()))) http.ServeFile(w, rq, h.MediaFilePath()) @@ -203,22 +206,23 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { util.PrepareRq(rq) var ( hyphaName = util.HyphaNameFromRq(rq, "page", "hypha") - h = hyphae2.ByName(hyphaName) + h = hyphae.ByName(hyphaName) contents string openGraph string lc = l18n.FromRequest(rq) ) switch h := h.(type) { - case *hyphae2.EmptyHypha: + case *hyphae.EmptyHypha: + // contents = hypview.EmptyHypha() util.HTTP404Page(w, - viewutil2.Base( - viewutil2.MetaFrom(w, rq), + viewutil.Base( + viewutil.MetaFrom(w, rq), util.BeautifulName(hyphaName), - views2.Hypha(viewutil2.MetaFrom(w, rq), h, contents), + hypview.Hypha(viewutil.MetaFrom(w, rq), h, ""), map[string]string{}, openGraph)) - case hyphae2.ExistingHypha: + case hyphae.ExistingHypha: fileContentsT, errT := os.ReadFile(h.TextFilePath()) if errT == nil { ctx, _ := mycocontext.ContextFromStringInput(string(fileContentsT), mycoopts.MarkupOptions(hyphaName)) @@ -228,17 +232,30 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { openGraph = getOpenGraph() } switch h := h.(type) { - case *hyphae2.MediaHypha: + case *hyphae.MediaHypha: contents = mycoopts.Media(h, lc) + contents } + meta := viewutil.MetaFrom(w, rq) category_list := ":" + strings.Join(categories.CategoriesWithHypha(h.CanonicalName()), ":") + ":" + subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.CanonicalName()) + isMyProfile := cfg.UseAuth && util.IsProfileName(h.CanonicalName()) && meta.U.Name == strings.TrimPrefix(h.CanonicalName(), cfg.UserHypha+"/") + _ = pageHypha.RenderTo( + meta, + map[string]any{ + "SubhyphaeHTML": subhyphae, + "PrevHyphaName": prevHyphaName, + "NextHyphaName": nextHyphaName, + "IsMyProfile": isMyProfile, + "NaviTitle": hypview.NaviTitle(meta, h.CanonicalName()), + "Contents": template.HTML(contents), + }) util.HTTP200Page(w, - viewutil2.Base( - viewutil2.MetaFrom(w, rq), + viewutil.Base( + viewutil.MetaFrom(w, rq), util.BeautifulName(hyphaName), - views2.Hypha(viewutil2.MetaFrom(w, rq), h, contents), + hypview.Hypha(viewutil.MetaFrom(w, rq), h, contents), map[string]string{"cats": category_list}, openGraph)) } @@ -248,7 +265,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) { func handlerBacklinks(w http.ResponseWriter, rq *http.Request) { hyphaName := util.HyphaNameFromRq(rq, "backlinks") - _ = pageBacklinks.RenderTo(viewutil2.MetaFrom(w, rq), + _ = pageBacklinks.RenderTo(viewutil.MetaFrom(w, rq), map[string]any{ "Addr": "/backlinks/" + hyphaName, "HyphaName": hyphaName, @@ -257,7 +274,7 @@ func handlerBacklinks(w http.ResponseWriter, rq *http.Request) { } func handlerOrphans(w http.ResponseWriter, rq *http.Request) { - _ = pageOrphans.RenderTo(viewutil2.MetaFrom(w, rq), + _ = pageOrphans.RenderTo(viewutil.MetaFrom(w, rq), map[string]any{ "Addr": "/orphans", "Orphans": backlinks.Orphans(), diff --git a/web/static/default.css b/web/static/default.css index b5b833f..50375c9 100644 --- a/web/static/default.css +++ b/web/static/default.css @@ -108,11 +108,11 @@ main h1:not(.navi-title) {font-size:1.7rem;} blockquote { margin: 0; padding-left: .75rem; } .wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; } /* .wikilink_external { padding-left: 16px; } */ -.wikilink_gopher::before { content: url("/staticatic/icon/gopher-proto.svg"); } -.wikilink_http::before, .wikilink_https::before { content: url("/staticatic/icon/http-proto.svg"); } +.wikilink_gopher::before { content: url("/static/icon/gopher-proto.svg"); } +.wikilink_http::before, .wikilink_https::before { content: url("/static/icon/http-proto.svg"); } /* .wikilink_https { background: transparent url("/static/icon/http-proto.svg") center left no-repeat; } */ -.wikilink_gemini::before { content: url("/staticatic/icon/gemini-proto.svg"); } -.wikilink_mailto::before { content: url("/staticatic/icon/mailto-proto.svg"); } +.wikilink_gemini::before { content: url("/static/icon/gemini-proto.svg"); } +.wikilink_mailto::before { content: url("/static/icon/mailto-proto.svg"); } article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; } main h1 { margin: .5rem 0 0 0; } diff --git a/hypview/view_delete.html b/web/views/hypha-delete.html similarity index 100% rename from hypview/view_delete.html rename to web/views/hypha-delete.html diff --git a/hypview/view_edit.html b/web/views/hypha-edit.html similarity index 100% rename from hypview/view_edit.html rename to web/views/hypha-edit.html diff --git a/hypview/view_empty_hypha.html b/web/views/hypha-empty.html similarity index 100% rename from hypview/view_empty_hypha.html rename to web/views/hypha-empty.html diff --git a/web/views/hypha.html b/web/views/hypha.html new file mode 100644 index 0000000..5721245 --- /dev/null +++ b/web/views/hypha.html @@ -0,0 +1,98 @@ +{{define "body"}} +
+
+ {{if .Meta.U.CanProceed "edit"}} + + {{end}} + + {{if .IsMyProfile}} + + {{if eq .Meta.U.Group "admin"}} + + {{end}} + {{end}} + + {{.NaviTitle}} + {{.Contents}} +
+ +
+ {{if .PrevHyphaName}} + + {{end}} + {{if .NextHyphaName}} + + {{end}} +
+ + {{ if .SubhyphaeHTML }} +
+

{%s lc.Get("ui.subhyphae") %}

+ +
+ {{end}} + +
+ {{hyphaInfo(meta, h)}} +
+
+ {{template "category card" .}} + {{range .ViewScripts}} + {{end}} +{{end}} + +{{define "category card"}} + {{if or .GivenPermissionToModify (len .Categories)}} + {{$hyphaName := .HyphaName}} + {{$givenPermission := .GivenPermissionToModify}} + + {{end}}{{end}}