Megarefactoring of hypha views

This commit is contained in:
Timur Ismagilov 2024-07-12 21:35:37 +03:00
parent 68a7573764
commit ea1ae0d078
16 changed files with 341 additions and 1132 deletions

View File

@ -2,12 +2,13 @@ package hypview
import (
"embed"
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"html/template"
"log"
"strings"
"github.com/bouncepaw/mycorrhiza/internal/backlinks"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
)
var (

View File

@ -1,50 +0,0 @@
{% import "github.com/bouncepaw/mycorrhiza/internal/backlinks" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
{% import "github.com/bouncepaw/mycorrhiza/web/viewutil" %}
{% func hyphaInfoEntry(h hyphae.Hypha, u *user.User, action string, hasToExist bool, displayText string) %}
{% code flag := true %}
{% switch h.(type) %}
{% case *hyphae.EmptyHypha %}
{% code flag = !hasToExist %}
{% endswitch %}
{% if u.CanProceed(action) && flag %}
<li class="hypha-info__entry hypha-info__entry_{%s action %}">
<a class="hypha-info__link" href="/{%s action %}/{%s h.CanonicalName() %}">{%s displayText %}</a>
</li>
{% endif %}
{% endfunc %}
{% func hyphaInfo(meta viewutil.Meta, h hyphae.Hypha) %}
{% code
u := meta.U
lc := meta.Lc
backs := backlinks.BacklinksCount(h.CanonicalName())
%}
<nav class="hypha-info">
<ul class="hypha-info__list">
{%= hyphaInfoEntry(h, u, "history", false, lc.Get("ui.history_link")) %}
{%= hyphaInfoEntry(h, u, "rename", true, lc.Get("ui.rename_link")) %}
{%= hyphaInfoEntry(h, u, "delete", true, lc.Get("ui.delete_link")) %}
{%= hyphaInfoEntry(h, u, "text", true, lc.Get("ui.text_link")) %}
{% switch h := h.(type) %}
{% case *hyphae.TextualHypha %}
{%= hyphaInfoEntry(h, u, "media", true, lc.Get("ui.media_link_for_textual")) %}
{% default %}
{%= hyphaInfoEntry(h, u, "media", true, lc.Get("ui.media_link")) %}
{% endswitch %}
{%= hyphaInfoEntry(h, u, "backlinks", false, lc.GetPlural("ui.backlinks_link", backs)) %}
</ul>
</nav>
{% endfunc %}
{% func commonScripts() %}
{% for _, scriptPath := range cfg.CommonScripts %}
<script src="{%s scriptPath %}"></script>
{% endfor %}
{% endfunc %}
{% func beautifulLink(hyphaName string) %}<a href="/hypha/{%s= hyphaName %}">{%s util.BeautifulName(hyphaName) %}</a>{% endfunc %}

View File

@ -1,311 +0,0 @@
// Code generated by qtc from "nav.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line hypview/nav.qtpl:1
package hypview
//line hypview/nav.qtpl:1
import "github.com/bouncepaw/mycorrhiza/internal/backlinks"
//line hypview/nav.qtpl:2
import "github.com/bouncepaw/mycorrhiza/internal/cfg"
//line hypview/nav.qtpl:3
import "github.com/bouncepaw/mycorrhiza/internal/hyphae"
//line hypview/nav.qtpl:4
import "github.com/bouncepaw/mycorrhiza/internal/user"
//line hypview/nav.qtpl:5
import "github.com/bouncepaw/mycorrhiza/util"
//line hypview/nav.qtpl:6
import "github.com/bouncepaw/mycorrhiza/web/viewutil"
//line hypview/nav.qtpl:8
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line hypview/nav.qtpl:8
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line hypview/nav.qtpl:8
func streamhyphaInfoEntry(qw422016 *qt422016.Writer, h hyphae.Hypha, u *user.User, action string, hasToExist bool, displayText string) {
//line hypview/nav.qtpl:8
qw422016.N().S(`
`)
//line hypview/nav.qtpl:9
flag := true
//line hypview/nav.qtpl:9
qw422016.N().S(`
`)
//line hypview/nav.qtpl:10
switch h.(type) {
//line hypview/nav.qtpl:11
case *hyphae.EmptyHypha:
//line hypview/nav.qtpl:11
qw422016.N().S(`
`)
//line hypview/nav.qtpl:12
flag = !hasToExist
//line hypview/nav.qtpl:12
qw422016.N().S(`
`)
//line hypview/nav.qtpl:13
}
//line hypview/nav.qtpl:13
qw422016.N().S(`
`)
//line hypview/nav.qtpl:14
if u.CanProceed(action) && flag {
//line hypview/nav.qtpl:14
qw422016.N().S(`
<li class="hypha-info__entry hypha-info__entry_`)
//line hypview/nav.qtpl:15
qw422016.E().S(action)
//line hypview/nav.qtpl:15
qw422016.N().S(`">
<a class="hypha-info__link" href="/`)
//line hypview/nav.qtpl:16
qw422016.E().S(action)
//line hypview/nav.qtpl:16
qw422016.N().S(`/`)
//line hypview/nav.qtpl:16
qw422016.E().S(h.CanonicalName())
//line hypview/nav.qtpl:16
qw422016.N().S(`">`)
//line hypview/nav.qtpl:16
qw422016.E().S(displayText)
//line hypview/nav.qtpl:16
qw422016.N().S(`</a>
</li>
`)
//line hypview/nav.qtpl:18
}
//line hypview/nav.qtpl:18
qw422016.N().S(`
`)
//line hypview/nav.qtpl:19
}
//line hypview/nav.qtpl:19
func writehyphaInfoEntry(qq422016 qtio422016.Writer, h hyphae.Hypha, u *user.User, action string, hasToExist bool, displayText string) {
//line hypview/nav.qtpl:19
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/nav.qtpl:19
streamhyphaInfoEntry(qw422016, h, u, action, hasToExist, displayText)
//line hypview/nav.qtpl:19
qt422016.ReleaseWriter(qw422016)
//line hypview/nav.qtpl:19
}
//line hypview/nav.qtpl:19
func hyphaInfoEntry(h hyphae.Hypha, u *user.User, action string, hasToExist bool, displayText string) string {
//line hypview/nav.qtpl:19
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/nav.qtpl:19
writehyphaInfoEntry(qb422016, h, u, action, hasToExist, displayText)
//line hypview/nav.qtpl:19
qs422016 := string(qb422016.B)
//line hypview/nav.qtpl:19
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/nav.qtpl:19
return qs422016
//line hypview/nav.qtpl:19
}
//line hypview/nav.qtpl:21
func streamhyphaInfo(qw422016 *qt422016.Writer, meta viewutil.Meta, h hyphae.Hypha) {
//line hypview/nav.qtpl:21
qw422016.N().S(`
`)
//line hypview/nav.qtpl:23
u := meta.U
lc := meta.Lc
backs := backlinks.BacklinksCount(h.CanonicalName())
//line hypview/nav.qtpl:26
qw422016.N().S(`
<nav class="hypha-info">
<ul class="hypha-info__list">
`)
//line hypview/nav.qtpl:29
streamhyphaInfoEntry(qw422016, h, u, "history", false, lc.Get("ui.history_link"))
//line hypview/nav.qtpl:29
qw422016.N().S(`
`)
//line hypview/nav.qtpl:30
streamhyphaInfoEntry(qw422016, h, u, "rename", true, lc.Get("ui.rename_link"))
//line hypview/nav.qtpl:30
qw422016.N().S(`
`)
//line hypview/nav.qtpl:31
streamhyphaInfoEntry(qw422016, h, u, "delete", true, lc.Get("ui.delete_link"))
//line hypview/nav.qtpl:31
qw422016.N().S(`
`)
//line hypview/nav.qtpl:32
streamhyphaInfoEntry(qw422016, h, u, "text", true, lc.Get("ui.text_link"))
//line hypview/nav.qtpl:32
qw422016.N().S(`
`)
//line hypview/nav.qtpl:33
switch h := h.(type) {
//line hypview/nav.qtpl:34
case *hyphae.TextualHypha:
//line hypview/nav.qtpl:34
qw422016.N().S(`
`)
//line hypview/nav.qtpl:35
streamhyphaInfoEntry(qw422016, h, u, "media", true, lc.Get("ui.media_link_for_textual"))
//line hypview/nav.qtpl:35
qw422016.N().S(`
`)
//line hypview/nav.qtpl:36
default:
//line hypview/nav.qtpl:36
qw422016.N().S(`
`)
//line hypview/nav.qtpl:37
streamhyphaInfoEntry(qw422016, h, u, "media", true, lc.Get("ui.media_link"))
//line hypview/nav.qtpl:37
qw422016.N().S(`
`)
//line hypview/nav.qtpl:38
}
//line hypview/nav.qtpl:38
qw422016.N().S(`
`)
//line hypview/nav.qtpl:39
streamhyphaInfoEntry(qw422016, h, u, "backlinks", false, lc.GetPlural("ui.backlinks_link", backs))
//line hypview/nav.qtpl:39
qw422016.N().S(`
</ul>
</nav>
`)
//line hypview/nav.qtpl:42
}
//line hypview/nav.qtpl:42
func writehyphaInfo(qq422016 qtio422016.Writer, meta viewutil.Meta, h hyphae.Hypha) {
//line hypview/nav.qtpl:42
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/nav.qtpl:42
streamhyphaInfo(qw422016, meta, h)
//line hypview/nav.qtpl:42
qt422016.ReleaseWriter(qw422016)
//line hypview/nav.qtpl:42
}
//line hypview/nav.qtpl:42
func hyphaInfo(meta viewutil.Meta, h hyphae.Hypha) string {
//line hypview/nav.qtpl:42
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/nav.qtpl:42
writehyphaInfo(qb422016, meta, h)
//line hypview/nav.qtpl:42
qs422016 := string(qb422016.B)
//line hypview/nav.qtpl:42
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/nav.qtpl:42
return qs422016
//line hypview/nav.qtpl:42
}
//line hypview/nav.qtpl:44
func streamcommonScripts(qw422016 *qt422016.Writer) {
//line hypview/nav.qtpl:44
qw422016.N().S(`
`)
//line hypview/nav.qtpl:45
for _, scriptPath := range cfg.CommonScripts {
//line hypview/nav.qtpl:45
qw422016.N().S(`
<script src="`)
//line hypview/nav.qtpl:46
qw422016.E().S(scriptPath)
//line hypview/nav.qtpl:46
qw422016.N().S(`"></script>
`)
//line hypview/nav.qtpl:47
}
//line hypview/nav.qtpl:47
qw422016.N().S(`
`)
//line hypview/nav.qtpl:48
}
//line hypview/nav.qtpl:48
func writecommonScripts(qq422016 qtio422016.Writer) {
//line hypview/nav.qtpl:48
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/nav.qtpl:48
streamcommonScripts(qw422016)
//line hypview/nav.qtpl:48
qt422016.ReleaseWriter(qw422016)
//line hypview/nav.qtpl:48
}
//line hypview/nav.qtpl:48
func commonScripts() string {
//line hypview/nav.qtpl:48
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/nav.qtpl:48
writecommonScripts(qb422016)
//line hypview/nav.qtpl:48
qs422016 := string(qb422016.B)
//line hypview/nav.qtpl:48
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/nav.qtpl:48
return qs422016
//line hypview/nav.qtpl:48
}
//line hypview/nav.qtpl:50
func streambeautifulLink(qw422016 *qt422016.Writer, hyphaName string) {
//line hypview/nav.qtpl:50
qw422016.N().S(`<a href="/hypha/`)
//line hypview/nav.qtpl:50
qw422016.N().S(hyphaName)
//line hypview/nav.qtpl:50
qw422016.N().S(`">`)
//line hypview/nav.qtpl:50
qw422016.E().S(util.BeautifulName(hyphaName))
//line hypview/nav.qtpl:50
qw422016.N().S(`</a>`)
//line hypview/nav.qtpl:50
}
//line hypview/nav.qtpl:50
func writebeautifulLink(qq422016 qtio422016.Writer, hyphaName string) {
//line hypview/nav.qtpl:50
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/nav.qtpl:50
streambeautifulLink(qw422016, hyphaName)
//line hypview/nav.qtpl:50
qt422016.ReleaseWriter(qw422016)
//line hypview/nav.qtpl:50
}
//line hypview/nav.qtpl:50
func beautifulLink(hyphaName string) string {
//line hypview/nav.qtpl:50
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/nav.qtpl:50
writebeautifulLink(qb422016, hyphaName)
//line hypview/nav.qtpl:50
qs422016 := string(qb422016.B)
//line hypview/nav.qtpl:50
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/nav.qtpl:50
return qs422016
//line hypview/nav.qtpl:50
}

View File

@ -1,94 +0,0 @@
{% import "net/http" %}
{% import "strings" %}
{% import "path" %}
{% import "os" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/mimetype" %}
{% import "github.com/bouncepaw/mycorrhiza/internal/user" %}
{% import "github.com/bouncepaw/mycorrhiza/web/viewutil" %}
{% func MediaMenu(rq *http.Request, h hyphae.Hypha, u *user.User) %}
{% code
lc := l18n.FromRequest(rq)
%}
<main class="main-width media-tab">
<h1>{%s= lc.Get("ui.media_title", &l18n.Replacements{"name": beautifulLink(h.CanonicalName())}) %}</h1>
{% switch h.(type) %}
{% case *hyphae.MediaHypha %}
<p class="explanation">{%s lc.Get("ui.media_tip") %} <a href="/help/en/media" class="shy-link">{%s lc.Get("ui.media_what_is") %}</a></p>
{% default %}
<p class="explanation">{%s lc.Get("ui.media_empty") %} <a href="/help/en/media" class="shy-link">{%s lc.Get("ui.media_what_is") %}</a></p>
{% endswitch %}
<section class="amnt-grid">
{% switch h := h.(type) %}
{% case *hyphae.MediaHypha %}
{% code
mime := mimetype.FromExtension(path.Ext(h.MediaFilePath()))
fileinfo, err := os.Stat(h.MediaFilePath()) %}
{% if err == nil %}
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">{%s lc.Get("ui.media_stat") %}</legend>
<p class="modal__confirmation-msg"><b>{%s lc.Get("ui.media_stat_size") %}</b> {%s lc.GetPlural64("ui.media_size_value", fileinfo.Size())%}</p>
<p><b>{%s lc.Get("ui.media_stat_mime") %}</b> {%s mime %}</p>
</fieldset>
{% endif %}
{% if strings.HasPrefix(mime, "image/") %}
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">{%s lc.Get("ui.media_include") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.media_include_tip") %}</p>
<pre class="codeblock"><code>img { {%s h.CanonicalName() %} }</code></pre>
</fieldset>
{% endif %}
{% endswitch %}
{% if u.CanProceed("upload-binary") %}
<form action="/upload-binary/{%s h.CanonicalName() %}"
method="post" enctype="multipart/form-data"
class="upload-binary modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">{%s lc.Get("ui.media_new") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.media_new_tip") %}</p>
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<button type="submit" class="btn stick-to-bottom" value="Upload">{%s lc.Get("ui.media_upload")%}</button>
</fieldset>
</form>
{% endif %}
{% switch h := h.(type) %}
{% case *hyphae.MediaHypha %}
{% if u.CanProceed("remove-media") %}
<form action="/remove-media/{%s h.CanonicalName() %}" method="post" class="modal amnt-menu-block" method="POST">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">{%s lc.Get("ui.media_remove") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.media_remove_tip") %}</p>
<button type="submit" class="btn" value="Remove media">{%s lc.Get("ui.media_remove_button") %}</button>
</fieldset>
</form>
{% endif %}
{% endswitch %}
</section>
</main>
{% endfunc %}
{% func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) %}
<main class="main-width">
<section>
<p>{%s meta.Lc.Get("ui.revision_warning") %} <a href="/rev-text/{%s revHash %}/{%s h.CanonicalName() %}">{%s meta.Lc.Get("ui.revision_link") %}</a></p>
{%s= NaviTitle(meta, h.CanonicalName()) %}
{%s= contents %}
</section>
</main>
{% for _, scriptPath := range cfg.ViewScripts %}
<script src="{%s scriptPath %}"></script>
{% endfor %}
{% endfunc %}

View File

@ -1,382 +0,0 @@
// Code generated by qtc from "readers.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
//line hypview/readers.qtpl:1
package hypview
//line hypview/readers.qtpl:1
import "net/http"
//line hypview/readers.qtpl:2
import "strings"
//line hypview/readers.qtpl:3
import "path"
//line hypview/readers.qtpl:4
import "os"
//line hypview/readers.qtpl:6
import "github.com/bouncepaw/mycorrhiza/internal/cfg"
//line hypview/readers.qtpl:7
import "github.com/bouncepaw/mycorrhiza/internal/hyphae"
//line hypview/readers.qtpl:8
import "github.com/bouncepaw/mycorrhiza/l18n"
//line hypview/readers.qtpl:9
import "github.com/bouncepaw/mycorrhiza/internal/mimetype"
//line hypview/readers.qtpl:10
import "github.com/bouncepaw/mycorrhiza/internal/user"
//line hypview/readers.qtpl:11
import "github.com/bouncepaw/mycorrhiza/web/viewutil"
//line hypview/readers.qtpl:13
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line hypview/readers.qtpl:13
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line hypview/readers.qtpl:13
func StreamMediaMenu(qw422016 *qt422016.Writer, rq *http.Request, h hyphae.Hypha, u *user.User) {
//line hypview/readers.qtpl:13
qw422016.N().S(`
`)
//line hypview/readers.qtpl:15
lc := l18n.FromRequest(rq)
//line hypview/readers.qtpl:16
qw422016.N().S(`
<main class="main-width media-tab">
<h1>`)
//line hypview/readers.qtpl:18
qw422016.N().S(lc.Get("ui.media_title", &l18n.Replacements{"name": beautifulLink(h.CanonicalName())}))
//line hypview/readers.qtpl:18
qw422016.N().S(`</h1>
`)
//line hypview/readers.qtpl:19
switch h.(type) {
//line hypview/readers.qtpl:20
case *hyphae.MediaHypha:
//line hypview/readers.qtpl:20
qw422016.N().S(`
<p class="explanation">`)
//line hypview/readers.qtpl:21
qw422016.E().S(lc.Get("ui.media_tip"))
//line hypview/readers.qtpl:21
qw422016.N().S(` <a href="/help/en/media" class="shy-link">`)
//line hypview/readers.qtpl:21
qw422016.E().S(lc.Get("ui.media_what_is"))
//line hypview/readers.qtpl:21
qw422016.N().S(`</a></p>
`)
//line hypview/readers.qtpl:22
default:
//line hypview/readers.qtpl:22
qw422016.N().S(`
<p class="explanation">`)
//line hypview/readers.qtpl:23
qw422016.E().S(lc.Get("ui.media_empty"))
//line hypview/readers.qtpl:23
qw422016.N().S(` <a href="/help/en/media" class="shy-link">`)
//line hypview/readers.qtpl:23
qw422016.E().S(lc.Get("ui.media_what_is"))
//line hypview/readers.qtpl:23
qw422016.N().S(`</a></p>
`)
//line hypview/readers.qtpl:24
}
//line hypview/readers.qtpl:24
qw422016.N().S(`
<section class="amnt-grid">
`)
//line hypview/readers.qtpl:27
switch h := h.(type) {
//line hypview/readers.qtpl:28
case *hyphae.MediaHypha:
//line hypview/readers.qtpl:28
qw422016.N().S(`
`)
//line hypview/readers.qtpl:30
mime := mimetype.FromExtension(path.Ext(h.MediaFilePath()))
fileinfo, err := os.Stat(h.MediaFilePath())
//line hypview/readers.qtpl:31
qw422016.N().S(`
`)
//line hypview/readers.qtpl:32
if err == nil {
//line hypview/readers.qtpl:32
qw422016.N().S(`
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">`)
//line hypview/readers.qtpl:34
qw422016.E().S(lc.Get("ui.media_stat"))
//line hypview/readers.qtpl:34
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg"><b>`)
//line hypview/readers.qtpl:35
qw422016.E().S(lc.Get("ui.media_stat_size"))
//line hypview/readers.qtpl:35
qw422016.N().S(`</b> `)
//line hypview/readers.qtpl:35
qw422016.E().S(lc.GetPlural64("ui.media_size_value", fileinfo.Size()))
//line hypview/readers.qtpl:35
qw422016.N().S(`</p>
<p><b>`)
//line hypview/readers.qtpl:36
qw422016.E().S(lc.Get("ui.media_stat_mime"))
//line hypview/readers.qtpl:36
qw422016.N().S(`</b> `)
//line hypview/readers.qtpl:36
qw422016.E().S(mime)
//line hypview/readers.qtpl:36
qw422016.N().S(`</p>
</fieldset>
`)
//line hypview/readers.qtpl:38
}
//line hypview/readers.qtpl:38
qw422016.N().S(`
`)
//line hypview/readers.qtpl:40
if strings.HasPrefix(mime, "image/") {
//line hypview/readers.qtpl:40
qw422016.N().S(`
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">`)
//line hypview/readers.qtpl:42
qw422016.E().S(lc.Get("ui.media_include"))
//line hypview/readers.qtpl:42
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line hypview/readers.qtpl:43
qw422016.E().S(lc.Get("ui.media_include_tip"))
//line hypview/readers.qtpl:43
qw422016.N().S(`</p>
<pre class="codeblock"><code>img { `)
//line hypview/readers.qtpl:44
qw422016.E().S(h.CanonicalName())
//line hypview/readers.qtpl:44
qw422016.N().S(` }</code></pre>
</fieldset>
`)
//line hypview/readers.qtpl:46
}
//line hypview/readers.qtpl:46
qw422016.N().S(`
`)
//line hypview/readers.qtpl:47
}
//line hypview/readers.qtpl:47
qw422016.N().S(`
`)
//line hypview/readers.qtpl:49
if u.CanProceed("upload-binary") {
//line hypview/readers.qtpl:49
qw422016.N().S(`
<form action="/upload-binary/`)
//line hypview/readers.qtpl:50
qw422016.E().S(h.CanonicalName())
//line hypview/readers.qtpl:50
qw422016.N().S(`"
method="post" enctype="multipart/form-data"
class="upload-binary modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">`)
//line hypview/readers.qtpl:54
qw422016.E().S(lc.Get("ui.media_new"))
//line hypview/readers.qtpl:54
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line hypview/readers.qtpl:55
qw422016.E().S(lc.Get("ui.media_new_tip"))
//line hypview/readers.qtpl:55
qw422016.N().S(`</p>
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<button type="submit" class="btn stick-to-bottom" value="Upload">`)
//line hypview/readers.qtpl:59
qw422016.E().S(lc.Get("ui.media_upload"))
//line hypview/readers.qtpl:59
qw422016.N().S(`</button>
</fieldset>
</form>
`)
//line hypview/readers.qtpl:62
}
//line hypview/readers.qtpl:62
qw422016.N().S(`
`)
//line hypview/readers.qtpl:65
switch h := h.(type) {
//line hypview/readers.qtpl:66
case *hyphae.MediaHypha:
//line hypview/readers.qtpl:66
qw422016.N().S(`
`)
//line hypview/readers.qtpl:67
if u.CanProceed("remove-media") {
//line hypview/readers.qtpl:67
qw422016.N().S(`
<form action="/remove-media/`)
//line hypview/readers.qtpl:68
qw422016.E().S(h.CanonicalName())
//line hypview/readers.qtpl:68
qw422016.N().S(`" method="post" class="modal amnt-menu-block" method="POST">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">`)
//line hypview/readers.qtpl:70
qw422016.E().S(lc.Get("ui.media_remove"))
//line hypview/readers.qtpl:70
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line hypview/readers.qtpl:71
qw422016.E().S(lc.Get("ui.media_remove_tip"))
//line hypview/readers.qtpl:71
qw422016.N().S(`</p>
<button type="submit" class="btn" value="Remove media">`)
//line hypview/readers.qtpl:72
qw422016.E().S(lc.Get("ui.media_remove_button"))
//line hypview/readers.qtpl:72
qw422016.N().S(`</button>
</fieldset>
</form>
`)
//line hypview/readers.qtpl:75
}
//line hypview/readers.qtpl:75
qw422016.N().S(`
`)
//line hypview/readers.qtpl:76
}
//line hypview/readers.qtpl:76
qw422016.N().S(`
</section>
</main>
`)
//line hypview/readers.qtpl:80
}
//line hypview/readers.qtpl:80
func WriteMediaMenu(qq422016 qtio422016.Writer, rq *http.Request, h hyphae.Hypha, u *user.User) {
//line hypview/readers.qtpl:80
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/readers.qtpl:80
StreamMediaMenu(qw422016, rq, h, u)
//line hypview/readers.qtpl:80
qt422016.ReleaseWriter(qw422016)
//line hypview/readers.qtpl:80
}
//line hypview/readers.qtpl:80
func MediaMenu(rq *http.Request, h hyphae.Hypha, u *user.User) string {
//line hypview/readers.qtpl:80
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/readers.qtpl:80
WriteMediaMenu(qb422016, rq, h, u)
//line hypview/readers.qtpl:80
qs422016 := string(qb422016.B)
//line hypview/readers.qtpl:80
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/readers.qtpl:80
return qs422016
//line hypview/readers.qtpl:80
}
//line hypview/readers.qtpl:83
func StreamRevision(qw422016 *qt422016.Writer, meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) {
//line hypview/readers.qtpl:83
qw422016.N().S(`
<main class="main-width">
<section>
<p>`)
//line hypview/readers.qtpl:86
qw422016.E().S(meta.Lc.Get("ui.revision_warning"))
//line hypview/readers.qtpl:86
qw422016.N().S(` <a href="/rev-text/`)
//line hypview/readers.qtpl:86
qw422016.E().S(revHash)
//line hypview/readers.qtpl:86
qw422016.N().S(`/`)
//line hypview/readers.qtpl:86
qw422016.E().S(h.CanonicalName())
//line hypview/readers.qtpl:86
qw422016.N().S(`">`)
//line hypview/readers.qtpl:86
qw422016.E().S(meta.Lc.Get("ui.revision_link"))
//line hypview/readers.qtpl:86
qw422016.N().S(`</a></p>
`)
//line hypview/readers.qtpl:87
qw422016.N().S(NaviTitle(meta, h.CanonicalName()))
//line hypview/readers.qtpl:87
qw422016.N().S(`
`)
//line hypview/readers.qtpl:88
qw422016.N().S(contents)
//line hypview/readers.qtpl:88
qw422016.N().S(`
</section>
</main>
`)
//line hypview/readers.qtpl:91
for _, scriptPath := range cfg.ViewScripts {
//line hypview/readers.qtpl:91
qw422016.N().S(`
<script src="`)
//line hypview/readers.qtpl:92
qw422016.E().S(scriptPath)
//line hypview/readers.qtpl:92
qw422016.N().S(`"></script>
`)
//line hypview/readers.qtpl:93
}
//line hypview/readers.qtpl:93
qw422016.N().S(`
`)
//line hypview/readers.qtpl:94
}
//line hypview/readers.qtpl:94
func WriteRevision(qq422016 qtio422016.Writer, meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) {
//line hypview/readers.qtpl:94
qw422016 := qt422016.AcquireWriter(qq422016)
//line hypview/readers.qtpl:94
StreamRevision(qw422016, meta, h, contents, revHash)
//line hypview/readers.qtpl:94
qt422016.ReleaseWriter(qw422016)
//line hypview/readers.qtpl:94
}
//line hypview/readers.qtpl:94
func Revision(meta viewutil.Meta, h hyphae.Hypha, contents, revHash string) string {
//line hypview/readers.qtpl:94
qb422016 := qt422016.AcquireByteBuffer()
//line hypview/readers.qtpl:94
WriteRevision(qb422016, meta, h, contents, revHash)
//line hypview/readers.qtpl:94
qs422016 := string(qb422016.B)
//line hypview/readers.qtpl:94
qt422016.ReleaseByteBuffer(qb422016)
//line hypview/readers.qtpl:94
return qs422016
//line hypview/readers.qtpl:94
}

View File

@ -4,18 +4,6 @@
"title_search": "Search by title",
"admin_panel": "Admin panel",
"edit_link": "Edit text",
"logout_link": "Log out",
"history_link": "View history",
"rename_link": "Rename",
"delete_link": "Delete",
"text_link": "View markup",
"media_link": "Manage media",
"media_link_for_textual": "Turn to media hypha",
"backlinks_link": "{{.n}} backlink%s",
"backlinks_link+one": "",
"backlinks_link+other": "s",
"subhyphae": "Subhyphae",
"random_no_hyphae": "There are no hyphae",
@ -57,9 +45,9 @@
"diff_title": "Diff of {{.name}} at {{.rev}}",
"revision_title": "{{.name}} at {{.rev}}",
"revision_warning": "Please note that viewing media is not supported in history for now.",
"revision_link": "Get Mycomarkup source of this revision",
"revision_title": "",
"revision_warning": "",
"revision_link": "",
"revision_no_text": "This hypha had no text at this revision.",
"about_title": "About {{.name}}",
@ -76,25 +64,6 @@
"media_noaudio": "Your browser does not support audio.",
"media_noaudio_link": "Download audio",
"media_title": "Media of {{.name}}",
"media_empty": "This hypha has no media, you can upload it here.",
"media_tip": "You can manage the hypha's media on this page.",
"media_what_is": "What is media?",
"media_upload": "Upload",
"media_stat": "Stat",
"media_stat_size": "File size:",
"media_size_value": "{{.n}} byte%s",
"media_size_value+one": "",
"media_size_value+other": "s",
"media_stat_mime": "MIME type:",
"media_include": "Include",
"media_include_tip": "This media is an image. To include it in a hypha, use a syntax like this:",
"media_new": "media",
"media_new_tip": "You can upload a new media. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.",
"media_remove": "Remove media",
"media_remove_tip": "Please note that you don't have to remove media before uploading a new media.",
"media_remove_button": "Remove media",
"confirm": "Confirm",
"cancel": "Cancel"
}

View File

@ -8,14 +8,14 @@
"backlinks_heading": "Обратные ссылки на {{.hypha_link}}",
"backlinks_desc": "Ниже перечислены гифы, на которых есть ссылка на эту гифу, трансклюзия этой гифы или эта гифа вставлена как изображение.",
"edit_link": "Редактировать",
"logout_link": "Выйти",
"history_link": "История",
"rename_link": "Переименовать",
"delete_link": "Удалить",
"text_link": "Посмотреть разметку",
"media_link": "Медиа",
"media_link_for_textual": "Превратить в медиа-гифу",
"edit_link": "",
"logout_link": "",
"history_link": "",
"rename_link": "",
"delete_link": "",
"text_link": "",
"media_link": "",
"media_link_for_textual": "",
"backlinks_link": "{{.n}} %s сюда",
"backlinks_link+one": "ссылка",
"backlinks_link+few": "ссылки",
@ -59,9 +59,9 @@
"ask_really": "Вы действительно хотите {{.verb}} гифу «{{.name}}»?",
"ask_remove_media_verb": "убрать медиа",
"revision_title": "{{.name}} из {{.rev}}",
"revision_warning": "Обратите внимание, просмотр медиа в истории пока что недоступен.",
"revision_link": "Посмотреть Микоразметку для этой ревизии",
"revision_title": "",
"revision_warning": "",
"revision_link": "",
"revision_no_text": "В этой ревизии гифы не было текста.",
"about_title": "О {{.name}}",
@ -78,26 +78,6 @@
"media_noaudio": "Ваш браузер не поддерживает аудио.",
"media_noaudio_link": "Скачать аудио",
"media_title": "Медиа «{{.name}}»",
"media_empty": "Эта гифа не имеет медиа, здесь вы можете его загрузить.",
"media_tip": "На этой странице вы можете управлять медиа.",
"media_what_is": "Что такое медиа?",
"media_upload": "Загрузить",
"media_stat": "Свойства",
"media_stat_size": "Размер файла:",
"media_size_value": "{{.n}} %s",
"media_size_value+one": "байт",
"media_size_value+few": "байта",
"media_size_value+many": "байт",
"media_stat_mime": "MIME-тип:",
"media_include": "Добавление",
"media_include_tip": "Это медиа изображение. Чтобы добавить его в текст гифы, используйте синтаксис ниже:",
"media_new": "Прикрепить",
"media_new_tip": "Вы можете загрузить новое медиа. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.",
"media_remove": "Открепить",
"media_remove_tip": "Заметьте, чтобы заменить медиа, вам не нужно его перед этим откреплять.",
"media_remove_button": "Открепить",
"confirm": "Применить",
"cancel": "Отмена"
}

View File

@ -3,7 +3,6 @@
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=history
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=mycoopts
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=auth
//go:generate go run github.com/valyala/quicktemplate/qtc -dir=hypview
package main
import (

View File

@ -5,7 +5,7 @@ import (
"fmt"
"github.com/bouncepaw/mycorrhiza/internal/cfg"
"github.com/bouncepaw/mycorrhiza/util"
viewutil2 "github.com/bouncepaw/mycorrhiza/web/viewutil"
"github.com/bouncepaw/mycorrhiza/web/viewutil"
"html/template"
"strings"
)
@ -27,6 +27,15 @@ func NewPage(fs embed.FS, russianTranslation map[string]string, tmpls ...string)
Funcs(template.FuncMap{
"beautifulName": util.BeautifulName,
"inc": func(i int) int { return i + 1 },
"base": func(hyphaName string) string {
parts := strings.Split(hyphaName, "/")
return parts[len(parts)-1]
},
"beautifulLink": func(hyphaName string) template.HTML {
return template.HTML(
fmt.Sprintf(
`<a href="/hypha/%s">%s</a>`, hyphaName, hyphaName))
},
}).
Parse(fmt.Sprintf(`
{{define "wiki name"}}%s{{end}}
@ -67,6 +76,13 @@ func NewPage(fs embed.FS, russianTranslation map[string]string, tmpls ...string)
}
russianTranslation["search by title"] = "Поиск по названию"
russianTranslation["login"] = "Войти"
russianTranslation["register"] = "Регистрация"
russianTranslation["cancel"] = "Отмена"
russianTranslation["categories"] = "Категории"
russianTranslation["remove from category title"] = "Убрать гифу из этой категории"
russianTranslation["placeholder"] = "Название категории..."
russianTranslation["add to category title"] = "Добавить гифу в эту категорию"
return &Page{
TemplateEnglish: en,
@ -84,13 +100,13 @@ func translationsIntoTemplates(m map[string]string) string {
return sb.String()
}
func (p *Page) RenderTo(meta viewutil2.Meta, data map[string]any) error {
func (p *Page) RenderTo(meta viewutil.Meta, data map[string]any) error {
data["Meta"] = meta
data["HeadElements"] = meta.HeadElements
data["BodyAttributes"] = meta.BodyAttributes
data["CommonScripts"] = cfg.CommonScripts
data["EditScripts"] = cfg.EditScripts
data["HeaderLinks"] = viewutil2.HeaderLinks
data["HeaderLinks"] = viewutil.HeaderLinks
tmpl := p.TemplateEnglish
if meta.LocaleIsRussian() {

View File

@ -11,6 +11,7 @@ var fs embed.FS
var pageOrphans, pageBacklinks, pageUserList, pageChangePassword *newtmpl.Page
var pageHyphaDelete, pageHyphaEdit, pageHyphaEmpty, pageHypha *newtmpl.Page
var pageRevision, pageMedia *newtmpl.Page
var panelChain, listChain, newUserChain, editUserChain, deleteUserChain viewutil.Chain
func initPages() {
@ -24,32 +25,19 @@ func initPages() {
pageOrphans = newtmpl.NewPage(fs, map[string]string{
"orphaned hyphae": "Гифы-сироты",
"orphan description": "Ниже перечислены гифы без ссылок на них.",
}, "views/orphans.html", map[string]string{
"orphaned hyphae": "Гифы-сироты",
"orphan description": "Ниже перечислены гифы без ссылок на них.",
})
}, "views/orphans.html")
pageBacklinks = newtmpl.NewPage(fs, map[string]string{
"backlinks to text": `Обратные ссылки на {{.}}`,
"backlinks to link": `Обратные ссылки на <a href="/hypha/{{.}}">{{beautifulName .}}</a>`,
"description": `Ниже перечислены гифы, на которых есть ссылка на эту гифу, трансклюзия этой гифы или эта гифа вставлена как изображение.`,
}, "views/backlinks.html", map[string]string{
"backlinks to text": `Обратные ссылки на {{.}}`,
"backlinks to link": `Обратные ссылки на <a href="/hypha/{{.}}">{{beautifulName .}}</a>`,
"description": `Ниже перечислены гифы, на которых есть ссылка на эту гифу, трансклюзия этой гифы или эта гифа вставлена как изображение.`,
})
}, "views/backlinks.html")
pageUserList = newtmpl.NewPage(fs, map[string]string{
"title": "Список пользователей",
"administrators": "Администраторы",
"moderators": "Модераторы",
"editors": "Редакторы",
"readers": "Читатели",
}, "views/user-list.html", map[string]string{
"title": "Список пользователей",
"administrators": "Администраторы",
"moderators": "Модераторы",
"editors": "Редакторы",
"readers": "Читатели",
})
}, "views/user-list.html")
pageChangePassword = newtmpl.NewPage(fs, map[string]string{
"change password": "Сменить пароль",
"confirm password": "Повторите пароль",
@ -57,25 +45,13 @@ func initPages() {
"non local password change": "Пароль можно поменять только местным аккаунтам. Telegram-аккаунтам нельзя.",
"password": "Пароль",
"submit": "Поменять",
}, "views/change-password.html", map[string]string{
"change password": "Сменить пароль",
"confirm password": "Повторите пароль",
"current password": "Текущий пароль",
"non local password change": "Пароль можно поменять только местным аккаунтам. Telegram-аккаунтам нельзя.",
"password": "Пароль",
"submit": "Поменять",
})
}, "views/change-password.html")
pageHyphaDelete = newtmpl.NewPage(fs, map[string]string{
"delete hypha?": "Удалить {{beautifulName .}}?",
"delete [[hypha]]?": "Удалить <a href=\"/hypha/{{.}}\">{{beautifulName .}}</a>?",
"want to delete?": "Вы действительно хотите удалить эту гифу?",
"delete tip": "Нельзя отменить удаление гифы, но её история останется доступной.",
}, "views/hypha-delete.html", map[string]string{
"delete hypha?": "Удалить {{beautifulName .}}?",
"delete [[hypha]]?": "Удалить <a href=\"/hypha/{{.}}\">{{beautifulName .}}</a>?",
"want to delete?": "Вы действительно хотите удалить эту гифу?",
"delete tip": "Нельзя отменить удаление гифы, но её история останется доступной.",
})
}, "views/hypha-delete.html")
pageHyphaEdit = newtmpl.NewPage(fs, map[string]string{
"editing hypha": `Редактирование {{beautifulName .}}`,
"editing [[hypha]]": `Редактирование <a href="/hypha/{{.}}">{{beautifulName .}}</a>`,
@ -87,65 +63,45 @@ func initPages() {
"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": `Ссылка на вас`,
}, "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 local": `Местная дата`,
"current time local": `Местное время`,
"current date utc": "Дата UTC",
"current time utc": "Время UTC",
"selflink": `Ссылка на вас`,
}, "views/hypha-edit.html")
pageHypha = newtmpl.NewPage(fs, map[string]string{
"edit text": "Редактировать",
"log out": "Выйти",
"admin panel": "Админка",
"subhyphae": "Подгифы",
"history": "История",
"rename": "Переименовать",
"delete": "Удалить",
"view markup": "Посмотреть разметку",
"manage media": "Медиа",
"turn to media": "Превратить в медиа-гифу",
"backlinks": "{{.BacklinkCount}} обратн{{if eq .BacklinkCount 1}}ая ссылка{{else if and (le .BacklinkCount 4) (gt .BacklinkCount 1)}}ые ссылки{{else}}ых ссылок{{end}}",
"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, map[string]string{
"empty heading": `Эта гифа не существует`,
"empty no rights": `У вас нет прав для создания новых гиф. Вы можете:`,
"empty log in": `Войти в свою учётную запись, если она у вас есть`,
@ -157,18 +113,27 @@ func initPages() {
"upload a media": `Загрузить медиа`,
"upload a media tip": `Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные можно только скачать и просмотреть локально. Позже вы можете дописать пояснение к этому медиа.`,
"upload a media btn": `Загрузить`,
}, "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, map[string]string{}, "views/hypha.html", map[string]string{})
}, "views/hypha.html")
pageRevision = newtmpl.NewPage(fs, map[string]string{
"revision warning": "Обратите внимание, просмотр медиа в истории пока что недоступен.",
"revision link": "Посмотреть Микоразметку для этой ревизии",
"hypha at rev": "{{.HyphaName}} на {{.RevHash}}",
}, "views/hypha-revision.html")
pageMedia = newtmpl.NewPage(fs, map[string]string{ // TODO: сделать новый перевод
"media title": "Медиа «{{.HyphaName | beautifulLink}}»",
"tip": "На этой странице вы можете управлять медиа.",
"empty": "Эта гифа не имеет медиа, здесь вы можете его загрузить.",
"what is media?": "Что такое медиа?",
"stat": "Свойства",
"stat size": "Размер файла:",
"stat mime": "MIME-тип:",
"upload title": "Прикрепить",
"upload tip": "Вы можете загрузить новое медиа. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.",
"upload btn": "Загрузить",
"remove title": "Открепить",
"remove tip": "Заметьте, чтобы заменить медиа, вам не нужно его перед этим откреплять.",
"remove btn": "Открепить",
}, "views/hypha-media.html")
}

View File

@ -17,8 +17,10 @@ import (
"html/template"
"io"
"log"
"log/slog"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"time"
@ -64,15 +66,31 @@ func handlerMedia(w http.ResponseWriter, rq *http.Request) {
hyphaName = util.HyphaNameFromRq(rq, "media")
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
isMedia = false
mime string
fileSize int64
)
util.HTTP200Page(w,
viewutil.Base(
viewutil.MetaFrom(w, rq),
lc.Get("ui.media_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}),
hypview.MediaMenu(rq, h, u),
map[string]string{},
))
switch h := h.(type) {
case *hyphae.MediaHypha:
isMedia = true
mime = mimetype.FromExtension(path.Ext(h.MediaFilePath()))
fileinfo, err := os.Stat(h.MediaFilePath())
if err != nil {
slog.Error("failed to stat media file", "err", err)
// no return
}
fileSize = fileinfo.Size()
}
_ = pageMedia.RenderTo(viewutil.MetaFrom(w, rq), map[string]any{
"HyphaName": h.CanonicalName(),
"U": u,
"IsMediaHypha": isMedia,
"MimeType": mime,
"FileSize": fileSize,
})
}
// handlerRevisionText sends Mycomarkup text of the hypha at the given revision. See also: handlerRevision, handlerText.
@ -137,7 +155,7 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
var (
hyphaName = util.CanonicalName(slug)
h = hyphae.ByName(hyphaName)
contents = fmt.Sprintf(`<p>%s</p>`, lc.Get("ui.revision_no_text"))
contents = template.HTML(fmt.Sprintf(`<p>%s</p>`, lc.Get("ui.revision_no_text")))
textContents string
err error
mycoFilePath string
@ -151,26 +169,17 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
textContents, err = history.FileAtRevision(mycoFilePath, revHash)
if err == nil {
ctx, _ := mycocontext.ContextFromStringInput(textContents, mycoopts.MarkupOptions(hyphaName))
contents = mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))
contents = template.HTML(mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx)))
}
page := hypview.Revision(
viewutil.MetaFrom(w, rq),
h,
contents,
revHash,
)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprint(
w,
viewutil.Base(
viewutil.MetaFrom(w, rq),
lc.Get("ui.revision_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}),
page,
map[string]string{},
),
)
meta := viewutil.MetaFrom(w, rq)
_ = pageRevision.RenderTo(meta, map[string]any{
"ViewScripts": cfg.ViewScripts,
"Contents": contents,
"RevHash": revHash,
"NaviTitle": hypview.NaviTitle(meta, h.CanonicalName()),
"HyphaName": h.CanonicalName(),
})
}
// handlerText serves raw source text of the hypha.
@ -190,8 +199,7 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
hyphaName := util.HyphaNameFromRq(rq, "binary")
switch h := hyphae.ByName(hyphaName).(type) {
case *hyphae.EmptyHypha:
case *hyphae.TextualHypha:
case *hyphae.EmptyHypha, *hyphae.TextualHypha:
w.WriteHeader(http.StatusNotFound)
log.Printf("Textual hypha %s has no media, cannot serve\n", h.CanonicalName())
case *hyphae.MediaHypha:
@ -205,59 +213,61 @@ func handlerBinary(w http.ResponseWriter, rq *http.Request) {
func handlerHypha(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
var (
hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
h = hyphae.ByName(hyphaName)
contents string
openGraph string
lc = l18n.FromRequest(rq)
hyphaName = util.HyphaNameFromRq(rq, "page", "hypha")
h = hyphae.ByName(hyphaName)
contents template.HTML
openGraph template.HTML
lc = l18n.FromRequest(rq)
meta = viewutil.MetaFrom(w, rq)
subhyphae, prevHyphaName, nextHyphaName = tree.Tree(h.CanonicalName())
cats = categories.CategoriesWithHypha(h.CanonicalName())
category_list = ":" + strings.Join(cats, ":") + ":"
isMyProfile = cfg.UseAuth && util.IsProfileName(h.CanonicalName()) && meta.U.Name == strings.TrimPrefix(h.CanonicalName(), cfg.UserHypha+"/")
data = map[string]any{
"HyphaName": h.CanonicalName(),
"SubhyphaeHTML": subhyphae,
"PrevHyphaName": prevHyphaName,
"NextHyphaName": nextHyphaName,
"IsMyProfile": isMyProfile,
"NaviTitle": hypview.NaviTitle(meta, h.CanonicalName()),
"BacklinkCount": backlinks.BacklinksCount(h.CanonicalName()),
"GivenPermissionToModify": user.CanProceed(rq, "edit"),
"Categories": cats,
"IsMediaHypha": false,
}
)
slog.Info("reading hypha", "name", h.CanonicalName(), "can edit", data["GivenPermissionToModify"])
meta.BodyAttributes = map[string]string{
"cats": category_list,
}
switch h := h.(type) {
case *hyphae.EmptyHypha:
// contents = hypview.EmptyHypha()
util.HTTP404Page(w,
viewutil.Base(
viewutil.MetaFrom(w, rq),
util.BeautifulName(hyphaName),
hypview.Hypha(viewutil.MetaFrom(w, rq), h, ""),
map[string]string{},
openGraph))
w.WriteHeader(http.StatusNotFound)
data["Contents"] = ""
_ = pageHypha.RenderTo(meta, data)
case hyphae.ExistingHypha:
fileContentsT, errT := os.ReadFile(h.TextFilePath())
if errT == nil {
fileContentsT, err := os.ReadFile(h.TextFilePath())
if err == nil {
ctx, _ := mycocontext.ContextFromStringInput(string(fileContentsT), mycoopts.MarkupOptions(hyphaName))
getOpenGraph, descVisitor, imgVisitor := tools.OpenGraphVisitors(ctx)
openGraph = template.HTML(getOpenGraph())
ast := mycomarkup.BlockTree(ctx, descVisitor, imgVisitor)
contents = mycomarkup.BlocksToHTML(ctx, ast)
openGraph = getOpenGraph()
contents = template.HTML(mycomarkup.BlocksToHTML(ctx, ast))
}
switch h := h.(type) {
case *hyphae.MediaHypha:
contents = mycoopts.Media(h, lc) + contents
contents = template.HTML(mycoopts.Media(h, lc)) + contents
data["IsMediaHypha"] = true
}
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+"/")
data["Contents"] = contents
meta.HeadElements = append(meta.HeadElements, openGraph)
_ = pageHypha.RenderTo(meta, data)
_ = 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,
viewutil.Base(
viewutil.MetaFrom(w, rq),
util.BeautifulName(hyphaName),
hypview.Hypha(viewutil.MetaFrom(w, rq), h, contents),
map[string]string{"cats": category_list},
openGraph))
// TODO: check head cats
// TODO: check opengraph
}
}

View File

@ -1,32 +0,0 @@
{{define "empty hypha card"}}
<section class="non-existent-hypha">
<h2 class="non-existent-hypha__title">{{block "empty heading" .}}This hypha does not exist{{end}}</h2>
{{if and .UseAuth (eq .Meta.U.Group "anon")}}
<p>{{block "empty no rights" .}}You are not authorized to create new hyphae. Here is what you can do:{{end}}</p>
<ul>
<li><a href="/login">{{block "empty log in" .}}Log in to your account, if you have one{{end}}</a></li>
{{if .AllowRegistration}}<li><a href="/register">{{block "empty register" .}}Register a new account{{end}}</a></li>{{end}}
</ul>
{{else}}
<div class="non-existent-hypha__ways">
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">📝 {{block "write a text" .}}Write a text{{end}}</h3>
<p>{{block "write a text tip" .}}Write a note, a diary, an article, a story or anything textual using <a href="/help/en/mycomarkup" class="shy-link">Mycomarkup</a>. Full history of edits to the document will be saved.{{end}}</p>
<p>{{block "write a text writing conventions" .}}Make sure to follow this wiki's writing conventions if there are any.{{end}}</p>
<a class="btn btn_accent stick-to-bottom" href="/edit/{{.HyphaName}}">{{block "write a text btn" .}}Create{{end}}</a>
</section>
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">🖼 {{block "upload a media" .}}Upload a media{{end}}</h3>
<p>{{block "upload a media tip" .}}Upload a picture, a video or an audio. Most common formats can be viewed from the browser, others can only be downloaded and viewed locally. You can write a description for the media later.{{end}}</p>
<form action="/upload-binary/{{.HyphaName}}"
method="post" enctype="multipart/form-data"
class="upload-binary">
<input type="file" id="upload-binary__input" name="binary">
<button type="submit" class="btn stick-to-bottom" value="Upload">{{block "upload a media btn" .}}Upload{{end}}</button>
</form>
</section>
</div>
{{end}}
</section>
{{end}}

View File

@ -0,0 +1,57 @@
{{define "title"}}{{end}}
{{define "body"}}
<main class="main-width media-tab">
<h1>{{block "media title" .}}Media of {{.HyphaName | beautifulLink }}{{end}}</h1>
<p class="explanation">
{{if .IsMediaHypha}}
{{block "tip" .}}You can manage the hypha's media on this page.{{end}}
{{else}}
{{block "empty" .}}This hypha has no media, you can upload it here.{{end}}
{{end}}
<a href="/help/en/media" class="shy-link">
{{block "what is media?" .}}What is media?{{end}}
</a>
</p>
<section class="amnt-grid">
{{if .IsMediaHypha}}
<fieldset class="amnt-menu-block"> <!-- TODO: refactor with <dl> -->
<legend class="modal__title modal__title_small">{{block "stat" .}}Stat{{end}}</legend>
<p><b>{{block "stat size" .}}File size:{{end}}</b> {{.FileSize}}</p> <!-- TODO: human readable measure -->
<p><b>{{block "stat mime" .}}MIME type:{{end}}</b> {{.MimeType}}</p>
</fieldset>
{{end}}
{{if .U.CanProceed "upload-binary" }}
<form action="/upload-binary/{{.HyphaName}}"
method="post" enctype="multipart/form-data"
class="upload-binary modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">
{{block "upload title" .}}Upload{{end}}</legend>
<p class="modal__confirmation-msg">
{{block "upload tip" .}}You can upload a new media. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.{{end}}</p>
<label for="upload-binary__input"></label> <!-- TODO: ? -->
<input type="file" id="upload-binary__input" name="binary">
<button type="submit" class="btn stick-to-bottom" value="Upload">
{{block "upload btn" .}}Upload{{end}}</button>
</fieldset>
</form>
{{end}}
{{if .IsMediaHypha | and (.U.CanProceed "remove-media")}}
<form action="/remove-media/{{.HyphaName}}" class="modal amnt-menu-block" method="POST">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">
{{block "remove title" .}}Remove media{{end}}</legend>
<p class="modal__confirmation-msg">
{{block "remove tip" .}}Please note that you don't have to remove media before uploading a new media.{{end}}</p>
<button type="submit" class="btn" value="Remove media">
{{block "remove btn" .}}Remove media{{end}}</button>
</fieldset>
</form>
{{end}}
</section>
</main>
{{end}}

View File

@ -0,0 +1,18 @@
{{define "hypha at rev"}}{{.HyphaName}} at {{.RevHash}}{{end}}
{{define "title"}}{{template "hypha at rev" .}}{{end}}
{{define "body"}}
<main class="main-width">
<section>
<p>
{{block "revision warning" .}}Please note that viewing media is not supported in history for now.{{end}}
<a href="/rev-text/{{.RevHash}}/{{.HyphaName}}">
{{block "revision link" .}}Get Mycomarkup source of this revision{{end}}
</a>
</p>
{{.NaviTitle}}
{{.Contents}}
</section>
</main>
{{range .ViewScripts}}<script src="{{.}}"></script>
{{end}}
{{end}}

View File

@ -1,47 +1,44 @@
{{define "title"}}{{.HyphaName | beautifulName}}{{end}}
{{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>
{{block "edit text" .}}Edit text{{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>
{{block "log out" .}}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>
{{block "admin panel" .}}Admin panel{{end}}</a></div>
{{end}}
{{end}}
{{.NaviTitle}}
{{.Contents}}
{{if .Contents}}{{.Contents}}{{else}}{{template "empty hypha card" .}}{{end}}
</section>
<section class="prevnext">
{{if .PrevHyphaName}}
<a class="prevnext__el prevnext__prev" href="/hypha/{{.PrevHyphaName}}" rel="prev">
← {{base .PrevHyphaName | beautifulName}}</a>
← {{.PrevHyphaName | base | beautifulName}}</a>
{{end}}
{{if .NextHyphaName}}
<a class="prevnext__el prevnext__next" href="/hypha/{{.NextHyphaName}}" rel="next">
{{base .NextHyphaName | beautifulName}} →</a>
{{.NextHyphaName | base | beautifulName}} →</a>
{{end}}
</section>
{{ if .SubhyphaeHTML }}
<section class="subhyphae">
<h2 class="subhyphae__title">{%s lc.Get("ui.subhyphae") %}</h2>
<h2 class="subhyphae__title">{{block "subhyphae" .}}Subhyphae{{end}}</h2>
<nav class="subhyphae__nav">
<ul class="subhyphae__list">
{{.SubhyphaeHTML}}
@ -51,12 +48,42 @@
{{end}}
<section id="hypha-bottom">
{{hyphaInfo(meta, h)}}
<nav class="hypha-info">
<ul class="hypha-info__list">
<li class="hypha-info__entry hypha-info__entry_history">
<a class="hypha-info__link" href="/history/{{.HyphaName}}">
{{block "history" .}}View history{{end}}</a></li>
<li class="hypha-info__entry hypha-info__entry_rename">
<a class="hypha-info__link" href="/rename/{{.HyphaName}}">
{{block "rename" .}}Rename{{end}}</a></li>
<li class="hypha-info__entry hypha-info__entry_delete">
<a class="hypha-info__link" href="/delete/{{.HyphaName}}">
{{block "delete" .}}Delete{{end}}</a></li>
<li class="hypha-info__entry hypha-info__entry_text">
<a class="hypha-info__link" href="/text/{{.HyphaName}}">
{{block "view markup" .}}View markup{{end}}</a></li>
<li class="hypha-info__entry hypha-info__entry_media">
<a class="hypha-info__link" href="/media/{{.HyphaName}}">
{{- if .IsMediaHypha -}}
{{block "manage media" .}}Manage media{{end}}
{{- else -}}
{{block "turn to media" .}}Turn to media{{end}}
{{- end}}</a></li>
<li class="hypha-info__entry hypha-info__entry_backlinks">
<a class="hypha-info__link" href="/backlinks/{{.HyphaName}}">
{{block "backlinks" .}}backlink{{if gt .BacklinkCount 1}}s{{end}}{{end}}</a></li>
</ul>
</nav>
</section>
</main>
{{template "category card" .}}
{{range .ViewScripts}}<script src="{{.}}"></script>
{{end}}
{{range .ViewScripts}}<script src="{{.}}">
</script>{{end}}
{{end}}
{{define "category card"}}
@ -95,4 +122,39 @@
{{end}}
</ul>
</aside>
{{end}}{{end}}
{{end}}
{{end}}
{{define "empty hypha card"}}
<section class="non-existent-hypha">
<h2 class="non-existent-hypha__title">{{block "empty heading" .}}This hypha does not exist{{end}}</h2>
{{if and .UseAuth (eq .Meta.U.Group "anon")}}
<p>{{block "empty no rights" .}}You are not authorized to create new hyphae. Here is what you can do:{{end}}</p>
<ul>
<li><a href="/login">{{block "empty log in" .}}Log in to your account, if you have one{{end}}</a></li>
{{if .AllowRegistration}}<li><a href="/register">{{block "empty register" .}}Register a new account{{end}}</a></li>{{end}}
</ul>
{{else}}
<div class="non-existent-hypha__ways">
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">📝 {{block "write a text" .}}Write a text{{end}}</h3>
<p>{{block "write a text tip" .}}Write a note, a diary, an article, a story or anything textual using <a href="/help/en/mycomarkup" class="shy-link">Mycomarkup</a>. Full history of edits to the document will be saved.{{end}}</p>
<p>{{block "write a text writing conventions" .}}Make sure to follow this wiki's writing conventions if there are any.{{end}}</p>
<a class="btn btn_accent stick-to-bottom" href="/edit/{{.HyphaName}}">{{block "write a text btn" .}}Create{{end}}</a>
</section>
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">🖼 {{block "upload a media" .}}Upload a media{{end}}</h3>
<p>{{block "upload a media tip" .}}Upload a picture, a video or an audio. Most common formats can be viewed from the browser, others can only be downloaded and viewed locally. You can write a description for the media later.{{end}}</p>
<form action="/upload-binary/{{.HyphaName}}"
method="post" enctype="multipart/form-data"
class="upload-binary">
<input type="file" id="upload-binary__input" name="binary">
<button type="submit" class="btn stick-to-bottom" value="Upload">{{block "upload a media btn" .}}Upload{{end}}</button>
</form>
</section>
</div>
{{end}}
</section>
{{end}}

View File

@ -1,8 +1,9 @@
package viewutil
import (
user2 "github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/internal/user"
"github.com/bouncepaw/mycorrhiza/l18n"
"html/template"
"io"
"net/http"
)
@ -10,12 +11,12 @@ import (
// Meta is a bundle of common stuffs used by views, templates.
type Meta struct {
Lc *l18n.Localizer
U *user2.User
U *user.User
W io.Writer
Addr string
// New template additions
HeadElements []string
HeadElements []template.HTML
BodyAttributes map[string]string
}
@ -23,7 +24,7 @@ type Meta struct {
func MetaFrom(w http.ResponseWriter, rq *http.Request) Meta {
return Meta{
Lc: l18n.FromRequest(rq),
U: user2.FromRequest(rq),
U: user.FromRequest(rq),
W: w,
Addr: rq.URL.Path,
}