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.
This commit is contained in:
parent
3755793cb0
commit
88ce77625b
@ -1,37 +0,0 @@
|
|||||||
{{define "category card"}}
|
|
||||||
{{if or .GivenPermissionToModify (len .Categories)}}
|
|
||||||
{{$hyphaName := .HyphaName}}
|
|
||||||
{{$givenPermission := .GivenPermissionToModify}}
|
|
||||||
<aside class="layout-card categories-card">
|
|
||||||
<h2 class="layout-card__title">{{block `categories` .}}Categories{{end}}</h2>
|
|
||||||
<ul class="categories-card__entries">
|
|
||||||
{{range .Categories}}
|
|
||||||
<li class="categories-card__entry">
|
|
||||||
<a class="categories-card__link" href="/category/{{.}}">{{beautifulName .}}</a>
|
|
||||||
<form method="POST" action="/remove-from-category" class="categories-card__remove-form">
|
|
||||||
<input type="hidden" name="cat" value="{{.}}">
|
|
||||||
<input type="hidden" name="hypha" value="{{$hyphaName}}">
|
|
||||||
<input type="hidden" name="redirect-to" value="/hypha/{{$hyphaName}}">
|
|
||||||
{{if $givenPermission}}
|
|
||||||
<input type="submit" value="x" class="btn categories-card__btn"
|
|
||||||
title="{{block `remove from category title` .}}Remove the hypha from this category{{end}}">
|
|
||||||
{{end}}
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
{{if .GivenPermissionToModify}}
|
|
||||||
<li class="categories-card__entry categories-card__add-to-cat">
|
|
||||||
<form method="POST" action="/add-to-category" class="categories-card__add-form js-add-cat-form">
|
|
||||||
<input type="text" name="cat" id="_cat-name" class="js-add-cat-name" autocomplete="off"
|
|
||||||
placeholder="{{block `placeholder` .}}Category name...{{end}}">
|
|
||||||
<datalist class="js-add-cat-list" id="cat-name-options"></datalist>
|
|
||||||
<input type="hidden" name="hypha" value="{{$hyphaName}}">
|
|
||||||
<input type="hidden" name="redirect-to" value="/hypha/{{$hyphaName}}">
|
|
||||||
<input type="submit" class="btn categories-card__btn" value="+"
|
|
||||||
title="{{block `add to category title` .}}Add the hypha to this category{{end}}">
|
|
||||||
</form>
|
|
||||||
</li>
|
|
||||||
{{end}}
|
|
||||||
</ul>
|
|
||||||
</aside>
|
|
||||||
{{end}}{{end}}
|
|
||||||
@ -4,7 +4,7 @@ import (
|
|||||||
"embed"
|
"embed"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
|
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||||||
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
|
"github.com/bouncepaw/mycorrhiza/web/viewutil"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
@ -14,57 +14,6 @@ var (
|
|||||||
//go:embed *.html
|
//go:embed *.html
|
||||||
fs embed.FS
|
fs embed.FS
|
||||||
ruTranslation = `
|
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 "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"}}<a href="/help/en/mycomarkup" class="shy-link">Подробнее</a> о Микоразметке{{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"}}Напишите заметку, дневник, статью, рассказ или иной текст с помощью <a href="/help/en/mycomarkup" class="shy-link">Микоразметки</a>. Сохраняется полная история правок документа.{{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]]?"}}Удалить <a href="/hypha/{{.}}">{{beautifulName .}}</a>?{{end}}
|
|
||||||
{{define "want to delete?"}}Вы действительно хотите удалить эту гифу?{{end}}
|
|
||||||
{{define "delete tip"}}Нельзя отменить удаление гифы, но её история останется доступной.{{end}}
|
|
||||||
|
|
||||||
{{define "rename hypha?"}}Переименовать {{beautifulName .}}?{{end}}
|
{{define "rename hypha?"}}Переименовать {{beautifulName .}}?{{end}}
|
||||||
{{define "rename [[hypha]]?"}}Переименовать <a href="/hypha/{{.}}">{{beautifulName .}}</a>?{{end}}
|
{{define "rename [[hypha]]?"}}Переименовать <a href="/hypha/{{.}}">{{beautifulName .}}</a>?{{end}}
|
||||||
{{define "new name"}}Новое название:{{end}}
|
{{define "new name"}}Новое название:{{end}}
|
||||||
@ -72,59 +21,26 @@ var (
|
|||||||
{{define "rename tip"}}Переименовывайте аккуратно. <a href="/help/en/rename">Документация на английском.</a>{{end}}
|
{{define "rename tip"}}Переименовывайте аккуратно. <a href="/help/en/rename">Документация на английском.</a>{{end}}
|
||||||
{{define "leave redirection"}}Оставить перенаправление{{end}}
|
{{define "leave redirection"}}Оставить перенаправление{{end}}
|
||||||
|
|
||||||
{{define "remove media from x?"}}Убрать медиа у {{beautifulName .}}?{{end}}
|
|
||||||
{{define "remove media from [[x]]?"}}Убрать медиа у <a href="/hypha/{{.MatchedHyphaName}}">{{beautifulName .MatchedHyphaName}}</a>?{{end}}
|
|
||||||
{{define "remove media for real?"}}Вы точно хотите убрать медиа у гифы «{{beautifulName .MatchedHyphaName}}»?{{end}}
|
|
||||||
`
|
`
|
||||||
chainNaviTitle viewutil2.Chain
|
chainNaviTitle viewutil.Chain
|
||||||
chainEditHypha viewutil2.Chain
|
chainRenameHypha viewutil.Chain
|
||||||
chainEmptyHypha viewutil2.Chain
|
|
||||||
chainDeleteHypha viewutil2.Chain
|
|
||||||
chainRenameHypha viewutil2.Chain
|
|
||||||
chainRemoveMedia viewutil2.Chain
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init() {
|
func Init() {
|
||||||
chainNaviTitle = viewutil2.CopyEnRuWith(fs, "view_navititle.html", "")
|
chainNaviTitle = viewutil.CopyEnRuWith(fs, "view_navititle.html", "")
|
||||||
chainEditHypha = viewutil2.CopyEnRuWith(fs, "view_edit.html", ruTranslation)
|
chainRenameHypha = viewutil.CopyEnRuWith(fs, "view_rename.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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type renameData struct {
|
type renameData struct {
|
||||||
*viewutil2.BaseData
|
*viewutil.BaseData
|
||||||
HyphaName string
|
HyphaName string
|
||||||
LeaveRedirectionDefault bool
|
LeaveRedirectionDefault bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func RenameHypha(meta viewutil2.Meta, hyphaName string) {
|
func RenameHypha(meta viewutil.Meta, hyphaName string) {
|
||||||
viewutil2.ExecutePage(meta, chainRenameHypha, renameData{
|
viewutil.ExecutePage(meta, chainRenameHypha, renameData{
|
||||||
BaseData: &viewutil2.BaseData{
|
BaseData: &viewutil.BaseData{
|
||||||
Addr: "/rename/" + hyphaName,
|
Addr: "/rename/" + hyphaName,
|
||||||
},
|
},
|
||||||
HyphaName: 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 {
|
type emptyHyphaData struct {
|
||||||
Meta viewutil2.Meta
|
Meta viewutil.Meta
|
||||||
HyphaName string
|
HyphaName string
|
||||||
AllowRegistration bool
|
AllowRegistration bool
|
||||||
UseAuth bool
|
UseAuth bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func EmptyHypha(meta viewutil2.Meta, hyphaName string) string {
|
func EmptyHypha(meta viewutil.Meta, hyphaName string) string {
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
if err := chainEmptyHypha.Get(meta).ExecuteTemplate(&buf, "empty hypha card", emptyHyphaData{
|
if err := chainEmptyHypha.Get(meta).ExecuteTemplate(&buf, "empty hypha card", emptyHyphaData{
|
||||||
Meta: meta,
|
Meta: meta,
|
||||||
@ -182,7 +75,7 @@ type naviTitleData struct {
|
|||||||
HomeHypha string
|
HomeHypha string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NaviTitle(meta viewutil2.Meta, hyphaName string) string {
|
func NaviTitle(meta viewutil.Meta, hyphaName string) template.HTML {
|
||||||
parts, partsWithParents := naviTitleify(hyphaName)
|
parts, partsWithParents := naviTitleify(hyphaName)
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
err := chainNaviTitle.Get(meta).ExecuteTemplate(&buf, "navititle", naviTitleData{
|
err := chainNaviTitle.Get(meta).ExecuteTemplate(&buf, "navititle", naviTitleData{
|
||||||
|
|||||||
@ -82,66 +82,6 @@
|
|||||||
</main>
|
</main>
|
||||||
{% endfunc %}
|
{% 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
|
|
||||||
%}
|
|
||||||
<main class="main-width">
|
|
||||||
<section id="hypha">
|
|
||||||
{% if meta.U.CanProceed("edit") %}
|
|
||||||
<div class="btn btn_navititle">
|
|
||||||
<a class="btn__link_navititle" href="/edit/{%s h.CanonicalName() %}">{%s lc.Get("ui.edit_link") %}</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if cfg.UseAuth && util.IsProfileName(h.CanonicalName()) && meta.U.Name == strings.TrimPrefix(h.CanonicalName(), cfg.UserHypha + "/") %}
|
|
||||||
<div class="btn btn_navititle">
|
|
||||||
<a class="btn__link_navititle" href="/logout">{%s lc.Get("ui.logout_link") %}</a>
|
|
||||||
</div>
|
|
||||||
{% if meta.U.Group == "admin" %}
|
|
||||||
<div class="btn btn_navititle">
|
|
||||||
<a class="btn__link_navititle" href="/admin">{%s lc.Get("ui.admin_panel") %}<a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{%s= NaviTitle(meta, h.CanonicalName()) %}
|
|
||||||
{% switch h.(type) %}
|
|
||||||
{% case *hyphae.EmptyHypha %}
|
|
||||||
{%s= EmptyHypha(meta, h.CanonicalName()) %}
|
|
||||||
{% default %}
|
|
||||||
{%s= contents %}
|
|
||||||
{% endswitch %}
|
|
||||||
</section>
|
|
||||||
<section class="prevnext">
|
|
||||||
{% if prevHyphaName != "" %}
|
|
||||||
<a class="prevnext__el prevnext__prev" href="/hypha/{%s prevHyphaName %}" rel="prev">← {%s util.BeautifulName(path.Base(prevHyphaName)) %}</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if nextHyphaName != "" %}
|
|
||||||
<a class="prevnext__el prevnext__next" href="/hypha/{%s nextHyphaName %}" rel="next">{%s util.BeautifulName(path.Base(nextHyphaName)) %} →</a>
|
|
||||||
{% endif %}
|
|
||||||
</section>
|
|
||||||
{% if strings.TrimSpace(subhyphae) != "" %}
|
|
||||||
<section class="subhyphae">
|
|
||||||
<h2 class="subhyphae__title">{%s lc.Get("ui.subhyphae") %}</h2>
|
|
||||||
<nav class="subhyphae__nav">
|
|
||||||
<ul class="subhyphae__list">
|
|
||||||
{%s= subhyphae %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</section>
|
|
||||||
{% endif %}
|
|
||||||
<section id="hypha-bottom">
|
|
||||||
{%= hyphaInfo(meta, h) %}
|
|
||||||
</section>
|
|
||||||
</main>
|
|
||||||
{%s= categories.CategoryCard(meta, h.CanonicalName()) %}
|
|
||||||
{%= viewScripts() %}
|
|
||||||
{% endfunc %}
|
|
||||||
|
|
||||||
{% func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) %}
|
{% func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) %}
|
||||||
<main class="main-width">
|
<main class="main-width">
|
||||||
@ -151,10 +91,6 @@ If you rename .prevnext, change the docs too.
|
|||||||
{%s= contents %}
|
{%s= contents %}
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
{%= viewScripts() %}
|
|
||||||
{% endfunc %}
|
|
||||||
|
|
||||||
{% func viewScripts() %}
|
|
||||||
{% for _, scriptPath := range cfg.ViewScripts %}
|
{% for _, scriptPath := range cfg.ViewScripts %}
|
||||||
<script src="{%s scriptPath %}"></script>
|
<script src="{%s scriptPath %}"></script>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -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"}}
|
|
||||||
<main class="main-width">
|
|
||||||
<form class="modal" action="/remove-media/{{.HyphaName}}" method="post">
|
|
||||||
<fieldset class="modal__fieldset">
|
|
||||||
<legend class="modal__title">
|
|
||||||
{{block "remove media from [[x]]?" .}}Remove media from <a href="/hypha/{{.HyphaName}}">{{beautifulName .HyphaName}}</a>?{{end}}
|
|
||||||
</legend>
|
|
||||||
<p class="modal__confirmation-msg">
|
|
||||||
{{block "remove media for real?" .}}Do you really want to remove media from hypha ‘{{beautifulName .HyphaName}}’?{{end}}
|
|
||||||
</p>
|
|
||||||
<button type="submit" value="Confirm" class="btn" autofocus>
|
|
||||||
{{template "confirm"}}
|
|
||||||
</button>
|
|
||||||
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">
|
|
||||||
{{template "cancel"}}
|
|
||||||
</a>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</main>
|
|
||||||
{{end}}
|
|
||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
||||||
"github.com/bouncepaw/mycorrhiza/util"
|
"github.com/bouncepaw/mycorrhiza/util"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
@ -11,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Tree returns the subhypha matrix as HTML and names of the next and previous hyphae (or empty strings).
|
// 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 (
|
var (
|
||||||
root = child{hyphaName, true, make([]child, 0)}
|
root = child{hyphaName, true, make([]child, 0)}
|
||||||
descendantPrefix = hyphaName + "/"
|
descendantPrefix = hyphaName + "/"
|
||||||
|
|||||||
123
web/mutators.go
123
web/mutators.go
@ -2,10 +2,10 @@ package web
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"git.sr.ht/~bouncepaw/mycomarkup/v5"
|
"git.sr.ht/~bouncepaw/mycomarkup/v5"
|
||||||
hyphae2 "github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
"github.com/bouncepaw/mycorrhiza/internal/hyphae"
|
||||||
shroom2 "github.com/bouncepaw/mycorrhiza/internal/shroom"
|
"github.com/bouncepaw/mycorrhiza/internal/shroom"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/user"
|
"github.com/bouncepaw/mycorrhiza/internal/user"
|
||||||
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
|
"github.com/bouncepaw/mycorrhiza/web/viewutil"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -24,7 +24,7 @@ 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("/rename/").HandlerFunc(handlerRename).Methods("GET", "POST")
|
||||||
r.PathPrefix("/delete/").HandlerFunc(handlerDelete).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-binary/").HandlerFunc(handlerUploadBinary)
|
||||||
r.PathPrefix("/upload-text/").HandlerFunc(handlerUploadText)
|
r.PathPrefix("/upload-text/").HandlerFunc(handlerUploadText)
|
||||||
}
|
}
|
||||||
@ -35,24 +35,20 @@ func handlerRemoveMedia(w http.ResponseWriter, rq *http.Request) {
|
|||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
h = hyphae2.ByName(util.HyphaNameFromRq(rq, "remove-media"))
|
h = hyphae.ByName(util.HyphaNameFromRq(rq, "remove-media"))
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
)
|
)
|
||||||
if !u.CanProceed("remove-media") {
|
if !u.CanProceed("remove-media") {
|
||||||
viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no rights")
|
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no rights")
|
||||||
return
|
|
||||||
}
|
|
||||||
if rq.Method == "GET" {
|
|
||||||
hypview.RemoveMedia(viewutil2.MetaFrom(w, rq), h.CanonicalName())
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case *hyphae2.EmptyHypha, *hyphae2.TextualHypha:
|
case *hyphae.EmptyHypha, *hyphae.TextualHypha:
|
||||||
viewutil2.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no media to remove")
|
viewutil.HttpErr(meta, http.StatusForbidden, h.CanonicalName(), "no media to remove")
|
||||||
return
|
return
|
||||||
case *hyphae2.MediaHypha:
|
case *hyphae.MediaHypha:
|
||||||
if err := shroom2.RemoveMedia(u, h); err != nil {
|
if err := shroom.RemoveMedia(u, h); err != nil {
|
||||||
viewutil2.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error())
|
viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,32 +59,36 @@ func handlerDelete(w http.ResponseWriter, rq *http.Request) {
|
|||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
h = hyphae2.ByName(util.HyphaNameFromRq(rq, "delete"))
|
h = hyphae.ByName(util.HyphaNameFromRq(rq, "delete"))
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
)
|
)
|
||||||
|
|
||||||
if !u.CanProceed("delete") {
|
if !u.CanProceed("delete") {
|
||||||
log.Printf("%s has no rights to delete ‘%s’\n", u.Name, h.CanonicalName())
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch h.(type) {
|
switch h.(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
log.Printf("%s tries to delete empty hypha ‘%s’\n", u.Name, h.CanonicalName())
|
log.Printf("%s tries to delete empty hypha ‘%s’\n", u.Name, h.CanonicalName())
|
||||||
// TODO: localize
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if rq.Method == "GET" {
|
if rq.Method == "GET" {
|
||||||
hypview.DeleteHypha(meta, h.CanonicalName())
|
_ = pageHyphaDelete.RenderTo(
|
||||||
|
viewutil.MetaFrom(w, rq),
|
||||||
|
map[string]any{
|
||||||
|
"HyphaName": h.CanonicalName(),
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := shroom2.Delete(u, h.(hyphae2.ExistingHypha)); err != nil {
|
if err := shroom.Delete(u, h.(hyphae.ExistingHypha)); err != nil {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
viewutil2.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error())
|
viewutil.HttpErr(meta, http.StatusInternalServerError, h.CanonicalName(), err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, rq, "/hypha/"+h.CanonicalName(), http.StatusSeeOther)
|
http.Redirect(w, rq, "/hypha/"+h.CanonicalName(), http.StatusSeeOther)
|
||||||
@ -99,25 +99,25 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) {
|
|||||||
var (
|
var (
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
lc = l18n.FromRequest(rq)
|
lc = l18n.FromRequest(rq)
|
||||||
h = hyphae2.ByName(util.HyphaNameFromRq(rq, "rename"))
|
h = hyphae.ByName(util.HyphaNameFromRq(rq, "rename"))
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
)
|
)
|
||||||
|
|
||||||
switch h.(type) {
|
switch h.(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
log.Printf("%s tries to rename empty hypha ‘%s’", u.Name, h.CanonicalName())
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !u.CanProceed("rename") {
|
if !u.CanProceed("rename") {
|
||||||
log.Printf("%s has no rights to rename ‘%s’\n", u.Name, h.CanonicalName())
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
oldHypha = h.(hyphae2.ExistingHypha)
|
oldHypha = h.(hyphae.ExistingHypha)
|
||||||
newName = util.CanonicalName(rq.PostFormValue("new-name"))
|
newName = util.CanonicalName(rq.PostFormValue("new-name"))
|
||||||
recursive = rq.PostFormValue("recursive") == "true"
|
recursive = rq.PostFormValue("recursive") == "true"
|
||||||
leaveRedirections = rq.PostFormValue("redirection") == "true"
|
leaveRedirections = rq.PostFormValue("redirection") == "true"
|
||||||
@ -128,9 +128,9 @@ func handlerRename(w http.ResponseWriter, rq *http.Request) {
|
|||||||
return
|
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())
|
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
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, rq, "/hypha/"+newName, http.StatusSeeOther)
|
http.Redirect(w, rq, "/hypha/"+newName, http.StatusSeeOther)
|
||||||
@ -142,33 +142,41 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
|
|||||||
var (
|
var (
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
lc = l18n.FromRequest(rq)
|
lc = l18n.FromRequest(rq)
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
|
|
||||||
hyphaName = util.HyphaNameFromRq(rq, "edit")
|
hyphaName = util.HyphaNameFromRq(rq, "edit")
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
|
|
||||||
isNew bool
|
isNew bool
|
||||||
content string
|
content string
|
||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := shroom2.CanEdit(u, h, lc); err != nil {
|
if err := shroom.CanEdit(u, h, lc); err != nil {
|
||||||
viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch h.(type) {
|
switch h.(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
isNew = true
|
isNew = true
|
||||||
default:
|
default:
|
||||||
content, err = hyphae2.FetchMycomarkupFile(h)
|
content, err = hyphae.FetchMycomarkupFile(h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
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
|
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.
|
// handlerUploadText uploads a new text part for the hypha.
|
||||||
@ -176,11 +184,11 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
|||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
|
|
||||||
hyphaName = util.HyphaNameFromRq(rq, "upload-text")
|
hyphaName = util.HyphaNameFromRq(rq, "upload-text")
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
_, isNew = h.(*hyphae2.EmptyHypha)
|
_, isNew = h.(*hyphae.EmptyHypha)
|
||||||
|
|
||||||
textData = rq.PostFormValue("text")
|
textData = rq.PostFormValue("text")
|
||||||
action = rq.PostFormValue("action")
|
action = rq.PostFormValue("action")
|
||||||
@ -190,12 +198,21 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
|
|||||||
if action == "preview" {
|
if action == "preview" {
|
||||||
ctx, _ := mycocontext.ContextFromStringInput(textData, mycoopts.MarkupOptions(hyphaName))
|
ctx, _ := mycocontext.ContextFromStringInput(textData, mycoopts.MarkupOptions(hyphaName))
|
||||||
preview := template.HTML(mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := shroom2.UploadText(h, []byte(textData), message, u); err != nil {
|
if err := shroom.UploadText(h, []byte(textData), message, u); err != nil {
|
||||||
viewutil2.HttpErr(meta, http.StatusForbidden, hyphaName, err.Error())
|
viewutil.HttpErr(meta, http.StatusForbidden, hyphaName, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)
|
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
|
rq.ParseMultipartForm(10 << 20) // Set upload limit
|
||||||
var (
|
var (
|
||||||
hyphaName = util.HyphaNameFromRq(rq, "upload-binary")
|
hyphaName = util.HyphaNameFromRq(rq, "upload-binary")
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
lc = l18n.FromRequest(rq)
|
lc = l18n.FromRequest(rq)
|
||||||
file, handler, err = rq.FormFile("binary")
|
file, handler, err = rq.FormFile("binary")
|
||||||
meta = viewutil2.MetaFrom(w, rq)
|
meta = viewutil.MetaFrom(w, rq)
|
||||||
)
|
)
|
||||||
if err != nil {
|
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 {
|
if err := shroom.CanAttach(u, h, lc); err != nil {
|
||||||
viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// If file is not passed:
|
// If file is not passed:
|
||||||
@ -234,8 +251,8 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
|
|||||||
mime = handler.Header.Get("Content-Type")
|
mime = handler.Header.Get("Content-Type")
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := shroom2.UploadBinary(h, mime, file, u); err != nil {
|
if err := shroom.UploadBinary(h, mime, file, u); err != nil {
|
||||||
viewutil2.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
viewutil.HttpErr(meta, http.StatusInternalServerError, hyphaName, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)
|
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)
|
||||||
|
|||||||
71
web/pages.go
71
web/pages.go
@ -3,23 +3,23 @@ package web
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/bouncepaw/mycorrhiza/web/newtmpl"
|
"github.com/bouncepaw/mycorrhiza/web/newtmpl"
|
||||||
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
|
"github.com/bouncepaw/mycorrhiza/web/viewutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed views/*.html
|
//go:embed views/*.html
|
||||||
var fs embed.FS
|
var fs embed.FS
|
||||||
|
|
||||||
var pageOrphans, pageBacklinks, pageUserList, pageChangePassword *newtmpl.Page
|
var pageOrphans, pageBacklinks, pageUserList, pageChangePassword *newtmpl.Page
|
||||||
|
var pageHyphaDelete, pageHyphaEdit, pageHyphaEmpty, pageHypha *newtmpl.Page
|
||||||
var panelChain, listChain, newUserChain, editUserChain, deleteUserChain viewutil2.Chain
|
var panelChain, listChain, newUserChain, editUserChain, deleteUserChain viewutil.Chain
|
||||||
|
|
||||||
func initPages() {
|
func initPages() {
|
||||||
|
|
||||||
panelChain = viewutil2.CopyEnRuWith(fs, "views/admin-panel.html", adminTranslationRu)
|
panelChain = viewutil.CopyEnRuWith(fs, "views/admin-panel.html", adminTranslationRu)
|
||||||
listChain = viewutil2.CopyEnRuWith(fs, "views/admin-user-list.html", adminTranslationRu)
|
listChain = viewutil.CopyEnRuWith(fs, "views/admin-user-list.html", adminTranslationRu)
|
||||||
newUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-new-user.html", adminTranslationRu)
|
newUserChain = viewutil.CopyEnRuWith(fs, "views/admin-new-user.html", adminTranslationRu)
|
||||||
editUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-edit-user.html", adminTranslationRu)
|
editUserChain = viewutil.CopyEnRuWith(fs, "views/admin-edit-user.html", adminTranslationRu)
|
||||||
deleteUserChain = viewutil2.CopyEnRuWith(fs, "views/admin-delete-user.html", adminTranslationRu)
|
deleteUserChain = viewutil.CopyEnRuWith(fs, "views/admin-delete-user.html", adminTranslationRu)
|
||||||
|
|
||||||
pageOrphans = newtmpl.NewPage(fs, "views/orphans.html", map[string]string{
|
pageOrphans = newtmpl.NewPage(fs, "views/orphans.html", map[string]string{
|
||||||
"orphaned hyphae": "Гифы-сироты",
|
"orphaned hyphae": "Гифы-сироты",
|
||||||
@ -45,4 +45,59 @@ func initPages() {
|
|||||||
"password": "Пароль",
|
"password": "Пароль",
|
||||||
"submit": "Поменять",
|
"submit": "Поменять",
|
||||||
})
|
})
|
||||||
|
pageHyphaDelete = newtmpl.NewPage(fs, "views/hypha-delete.html", map[string]string{
|
||||||
|
"delete hypha?": "Удалить {{beautifulName .}}?",
|
||||||
|
"delete [[hypha]]?": "Удалить <a href=\"/hypha/{{.}}\">{{beautifulName .}}</a>?",
|
||||||
|
"want to delete?": "Вы действительно хотите удалить эту гифу?",
|
||||||
|
"delete tip": "Нельзя отменить удаление гифы, но её история останется доступной.",
|
||||||
|
})
|
||||||
|
pageHyphaEdit = newtmpl.NewPage(fs, "views/hypha-edit.html", map[string]string{
|
||||||
|
"editing hypha": `Редактирование {{beautifulName .}}`,
|
||||||
|
"editing [[hypha]]": `Редактирование <a href="/hypha/{{.}}">{{beautifulName .}}</a>`,
|
||||||
|
"creating [[hypha]]": `Создание <a href="/hypha/{{.}}">{{beautifulName .}}</a>`,
|
||||||
|
"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": `<a href="/help/en/mycomarkup" class="shy-link">Подробнее</a> о Микоразметке`,
|
||||||
|
"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": `Напишите заметку, дневник, статью, рассказ или иной текст с помощью <a href="/help/en/mycomarkup" class="shy-link">Микоразметки</a>. Сохраняется полная история правок документа.`,
|
||||||
|
"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{})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,14 +4,17 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"git.sr.ht/~bouncepaw/mycomarkup/v5"
|
"git.sr.ht/~bouncepaw/mycomarkup/v5"
|
||||||
"github.com/bouncepaw/mycorrhiza/categories"
|
"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/backlinks"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/internal/cfg"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/files"
|
"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/mimetype"
|
||||||
|
"github.com/bouncepaw/mycorrhiza/internal/tree"
|
||||||
"github.com/bouncepaw/mycorrhiza/internal/user"
|
"github.com/bouncepaw/mycorrhiza/internal/user"
|
||||||
"github.com/bouncepaw/mycorrhiza/mycoopts"
|
"github.com/bouncepaw/mycorrhiza/mycoopts"
|
||||||
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
|
"github.com/bouncepaw/mycorrhiza/web/viewutil"
|
||||||
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -59,15 +62,15 @@ func handlerMedia(w http.ResponseWriter, rq *http.Request) {
|
|||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = util.HyphaNameFromRq(rq, "media")
|
hyphaName = util.HyphaNameFromRq(rq, "media")
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
u = user.FromRequest(rq)
|
u = user.FromRequest(rq)
|
||||||
lc = l18n.FromRequest(rq)
|
lc = l18n.FromRequest(rq)
|
||||||
)
|
)
|
||||||
util.HTTP200Page(w,
|
util.HTTP200Page(w,
|
||||||
viewutil2.Base(
|
viewutil.Base(
|
||||||
viewutil2.MetaFrom(w, rq),
|
viewutil.MetaFrom(w, rq),
|
||||||
lc.Get("ui.media_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}),
|
lc.Get("ui.media_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}),
|
||||||
views2.MediaMenu(rq, h, u),
|
hypview.MediaMenu(rq, h, u),
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -85,11 +88,11 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
hyphaName = util.CanonicalName(slug)
|
hyphaName = util.CanonicalName(slug)
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
)
|
)
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
|
var mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
|
||||||
var textContents, err = history.FileAtRevision(mycoFilePath, revHash)
|
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)
|
log.Printf("Serving text of ‘%s’ from ‘%s’ at revision ‘%s’\n", hyphaName, mycoFilePath, revHash)
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = io.WriteString(w, textContents)
|
_, _ = io.WriteString(w, textContents)
|
||||||
case hyphae2.ExistingHypha:
|
case hyphae.ExistingHypha:
|
||||||
if !h.HasTextFile() {
|
if !h.HasTextFile() {
|
||||||
log.Printf(`Media hypha ‘%s’ has no text`)
|
log.Printf(`Media hypha ‘%s’ has no text`)
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
@ -133,16 +136,16 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
|||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
hyphaName = util.CanonicalName(slug)
|
hyphaName = util.CanonicalName(slug)
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
contents = fmt.Sprintf(`<p>%s</p>`, lc.Get("ui.revision_no_text"))
|
contents = fmt.Sprintf(`<p>%s</p>`, lc.Get("ui.revision_no_text"))
|
||||||
textContents string
|
textContents string
|
||||||
err error
|
err error
|
||||||
mycoFilePath string
|
mycoFilePath string
|
||||||
)
|
)
|
||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case hyphae2.ExistingHypha:
|
case hyphae.ExistingHypha:
|
||||||
mycoFilePath = h.TextFilePath()
|
mycoFilePath = h.TextFilePath()
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
|
mycoFilePath = filepath.Join(files.HyphaeDir(), h.CanonicalName()+".myco")
|
||||||
}
|
}
|
||||||
textContents, err = history.FileAtRevision(mycoFilePath, revHash)
|
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))
|
contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
page := views2.Revision(
|
page := hypview.Revision(
|
||||||
viewutil2.MetaFrom(w, rq),
|
viewutil.MetaFrom(w, rq),
|
||||||
h,
|
h,
|
||||||
contents,
|
contents,
|
||||||
revHash,
|
revHash,
|
||||||
@ -161,8 +164,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
_, _ = fmt.Fprint(
|
_, _ = fmt.Fprint(
|
||||||
w,
|
w,
|
||||||
viewutil2.Base(
|
viewutil.Base(
|
||||||
viewutil2.MetaFrom(w, rq),
|
viewutil.MetaFrom(w, rq),
|
||||||
lc.Get("ui.revision_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}),
|
lc.Get("ui.revision_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}),
|
||||||
page,
|
page,
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
@ -174,8 +177,8 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
|
|||||||
func handlerText(w http.ResponseWriter, rq *http.Request) {
|
func handlerText(w http.ResponseWriter, rq *http.Request) {
|
||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
hyphaName := util.HyphaNameFromRq(rq, "text")
|
hyphaName := util.HyphaNameFromRq(rq, "text")
|
||||||
switch h := hyphae2.ByName(hyphaName).(type) {
|
switch h := hyphae.ByName(hyphaName).(type) {
|
||||||
case hyphae2.ExistingHypha:
|
case hyphae.ExistingHypha:
|
||||||
log.Println("Serving", h.TextFilePath())
|
log.Println("Serving", h.TextFilePath())
|
||||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||||
http.ServeFile(w, rq, h.TextFilePath())
|
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) {
|
func handlerBinary(w http.ResponseWriter, rq *http.Request) {
|
||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
hyphaName := util.HyphaNameFromRq(rq, "binary")
|
hyphaName := util.HyphaNameFromRq(rq, "binary")
|
||||||
switch h := hyphae2.ByName(hyphaName).(type) {
|
switch h := hyphae.ByName(hyphaName).(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
case *hyphae2.TextualHypha:
|
case *hyphae.TextualHypha:
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
log.Printf("Textual hypha ‘%s’ has no media, cannot serve\n", h.CanonicalName())
|
log.Printf("Textual hypha ‘%s’ has no media, cannot serve\n", h.CanonicalName())
|
||||||
case *hyphae2.MediaHypha:
|
case *hyphae.MediaHypha:
|
||||||
log.Println("Serving", h.MediaFilePath())
|
log.Println("Serving", h.MediaFilePath())
|
||||||
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath())))
|
w.Header().Set("Content-Type", mimetype.FromExtension(filepath.Ext(h.MediaFilePath())))
|
||||||
http.ServeFile(w, rq, h.MediaFilePath())
|
http.ServeFile(w, rq, h.MediaFilePath())
|
||||||
@ -203,22 +206,23 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
|||||||
util.PrepareRq(rq)
|
util.PrepareRq(rq)
|
||||||
var (
|
var (
|
||||||
hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
|
hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
|
||||||
h = hyphae2.ByName(hyphaName)
|
h = hyphae.ByName(hyphaName)
|
||||||
contents string
|
contents string
|
||||||
openGraph string
|
openGraph string
|
||||||
lc = l18n.FromRequest(rq)
|
lc = l18n.FromRequest(rq)
|
||||||
)
|
)
|
||||||
|
|
||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case *hyphae2.EmptyHypha:
|
case *hyphae.EmptyHypha:
|
||||||
|
// contents = hypview.EmptyHypha()
|
||||||
util.HTTP404Page(w,
|
util.HTTP404Page(w,
|
||||||
viewutil2.Base(
|
viewutil.Base(
|
||||||
viewutil2.MetaFrom(w, rq),
|
viewutil.MetaFrom(w, rq),
|
||||||
util.BeautifulName(hyphaName),
|
util.BeautifulName(hyphaName),
|
||||||
views2.Hypha(viewutil2.MetaFrom(w, rq), h, contents),
|
hypview.Hypha(viewutil.MetaFrom(w, rq), h, ""),
|
||||||
map[string]string{},
|
map[string]string{},
|
||||||
openGraph))
|
openGraph))
|
||||||
case hyphae2.ExistingHypha:
|
case hyphae.ExistingHypha:
|
||||||
fileContentsT, errT := os.ReadFile(h.TextFilePath())
|
fileContentsT, errT := os.ReadFile(h.TextFilePath())
|
||||||
if errT == nil {
|
if errT == nil {
|
||||||
ctx, _ := mycocontext.ContextFromStringInput(string(fileContentsT), mycoopts.MarkupOptions(hyphaName))
|
ctx, _ := mycocontext.ContextFromStringInput(string(fileContentsT), mycoopts.MarkupOptions(hyphaName))
|
||||||
@ -228,17 +232,30 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
|||||||
openGraph = getOpenGraph()
|
openGraph = getOpenGraph()
|
||||||
}
|
}
|
||||||
switch h := h.(type) {
|
switch h := h.(type) {
|
||||||
case *hyphae2.MediaHypha:
|
case *hyphae.MediaHypha:
|
||||||
contents = mycoopts.Media(h, lc) + contents
|
contents = mycoopts.Media(h, lc) + contents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
meta := viewutil.MetaFrom(w, rq)
|
||||||
category_list := ":" + strings.Join(categories.CategoriesWithHypha(h.CanonicalName()), ":") + ":"
|
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,
|
util.HTTP200Page(w,
|
||||||
viewutil2.Base(
|
viewutil.Base(
|
||||||
viewutil2.MetaFrom(w, rq),
|
viewutil.MetaFrom(w, rq),
|
||||||
util.BeautifulName(hyphaName),
|
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},
|
map[string]string{"cats": category_list},
|
||||||
openGraph))
|
openGraph))
|
||||||
}
|
}
|
||||||
@ -248,7 +265,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
|
|||||||
func handlerBacklinks(w http.ResponseWriter, rq *http.Request) {
|
func handlerBacklinks(w http.ResponseWriter, rq *http.Request) {
|
||||||
hyphaName := util.HyphaNameFromRq(rq, "backlinks")
|
hyphaName := util.HyphaNameFromRq(rq, "backlinks")
|
||||||
|
|
||||||
_ = pageBacklinks.RenderTo(viewutil2.MetaFrom(w, rq),
|
_ = pageBacklinks.RenderTo(viewutil.MetaFrom(w, rq),
|
||||||
map[string]any{
|
map[string]any{
|
||||||
"Addr": "/backlinks/" + hyphaName,
|
"Addr": "/backlinks/" + hyphaName,
|
||||||
"HyphaName": hyphaName,
|
"HyphaName": hyphaName,
|
||||||
@ -257,7 +274,7 @@ func handlerBacklinks(w http.ResponseWriter, rq *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handlerOrphans(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{
|
map[string]any{
|
||||||
"Addr": "/orphans",
|
"Addr": "/orphans",
|
||||||
"Orphans": backlinks.Orphans(),
|
"Orphans": backlinks.Orphans(),
|
||||||
|
|||||||
@ -108,11 +108,11 @@ main h1:not(.navi-title) {font-size:1.7rem;}
|
|||||||
blockquote { margin: 0; padding-left: .75rem; }
|
blockquote { margin: 0; padding-left: .75rem; }
|
||||||
.wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; }
|
.wikilink_external::before { display: inline-block; width: 18px; height: 16px; vertical-align: sub; }
|
||||||
/* .wikilink_external { padding-left: 16px; } */
|
/* .wikilink_external { padding-left: 16px; } */
|
||||||
.wikilink_gopher::before { content: url("/staticatic/icon/gopher-proto.svg"); }
|
.wikilink_gopher::before { content: url("/static/icon/gopher-proto.svg"); }
|
||||||
.wikilink_http::before, .wikilink_https::before { content: url("/staticatic/icon/http-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_https { background: transparent url("/static/icon/http-proto.svg") center left no-repeat; } */
|
||||||
.wikilink_gemini::before { content: url("/staticatic/icon/gemini-proto.svg"); }
|
.wikilink_gemini::before { content: url("/static/icon/gemini-proto.svg"); }
|
||||||
.wikilink_mailto::before { content: url("/staticatic/icon/mailto-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%; }
|
article { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; line-height: 150%; }
|
||||||
main h1 { margin: .5rem 0 0 0; }
|
main h1 { margin: .5rem 0 0 0; }
|
||||||
|
|||||||
98
web/views/hypha.html
Normal file
98
web/views/hypha.html
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
{{define "body"}}
|
||||||
|
<main class="main-width">
|
||||||
|
<section id="hypha">
|
||||||
|
{{if .Meta.U.CanProceed "edit"}}
|
||||||
|
<div class="btn btn_navititle">
|
||||||
|
<a class="btn__link_navititle" href="/edit/{{.HyphaName}}">
|
||||||
|
{{block "edit" .}}Edit{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .IsMyProfile}}
|
||||||
|
<div class="btn btn_navititle">
|
||||||
|
<a class="btn__link_navititle" href="/logout">
|
||||||
|
{{block "logout" .}}Log out{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{if eq .Meta.U.Group "admin"}}
|
||||||
|
<div class="btn btn_navititle">
|
||||||
|
<a class="btn__link_navititle" href="/admin">
|
||||||
|
{{block "admin panel" .}}Admin panel{{end}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{.NaviTitle}}
|
||||||
|
{{.Contents}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="prevnext">
|
||||||
|
{{if .PrevHyphaName}}
|
||||||
|
<a class="prevnext__el prevnext__prev" href="/hypha/{{.PrevHyphaName}}" rel="prev">
|
||||||
|
← {{base .PrevHyphaName | beautifulName}}</a>
|
||||||
|
{{end}}
|
||||||
|
{{if .NextHyphaName}}
|
||||||
|
<a class="prevnext__el prevnext__next" href="/hypha/{{.NextHyphaName}}" rel="next">
|
||||||
|
{{base .NextHyphaName | beautifulName}} →</a>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{ if .SubhyphaeHTML }}
|
||||||
|
<section class="subhyphae">
|
||||||
|
<h2 class="subhyphae__title">{%s lc.Get("ui.subhyphae") %}</h2>
|
||||||
|
<nav class="subhyphae__nav">
|
||||||
|
<ul class="subhyphae__list">
|
||||||
|
{{.SubhyphaeHTML}}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</section>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<section id="hypha-bottom">
|
||||||
|
{{hyphaInfo(meta, h)}}
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
{{template "category card" .}}
|
||||||
|
{{range .ViewScripts}}<script src="{{.}}"></script>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{define "category card"}}
|
||||||
|
{{if or .GivenPermissionToModify (len .Categories)}}
|
||||||
|
{{$hyphaName := .HyphaName}}
|
||||||
|
{{$givenPermission := .GivenPermissionToModify}}
|
||||||
|
<aside class="layout-card categories-card">
|
||||||
|
<h2 class="layout-card__title">{{block `categories` .}}Categories{{end}}</h2>
|
||||||
|
<ul class="categories-card__entries">
|
||||||
|
{{range .Categories}}
|
||||||
|
<li class="categories-card__entry">
|
||||||
|
<a class="categories-card__link" href="/category/{{.}}">{{beautifulName .}}</a>
|
||||||
|
<form method="POST" action="/remove-from-category" class="categories-card__remove-form">
|
||||||
|
<input type="hidden" name="cat" value="{{.}}">
|
||||||
|
<input type="hidden" name="hypha" value="{{$hyphaName}}">
|
||||||
|
<input type="hidden" name="redirect-to" value="/hypha/{{$hyphaName}}">
|
||||||
|
{{if $givenPermission}}
|
||||||
|
<input type="submit" value="x" class="btn categories-card__btn"
|
||||||
|
title="{{block `remove from category title` .}}Remove the hypha from this category{{end}}">
|
||||||
|
{{end}}
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{if .GivenPermissionToModify}}
|
||||||
|
<li class="categories-card__entry categories-card__add-to-cat">
|
||||||
|
<form method="POST" action="/add-to-category" class="categories-card__add-form js-add-cat-form">
|
||||||
|
<input type="text" name="cat" id="_cat-name" class="js-add-cat-name" autocomplete="off"
|
||||||
|
placeholder="{{block `placeholder` .}}Category name...{{end}}">
|
||||||
|
<datalist class="js-add-cat-list" id="cat-name-options"></datalist>
|
||||||
|
<input type="hidden" name="hypha" value="{{$hyphaName}}">
|
||||||
|
<input type="hidden" name="redirect-to" value="/hypha/{{$hyphaName}}">
|
||||||
|
<input type="submit" class="btn categories-card__btn" value="+"
|
||||||
|
title="{{block `add to category title` .}}Add the hypha to this category{{end}}">
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
{{end}}{{end}}
|
||||||
Loading…
Reference in New Issue
Block a user