1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2024-10-30 11:46:16 +00:00

Merge pull request #95 from chekoopa/l18n

Initial l18n support
This commit is contained in:
Umar Getagazov 2021-09-27 19:01:38 +07:00 committed by GitHub
commit 04de18ebfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 5003 additions and 2212 deletions

1
go.mod
View File

@ -13,6 +13,7 @@ require (
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b
golang.org/x/text v0.3.7
gopkg.in/ini.v1 v1.62.0 // indirect
)

2
go.sum
View File

@ -46,6 +46,8 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlA
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=

View File

@ -11,10 +11,10 @@ You can upload any file, but only those listed below will be displayed on the we
## How to add an attachment?
For non-existent hyphae, upload a file in the //Upload a media// section.
For any hyphae, upload a file in the //Attachment// tab.
For any hyphae, upload a file in the //Manage attachment// tab.
## Attachment tab
Every hypha has the //Attachment// tab. Click it to see what is out there.
## Attachment management
Every hypha has the //Manage attachment// section. Click it to see what is out there.
You can upload a new file, you can //delete// the attachment (it is called //unattaching//) and see some file stats (size and type).
@ -31,4 +31,4 @@ If a hypha has an attachment, here is what the text part might be about:
* Some meta data.
* Things above combined.
The attachment //should not// be an illustration.
The attachment //should not// be an illustration of the text part. In this case it is better to put it into a subhypha and embed it into the markup.

View File

@ -38,9 +38,9 @@ Second line of paragraph 2
You can apply styling to paragraph content.
* {```
You can use //italic//, **bold**, `monospace`, ++highlighted++, ^^lifted^^, __underscored__, ,,lowered,, or ~~striked-through~~ text. You can also ++//combine//++ them!
You can use //italic//, **bold**, `monospace`, ++highlighted++, ^^lifted^^, __underscored__, ,,lowered,, or ~~striked-through~~ text. You can also ++**//combine//**++ them!
```}
* You can use //italic//, **bold**, `monospace`, ++highlighted++, ^^lifted^^, __underscored__, ,,lowered,, or ~~striked-through~~ text. You can also ++//combine//++ them!
* You can use //italic//, **bold**, `monospace`, ++highlighted++, ^^lifted^^, __underscored__, ,,lowered,, or ~~striked-through~~ text. You can also ++**//combine//**++ them!
Use the backslash to prevent the styling.
* {```
@ -111,7 +111,7 @@ You don't have to write the full hypha name in every link, you can use **relativ
Consider you are editing a hypha called //fruit/apple//.
To link //fruit/pear// (a sister hypha) you can write `[\[../pear]]`. To link //fruit/apple/red// (a subhypha) you can write `[\[./red]]`. You can do the same in rocket links, image galleries, transclusion and everywhere else you write hypha names.
To link //fruit/pear// (a sibling hypha) you can write `[\[../pear]]`. To link //fruit/apple/red// (a subhypha) you can write `[\[./red]]`. You can do the same in rocket links, image galleries, transclusion and everywhere else you write hypha names.
There is also a way to link the wiki's non-hypha pages. For example, to link the Recent changes page, you can write `[\[/recent-changes]]`. You should use that rather than write the site's full URL because it may change in the future.
@ -132,7 +132,7 @@ There are six levels of **headings**. They consist of some hash signs followed b
###### level 6
```
There is an invisible link denoted by the § sign near every heading. You can reveal it with a mouse. If you click it, the URL in the browser will change to the URL leading to that very heading. Try that on headings in this article.
There is an invisible link denoted by the § sign near every heading (right after the heading text). You can reveal it with a mouse. If you click it, the URL in the browser will change to the URL leading to that very heading. Try that on headings in this article.
## Codeblock
Use **codeblocks** to show code or any other preformatted text. Codeblocks start with triple backticks on column 1 and end similarly. You can write any text after the backticks, it is ignored. Put the preformatted text between them.
@ -394,4 +394,4 @@ This is an actual transclusion of a hypha below. It will fail if your wiki does
Recursive transclusion is also supported but it is limited to three iterations.
## See also
=> https://mycorrhiza.wiki/hypha/essay/why_mycomarkup Why it was created
=> https://mycorrhiza.wiki/hypha/essay/why_mycomarkup Why it was created

View File

@ -32,6 +32,7 @@ If both fields are both set, the engine will enable Telegram authorization.
On login and register pages there is a blue button. If a user clicks it, they are prompted to give the authorization permission to your bot. The user's @username will be used as wiki username. Telegram users are part of the //editor// user group by default. Telegram users can use the wiki just like everyone else.
## Limitations
* You should host your wiki using a public IP or domain name. Private-hosted (i.e. localhost or LAN) wikis are not supported, obviously.
* Telegram does not support HTTP wikis, you //must// use HTTPS.
** One way of setting up HTTPS is using [[https://certbot.eff.org | certbot]] and a reverse proxy such as [[https://nginx.org | nginx]].
* Telegram users without @username cannot authorize.

View File

@ -6,6 +6,7 @@ import (
)
//go:embed en en.myco
//go:embed ru ru.myco
var fs embed.FS
// Get determines what help text you need and returns it. The path is a substring from URL, it follows this form:

9
help/ru.myco Normal file
View File

@ -0,0 +1,9 @@
# Справка
Это документация к **вики-движку Микориза** версии **1.5** ([[https://mycorrhiza.wiki | официальная вики]]).
**Выберите тему из списка.**
В настоящее время документация охватывает не всё, что должна охватить, но в будущем это наверняка изменится.
Если вы хотите внести правки в эту документацию, создайте pull request или issue в [[https://github.com/bouncepaw/mycorrhiza | репозитории на GitHub]].

34
help/ru/attachment.myco Normal file
View File

@ -0,0 +1,34 @@
# Справка: Вложение
В контексте гиф **вложение** — это содержимое, представленное в виде ином, чем [[/help/ru/mycomarkup | микоразметка]]. Чаще всего это изображение, видео или аудио.
## Поддерживаемые типы вложений
Вы можете загружать любые файлы, но только перечисленные ниже будут отображаться на странице. Но в то же время вы можете скачивать неподдерживаемые вложения.
* **Изображения:** jpg, gif, png, webp, svg, ico
* **Видео:** ogg, webm, mp4
* **Аудио:** ogg, webm, mp3
## Как добавить вложение?
Для несуществующих гиф, загрузите файл в разделе //Загрузить медиа//.
Также для всех гиф есть ссылка //Вложение// в подвале.
## Управление вложением
У каждой гифы есть раздел //Вложение//. Нажмите на ссылку в подвале, чтобы увидеть, что в нём находится.
Здесь вы можете загрузить новый файл, //удалить// вложение (здесь это называется //открепление//) и посмотреть свойства файла (размер и тип).
## Об именовании гиф с вложениями
В большинстве случаев название гифы не должно просто копировать название файла. Если вы загружаете фотографию розы, не называйте её `rose.jpg`, нет. Назовите её `фотография розы` или `фото розы` или как-нибудь иначе. В работе с Микоризой вам очень редко понадобится обращаться к расширениям файлов.
Конечно, это не правило, скорее просто соглашение.
## Что поместить в текстовую часть?
Если у гиф есть вложение, о чём может быть текстовая часть:
* Текстовое описание или представление изображения.
* Транскрипт песни.
* Анализ вложения.
* Какие-нибудь метаданные.
* Сочетание перечисленного выше.
Вложение //не должно// быть иллюстрацией текстовой части. В подобных случаях лучше загрузить его в подгифу и добавить ссылку в разметку.

35
help/ru/hypha.myco Normal file
View File

@ -0,0 +1,35 @@
# Справка: Гифа
**Гифа** (//англ.// hypha, //мн.// hyphae) — основная единица содержимого, используемая в Микоризе.
## Структура гифы
Гифа состоит из двух частей:
* **Вложение.** Определённый вид медиаданных. Гифа может содержать только одно вложение. См. [[/help/ru/attachment | Вложение]], чтобы узнать больше.
* **Текстовая часть.** Это либо описание вложения, либо самостоятельная единица текста, будь то статья, дневник или стих. Пишется с помощью специальной разметки, называемой [[/help/ru/mycomarkup | микоразметкой]].
Эти части сами по себе необязательны. Вы можете разместить картинку без описания, статью без вложения и т.д. Можете использовать обе части вместе. Но минимум одна из них обязана присутствовать.
## Как создать гифу?
Некоторые ссылки в вики окрашены красным. Это означает, что они ведут на ещё не существующую гифу. Если вы пройдёте по ссылке, вы увидите специальную страницу, на которой можно загрузить вложение или перейти в текстовый редактор. Таким образом и создаются гифы.
Вы можете создавать подобные красные ссылки и переходить по ним, чтобы создавать новые гифы.
Как вариант, можно прописать нужный адрес в браузере, чтобы перейти сразу на страницу создания.
## Названия гиф
Названия гиф регистронезависимы. Это значит, что названия //amanita muscaria// и //Amanita Muscaria// указывают на одну и ту же гифу. Также эквивалентны пробел и знак подчёркивания (//amanita muscaria// = //amanita_muscaria//). Канонические названия пишутся полностью в нижнем регистре и через подчёркивания.
Есть символы, которые нельзя использовать в названии: `?!:#@><*|"'&%{}\\` Остальные можно.
## Генеалогия
**Подгифа** — это гифа, название которой начинается с названия другой гифы, после чего через косую черту (слэш) следует собственная часть названия. Например, гифа //Фрукт/Яблоко// является подгифой для //Фрукт//. Подгиф может быть сколько угодно, а подгифы могут содержать свои подгифы.
Так, **надгифа** (superhypha) — обратное подгифе: //Фрукт// — надгифа для //Фрукт/Яблоко//. Существует лишь одна надгифа.
**Гифы-сиблинги** — гифы, являющиеся подгифами одной и той же гифы. Например, //Фрукт/Яблоко// и //Фрукт/Груша// приходятся сиблингами.
## Слово
Английское слово //hypha// произносится как /ˈhaɪfə/. Множественная форма — //hyphae//. Произносите её как /ˈhaɪfi/.
Слово «гифа» происходит из микологии, науки о грибах. Им обозначают тонкие белые нити, формирующие мицелий. См. [[https://en.wikipedia.org/wiki/Hypha | эту статью на Википедии]], чтобы узнать больше о настоящих гифах.
Рассматривайте гифы Микоризы как малые элементы, из которых строится ваша вики.

27
help/ru/lock.myco Normal file
View File

@ -0,0 +1,27 @@
# Блокировка
//Эта статья предназначена для администраторов вики.//
Иногда вы можете захотеть, чтобы доступ к вики имели только авторизованные пользователи. В таких случаях пригодится **блокировка**.
## Включение
Чтобы включить блокировку, в `config.ini` поменяйте значение `Locked` на `true`. `UseAuth` также должен быть `true`.
```ini
...
[Authorization]
UseAuth = true
Locked = true
...
```
Перезагрузите вики.
## Применение
Когда неавторизованные гости зайдут на вашу вики, они увидят что-то похожее на это:
img {
https://mycorrhiza.wiki/binary/release/1.3/lock_screenshot
}
После авторизации они смогут просматривать вики. Но зарегистрироваться отсюда они не могут. Поддерживается авторизация через [[/help/ru/telegram | Телеграм]].
## См. также
=> /help/ru/whitelist Белый список

397
help/ru/mycomarkup.myco Normal file
View File

@ -0,0 +1,397 @@
# Микоразметка
**Микоразметка** — это собственный язык разметки в Микоризе.
Это единственная поддерживаемая разметка; другие разметки, будь то Markdown, Creole и прочие, не поддерживаются.
Документ в микоразметке (чаще всего это текстовая часть гифы) состоит из //блоков//. Для разных задач существуют разные блоки.
## Содержание
=> /help/ru/mycomarkup#Абзац Абзац
=> /help/ru/mycomarkup#Внутритекстовая_ссылка Внутритекстовая ссылка
=> /help/ru/mycomarkup#Ссылка_ракета Ссылка-ракета
=> /help/ru/mycomarkup#Заголовок Заголовок
=> /help/ru/mycomarkup#Код_блок Код-блок
=> /help/ru/mycomarkup#Горизонтальная_черта Горизонтальная черта
=> /help/ru/mycomarkup#Галерея_изображений Галерея изображений
=> /help/ru/mycomarkup#Список Список
=> /help/ru/mycomarkup#Цитата Цитата
=> /help/ru/mycomarkup#Таблица Таблица
=> /help/ru/mycomarkup#Трансклюзия Трансклюзия
## Абзац
**Абзацы** — самые распространённые блоки. Вы будете использовать их чаще остальных.
Чтобы создать абзац, просто напишите текст. Абзацы отделяются друг от друга пустыми строками.
* {```
Первый абзац
Второй абзац
Вторая строка второго абзаца
```}
* {
Первый абзац
Второй абзац
Вторая строка второго абзаца
}
Вы можете применять стили к содержимому абзаца.
* {```
Вы можете использовать //курсив//, **жирный**, `моноширинный`, ++выделенный++, ^^надстрочный^^, __подчёркнутый__, ,,подстрочный,, или ~~зачёркнутый~~ текст. А также вы можете их ++**//сочетать//**++!
```}
* Вы можете использовать //курсив//, **жирный**, `моноширинный`, ++выделенный++, ^^надстрочный^^, __подчёркнутый__, ,,подстрочный,, или ~~зачёркнутый~~ текст. А также вы можете их ++**//сочетать//**++!
Используйте обратный слэш (`\`), чтобы отменить стиль.
* {```
Это не \//курсив\//
```}
* Это не \//курсив\//
Вы можете не закрывать декоратор, и тогда стиль будет действовать до конца строки.
* {```
Это //курсив
А это — нет
```}
* {
Это //курсив
А это — нет
}
Вы можете добавлять ссылки.
* {```
Просто абзац с парой [[https://example.org | ссылок]], ведущих [[никуда]].
```}
* Просто абзац с парой [[https://example.org | ссылок]], ведущих [[никуда]].
## Ссылка
### Внутритекстовая ссылка
**Внутритекстовые ссылки** размещаются внутри абзацев.
Внешние ссылки можно помещать как есть, если они содержат протокольную часть. Такие ссылки называются автоссылками. Но иногда они могут работать не совсем, как от них ожидается. Автоссылки поддерживаются для протоколов https, http, gemini, gopher и ftp.
* {```
https://example.org
```}
* https://example.org
Оборачивайте ссылки на гифы и внешние ресурсы в `[\[` и `]]`.
* {```
По ссылкам откроются [[гифа]] и [[https://example.org]].
```}
* По ссылкам откроются [[гифа]] и [[https://example.org]].
Если вы хотите поменять отображаемый текст у ссылки, пропишите его после `|`.
* {```
Ссылка на [[гифа | другую гифу]] и [[https://example.org | какой-то сайт]].
```}
* Ссылка на [[гифа | другую гифу]] и [[https://example.org | какой-то сайт]].
Так как названия гиф не чувствительны к регистру, эти ссылки функционально одинаковы: `[[гифа]]`, `[[Гифа]]`, `[[ГИФА]]`.
### Ссылка-ракета
**Ссылки-ракеты** — особые ссылки. Они занимают целую строку. Они не согласуются с обычными внутритекстовыми ссылками. Ссылки-ракеты взяты из разметки [[https://gemini.circumlunar.space/docs/gemtext.gmi | gemtext]].
Отображаемый текст пишется после первого пробела, не `|`. Если вы пишете ссылку на гифу с пробелами в названии, замените пробелы на _.
* {```
=> гифа
=> гифа_с_пробелами
=> https://example.org
=> https://example.org Отображаемый текст
```}
* {
=> гифа
=> гифа_с_пробелами
=> https://example.org
=> https://example.org Отображаемый текст
}
### Относительная адресация
Необязательно писать полное название гифы в каждой ссылке, достаточно использовать **относительные** ссылки.
Допустим, вы редактируете гифу под названием //фрукт/яблоко//.
Чтобы сослаться на //фрукт/груша// (гифа-сиблинг), можно написать `[\[../груша]]`. Чтобы сослаться на //фрукт/яблоко/красный// (подгифа), можно написать `[\[./красный]]`. То же самое можно делать с ссылками-ракетами, галереями, трансклюзиями и прочими местами, использующими названия гиф.
Также есть возможность ссылаться на страницы вики, не являющиеся гифами. Например, чтобы сделать ссылку на страницу с недавними изменениями, вы можете написать `[\[/recent-changes]]`. Лучше писать так вместо того, чтобы указывать полный адрес сайта, так как в будущем он может поменяться.
### Цвета ссылок
Ссылки могут иметь разные цвета. Синие ссылки ведут на //существующие// страницы, когда как красные ведут на //отсутствующие//. Все внешние ссылки считаются существующими, следовательно, они всегда синие. Внутренние ссылки на гифы всегда проверяются на существование.
Заметьте, что посещённые синие ссылки окрашиваются в пурпурный, но всё равно называются синими. Более того, синие ссылки имеют жёлтый цвет в стандартной тёмной теме.
## Заголовок
Есть шесть уровней **заголовков**. Они начинаются с одного или более знака решётки, после через пробел пишется текст заголовка. Вы можете оформлять заголовок также, как абзац. Желательно не использовать заголовки 1 уровня, потому что на этом уровне уже находится название гифы.
```
# уровень 1
## уровень 2
### уровень 3
#### уровень 4
##### уровень 5
###### уровень 6
```
Рядом с каждым заголовком (сразу после его текста) есть невидимая ссылка в виде знака §. Она появляется при наведении курсора. Если вы нажмёте на ссылку, URL в адресной строке заменится на URL, ведущий на соответствующий заголовок этой страницы. Попробуйте проделать это с заголовками в этой статье.
## Код-блок
Используйте **код-блоки** для отображения кода или иного преформатированного текста. Код-блоки начинаются с трёх обратных кавычек в начале строки и заканчиваются тем же образом. После обратных кавычек в пределах строки можно писать любой текст, он игнорируется. Преформатированный текст пишется между строк с кавычками.
Примерно так, но без пробела в начале:
```
```
оно преформатированное
видите?
```
```
```
оно преформатированное
видите?
```
## Горизонтальная черта
Пропишите четыре дефиса, чтобы вставить **горизонтальную черту**.
* {```
----
```}
* ----
## Галерея изображений
Используйте **галереи изображений**, чтобы встраивать изображения в страницу. Изображения могут быть гифами или внешними файлами. В примере ниже вы можете заменить URL названием гифы. Если эта гифа — изображение, оно появится в галерее.
Для изображения можно задать описание и определить размер.
* {```
img {
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg {
Описание //здесь//
}
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 100 { Размер }
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 50*50
}
```}
* {
img {
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg {
Описание //здесь//
}
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 100 { Размер }
https://upload.wikimedia.org/wikipedia/commons/4/48/Timbre_ciuperci_otravitoare.jpg | 50*50 { Квадрат }
}
}
Если вы встраиваете гифу под названием //гифа-изображение//, разметка будет выглядеть так:
* {```
img {
гифа-изображение
}
```}
Если вы пропишете одно единственное изображение, оно будет отображаться без декораций:
* {```
img { https://mycorrhiza.wiki/static/favicon.ico }
```}
* {img { https://mycorrhiza.wiki/static/favicon.ico }}
## Список
**Списки** используются отображения упорядоченных или древовидных данных. Они весьма распространены.
Каждый пункт списка начинается со звёздочки и пробела:
* {```
* раз
* два
* три
```}
* {
* раз
* два
* три
}
Если после звёздочки прописать точки, список становится нумерованным:
* {```
*. раз
*. два
*. три
```}
* {
*. раз
*. два
*. три
}
Если вы пропишете `x` или `v`, вы превратите пункты в соответственно незавершённные и завершённые пункты списка дел (T\ODO).
* {```
*v Готово
*x Не готово
**v Очень готово
** Круто
```}
* {
*v Готово
*x Не готово
**v Очень готово
** Круто
}
В пунктах списка поддерживается вся микоразметка. Если вы хотите прописать многострочный пункт, оберните его содержимое в фигурные скобки.
* {```
* {
## Заголовок
Текст
}
* Не многострочное
```}
* {
* {
## Заголовок
Текст
}
* Не многострочное
}
## Цитата
Начните строку с `>`, чтобы поместить её в цитату.
* {```
> ## Заголовок
>
> Абзац
> > Вложенная цитата
```}
* {
> ## Заголовок
>
> Абзац
> > Вложенная цитата
}
## Таблица
**Таблицы** прописываются в блоке вида `table {...}`. Обе ограничивающие части блока должны размещаться на своих строках. На первой строке вы можете прописать заголовок таблицы.
```
Пустая таблица:
table {
}
```
Пустая таблица:
table {
}
```
table { Пустая таблица с заголовком
}
```
table { Пустая таблица с заголовком
}
Ячейки-заголовки начинаются с !, обычные — с |. Ряды таблицы отделяются переносами строки:
```
table {
! Понедельник ! Пятница
| день тяжёлый | день весёлый
}
```
table {
! Понедельник ! Пятница
| день тяжёлый | день весёлый
}
Ячейки таблицы поддерживают всё форматирование абзаца:
```
table {
! Понедельник ! Пятница
| день тяжёлый | //день весёлый//
}
```
table {
! Понедельник ! Пятница
| день тяжёлый | //день весёлый//
}
Если вы хотите, чтобы ячейка занимала несколько столбцов, пропишите символ начала этой ячейки нужное число раз подряд (без пробелов):
```
table {
! Понедельник ! Пятница
|| нормальный день
}
```
table {
! Понедельник ! Пятница
|| нормальный день
}
Пока что объединение ячеек по вертикали не поддерживается.
Если вы хотите прописать многострочную ячейку, оберните её содержимое в `{}` и продолжите таблицу после этого блока:
```
table {
| a | b
| { в этой ячейке
целых //два// абзаца! } | d
}
```
table {
| a | b
| { в этой ячейке
целых //два// абзаца! } | d
}
Вертикальные черты в начале строки можно опустить, они будут вставлены автоматически:
```
table {
a | b
c | d
}
```
table {
a | b
c | d
}
## Трансклюзия
**Трансклюзия** — механизм включения содержимого других гиф в одну гифу.
Чтобы включить гифу под названием `йогурт`, напишите строку такого вида:
```
<= йогурт
```
Строки-трансклюзии начинаются с перевёрнутой ракеты (`<=`), после которой пишется ноль или более пробелов. Текст до переноса строки или вертикальной черты (`|`) называется //целью// или //целевой гифой//. Если есть вертикальная черта, текст после неё называется //селектором//. Если черты нет, //селектор// пустой. И //цель//, и //селектор// проходят обрезку непечатных символов (strip) с обеих сторон перед дальнейшей обработкой.
```
<= целевая гифа
<= целевая гифа |
<= целевая гифа | селектор
```
Заметьте, с релиза 1.2 семантика и синтаксис трансклюзии изменились. Если вы ранее использовали трансклюзию, обновите ваши гифы. Пока что движок будет предупреждать о трансклюзиях со старым синтаксисом через двоеточие.
### Селектор
//Селектор// определяет, какая часть //целевой гифы// транклюзируется. Парсер распознаёт следующие ключевые слова:
* **full.** Транклюзировать весь документ.
* **text.** Транклюзировать весь текст.
* **attachment.** Транклюзировать только вложение.
* **description.** Транклюзировать только первый абзац.
* **overview.** Объединяет **attachment** и **description**.
Если найдено только одно из них, транклюзируется соответствующая часть. Если найдено несколько, производится б__о__льшая трансклюзия. Если не найдено ни одно, неявно подразумевается **overview**.
К этому же, если прописано слово **blend**, трансклюзия отображается без стандартных серой рамки и ссылки на //целевую гифу//.
Ниже приведена настоящая трансклюзия гифы. Она выдаст ошибку, если в вашей вики нет такой гифы.
<= u
Рекурсивная трансклюзия поддерживается, но ограничена тремя итерациями.
## См. также
=> https://mycorrhiza.wiki/hypha/essay/why_mycomarkup Почему была создана микоразметка

19
help/ru/prevnext.myco Normal file
View File

@ -0,0 +1,19 @@
# Назад/далее
Под каждой гифой есть раздел **«назад/далее»** с быстрыми ссылками на предыдущую и следующую гифы по алфавитному порядку.
Эта функция подталкивает вас именовать гифы так, чтобы использование этих ссылок имело смысл. Например, если вы храните страницы книги, вам стоит проименовать их //p01//, //p02//, //p03// и т.д.
Невозможно изменить гифы, на которую ведут ссылки этого раздела. Если вы хотите предоставить другой способ последовательной навигации, проставьте собственные ссылки.
## Горячие клавиши
Нажмите `n` (**n**ext), чтобы перейти на следующую страницу. Для перехода на предыдущую, нажмите `p` (**p**revious).
## Для администраторов: как убрать эти ссылки
Для некоторых вики эти ссылки несут мало смысла или не несут вовсе. В таком случае лучше их скрыть.
В файле `your-wiki/static/custom.css` пропишите следующее:
```css
.prevnext { display: none; }
```
Раздел останется на месте, но никто его не увидит. Горячие клавиши всё ещё будут работать.

View File

@ -0,0 +1,20 @@
# Недавние изменения
**Недавние изменения** — это специальная страница, которая содержит список последних правок в вики. По умолчанию ссылка на эту страницу помещена в [[/help/ru/top_bar | верхнюю панель]]. Также вы можете быстро перейти сюда, нажав горячие клавиши `g r`.
Обычно увлечённые и ответственные вики-редакторы регулярно заходят на эту страницу.
=> /recent-changes Посмотреть недавние изменения на этой вики
По умолчанию на странице приводится 20 последних правок. Там же вы можете выбрать другое число: 50 или 100.
Правки сгруппированы по дате.
Каждая правка имеет следующие свойства:
* **Время по UTC.**
* **Хэш коммита.** Играет роль идентификатора правки.
* **Автор,** если есть.
* **Затронутые гифы.** Большая часть действий затрагивает одну гифу (например, само редактирование), но некоторые затрагивают больше (например, рекурсивное редактирование или переименование).
* **Сообщение.** Оно поясняет, что это за правка. Формат сообщения относительно регулярен и его можно пропарсить.
## См. также
=> /help/ru/feeds Ленты

View File

@ -0,0 +1,13 @@
# Раздел с гифами-сиблингами
В правой (или нижней на небольших экранах) части страницы с гифой размещается особый раздел, перечисляющий **гифы-сиблинги**.
> **Гифы-сиблинги** — гифы, являющиеся подгифами одной и той же гифы. Например, //Фрукт/Яблоко// и //Фрукт/Груша// приходятся сиблингами.
Гифы-сиблинги приводятся в алфавитном порядке. Название гифы, которую вы просматриваете, также входит в список. Остальные пункты списка ссылки на другие гифы.
Иногда рядом с ссылками приводятся числа:
* **Нет числа.** У гифы нет подгиф.
* **Одно число.** Оно обозначает, сколько у гифы прямых подгиф.
* **Два числа.** Первое количество прямых подгиф. Второе, в скобках количество непрямых подгиф.
Для гифы //Фрукт//, подгифы //Фрукт/Яблоко// и //Фрукт/Груша// будут прямыми, а подгифы //Фрукт/Яблоко/Красное// и //Фрукт/Яблоко/Зелёное// непрямыми.

40
help/ru/telegram.myco Normal file
View File

@ -0,0 +1,40 @@
# Авторизация через Телеграм
//Эта статья предназначена для администраторов вики.//
Если вы хотите, можете разрешить пользователям входить на вашу вики с помощью **Телеграм**.
Телеграм (Telegram) — проприетарное приложение для обмена сообщениями с полмиллиарда пользователей по всему миру. Узнайте больше на [[https://telegram.org]].
## Настройка интеграции с Телеграм
Чтобы включить Телеграм-авторизацию, необходимо создать Телеграм-бота и связать его с вашей вики.
### Создание бота
Откройте чат с [[https://t.me/botfather | @BotFather]], ботом для создания других ботов. Создайте в нём бота. В следующих шагах вам понадобятся его имя (username) и ключ (token). Также вы можете задать его аватар, будет здорово, если он будет совпадать с логотипом вашей вики.
Создав бота, отправьте команду `/setdomain` и пропишите домен вашей вики.
Вам не нужно будет //размещать// этого бота. Достаточно лишь того, что он будет создан в BotFather. Вы также можете переиспользовать ранее созданного бота.
### Конфигурация
В секции `[Telegram]` файла `config.ini` впишите имя бота (без @) и его ключ:
```
[Telegram]
TelegramBotName = your_bot
TelegramBotToken = 0000000000:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
```
Затем перезагрузите вики.
Если обе опции прописаны, движок включит авториазцию через Telegram.
## Использование
На страницах входа и регистрации появится синяя кнопка. После её нажатия пользователю предложат связаться с вашим ботом, чтобы подтвердить авторизацию. Имя пользователя в Телеграм (@username) будет переиспользовано в качестве имени в вики. По умолчанию пользователи Телеграм принадлежат к группе //редакторов (editor)//. Они могут использовать вики наравне с остальными.
## Ограничения
* Ваша вики должна размещаться на публичном домене или белом IP-адресе. Приватно размещённые вики (например, в localhost или локальной сети) не поддерживаются.
* Телеграм не поддерживает вики на HTTP, вы //обязаны// использовать HTTPS.
** Один из способов настроить HTTPS — использовать [[https://certbot.eff.org | certbot]] в связке с обратным прокси, например, [[https://nginx.org | nginx]].
* Телеграм-пользователи без @имени не смогут авторизоваться.
* Телеграм-пользователи с именем, уже занятым на вики, также не смогут авторизоваться.
* В целом, это экспериментальная функция. Применяйте её на свой страх и риск.

54
help/ru/top_bar.myco Normal file
View File

@ -0,0 +1,54 @@
# Верхняя панель
**Верхняя панель** есть абсолютно на каждой странице вики. Это главный способ навигации.
На больших экранах панель разделена на две строки.
* Первая строка
** Ссылка на [[/ | главную страницу]]
** Поисковая строка
** //Если включена авторизация,//
*** //Если произведён вход,//
**** Ссылка на гифу с профилем вашего пользователя
**** //Для админов,// ссылка на панель администратора
*** //Если входа не было,//
**** Ссылка на вход
**** Ссылка на регистрацию
* Вторая строка, часто используемые ссылки. По умолчанию содержит:
** Недавние изменения
** Все гифы
** Случайная гифа
** Справка
На небольших экранах, раздел авторизации и часто используемые ссылки спрятаны в меню. Нажмите на кнопку, чтобы их увидеть. Если ваш браузер не поддерживает JavaScript, они будут перечислены как есть.
## Использование верхней панели
Предполагается, что администраторы вики сконфигурируют ссылки верхней панели под себя. Вот что вам стоит туда поместить:
* Популярные статьи
* Списки чего-либо
* Недавние изменения
* Что вам угодно, но не так много, конечно. Пространство панели ограничено.
## Конфигурация ссылок
//Этот раздел предназначен для администраторов вики.//
Чтобы поменять стандартные ссылки, сначала нужно выбрать гифу, где вы собираетесь хранить конфигурацию. Хорошим выбором может быть подгифа гифы с профилем администратора. Пропишите адрес гифы в разделе `[Hyphae]` файла `config.ini`:
```ini
...
[Hyphae]
HeaderLinksHypha = u/admin/header_links
...
```
Затем перезагрузите вики.
----
Отредактируйте гифу. Вы можете поместить в неё любую разметку. Для генерации верхней панели используются ссылки-ракеты:
```myco
=> /recent-changes История правок
=> Хайлайты
=> Философия Наши взгляды на жизнь
=> Статьи
```
Пока что, чтобы изменения вступили в силу, модератор или администратор должен открыть [[/update-header-links]].

17
help/ru/whitelist.myco Normal file
View File

@ -0,0 +1,17 @@
# Белый список
//Эта статья предназначена для администраторов вики.//
Если вы хотите ограничить круг лиц, способных авторизоваться на вашей вики, вам пригодится **белый список**.
Чтобы его включить, в секции `[Authorization]` файла `config.ini` пропишите значение `true` в `UseWhiteList`, а в поле `WhiteList` перечислите все разрешённые имена пользователей через запятую:
```
...
[Authorization]
UseWhiteList = true
WhiteList = fish,pesce,рыба
...
```
Затем перезагрузите вики.
С этого момента можно использовать только указанные имена, т.е. регистрироваться и заходить можно только под ними. С остальными именами этого не получится.

528
l18n/l18n.go Normal file
View File

@ -0,0 +1,528 @@
// Code generated by go-localize; DO NOT EDIT.
// This file was generated by robots at
// 2021-09-27 19:53:53.262188327 +0800 +08 m=+0.002302333
package l18n
import (
"bytes"
"fmt"
"strings"
"text/template"
)
var localizations = map[string]string{
"en.admin.newuser_create": "Create",
"en.admin.newuser_title": "New user",
"en.admin.panel_about": "About this wiki",
"en.admin.panel_reindex": "Reindex hyphae",
"en.admin.panel_safe": "Safe things",
"en.admin.panel_shutdown": "Shutdown wiki",
"en.admin.panel_title": "Administrative functions",
"en.admin.panel_unsafe": "Dangerous things",
"en.admin.panel_updateheader": "Update header links",
"en.admin.panel_userlist": "User list",
"en.admin.panel_users": "Manage users",
"en.admin.user_delete": "Delete",
"en.admin.user_delete_heading": "Delete user",
"en.admin.user_delete_tip": "Remove the user from the database. Changes made by the user will be preserved. It will be possible to take this username later.",
"en.admin.user_delete_warn": "Are you sure you want to delete {{.name}} from the database? This action is irreversible.",
"en.admin.user_group_heading": "Change group",
"en.admin.user_title": "User %s",
"en.admin.user_update": "Update",
"en.admin.users_actions": "Actions",
"en.admin.users_create": "Create a new user",
"en.admin.users_edit": "Edit",
"en.admin.users_group": "Group",
"en.admin.users_name": "Name",
"en.admin.users_notime": "unknown",
"en.admin.users_password": "Password",
"en.admin.users_registered": "Registered at",
"en.admin.users_reindex": "Reindex users",
"en.admin.users_title": "Manage users",
"en.auth.cookie_tip": "By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.",
"en.auth.error_password": "Wrong password.",
"en.auth.error_telegram": "Could not authorize using Telegram.",
"en.auth.error_username": "Unknown username.",
"en.auth.go_back": "Go back",
"en.auth.go_home": "Go home",
"en.auth.go_login": "Go to the login page",
"en.auth.lock_title": "Locked",
"en.auth.login_button": "Log in",
"en.auth.login_header": "Log in to {{.name}}",
"en.auth.login_title": "Login",
"en.auth.logout_anon": "You cannot log out because you are not logged in.",
"en.auth.logout_button": "Confirm",
"en.auth.logout_header": "Log out?",
"en.auth.logout_title": "Logout?",
"en.auth.noauth": "Authentication is disabled. You can make edits anonymously.",
"en.auth.noregister": "Registrations are currently closed. Administrators can make an account for you by hand; contact them.",
"en.auth.password": "Password",
"en.auth.password_tip": "The server stores your password in an encrypted form; even administrators cannot read it.",
"en.auth.register_button": "Register",
"en.auth.register_header": "Register on {{.name}}",
"en.auth.register_title": "Register",
"en.auth.telegram_tip": "You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.",
"en.auth.try_again": "Try again",
"en.auth.username": "Username",
"en.edit.actions": "Actions",
"en.edit.bold": "Bold",
"en.edit.bullets": "Bullet list",
"en.edit.code": "Code block",
"en.edit.date": "Insert current date",
"en.edit.heading": "Heading",
"en.edit.help": "{{.link}} about mycomarkup",
"en.edit.help_link": "Learn more",
"en.edit.highlight": "Highlight",
"en.edit.hr": "Horizontal bar",
"en.edit.italic": "Italic",
"en.edit.link": "Link",
"en.edit.link_title": "Title",
"en.edit.markup": "Markup",
"en.edit.mono": "Monospace",
"en.edit.new_hypha": "You are creating a new hypha.",
"en.edit.numbers": "Number list",
"en.edit.preview": "Preview",
"en.edit.preview_tip": "Note that the hypha hasn't been saved yet. Here's the preview:",
"en.edit.preview_title": "Preview of %s",
"en.edit.rocket": "Rocketlink",
"en.edit.save": "Save",
"en.edit.selflink": "Link yourself",
"en.edit.strike": "Strikethrough",
"en.edit.sub": "Subtext",
"en.edit.super": "Supertext",
"en.edit.tag": "Describe your changes:",
"en.edit.time": "Insert current time",
"en.edit.title": "Edit %s",
"en.edit.transclude": "Transclusion",
"en.edit.underline": "Underline",
"en.help.attachment": "Attachment",
"en.help.configuration": "Configuration (for administrators)",
"en.help.empty_error_line_1": "Try finding a different entry that would help you.",
"en.help.empty_error_line_2a": "If you want to write this entry by yourself, consider",
"en.help.empty_error_line_2b": "to Mycorrhiza Wiki directly.",
"en.help.empty_error_link": "contributing",
"en.help.empty_error_title": "This entry does not exist!",
"en.help.entry_not_found": "Entry not found",
"en.help.hypha": "Hypha",
"en.help.interface": "Interface",
"en.help.lock": "Lock",
"en.help.main": "Main",
"en.help.mycomarkup": "Mycomarkup",
"en.help.prevnext": "Previous/next",
"en.help.recent_changes": "Recent changes",
"en.help.sibling_hyphae": "Sibling hyphae",
"en.help.special_pages": "Special pages",
"en.help.telegram": "Telegram authorization",
"en.help.title": "Help",
"en.help.top_bar": "Top bar",
"en.help.topics": "Help topics",
"en.help.whitelist": "Whitelist",
"en.ui.about_admins": "Administrators:",
"en.ui.about_homepage": "Home page:",
"en.ui.about_hyphae": "See {{.link}} for information about hyphae on this wiki.",
"en.ui.about_noauth": "This wiki does not use authorization",
"en.ui.about_title": "About {{.name}}",
"en.ui.about_usercount": "User count:",
"en.ui.about_version": "{{.pre}}Mycorrhiza Wiki{{.post}} version:",
"en.ui.admin_panel": "Admin panel",
"en.ui.ask_delete": "Delete %s?",
"en.ui.ask_delete_tip": "In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.",
"en.ui.ask_delete_verb": "delete",
"en.ui.ask_really": "Do you really want to {{.verb}} hypha {{.name}}?",
"en.ui.ask_rename": "Rename %s",
"en.ui.ask_unattach": "Unattach %s?",
"en.ui.ask_unattach_verb": "unattach",
"en.ui.attach_empty": "This hypha has no attachment, you can upload it here.",
"en.ui.attach_include": "Include",
"en.ui.attach_include_tip": "This attachment is an image. To include it in a hypha, use a syntax like this:",
"en.ui.attach_link": "What are attachments?",
"en.ui.attach_new": "Attach",
"en.ui.attach_new_tip": "You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.",
"en.ui.attach_remove": "Unattach",
"en.ui.attach_remove_button": "Unattach",
"en.ui.attach_remove_tip": "Please note that you don't have to unattach before uploading a new attachment.",
"en.ui.attach_size_value": "{{.n}} byte%s",
"en.ui.attach_size_value+one": "",
"en.ui.attach_size_value+other": "s",
"en.ui.attach_stat": "Stat",
"en.ui.attach_stat_mime": "MIME type:",
"en.ui.attach_stat_size": "File size:",
"en.ui.attach_tip": "You can manage the hypha's attachment on this page.",
"en.ui.attach_title": "Attachment of {{.name}}",
"en.ui.attach_upload": "Upload",
"en.ui.attachment_link": "Manage attachment",
"en.ui.backlinks_desc": "Hyphae which have a link to the selected hypha are listed below.",
"en.ui.backlinks_link": "{{.n}} backlink%s",
"en.ui.backlinks_link+one": "",
"en.ui.backlinks_link+other": "s",
"en.ui.backlinks_query": "Backlinks to {{.query}}",
"en.ui.backlinks_title": "Backlinks to {{.query}}",
"en.ui.cancel": "Cancel",
"en.ui.close_dialog": "Close this dialog",
"en.ui.confirm": "Confirm",
"en.ui.delete_link": "Delete",
"en.ui.diff_title": "Diff of {{.name}} at {{.rev}}",
"en.ui.edit_link": "Edit text",
"en.ui.error": "Error",
"en.ui.error_go_back": "Go back to the hypha.",
"en.ui.error_text_fetch": "Could not fetch text data",
"en.ui.error_try_again": "Try again",
"en.ui.header_no_rights": "You must be a moderator to update header links.",
"en.ui.history_link": "View history",
"en.ui.history_title": "History of %s",
"en.ui.list_desc": "This wiki has {{.n}} %s.",
"en.ui.list_desc+one": "hypha",
"en.ui.list_desc+other": "hyphae",
"en.ui.list_heading": "List of hyphae",
"en.ui.list_title": "List of pages",
"en.ui.login": "Login",
"en.ui.media_download": "Download media",
"en.ui.media_noaudio": "Your browser does not support audio.",
"en.ui.media_noaudio_link": "Download audio",
"en.ui.media_novideo": "Your browser does not support video.",
"en.ui.media_novideo_link": "Download video",
"en.ui.no_rights": "Not enough rights",
"en.ui.notexist_heading": "This hypha does not exist",
"en.ui.notexist_login": "Log in to your account, if you have one",
"en.ui.notexist_media": "Upload a media",
"en.ui.notexist_media_tip1": "Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.",
"en.ui.notexist_norights": "You are not authorized to create new hyphae. Here is what you can do:",
"en.ui.notexist_register": "Register a new account",
"en.ui.notexist_write": "Write a text",
"en.ui.notexist_write_button": "Create",
"en.ui.notexist_write_myco": "Mycomarkup",
"en.ui.notexist_write_tip1": "Write a note, a diary, an article, a story or anything textual using {{.myco}}. Full history of edits to the document will be saved.",
"en.ui.notexist_write_tip2": "Make sure to follow this wiki's writing conventions if there are any.",
"en.ui.random_no_hyphae": "There are no hyphae",
"en.ui.random_no_hyphae_tip": "It is impossible to display a random hypha because the wiki does not contain any hyphae",
"en.ui.recent_count_post": "recent changes",
"en.ui.recent_count_pre": "See",
"en.ui.recent_empty": "Could not find any recent changes.",
"en.ui.recent_heading": "Recent Changes",
"en.ui.recent_subscribe": "Subscribe via {{.rss}}, {{.atom}} or {{.json}}",
"en.ui.recent_subscribe_json": "JSON feed",
"en.ui.recent_title": "{{.n}} recent change%s",
"en.ui.recent_title+one": "",
"en.ui.recent_title+other": "s",
"en.ui.register": "Register",
"en.ui.reindex_no_rights": "You must be an admin to reindex hyphae.",
"en.ui.rename_link": "Rename",
"en.ui.rename_recurse": "Rename subhyphae too",
"en.ui.rename_tip": "If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.",
"en.ui.rename_to": "New name",
"en.ui.revision_link": "Get Mycomarkup source of this revision",
"en.ui.revision_no_text": "This hypha had no text at this revision.",
"en.ui.revision_title": "{{.name}} at {{.rev}}",
"en.ui.revision_warning": "Please note that viewing attachments of hyphae is not supported in history for now.",
"en.ui.search_results_desc": "Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.",
"en.ui.search_results_query": "Search results for {{.query}}",
"en.ui.search_results_title": "Search: {{.query}}",
"en.ui.sibling_hyphae": "Sibling hyphae",
"en.ui.subhyphae": "Subhyphae",
"en.ui.text_link": "View markup",
"en.ui.title_search": "Search by title",
"en.ui.users_admins": "Admins",
"en.ui.users_editors": "Editors",
"en.ui.users_heading": "List of users",
"en.ui.users_moderators": "Moderators",
"en.ui.users_title": "User list",
"ru.admin.newuser_create": "Создать",
"ru.admin.newuser_title": "Новый пользователь",
"ru.admin.panel_about": "Об этой вики",
"ru.admin.panel_reindex": "Переиндексировать гифы",
"ru.admin.panel_safe": "Безопасные действия",
"ru.admin.panel_shutdown": "Отключить вики",
"ru.admin.panel_title": "Панель администратора",
"ru.admin.panel_unsafe": "Опасные действия",
"ru.admin.panel_updateheader": "Обновить ссылки верхней панели",
"ru.admin.panel_userlist": "Список пользователей",
"ru.admin.panel_users": "Менеджер пользователей",
"ru.admin.user_delete": "Удалить",
"ru.admin.user_delete_heading": "Удалить пользователя",
"ru.admin.user_delete_tip": "Удаляет пользователя из базы данных. Правки пользователя будут сохранены. Имя пользователя освободится для повторной регистрации.",
"ru.admin.user_delete_warn": "Вы уверены, что хотите удалить {{.name}} из базы данных? Это действие нельзя отменить.",
"ru.admin.user_group_heading": "Изменить группу",
"ru.admin.user_title": "Пользователь %s",
"ru.admin.user_update": "Обновить",
"ru.admin.users_actions": "Действия",
"ru.admin.users_create": "Создать пользователя",
"ru.admin.users_edit": "Изменить",
"ru.admin.users_group": "Группа",
"ru.admin.users_name": "Имя",
"ru.admin.users_notime": "неизвестно",
"ru.admin.users_password": "Пароль",
"ru.admin.users_registered": "Время создания",
"ru.admin.users_reindex": "Переиндексировать пользователей",
"ru.admin.users_title": "Менеджер пользователей",
"ru.auth.cookie_tip": "Отправляя эту форму, вы разрешаете вики хранить cookie в вашем браузере. Это позволит движку связывать ваши правки с вашей учётной записью. Вы будете авторизованы, пока не выйдете из учётной записи.",
"ru.auth.error_password": "Неверный пароль.",
"ru.auth.error_telegram": "Не удалось авторизоваться через Телеграм.",
"ru.auth.error_username": "Неизвестное имя пользователя.",
"ru.auth.go_back": "Назад",
"ru.auth.go_home": "Домой",
"ru.auth.go_login": "На страницу входа",
"ru.auth.lock_title": "Доступ закрыт",
"ru.auth.login_button": "Войти",
"ru.auth.login_header": "Вход в «{{.name}}»",
"ru.auth.login_title": "Вход",
"ru.auth.logout_anon": "Вы не можете выйти, потому что ещё не вошли.",
"ru.auth.logout_button": "Подтвердить",
"ru.auth.logout_header": "Выйти?",
"ru.auth.logout_title": "Выйти?",
"ru.auth.noauth": "Аутентификация отключена. Вы можете делать правки анонимно.",
"ru.auth.noregister": "Регистрация в текущее время недоступна. Администраторы могут вручную создать вам учётную запись, свяжитесь с ними.",
"ru.auth.password": "Пароль",
"ru.auth.password_tip": "Сервер хранит ваш пароль в зашифрованном виде, даже администраторы не смогут его прочесть.",
"ru.auth.register_button": "Зарегистрироваться",
"ru.auth.register_header": "Регистрация на «{{.name}}»",
"ru.auth.register_title": "Регистрация",
"ru.auth.telegram_tip": "Вы можете войти с помощью Телеграм. Это сработает, если у вашего профиля есть @имя, и оно не занято в этой вики.",
"ru.auth.try_again": "Ещё раз",
"ru.auth.username": "Логин",
"ru.edit.actions": "Действия",
"ru.edit.bold": "Жирный",
"ru.edit.bullets": "Маркир. список",
"ru.edit.code": "Код-блок",
"ru.edit.date": "Текущая дата",
"ru.edit.heading": "Заголовок",
"ru.edit.help": "{{.link}} о микоразметке",
"ru.edit.help_link": "Подробнее",
"ru.edit.highlight": "Выделение",
"ru.edit.hr": "Гориз. черта",
"ru.edit.italic": "Курсив",
"ru.edit.link": "Ссылка",
"ru.edit.link_title": "Текст",
"ru.edit.markup": "Разметка",
"ru.edit.mono": "Моноширинный",
"ru.edit.new_hypha": "Вы создаёте новую гифу.",
"ru.edit.numbers": "Нумер. список",
"ru.edit.preview": "Предпросмотр",
"ru.edit.preview_tip": "Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:",
"ru.edit.preview_title": "Предпросмотр «%s»",
"ru.edit.rocket": "Ссылка-ракета",
"ru.edit.save": "Сохранить",
"ru.edit.selflink": "Ссылка на вас",
"ru.edit.strike": "Зачёркнутый",
"ru.edit.sub": "Подстрочный",
"ru.edit.super": "Надстрочный",
"ru.edit.tag": "Опишите ваши правки:",
"ru.edit.time": "Текущее время",
"ru.edit.title": "Редактирование «%s»",
"ru.edit.transclude": "Трансклюзия",
"ru.edit.underline": "Подчеркивание",
"ru.help.attachment": "Вложение",
"ru.help.configuration": "Конфигурация (для администраторов)",
"ru.help.empty_error_line_1": "Попробуйте поискать другую страницу, способную вам помочь.",
"ru.help.empty_error_line_2a": "Если вы хотите написать эту страницу сами, будем рады вашим правкам в ",
"ru.help.empty_error_line_2b": "Микоризы.",
"ru.help.empty_error_link": "репозитории",
"ru.help.empty_error_title": "Этой страницы не существует!",
"ru.help.entry_not_found": "Запись не найдена",
"ru.help.hypha": "Гифа",
"ru.help.interface": "Интерфейс",
"ru.help.lock": "Блокировка",
"ru.help.main": "Введение",
"ru.help.mycomarkup": "Микоразметка",
"ru.help.prevnext": "Назад/далее",
"ru.help.recent_changes": "Недавние изменения",
"ru.help.sibling_hyphae": "Гифы-сиблинги",
"ru.help.special_pages": "Специальные страницы",
"ru.help.telegram": "Авторизация через Телеграм",
"ru.help.title": "Справка",
"ru.help.top_bar": "Верхняя панель",
"ru.help.topics": "Темы справки",
"ru.help.whitelist": "Белый список",
"ru.ui.about_admins": "Администраторы:",
"ru.ui.about_homepage": "Домашняя гифа:",
"ru.ui.about_hyphae": "См. {{.link}}, чтобы узнать о гифах в этой вики.",
"ru.ui.about_noauth": "В этой вики нет авторизации",
"ru.ui.about_title": "О вики «{{.name}}»",
"ru.ui.about_usercount": "Число пользователей:",
"ru.ui.about_version": "Версия {{.pre}}Микоризы{{.post}}:",
"ru.ui.admin_panel": "Администрирование",
"ru.ui.ask_delete": "Удалить «%s»?",
"ru.ui.ask_delete_tip": "В этой версии Микоризы нельзя отменить удаление гифы, но её история останется доступной.",
"ru.ui.ask_delete_verb": "удалить",
"ru.ui.ask_really": "Вы действительно хотите {{.verb}} гифу «{{.name}}»?",
"ru.ui.ask_rename": "Переименовать «%s»",
"ru.ui.ask_unattach": "Открепить «%s»?",
"ru.ui.ask_unattach_verb": "открепить",
"ru.ui.attach_empty": "Эта гифа не имеет вложения, здесь вы можете его загрузить.",
"ru.ui.attach_include": "Добавление",
"ru.ui.attach_include_tip": "Это вложение изображение. Чтобы добавить его в текст гифы, используйте синтаксис ниже:",
"ru.ui.attach_link": "Что такое вложение?",
"ru.ui.attach_new": "Прикрепить",
"ru.ui.attach_new_tip": "Вы можете загрузить новое вложение. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.",
"ru.ui.attach_remove": "Открепить",
"ru.ui.attach_remove_button": "Открепить",
"ru.ui.attach_remove_tip": "Заметьте, чтобы заменить вложение, вам не нужно его перед этим откреплять.",
"ru.ui.attach_size_value": "{{.n}} %s",
"ru.ui.attach_size_value+few": "байта",
"ru.ui.attach_size_value+many": "байт",
"ru.ui.attach_size_value+one": "байт",
"ru.ui.attach_stat": "Свойства",
"ru.ui.attach_stat_mime": "MIME-тип:",
"ru.ui.attach_stat_size": "Размер файла:",
"ru.ui.attach_tip": "На этой странице вы можете управлять вложением.",
"ru.ui.attach_title": "Вложение «{{.name}}»",
"ru.ui.attach_upload": "Загрузить",
"ru.ui.attachment_link": "Вложение",
"ru.ui.backlinks_desc": "Ниже перечислены гифы, содержащие ссылку на выбранную гифу.",
"ru.ui.backlinks_link": "{{.n}} %s сюда",
"ru.ui.backlinks_link+few": "ссылки",
"ru.ui.backlinks_link+many": "ссылок",
"ru.ui.backlinks_link+one": "ссылка",
"ru.ui.backlinks_query": "Обратные ссылки на «{{.query}}»",
"ru.ui.backlinks_title": "Обратные ссылки на {{.query}}",
"ru.ui.cancel": "Отмена",
"ru.ui.close_dialog": "Закрыть этот диалог",
"ru.ui.confirm": "Применить",
"ru.ui.delete_link": "Удалить",
"ru.ui.diff_title": "Разница для «{{.name}}» из {{.rev}}",
"ru.ui.edit_link": "Редактировать",
"ru.ui.error": "Ошибка",
"ru.ui.error_go_back": "Вернуться к гифе.",
"ru.ui.error_text_fetch": "Не удалось получить текстовые данные",
"ru.ui.error_try_again": "Попробуйте ещё раз",
"ru.ui.header_no_rights": "Вы должны быть модератором, чтобы обновить ссылки в заголовке.",
"ru.ui.history_link": "История",
"ru.ui.history_title": "История «%s»",
"ru.ui.list_desc": "В этой вики {{.n}} %s.",
"ru.ui.list_desc+few": "гифы",
"ru.ui.list_desc+many": "гиф",
"ru.ui.list_desc+one": "гифа",
"ru.ui.list_heading": "Список гиф",
"ru.ui.list_title": "Список страниц",
"ru.ui.login": "Войти",
"ru.ui.media_download": "Скачать медиа",
"ru.ui.media_noaudio": "Ваш браузер не поддерживает аудио.",
"ru.ui.media_noaudio_link": "Скачать аудио",
"ru.ui.media_novideo": "Ваш браузер не поддерживает видео.",
"ru.ui.media_novideo_link": "Скачать видео",
"ru.ui.no_rights": "Недостаточно прав",
"ru.ui.notexist_heading": "Эта гифа не существует",
"ru.ui.notexist_login": "Войти в свою учётную запись, если она у вас есть",
"ru.ui.notexist_media": "Загрузить медиа",
"ru.ui.notexist_media_tip1": "Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные просто скачать. Позже вы можете дописать пояснение к этому медиа.",
"ru.ui.notexist_norights": "У вас нет прав для создания новых гиф. Вы можете:",
"ru.ui.notexist_register": "Создать новую учётную запись",
"ru.ui.notexist_write": "Написать текст",
"ru.ui.notexist_write_button": "Создать",
"ru.ui.notexist_write_myco": "микоразметки",
"ru.ui.notexist_write_tip1": "Напишите заметку, дневник, статью, рассказ или иной текст с помощью {{.myco}}. Сохраняется полная история правок документа.",
"ru.ui.notexist_write_tip2": "Не забывайте следовать правилам оформления этой вики, если они имеются.",
"ru.ui.random_no_hyphae": "В этой вики нет гиф",
"ru.ui.random_no_hyphae_tip": "Невозможно отобразить случайную гифу, потому что вики не содержит ни одной гифы",
"ru.ui.recent_count_post": "недавних изменений",
"ru.ui.recent_count_pre": "Отобразить",
"ru.ui.recent_empty": "Не удалось найти последние изменения.",
"ru.ui.recent_heading": "Недавние изменения",
"ru.ui.recent_subscribe": "Подписаться через {{.rss}}, {{.atom}} или {{.json}}",
"ru.ui.recent_subscribe_json": "JSON-ленту",
"ru.ui.recent_title": "{{.n}} %s",
"ru.ui.recent_title+few": "недавних изменения",
"ru.ui.recent_title+many": "недавних изменений",
"ru.ui.recent_title+one": "недавнее изменение",
"ru.ui.register": "Регистрация",
"ru.ui.reindex_no_rights": "Вы должны быть администратором, чтобы переиндексировать гифы.",
"ru.ui.rename_link": "Переименовать",
"ru.ui.rename_recurse": "Также переименовать подгифы",
"ru.ui.rename_tip": "Если вы переименуете эту гифу, сломаются все ссылки, ведущие на неё, а также исходящие относительные ссылки. Также вы потеряете всю текущую историю для нового названия. Переименовывайте аккуратно.",
"ru.ui.rename_to": "Новое название",
"ru.ui.revision_link": "Посмотреть код микоразметки для этой ревизии",
"ru.ui.revision_no_text": "В этой ревизии гифы не было текста.",
"ru.ui.revision_title": "{{.name}} из {{.rev}}",
"ru.ui.revision_warning": "Обратите внимание, просмотр вложений в истории гифы пока что недоступен.",
"ru.ui.search_results_desc": "Название каждой из существующих гиф сопоставлено с запросом. Подходящие гифы приведены ниже.",
"ru.ui.search_results_query": "Результаты поиска для «{{.query}}»",
"ru.ui.search_results_title": "Поиск: {{.query}}",
"ru.ui.sibling_hyphae": "Гифы-сиблинги",
"ru.ui.subhyphae": "Подгифы",
"ru.ui.text_link": "Посмотреть разметку",
"ru.ui.title_search": "Поиск по названию",
"ru.ui.users_admins": "Администраторы",
"ru.ui.users_editors": "Редакторы",
"ru.ui.users_heading": "Список пользователей",
"ru.ui.users_moderators": "Модераторы",
"ru.ui.users_title": "Список пользователей",
}
type Replacements map[string]interface{}
type Localizer struct {
Locale string
FallbackLocale string
Localizations map[string]string
}
func New(locale string, fallbackLocale string) *Localizer {
t := &Localizer{Locale: locale, FallbackLocale: fallbackLocale}
t.Localizations = localizations
return t
}
func (t Localizer) SetLocales(locale, fallback string) Localizer {
t.Locale = locale
t.FallbackLocale = fallback
return t
}
func (t Localizer) SetLocale(locale string) Localizer {
t.Locale = locale
return t
}
func (t Localizer) SetFallbackLocale(fallback string) Localizer {
t.FallbackLocale = fallback
return t
}
func (t Localizer) GetWithLocale(locale, key string, replacements ...*Replacements) string {
str, ok := t.Localizations[t.getLocalizationKey(locale, key)]
if !ok {
str, ok = t.Localizations[t.getLocalizationKey(t.FallbackLocale, key)]
if !ok {
return key
}
}
// If the str doesn't have any substitutions, no need to
// template.Execute.
if strings.Index(str, "}}") == -1 {
return str
}
return t.replace(str, replacements...)
}
func (t Localizer) Get(key string, replacements ...*Replacements) string {
str := t.GetWithLocale(t.Locale, key, replacements...)
return str
}
func (t Localizer) getLocalizationKey(locale string, key string) string {
return fmt.Sprintf("%v.%v", locale, key)
}
func (t Localizer) replace(str string, replacements ...*Replacements) string {
b := &bytes.Buffer{}
tmpl, err := template.New("").Parse(str)
if err != nil {
return str
}
replacementsMerge := Replacements{}
for _, replacement := range replacements {
for k, v := range *replacement {
replacementsMerge[k] = v
}
}
err = template.Must(tmpl, err).Execute(b, replacementsMerge)
if err != nil {
return str
}
buff := b.String()
return buff
}

105
l18n/util.go Normal file
View File

@ -0,0 +1,105 @@
package l18n
import (
"fmt"
"golang.org/x/text/feature/plural"
"golang.org/x/text/language"
"net/http"
"strings"
)
// matcher is a language.Matcher configured for all supported languages.
var locales = language.NewMatcher([]language.Tag{
language.Make("en"),
language.Make("ru"),
})
// GetLocalizer takes a HTTP request and picks the most appropriate localizer (with English fallback)
func FromRequest(r *http.Request) *Localizer {
t, _, _ := language.ParseAcceptLanguage(r.Header.Get("Accept-Language"))
tag, _, _ := locales.Match(t...)
// TODO: support subtags such as en-US, en-GB, zh-Hans
base, _ := tag.Base()
return New(base.String(), "en")
}
var formNames = map[plural.Form]string{
plural.Other: "other",
plural.Zero: "zero",
plural.One: "one",
plural.Two: "two",
plural.Few: "few",
plural.Many: "many",
}
func (t Localizer) rawPlural(lang, rawKey string, n int) (string, bool) {
key := t.getLocalizationKey(lang, rawKey)
str, ok := t.Localizations[key]
if !ok {
return key, false
}
var (
formIdx = plural.Cardinal.MatchPlural(language.Make(lang), n, 0, 0, 0, 0)
form = formNames[formIdx]
)
plural, plOk := t.Localizations[fmt.Sprintf("%v+%v", key, form)]
if !plOk {
return key, false
}
return fmt.Sprintf(str, plural), true
}
// GetPlural gets a translated string respecting locale-specific plural rules. Technically, it replaces %s token with +form subkey and proceed as usual.
func (t Localizer) GetPlural(key string, n int, replacements ...*Replacements) string {
str, ok := t.rawPlural(t.Locale, key, n)
if !ok {
str, ok = t.rawPlural(t.FallbackLocale, key, n)
if !ok {
return key
}
}
// As in the original, we skip templating if have nothing to replace (however, it's strange case for plurals)
if strings.Index(str, "}}") == -1 {
return str
}
return t.replace(str, append(replacements, &Replacements{"n": n})...)
}
// GetPlural64 is ditto for int64
func (t Localizer) GetPlural64(key string, n int64, replacements ...*Replacements) string {
str, ok := t.rawPlural(t.Locale, key, int(n%1000000))
if !ok {
str, ok = t.rawPlural(t.FallbackLocale, key, int(n%1000000))
if !ok {
return key
}
}
// As in the original, we skip templating if have nothing to replace (however, it's strange case for plurals)
if strings.Index(str, "}}") == -1 {
return str
}
return t.replace(str, append(replacements, &Replacements{"n": n})...)
}
func getLocalizationKey(locale string, key string) string {
return fmt.Sprintf("%v.%v", locale, key)
}
/* chekoopa: Missing translation features:
- history records (they use Git description, the possible solution is to parse and translate)
- history dates (HistoryWithRevisions doesn't consider locale, Monday package is bad idea)
- probably error messages (which are scattered across the code)
- default top bar (it is static from one-shot cfg.SetDefaultHeaderLinks, but it is possible to track default-ness in templates)
- alt solution is implementing "special" links
- dynamic UI (JS are static, though we may send some strings through templates)
- help switches, like,
- "Read in your language"
- "Try reading it in English", if no page found in a foreign locale
- feeds (it seems diffcult to pull locale here)
We do not translate:
- stdout traces (logging is English-only)
*/

33
l18n_src/en/admin.json Normal file
View File

@ -0,0 +1,33 @@
{
"panel_title": "Administrative functions",
"panel_safe": "Safe things",
"panel_unsafe": "Dangerous things",
"panel_about": "About this wiki",
"panel_userlist": "User list",
"panel_updateheader": "Update header links",
"panel_users": "Manage users",
"panel_shutdown": "Shutdown wiki",
"panel_reindex": "Reindex hyphae",
"users_title": "Manage users",
"users_create": "Create a new user",
"users_reindex": "Reindex users",
"users_name": "Name",
"users_password": "Password",
"users_group": "Group",
"users_registered": "Registered at",
"users_actions": "Actions",
"users_notime": "unknown",
"users_edit": "Edit",
"user_title": "User %s",
"user_group_heading": "Change group",
"user_update": "Update",
"user_delete_heading": "Delete user",
"user_delete_tip": "Remove the user from the database. Changes made by the user will be preserved. It will be possible to take this username later.",
"user_delete_warn": "Are you sure you want to delete {{.name}} from the database? This action is irreversible.",
"user_delete": "Delete",
"newuser_title": "New user",
"newuser_create": "Create"
}

35
l18n_src/en/auth.json Normal file
View File

@ -0,0 +1,35 @@
{
"username": "Username",
"password": "Password",
"register_title": "Register",
"register_header": "Register on {{.name}}",
"register_button": "Register",
"login_title": "Login",
"login_header": "Log in to {{.name}}",
"login_button": "Log in",
"logout_title": "Logout?",
"logout_header": "Log out?",
"logout_button": "Confirm",
"logout_anon": "You cannot log out because you are not logged in.",
"lock_title": "Locked",
"password_tip": "The server stores your password in an encrypted form; even administrators cannot read it.",
"cookie_tip": "By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.",
"telegram_tip": "You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.",
"noauth": "Authentication is disabled. You can make edits anonymously.",
"noregister": "Registrations are currently closed. Administrators can make an account for you by hand; contact them.",
"error_username": "Unknown username.",
"error_password": "Wrong password.",
"error_telegram": "Could not authorize using Telegram.",
"go_back": "Go back",
"go_home": "Go home",
"go_login": "Go to the login page",
"try_again": "Try again"
}

38
l18n_src/en/edit.json Normal file
View File

@ -0,0 +1,38 @@
{
"title": "Edit %s",
"new_hypha": "You are creating a new hypha.",
"tag": "Describe your changes:",
"save": "Save",
"preview": "Preview",
"preview_title": "Preview of %s",
"preview_tip": "Note that the hypha hasn't been saved yet. Here's the preview:",
"markup": "Markup",
"actions": "Actions",
"link": "Link",
"link_title": "Title",
"heading": "Heading",
"bold": "Bold",
"italic": "Italic",
"highlight": "Highlight",
"underline": "Underline",
"mono": "Monospace",
"super": "Supertext",
"sub": "Subtext",
"strike": "Strikethrough",
"rocket": "Rocketlink",
"transclude": "Transclusion",
"hr": "Horizontal bar",
"code": "Code block",
"bullets": "Bullet list",
"numbers": "Number list",
"help": "{{.link}} about mycomarkup",
"help_link": "Learn more",
"selflink": "Link yourself",
"date": "Insert current date",
"time": "Insert current time"
}

25
l18n_src/en/help.json Normal file
View File

@ -0,0 +1,25 @@
{
"title": "Help",
"entry_not_found": "Entry not found",
"empty_error_title": "This entry does not exist!",
"empty_error_line_1": "Try finding a different entry that would help you.",
"empty_error_line_2a": "If you want to write this entry by yourself, consider",
"empty_error_link": "contributing",
"empty_error_line_2b": "to Mycorrhiza Wiki directly.",
"topics": "Help topics",
"main": "Main",
"hypha": "Hypha",
"attachment": "Attachment",
"mycomarkup": "Mycomarkup",
"interface": "Interface",
"prevnext": "Previous/next",
"top_bar": "Top bar",
"sibling_hyphae": "Sibling hyphae",
"special_pages": "Special pages",
"recent_changes": "Recent changes",
"configuration": "Configuration (for administrators)",
"lock": "Lock",
"whitelist": "Whitelist",
"telegram": "Telegram authorization"
}

131
l18n_src/en/ui.json Normal file
View File

@ -0,0 +1,131 @@
{
"login": "Login",
"register": "Register",
"title_search": "Search by title",
"admin_panel": "Admin panel",
"search_results_title": "Search: {{.query}}",
"search_results_query": "Search results for {{.query}}",
"search_results_desc": "Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.",
"backlinks_title": "Backlinks to {{.query}}",
"backlinks_query": "Backlinks to {{.query}}",
"backlinks_desc": "Hyphae which have a link to the selected hypha are listed below.",
"list_title": "List of pages",
"list_heading": "List of hyphae",
"list_desc": "This wiki has {{.n}} %s.",
"list_desc+one": "hypha",
"list_desc+other": "hyphae",
"edit_link": "Edit text",
"history_link": "View history",
"rename_link": "Rename",
"delete_link": "Delete",
"text_link": "View markup",
"attachment_link": "Manage attachment",
"backlinks_link": "{{.n}} backlink%s",
"backlinks_link+one": "",
"backlinks_link+other": "s",
"sibling_hyphae": "Sibling hyphae",
"subhyphae": "Subhyphae",
"random_no_hyphae": "There are no hyphae",
"random_no_hyphae_tip": "It is impossible to display a random hypha because the wiki does not contain any hyphae",
"error": "Error",
"error_text_fetch": "Could not fetch text data",
"error_try_again": "Try again",
"error_go_back": "Go back to the hypha.",
"ask_rename": "Rename %s",
"rename_to": "New name",
"rename_recurse": "Rename subhyphae too",
"rename_tip": "If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.",
"ask_delete": "Delete %s?",
"ask_delete_tip": "In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.",
"ask_unattach": "Unattach %s?",
"ask_really": "Do you really want to {{.verb}} hypha {{.name}}?",
"ask_delete_verb": "delete",
"ask_unattach_verb": "unattach",
"history_title": "History of %s",
"recent_title": "{{.n}} recent change%s",
"recent_title+one": "",
"recent_title+other": "s",
"recent_heading": "Recent Changes",
"recent_count_pre": "See",
"recent_count_post": "recent changes",
"recent_subscribe": "Subscribe via {{.rss}}, {{.atom}} or {{.json}}",
"recent_subscribe_json": "JSON feed",
"recent_empty": "Could not find any recent changes.",
"diff_title": "Diff of {{.name}} at {{.rev}}",
"revision_title": "{{.name}} at {{.rev}}",
"revision_warning": "Please note that viewing attachments of hyphae is not supported in history for now.",
"revision_link": "Get Mycomarkup source of this revision",
"revision_no_text": "This hypha had no text at this revision.",
"about_title": "About {{.name}}",
"about_version": "{{.pre}}Mycorrhiza Wiki{{.post}} version:",
"about_usercount": "User count:",
"about_homepage": "Home page:",
"about_admins": "Administrators:",
"about_noauth": "This wiki does not use authorization",
"about_hyphae": "See {{.link}} for information about hyphae on this wiki.",
"users_title": "User list",
"users_heading": "List of users",
"users_admins": "Admins",
"users_moderators": "Moderators",
"users_editors": "Editors",
"no_rights": "Not enough rights",
"reindex_no_rights": "You must be an admin to reindex hyphae.",
"header_no_rights": "You must be a moderator to update header links.",
"notexist_heading": "This hypha does not exist",
"notexist_norights": "You are not authorized to create new hyphae. Here is what you can do:",
"notexist_login": "Log in to your account, if you have one",
"notexist_register": "Register a new account",
"notexist_write": "Write a text",
"notexist_write_tip1": "Write a note, a diary, an article, a story or anything textual using {{.myco}}. Full history of edits to the document will be saved.",
"notexist_write_myco": "Mycomarkup",
"notexist_write_tip2": "Make sure to follow this wiki's writing conventions if there are any.",
"notexist_write_button": "Create",
"notexist_media": "Upload a media",
"notexist_media_tip1": "Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.",
"media_download": "Download media",
"media_novideo": "Your browser does not support video.",
"media_novideo_link": "Download video",
"media_noaudio": "Your browser does not support audio.",
"media_noaudio_link": "Download audio",
"attach_title": "Attachment of {{.name}}",
"attach_empty": "This hypha has no attachment, you can upload it here.",
"attach_tip": "You can manage the hypha's attachment on this page.",
"attach_link": "What are attachments?",
"attach_upload": "Upload",
"attach_stat": "Stat",
"attach_stat_size": "File size:",
"attach_size_value": "{{.n}} byte%s",
"attach_size_value+one": "",
"attach_size_value+other": "s",
"attach_stat_mime": "MIME type:",
"attach_include": "Include",
"attach_include_tip": "This attachment is an image. To include it in a hypha, use a syntax like this:",
"attach_new": "Attach",
"attach_new_tip": "You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.",
"attach_remove": "Unattach",
"attach_remove_tip": "Please note that you don't have to unattach before uploading a new attachment.",
"attach_remove_button": "Unattach",
"close_dialog": "Close this dialog",
"confirm": "Confirm",
"cancel": "Cancel"
}

33
l18n_src/ru/admin.json Normal file
View File

@ -0,0 +1,33 @@
{
"panel_title": "Панель администратора",
"panel_safe": "Безопасные действия",
"panel_unsafe": "Опасные действия",
"panel_about": "Об этой вики",
"panel_userlist": "Список пользователей",
"panel_updateheader": "Обновить ссылки верхней панели",
"panel_users": "Менеджер пользователей",
"panel_shutdown": "Отключить вики",
"panel_reindex": "Переиндексировать гифы",
"users_title": "Менеджер пользователей",
"users_create": "Создать пользователя",
"users_reindex": "Переиндексировать пользователей",
"users_name": "Имя",
"users_password": "Пароль",
"users_group": "Группа",
"users_registered": "Время создания",
"users_actions": "Действия",
"users_notime": "неизвестно",
"users_edit": "Изменить",
"user_title": "Пользователь %s",
"user_group_heading": "Изменить группу",
"user_update": "Обновить",
"user_delete_heading": "Удалить пользователя",
"user_delete_tip": "Удаляет пользователя из базы данных. Правки пользователя будут сохранены. Имя пользователя освободится для повторной регистрации.",
"user_delete_warn": "Вы уверены, что хотите удалить {{.name}} из базы данных? Это действие нельзя отменить.",
"user_delete": "Удалить",
"newuser_title": "Новый пользователь",
"newuser_create": "Создать"
}

35
l18n_src/ru/auth.json Normal file
View File

@ -0,0 +1,35 @@
{
"username": "Логин",
"password": "Пароль",
"register_title": "Регистрация",
"register_header": "Регистрация на «{{.name}}»",
"register_button": "Зарегистрироваться",
"login_title": "Вход",
"login_header": "Вход в «{{.name}}»",
"login_button": "Войти",
"logout_title": "Выйти?",
"logout_header": "Выйти?",
"logout_button": "Подтвердить",
"logout_anon": "Вы не можете выйти, потому что ещё не вошли.",
"lock_title": "Доступ закрыт",
"password_tip": "Сервер хранит ваш пароль в зашифрованном виде, даже администраторы не смогут его прочесть.",
"cookie_tip": "Отправляя эту форму, вы разрешаете вики хранить cookie в вашем браузере. Это позволит движку связывать ваши правки с вашей учётной записью. Вы будете авторизованы, пока не выйдете из учётной записи.",
"telegram_tip": "Вы можете войти с помощью Телеграм. Это сработает, если у вашего профиля есть @имя, и оно не занято в этой вики.",
"noauth": "Аутентификация отключена. Вы можете делать правки анонимно.",
"noregister": "Регистрация в текущее время недоступна. Администраторы могут вручную создать вам учётную запись, свяжитесь с ними.",
"error_username": "Неизвестное имя пользователя.",
"error_password": "Неверный пароль.",
"error_telegram": "Не удалось авторизоваться через Телеграм.",
"go_back": "Назад",
"go_home": "Домой",
"go_login": "На страницу входа",
"try_again": "Ещё раз"
}

38
l18n_src/ru/edit.json Normal file
View File

@ -0,0 +1,38 @@
{
"title": "Редактирование «%s»",
"new_hypha": "Вы создаёте новую гифу.",
"tag": "Опишите ваши правки:",
"save": "Сохранить",
"preview": "Предпросмотр",
"preview_title": "Предпросмотр «%s»",
"preview_tip": "Заметьте, эта гифа ещё не сохранена. Вот её предпросмотр:",
"markup": "Разметка",
"actions": "Действия",
"link": "Ссылка",
"link_title": "Текст",
"heading": "Заголовок",
"bold": "Жирный",
"italic": "Курсив",
"highlight": "Выделение",
"underline": "Подчеркивание",
"mono": "Моноширинный",
"super": "Надстрочный",
"sub": "Подстрочный",
"strike": "Зачёркнутый",
"rocket": "Ссылка-ракета",
"transclude": "Трансклюзия",
"hr": "Гориз. черта",
"code": "Код-блок",
"bullets": "Маркир. список",
"numbers": "Нумер. список",
"help": "{{.link}} о микоразметке",
"help_link": "Подробнее",
"selflink": "Ссылка на вас",
"date": "Текущая дата",
"time": "Текущее время"
}

25
l18n_src/ru/help.json Normal file
View File

@ -0,0 +1,25 @@
{
"title": "Справка",
"entry_not_found": "Запись не найдена",
"empty_error_title": "Этой страницы не существует!",
"empty_error_line_1": "Попробуйте поискать другую страницу, способную вам помочь.",
"empty_error_line_2a": "Если вы хотите написать эту страницу сами, будем рады вашим правкам в ",
"empty_error_link": "репозитории",
"empty_error_line_2b": "Микоризы.",
"topics": "Темы справки",
"main": "Введение",
"hypha": "Гифа",
"attachment": "Вложение",
"mycomarkup": "Микоразметка",
"interface": "Интерфейс",
"prevnext": "Назад/далее",
"top_bar": "Верхняя панель",
"sibling_hyphae": "Гифы-сиблинги",
"special_pages": "Специальные страницы",
"recent_changes": "Недавние изменения",
"configuration": "Конфигурация (для администраторов)",
"lock": "Блокировка",
"whitelist": "Белый список",
"telegram": "Авторизация через Телеграм"
}

135
l18n_src/ru/ui.json Normal file
View File

@ -0,0 +1,135 @@
{
"login": "Войти",
"register": "Регистрация",
"title_search": "Поиск по названию",
"admin_panel": "Администрирование",
"search_results_title": "Поиск: {{.query}}",
"search_results_query": "Результаты поиска для «{{.query}}»",
"search_results_desc": "Название каждой из существующих гиф сопоставлено с запросом. Подходящие гифы приведены ниже.",
"backlinks_title": "Обратные ссылки на {{.query}}",
"backlinks_query": "Обратные ссылки на «{{.query}}»",
"backlinks_desc": "Ниже перечислены гифы, содержащие ссылку на выбранную гифу.",
"list_title": "Список страниц",
"list_heading": "Список гиф",
"list_desc": "В этой вики {{.n}} %s.",
"list_desc+one": "гифа",
"list_desc+few": "гифы",
"list_desc+many": "гиф",
"edit_link": "Редактировать",
"history_link": "История",
"rename_link": "Переименовать",
"delete_link": "Удалить",
"text_link": "Посмотреть разметку",
"attachment_link": "Вложение",
"backlinks_link": "{{.n}} %s сюда",
"backlinks_link+one": "ссылка",
"backlinks_link+few": "ссылки",
"backlinks_link+many": "ссылок",
"sibling_hyphae": "Гифы-сиблинги",
"subhyphae": "Подгифы",
"random_no_hyphae": "В этой вики нет гиф",
"random_no_hyphae_tip": "Невозможно отобразить случайную гифу, потому что вики не содержит ни одной гифы",
"error": "Ошибка",
"error_text_fetch": "Не удалось получить текстовые данные",
"error_try_again": "Попробуйте ещё раз",
"error_go_back": "Вернуться к гифе.",
"ask_rename": "Переименовать «%s»",
"rename_to": "Новое название",
"rename_recurse": "Также переименовать подгифы",
"rename_tip": "Если вы переименуете эту гифу, сломаются все ссылки, ведущие на неё, а также исходящие относительные ссылки. Также вы потеряете всю текущую историю для нового названия. Переименовывайте аккуратно.",
"ask_delete": "Удалить «%s»?",
"ask_delete_tip": "В этой версии Микоризы нельзя отменить удаление гифы, но её история останется доступной.",
"ask_unattach": "Открепить «%s»?",
"ask_really": "Вы действительно хотите {{.verb}} гифу «{{.name}}»?",
"ask_delete_verb": "удалить",
"ask_unattach_verb": "открепить",
"history_title": "История «%s»",
"recent_title": "{{.n}} %s",
"recent_title+one": "недавнее изменение",
"recent_title+few": "недавних изменения",
"recent_title+many": "недавних изменений",
"recent_heading": "Недавние изменения",
"recent_count_pre": "Отобразить",
"recent_count_post": "недавних изменений",
"recent_subscribe": "Подписаться через {{.rss}}, {{.atom}} или {{.json}}",
"recent_subscribe_json": "JSON-ленту",
"recent_empty": "Не удалось найти последние изменения.",
"diff_title": "Разница для «{{.name}}» из {{.rev}}",
"revision_title": "{{.name}} из {{.rev}}",
"revision_warning": "Обратите внимание, просмотр вложений в истории гифы пока что недоступен.",
"revision_link": "Посмотреть код микоразметки для этой ревизии",
"revision_no_text": "В этой ревизии гифы не было текста.",
"about_title": "О вики «{{.name}}»",
"about_version": "Версия {{.pre}}Микоризы{{.post}}:",
"about_usercount": "Число пользователей:",
"about_homepage": "Домашняя гифа:",
"about_admins": "Администраторы:",
"about_noauth": "В этой вики нет авторизации",
"about_hyphae": "См. {{.link}}, чтобы узнать о гифах в этой вики.",
"users_title": "Список пользователей",
"users_heading": "Список пользователей",
"users_admins": "Администраторы",
"users_moderators": "Модераторы",
"users_editors": "Редакторы",
"no_rights": "Недостаточно прав",
"reindex_no_rights": "Вы должны быть администратором, чтобы переиндексировать гифы.",
"header_no_rights": "Вы должны быть модератором, чтобы обновить ссылки в заголовке.",
"notexist_heading": "Эта гифа не существует",
"notexist_norights": "У вас нет прав для создания новых гиф. Вы можете:",
"notexist_login": "Войти в свою учётную запись, если она у вас есть",
"notexist_register": "Создать новую учётную запись",
"notexist_write": "Написать текст",
"notexist_write_tip1": "Напишите заметку, дневник, статью, рассказ или иной текст с помощью {{.myco}}. Сохраняется полная история правок документа.",
"notexist_write_myco": "микоразметки",
"notexist_write_tip2": "Не забывайте следовать правилам оформления этой вики, если они имеются.",
"notexist_write_button": "Создать",
"notexist_media": "Загрузить медиа",
"notexist_media_tip1": "Загрузите изображение, видео или аудио. Распространённые форматы можно просматривать из браузера, остальные просто скачать. Позже вы можете дописать пояснение к этому медиа.",
"media_download": "Скачать медиа",
"media_novideo": "Ваш браузер не поддерживает видео.",
"media_novideo_link": "Скачать видео",
"media_noaudio": "Ваш браузер не поддерживает аудио.",
"media_noaudio_link": "Скачать аудио",
"attach_title": "Вложение «{{.name}}»",
"attach_empty": "Эта гифа не имеет вложения, здесь вы можете его загрузить.",
"attach_tip": "На этой странице вы можете управлять вложением.",
"attach_link": "Что такое вложение?",
"attach_upload": "Загрузить",
"attach_stat": "Свойства",
"attach_stat_size": "Размер файла:",
"attach_size_value": "{{.n}} %s",
"attach_size_value+one": "байт",
"attach_size_value+few": "байта",
"attach_size_value+many": "байт",
"attach_stat_mime": "MIME-тип:",
"attach_include": "Добавление",
"attach_include_tip": "Это вложение изображение. Чтобы добавить его в текст гифы, используйте синтаксис ниже:",
"attach_new": "Прикрепить",
"attach_new_tip": "Вы можете загрузить новое вложение. Пожалуйста, не загружайте слишком большие изображения без необходимости, чтобы впоследствии не ждать её долгую загрузку.",
"attach_remove": "Открепить",
"attach_remove_tip": "Заметьте, чтобы заменить вложение, вам не нужно его перед этим откреплять.",
"attach_remove_button": "Открепить",
"close_dialog": "Закрыть этот диалог",
"confirm": "Применить",
"cancel": "Отмена"
}

View File

@ -1,5 +1,6 @@
//go:generate qtc -dir=views
//go:generate qtc -dir=tree
//go:generate go-localize -input l18n_src -output l18n
// Command mycorrhiza is a program that runs a mycorrhiza wiki.
package main

View File

@ -17,7 +17,8 @@ func init() {
if h := hyphae.ByName(hyphaName); h.Exists {
rawText, err = FetchTextPart(h)
if h.BinaryPath != "" {
binaryBlock = views.AttachmentHTML(h)
// the view is localized, but we can't pass it, so...
binaryBlock = views.AttachmentHTMLRaw(h)
}
} else {
err = errors.New("Hypha " + hyphaName + " does not exist")

View File

@ -1,31 +1,33 @@
{% import "fmt" %}
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
{% func AdminPanelHTML() %}
{% func AdminPanelHTML(lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<h1>Administrative functions</h1>
<h1>{%s lc.Get("admin.panel_title") %}</h1>
<section>
<h2>Safe things</h2>
<h2>{%s lc.Get("admin.panel_safe") %}</h2>
<ul>
<li><a href="/about">About this wiki</a></li>
<li><a href="/user-list">User list</a></li>
<li><a href="/update-header-links">Update header links</a></li>
<li><a href="/admin/users/">Manage users</a></li>
<li><a href="/about">{%s lc.Get("admin.panel_about") %}</a></li>
<li><a href="/user-list">{%s lc.Get("admin.panel_userlist") %}</a></li>
<li><a href="/update-header-links">{%s lc.Get("admin.panel_updateheader") %}</a></li>
<li><a href="/admin/users/">{%s lc.Get("admin.panel_users") %}</a></li>
</ul>
</section>
<section>
<h2>Dangerous things</h2>
<h2>{%s lc.Get("admin.panel_unsafe") %}</h2>
<form action="/admin/shutdown" method="POST" style="float:left">
<fieldset>
<legend>Shutdown wiki</legend>
<legend>{%s lc.Get("admin.panel_shutdown") %}</legend>
<input type="submit" class="btn">
</fieldset>
</form>
<form action="/reindex" method="GET" style="float:left">
<fieldset>
<legend>Reindex hyphae</legend>
<legend>{%s lc.Get("admin.panel_reindex") %}</legend>
<input type="submit" class="btn">
</fieldset>
</form>
@ -34,14 +36,14 @@
</div>
{% endfunc %}
{% func AdminUsersPanelHTML(userList []*user.User) %}
{% func AdminUsersPanelHTML(userList []*user.User, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<h1>Manage users</h1>
<h1>{%s lc.Get("admin.users_title") %}</h1>
<form action="/admin/reindex-users" method="post">
<a class="btn" href="/admin/user/new">Create a new user</a>
<button class="btn" type="submit">Reindex users</button>
<a class="btn" href="/admin/user/new">{%s lc.Get("admin.users_create") %}</a>
<button class="btn" type="submit">{%s lc.Get("admin.users_reindex") %}</button>
</form>
<br>
@ -49,10 +51,10 @@
<table class="users-table">
<thead>
<tr>
<th>Name</th>
<th>Group</th>
<th>Registered at</th>
<th aria-label="Actions"></th>
<th>{%s lc.Get("admin.users_name") %}</th>
<th>{%s lc.Get("admin.users_group") %}</th>
<th>{%s lc.Get("admin.users_registered") %}</th>
<th aria-label="{%s lc.Get("admin.users_actions") %}"></th>
</tr>
</thead>
<tbody>
@ -64,13 +66,13 @@
<td>{%s u.Group %}</td>
<td>
{% if u.RegisteredAt.IsZero() %}
unknown
{%s lc.Get("admin.users_notime") %}
{% else %}
{%s u.RegisteredAt.UTC().Format("2006-01-02 15:04") %}
{% endif %}
</td>
<td>
<a href="/admin/users/{%u u.Name %}/edit">Edit</a>
<a href="/admin/users/{%u u.Name %}/edit">{%s lc.Get("admin.users_edit") %}</a>
</td>
</tr>
{% endfor %}
@ -80,31 +82,31 @@
</div>
{% endfunc %}
{% func AdminUserNewHTML(f util.FormData) %}
{% func AdminUserNewHTML(f util.FormData, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width form-wrap">
<h1>New user</h1>
<h1>{%s lc.Get("admin.newuser_title") %}</h1>
{% if f.HasError() %}
<div class="notice notice--error">
<strong>Error:</strong>
<strong>{%s lc.Get("ui.error") %}:</strong>
{%s f.Error() %}
</div>
{% endif %}
<form class="form--double" action="" method="post">
<div class="form-field">
<label for="name">Name:</label>
<label for="name">{%s lc.Get("admin.users_name") %}:</label>
<input type="text" name="name" id="name" value="{%s f.Get("name") %}" autofocus>
</div>
<div class="form-field">
<label for="password">Password:</label>
<label for="password">{%s lc.Get("admin.users_password") %}:</label>
<input type="password" name="password" id="password" value="{%s f.Get("password") %}">
</div>
<div class="form-field">
<label for="group">Group:</label>
<label for="group">{%s lc.Get("admin.users_group") %}:</label>
<select id="group" name="group">
<option{% if f.Get("group") == "anon" %} selected{% endif %}>anon</option>
<option{% if f.Get("group") == "editor" %} selected{% endif %}>editor</option>
@ -116,8 +118,8 @@
<div class="form-field">
<div class="form-field__input">
<button class="btn" type="submit">Create</button>
<a class="btn btn_weak" href="/admin/users/">Cancel</a>
<button class="btn" type="submit">{%s lc.Get("admin.newuser_create") %}</button>
<a class="btn btn_weak" href="/admin/users/">{%s lc.Get("ui.cancel") %}</a>
</div>
</div>
</form>
@ -125,7 +127,7 @@
</div>
{% endfunc %}
{% func AdminUserEditHTML(u *user.User, f util.FormData) %}
{% func AdminUserEditHTML(u *user.User, f util.FormData, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width form-wrap">
<h1>
@ -133,18 +135,18 @@
{%s u.Name %}
</h1>
<h2>Change group</h2>
<h2>{%s lc.Get("admin.user_group_heading") %}</h2>
{% if f.HasError() %}
<div class="notice notice--error">
<strong>Error:</strong>
<strong>{%s lc.Get("ui.error") %}:</strong>
{%s f.Error() %}
</div>
{% endif %}
<form action="" method="post">
<div class="form-field">
<select id="group" name="group" aria-label="Group">
<select id="group" name="group" aria-label="{%s lc.Get("admin.users_group") %}">
<option{% if f.Get("group") == "anon" %} selected{% endif %}>anon</option>
<option{% if f.Get("group") == "editor" %} selected{% endif %}>editor</option>
<option{% if f.Get("group") == "trusted" %} selected{% endif %}>trusted</option>
@ -154,36 +156,34 @@
</div>
<div class="form-field">
<button class="btn" type="submit">Update</button>
<button class="btn" type="submit">{%s lc.Get("admin.user_update") %}</button>
</div>
</form>
<h2>Delete user</h2>
<p>Remove the user from the database. Changes made by the user will
be preserved. It will be possible to take this username later.</p>
<a class="btn btn_destructive" href="/admin/users/{%u u.Name %}/delete">Delete</a>
<h2>{%s lc.Get("admin.user_delete_heading") %}</h2>
<p>{%s lc.Get("admin.user_delete_tip") %}</p>
<a class="btn btn_destructive" href="/admin/users/{%u u.Name %}/delete">{%s lc.Get("admin.user_delete") %}</a>
</main>
</div>
{% endfunc %}
{% func AdminUserDeleteHTML(u *user.User, f util.FormData) %}
{% func AdminUserDeleteHTML(u *user.User, f util.FormData, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width form-wrap">
<h1>Delete user</h1>
<h1>{%s lc.Get("admin.user_delete_heading") %}</h1>
{% if f.HasError() %}
<div class="notice notice--error">
<strong>Error:</strong>
<strong>{%s lc.Get("ui.error") %}:</strong>
{%s f.Error() %}
</div>
{% endif %}
<p>Are you sure you want to delete <strong>{%s u.Name %}</strong>
from the database? This action is irreversible.</p>
<p>{%s= lc.Get("admin.user_delete_warn", &l18n.Replacements{"name": fmt.Sprintf("<strong>%s</strong>", u.Name)}) %}</p>
<form action="" method="post">
<button class="btn btn_destructive" type="submit">Delete</button>
<a class="btn btn_weak" href="/admin/users/{%u u.Name %}/edit">Cancel</a>
<button class="btn btn_destructive" type="submit">{%s lc.Get("admin.user_delete") %}</button>
<a class="btn btn_weak" href="/admin/users/{%u u.Name %}/edit">{%s lc.Get("ui.cancel") %}</a>
</form>
</main>
</div>

View File

@ -5,54 +5,96 @@
package views
//line views/admin.qtpl:1
import "github.com/bouncepaw/mycorrhiza/cfg"
import "fmt"
//line views/admin.qtpl:2
import "github.com/bouncepaw/mycorrhiza/user"
import "github.com/bouncepaw/mycorrhiza/cfg"
//line views/admin.qtpl:3
import "github.com/bouncepaw/mycorrhiza/util"
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/admin.qtpl:4
import "github.com/bouncepaw/mycorrhiza/user"
//line views/admin.qtpl:5
import "github.com/bouncepaw/mycorrhiza/util"
//line views/admin.qtpl:7
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/admin.qtpl:5
//line views/admin.qtpl:7
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/admin.qtpl:5
func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
//line views/admin.qtpl:5
//line views/admin.qtpl:7
func StreamAdminPanelHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/admin.qtpl:7
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<h1>Administrative functions</h1>
<h1>`)
//line views/admin.qtpl:10
qw422016.E().S(lc.Get("admin.panel_title"))
//line views/admin.qtpl:10
qw422016.N().S(`</h1>
<section>
<h2>Safe things</h2>
<h2>`)
//line views/admin.qtpl:12
qw422016.E().S(lc.Get("admin.panel_safe"))
//line views/admin.qtpl:12
qw422016.N().S(`</h2>
<ul>
<li><a href="/about">About this wiki</a></li>
<li><a href="/user-list">User list</a></li>
<li><a href="/update-header-links">Update header links</a></li>
<li><a href="/admin/users/">Manage users</a></li>
<li><a href="/about">`)
//line views/admin.qtpl:14
qw422016.E().S(lc.Get("admin.panel_about"))
//line views/admin.qtpl:14
qw422016.N().S(`</a></li>
<li><a href="/user-list">`)
//line views/admin.qtpl:15
qw422016.E().S(lc.Get("admin.panel_userlist"))
//line views/admin.qtpl:15
qw422016.N().S(`</a></li>
<li><a href="/update-header-links">`)
//line views/admin.qtpl:16
qw422016.E().S(lc.Get("admin.panel_updateheader"))
//line views/admin.qtpl:16
qw422016.N().S(`</a></li>
<li><a href="/admin/users/">`)
//line views/admin.qtpl:17
qw422016.E().S(lc.Get("admin.panel_users"))
//line views/admin.qtpl:17
qw422016.N().S(`</a></li>
</ul>
</section>
<section>
<h2>Dangerous things</h2>
<h2>`)
//line views/admin.qtpl:21
qw422016.E().S(lc.Get("admin.panel_unsafe"))
//line views/admin.qtpl:21
qw422016.N().S(`</h2>
<form action="/admin/shutdown" method="POST" style="float:left">
<fieldset>
<legend>Shutdown wiki</legend>
<legend>`)
//line views/admin.qtpl:24
qw422016.E().S(lc.Get("admin.panel_shutdown"))
//line views/admin.qtpl:24
qw422016.N().S(`</legend>
<input type="submit" class="btn">
</fieldset>
</form>
<form action="/reindex" method="GET" style="float:left">
<fieldset>
<legend>Reindex hyphae</legend>
<legend>`)
//line views/admin.qtpl:30
qw422016.E().S(lc.Get("admin.panel_reindex"))
//line views/admin.qtpl:30
qw422016.N().S(`</legend>
<input type="submit" class="btn">
</fieldset>
</form>
@ -60,46 +102,58 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
</main>
</div>
`)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
}
//line views/admin.qtpl:35
func WriteAdminPanelHTML(qq422016 qtio422016.Writer) {
//line views/admin.qtpl:35
//line views/admin.qtpl:37
func WriteAdminPanelHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/admin.qtpl:37
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/admin.qtpl:35
StreamAdminPanelHTML(qw422016)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
StreamAdminPanelHTML(qw422016, lc)
//line views/admin.qtpl:37
qt422016.ReleaseWriter(qw422016)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
}
//line views/admin.qtpl:35
func AdminPanelHTML() string {
//line views/admin.qtpl:35
//line views/admin.qtpl:37
func AdminPanelHTML(lc *l18n.Localizer) string {
//line views/admin.qtpl:37
qb422016 := qt422016.AcquireByteBuffer()
//line views/admin.qtpl:35
WriteAdminPanelHTML(qb422016)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
WriteAdminPanelHTML(qb422016, lc)
//line views/admin.qtpl:37
qs422016 := string(qb422016.B)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
qt422016.ReleaseByteBuffer(qb422016)
//line views/admin.qtpl:35
//line views/admin.qtpl:37
return qs422016
//line views/admin.qtpl:35
//line views/admin.qtpl:37
}
//line views/admin.qtpl:37
func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User) {
//line views/admin.qtpl:37
//line views/admin.qtpl:39
func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User, lc *l18n.Localizer) {
//line views/admin.qtpl:39
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<h1>Manage users</h1>
<h1>`)
//line views/admin.qtpl:42
qw422016.E().S(lc.Get("admin.users_title"))
//line views/admin.qtpl:42
qw422016.N().S(`</h1>
<form action="/admin/reindex-users" method="post">
<a class="btn" href="/admin/user/new">Create a new user</a>
<button class="btn" type="submit">Reindex users</button>
<a class="btn" href="/admin/user/new">`)
//line views/admin.qtpl:45
qw422016.E().S(lc.Get("admin.users_create"))
//line views/admin.qtpl:45
qw422016.N().S(`</a>
<button class="btn" type="submit">`)
//line views/admin.qtpl:46
qw422016.E().S(lc.Get("admin.users_reindex"))
//line views/admin.qtpl:46
qw422016.N().S(`</button>
</form>
<br>
@ -107,418 +161,512 @@ func StreamAdminUsersPanelHTML(qw422016 *qt422016.Writer, userList []*user.User)
<table class="users-table">
<thead>
<tr>
<th>Name</th>
<th>Group</th>
<th>Registered at</th>
<th aria-label="Actions"></th>
<th>`)
//line views/admin.qtpl:54
qw422016.E().S(lc.Get("admin.users_name"))
//line views/admin.qtpl:54
qw422016.N().S(`</th>
<th>`)
//line views/admin.qtpl:55
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:55
qw422016.N().S(`</th>
<th>`)
//line views/admin.qtpl:56
qw422016.E().S(lc.Get("admin.users_registered"))
//line views/admin.qtpl:56
qw422016.N().S(`</th>
<th aria-label="`)
//line views/admin.qtpl:57
qw422016.E().S(lc.Get("admin.users_actions"))
//line views/admin.qtpl:57
qw422016.N().S(`"></th>
</tr>
</thead>
<tbody>
`)
//line views/admin.qtpl:59
//line views/admin.qtpl:61
for _, u := range userList {
//line views/admin.qtpl:59
//line views/admin.qtpl:61
qw422016.N().S(`
<tr>
<td class="table-cell--fill">
<a href="/hypha/`)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.N().U(cfg.UserHypha)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.N().S(`/`)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.N().U(u.Name)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.N().S(`">`)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.E().S(u.Name)
//line views/admin.qtpl:62
//line views/admin.qtpl:64
qw422016.N().S(`</a>
</td>
<td>`)
//line views/admin.qtpl:64
//line views/admin.qtpl:66
qw422016.E().S(u.Group)
//line views/admin.qtpl:64
//line views/admin.qtpl:66
qw422016.N().S(`</td>
<td>
`)
//line views/admin.qtpl:66
if u.RegisteredAt.IsZero() {
//line views/admin.qtpl:66
qw422016.N().S(`
unknown
`)
//line views/admin.qtpl:68
} else {
if u.RegisteredAt.IsZero() {
//line views/admin.qtpl:68
qw422016.N().S(`
`)
//line views/admin.qtpl:69
qw422016.E().S(u.RegisteredAt.UTC().Format("2006-01-02 15:04"))
qw422016.E().S(lc.Get("admin.users_notime"))
//line views/admin.qtpl:69
qw422016.N().S(`
`)
//line views/admin.qtpl:70
}
} else {
//line views/admin.qtpl:70
qw422016.N().S(`
`)
//line views/admin.qtpl:71
qw422016.E().S(u.RegisteredAt.UTC().Format("2006-01-02 15:04"))
//line views/admin.qtpl:71
qw422016.N().S(`
`)
//line views/admin.qtpl:72
}
//line views/admin.qtpl:72
qw422016.N().S(`
</td>
<td>
<a href="/admin/users/`)
//line views/admin.qtpl:73
//line views/admin.qtpl:75
qw422016.N().U(u.Name)
//line views/admin.qtpl:73
qw422016.N().S(`/edit">Edit</a>
//line views/admin.qtpl:75
qw422016.N().S(`/edit">`)
//line views/admin.qtpl:75
qw422016.E().S(lc.Get("admin.users_edit"))
//line views/admin.qtpl:75
qw422016.N().S(`</a>
</td>
</tr>
`)
//line views/admin.qtpl:76
//line views/admin.qtpl:78
}
//line views/admin.qtpl:76
//line views/admin.qtpl:78
qw422016.N().S(`
</tbody>
</table>
</main>
</div>
`)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
}
//line views/admin.qtpl:81
func WriteAdminUsersPanelHTML(qq422016 qtio422016.Writer, userList []*user.User) {
//line views/admin.qtpl:81
//line views/admin.qtpl:83
func WriteAdminUsersPanelHTML(qq422016 qtio422016.Writer, userList []*user.User, lc *l18n.Localizer) {
//line views/admin.qtpl:83
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/admin.qtpl:81
StreamAdminUsersPanelHTML(qw422016, userList)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
StreamAdminUsersPanelHTML(qw422016, userList, lc)
//line views/admin.qtpl:83
qt422016.ReleaseWriter(qw422016)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
}
//line views/admin.qtpl:81
func AdminUsersPanelHTML(userList []*user.User) string {
//line views/admin.qtpl:81
//line views/admin.qtpl:83
func AdminUsersPanelHTML(userList []*user.User, lc *l18n.Localizer) string {
//line views/admin.qtpl:83
qb422016 := qt422016.AcquireByteBuffer()
//line views/admin.qtpl:81
WriteAdminUsersPanelHTML(qb422016, userList)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
WriteAdminUsersPanelHTML(qb422016, userList, lc)
//line views/admin.qtpl:83
qs422016 := string(qb422016.B)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
qt422016.ReleaseByteBuffer(qb422016)
//line views/admin.qtpl:81
//line views/admin.qtpl:83
return qs422016
//line views/admin.qtpl:81
//line views/admin.qtpl:83
}
//line views/admin.qtpl:83
func StreamAdminUserNewHTML(qw422016 *qt422016.Writer, f util.FormData) {
//line views/admin.qtpl:83
//line views/admin.qtpl:85
func StreamAdminUserNewHTML(qw422016 *qt422016.Writer, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:85
qw422016.N().S(`
<div class="layout">
<main class="main-width form-wrap">
<h1>New user</h1>
<h1>`)
//line views/admin.qtpl:88
qw422016.E().S(lc.Get("admin.newuser_title"))
//line views/admin.qtpl:88
qw422016.N().S(`</h1>
`)
//line views/admin.qtpl:88
//line views/admin.qtpl:90
if f.HasError() {
//line views/admin.qtpl:88
//line views/admin.qtpl:90
qw422016.N().S(`
<div class="notice notice--error">
<strong>Error:</strong>
<strong>`)
//line views/admin.qtpl:92
qw422016.E().S(lc.Get("ui.error"))
//line views/admin.qtpl:92
qw422016.N().S(`:</strong>
`)
//line views/admin.qtpl:91
//line views/admin.qtpl:93
qw422016.E().S(f.Error())
//line views/admin.qtpl:91
//line views/admin.qtpl:93
qw422016.N().S(`
</div>
`)
//line views/admin.qtpl:93
//line views/admin.qtpl:95
}
//line views/admin.qtpl:93
//line views/admin.qtpl:95
qw422016.N().S(`
<form class="form--double" action="" method="post">
<div class="form-field">
<label for="name">Name:</label>
<label for="name">`)
//line views/admin.qtpl:99
qw422016.E().S(lc.Get("admin.users_name"))
//line views/admin.qtpl:99
qw422016.N().S(`:</label>
<input type="text" name="name" id="name" value="`)
//line views/admin.qtpl:98
//line views/admin.qtpl:100
qw422016.E().S(f.Get("name"))
//line views/admin.qtpl:98
//line views/admin.qtpl:100
qw422016.N().S(`" autofocus>
</div>
<div class="form-field">
<label for="password">Password:</label>
<label for="password">`)
//line views/admin.qtpl:104
qw422016.E().S(lc.Get("admin.users_password"))
//line views/admin.qtpl:104
qw422016.N().S(`:</label>
<input type="password" name="password" id="password" value="`)
//line views/admin.qtpl:103
//line views/admin.qtpl:105
qw422016.E().S(f.Get("password"))
//line views/admin.qtpl:103
//line views/admin.qtpl:105
qw422016.N().S(`">
</div>
<div class="form-field">
<label for="group">Group:</label>
<label for="group">`)
//line views/admin.qtpl:109
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:109
qw422016.N().S(`:</label>
<select id="group" name="group">
<option`)
//line views/admin.qtpl:109
//line views/admin.qtpl:111
if f.Get("group") == "anon" {
//line views/admin.qtpl:109
//line views/admin.qtpl:111
qw422016.N().S(` selected`)
//line views/admin.qtpl:109
//line views/admin.qtpl:111
}
//line views/admin.qtpl:109
//line views/admin.qtpl:111
qw422016.N().S(`>anon</option>
<option`)
//line views/admin.qtpl:110
//line views/admin.qtpl:112
if f.Get("group") == "editor" {
//line views/admin.qtpl:110
//line views/admin.qtpl:112
qw422016.N().S(` selected`)
//line views/admin.qtpl:110
//line views/admin.qtpl:112
}
//line views/admin.qtpl:110
//line views/admin.qtpl:112
qw422016.N().S(`>editor</option>
<option`)
//line views/admin.qtpl:111
//line views/admin.qtpl:113
if f.Get("group") == "trusted" {
//line views/admin.qtpl:111
//line views/admin.qtpl:113
qw422016.N().S(` selected`)
//line views/admin.qtpl:111
//line views/admin.qtpl:113
}
//line views/admin.qtpl:111
//line views/admin.qtpl:113
qw422016.N().S(`>trusted</option>
<option`)
//line views/admin.qtpl:112
//line views/admin.qtpl:114
if f.Get("group") == "moderator" {
//line views/admin.qtpl:112
//line views/admin.qtpl:114
qw422016.N().S(` selected`)
//line views/admin.qtpl:112
//line views/admin.qtpl:114
}
//line views/admin.qtpl:112
//line views/admin.qtpl:114
qw422016.N().S(`>moderator</option>
<option`)
//line views/admin.qtpl:113
//line views/admin.qtpl:115
if f.Get("group") == "admin" {
//line views/admin.qtpl:113
//line views/admin.qtpl:115
qw422016.N().S(` selected`)
//line views/admin.qtpl:113
//line views/admin.qtpl:115
}
//line views/admin.qtpl:113
//line views/admin.qtpl:115
qw422016.N().S(`>admin</option>
</select>
</div>
<div class="form-field">
<div class="form-field__input">
<button class="btn" type="submit">Create</button>
<a class="btn btn_weak" href="/admin/users/">Cancel</a>
<button class="btn" type="submit">`)
//line views/admin.qtpl:121
qw422016.E().S(lc.Get("admin.newuser_create"))
//line views/admin.qtpl:121
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/admin/users/">`)
//line views/admin.qtpl:122
qw422016.E().S(lc.Get("ui.cancel"))
//line views/admin.qtpl:122
qw422016.N().S(`</a>
</div>
</div>
</form>
</main>
</div>
`)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
}
//line views/admin.qtpl:126
func WriteAdminUserNewHTML(qq422016 qtio422016.Writer, f util.FormData) {
//line views/admin.qtpl:126
//line views/admin.qtpl:128
func WriteAdminUserNewHTML(qq422016 qtio422016.Writer, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:128
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/admin.qtpl:126
StreamAdminUserNewHTML(qw422016, f)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
StreamAdminUserNewHTML(qw422016, f, lc)
//line views/admin.qtpl:128
qt422016.ReleaseWriter(qw422016)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
}
//line views/admin.qtpl:126
func AdminUserNewHTML(f util.FormData) string {
//line views/admin.qtpl:126
//line views/admin.qtpl:128
func AdminUserNewHTML(f util.FormData, lc *l18n.Localizer) string {
//line views/admin.qtpl:128
qb422016 := qt422016.AcquireByteBuffer()
//line views/admin.qtpl:126
WriteAdminUserNewHTML(qb422016, f)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
WriteAdminUserNewHTML(qb422016, f, lc)
//line views/admin.qtpl:128
qs422016 := string(qb422016.B)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
qt422016.ReleaseByteBuffer(qb422016)
//line views/admin.qtpl:126
//line views/admin.qtpl:128
return qs422016
//line views/admin.qtpl:126
//line views/admin.qtpl:128
}
//line views/admin.qtpl:128
func StreamAdminUserEditHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData) {
//line views/admin.qtpl:128
//line views/admin.qtpl:130
func StreamAdminUserEditHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:130
qw422016.N().S(`
<div class="layout">
<main class="main-width form-wrap">
<h1>
<a href="/admin/users/">&larr;</a>
`)
//line views/admin.qtpl:133
//line views/admin.qtpl:135
qw422016.E().S(u.Name)
//line views/admin.qtpl:133
//line views/admin.qtpl:135
qw422016.N().S(`
</h1>
<h2>Change group</h2>
<h2>`)
//line views/admin.qtpl:138
qw422016.E().S(lc.Get("admin.user_group_heading"))
//line views/admin.qtpl:138
qw422016.N().S(`</h2>
`)
//line views/admin.qtpl:138
//line views/admin.qtpl:140
if f.HasError() {
//line views/admin.qtpl:138
//line views/admin.qtpl:140
qw422016.N().S(`
<div class="notice notice--error">
<strong>Error:</strong>
<strong>`)
//line views/admin.qtpl:142
qw422016.E().S(lc.Get("ui.error"))
//line views/admin.qtpl:142
qw422016.N().S(`:</strong>
`)
//line views/admin.qtpl:141
//line views/admin.qtpl:143
qw422016.E().S(f.Error())
//line views/admin.qtpl:141
//line views/admin.qtpl:143
qw422016.N().S(`
</div>
`)
//line views/admin.qtpl:143
//line views/admin.qtpl:145
}
//line views/admin.qtpl:143
//line views/admin.qtpl:145
qw422016.N().S(`
<form action="" method="post">
<div class="form-field">
<select id="group" name="group" aria-label="Group">
<select id="group" name="group" aria-label="`)
//line views/admin.qtpl:149
qw422016.E().S(lc.Get("admin.users_group"))
//line views/admin.qtpl:149
qw422016.N().S(`">
<option`)
//line views/admin.qtpl:148
//line views/admin.qtpl:150
if f.Get("group") == "anon" {
//line views/admin.qtpl:148
//line views/admin.qtpl:150
qw422016.N().S(` selected`)
//line views/admin.qtpl:148
//line views/admin.qtpl:150
}
//line views/admin.qtpl:148
//line views/admin.qtpl:150
qw422016.N().S(`>anon</option>
<option`)
//line views/admin.qtpl:149
//line views/admin.qtpl:151
if f.Get("group") == "editor" {
//line views/admin.qtpl:149
//line views/admin.qtpl:151
qw422016.N().S(` selected`)
//line views/admin.qtpl:149
//line views/admin.qtpl:151
}
//line views/admin.qtpl:149
//line views/admin.qtpl:151
qw422016.N().S(`>editor</option>
<option`)
//line views/admin.qtpl:150
//line views/admin.qtpl:152
if f.Get("group") == "trusted" {
//line views/admin.qtpl:150
//line views/admin.qtpl:152
qw422016.N().S(` selected`)
//line views/admin.qtpl:150
//line views/admin.qtpl:152
}
//line views/admin.qtpl:150
//line views/admin.qtpl:152
qw422016.N().S(`>trusted</option>
<option`)
//line views/admin.qtpl:151
//line views/admin.qtpl:153
if f.Get("group") == "moderator" {
//line views/admin.qtpl:151
//line views/admin.qtpl:153
qw422016.N().S(` selected`)
//line views/admin.qtpl:151
//line views/admin.qtpl:153
}
//line views/admin.qtpl:151
//line views/admin.qtpl:153
qw422016.N().S(`>moderator</option>
<option`)
//line views/admin.qtpl:152
//line views/admin.qtpl:154
if f.Get("group") == "admin" {
//line views/admin.qtpl:152
//line views/admin.qtpl:154
qw422016.N().S(` selected`)
//line views/admin.qtpl:152
//line views/admin.qtpl:154
}
//line views/admin.qtpl:152
//line views/admin.qtpl:154
qw422016.N().S(`>admin</option>
</select>
</div>
<div class="form-field">
<button class="btn" type="submit">Update</button>
<button class="btn" type="submit">`)
//line views/admin.qtpl:159
qw422016.E().S(lc.Get("admin.user_update"))
//line views/admin.qtpl:159
qw422016.N().S(`</button>
</div>
</form>
<h2>Delete user</h2>
<p>Remove the user from the database. Changes made by the user will
be preserved. It will be possible to take this username later.</p>
<h2>`)
//line views/admin.qtpl:163
qw422016.E().S(lc.Get("admin.user_delete_heading"))
//line views/admin.qtpl:163
qw422016.N().S(`</h2>
<p>`)
//line views/admin.qtpl:164
qw422016.E().S(lc.Get("admin.user_delete_tip"))
//line views/admin.qtpl:164
qw422016.N().S(`</p>
<a class="btn btn_destructive" href="/admin/users/`)
//line views/admin.qtpl:164
//line views/admin.qtpl:165
qw422016.N().U(u.Name)
//line views/admin.qtpl:164
qw422016.N().S(`/delete">Delete</a>
//line views/admin.qtpl:165
qw422016.N().S(`/delete">`)
//line views/admin.qtpl:165
qw422016.E().S(lc.Get("admin.user_delete"))
//line views/admin.qtpl:165
qw422016.N().S(`</a>
</main>
</div>
`)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
}
//line views/admin.qtpl:167
func WriteAdminUserEditHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData) {
//line views/admin.qtpl:167
//line views/admin.qtpl:168
func WriteAdminUserEditHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:168
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/admin.qtpl:167
StreamAdminUserEditHTML(qw422016, u, f)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
StreamAdminUserEditHTML(qw422016, u, f, lc)
//line views/admin.qtpl:168
qt422016.ReleaseWriter(qw422016)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
}
//line views/admin.qtpl:167
func AdminUserEditHTML(u *user.User, f util.FormData) string {
//line views/admin.qtpl:167
//line views/admin.qtpl:168
func AdminUserEditHTML(u *user.User, f util.FormData, lc *l18n.Localizer) string {
//line views/admin.qtpl:168
qb422016 := qt422016.AcquireByteBuffer()
//line views/admin.qtpl:167
WriteAdminUserEditHTML(qb422016, u, f)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
WriteAdminUserEditHTML(qb422016, u, f, lc)
//line views/admin.qtpl:168
qs422016 := string(qb422016.B)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
qt422016.ReleaseByteBuffer(qb422016)
//line views/admin.qtpl:167
//line views/admin.qtpl:168
return qs422016
//line views/admin.qtpl:167
//line views/admin.qtpl:168
}
//line views/admin.qtpl:169
func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData) {
//line views/admin.qtpl:169
//line views/admin.qtpl:170
func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:170
qw422016.N().S(`
<div class="layout">
<main class="main-width form-wrap">
<h1>Delete user</h1>
<h1>`)
//line views/admin.qtpl:173
qw422016.E().S(lc.Get("admin.user_delete_heading"))
//line views/admin.qtpl:173
qw422016.N().S(`</h1>
`)
//line views/admin.qtpl:174
//line views/admin.qtpl:175
if f.HasError() {
//line views/admin.qtpl:174
//line views/admin.qtpl:175
qw422016.N().S(`
<div class="notice notice--error">
<strong>Error:</strong>
<strong>`)
//line views/admin.qtpl:177
qw422016.E().S(lc.Get("ui.error"))
//line views/admin.qtpl:177
qw422016.N().S(`:</strong>
`)
//line views/admin.qtpl:177
//line views/admin.qtpl:178
qw422016.E().S(f.Error())
//line views/admin.qtpl:177
//line views/admin.qtpl:178
qw422016.N().S(`
</div>
`)
//line views/admin.qtpl:179
//line views/admin.qtpl:180
}
//line views/admin.qtpl:179
//line views/admin.qtpl:180
qw422016.N().S(`
<p>Are you sure you want to delete <strong>`)
//line views/admin.qtpl:181
qw422016.E().S(u.Name)
//line views/admin.qtpl:181
qw422016.N().S(`</strong>
from the database? This action is irreversible.</p>
<p>`)
//line views/admin.qtpl:182
qw422016.N().S(lc.Get("admin.user_delete_warn", &l18n.Replacements{"name": fmt.Sprintf("<strong>%s</strong>", u.Name)}))
//line views/admin.qtpl:182
qw422016.N().S(`</p>
<form action="" method="post">
<button class="btn btn_destructive" type="submit">Delete</button>
<button class="btn btn_destructive" type="submit">`)
//line views/admin.qtpl:185
qw422016.E().S(lc.Get("admin.user_delete"))
//line views/admin.qtpl:185
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/admin/users/`)
//line views/admin.qtpl:186
qw422016.N().U(u.Name)
//line views/admin.qtpl:186
qw422016.N().S(`/edit">Cancel</a>
qw422016.N().S(`/edit">`)
//line views/admin.qtpl:186
qw422016.E().S(lc.Get("ui.cancel"))
//line views/admin.qtpl:186
qw422016.N().S(`</a>
</form>
</main>
</div>
@ -527,22 +675,22 @@ func StreamAdminUserDeleteHTML(qw422016 *qt422016.Writer, u *user.User, f util.F
}
//line views/admin.qtpl:190
func WriteAdminUserDeleteHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData) {
func WriteAdminUserDeleteHTML(qq422016 qtio422016.Writer, u *user.User, f util.FormData, lc *l18n.Localizer) {
//line views/admin.qtpl:190
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/admin.qtpl:190
StreamAdminUserDeleteHTML(qw422016, u, f)
StreamAdminUserDeleteHTML(qw422016, u, f, lc)
//line views/admin.qtpl:190
qt422016.ReleaseWriter(qw422016)
//line views/admin.qtpl:190
}
//line views/admin.qtpl:190
func AdminUserDeleteHTML(u *user.User, f util.FormData) string {
func AdminUserDeleteHTML(u *user.User, f util.FormData, lc *l18n.Localizer) string {
//line views/admin.qtpl:190
qb422016 := qt422016.AcquireByteBuffer()
//line views/admin.qtpl:190
WriteAdminUserDeleteHTML(qb422016, u, f)
WriteAdminUserDeleteHTML(qb422016, u, f, lc)
//line views/admin.qtpl:190
qs422016 := string(qb422016.B)
//line views/admin.qtpl:190

View File

@ -1,65 +1,69 @@
{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% func RegisterHTML(rq *http.Request) %}
{% code
lc := l18n.FromRequest(rq)
%}
<div class="layout">
<main class="main-width">
<section>
{% if cfg.AllowRegistration %}
<form class="modal" method="post" action="/register?{%s rq.URL.RawQuery %}" id="register-form" enctype="multipart/form-data" autocomplete="off">
<fieldset class="modal__fieldset">
<legend class="modal__title">Register on {%s cfg.WikiName %}</legend>
<legend class="modal__title">{%s lc.Get("auth.register_header", &l18n.Replacements{"name": cfg.WikiName}) %}</legend>
<label for="register-form__username">Username</label>
<label for="register-form__username">{%s lc.Get("auth.username") %}</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">{%s lc.Get("auth.password") %}</label>
<br>
<input type="password" required name="password">
<p>The server stores your password in an encrypted form; even administrators cannot read it.</p>
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.</p>
<input class="btn" type="submit" value="Register">
<a class="btn btn_weak" href="/{%s rq.URL.RawQuery %}">Cancel</a>
<p>{%s lc.Get("auth.password_tip") %}</p>
<p>{%s lc.Get("auth.cookie_tip") %}</p>
<button class="btn" type="submit" value="Register">{%s lc.Get("auth.register_button") %}</button>
<a class="btn btn_weak" href="/{%s rq.URL.RawQuery %}">{%s lc.Get("ui.cancel") %}</a>
</fieldset>
</form>
{%= telegramWidgetHTML() %}
{%= telegramWidgetHTML(lc) %}
{% elseif cfg.UseAuth %}
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
<p>{%s lc.Get("auth.noregister") %}</p>
<p><a href="/{%s rq.URL.RawQuery %}">← {%s lc.Get("auth.go_back") %}</a></p>
{% else %}
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
<p>{%s lc.Get("auth.noauth") %}</p>
<p><a href="/{%s rq.URL.RawQuery %}">← {%s lc.Get("auth.go_back") %}</a></p>
{% endif %}
</section>
</main>
</div>
{% endfunc %}
{% func LoginHTML() %}
{% func LoginHTML(lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<section>
{% if cfg.UseAuth %}
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset">
<legend class="modal__title">Log in to {%s cfg.WikiName %}</legend>
<label for="login-form__username">Username</label>
<legend class="modal__title">{%s lc.Get("auth.login_header", &l18n.Replacements{"name": cfg.WikiName}) %}</legend>
<label for="login-form__username">{%s lc.Get("auth.username") %}</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">{%s lc.Get("auth.password") %}</label>
<br>
<input type="password" required name="password" autocomplete="current-password">
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.</p>
<input class="btn" type="submit" value="Log in">
<a class="btn btn_weak" href="/">Cancel</a>
<p>{%s lc.Get("auth.cookie_tip") %}</p>
<button class="btn" type="submit" value="Log in">{%s lc.Get("auth.login_button") %}</button>
<a class="btn btn_weak" href="/">{%s lc.Get("ui.cancel") %}</a>
</fieldset>
</form>
{%= telegramWidgetHTML() %}
{%= telegramWidgetHTML(lc) %}
{% else %}
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a class="btn btn_weak" href="/">← Go home</a></p>
<p>{%s lc.Get("auth.noauth") %}</p>
<p><a class="btn btn_weak" href="/">← {%s lc.Get("auth.go_home") %}</a></p>
{% endif %}
</section>
</main>
@ -67,56 +71,56 @@
{% endfunc %}
Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't.
{% func telegramWidgetHTML() %}
{% func telegramWidgetHTML(lc *l18n.Localizer) %}
{% if cfg.TelegramEnabled %}
<p class="telegram-notice">You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.</p>
<p class="telegram-notice">{%s lc.Get("auth.telegram_tip") %}</p>
<script async src="https://telegram.org/js/telegram-widget.js?15" data-telegram-login="{%s cfg.TelegramBotName %}" data-size="medium" data-userpic="false" data-auth-url="{%s cfg.URL %}/telegram-login"></script>
{% endif %}
{% endfunc %}
{% func LoginErrorHTML(err string) %}
{% func LoginErrorHTML(err string, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<section>
{% switch err %}
{% case "unknown username" %}
<p class="error">Unknown username.</p>
<p class="error">{%s lc.Get("auth.error_username") %}</p>
{% case "wrong password" %}
<p class="error">Wrong password.</p>
<p class="error">{%s lc.Get("auth.error_password") %}</p>
{% default %}
<p class="error">{%s err %}</p>
{% endswitch %}
<p><a href="/login">← Try again</a></p>
<p><a href="/login">← {%s lc.Get("auth.try_again") %}</a></p>
</section>
</main>
</div>
{% endfunc %}
{% func LogoutHTML(can bool) %}
{% func LogoutHTML(can bool, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<section>
{% if can %}
<h1>Log out?</h1>
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
<p><a href="/">Cancel</a></p>
<h1>{%s lc.Get("auth.logout_header") %}</h1>
<p><a href="/logout-confirm"><strong>{%s lc.Get("auth.logout_button") %}</strong></a></p>
<p><a href="/">{%s lc.Get("ui.cancel") %}</a></p>
{% else %}
<p>You cannot log out because you are not logged in.</p>
<p><a href="/login">Login</a></p>
<p><a href="/login">← Home</a></p>
<p>{%s lc.Get("auth.logout_anon") %}</p>
<p><a href="/login">{%s lc.Get("auth.login_title") %}</a></p>
<p><a href="/">← {%s lc.Get("auth.go_home") %}</a></p>
{% endif %}
</section>
</main>
</div>
{% endfunc %}
{% func LockHTML() %}
{% func LockHTML(lc *l18n.Localizer) %}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🔒 Locked</title>
<title>🔒 {%s lc.Get("auth.lock_title") %}</title>
<link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/style.css">
</head>
@ -124,19 +128,19 @@ Telegram auth widget was requested by Yogurt. As you can see, we don't offer use
<main class="locked-notice">
<section class="locked-notice__message">
<p class="locked-notice__lock">🔒</p>
<h1 class="locked-notice__title">Locked</h1>
<h1 class="locked-notice__title">{%s lc.Get("auth.lock_title") %}</h1>
<form class="locked-notice__login-form" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<label for="login-form__username">Username</label>
<label for="login-form__username">{%s lc.Get("auth.username") %}</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">{%s lc.Get("auth.password") %}</label>
<br>
<input type="password" required name="password" autocomplete="current-password">
<br>
<input class="btn" type="submit" value="Log in">
<button class="btn" type="submit" value="Log in">{%s lc.Get("auth.login_button") %}</button>
</form>
{%= telegramWidgetHTML() %}
{%= telegramWidgetHTML(lc) %}
</section>
</main>
</body>

View File

@ -10,403 +10,524 @@ import "net/http"
//line views/auth.qtpl:2
import "github.com/bouncepaw/mycorrhiza/cfg"
//line views/auth.qtpl:4
//line views/auth.qtpl:3
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/auth.qtpl:5
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/auth.qtpl:4
//line views/auth.qtpl:5
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/auth.qtpl:4
//line views/auth.qtpl:5
func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {
//line views/auth.qtpl:4
//line views/auth.qtpl:5
qw422016.N().S(`
`)
//line views/auth.qtpl:7
lc := l18n.FromRequest(rq)
//line views/auth.qtpl:8
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:8
//line views/auth.qtpl:12
if cfg.AllowRegistration {
//line views/auth.qtpl:8
//line views/auth.qtpl:12
qw422016.N().S(`
<form class="modal" method="post" action="/register?`)
//line views/auth.qtpl:9
//line views/auth.qtpl:13
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:9
//line views/auth.qtpl:13
qw422016.N().S(`" id="register-form" enctype="multipart/form-data" autocomplete="off">
<fieldset class="modal__fieldset">
<legend class="modal__title">Register on `)
//line views/auth.qtpl:11
qw422016.E().S(cfg.WikiName)
//line views/auth.qtpl:11
<legend class="modal__title">`)
//line views/auth.qtpl:15
qw422016.E().S(lc.Get("auth.register_header", &l18n.Replacements{"name": cfg.WikiName}))
//line views/auth.qtpl:15
qw422016.N().S(`</legend>
<label for="register-form__username">Username</label>
<label for="register-form__username">`)
//line views/auth.qtpl:17
qw422016.E().S(lc.Get("auth.username"))
//line views/auth.qtpl:17
qw422016.N().S(`</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">`)
//line views/auth.qtpl:21
qw422016.E().S(lc.Get("auth.password"))
//line views/auth.qtpl:21
qw422016.N().S(`</label>
<br>
<input type="password" required name="password">
<p>The server stores your password in an encrypted form; even administrators cannot read it.</p>
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.</p>
<input class="btn" type="submit" value="Register">
<p>`)
//line views/auth.qtpl:24
qw422016.E().S(lc.Get("auth.password_tip"))
//line views/auth.qtpl:24
qw422016.N().S(`</p>
<p>`)
//line views/auth.qtpl:25
qw422016.E().S(lc.Get("auth.cookie_tip"))
//line views/auth.qtpl:25
qw422016.N().S(`</p>
<button class="btn" type="submit" value="Register">`)
//line views/auth.qtpl:26
qw422016.E().S(lc.Get("auth.register_button"))
//line views/auth.qtpl:26
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/`)
//line views/auth.qtpl:23
//line views/auth.qtpl:27
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:23
qw422016.N().S(`">Cancel</a>
//line views/auth.qtpl:27
qw422016.N().S(`">`)
//line views/auth.qtpl:27
qw422016.E().S(lc.Get("ui.cancel"))
//line views/auth.qtpl:27
qw422016.N().S(`</a>
</fieldset>
</form>
`)
//line views/auth.qtpl:26
streamtelegramWidgetHTML(qw422016)
//line views/auth.qtpl:26
//line views/auth.qtpl:30
streamtelegramWidgetHTML(qw422016, lc)
//line views/auth.qtpl:30
qw422016.N().S(`
`)
//line views/auth.qtpl:27
//line views/auth.qtpl:31
} else if cfg.UseAuth {
//line views/auth.qtpl:27
//line views/auth.qtpl:31
qw422016.N().S(`
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
<p>`)
//line views/auth.qtpl:32
qw422016.E().S(lc.Get("auth.noregister"))
//line views/auth.qtpl:32
qw422016.N().S(`</p>
<p><a href="/`)
//line views/auth.qtpl:29
//line views/auth.qtpl:33
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:29
qw422016.N().S(`"> Go back</a></p>
//line views/auth.qtpl:33
qw422016.N().S(`">← `)
//line views/auth.qtpl:33
qw422016.E().S(lc.Get("auth.go_back"))
//line views/auth.qtpl:33
qw422016.N().S(`</a></p>
`)
//line views/auth.qtpl:30
//line views/auth.qtpl:34
} else {
//line views/auth.qtpl:30
//line views/auth.qtpl:34
qw422016.N().S(`
<p>Authentication is disabled. You can make edits anonymously.</p>
<p>`)
//line views/auth.qtpl:35
qw422016.E().S(lc.Get("auth.noauth"))
//line views/auth.qtpl:35
qw422016.N().S(`</p>
<p><a href="/`)
//line views/auth.qtpl:32
//line views/auth.qtpl:36
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:32
qw422016.N().S(`"> Go back</a></p>
//line views/auth.qtpl:36
qw422016.N().S(`">← `)
//line views/auth.qtpl:36
qw422016.E().S(lc.Get("auth.go_back"))
//line views/auth.qtpl:36
qw422016.N().S(`</a></p>
`)
//line views/auth.qtpl:33
//line views/auth.qtpl:37
}
//line views/auth.qtpl:33
//line views/auth.qtpl:37
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
}
//line views/auth.qtpl:37
//line views/auth.qtpl:41
func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) {
//line views/auth.qtpl:37
//line views/auth.qtpl:41
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
StreamRegisterHTML(qw422016, rq)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
}
//line views/auth.qtpl:37
//line views/auth.qtpl:41
func RegisterHTML(rq *http.Request) string {
//line views/auth.qtpl:37
//line views/auth.qtpl:41
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:37
//line views/auth.qtpl:41
WriteRegisterHTML(qb422016, rq)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
qs422016 := string(qb422016.B)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:41
return qs422016
//line views/auth.qtpl:37
//line views/auth.qtpl:41
}
//line views/auth.qtpl:39
func StreamLoginHTML(qw422016 *qt422016.Writer) {
//line views/auth.qtpl:39
//line views/auth.qtpl:43
func StreamLoginHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:43
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:43
//line views/auth.qtpl:47
if cfg.UseAuth {
//line views/auth.qtpl:43
//line views/auth.qtpl:47
qw422016.N().S(`
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset">
<legend class="modal__title">Log in to `)
//line views/auth.qtpl:46
qw422016.E().S(cfg.WikiName)
//line views/auth.qtpl:46
<legend class="modal__title">`)
//line views/auth.qtpl:50
qw422016.E().S(lc.Get("auth.login_header", &l18n.Replacements{"name": cfg.WikiName}))
//line views/auth.qtpl:50
qw422016.N().S(`</legend>
<label for="login-form__username">Username</label>
<label for="login-form__username">`)
//line views/auth.qtpl:51
qw422016.E().S(lc.Get("auth.username"))
//line views/auth.qtpl:51
qw422016.N().S(`</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">`)
//line views/auth.qtpl:55
qw422016.E().S(lc.Get("auth.password"))
//line views/auth.qtpl:55
qw422016.N().S(`</label>
<br>
<input type="password" required name="password" autocomplete="current-password">
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.</p>
<input class="btn" type="submit" value="Log in">
<a class="btn btn_weak" href="/">Cancel</a>
<p>`)
//line views/auth.qtpl:58
qw422016.E().S(lc.Get("auth.cookie_tip"))
//line views/auth.qtpl:58
qw422016.N().S(`</p>
<button class="btn" type="submit" value="Log in">`)
//line views/auth.qtpl:59
qw422016.E().S(lc.Get("auth.login_button"))
//line views/auth.qtpl:59
qw422016.N().S(`</button>
<a class="btn btn_weak" href="/">`)
//line views/auth.qtpl:60
qw422016.E().S(lc.Get("ui.cancel"))
//line views/auth.qtpl:60
qw422016.N().S(`</a>
</fieldset>
</form>
`)
//line views/auth.qtpl:59
streamtelegramWidgetHTML(qw422016)
//line views/auth.qtpl:59
//line views/auth.qtpl:63
streamtelegramWidgetHTML(qw422016, lc)
//line views/auth.qtpl:63
qw422016.N().S(`
`)
//line views/auth.qtpl:60
//line views/auth.qtpl:64
} else {
//line views/auth.qtpl:60
//line views/auth.qtpl:64
qw422016.N().S(`
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a class="btn btn_weak" href="/"> Go home</a></p>
<p>`)
//line views/auth.qtpl:65
qw422016.E().S(lc.Get("auth.noauth"))
//line views/auth.qtpl:65
qw422016.N().S(`</p>
<p><a class="btn btn_weak" href="/"> `)
//line views/auth.qtpl:66
qw422016.E().S(lc.Get("auth.go_home"))
//line views/auth.qtpl:66
qw422016.N().S(`</a></p>
`)
//line views/auth.qtpl:63
//line views/auth.qtpl:67
}
//line views/auth.qtpl:63
//line views/auth.qtpl:67
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
}
//line views/auth.qtpl:67
func WriteLoginHTML(qq422016 qtio422016.Writer) {
//line views/auth.qtpl:67
//line views/auth.qtpl:71
func WriteLoginHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:71
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:67
StreamLoginHTML(qw422016)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
StreamLoginHTML(qw422016, lc)
//line views/auth.qtpl:71
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
}
//line views/auth.qtpl:67
func LoginHTML() string {
//line views/auth.qtpl:67
//line views/auth.qtpl:71
func LoginHTML(lc *l18n.Localizer) string {
//line views/auth.qtpl:71
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:67
WriteLoginHTML(qb422016)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
WriteLoginHTML(qb422016, lc)
//line views/auth.qtpl:71
qs422016 := string(qb422016.B)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:67
//line views/auth.qtpl:71
return qs422016
//line views/auth.qtpl:67
//line views/auth.qtpl:71
}
// Telegram auth widget was requested by Yogurt. As you can see, we don't offer user administrators control over it. Of course we don't.
//line views/auth.qtpl:70
func streamtelegramWidgetHTML(qw422016 *qt422016.Writer) {
//line views/auth.qtpl:70
//line views/auth.qtpl:74
func streamtelegramWidgetHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:74
qw422016.N().S(`
`)
//line views/auth.qtpl:71
//line views/auth.qtpl:75
if cfg.TelegramEnabled {
//line views/auth.qtpl:71
//line views/auth.qtpl:75
qw422016.N().S(`
<p class="telegram-notice">You can log in using Telegram. It only works if you have set your @username in Telegram and this username is free on this wiki.</p>
<p class="telegram-notice">`)
//line views/auth.qtpl:76
qw422016.E().S(lc.Get("auth.telegram_tip"))
//line views/auth.qtpl:76
qw422016.N().S(`</p>
<script async src="https://telegram.org/js/telegram-widget.js?15" data-telegram-login="`)
//line views/auth.qtpl:73
//line views/auth.qtpl:77
qw422016.E().S(cfg.TelegramBotName)
//line views/auth.qtpl:73
//line views/auth.qtpl:77
qw422016.N().S(`" data-size="medium" data-userpic="false" data-auth-url="`)
//line views/auth.qtpl:73
//line views/auth.qtpl:77
qw422016.E().S(cfg.URL)
//line views/auth.qtpl:73
//line views/auth.qtpl:77
qw422016.N().S(`/telegram-login"></script>
`)
//line views/auth.qtpl:74
//line views/auth.qtpl:78
}
//line views/auth.qtpl:74
//line views/auth.qtpl:78
qw422016.N().S(`
`)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
}
//line views/auth.qtpl:75
func writetelegramWidgetHTML(qq422016 qtio422016.Writer) {
//line views/auth.qtpl:75
//line views/auth.qtpl:79
func writetelegramWidgetHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:79
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:75
streamtelegramWidgetHTML(qw422016)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
streamtelegramWidgetHTML(qw422016, lc)
//line views/auth.qtpl:79
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
}
//line views/auth.qtpl:75
func telegramWidgetHTML() string {
//line views/auth.qtpl:75
//line views/auth.qtpl:79
func telegramWidgetHTML(lc *l18n.Localizer) string {
//line views/auth.qtpl:79
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:75
writetelegramWidgetHTML(qb422016)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
writetelegramWidgetHTML(qb422016, lc)
//line views/auth.qtpl:79
qs422016 := string(qb422016.B)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:75
//line views/auth.qtpl:79
return qs422016
//line views/auth.qtpl:75
//line views/auth.qtpl:79
}
//line views/auth.qtpl:77
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
//line views/auth.qtpl:77
//line views/auth.qtpl:81
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string, lc *l18n.Localizer) {
//line views/auth.qtpl:81
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:81
//line views/auth.qtpl:85
switch err {
//line views/auth.qtpl:82
case "unknown username":
//line views/auth.qtpl:82
qw422016.N().S(`
<p class="error">Unknown username.</p>
`)
//line views/auth.qtpl:84
case "wrong password":
//line views/auth.qtpl:84
qw422016.N().S(`
<p class="error">Wrong password.</p>
`)
//line views/auth.qtpl:86
default:
case "unknown username":
//line views/auth.qtpl:86
qw422016.N().S(`
<p class="error">`)
//line views/auth.qtpl:87
qw422016.E().S(err)
qw422016.E().S(lc.Get("auth.error_username"))
//line views/auth.qtpl:87
qw422016.N().S(`</p>
`)
//line views/auth.qtpl:88
}
case "wrong password":
//line views/auth.qtpl:88
qw422016.N().S(`
<p class="error">`)
//line views/auth.qtpl:89
qw422016.E().S(lc.Get("auth.error_password"))
//line views/auth.qtpl:89
qw422016.N().S(`</p>
`)
//line views/auth.qtpl:90
default:
//line views/auth.qtpl:90
qw422016.N().S(`
<p class="error">`)
//line views/auth.qtpl:91
qw422016.E().S(err)
//line views/auth.qtpl:91
qw422016.N().S(`</p>
`)
//line views/auth.qtpl:92
}
//line views/auth.qtpl:92
qw422016.N().S(`
<p><a href="/login"> Try again</a></p>
<p><a href="/login"> `)
//line views/auth.qtpl:93
qw422016.E().S(lc.Get("auth.try_again"))
//line views/auth.qtpl:93
qw422016.N().S(`</a></p>
</section>
</main>
</div>
`)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
}
//line views/auth.qtpl:93
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
//line views/auth.qtpl:93
//line views/auth.qtpl:97
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string, lc *l18n.Localizer) {
//line views/auth.qtpl:97
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:93
StreamLoginErrorHTML(qw422016, err)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
StreamLoginErrorHTML(qw422016, err, lc)
//line views/auth.qtpl:97
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
}
//line views/auth.qtpl:93
func LoginErrorHTML(err string) string {
//line views/auth.qtpl:93
//line views/auth.qtpl:97
func LoginErrorHTML(err string, lc *l18n.Localizer) string {
//line views/auth.qtpl:97
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:93
WriteLoginErrorHTML(qb422016, err)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
WriteLoginErrorHTML(qb422016, err, lc)
//line views/auth.qtpl:97
qs422016 := string(qb422016.B)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:93
//line views/auth.qtpl:97
return qs422016
//line views/auth.qtpl:93
//line views/auth.qtpl:97
}
//line views/auth.qtpl:95
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
//line views/auth.qtpl:95
//line views/auth.qtpl:99
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool, lc *l18n.Localizer) {
//line views/auth.qtpl:99
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:99
//line views/auth.qtpl:103
if can {
//line views/auth.qtpl:99
qw422016.N().S(`
<h1>Log out?</h1>
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
<p><a href="/">Cancel</a></p>
`)
//line views/auth.qtpl:103
qw422016.N().S(`
<h1>`)
//line views/auth.qtpl:104
qw422016.E().S(lc.Get("auth.logout_header"))
//line views/auth.qtpl:104
qw422016.N().S(`</h1>
<p><a href="/logout-confirm"><strong>`)
//line views/auth.qtpl:105
qw422016.E().S(lc.Get("auth.logout_button"))
//line views/auth.qtpl:105
qw422016.N().S(`</strong></a></p>
<p><a href="/">`)
//line views/auth.qtpl:106
qw422016.E().S(lc.Get("ui.cancel"))
//line views/auth.qtpl:106
qw422016.N().S(`</a></p>
`)
//line views/auth.qtpl:107
} else {
//line views/auth.qtpl:103
//line views/auth.qtpl:107
qw422016.N().S(`
<p>You cannot log out because you are not logged in.</p>
<p><a href="/login">Login</a></p>
<p><a href="/login"> Home</a></p>
<p>`)
//line views/auth.qtpl:108
qw422016.E().S(lc.Get("auth.logout_anon"))
//line views/auth.qtpl:108
qw422016.N().S(`</p>
<p><a href="/login">`)
//line views/auth.qtpl:109
qw422016.E().S(lc.Get("auth.login_title"))
//line views/auth.qtpl:109
qw422016.N().S(`</a></p>
<p><a href="/"> `)
//line views/auth.qtpl:110
qw422016.E().S(lc.Get("auth.go_home"))
//line views/auth.qtpl:110
qw422016.N().S(`</a></p>
`)
//line views/auth.qtpl:107
//line views/auth.qtpl:111
}
//line views/auth.qtpl:107
//line views/auth.qtpl:111
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
}
//line views/auth.qtpl:111
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
//line views/auth.qtpl:111
//line views/auth.qtpl:115
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool, lc *l18n.Localizer) {
//line views/auth.qtpl:115
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:111
StreamLogoutHTML(qw422016, can)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
StreamLogoutHTML(qw422016, can, lc)
//line views/auth.qtpl:115
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
}
//line views/auth.qtpl:111
func LogoutHTML(can bool) string {
//line views/auth.qtpl:111
//line views/auth.qtpl:115
func LogoutHTML(can bool, lc *l18n.Localizer) string {
//line views/auth.qtpl:115
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:111
WriteLogoutHTML(qb422016, can)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
WriteLogoutHTML(qb422016, can, lc)
//line views/auth.qtpl:115
qs422016 := string(qb422016.B)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:111
//line views/auth.qtpl:115
return qs422016
//line views/auth.qtpl:111
//line views/auth.qtpl:115
}
//line views/auth.qtpl:113
func StreamLockHTML(qw422016 *qt422016.Writer) {
//line views/auth.qtpl:113
//line views/auth.qtpl:117
func StreamLockHTML(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:117
qw422016.N().S(`
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🔒 Locked</title>
<title>🔒 `)
//line views/auth.qtpl:123
qw422016.E().S(lc.Get("auth.lock_title"))
//line views/auth.qtpl:123
qw422016.N().S(`</title>
<link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/style.css">
</head>
@ -414,53 +535,69 @@ func StreamLockHTML(qw422016 *qt422016.Writer) {
<main class="locked-notice">
<section class="locked-notice__message">
<p class="locked-notice__lock">🔒</p>
<h1 class="locked-notice__title">Locked</h1>
<h1 class="locked-notice__title">`)
//line views/auth.qtpl:131
qw422016.E().S(lc.Get("auth.lock_title"))
//line views/auth.qtpl:131
qw422016.N().S(`</h1>
<form class="locked-notice__login-form" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<label for="login-form__username">Username</label>
<label for="login-form__username">`)
//line views/auth.qtpl:133
qw422016.E().S(lc.Get("auth.username"))
//line views/auth.qtpl:133
qw422016.N().S(`</label>
<br>
<input type="text" required autofocus id="login-form__username" name="username" autocomplete="username">
<br>
<label for="login-form__password">Password</label>
<label for="login-form__password">`)
//line views/auth.qtpl:137
qw422016.E().S(lc.Get("auth.password"))
//line views/auth.qtpl:137
qw422016.N().S(`</label>
<br>
<input type="password" required name="password" autocomplete="current-password">
<br>
<input class="btn" type="submit" value="Log in">
<button class="btn" type="submit" value="Log in">`)
//line views/auth.qtpl:141
qw422016.E().S(lc.Get("auth.login_button"))
//line views/auth.qtpl:141
qw422016.N().S(`</button>
</form>
`)
//line views/auth.qtpl:139
streamtelegramWidgetHTML(qw422016)
//line views/auth.qtpl:139
//line views/auth.qtpl:143
streamtelegramWidgetHTML(qw422016, lc)
//line views/auth.qtpl:143
qw422016.N().S(`
</section>
</main>
</body>
</html>
`)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
}
//line views/auth.qtpl:144
func WriteLockHTML(qq422016 qtio422016.Writer) {
//line views/auth.qtpl:144
//line views/auth.qtpl:148
func WriteLockHTML(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/auth.qtpl:148
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:144
StreamLockHTML(qw422016)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
StreamLockHTML(qw422016, lc)
//line views/auth.qtpl:148
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
}
//line views/auth.qtpl:144
func LockHTML() string {
//line views/auth.qtpl:144
//line views/auth.qtpl:148
func LockHTML(lc *l18n.Localizer) string {
//line views/auth.qtpl:148
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:144
WriteLockHTML(qb422016)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
WriteLockHTML(qb422016, lc)
//line views/auth.qtpl:148
qs422016 := string(qb422016.B)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:144
//line views/auth.qtpl:148
return qs422016
//line views/auth.qtpl:144
//line views/auth.qtpl:148
}

View File

@ -3,6 +3,7 @@
{% import "time" %}
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/history" %}
@ -10,6 +11,7 @@
{% func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) %}
{% code
lc := l18n.FromRequest(rq)
text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash)
if err != nil {
text = err.Error()
@ -18,20 +20,20 @@ if err != nil {
<div class="layout">
<main class="main-width">
<article>
<h1>Diff {%s= beautifulLink(h.Name) %} at {%s hash %}</h1>
<h1>{%s= lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.Name), "rev": hash}) %}</h1>
<pre class="codeblock"><code>{%s text %}</code></pre>
</article>
</main>
</div>
{% endfunc %}
{% func RecentChangesHTML(n int) %}
{% func RecentChangesHTML(n int, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width recent-changes">
<h1>Recent Changes</h1>
<h1>{%s lc.Get("ui.recent_heading") %}</h1>
<nav class="recent-changes__count">
See
{%s lc.Get("ui.recent_count_pre") %}
{% for i, m := range []int{20, 50, 100} %}
{% if i > 0 %}
<span aria-hidden="true">|</span>
@ -42,10 +44,10 @@ if err != nil {
<a href="/recent-changes/{%d m %}">{%d m %}</a>
{% endif %}
{% endfor %}
recent changes
{%s lc.Get("ui.recent_count_post") %}
</nav>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">{%s= lc.Get("ui.recent_subscribe", &l18n.Replacements{"rss": "<a href=\"/recent-changes-rss\">RSS</a>", "atom": "<a href=\"/recent-changes-atom\">Atom</a>", "json": fmt.Sprintf("<a href=\"/recent-changes-json\">%s</a>", lc.Get("ui.recent_subscribe_json"))}) %}</p>
{% comment %}
Here I am, willing to add some accessibility using ARIA. Turns out,
@ -61,7 +63,7 @@ if err != nil {
%}
<section class="recent-changes__list" role="feed">
{% if len(changes) == 0 %}
<p>Could not find any recent changes.</p>
<p>{%s lc.Get("ui.recent_empty") %}</p>
{% else %}
{% for i, entry := range changes %}
@ -80,7 +82,7 @@ if err != nil {
{% endfor %}
{% endif %}
{%s= helpTopicBadgeHTML("en", "recent_changes") %}
{%s= helpTopicBadgeHTML(lc.Locale, "recent_changes") %}
</section>
</main>
</div>
@ -109,11 +111,11 @@ if err != nil {
</div>
{% endfunc %}
{% func HistoryHTML(rq *http.Request, hyphaName, list string) %}
{% func HistoryHTML(rq *http.Request, hyphaName, list string, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<article class="history">
<h1>History of {%s= beautifulLink(hyphaName) %}</h1>
<h1>{%s= fmt.Sprintf(lc.Get("ui.history_title"), beautifulLink(hyphaName)) %}</h1>
{%s= list %}
</article>
</main>

View File

@ -17,416 +17,436 @@ import "time"
import "github.com/bouncepaw/mycorrhiza/cfg"
//line views/history.qtpl:6
import "github.com/bouncepaw/mycorrhiza/user"
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/history.qtpl:7
import "github.com/bouncepaw/mycorrhiza/hyphae"
import "github.com/bouncepaw/mycorrhiza/user"
//line views/history.qtpl:8
import "github.com/bouncepaw/mycorrhiza/hyphae"
//line views/history.qtpl:9
import "github.com/bouncepaw/mycorrhiza/history"
//line views/history.qtpl:11
//line views/history.qtpl:12
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/history.qtpl:11
//line views/history.qtpl:12
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/history.qtpl:11
//line views/history.qtpl:12
func StreamPrimitiveDiffHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) {
//line views/history.qtpl:11
//line views/history.qtpl:12
qw422016.N().S(`
`)
//line views/history.qtpl:13
//line views/history.qtpl:14
lc := l18n.FromRequest(rq)
text, err := history.PrimitiveDiffAtRevision(h.TextPartPath(), hash)
if err != nil {
text = err.Error()
}
//line views/history.qtpl:17
//line views/history.qtpl:19
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<article>
<h1>Diff `)
//line views/history.qtpl:21
qw422016.N().S(beautifulLink(h.Name))
//line views/history.qtpl:21
qw422016.N().S(` at `)
//line views/history.qtpl:21
qw422016.E().S(hash)
//line views/history.qtpl:21
<h1>`)
//line views/history.qtpl:23
qw422016.N().S(lc.Get("ui.diff_title", &l18n.Replacements{"name": beautifulLink(h.Name), "rev": hash}))
//line views/history.qtpl:23
qw422016.N().S(`</h1>
<pre class="codeblock"><code>`)
//line views/history.qtpl:22
//line views/history.qtpl:24
qw422016.E().S(text)
//line views/history.qtpl:22
//line views/history.qtpl:24
qw422016.N().S(`</code></pre>
</article>
</main>
</div>
`)
//line views/history.qtpl:26
//line views/history.qtpl:28
}
//line views/history.qtpl:26
//line views/history.qtpl:28
func WritePrimitiveDiffHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) {
//line views/history.qtpl:26
//line views/history.qtpl:28
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/history.qtpl:26
//line views/history.qtpl:28
StreamPrimitiveDiffHTML(qw422016, rq, h, u, hash)
//line views/history.qtpl:26
//line views/history.qtpl:28
qt422016.ReleaseWriter(qw422016)
//line views/history.qtpl:26
//line views/history.qtpl:28
}
//line views/history.qtpl:26
//line views/history.qtpl:28
func PrimitiveDiffHTML(rq *http.Request, h *hyphae.Hypha, u *user.User, hash string) string {
//line views/history.qtpl:26
//line views/history.qtpl:28
qb422016 := qt422016.AcquireByteBuffer()
//line views/history.qtpl:26
//line views/history.qtpl:28
WritePrimitiveDiffHTML(qb422016, rq, h, u, hash)
//line views/history.qtpl:26
//line views/history.qtpl:28
qs422016 := string(qb422016.B)
//line views/history.qtpl:26
//line views/history.qtpl:28
qt422016.ReleaseByteBuffer(qb422016)
//line views/history.qtpl:26
//line views/history.qtpl:28
return qs422016
//line views/history.qtpl:26
//line views/history.qtpl:28
}
//line views/history.qtpl:28
func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int) {
//line views/history.qtpl:28
//line views/history.qtpl:30
func StreamRecentChangesHTML(qw422016 *qt422016.Writer, n int, lc *l18n.Localizer) {
//line views/history.qtpl:30
qw422016.N().S(`
<div class="layout">
<main class="main-width recent-changes">
<h1>Recent Changes</h1>
<h1>`)
//line views/history.qtpl:33
qw422016.E().S(lc.Get("ui.recent_heading"))
//line views/history.qtpl:33
qw422016.N().S(`</h1>
<nav class="recent-changes__count">
See
`)
//line views/history.qtpl:36
qw422016.E().S(lc.Get("ui.recent_count_pre"))
//line views/history.qtpl:36
qw422016.N().S(`
`)
//line views/history.qtpl:35
//line views/history.qtpl:37
for i, m := range []int{20, 50, 100} {
//line views/history.qtpl:35
//line views/history.qtpl:37
qw422016.N().S(`
`)
//line views/history.qtpl:36
//line views/history.qtpl:38
if i > 0 {
//line views/history.qtpl:36
//line views/history.qtpl:38
qw422016.N().S(`
<span aria-hidden="true">|</span>
`)
//line views/history.qtpl:38
//line views/history.qtpl:40
}
//line views/history.qtpl:38
//line views/history.qtpl:40
qw422016.N().S(`
`)
//line views/history.qtpl:39
//line views/history.qtpl:41
if m == n {
//line views/history.qtpl:39
//line views/history.qtpl:41
qw422016.N().S(`
<b>`)
//line views/history.qtpl:40
//line views/history.qtpl:42
qw422016.N().D(m)
//line views/history.qtpl:40
//line views/history.qtpl:42
qw422016.N().S(`</b>
`)
//line views/history.qtpl:41
//line views/history.qtpl:43
} else {
//line views/history.qtpl:41
//line views/history.qtpl:43
qw422016.N().S(`
<a href="/recent-changes/`)
//line views/history.qtpl:42
//line views/history.qtpl:44
qw422016.N().D(m)
//line views/history.qtpl:42
//line views/history.qtpl:44
qw422016.N().S(`">`)
//line views/history.qtpl:42
//line views/history.qtpl:44
qw422016.N().D(m)
//line views/history.qtpl:42
//line views/history.qtpl:44
qw422016.N().S(`</a>
`)
//line views/history.qtpl:43
//line views/history.qtpl:45
}
//line views/history.qtpl:43
//line views/history.qtpl:45
qw422016.N().S(`
`)
//line views/history.qtpl:44
//line views/history.qtpl:46
}
//line views/history.qtpl:44
//line views/history.qtpl:46
qw422016.N().S(`
`)
//line views/history.qtpl:47
qw422016.E().S(lc.Get("ui.recent_count_post"))
//line views/history.qtpl:47
qw422016.N().S(`
recent changes
</nav>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">Subscribe via <a href="/recent-changes-rss">RSS</a>, <a href="/recent-changes-atom">Atom</a> or <a href="/recent-changes-json">JSON feed</a>.</p>
<p><img class="icon" width="20" height="20" src="/static/icon/feed.svg">`)
//line views/history.qtpl:50
qw422016.N().S(lc.Get("ui.recent_subscribe", &l18n.Replacements{"rss": "<a href=\"/recent-changes-rss\">RSS</a>", "atom": "<a href=\"/recent-changes-atom\">Atom</a>", "json": fmt.Sprintf("<a href=\"/recent-changes-json\">%s</a>", lc.Get("ui.recent_subscribe_json"))}))
//line views/history.qtpl:50
qw422016.N().S(`</p>
`)
//line views/history.qtpl:55
//line views/history.qtpl:57
qw422016.N().S(`
`)
//line views/history.qtpl:58
//line views/history.qtpl:60
changes := history.RecentChanges(n)
var year, day int
var month time.Month
//line views/history.qtpl:61
//line views/history.qtpl:63
qw422016.N().S(`
<section class="recent-changes__list" role="feed">
`)
//line views/history.qtpl:63
//line views/history.qtpl:65
if len(changes) == 0 {
//line views/history.qtpl:63
//line views/history.qtpl:65
qw422016.N().S(`
<p>Could not find any recent changes.</p>
<p>`)
//line views/history.qtpl:66
qw422016.E().S(lc.Get("ui.recent_empty"))
//line views/history.qtpl:66
qw422016.N().S(`</p>
`)
//line views/history.qtpl:65
//line views/history.qtpl:67
} else {
//line views/history.qtpl:65
//line views/history.qtpl:67
qw422016.N().S(`
`)
//line views/history.qtpl:66
//line views/history.qtpl:68
for i, entry := range changes {
//line views/history.qtpl:66
//line views/history.qtpl:68
qw422016.N().S(`
`)
//line views/history.qtpl:68
//line views/history.qtpl:70
y, m, d := entry.Time.UTC().Date()
//line views/history.qtpl:68
//line views/history.qtpl:70
qw422016.N().S(`
`)
//line views/history.qtpl:69
//line views/history.qtpl:71
if d != day || m != month || y != year {
//line views/history.qtpl:69
//line views/history.qtpl:71
qw422016.N().S(`
<h2 class="recent-changes__heading">
`)
//line views/history.qtpl:71
//line views/history.qtpl:73
qw422016.E().S(fmt.Sprintf("%04d-%02d-%02d", y, m, d))
//line views/history.qtpl:71
//line views/history.qtpl:73
qw422016.N().S(`
</h2>
`)
//line views/history.qtpl:73
//line views/history.qtpl:75
year, month, day = y, m, d
//line views/history.qtpl:73
//line views/history.qtpl:75
qw422016.N().S(`
`)
//line views/history.qtpl:74
//line views/history.qtpl:76
}
//line views/history.qtpl:74
//line views/history.qtpl:76
qw422016.N().S(`
<div class="recent-changes__entry" role="article"
aria-setsize="`)
//line views/history.qtpl:77
//line views/history.qtpl:79
qw422016.N().D(n)
//line views/history.qtpl:77
//line views/history.qtpl:79
qw422016.N().S(`" aria-posinset="`)
//line views/history.qtpl:77
//line views/history.qtpl:79
qw422016.N().D(i)
//line views/history.qtpl:77
//line views/history.qtpl:79
qw422016.N().S(`">
`)
//line views/history.qtpl:78
//line views/history.qtpl:80
qw422016.N().S(recentChangesEntry(entry))
//line views/history.qtpl:78
//line views/history.qtpl:80
qw422016.N().S(`
</div>
`)
//line views/history.qtpl:81
//line views/history.qtpl:83
}
//line views/history.qtpl:81
//line views/history.qtpl:83
qw422016.N().S(`
`)
//line views/history.qtpl:82
//line views/history.qtpl:84
}
//line views/history.qtpl:82
//line views/history.qtpl:84
qw422016.N().S(`
`)
//line views/history.qtpl:83
qw422016.N().S(helpTopicBadgeHTML("en", "recent_changes"))
//line views/history.qtpl:83
//line views/history.qtpl:85
qw422016.N().S(helpTopicBadgeHTML(lc.Locale, "recent_changes"))
//line views/history.qtpl:85
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/history.qtpl:87
//line views/history.qtpl:89
}
//line views/history.qtpl:87
func WriteRecentChangesHTML(qq422016 qtio422016.Writer, n int) {
//line views/history.qtpl:87
//line views/history.qtpl:89
func WriteRecentChangesHTML(qq422016 qtio422016.Writer, n int, lc *l18n.Localizer) {
//line views/history.qtpl:89
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/history.qtpl:87
StreamRecentChangesHTML(qw422016, n)
//line views/history.qtpl:87
//line views/history.qtpl:89
StreamRecentChangesHTML(qw422016, n, lc)
//line views/history.qtpl:89
qt422016.ReleaseWriter(qw422016)
//line views/history.qtpl:87
//line views/history.qtpl:89
}
//line views/history.qtpl:87
func RecentChangesHTML(n int) string {
//line views/history.qtpl:87
//line views/history.qtpl:89
func RecentChangesHTML(n int, lc *l18n.Localizer) string {
//line views/history.qtpl:89
qb422016 := qt422016.AcquireByteBuffer()
//line views/history.qtpl:87
WriteRecentChangesHTML(qb422016, n)
//line views/history.qtpl:87
//line views/history.qtpl:89
WriteRecentChangesHTML(qb422016, n, lc)
//line views/history.qtpl:89
qs422016 := string(qb422016.B)
//line views/history.qtpl:87
//line views/history.qtpl:89
qt422016.ReleaseByteBuffer(qb422016)
//line views/history.qtpl:87
//line views/history.qtpl:89
return qs422016
//line views/history.qtpl:87
//line views/history.qtpl:89
}
//line views/history.qtpl:89
//line views/history.qtpl:91
func streamrecentChangesEntry(qw422016 *qt422016.Writer, rev history.Revision) {
//line views/history.qtpl:89
//line views/history.qtpl:91
qw422016.N().S(`
<div>
<time class="recent-changes__entry__time">
`)
//line views/history.qtpl:92
//line views/history.qtpl:94
qw422016.E().S(rev.Time.UTC().Format("15:04 UTC"))
//line views/history.qtpl:92
//line views/history.qtpl:94
qw422016.N().S(`
</time>
<span class="recent-changes__entry__message">`)
//line views/history.qtpl:94
//line views/history.qtpl:96
qw422016.E().S(rev.Hash)
//line views/history.qtpl:94
//line views/history.qtpl:96
qw422016.N().S(`</span>
`)
//line views/history.qtpl:96
//line views/history.qtpl:98
if rev.Username != "anon" {
//line views/history.qtpl:96
//line views/history.qtpl:98
qw422016.N().S(`
<span class="recent-changes__entry__author">
&mdash; <a href="/hypha/`)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.E().S(cfg.UserHypha)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.N().S(`/`)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.E().S(rev.Username)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.N().S(`" rel="author">`)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.E().S(rev.Username)
//line views/history.qtpl:98
//line views/history.qtpl:100
qw422016.N().S(`</a>
</span>
`)
//line views/history.qtpl:100
//line views/history.qtpl:102
}
//line views/history.qtpl:100
//line views/history.qtpl:102
qw422016.N().S(`
</div>
<div>
<span class="recent-changes__entry__links">
`)
//line views/history.qtpl:104
//line views/history.qtpl:106
qw422016.N().S(rev.HyphaeLinksHTML())
//line views/history.qtpl:104
//line views/history.qtpl:106
qw422016.N().S(`
</span>
<span class="recent-changes__entry__message">
`)
//line views/history.qtpl:107
//line views/history.qtpl:109
qw422016.E().S(rev.Message)
//line views/history.qtpl:107
//line views/history.qtpl:109
qw422016.N().S(`
</span>
</div>
`)
//line views/history.qtpl:110
//line views/history.qtpl:112
}
//line views/history.qtpl:110
//line views/history.qtpl:112
func writerecentChangesEntry(qq422016 qtio422016.Writer, rev history.Revision) {
//line views/history.qtpl:110
//line views/history.qtpl:112
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/history.qtpl:110
//line views/history.qtpl:112
streamrecentChangesEntry(qw422016, rev)
//line views/history.qtpl:110
//line views/history.qtpl:112
qt422016.ReleaseWriter(qw422016)
//line views/history.qtpl:110
//line views/history.qtpl:112
}
//line views/history.qtpl:110
//line views/history.qtpl:112
func recentChangesEntry(rev history.Revision) string {
//line views/history.qtpl:110
//line views/history.qtpl:112
qb422016 := qt422016.AcquireByteBuffer()
//line views/history.qtpl:110
//line views/history.qtpl:112
writerecentChangesEntry(qb422016, rev)
//line views/history.qtpl:110
//line views/history.qtpl:112
qs422016 := string(qb422016.B)
//line views/history.qtpl:110
//line views/history.qtpl:112
qt422016.ReleaseByteBuffer(qb422016)
//line views/history.qtpl:110
//line views/history.qtpl:112
return qs422016
//line views/history.qtpl:110
//line views/history.qtpl:112
}
//line views/history.qtpl:112
func StreamHistoryHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string) {
//line views/history.qtpl:112
//line views/history.qtpl:114
func StreamHistoryHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) {
//line views/history.qtpl:114
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<article class="history">
<h1>History of `)
//line views/history.qtpl:116
qw422016.N().S(beautifulLink(hyphaName))
//line views/history.qtpl:116
<h1>`)
//line views/history.qtpl:118
qw422016.N().S(fmt.Sprintf(lc.Get("ui.history_title"), beautifulLink(hyphaName)))
//line views/history.qtpl:118
qw422016.N().S(`</h1>
`)
//line views/history.qtpl:117
//line views/history.qtpl:119
qw422016.N().S(list)
//line views/history.qtpl:117
//line views/history.qtpl:119
qw422016.N().S(`
</article>
</main>
</div>
`)
//line views/history.qtpl:121
//line views/history.qtpl:123
}
//line views/history.qtpl:121
func WriteHistoryHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string) {
//line views/history.qtpl:121
//line views/history.qtpl:123
func WriteHistoryHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, list string, lc *l18n.Localizer) {
//line views/history.qtpl:123
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/history.qtpl:121
StreamHistoryHTML(qw422016, rq, hyphaName, list)
//line views/history.qtpl:121
//line views/history.qtpl:123
StreamHistoryHTML(qw422016, rq, hyphaName, list, lc)
//line views/history.qtpl:123
qt422016.ReleaseWriter(qw422016)
//line views/history.qtpl:121
//line views/history.qtpl:123
}
//line views/history.qtpl:121
func HistoryHTML(rq *http.Request, hyphaName, list string) string {
//line views/history.qtpl:121
//line views/history.qtpl:123
func HistoryHTML(rq *http.Request, hyphaName, list string, lc *l18n.Localizer) string {
//line views/history.qtpl:123
qb422016 := qt422016.AcquireByteBuffer()
//line views/history.qtpl:121
WriteHistoryHTML(qb422016, rq, hyphaName, list)
//line views/history.qtpl:121
//line views/history.qtpl:123
WriteHistoryHTML(qb422016, rq, hyphaName, list, lc)
//line views/history.qtpl:123
qs422016 := string(qb422016.B)
//line views/history.qtpl:121
//line views/history.qtpl:123
qt422016.ReleaseByteBuffer(qb422016)
//line views/history.qtpl:121
//line views/history.qtpl:123
return qs422016
//line views/history.qtpl:121
//line views/history.qtpl:123
}

View File

@ -3,41 +3,43 @@
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
{% func beautifulLink(hyphaName string) %}
<a href="/hypha/{%s= hyphaName %}">{%s util.BeautifulName(hyphaName) %}</a>{% endfunc %}
{% func beautifulLink(hyphaName string) %}<a href="/hypha/{%s= hyphaName %}">{%s util.BeautifulName(hyphaName) %}</a>{% endfunc %}
{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) %}
{% func mycoLink(lc *l18n.Localizer) %}<a href="/help/{%s lc.Locale %}/mycomarkup" class="shy-link">{%s lc.Get("ui.notexist_write_myco") %}</a>{% endfunc %}
{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) %}
<section class="non-existent-hypha">
<h2 class="non-existent-hypha__title">This hypha does not exist</h2>
<h2 class="non-existent-hypha__title">{%s lc.Get("ui.notexist_heading") %}</h2>
{% if cfg.UseAuth && u.Group == "anon" %}
<p>You are not authorized to create new hyphae. Here is what you can do:</p>
<p>{%s lc.Get("ui.notexist_norights") %}</p>
<ul>
<li><a href="/login">Log in to your account, if you have one</a></li>
{% if cfg.AllowRegistration %}<li><a href="/register">Register a new account</a></li>{% endif %}
<li><a href="/login">{%s lc.Get("ui.notexist_login") %}</a></li>
{% if cfg.AllowRegistration %}<li><a href="/register">{%s lc.Get("ui.notexist_register") %}</a></li>{% endif %}
</ul>
{% else %}
<div class="non-existent-hypha__ways">
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">📝 Write a text</h3>
<p>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.</p>
<p>Make sure to follow this wiki&apos;s writing conventions if there are any.</p>
<a class="btn btn_accent stick-to-bottom" href="/edit/{%s h.Name %}">Create</a>
<h3 class="non-existent-hypha__subtitle">📝 {%s lc.Get("ui.notexist_write") %}</h3>
<p>{%s= lc.Get("ui.notexist_write_tip1", &l18n.Replacements{"myco": mycoLink(lc)}) %}</p>
<p>{%s lc.Get("ui.notexist_write_tip2") %}</p>
<a class="btn btn_accent stick-to-bottom" href="/edit/{%s h.Name %}">{%s lc.Get("ui.notexist_write_button") %}</a>
</section>
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">🖼 Upload a media</h3>
<p>Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.</p>
<h3 class="non-existent-hypha__subtitle">🖼 {%s lc.Get("ui.notexist_media") %}</h3>
<p>{%s lc.Get("ui.notexist_media_tip1") %}</p>
<form action="/upload-binary/{%s h.Name %}"
method="post" enctype="multipart/form-data"
class="upload-binary">
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<input type="submit" class="btn stick-to-bottom" value="Upload">
<button type="submit" class="btn stick-to-bottom" value="Upload">{%s lc.Get("ui.attach_upload")%}</button>
</form>
</section>
</div>
@ -73,7 +75,9 @@
</h1>
{% endfunc %}
{% func AttachmentHTML(h *hyphae.Hypha) %}
{% func AttachmentHTMLRaw(h *hyphae.Hypha) %}{%= AttachmentHTML(h, l18n.New("en", "en")) %}{% endfunc %}
{% func AttachmentHTML(h *hyphae.Hypha, lc *l18n.Localizer) %}
{% switch filepath.Ext(h.BinaryPath) %}
{% case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico" %}
@ -85,7 +89,7 @@
<div class="binary-container binary-container_with-video">
<video controls>
<source src="/binary/{%s= h.Name %}"/>
<p>Your browser does not support video. <a href="/binary/{%s= h.Name %}">Download video</a></p>
<p>{%s lc.Get("ui.media_novideo") %} <a href="/binary/{%s= h.Name %}">{%s lc.Get("ui.media_novideo_link") %}</a></p>
</video>
</div>
@ -93,13 +97,13 @@
<div class="binary-container binary-container_with-audio">
<audio controls>
<source src="/binary/{%s= h.Name %}"/>
<p>Your browser does not support audio. <a href="/binary/{%s= h.Name %}">Download audio</a></p>
<p>{%s lc.Get("ui.media_noaudio") %} <a href="/binary/{%s= h.Name %}">{%s lc.Get("ui.media_noaudio_link") %}</a></p>
</audio>
</div>
{% default %}
<div class="binary-container binary-container_with-nothing">
<p><a href="/binary/{%s= h.Name %}">Download media</a></p>
<p><a href="/binary/{%s= h.Name %}">{%s lc.Get("ui.media_download") %}</a></p>
</div>
{% endswitch %}
{% endfunc %}

View File

@ -17,29 +17,31 @@ import "github.com/bouncepaw/mycorrhiza/cfg"
import "github.com/bouncepaw/mycorrhiza/hyphae"
//line views/hypha.qtpl:6
import "github.com/bouncepaw/mycorrhiza/user"
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/hypha.qtpl:7
import "github.com/bouncepaw/mycorrhiza/user"
//line views/hypha.qtpl:8
import "github.com/bouncepaw/mycorrhiza/util"
//line views/hypha.qtpl:9
//line views/hypha.qtpl:10
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/hypha.qtpl:9
//line views/hypha.qtpl:10
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/hypha.qtpl:9
//line views/hypha.qtpl:10
func streambeautifulLink(qw422016 *qt422016.Writer, hyphaName string) {
//line views/hypha.qtpl:9
qw422016.N().S(`
<a href="/hypha/`)
//line views/hypha.qtpl:10
qw422016.N().S(`<a href="/hypha/`)
//line views/hypha.qtpl:10
qw422016.N().S(hyphaName)
//line views/hypha.qtpl:10
@ -78,299 +80,437 @@ func beautifulLink(hyphaName string) string {
}
//line views/hypha.qtpl:12
func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u *user.User) {
func streammycoLink(qw422016 *qt422016.Writer, lc *l18n.Localizer) {
//line views/hypha.qtpl:12
qw422016.N().S(`<a href="/help/`)
//line views/hypha.qtpl:12
qw422016.E().S(lc.Locale)
//line views/hypha.qtpl:12
qw422016.N().S(`/mycomarkup" class="shy-link">`)
//line views/hypha.qtpl:12
qw422016.E().S(lc.Get("ui.notexist_write_myco"))
//line views/hypha.qtpl:12
qw422016.N().S(`</a>`)
//line views/hypha.qtpl:12
}
//line views/hypha.qtpl:12
func writemycoLink(qq422016 qtio422016.Writer, lc *l18n.Localizer) {
//line views/hypha.qtpl:12
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/hypha.qtpl:12
streammycoLink(qw422016, lc)
//line views/hypha.qtpl:12
qt422016.ReleaseWriter(qw422016)
//line views/hypha.qtpl:12
}
//line views/hypha.qtpl:12
func mycoLink(lc *l18n.Localizer) string {
//line views/hypha.qtpl:12
qb422016 := qt422016.AcquireByteBuffer()
//line views/hypha.qtpl:12
writemycoLink(qb422016, lc)
//line views/hypha.qtpl:12
qs422016 := string(qb422016.B)
//line views/hypha.qtpl:12
qt422016.ReleaseByteBuffer(qb422016)
//line views/hypha.qtpl:12
return qs422016
//line views/hypha.qtpl:12
}
//line views/hypha.qtpl:14
func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) {
//line views/hypha.qtpl:14
qw422016.N().S(`
<section class="non-existent-hypha">
<h2 class="non-existent-hypha__title">This hypha does not exist</h2>
<h2 class="non-existent-hypha__title">`)
//line views/hypha.qtpl:16
qw422016.E().S(lc.Get("ui.notexist_heading"))
//line views/hypha.qtpl:16
qw422016.N().S(`</h2>
`)
//line views/hypha.qtpl:15
//line views/hypha.qtpl:17
if cfg.UseAuth && u.Group == "anon" {
//line views/hypha.qtpl:15
//line views/hypha.qtpl:17
qw422016.N().S(`
<p>You are not authorized to create new hyphae. Here is what you can do:</p>
<p>`)
//line views/hypha.qtpl:18
qw422016.E().S(lc.Get("ui.notexist_norights"))
//line views/hypha.qtpl:18
qw422016.N().S(`</p>
<ul>
<li><a href="/login">Log in to your account, if you have one</a></li>
<li><a href="/login">`)
//line views/hypha.qtpl:20
qw422016.E().S(lc.Get("ui.notexist_login"))
//line views/hypha.qtpl:20
qw422016.N().S(`</a></li>
`)
//line views/hypha.qtpl:19
//line views/hypha.qtpl:21
if cfg.AllowRegistration {
//line views/hypha.qtpl:19
qw422016.N().S(`<li><a href="/register">Register a new account</a></li>`)
//line views/hypha.qtpl:19
//line views/hypha.qtpl:21
qw422016.N().S(`<li><a href="/register">`)
//line views/hypha.qtpl:21
qw422016.E().S(lc.Get("ui.notexist_register"))
//line views/hypha.qtpl:21
qw422016.N().S(`</a></li>`)
//line views/hypha.qtpl:21
}
//line views/hypha.qtpl:19
//line views/hypha.qtpl:21
qw422016.N().S(`
</ul>
`)
//line views/hypha.qtpl:21
//line views/hypha.qtpl:23
} else {
//line views/hypha.qtpl:21
//line views/hypha.qtpl:23
qw422016.N().S(`
<div class="non-existent-hypha__ways">
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">📝 Write a text</h3>
<p>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.</p>
<p>Make sure to follow this wiki&apos;s writing conventions if there are any.</p>
<h3 class="non-existent-hypha__subtitle">📝 `)
//line views/hypha.qtpl:27
qw422016.E().S(lc.Get("ui.notexist_write"))
//line views/hypha.qtpl:27
qw422016.N().S(`</h3>
<p>`)
//line views/hypha.qtpl:28
qw422016.N().S(lc.Get("ui.notexist_write_tip1", &l18n.Replacements{"myco": mycoLink(lc)}))
//line views/hypha.qtpl:28
qw422016.N().S(`</p>
<p>`)
//line views/hypha.qtpl:29
qw422016.E().S(lc.Get("ui.notexist_write_tip2"))
//line views/hypha.qtpl:29
qw422016.N().S(`</p>
<a class="btn btn_accent stick-to-bottom" href="/edit/`)
//line views/hypha.qtpl:28
//line views/hypha.qtpl:30
qw422016.E().S(h.Name)
//line views/hypha.qtpl:28
qw422016.N().S(`">Create</a>
//line views/hypha.qtpl:30
qw422016.N().S(`">`)
//line views/hypha.qtpl:30
qw422016.E().S(lc.Get("ui.notexist_write_button"))
//line views/hypha.qtpl:30
qw422016.N().S(`</a>
</section>
<section class="non-existent-hypha__way">
<h3 class="non-existent-hypha__subtitle">🖼 Upload a media</h3>
<p>Upload a picture, a video or an audio. Most common formats can be accessed from the browser, others can be only downloaded afterwards. You can write a description for the media later.</p>
<h3 class="non-existent-hypha__subtitle">🖼 `)
//line views/hypha.qtpl:34
qw422016.E().S(lc.Get("ui.notexist_media"))
//line views/hypha.qtpl:34
qw422016.N().S(`</h3>
<p>`)
//line views/hypha.qtpl:35
qw422016.E().S(lc.Get("ui.notexist_media_tip1"))
//line views/hypha.qtpl:35
qw422016.N().S(`</p>
<form action="/upload-binary/`)
//line views/hypha.qtpl:34
//line views/hypha.qtpl:36
qw422016.E().S(h.Name)
//line views/hypha.qtpl:34
//line views/hypha.qtpl:36
qw422016.N().S(`"
method="post" enctype="multipart/form-data"
class="upload-binary">
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<input type="submit" class="btn stick-to-bottom" value="Upload">
<button type="submit" class="btn stick-to-bottom" value="Upload">`)
//line views/hypha.qtpl:42
qw422016.E().S(lc.Get("ui.attach_upload"))
//line views/hypha.qtpl:42
qw422016.N().S(`</button>
</form>
</section>
</div>
`)
//line views/hypha.qtpl:44
//line views/hypha.qtpl:46
}
//line views/hypha.qtpl:44
//line views/hypha.qtpl:46
qw422016.N().S(`
</section>
`)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
}
//line views/hypha.qtpl:46
func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h *hyphae.Hypha, u *user.User) {
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
func writenonExistentHyphaNotice(qq422016 qtio422016.Writer, h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) {
//line views/hypha.qtpl:48
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/hypha.qtpl:46
streamnonExistentHyphaNotice(qw422016, h, u)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
streamnonExistentHyphaNotice(qw422016, h, u, lc)
//line views/hypha.qtpl:48
qt422016.ReleaseWriter(qw422016)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
}
//line views/hypha.qtpl:46
func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) string {
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User, lc *l18n.Localizer) string {
//line views/hypha.qtpl:48
qb422016 := qt422016.AcquireByteBuffer()
//line views/hypha.qtpl:46
writenonExistentHyphaNotice(qb422016, h, u)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
writenonExistentHyphaNotice(qb422016, h, u, lc)
//line views/hypha.qtpl:48
qs422016 := string(qb422016.B)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
qt422016.ReleaseByteBuffer(qb422016)
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
return qs422016
//line views/hypha.qtpl:46
//line views/hypha.qtpl:48
}
//line views/hypha.qtpl:48
//line views/hypha.qtpl:50
func StreamNaviTitleHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:48
//line views/hypha.qtpl:50
qw422016.N().S(`
`)
//line views/hypha.qtpl:50
//line views/hypha.qtpl:52
var (
prevAcc = "/hypha/"
parts = strings.Split(h.Name, "/")
)
//line views/hypha.qtpl:54
//line views/hypha.qtpl:56
qw422016.N().S(`
<h1 class="navi-title">
`)
//line views/hypha.qtpl:56
//line views/hypha.qtpl:58
qw422016.N().S(`<a href="/hypha/`)
//line views/hypha.qtpl:57
//line views/hypha.qtpl:59
qw422016.E().S(cfg.HomeHypha)
//line views/hypha.qtpl:57
//line views/hypha.qtpl:59
qw422016.N().S(`">`)
//line views/hypha.qtpl:58
//line views/hypha.qtpl:60
qw422016.N().S(cfg.NaviTitleIcon)
//line views/hypha.qtpl:58
//line views/hypha.qtpl:60
qw422016.N().S(`<span aria-hidden="true" class="navi-title__colon">:</span></a>`)
//line views/hypha.qtpl:62
//line views/hypha.qtpl:64
for i, part := range parts {
//line views/hypha.qtpl:63
//line views/hypha.qtpl:65
if i > 0 {
//line views/hypha.qtpl:63
//line views/hypha.qtpl:65
qw422016.N().S(`<span aria-hidden="true" class="navi-title__separator">/</span>`)
//line views/hypha.qtpl:65
//line views/hypha.qtpl:67
}
//line views/hypha.qtpl:65
//line views/hypha.qtpl:67
qw422016.N().S(`<a href="`)
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
qw422016.E().S(prevAcc + part)
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
qw422016.N().S(`" rel="`)
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
if i == len(parts)-1 {
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
qw422016.N().S(`bookmark`)
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
} else {
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
qw422016.N().S(`up`)
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
}
//line views/hypha.qtpl:67
//line views/hypha.qtpl:69
qw422016.N().S(`">`)
//line views/hypha.qtpl:68
qw422016.N().S(util.BeautifulName(part))
//line views/hypha.qtpl:68
qw422016.N().S(`</a>`)
//line views/hypha.qtpl:70
qw422016.N().S(util.BeautifulName(part))
//line views/hypha.qtpl:70
qw422016.N().S(`</a>`)
//line views/hypha.qtpl:72
prevAcc += part + "/"
//line views/hypha.qtpl:71
//line views/hypha.qtpl:73
}
//line views/hypha.qtpl:72
//line views/hypha.qtpl:74
qw422016.N().S(`
</h1>
`)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
}
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
func WriteNaviTitleHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
StreamNaviTitleHTML(qw422016, h)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
qt422016.ReleaseWriter(qw422016)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
}
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
func NaviTitleHTML(h *hyphae.Hypha) string {
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
qb422016 := qt422016.AcquireByteBuffer()
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
WriteNaviTitleHTML(qb422016, h)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
qs422016 := string(qb422016.B)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
qt422016.ReleaseByteBuffer(qb422016)
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
return qs422016
//line views/hypha.qtpl:74
//line views/hypha.qtpl:76
}
//line views/hypha.qtpl:76
func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:76
//line views/hypha.qtpl:78
func StreamAttachmentHTMLRaw(qw422016 *qt422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:78
StreamAttachmentHTML(qw422016, h, l18n.New("en", "en"))
//line views/hypha.qtpl:78
}
//line views/hypha.qtpl:78
func WriteAttachmentHTMLRaw(qq422016 qtio422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:78
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/hypha.qtpl:78
StreamAttachmentHTMLRaw(qw422016, h)
//line views/hypha.qtpl:78
qt422016.ReleaseWriter(qw422016)
//line views/hypha.qtpl:78
}
//line views/hypha.qtpl:78
func AttachmentHTMLRaw(h *hyphae.Hypha) string {
//line views/hypha.qtpl:78
qb422016 := qt422016.AcquireByteBuffer()
//line views/hypha.qtpl:78
WriteAttachmentHTMLRaw(qb422016, h)
//line views/hypha.qtpl:78
qs422016 := string(qb422016.B)
//line views/hypha.qtpl:78
qt422016.ReleaseByteBuffer(qb422016)
//line views/hypha.qtpl:78
return qs422016
//line views/hypha.qtpl:78
}
//line views/hypha.qtpl:80
func StreamAttachmentHTML(qw422016 *qt422016.Writer, h *hyphae.Hypha, lc *l18n.Localizer) {
//line views/hypha.qtpl:80
qw422016.N().S(`
`)
//line views/hypha.qtpl:77
//line views/hypha.qtpl:81
switch filepath.Ext(h.BinaryPath) {
//line views/hypha.qtpl:79
//line views/hypha.qtpl:83
case ".jpg", ".gif", ".png", ".webp", ".svg", ".ico":
//line views/hypha.qtpl:79
//line views/hypha.qtpl:83
qw422016.N().S(`
<div class="binary-container binary-container_with-img">
<a href="/binary/`)
//line views/hypha.qtpl:81
//line views/hypha.qtpl:85
qw422016.N().S(h.Name)
//line views/hypha.qtpl:81
//line views/hypha.qtpl:85
qw422016.N().S(`"><img src="/binary/`)
//line views/hypha.qtpl:81
//line views/hypha.qtpl:85
qw422016.N().S(h.Name)
//line views/hypha.qtpl:81
//line views/hypha.qtpl:85
qw422016.N().S(`"/></a>
</div>
`)
//line views/hypha.qtpl:84
//line views/hypha.qtpl:88
case ".ogg", ".webm", ".mp4":
//line views/hypha.qtpl:84
//line views/hypha.qtpl:88
qw422016.N().S(`
<div class="binary-container binary-container_with-video">
<video controls>
<source src="/binary/`)
//line views/hypha.qtpl:87
//line views/hypha.qtpl:91
qw422016.N().S(h.Name)
//line views/hypha.qtpl:87
//line views/hypha.qtpl:91
qw422016.N().S(`"/>
<p>Your browser does not support video. <a href="/binary/`)
//line views/hypha.qtpl:88
<p>`)
//line views/hypha.qtpl:92
qw422016.E().S(lc.Get("ui.media_novideo"))
//line views/hypha.qtpl:92
qw422016.N().S(` <a href="/binary/`)
//line views/hypha.qtpl:92
qw422016.N().S(h.Name)
//line views/hypha.qtpl:88
qw422016.N().S(`">Download video</a></p>
//line views/hypha.qtpl:92
qw422016.N().S(`">`)
//line views/hypha.qtpl:92
qw422016.E().S(lc.Get("ui.media_novideo_link"))
//line views/hypha.qtpl:92
qw422016.N().S(`</a></p>
</video>
</div>
`)
//line views/hypha.qtpl:92
//line views/hypha.qtpl:96
case ".mp3":
//line views/hypha.qtpl:92
//line views/hypha.qtpl:96
qw422016.N().S(`
<div class="binary-container binary-container_with-audio">
<audio controls>
<source src="/binary/`)
//line views/hypha.qtpl:95
//line views/hypha.qtpl:99
qw422016.N().S(h.Name)
//line views/hypha.qtpl:95
//line views/hypha.qtpl:99
qw422016.N().S(`"/>
<p>Your browser does not support audio. <a href="/binary/`)
//line views/hypha.qtpl:96
<p>`)
//line views/hypha.qtpl:100
qw422016.E().S(lc.Get("ui.media_noaudio"))
//line views/hypha.qtpl:100
qw422016.N().S(` <a href="/binary/`)
//line views/hypha.qtpl:100
qw422016.N().S(h.Name)
//line views/hypha.qtpl:96
qw422016.N().S(`">Download audio</a></p>
//line views/hypha.qtpl:100
qw422016.N().S(`">`)
//line views/hypha.qtpl:100
qw422016.E().S(lc.Get("ui.media_noaudio_link"))
//line views/hypha.qtpl:100
qw422016.N().S(`</a></p>
</audio>
</div>
`)
//line views/hypha.qtpl:100
//line views/hypha.qtpl:104
default:
//line views/hypha.qtpl:100
//line views/hypha.qtpl:104
qw422016.N().S(`
<div class="binary-container binary-container_with-nothing">
<p><a href="/binary/`)
//line views/hypha.qtpl:102
//line views/hypha.qtpl:106
qw422016.N().S(h.Name)
//line views/hypha.qtpl:102
qw422016.N().S(`">Download media</a></p>
//line views/hypha.qtpl:106
qw422016.N().S(`">`)
//line views/hypha.qtpl:106
qw422016.E().S(lc.Get("ui.media_download"))
//line views/hypha.qtpl:106
qw422016.N().S(`</a></p>
</div>
`)
//line views/hypha.qtpl:104
//line views/hypha.qtpl:108
}
//line views/hypha.qtpl:104
//line views/hypha.qtpl:108
qw422016.N().S(`
`)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
}
//line views/hypha.qtpl:105
func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha) {
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
func WriteAttachmentHTML(qq422016 qtio422016.Writer, h *hyphae.Hypha, lc *l18n.Localizer) {
//line views/hypha.qtpl:109
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/hypha.qtpl:105
StreamAttachmentHTML(qw422016, h)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
StreamAttachmentHTML(qw422016, h, lc)
//line views/hypha.qtpl:109
qt422016.ReleaseWriter(qw422016)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
}
//line views/hypha.qtpl:105
func AttachmentHTML(h *hyphae.Hypha) string {
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
func AttachmentHTML(h *hyphae.Hypha, lc *l18n.Localizer) string {
//line views/hypha.qtpl:109
qb422016 := qt422016.AcquireByteBuffer()
//line views/hypha.qtpl:105
WriteAttachmentHTML(qb422016, h)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
WriteAttachmentHTML(qb422016, h, lc)
//line views/hypha.qtpl:109
qs422016 := string(qb422016.B)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
qt422016.ReleaseByteBuffer(qb422016)
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
return qs422016
//line views/hypha.qtpl:105
//line views/hypha.qtpl:109
}

View File

@ -1,44 +1,55 @@
{% import "fmt" %}
{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
{% code
lc := l18n.FromRequest(rq)
%}
{%= modalBegin(
"delete-confirm",
hyphaName,
"",
"Delete "+beautifulLink(hyphaName)+"?") %}
{%= modalReallyWant(hyphaName, "unattach") %}
<p>In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.</p>
{%= modalEnd(hyphaName, true) %}
fmt.Sprintf(lc.Get("ui.ask_delete"), beautifulLink(hyphaName))) %}
{%= modalReallyWant(hyphaName, lc.Get("ui.ask_delete_verb"), lc) %}
<p>{%s lc.Get("ui.ask_delete_tip") %}</p>
{%= modalEnd(hyphaName, true, lc) %}
{% endfunc %}
{% func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
{% code
lc := l18n.FromRequest(rq)
%}
{%= modalBegin(
"unattach",
hyphaName,
"",
"Unattach "+beautifulLink(hyphaName)+"?") %}
{%= modalReallyWant(hyphaName, "unattach") %}
{%= modalEnd(hyphaName, true) %}
fmt.Sprintf(lc.Get("ui.ask_unattach"), beautifulLink(hyphaName))) %}
{%= modalReallyWant(hyphaName, lc.Get("ui.ask_unattach_verb"), lc) %}
{%= modalEnd(hyphaName, true, lc) %}
{% endfunc %}
{% func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) %}
{% code
lc := l18n.FromRequest(rq)
%}
{%= modalBegin(
"rename-confirm",
hyphaName,
` method="post" enctype="multipart/form-data"`,
"Rename "+beautifulLink(hyphaName)) %}
<label for="new-name">New name</label>
fmt.Sprintf(lc.Get("ui.ask_rename"), beautifulLink(hyphaName))) %}
<label for="new-name">{%s lc.Get("ui.rename_to") %}</label>
<input type="text" value="{%s hyphaName %}" required autofocus id="new-name" name="new-name"/>
<input type="checkbox" id="recursive" name="recursive" value="true" checked/>
<label for="recursive">Rename subhyphae too</label>
<label for="recursive">{%s lc.Get("ui.rename_recurse") %}</label>
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
{%= modalEnd(hyphaName, false) %}
<p>{%s lc.Get("ui.rename_tip") %}</p>
{%= modalEnd(hyphaName, false, lc) %}
{% endfunc %}
{% func modalReallyWant(hyphaName, verb string) %}
<p class="modal__confirmation-msg">Do you really want to {%s verb %} hypha <em>{%s hyphaName %}</em>?</p>
{% func modalReallyWant(hyphaName, verb string, lc *l18n.Localizer) %}
<p class="modal__confirmation-msg">{%s= lc.Get("ui.ask_really", &l18n.Replacements{"verb": verb, "name": fmt.Sprintf("<em>%s</em>", hyphaName)}) %}</p>
{% endfunc %}
{% func modalBegin(path, hyphaName, formAttrs, legend string) %}
@ -49,9 +60,9 @@
<legend class="modal__title">{%s= legend %}</legend>
{% endfunc %}
{% func modalEnd(hyphaName string, shouldFocusOnConfirm bool) %}
<input type="submit" value="Confirm" class="btn" {% if shouldFocusOnConfirm %}autofocus{% endif %}>
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">Cancel</a>
{% func modalEnd(hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) %}
<button type="submit" value="Confirm" class="btn" {% if shouldFocusOnConfirm %}autofocus{% endif %}>{%s lc.Get("ui.confirm") %}</button>
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">{%s lc.Get("ui.cancel") %}</a>
</fieldset>
</form>
</main>

View File

@ -5,333 +5,377 @@
package views
//line views/modal.qtpl:1
import "fmt"
//line views/modal.qtpl:2
import "net/http"
//line views/modal.qtpl:3
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/modal.qtpl:5
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/modal.qtpl:3
//line views/modal.qtpl:5
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/modal.qtpl:3
//line views/modal.qtpl:5
func StreamDeleteAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:3
//line views/modal.qtpl:5
qw422016.N().S(`
`)
//line views/modal.qtpl:4
streammodalBegin(qw422016,
"delete-confirm",
hyphaName,
"",
"Delete "+beautifulLink(hyphaName)+"?")
//line views/modal.qtpl:7
lc := l18n.FromRequest(rq)
//line views/modal.qtpl:8
qw422016.N().S(`
`)
//line views/modal.qtpl:9
streammodalReallyWant(qw422016, hyphaName, "unattach")
//line views/modal.qtpl:9
qw422016.N().S(`
<p>In this version of Mycorrhiza Wiki you cannot undelete a deleted hypha but the history can still be accessed.</p>
`)
//line views/modal.qtpl:11
streammodalEnd(qw422016, hyphaName, true)
//line views/modal.qtpl:11
streammodalBegin(qw422016,
"delete-confirm",
hyphaName,
"",
fmt.Sprintf(lc.Get("ui.ask_delete"), beautifulLink(hyphaName)))
//line views/modal.qtpl:13
qw422016.N().S(`
`)
//line views/modal.qtpl:12
}
//line views/modal.qtpl:12
func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:12
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:12
StreamDeleteAskHTML(qw422016, rq, hyphaName, isOld)
//line views/modal.qtpl:12
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:12
}
//line views/modal.qtpl:12
func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
//line views/modal.qtpl:12
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:12
WriteDeleteAskHTML(qb422016, rq, hyphaName, isOld)
//line views/modal.qtpl:12
qs422016 := string(qb422016.B)
//line views/modal.qtpl:12
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:12
return qs422016
//line views/modal.qtpl:12
}
//line views/modal.qtpl:14
func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
streammodalReallyWant(qw422016, hyphaName, lc.Get("ui.ask_delete_verb"), lc)
//line views/modal.qtpl:14
qw422016.N().S(`
`)
<p>`)
//line views/modal.qtpl:15
qw422016.E().S(lc.Get("ui.ask_delete_tip"))
//line views/modal.qtpl:15
qw422016.N().S(`</p>
`)
//line views/modal.qtpl:16
streammodalEnd(qw422016, hyphaName, true, lc)
//line views/modal.qtpl:16
qw422016.N().S(`
`)
//line views/modal.qtpl:17
}
//line views/modal.qtpl:17
func WriteDeleteAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:17
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:17
StreamDeleteAskHTML(qw422016, rq, hyphaName, isOld)
//line views/modal.qtpl:17
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:17
}
//line views/modal.qtpl:17
func DeleteAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
//line views/modal.qtpl:17
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:17
WriteDeleteAskHTML(qb422016, rq, hyphaName, isOld)
//line views/modal.qtpl:17
qs422016 := string(qb422016.B)
//line views/modal.qtpl:17
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:17
return qs422016
//line views/modal.qtpl:17
}
//line views/modal.qtpl:19
func StreamUnattachAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:19
qw422016.N().S(`
`)
//line views/modal.qtpl:21
lc := l18n.FromRequest(rq)
//line views/modal.qtpl:22
qw422016.N().S(`
`)
//line views/modal.qtpl:23
streammodalBegin(qw422016,
"unattach",
hyphaName,
"",
"Unattach "+beautifulLink(hyphaName)+"?")
//line views/modal.qtpl:19
fmt.Sprintf(lc.Get("ui.ask_unattach"), beautifulLink(hyphaName)))
//line views/modal.qtpl:27
qw422016.N().S(`
`)
//line views/modal.qtpl:20
streammodalReallyWant(qw422016, hyphaName, "unattach")
//line views/modal.qtpl:20
//line views/modal.qtpl:28
streammodalReallyWant(qw422016, hyphaName, lc.Get("ui.ask_unattach_verb"), lc)
//line views/modal.qtpl:28
qw422016.N().S(`
`)
//line views/modal.qtpl:21
streammodalEnd(qw422016, hyphaName, true)
//line views/modal.qtpl:21
//line views/modal.qtpl:29
streammodalEnd(qw422016, hyphaName, true, lc)
//line views/modal.qtpl:29
qw422016.N().S(`
`)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
}
//line views/modal.qtpl:22
//line views/modal.qtpl:30
func WriteUnattachAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:22
//line views/modal.qtpl:30
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
StreamUnattachAskHTML(qw422016, rq, hyphaName, isOld)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
}
//line views/modal.qtpl:22
//line views/modal.qtpl:30
func UnattachAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
//line views/modal.qtpl:22
//line views/modal.qtpl:30
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:22
//line views/modal.qtpl:30
WriteUnattachAskHTML(qb422016, rq, hyphaName, isOld)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
qs422016 := string(qb422016.B)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:22
//line views/modal.qtpl:30
return qs422016
//line views/modal.qtpl:22
//line views/modal.qtpl:30
}
//line views/modal.qtpl:24
//line views/modal.qtpl:32
func StreamRenameAskHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:24
//line views/modal.qtpl:32
qw422016.N().S(`
`)
//line views/modal.qtpl:25
//line views/modal.qtpl:34
lc := l18n.FromRequest(rq)
//line views/modal.qtpl:35
qw422016.N().S(`
`)
//line views/modal.qtpl:36
streammodalBegin(qw422016,
"rename-confirm",
hyphaName,
` method="post" enctype="multipart/form-data"`,
"Rename "+beautifulLink(hyphaName))
//line views/modal.qtpl:29
fmt.Sprintf(lc.Get("ui.ask_rename"), beautifulLink(hyphaName)))
//line views/modal.qtpl:40
qw422016.N().S(`
<label for="new-name">New name</label>
<label for="new-name">`)
//line views/modal.qtpl:41
qw422016.E().S(lc.Get("ui.rename_to"))
//line views/modal.qtpl:41
qw422016.N().S(`</label>
<input type="text" value="`)
//line views/modal.qtpl:31
//line views/modal.qtpl:42
qw422016.E().S(hyphaName)
//line views/modal.qtpl:31
//line views/modal.qtpl:42
qw422016.N().S(`" required autofocus id="new-name" name="new-name"/>
<input type="checkbox" id="recursive" name="recursive" value="true" checked/>
<label for="recursive">Rename subhyphae too</label>
<label for="recursive">`)
//line views/modal.qtpl:45
qw422016.E().S(lc.Get("ui.rename_recurse"))
//line views/modal.qtpl:45
qw422016.N().S(`</label>
<p>If you rename this hypha, all incoming links and all relative outcoming links will break. You will also lose all history for the new name. Rename carefully.</p>
<p>`)
//line views/modal.qtpl:47
qw422016.E().S(lc.Get("ui.rename_tip"))
//line views/modal.qtpl:47
qw422016.N().S(`</p>
`)
//line views/modal.qtpl:37
streammodalEnd(qw422016, hyphaName, false)
//line views/modal.qtpl:37
//line views/modal.qtpl:48
streammodalEnd(qw422016, hyphaName, false, lc)
//line views/modal.qtpl:48
qw422016.N().S(`
`)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
}
//line views/modal.qtpl:38
//line views/modal.qtpl:49
func WriteRenameAskHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName string, isOld bool) {
//line views/modal.qtpl:38
//line views/modal.qtpl:49
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
StreamRenameAskHTML(qw422016, rq, hyphaName, isOld)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
}
//line views/modal.qtpl:38
//line views/modal.qtpl:49
func RenameAskHTML(rq *http.Request, hyphaName string, isOld bool) string {
//line views/modal.qtpl:38
//line views/modal.qtpl:49
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:38
//line views/modal.qtpl:49
WriteRenameAskHTML(qb422016, rq, hyphaName, isOld)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
qs422016 := string(qb422016.B)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:38
//line views/modal.qtpl:49
return qs422016
//line views/modal.qtpl:38
//line views/modal.qtpl:49
}
//line views/modal.qtpl:40
func streammodalReallyWant(qw422016 *qt422016.Writer, hyphaName, verb string) {
//line views/modal.qtpl:40
//line views/modal.qtpl:51
func streammodalReallyWant(qw422016 *qt422016.Writer, hyphaName, verb string, lc *l18n.Localizer) {
//line views/modal.qtpl:51
qw422016.N().S(`
<p class="modal__confirmation-msg">Do you really want to `)
//line views/modal.qtpl:41
qw422016.E().S(verb)
//line views/modal.qtpl:41
qw422016.N().S(` hypha <em>`)
//line views/modal.qtpl:41
qw422016.E().S(hyphaName)
//line views/modal.qtpl:41
qw422016.N().S(`</em>?</p>
<p class="modal__confirmation-msg">`)
//line views/modal.qtpl:52
qw422016.N().S(lc.Get("ui.ask_really", &l18n.Replacements{"verb": verb, "name": fmt.Sprintf("<em>%s</em>", hyphaName)}))
//line views/modal.qtpl:52
qw422016.N().S(`</p>
`)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
}
//line views/modal.qtpl:42
func writemodalReallyWant(qq422016 qtio422016.Writer, hyphaName, verb string) {
//line views/modal.qtpl:42
//line views/modal.qtpl:53
func writemodalReallyWant(qq422016 qtio422016.Writer, hyphaName, verb string, lc *l18n.Localizer) {
//line views/modal.qtpl:53
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:42
streammodalReallyWant(qw422016, hyphaName, verb)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
streammodalReallyWant(qw422016, hyphaName, verb, lc)
//line views/modal.qtpl:53
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
}
//line views/modal.qtpl:42
func modalReallyWant(hyphaName, verb string) string {
//line views/modal.qtpl:42
//line views/modal.qtpl:53
func modalReallyWant(hyphaName, verb string, lc *l18n.Localizer) string {
//line views/modal.qtpl:53
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:42
writemodalReallyWant(qb422016, hyphaName, verb)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
writemodalReallyWant(qb422016, hyphaName, verb, lc)
//line views/modal.qtpl:53
qs422016 := string(qb422016.B)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:42
//line views/modal.qtpl:53
return qs422016
//line views/modal.qtpl:42
//line views/modal.qtpl:53
}
//line views/modal.qtpl:44
//line views/modal.qtpl:55
func streammodalBegin(qw422016 *qt422016.Writer, path, hyphaName, formAttrs, legend string) {
//line views/modal.qtpl:44
//line views/modal.qtpl:55
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<form class="modal" action="/`)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.E().S(path)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.N().S(`/`)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.E().S(hyphaName)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.N().S(`"`)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.N().S(formAttrs)
//line views/modal.qtpl:47
//line views/modal.qtpl:58
qw422016.N().S(`>
<fieldset class="modal__fieldset">
<legend class="modal__title">`)
//line views/modal.qtpl:49
//line views/modal.qtpl:60
qw422016.N().S(legend)
//line views/modal.qtpl:49
//line views/modal.qtpl:60
qw422016.N().S(`</legend>
`)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
}
//line views/modal.qtpl:50
//line views/modal.qtpl:61
func writemodalBegin(qq422016 qtio422016.Writer, path, hyphaName, formAttrs, legend string) {
//line views/modal.qtpl:50
//line views/modal.qtpl:61
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
streammodalBegin(qw422016, path, hyphaName, formAttrs, legend)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
}
//line views/modal.qtpl:50
//line views/modal.qtpl:61
func modalBegin(path, hyphaName, formAttrs, legend string) string {
//line views/modal.qtpl:50
//line views/modal.qtpl:61
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:50
//line views/modal.qtpl:61
writemodalBegin(qb422016, path, hyphaName, formAttrs, legend)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
qs422016 := string(qb422016.B)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:50
//line views/modal.qtpl:61
return qs422016
//line views/modal.qtpl:50
//line views/modal.qtpl:61
}
//line views/modal.qtpl:52
func streammodalEnd(qw422016 *qt422016.Writer, hyphaName string, shouldFocusOnConfirm bool) {
//line views/modal.qtpl:52
//line views/modal.qtpl:63
func streammodalEnd(qw422016 *qt422016.Writer, hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) {
//line views/modal.qtpl:63
qw422016.N().S(`
<input type="submit" value="Confirm" class="btn" `)
//line views/modal.qtpl:53
<button type="submit" value="Confirm" class="btn" `)
//line views/modal.qtpl:64
if shouldFocusOnConfirm {
//line views/modal.qtpl:53
//line views/modal.qtpl:64
qw422016.N().S(`autofocus`)
//line views/modal.qtpl:53
//line views/modal.qtpl:64
}
//line views/modal.qtpl:53
qw422016.N().S(`>
//line views/modal.qtpl:64
qw422016.N().S(`>`)
//line views/modal.qtpl:64
qw422016.E().S(lc.Get("ui.confirm"))
//line views/modal.qtpl:64
qw422016.N().S(`</button>
<a href="/hypha/`)
//line views/modal.qtpl:54
//line views/modal.qtpl:65
qw422016.E().S(hyphaName)
//line views/modal.qtpl:54
qw422016.N().S(`" class="btn btn_weak">Cancel</a>
//line views/modal.qtpl:65
qw422016.N().S(`" class="btn btn_weak">`)
//line views/modal.qtpl:65
qw422016.E().S(lc.Get("ui.cancel"))
//line views/modal.qtpl:65
qw422016.N().S(`</a>
</fieldset>
</form>
</main>
</div>
`)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
}
//line views/modal.qtpl:59
func writemodalEnd(qq422016 qtio422016.Writer, hyphaName string, shouldFocusOnConfirm bool) {
//line views/modal.qtpl:59
//line views/modal.qtpl:70
func writemodalEnd(qq422016 qtio422016.Writer, hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) {
//line views/modal.qtpl:70
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/modal.qtpl:59
streammodalEnd(qw422016, hyphaName, shouldFocusOnConfirm)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
streammodalEnd(qw422016, hyphaName, shouldFocusOnConfirm, lc)
//line views/modal.qtpl:70
qt422016.ReleaseWriter(qw422016)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
}
//line views/modal.qtpl:59
func modalEnd(hyphaName string, shouldFocusOnConfirm bool) string {
//line views/modal.qtpl:59
//line views/modal.qtpl:70
func modalEnd(hyphaName string, shouldFocusOnConfirm bool, lc *l18n.Localizer) string {
//line views/modal.qtpl:70
qb422016 := qt422016.AcquireByteBuffer()
//line views/modal.qtpl:59
writemodalEnd(qb422016, hyphaName, shouldFocusOnConfirm)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
writemodalEnd(qb422016, hyphaName, shouldFocusOnConfirm, lc)
//line views/modal.qtpl:70
qs422016 := string(qb422016.B)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
qt422016.ReleaseByteBuffer(qb422016)
//line views/modal.qtpl:59
//line views/modal.qtpl:70
return qs422016
//line views/modal.qtpl:59
//line views/modal.qtpl:70
}

View File

@ -1,37 +1,39 @@
{% import "fmt" %}
{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% func Toolbar(u *user.User) %}
{% func Toolbar(u *user.User, lc *l18n.Localizer) %}
<aside class="edit-toolbar layout-card">
<h2 class="edit-toolbar__title layout-card__title">Markup</h2>
<h2 class="edit-toolbar__title layout-card__title">{%s lc.Get("edit.markup")%}</h2>
<section class="edit-toolbar__buttons">
{% for _, el := range []struct{
class string
onclick string
display string
}{
{"link", "wrapLink()", "[[Link]]"},
{"titlelink", "wrapTitleLink()", "[[Link | Title]]"},
{"heading2", "insertHeading2()", "## Heading"},
{"heading3", "insertHeading3()", "### Heading"},
{"bold", "wrapBold()", "<b>**Bold**</b>"},
{"italic", "wrapItalic()", "<i>//Italic//</i>"},
{"highlighted", "wrapHighlighted()", "<mark>++Highlight++</mark>"},
{"underline", "wrapUnderline()", "<u>__Underline__</u>"},
{"monospace", "wrapMonospace()", "<code>`Monospace`</code>"},
{"lifted", "wrapLifted()", "<sup>^^Supertext^^</sup>"}, // inconsistent names: lifted, supertext. How cute ❤️
{"lowered", "wrapLowered()", "<sub>,,Subtext,,</sub>"},
{"strikethrough", "wrapStrikethrough()", "<strike>~~Strikethrough~~</strike>"},
{"rocket", "insertRocket()", "=> Rocketlink"},
{"xcl", "insertXcl()", "<= Transclusion"},
{"link", "wrapLink()", fmt.Sprintf("[[%s]]", lc.Get("edit.link"))},
{"titlelink", "wrapTitleLink()", fmt.Sprintf("[[%s | %s]]", lc.Get("edit.link"), lc.Get("edit.link_title"))},
{"heading2", "insertHeading2()", fmt.Sprintf("## %s", lc.Get("edit.heading"))},
{"heading3", "insertHeading3()", fmt.Sprintf("### %s", lc.Get("edit.heading"))},
{"bold", "wrapBold()", fmt.Sprintf("<b>**%s**</b>", lc.Get("edit.bold"))},
{"italic", "wrapItalic()", fmt.Sprintf("<i>//%s//</i>", lc.Get("edit.italic"))},
{"highlighted", "wrapHighlighted()", fmt.Sprintf("<mark>++%s++</mark>", lc.Get("edit.highlight"))},
{"underline", "wrapUnderline()", fmt.Sprintf("<u>__%s__</u>", lc.Get("edit.underline"))},
{"monospace", "wrapMonospace()", fmt.Sprintf("<code>`%s`</code>", lc.Get("edit.mono"))},
{"lifted", "wrapLifted()", fmt.Sprintf("<sup>^^%s^^</sup>", lc.Get("edit.super"))}, // inconsistent names: lifted, supertext. How cute ❤️
{"lowered", "wrapLowered()", fmt.Sprintf("<sub>,,%s,,</sub>", lc.Get("edit.sub"))},
{"strikethrough", "wrapStrikethrough()", fmt.Sprintf("<strike>~~%s~~</strike>", lc.Get("edit.strike"))},
{"rocket", "insertRocket()", "=> " + lc.Get("edit.rocket")},
{"xcl", "insertXcl()", "<= " + lc.Get("edit.transclude")},
{"img", "insertImgBlock()", "<code>img {}</code>"},
{"table", "insertTableBlock()", "<code>table {}</code>"},
{"hr", "insertHorizontalBar()", "Horizontal bar"},
{"codeblock", "insertCodeblock()", "Code block"},
{"bulletedlist", "insertBulletedList()", "* Bullet list"},
{"numberedlist", "insertNumberedList()", "*. Number list"},
{"hr", "insertHorizontalBar()", lc.Get("edit.hr")},
{"codeblock", "insertCodeblock()", lc.Get("edit.code")},
{"bulletedlist", "insertBulletedList()", "* " + lc.Get("edit.bullets")},
{"numberedlist", "insertNumberedList()", "*. " + lc.Get("edit.numbers")},
} %}
<button
class="btn edit-toolbar__btn edit-toolbar__{%s el.class %}"
@ -40,16 +42,16 @@
</button>
{% endfor %}
</section>
<p class="edit-toolbar__ad"><a href="/help/en/mycomarkup" target="_blank" class="shy-link">Learn more</a> about mycomarkup</p>
<h2 class="edit-toolbar__title layout-card__title">Actions</h2>
<p class="edit-toolbar__ad">{%s= lc.Get("edit.help", &l18n.Replacements{"link": fmt.Sprintf("<a href=\"/help/%s/mycomarkup\" target=\"_blank\" class=\"shy-link\">%s</a>", lc.Locale, lc.Get("edit.help_link"))}) %}</p>
<h2 class="edit-toolbar__title layout-card__title">{%s lc.Get("edit.actions")%}</h2>
<section class="edit-toolbar__buttons">
{% for _, el := range []struct{
class string
onclick string
display string
}{
{"date", "insertDate()", "Insert current date"},
{"time", "insertTimeUTC()", "Insert current time"},
{"date", "insertDate()", lc.Get("edit.date")},
{"time", "insertTimeUTC()", lc.Get("edit.time")},
} %}
<button
class="btn edit-toolbar__btn edit-toolbar__{%s el.class %}"
@ -61,7 +63,7 @@
<button
class="btn edit-toolbar__btn edit-toolbar__user-link"
onclick="insertUserlink()">
Link yourself
{%s lc.Get("edit.selflink") %}
</button>
{% endif %}
</section>
@ -70,47 +72,53 @@
{% endfunc %}
{% func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) %}
{% code
lc := l18n.FromRequest(rq)
%}
<div class="layout">
<main class="main-width edit edit_no-preview">
<h1 class="edit__title">Edit {%s= beautifulLink(hyphaName) %}</h1>
<h1 class="edit__title">{%s= fmt.Sprintf(lc.Get("edit.title"), beautifulLink(hyphaName)) %}</h1>
{%s= warning %}
<form method="post" class="edit-form"
action="/upload-text/{%s hyphaName %}">
<textarea name="text" class="edit-form__textarea" autofocus>{%s textAreaFill %}</textarea>
<br><br>
<label for="text">Describe your changes:</label><br>
<label for="text">{%s lc.Get("edit.tag") %}</label><br>
<input id="text" type="text" name="message" class="edit-form__message">
<br><br>
<input type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">
<input type="submit" name="action" class="btn edit-form__preview" value="Preview">
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">Cancel</a>
<button type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">{%s lc.Get("edit.save") %}</button>
<button type="submit" name="action" class="btn edit-form__preview" value="Preview">{%s lc.Get("edit.preview") %}</button>
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">{%s lc.Get("ui.cancel") %}</a>
</form>
</main>
{%s= Toolbar(user.FromRequest(rq)) %}
{%s= Toolbar(user.FromRequest(rq), lc) %}
</div>
{%= editScripts() %}
{% endfunc %}
{% func PreviewHTML(rq *http.Request, hyphaName, textAreaFill, message, warning string, renderedPage string) %}
{% code
lc := l18n.FromRequest(rq)
%}
<div class="layout">
<main class="main-width edit edit_with-preview">
<h1 class="edit__title">Edit {%s= beautifulLink(hyphaName) %}</h1>
<h1 class="edit__title">{%s= fmt.Sprintf(lc.Get("edit.title"), beautifulLink(hyphaName)) %}</h1>
{%s= warning %}
<form method="post" class="edit-form"
action="/upload-text/{%s hyphaName %}">
<textarea name="text" class="edit-form__textarea" autofocus>{%s textAreaFill %}</textarea>
<br><br>
<label for="text">Describe your changes:</label><br>
<label for="text">{%s lc.Get("edit.tag") %}</label><br>
<input id="text" type="text" name="message" class="edit-form__message" value="{%s message %}">
<br><br>
<input type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">
<input type="submit" name="action" class="btn edit-form__preview" value="Preview">
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">Cancel</a>
<button type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">{%s lc.Get("edit.save") %}</button>
<button type="submit" name="action" class="btn edit-form__preview" value="Preview">{%s lc.Get("edit.preview") %}</button>
<a href="/hypha/{%s hyphaName %}" class="btn btn_weak">{%s lc.Get("ui.cancel") %}</a>
</form>
<p class="warning">Note that the hypha hasn't been saved yet. Here's the preview:</p>
<p class="warning">{%s lc.Get("edit.preview_tip") %}</p>
<article class="edit__preview">{%s= renderedPage %}</article>
</main>
{%s= Toolbar(user.FromRequest(rq)) %}
{%s= Toolbar(user.FromRequest(rq), lc) %}
</div>
{%= editScripts() %}
{% endfunc %}

View File

@ -5,390 +5,460 @@
package views
//line views/mutators.qtpl:1
import "fmt"
//line views/mutators.qtpl:2
import "net/http"
//line views/mutators.qtpl:3
//line views/mutators.qtpl:4
import "github.com/bouncepaw/mycorrhiza/cfg"
//line views/mutators.qtpl:4
import "github.com/bouncepaw/mycorrhiza/user"
//line views/mutators.qtpl:5
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/mutators.qtpl:6
import "github.com/bouncepaw/mycorrhiza/user"
//line views/mutators.qtpl:8
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/mutators.qtpl:6
//line views/mutators.qtpl:8
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/mutators.qtpl:6
func StreamToolbar(qw422016 *qt422016.Writer, u *user.User) {
//line views/mutators.qtpl:6
//line views/mutators.qtpl:8
func StreamToolbar(qw422016 *qt422016.Writer, u *user.User, lc *l18n.Localizer) {
//line views/mutators.qtpl:8
qw422016.N().S(`
<aside class="edit-toolbar layout-card">
<h2 class="edit-toolbar__title layout-card__title">Markup</h2>
<h2 class="edit-toolbar__title layout-card__title">`)
//line views/mutators.qtpl:10
qw422016.E().S(lc.Get("edit.markup"))
//line views/mutators.qtpl:10
qw422016.N().S(`</h2>
<section class="edit-toolbar__buttons">
`)
//line views/mutators.qtpl:10
//line views/mutators.qtpl:12
for _, el := range []struct {
class string
onclick string
display string
}{
{"link", "wrapLink()", "[[Link]]"},
{"titlelink", "wrapTitleLink()", "[[Link | Title]]"},
{"heading2", "insertHeading2()", "## Heading"},
{"heading3", "insertHeading3()", "### Heading"},
{"bold", "wrapBold()", "<b>**Bold**</b>"},
{"italic", "wrapItalic()", "<i>//Italic//</i>"},
{"highlighted", "wrapHighlighted()", "<mark>++Highlight++</mark>"},
{"underline", "wrapUnderline()", "<u>__Underline__</u>"},
{"monospace", "wrapMonospace()", "<code>`Monospace`</code>"},
{"lifted", "wrapLifted()", "<sup>^^Supertext^^</sup>"}, // inconsistent names: lifted, supertext. How cute ❤️
{"lowered", "wrapLowered()", "<sub>,,Subtext,,</sub>"},
{"strikethrough", "wrapStrikethrough()", "<strike>~~Strikethrough~~</strike>"},
{"rocket", "insertRocket()", "=> Rocketlink"},
{"xcl", "insertXcl()", "<= Transclusion"},
{"link", "wrapLink()", fmt.Sprintf("[[%s]]", lc.Get("edit.link"))},
{"titlelink", "wrapTitleLink()", fmt.Sprintf("[[%s | %s]]", lc.Get("edit.link"), lc.Get("edit.link_title"))},
{"heading2", "insertHeading2()", fmt.Sprintf("## %s", lc.Get("edit.heading"))},
{"heading3", "insertHeading3()", fmt.Sprintf("### %s", lc.Get("edit.heading"))},
{"bold", "wrapBold()", fmt.Sprintf("<b>**%s**</b>", lc.Get("edit.bold"))},
{"italic", "wrapItalic()", fmt.Sprintf("<i>//%s//</i>", lc.Get("edit.italic"))},
{"highlighted", "wrapHighlighted()", fmt.Sprintf("<mark>++%s++</mark>", lc.Get("edit.highlight"))},
{"underline", "wrapUnderline()", fmt.Sprintf("<u>__%s__</u>", lc.Get("edit.underline"))},
{"monospace", "wrapMonospace()", fmt.Sprintf("<code>`%s`</code>", lc.Get("edit.mono"))},
{"lifted", "wrapLifted()", fmt.Sprintf("<sup>^^%s^^</sup>", lc.Get("edit.super"))}, // inconsistent names: lifted, supertext. How cute ❤️
{"lowered", "wrapLowered()", fmt.Sprintf("<sub>,,%s,,</sub>", lc.Get("edit.sub"))},
{"strikethrough", "wrapStrikethrough()", fmt.Sprintf("<strike>~~%s~~</strike>", lc.Get("edit.strike"))},
{"rocket", "insertRocket()", "=> " + lc.Get("edit.rocket")},
{"xcl", "insertXcl()", "<= " + lc.Get("edit.transclude")},
{"img", "insertImgBlock()", "<code>img {}</code>"},
{"table", "insertTableBlock()", "<code>table {}</code>"},
{"hr", "insertHorizontalBar()", "Horizontal bar"},
{"codeblock", "insertCodeblock()", "Code block"},
{"bulletedlist", "insertBulletedList()", "* Bullet list"},
{"numberedlist", "insertNumberedList()", "*. Number list"},
{"hr", "insertHorizontalBar()", lc.Get("edit.hr")},
{"codeblock", "insertCodeblock()", lc.Get("edit.code")},
{"bulletedlist", "insertBulletedList()", "* " + lc.Get("edit.bullets")},
{"numberedlist", "insertNumberedList()", "*. " + lc.Get("edit.numbers")},
} {
//line views/mutators.qtpl:35
//line views/mutators.qtpl:37
qw422016.N().S(`
<button
class="btn edit-toolbar__btn edit-toolbar__`)
//line views/mutators.qtpl:37
//line views/mutators.qtpl:39
qw422016.E().S(el.class)
//line views/mutators.qtpl:37
//line views/mutators.qtpl:39
qw422016.N().S(`"
onclick="`)
//line views/mutators.qtpl:38
//line views/mutators.qtpl:40
qw422016.E().S(el.onclick)
//line views/mutators.qtpl:38
//line views/mutators.qtpl:40
qw422016.N().S(`">
`)
//line views/mutators.qtpl:39
//line views/mutators.qtpl:41
qw422016.N().S(el.display)
//line views/mutators.qtpl:39
//line views/mutators.qtpl:41
qw422016.N().S(`
</button>
`)
//line views/mutators.qtpl:41
//line views/mutators.qtpl:43
}
//line views/mutators.qtpl:41
//line views/mutators.qtpl:43
qw422016.N().S(`
</section>
<p class="edit-toolbar__ad"><a href="/help/en/mycomarkup" target="_blank" class="shy-link">Learn more</a> about mycomarkup</p>
<h2 class="edit-toolbar__title layout-card__title">Actions</h2>
<p class="edit-toolbar__ad">`)
//line views/mutators.qtpl:45
qw422016.N().S(lc.Get("edit.help", &l18n.Replacements{"link": fmt.Sprintf("<a href=\"/help/%s/mycomarkup\" target=\"_blank\" class=\"shy-link\">%s</a>", lc.Locale, lc.Get("edit.help_link"))}))
//line views/mutators.qtpl:45
qw422016.N().S(`</p>
<h2 class="edit-toolbar__title layout-card__title">`)
//line views/mutators.qtpl:46
qw422016.E().S(lc.Get("edit.actions"))
//line views/mutators.qtpl:46
qw422016.N().S(`</h2>
<section class="edit-toolbar__buttons">
`)
//line views/mutators.qtpl:46
//line views/mutators.qtpl:48
for _, el := range []struct {
class string
onclick string
display string
}{
{"date", "insertDate()", "Insert current date"},
{"time", "insertTimeUTC()", "Insert current time"},
{"date", "insertDate()", lc.Get("edit.date")},
{"time", "insertTimeUTC()", lc.Get("edit.time")},
} {
//line views/mutators.qtpl:53
//line views/mutators.qtpl:55
qw422016.N().S(`
<button
class="btn edit-toolbar__btn edit-toolbar__`)
//line views/mutators.qtpl:55
//line views/mutators.qtpl:57
qw422016.E().S(el.class)
//line views/mutators.qtpl:55
//line views/mutators.qtpl:57
qw422016.N().S(`"
onclick="`)
//line views/mutators.qtpl:56
//line views/mutators.qtpl:58
qw422016.E().S(el.onclick)
//line views/mutators.qtpl:56
//line views/mutators.qtpl:58
qw422016.N().S(`">
`)
//line views/mutators.qtpl:57
//line views/mutators.qtpl:59
qw422016.N().S(el.display)
//line views/mutators.qtpl:57
//line views/mutators.qtpl:59
qw422016.N().S(`
</button>
`)
//line views/mutators.qtpl:59
//line views/mutators.qtpl:61
}
//line views/mutators.qtpl:59
//line views/mutators.qtpl:61
qw422016.N().S(`
`)
//line views/mutators.qtpl:60
//line views/mutators.qtpl:62
if u.Group != "anon" {
//line views/mutators.qtpl:60
//line views/mutators.qtpl:62
qw422016.N().S(`
<button
class="btn edit-toolbar__btn edit-toolbar__user-link"
onclick="insertUserlink()">
Link yourself
`)
//line views/mutators.qtpl:66
qw422016.E().S(lc.Get("edit.selflink"))
//line views/mutators.qtpl:66
qw422016.N().S(`
</button>
`)
//line views/mutators.qtpl:66
//line views/mutators.qtpl:68
}
//line views/mutators.qtpl:66
//line views/mutators.qtpl:68
qw422016.N().S(`
</section>
</aside>
<script src="/static/toolbar.js"></script>
`)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
}
//line views/mutators.qtpl:70
func WriteToolbar(qq422016 qtio422016.Writer, u *user.User) {
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
func WriteToolbar(qq422016 qtio422016.Writer, u *user.User, lc *l18n.Localizer) {
//line views/mutators.qtpl:72
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/mutators.qtpl:70
StreamToolbar(qw422016, u)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
StreamToolbar(qw422016, u, lc)
//line views/mutators.qtpl:72
qt422016.ReleaseWriter(qw422016)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
}
//line views/mutators.qtpl:70
func Toolbar(u *user.User) string {
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
func Toolbar(u *user.User, lc *l18n.Localizer) string {
//line views/mutators.qtpl:72
qb422016 := qt422016.AcquireByteBuffer()
//line views/mutators.qtpl:70
WriteToolbar(qb422016, u)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
WriteToolbar(qb422016, u, lc)
//line views/mutators.qtpl:72
qs422016 := string(qb422016.B)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
qt422016.ReleaseByteBuffer(qb422016)
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
return qs422016
//line views/mutators.qtpl:70
//line views/mutators.qtpl:72
}
//line views/mutators.qtpl:72
//line views/mutators.qtpl:74
func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) {
//line views/mutators.qtpl:72
//line views/mutators.qtpl:74
qw422016.N().S(`
`)
//line views/mutators.qtpl:76
lc := l18n.FromRequest(rq)
//line views/mutators.qtpl:77
qw422016.N().S(`
<div class="layout">
<main class="main-width edit edit_no-preview">
<h1 class="edit__title">Edit `)
//line views/mutators.qtpl:75
qw422016.N().S(beautifulLink(hyphaName))
//line views/mutators.qtpl:75
<h1 class="edit__title">`)
//line views/mutators.qtpl:80
qw422016.N().S(fmt.Sprintf(lc.Get("edit.title"), beautifulLink(hyphaName)))
//line views/mutators.qtpl:80
qw422016.N().S(`</h1>
`)
//line views/mutators.qtpl:76
//line views/mutators.qtpl:81
qw422016.N().S(warning)
//line views/mutators.qtpl:76
//line views/mutators.qtpl:81
qw422016.N().S(`
<form method="post" class="edit-form"
action="/upload-text/`)
//line views/mutators.qtpl:78
//line views/mutators.qtpl:83
qw422016.E().S(hyphaName)
//line views/mutators.qtpl:78
//line views/mutators.qtpl:83
qw422016.N().S(`">
<textarea name="text" class="edit-form__textarea" autofocus>`)
//line views/mutators.qtpl:79
//line views/mutators.qtpl:84
qw422016.E().S(textAreaFill)
//line views/mutators.qtpl:79
//line views/mutators.qtpl:84
qw422016.N().S(`</textarea>
<br><br>
<label for="text">Describe your changes:</label><br>
<label for="text">`)
//line views/mutators.qtpl:86
qw422016.E().S(lc.Get("edit.tag"))
//line views/mutators.qtpl:86
qw422016.N().S(`</label><br>
<input id="text" type="text" name="message" class="edit-form__message">
<br><br>
<input type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">
<input type="submit" name="action" class="btn edit-form__preview" value="Preview">
<button type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">`)
//line views/mutators.qtpl:89
qw422016.E().S(lc.Get("edit.save"))
//line views/mutators.qtpl:89
qw422016.N().S(`</button>
<button type="submit" name="action" class="btn edit-form__preview" value="Preview">`)
//line views/mutators.qtpl:90
qw422016.E().S(lc.Get("edit.preview"))
//line views/mutators.qtpl:90
qw422016.N().S(`</button>
<a href="/hypha/`)
//line views/mutators.qtpl:86
//line views/mutators.qtpl:91
qw422016.E().S(hyphaName)
//line views/mutators.qtpl:86
qw422016.N().S(`" class="btn btn_weak">Cancel</a>
//line views/mutators.qtpl:91
qw422016.N().S(`" class="btn btn_weak">`)
//line views/mutators.qtpl:91
qw422016.E().S(lc.Get("ui.cancel"))
//line views/mutators.qtpl:91
qw422016.N().S(`</a>
</form>
</main>
`)
//line views/mutators.qtpl:89
qw422016.N().S(Toolbar(user.FromRequest(rq)))
//line views/mutators.qtpl:89
//line views/mutators.qtpl:94
qw422016.N().S(Toolbar(user.FromRequest(rq), lc))
//line views/mutators.qtpl:94
qw422016.N().S(`
</div>
`)
//line views/mutators.qtpl:91
//line views/mutators.qtpl:96
streameditScripts(qw422016)
//line views/mutators.qtpl:91
//line views/mutators.qtpl:96
qw422016.N().S(`
`)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
}
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
func WriteEditHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, warning string) {
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
StreamEditHTML(qw422016, rq, hyphaName, textAreaFill, warning)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
qt422016.ReleaseWriter(qw422016)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
}
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
func EditHTML(rq *http.Request, hyphaName, textAreaFill, warning string) string {
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
qb422016 := qt422016.AcquireByteBuffer()
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
WriteEditHTML(qb422016, rq, hyphaName, textAreaFill, warning)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
qs422016 := string(qb422016.B)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
qt422016.ReleaseByteBuffer(qb422016)
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
return qs422016
//line views/mutators.qtpl:92
//line views/mutators.qtpl:97
}
//line views/mutators.qtpl:94
//line views/mutators.qtpl:99
func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, textAreaFill, message, warning string, renderedPage string) {
//line views/mutators.qtpl:94
//line views/mutators.qtpl:99
qw422016.N().S(`
`)
//line views/mutators.qtpl:101
lc := l18n.FromRequest(rq)
//line views/mutators.qtpl:102
qw422016.N().S(`
<div class="layout">
<main class="main-width edit edit_with-preview">
<h1 class="edit__title">Edit `)
//line views/mutators.qtpl:97
qw422016.N().S(beautifulLink(hyphaName))
//line views/mutators.qtpl:97
<h1 class="edit__title">`)
//line views/mutators.qtpl:105
qw422016.N().S(fmt.Sprintf(lc.Get("edit.title"), beautifulLink(hyphaName)))
//line views/mutators.qtpl:105
qw422016.N().S(`</h1>
`)
//line views/mutators.qtpl:98
//line views/mutators.qtpl:106
qw422016.N().S(warning)
//line views/mutators.qtpl:98
//line views/mutators.qtpl:106
qw422016.N().S(`
<form method="post" class="edit-form"
action="/upload-text/`)
//line views/mutators.qtpl:100
//line views/mutators.qtpl:108
qw422016.E().S(hyphaName)
//line views/mutators.qtpl:100
//line views/mutators.qtpl:108
qw422016.N().S(`">
<textarea name="text" class="edit-form__textarea" autofocus>`)
//line views/mutators.qtpl:101
//line views/mutators.qtpl:109
qw422016.E().S(textAreaFill)
//line views/mutators.qtpl:101
//line views/mutators.qtpl:109
qw422016.N().S(`</textarea>
<br><br>
<label for="text">Describe your changes:</label><br>
<label for="text">`)
//line views/mutators.qtpl:111
qw422016.E().S(lc.Get("edit.tag"))
//line views/mutators.qtpl:111
qw422016.N().S(`</label><br>
<input id="text" type="text" name="message" class="edit-form__message" value="`)
//line views/mutators.qtpl:104
//line views/mutators.qtpl:112
qw422016.E().S(message)
//line views/mutators.qtpl:104
//line views/mutators.qtpl:112
qw422016.N().S(`">
<br><br>
<input type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">
<input type="submit" name="action" class="btn edit-form__preview" value="Preview">
<button type="submit" name="action" class="btn btn_accent edit-form__save" value="Save">`)
//line views/mutators.qtpl:114
qw422016.E().S(lc.Get("edit.save"))
//line views/mutators.qtpl:114
qw422016.N().S(`</button>
<button type="submit" name="action" class="btn edit-form__preview" value="Preview">`)
//line views/mutators.qtpl:115
qw422016.E().S(lc.Get("edit.preview"))
//line views/mutators.qtpl:115
qw422016.N().S(`</button>
<a href="/hypha/`)
//line views/mutators.qtpl:108
//line views/mutators.qtpl:116
qw422016.E().S(hyphaName)
//line views/mutators.qtpl:108
qw422016.N().S(`" class="btn btn_weak">Cancel</a>
//line views/mutators.qtpl:116
qw422016.N().S(`" class="btn btn_weak">`)
//line views/mutators.qtpl:116
qw422016.E().S(lc.Get("ui.cancel"))
//line views/mutators.qtpl:116
qw422016.N().S(`</a>
</form>
<p class="warning">Note that the hypha hasn't been saved yet. Here's the preview:</p>
<p class="warning">`)
//line views/mutators.qtpl:118
qw422016.E().S(lc.Get("edit.preview_tip"))
//line views/mutators.qtpl:118
qw422016.N().S(`</p>
<article class="edit__preview">`)
//line views/mutators.qtpl:111
//line views/mutators.qtpl:119
qw422016.N().S(renderedPage)
//line views/mutators.qtpl:111
//line views/mutators.qtpl:119
qw422016.N().S(`</article>
</main>
`)
//line views/mutators.qtpl:113
qw422016.N().S(Toolbar(user.FromRequest(rq)))
//line views/mutators.qtpl:113
//line views/mutators.qtpl:121
qw422016.N().S(Toolbar(user.FromRequest(rq), lc))
//line views/mutators.qtpl:121
qw422016.N().S(`
</div>
`)
//line views/mutators.qtpl:115
//line views/mutators.qtpl:123
streameditScripts(qw422016)
//line views/mutators.qtpl:115
//line views/mutators.qtpl:123
qw422016.N().S(`
`)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
}
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
func WritePreviewHTML(qq422016 qtio422016.Writer, rq *http.Request, hyphaName, textAreaFill, message, warning string, renderedPage string) {
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
StreamPreviewHTML(qw422016, rq, hyphaName, textAreaFill, message, warning, renderedPage)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
qt422016.ReleaseWriter(qw422016)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
}
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
func PreviewHTML(rq *http.Request, hyphaName, textAreaFill, message, warning string, renderedPage string) string {
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
qb422016 := qt422016.AcquireByteBuffer()
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
WritePreviewHTML(qb422016, rq, hyphaName, textAreaFill, message, warning, renderedPage)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
qs422016 := string(qb422016.B)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
qt422016.ReleaseByteBuffer(qb422016)
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
return qs422016
//line views/mutators.qtpl:116
//line views/mutators.qtpl:124
}
//line views/mutators.qtpl:118
//line views/mutators.qtpl:126
func streameditScripts(qw422016 *qt422016.Writer) {
//line views/mutators.qtpl:118
//line views/mutators.qtpl:126
qw422016.N().S(`
<script src="/static/editor.js"></script>
`)
//line views/mutators.qtpl:120
//line views/mutators.qtpl:128
for _, scriptPath := range cfg.EditScripts {
//line views/mutators.qtpl:120
//line views/mutators.qtpl:128
qw422016.N().S(`
<script src="`)
//line views/mutators.qtpl:121
//line views/mutators.qtpl:129
qw422016.E().S(scriptPath)
//line views/mutators.qtpl:121
//line views/mutators.qtpl:129
qw422016.N().S(`"></script>
`)
//line views/mutators.qtpl:122
//line views/mutators.qtpl:130
}
//line views/mutators.qtpl:122
//line views/mutators.qtpl:130
qw422016.N().S(`
`)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
}
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
func writeeditScripts(qq422016 qtio422016.Writer) {
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
streameditScripts(qw422016)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
qt422016.ReleaseWriter(qw422016)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
}
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
func editScripts() string {
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
qb422016 := qt422016.AcquireByteBuffer()
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
writeeditScripts(qb422016)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
qs422016 := string(qb422016.B)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
qt422016.ReleaseByteBuffer(qb422016)
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
return qs422016
//line views/mutators.qtpl:123
//line views/mutators.qtpl:131
}

View File

@ -1,6 +1,6 @@
{% import "net/http" %}
{% import "fmt" %}
{% import "strings" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/hyphae" %}
@ -12,44 +12,35 @@
{% endif %}
{% endfunc %}
{% code
func backlinksDisplay(h *hyphae.Hypha) string {
n := hyphae.BacklinksCount(h)
suffix := "s"
if n % 10 == 1 {
suffix = ""
}
return fmt.Sprintf("%d backlink%s", n, suffix)
}
%}
{% func hyphaInfo(rq *http.Request, h *hyphae.Hypha) %}
{% code
u := user.FromRequest(rq)
lc := l18n.FromRequest(rq)
backs := hyphae.BacklinksCount(h)
%}
<nav class="hypha-info">
<ul class="hypha-info__list">
{%= hyphaInfoEntry(h, u, "history", "View history") %}
{%= hyphaInfoEntry(h, u, "rename-ask", "Rename") %}
{%= hyphaInfoEntry(h, u, "delete-ask", "Delete") %}
{%= hyphaInfoEntry(h, u, "text", "View markup") %}
{%= hyphaInfoEntry(h, u, "attachment", "Manage attachment") %}
{%= hyphaInfoEntry(h, u, "backlinks", backlinksDisplay(h)) %}
{%= hyphaInfoEntry(h, u, "history", lc.Get("ui.history_link")) %}
{%= hyphaInfoEntry(h, u, "rename-ask", lc.Get("ui.rename_link")) %}
{%= hyphaInfoEntry(h, u, "delete-ask", lc.Get("ui.delete_link")) %}
{%= hyphaInfoEntry(h, u, "text", lc.Get("ui.text_link")) %}
{%= hyphaInfoEntry(h, u, "attachment", lc.Get("ui.attachment_link")) %}
{%= hyphaInfoEntry(h, u, "backlinks", lc.GetPlural("ui.backlinks_link", backs)) %}
</ul>
</nav>
{% endfunc %}
{% func siblingHyphaeHTML(siblings string) %}
{% func siblingHyphaeHTML(siblings string, lc *l18n.Localizer) %}
<aside class="sibling-hyphae layout-card">
<h2 class="sibling-hyphae__title layout-card__title">Sibling hyphae</h2>
<h2 class="sibling-hyphae__title layout-card__title">{%s lc.Get("ui.sibling_hyphae") %}</h2>
{%s= siblings %}
</aside>
{% endfunc %}
{% func SubhyphaeHTML(subhyphae string) %}
{% func SubhyphaeHTML(subhyphae string, lc *l18n.Localizer) %}
{% if strings.TrimSpace(subhyphae) != "" %}
<section class="subhyphae">
<h2 class="subhyphae__title">Subhyphae</h2>
<h2 class="subhyphae__title">{%s lc.Get("ui.subhyphae") %}</h2>
<nav class="subhyphae__nav">
<ul class="subhyphae__list">
{%s= subhyphae %}

View File

@ -8,10 +8,10 @@ package views
import "net/http"
//line views/nav.qtpl:2
import "fmt"
import "strings"
//line views/nav.qtpl:3
import "strings"
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/nav.qtpl:4
import "github.com/bouncepaw/mycorrhiza/user"
@ -95,184 +95,184 @@ func hyphaInfoEntry(h *hyphae.Hypha, u *user.User, action, displayText string) s
//line views/nav.qtpl:13
}
//line views/nav.qtpl:16
func backlinksDisplay(h *hyphae.Hypha) string {
n := hyphae.BacklinksCount(h)
suffix := "s"
if n%10 == 1 {
suffix = ""
}
return fmt.Sprintf("%d backlink%s", n, suffix)
}
//line views/nav.qtpl:26
//line views/nav.qtpl:15
func streamhyphaInfo(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha) {
//line views/nav.qtpl:26
//line views/nav.qtpl:15
qw422016.N().S(`
`)
//line views/nav.qtpl:28
//line views/nav.qtpl:17
u := user.FromRequest(rq)
lc := l18n.FromRequest(rq)
backs := hyphae.BacklinksCount(h)
//line views/nav.qtpl:29
//line views/nav.qtpl:20
qw422016.N().S(`
<nav class="hypha-info">
<ul class="hypha-info__list">
`)
//line views/nav.qtpl:32
streamhyphaInfoEntry(qw422016, h, u, "history", "View history")
//line views/nav.qtpl:32
//line views/nav.qtpl:23
streamhyphaInfoEntry(qw422016, h, u, "history", lc.Get("ui.history_link"))
//line views/nav.qtpl:23
qw422016.N().S(`
`)
//line views/nav.qtpl:33
streamhyphaInfoEntry(qw422016, h, u, "rename-ask", "Rename")
//line views/nav.qtpl:33
//line views/nav.qtpl:24
streamhyphaInfoEntry(qw422016, h, u, "rename-ask", lc.Get("ui.rename_link"))
//line views/nav.qtpl:24
qw422016.N().S(`
`)
//line views/nav.qtpl:34
streamhyphaInfoEntry(qw422016, h, u, "delete-ask", "Delete")
//line views/nav.qtpl:34
//line views/nav.qtpl:25
streamhyphaInfoEntry(qw422016, h, u, "delete-ask", lc.Get("ui.delete_link"))
//line views/nav.qtpl:25
qw422016.N().S(`
`)
//line views/nav.qtpl:35
streamhyphaInfoEntry(qw422016, h, u, "text", "View markup")
//line views/nav.qtpl:35
//line views/nav.qtpl:26
streamhyphaInfoEntry(qw422016, h, u, "text", lc.Get("ui.text_link"))
//line views/nav.qtpl:26
qw422016.N().S(`
`)
//line views/nav.qtpl:36
streamhyphaInfoEntry(qw422016, h, u, "attachment", "Manage attachment")
//line views/nav.qtpl:36
//line views/nav.qtpl:27
streamhyphaInfoEntry(qw422016, h, u, "attachment", lc.Get("ui.attachment_link"))
//line views/nav.qtpl:27
qw422016.N().S(`
`)
//line views/nav.qtpl:37
streamhyphaInfoEntry(qw422016, h, u, "backlinks", backlinksDisplay(h))
//line views/nav.qtpl:37
//line views/nav.qtpl:28
streamhyphaInfoEntry(qw422016, h, u, "backlinks", lc.GetPlural("ui.backlinks_link", backs))
//line views/nav.qtpl:28
qw422016.N().S(`
</ul>
</nav>
`)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
}
//line views/nav.qtpl:40
//line views/nav.qtpl:31
func writehyphaInfo(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha) {
//line views/nav.qtpl:40
//line views/nav.qtpl:31
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
streamhyphaInfo(qw422016, rq, h)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
qt422016.ReleaseWriter(qw422016)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
}
//line views/nav.qtpl:40
//line views/nav.qtpl:31
func hyphaInfo(rq *http.Request, h *hyphae.Hypha) string {
//line views/nav.qtpl:40
//line views/nav.qtpl:31
qb422016 := qt422016.AcquireByteBuffer()
//line views/nav.qtpl:40
//line views/nav.qtpl:31
writehyphaInfo(qb422016, rq, h)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
qs422016 := string(qb422016.B)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
qt422016.ReleaseByteBuffer(qb422016)
//line views/nav.qtpl:40
//line views/nav.qtpl:31
return qs422016
//line views/nav.qtpl:40
//line views/nav.qtpl:31
}
//line views/nav.qtpl:42
func streamsiblingHyphaeHTML(qw422016 *qt422016.Writer, siblings string) {
//line views/nav.qtpl:42
//line views/nav.qtpl:33
func streamsiblingHyphaeHTML(qw422016 *qt422016.Writer, siblings string, lc *l18n.Localizer) {
//line views/nav.qtpl:33
qw422016.N().S(`
<aside class="sibling-hyphae layout-card">
<h2 class="sibling-hyphae__title layout-card__title">Sibling hyphae</h2>
<h2 class="sibling-hyphae__title layout-card__title">`)
//line views/nav.qtpl:35
qw422016.E().S(lc.Get("ui.sibling_hyphae"))
//line views/nav.qtpl:35
qw422016.N().S(`</h2>
`)
//line views/nav.qtpl:45
//line views/nav.qtpl:36
qw422016.N().S(siblings)
//line views/nav.qtpl:45
//line views/nav.qtpl:36
qw422016.N().S(`
</aside>
`)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
}
//line views/nav.qtpl:47
func writesiblingHyphaeHTML(qq422016 qtio422016.Writer, siblings string) {
//line views/nav.qtpl:47
//line views/nav.qtpl:38
func writesiblingHyphaeHTML(qq422016 qtio422016.Writer, siblings string, lc *l18n.Localizer) {
//line views/nav.qtpl:38
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/nav.qtpl:47
streamsiblingHyphaeHTML(qw422016, siblings)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
streamsiblingHyphaeHTML(qw422016, siblings, lc)
//line views/nav.qtpl:38
qt422016.ReleaseWriter(qw422016)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
}
//line views/nav.qtpl:47
func siblingHyphaeHTML(siblings string) string {
//line views/nav.qtpl:47
//line views/nav.qtpl:38
func siblingHyphaeHTML(siblings string, lc *l18n.Localizer) string {
//line views/nav.qtpl:38
qb422016 := qt422016.AcquireByteBuffer()
//line views/nav.qtpl:47
writesiblingHyphaeHTML(qb422016, siblings)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
writesiblingHyphaeHTML(qb422016, siblings, lc)
//line views/nav.qtpl:38
qs422016 := string(qb422016.B)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
qt422016.ReleaseByteBuffer(qb422016)
//line views/nav.qtpl:47
//line views/nav.qtpl:38
return qs422016
//line views/nav.qtpl:47
//line views/nav.qtpl:38
}
//line views/nav.qtpl:49
func StreamSubhyphaeHTML(qw422016 *qt422016.Writer, subhyphae string) {
//line views/nav.qtpl:49
//line views/nav.qtpl:40
func StreamSubhyphaeHTML(qw422016 *qt422016.Writer, subhyphae string, lc *l18n.Localizer) {
//line views/nav.qtpl:40
qw422016.N().S(`
`)
//line views/nav.qtpl:50
//line views/nav.qtpl:41
if strings.TrimSpace(subhyphae) != "" {
//line views/nav.qtpl:50
//line views/nav.qtpl:41
qw422016.N().S(`
<section class="subhyphae">
<h2 class="subhyphae__title">Subhyphae</h2>
<h2 class="subhyphae__title">`)
//line views/nav.qtpl:43
qw422016.E().S(lc.Get("ui.subhyphae"))
//line views/nav.qtpl:43
qw422016.N().S(`</h2>
<nav class="subhyphae__nav">
<ul class="subhyphae__list">
`)
//line views/nav.qtpl:55
//line views/nav.qtpl:46
qw422016.N().S(subhyphae)
//line views/nav.qtpl:55
//line views/nav.qtpl:46
qw422016.N().S(`
</ul>
</nav>
</section>
`)
//line views/nav.qtpl:59
//line views/nav.qtpl:50
}
//line views/nav.qtpl:59
//line views/nav.qtpl:50
qw422016.N().S(`
`)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
}
//line views/nav.qtpl:60
func WriteSubhyphaeHTML(qq422016 qtio422016.Writer, subhyphae string) {
//line views/nav.qtpl:60
//line views/nav.qtpl:51
func WriteSubhyphaeHTML(qq422016 qtio422016.Writer, subhyphae string, lc *l18n.Localizer) {
//line views/nav.qtpl:51
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/nav.qtpl:60
StreamSubhyphaeHTML(qw422016, subhyphae)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
StreamSubhyphaeHTML(qw422016, subhyphae, lc)
//line views/nav.qtpl:51
qt422016.ReleaseWriter(qw422016)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
}
//line views/nav.qtpl:60
func SubhyphaeHTML(subhyphae string) string {
//line views/nav.qtpl:60
//line views/nav.qtpl:51
func SubhyphaeHTML(subhyphae string, lc *l18n.Localizer) string {
//line views/nav.qtpl:51
qb422016 := qt422016.AcquireByteBuffer()
//line views/nav.qtpl:60
WriteSubhyphaeHTML(qb422016, subhyphae)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
WriteSubhyphaeHTML(qb422016, subhyphae, lc)
//line views/nav.qtpl:51
qs422016 := string(qb422016.B)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
qt422016.ReleaseByteBuffer(qb422016)
//line views/nav.qtpl:60
//line views/nav.qtpl:51
return qs422016
//line views/nav.qtpl:60
//line views/nav.qtpl:51
}

View File

@ -5,19 +5,23 @@
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% import "github.com/bouncepaw/mycorrhiza/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% import "github.com/bouncepaw/mycorrhiza/mimetype" %}
{% import "github.com/bouncepaw/mycorrhiza/tree" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
{% func AttachmentMenuHTML(rq *http.Request, h *hyphae.Hypha, u *user.User) %}
{% code
lc := l18n.FromRequest(rq)
%}
<div class="layout">
<main class="main-width attachment-tab">
<h1>Attachment of {%s= beautifulLink(h.Name) %}</h1>
<h1>{%s= lc.Get("ui.attach_title", &l18n.Replacements{"name": beautifulLink(h.Name)}) %}</h1>
{% if h.BinaryPath == "" %}
<p class="explanation">This hypha has no attachment, you can upload it here. <a href="/help/en/attachment" class="shy-link">What are attachments?</a></p>
<p class="explanation">{%s lc.Get("ui.attach_empty") %} <a href="/help/{%s lc.Locale %}/attachment" class="shy-link">{%s lc.Get("ui.attach_link") %}</a></p>
{% else %}
<p class="explanation">You can manage the hypha's attachment on this page. <a href="/help/en/attachment" class="shy-link">What are attachments?</a></p>
<p class="explanation">{%s lc.Get("ui.attach_tip") %} <a href="/help/{%s lc.Locale %}/attachment" class="shy-link">{%s lc.Get("ui.attach_link") %}</a></p>
{% endif %}
<section class="amnt-grid">
@ -28,17 +32,17 @@
fileinfo, err := os.Stat(h.BinaryPath) %}
{% if err == nil %}
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">Stat</legend>
<p class="modal__confirmation-msg"><b>File size:</b> {%dl fileinfo.Size() %} bytes</p>
<p><b>MIME type:</b> {%s mime %}</p>
<legend class="modal__title modal__title_small">{%s lc.Get("ui.attach_stat") %}</legend>
<p class="modal__confirmation-msg"><b>{%s lc.Get("ui.attach_stat_size") %}</b> {%s lc.GetPlural64("ui.attach_size_value", fileinfo.Size())%}</p>
<p><b>{%s lc.Get("ui.attach_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">Include</legend>
<p class="modal__confirmation-msg">This attachment is an image. To include it n a hypha, use a syntax like this:</p>
<pre class="codebleck"><code>img { {%s h.Name %} }</code></pre>
<legend class="modal__title modal__title_small">{%s lc.Get("ui.attach_include") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.attach_include_tip") %}</p>
<pre class="codeblock"><code>img { {%s h.Name %} }</code></pre>
</fieldset>
{% endif %}
{% endif %}
@ -48,12 +52,12 @@
method="post" enctype="multipart/form-data"
class="upload-binary modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">Attach</legend>
<p class="modal__confirmation-msg">You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.</p>
<legend class="modal__title modal__title_small">{%s lc.Get("ui.attach_new") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.attach_new_tip") %}</p>
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<input type="submit" class="btn stick-to-bottom" value="Upload">
<button type="submit" class="btn stick-to-bottom" value="Upload">{%s lc.Get("ui.attach_upload")%}</button>
</fieldset>
</form>
{% endif %}
@ -61,9 +65,9 @@
{% if h.BinaryPath != "" && u.CanProceed("unattach-confirm") %}
<form action="/unattach-confirm/{%s h.Name %}" method="post" class="modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">Unattach</legend>
<p class="modal__confirmation-msg">Please note that you don't have to unattach before uploading a new attachment.</p>
<input type="submit" class="btn" value="Unattach">
<legend class="modal__title modal__title_small">{%s lc.Get("ui.attach_remove") %}</legend>
<p class="modal__confirmation-msg">{%s lc.Get("ui.attach_remove_tip") %}</p>
<button type="submit" class="btn" value="Unattach">{%s lc.Get("ui.attach_remove_button") %}</button>
</fieldset>
</form>
{% endif %}
@ -76,7 +80,7 @@
If `contents` == "", a helpful message is shown instead.
If you rename .prevnext, change the docs too.
{% func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) %}
{% func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) %}
{% code
siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name)
u := user.FromRequest(rq)
@ -88,13 +92,13 @@ If you rename .prevnext, change the docs too.
<a class="jump-btn__link" href="#hypha-bottom">↓</a>
</div>
{% if u.CanProceed("edit") %}<div class="btn edit-btn">
<a class="edit-btn__link" href="/edit/{%s h.Name %}">Edit text</a>
<a class="edit-btn__link" href="/edit/{%s h.Name %}">{%s lc.Get("ui.edit_link") %}</a>
</div>{% endif %}
{%s= NaviTitleHTML(h) %}
{% if h.Exists %}
{%s= contents %}
{% else %}
{%= nonExistentHyphaNotice(h, u) %}
{%= nonExistentHyphaNotice(h, u, lc) %}
{% endif %}
</article>
<section class="prevnext">
@ -105,7 +109,7 @@ If you rename .prevnext, change the docs too.
<a class="prevnext__el prevnext__next" href="/hypha/{%s nextHyphaName %}" rel="next">{%s util.BeautifulName(path.Base(nextHyphaName)) %} →</a>
{% endif %}
</section>
{%= SubhyphaeHTML(subhyphae) %}
{%= SubhyphaeHTML(subhyphae, lc) %}
<section id="hypha-bottom">
<div class="jump-btn">
<a class="jump-btn__link" href="#hypha">↑</a>
@ -113,25 +117,25 @@ If you rename .prevnext, change the docs too.
{%= hyphaInfo(rq, h) %}
</section>
</main>
{%= siblingHyphaeHTML(siblings) %}
{%= siblingHyphaeHTML(siblings, lc) %}
</div>
{%= viewScripts() %}
{% endfunc %}
{% func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) %}
{% func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) %}
{% code
siblings, subhyphae, _, _ := tree.Tree(h.Name)
%}
<div class="layout">
<main class="main-width">
<article>
<p>Please note that viewing attachments of hyphae is not supported in history for now. <a href="/rev-text/{%s revHash %}/{%s h.Name %}">Get Mycomarkup source of this revision</a></p>
<p>{%s lc.Get("ui.revision_warning") %} <a href="/rev-text/{%s revHash %}/{%s h.Name %}">{%s lc.Get("ui.revision_link") %}</a></p>
{%s= NaviTitleHTML(h) %}
{%s= contents %}
</article>
{%= SubhyphaeHTML(subhyphae) %}
{%= SubhyphaeHTML(subhyphae, lc) %}
</main>
{%= siblingHyphaeHTML(siblings) %}
{%= siblingHyphaeHTML(siblings, lc) %}
</div>
{%= viewScripts() %}
{% endfunc %}

View File

@ -23,218 +23,295 @@ import "github.com/bouncepaw/mycorrhiza/cfg"
import "github.com/bouncepaw/mycorrhiza/hyphae"
//line views/readers.qtpl:8
import "github.com/bouncepaw/mycorrhiza/mimetype"
import "github.com/bouncepaw/mycorrhiza/l18n"
//line views/readers.qtpl:9
import "github.com/bouncepaw/mycorrhiza/tree"
import "github.com/bouncepaw/mycorrhiza/mimetype"
//line views/readers.qtpl:10
import "github.com/bouncepaw/mycorrhiza/user"
import "github.com/bouncepaw/mycorrhiza/tree"
//line views/readers.qtpl:11
import "github.com/bouncepaw/mycorrhiza/user"
//line views/readers.qtpl:12
import "github.com/bouncepaw/mycorrhiza/util"
//line views/readers.qtpl:13
//line views/readers.qtpl:14
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/readers.qtpl:13
//line views/readers.qtpl:14
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/readers.qtpl:13
//line views/readers.qtpl:14
func StreamAttachmentMenuHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) {
//line views/readers.qtpl:13
//line views/readers.qtpl:14
qw422016.N().S(`
`)
//line views/readers.qtpl:16
lc := l18n.FromRequest(rq)
//line views/readers.qtpl:17
qw422016.N().S(`
<div class="layout">
<main class="main-width attachment-tab">
<h1>Attachment of `)
//line views/readers.qtpl:16
qw422016.N().S(beautifulLink(h.Name))
//line views/readers.qtpl:16
<h1>`)
//line views/readers.qtpl:20
qw422016.N().S(lc.Get("ui.attach_title", &l18n.Replacements{"name": beautifulLink(h.Name)}))
//line views/readers.qtpl:20
qw422016.N().S(`</h1>
`)
//line views/readers.qtpl:17
//line views/readers.qtpl:21
if h.BinaryPath == "" {
//line views/readers.qtpl:17
//line views/readers.qtpl:21
qw422016.N().S(`
<p class="explanation">This hypha has no attachment, you can upload it here. <a href="/help/en/attachment" class="shy-link">What are attachments?</a></p>
<p class="explanation">`)
//line views/readers.qtpl:22
qw422016.E().S(lc.Get("ui.attach_empty"))
//line views/readers.qtpl:22
qw422016.N().S(` <a href="/help/`)
//line views/readers.qtpl:22
qw422016.E().S(lc.Locale)
//line views/readers.qtpl:22
qw422016.N().S(`/attachment" class="shy-link">`)
//line views/readers.qtpl:22
qw422016.E().S(lc.Get("ui.attach_link"))
//line views/readers.qtpl:22
qw422016.N().S(`</a></p>
`)
//line views/readers.qtpl:19
//line views/readers.qtpl:23
} else {
//line views/readers.qtpl:19
//line views/readers.qtpl:23
qw422016.N().S(`
<p class="explanation">You can manage the hypha's attachment on this page. <a href="/help/en/attachment" class="shy-link">What are attachments?</a></p>
<p class="explanation">`)
//line views/readers.qtpl:24
qw422016.E().S(lc.Get("ui.attach_tip"))
//line views/readers.qtpl:24
qw422016.N().S(` <a href="/help/`)
//line views/readers.qtpl:24
qw422016.E().S(lc.Locale)
//line views/readers.qtpl:24
qw422016.N().S(`/attachment" class="shy-link">`)
//line views/readers.qtpl:24
qw422016.E().S(lc.Get("ui.attach_link"))
//line views/readers.qtpl:24
qw422016.N().S(`</a></p>
`)
//line views/readers.qtpl:21
//line views/readers.qtpl:25
}
//line views/readers.qtpl:21
//line views/readers.qtpl:25
qw422016.N().S(`
<section class="amnt-grid">
`)
//line views/readers.qtpl:25
//line views/readers.qtpl:29
if h.BinaryPath != "" {
//line views/readers.qtpl:25
//line views/readers.qtpl:29
qw422016.N().S(`
`)
//line views/readers.qtpl:27
//line views/readers.qtpl:31
mime := mimetype.FromExtension(path.Ext(h.BinaryPath))
fileinfo, err := os.Stat(h.BinaryPath)
//line views/readers.qtpl:28
//line views/readers.qtpl:32
qw422016.N().S(`
`)
//line views/readers.qtpl:29
//line views/readers.qtpl:33
if err == nil {
//line views/readers.qtpl:29
//line views/readers.qtpl:33
qw422016.N().S(`
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">Stat</legend>
<p class="modal__confirmation-msg"><b>File size:</b> `)
//line views/readers.qtpl:32
qw422016.N().DL(fileinfo.Size())
//line views/readers.qtpl:32
qw422016.N().S(` bytes</p>
<p><b>MIME type:</b> `)
//line views/readers.qtpl:33
<legend class="modal__title modal__title_small">`)
//line views/readers.qtpl:35
qw422016.E().S(lc.Get("ui.attach_stat"))
//line views/readers.qtpl:35
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg"><b>`)
//line views/readers.qtpl:36
qw422016.E().S(lc.Get("ui.attach_stat_size"))
//line views/readers.qtpl:36
qw422016.N().S(`</b> `)
//line views/readers.qtpl:36
qw422016.E().S(lc.GetPlural64("ui.attach_size_value", fileinfo.Size()))
//line views/readers.qtpl:36
qw422016.N().S(`</p>
<p><b>`)
//line views/readers.qtpl:37
qw422016.E().S(lc.Get("ui.attach_stat_mime"))
//line views/readers.qtpl:37
qw422016.N().S(`</b> `)
//line views/readers.qtpl:37
qw422016.E().S(mime)
//line views/readers.qtpl:33
//line views/readers.qtpl:37
qw422016.N().S(`</p>
</fieldset>
`)
//line views/readers.qtpl:35
//line views/readers.qtpl:39
}
//line views/readers.qtpl:35
//line views/readers.qtpl:39
qw422016.N().S(`
`)
//line views/readers.qtpl:37
//line views/readers.qtpl:41
if strings.HasPrefix(mime, "image/") {
//line views/readers.qtpl:37
//line views/readers.qtpl:41
qw422016.N().S(`
<fieldset class="amnt-menu-block">
<legend class="modal__title modal__title_small">Include</legend>
<p class="modal__confirmation-msg">This attachment is an image. To include it n a hypha, use a syntax like this:</p>
<pre class="codebleck"><code>img { `)
//line views/readers.qtpl:41
<legend class="modal__title modal__title_small">`)
//line views/readers.qtpl:43
qw422016.E().S(lc.Get("ui.attach_include"))
//line views/readers.qtpl:43
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line views/readers.qtpl:44
qw422016.E().S(lc.Get("ui.attach_include_tip"))
//line views/readers.qtpl:44
qw422016.N().S(`</p>
<pre class="codeblock"><code>img { `)
//line views/readers.qtpl:45
qw422016.E().S(h.Name)
//line views/readers.qtpl:41
//line views/readers.qtpl:45
qw422016.N().S(` }</code></pre>
</fieldset>
`)
//line views/readers.qtpl:43
//line views/readers.qtpl:47
}
//line views/readers.qtpl:43
//line views/readers.qtpl:47
qw422016.N().S(`
`)
//line views/readers.qtpl:44
//line views/readers.qtpl:48
}
//line views/readers.qtpl:44
//line views/readers.qtpl:48
qw422016.N().S(`
`)
//line views/readers.qtpl:46
//line views/readers.qtpl:50
if u.CanProceed("upload-binary") {
//line views/readers.qtpl:46
//line views/readers.qtpl:50
qw422016.N().S(`
<form action="/upload-binary/`)
//line views/readers.qtpl:47
//line views/readers.qtpl:51
qw422016.E().S(h.Name)
//line views/readers.qtpl:47
//line views/readers.qtpl:51
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">Attach</legend>
<p class="modal__confirmation-msg">You can upload a new attachment. Please do not upload too big pictures unless you need to because may not want to wait for big pictures to load.</p>
<legend class="modal__title modal__title_small">`)
//line views/readers.qtpl:55
qw422016.E().S(lc.Get("ui.attach_new"))
//line views/readers.qtpl:55
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line views/readers.qtpl:56
qw422016.E().S(lc.Get("ui.attach_new_tip"))
//line views/readers.qtpl:56
qw422016.N().S(`</p>
<label for="upload-binary__input"></label>
<input type="file" id="upload-binary__input" name="binary">
<input type="submit" class="btn stick-to-bottom" value="Upload">
<button type="submit" class="btn stick-to-bottom" value="Upload">`)
//line views/readers.qtpl:60
qw422016.E().S(lc.Get("ui.attach_upload"))
//line views/readers.qtpl:60
qw422016.N().S(`</button>
</fieldset>
</form>
`)
//line views/readers.qtpl:59
//line views/readers.qtpl:63
}
//line views/readers.qtpl:59
//line views/readers.qtpl:63
qw422016.N().S(`
`)
//line views/readers.qtpl:61
//line views/readers.qtpl:65
if h.BinaryPath != "" && u.CanProceed("unattach-confirm") {
//line views/readers.qtpl:61
//line views/readers.qtpl:65
qw422016.N().S(`
<form action="/unattach-confirm/`)
//line views/readers.qtpl:62
//line views/readers.qtpl:66
qw422016.E().S(h.Name)
//line views/readers.qtpl:62
//line views/readers.qtpl:66
qw422016.N().S(`" method="post" class="modal amnt-menu-block">
<fieldset class="modal__fieldset">
<legend class="modal__title modal__title_small">Unattach</legend>
<p class="modal__confirmation-msg">Please note that you don't have to unattach before uploading a new attachment.</p>
<input type="submit" class="btn" value="Unattach">
<legend class="modal__title modal__title_small">`)
//line views/readers.qtpl:68
qw422016.E().S(lc.Get("ui.attach_remove"))
//line views/readers.qtpl:68
qw422016.N().S(`</legend>
<p class="modal__confirmation-msg">`)
//line views/readers.qtpl:69
qw422016.E().S(lc.Get("ui.attach_remove_tip"))
//line views/readers.qtpl:69
qw422016.N().S(`</p>
<button type="submit" class="btn" value="Unattach">`)
//line views/readers.qtpl:70
qw422016.E().S(lc.Get("ui.attach_remove_button"))
//line views/readers.qtpl:70
qw422016.N().S(`</button>
</fieldset>
</form>
`)
//line views/readers.qtpl:69
//line views/readers.qtpl:73
}
//line views/readers.qtpl:69
//line views/readers.qtpl:73
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
}
//line views/readers.qtpl:74
//line views/readers.qtpl:78
func WriteAttachmentMenuHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, u *user.User) {
//line views/readers.qtpl:74
//line views/readers.qtpl:78
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
StreamAttachmentMenuHTML(qw422016, rq, h, u)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
}
//line views/readers.qtpl:74
//line views/readers.qtpl:78
func AttachmentMenuHTML(rq *http.Request, h *hyphae.Hypha, u *user.User) string {
//line views/readers.qtpl:74
//line views/readers.qtpl:78
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:74
//line views/readers.qtpl:78
WriteAttachmentMenuHTML(qb422016, rq, h, u)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
qs422016 := string(qb422016.B)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:74
//line views/readers.qtpl:78
return qs422016
//line views/readers.qtpl:74
//line views/readers.qtpl:78
}
// If `contents` == "", a helpful message is shown instead.
//
// If you rename .prevnext, change the docs too.
//line views/readers.qtpl:79
func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) {
//line views/readers.qtpl:79
//line views/readers.qtpl:83
func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) {
//line views/readers.qtpl:83
qw422016.N().S(`
`)
//line views/readers.qtpl:81
//line views/readers.qtpl:85
siblings, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name)
u := user.FromRequest(rq)
//line views/readers.qtpl:83
//line views/readers.qtpl:87
qw422016.N().S(`
<div class="layout">
<main class="main-width">
@ -243,273 +320,285 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph
<a class="jump-btn__link" href="#hypha-bottom"></a>
</div>
`)
//line views/readers.qtpl:90
//line views/readers.qtpl:94
if u.CanProceed("edit") {
//line views/readers.qtpl:90
//line views/readers.qtpl:94
qw422016.N().S(`<div class="btn edit-btn">
<a class="edit-btn__link" href="/edit/`)
//line views/readers.qtpl:91
//line views/readers.qtpl:95
qw422016.E().S(h.Name)
//line views/readers.qtpl:91
qw422016.N().S(`">Edit text</a>
//line views/readers.qtpl:95
qw422016.N().S(`">`)
//line views/readers.qtpl:95
qw422016.E().S(lc.Get("ui.edit_link"))
//line views/readers.qtpl:95
qw422016.N().S(`</a>
</div>`)
//line views/readers.qtpl:92
//line views/readers.qtpl:96
}
//line views/readers.qtpl:92
//line views/readers.qtpl:96
qw422016.N().S(`
`)
//line views/readers.qtpl:93
//line views/readers.qtpl:97
qw422016.N().S(NaviTitleHTML(h))
//line views/readers.qtpl:93
//line views/readers.qtpl:97
qw422016.N().S(`
`)
//line views/readers.qtpl:94
//line views/readers.qtpl:98
if h.Exists {
//line views/readers.qtpl:94
//line views/readers.qtpl:98
qw422016.N().S(`
`)
//line views/readers.qtpl:95
//line views/readers.qtpl:99
qw422016.N().S(contents)
//line views/readers.qtpl:95
//line views/readers.qtpl:99
qw422016.N().S(`
`)
//line views/readers.qtpl:96
//line views/readers.qtpl:100
} else {
//line views/readers.qtpl:96
//line views/readers.qtpl:100
qw422016.N().S(`
`)
//line views/readers.qtpl:97
streamnonExistentHyphaNotice(qw422016, h, u)
//line views/readers.qtpl:97
//line views/readers.qtpl:101
streamnonExistentHyphaNotice(qw422016, h, u, lc)
//line views/readers.qtpl:101
qw422016.N().S(`
`)
//line views/readers.qtpl:98
//line views/readers.qtpl:102
}
//line views/readers.qtpl:98
//line views/readers.qtpl:102
qw422016.N().S(`
</article>
<section class="prevnext">
`)
//line views/readers.qtpl:101
//line views/readers.qtpl:105
if prevHyphaName != "" {
//line views/readers.qtpl:101
//line views/readers.qtpl:105
qw422016.N().S(`
<a class="prevnext__el prevnext__prev" href="/hypha/`)
//line views/readers.qtpl:102
//line views/readers.qtpl:106
qw422016.E().S(prevHyphaName)
//line views/readers.qtpl:102
//line views/readers.qtpl:106
qw422016.N().S(`" rel="prev">← `)
//line views/readers.qtpl:102
//line views/readers.qtpl:106
qw422016.E().S(util.BeautifulName(path.Base(prevHyphaName)))
//line views/readers.qtpl:102
//line views/readers.qtpl:106
qw422016.N().S(`</a>
`)
//line views/readers.qtpl:103
//line views/readers.qtpl:107
}
//line views/readers.qtpl:103
//line views/readers.qtpl:107
qw422016.N().S(`
`)
//line views/readers.qtpl:104
//line views/readers.qtpl:108
if nextHyphaName != "" {
//line views/readers.qtpl:104
//line views/readers.qtpl:108
qw422016.N().S(`
<a class="prevnext__el prevnext__next" href="/hypha/`)
//line views/readers.qtpl:105
//line views/readers.qtpl:109
qw422016.E().S(nextHyphaName)
//line views/readers.qtpl:105
//line views/readers.qtpl:109
qw422016.N().S(`" rel="next">`)
//line views/readers.qtpl:105
//line views/readers.qtpl:109
qw422016.E().S(util.BeautifulName(path.Base(nextHyphaName)))
//line views/readers.qtpl:105
//line views/readers.qtpl:109
qw422016.N().S(` </a>
`)
//line views/readers.qtpl:106
//line views/readers.qtpl:110
}
//line views/readers.qtpl:106
//line views/readers.qtpl:110
qw422016.N().S(`
</section>
`)
//line views/readers.qtpl:108
StreamSubhyphaeHTML(qw422016, subhyphae)
//line views/readers.qtpl:108
//line views/readers.qtpl:112
StreamSubhyphaeHTML(qw422016, subhyphae, lc)
//line views/readers.qtpl:112
qw422016.N().S(`
<section id="hypha-bottom">
<div class="jump-btn">
<a class="jump-btn__link" href="#hypha"></a>
</div>
`)
//line views/readers.qtpl:113
//line views/readers.qtpl:117
streamhyphaInfo(qw422016, rq, h)
//line views/readers.qtpl:113
//line views/readers.qtpl:117
qw422016.N().S(`
</section>
</main>
`)
//line views/readers.qtpl:116
streamsiblingHyphaeHTML(qw422016, siblings)
//line views/readers.qtpl:116
//line views/readers.qtpl:120
streamsiblingHyphaeHTML(qw422016, siblings, lc)
//line views/readers.qtpl:120
qw422016.N().S(`
</div>
`)
//line views/readers.qtpl:118
//line views/readers.qtpl:122
streamviewScripts(qw422016)
//line views/readers.qtpl:118
qw422016.N().S(`
`)
//line views/readers.qtpl:119
}
//line views/readers.qtpl:119
func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents string) {
//line views/readers.qtpl:119
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:119
StreamHyphaHTML(qw422016, rq, h, contents)
//line views/readers.qtpl:119
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:119
}
//line views/readers.qtpl:119
func HyphaHTML(rq *http.Request, h *hyphae.Hypha, contents string) string {
//line views/readers.qtpl:119
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:119
WriteHyphaHTML(qb422016, rq, h, contents)
//line views/readers.qtpl:119
qs422016 := string(qb422016.B)
//line views/readers.qtpl:119
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:119
return qs422016
//line views/readers.qtpl:119
}
//line views/readers.qtpl:121
func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:121
//line views/readers.qtpl:122
qw422016.N().S(`
`)
//line views/readers.qtpl:123
}
//line views/readers.qtpl:123
func WriteHyphaHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) {
//line views/readers.qtpl:123
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:123
StreamHyphaHTML(qw422016, rq, lc, h, contents)
//line views/readers.qtpl:123
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:123
}
//line views/readers.qtpl:123
func HyphaHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents string) string {
//line views/readers.qtpl:123
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:123
WriteHyphaHTML(qb422016, rq, lc, h, contents)
//line views/readers.qtpl:123
qs422016 := string(qb422016.B)
//line views/readers.qtpl:123
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:123
return qs422016
//line views/readers.qtpl:123
}
//line views/readers.qtpl:125
func StreamRevisionHTML(qw422016 *qt422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:125
qw422016.N().S(`
`)
//line views/readers.qtpl:127
siblings, subhyphae, _, _ := tree.Tree(h.Name)
//line views/readers.qtpl:124
//line views/readers.qtpl:128
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<article>
<p>Please note that viewing attachments of hyphae is not supported in history for now. <a href="/rev-text/`)
//line views/readers.qtpl:128
<p>`)
//line views/readers.qtpl:132
qw422016.E().S(lc.Get("ui.revision_warning"))
//line views/readers.qtpl:132
qw422016.N().S(` <a href="/rev-text/`)
//line views/readers.qtpl:132
qw422016.E().S(revHash)
//line views/readers.qtpl:128
//line views/readers.qtpl:132
qw422016.N().S(`/`)
//line views/readers.qtpl:128
//line views/readers.qtpl:132
qw422016.E().S(h.Name)
//line views/readers.qtpl:128
qw422016.N().S(`">Get Mycomarkup source of this revision</a></p>
//line views/readers.qtpl:132
qw422016.N().S(`">`)
//line views/readers.qtpl:132
qw422016.E().S(lc.Get("ui.revision_link"))
//line views/readers.qtpl:132
qw422016.N().S(`</a></p>
`)
//line views/readers.qtpl:129
//line views/readers.qtpl:133
qw422016.N().S(NaviTitleHTML(h))
//line views/readers.qtpl:129
//line views/readers.qtpl:133
qw422016.N().S(`
`)
//line views/readers.qtpl:130
//line views/readers.qtpl:134
qw422016.N().S(contents)
//line views/readers.qtpl:130
//line views/readers.qtpl:134
qw422016.N().S(`
</article>
`)
//line views/readers.qtpl:132
StreamSubhyphaeHTML(qw422016, subhyphae)
//line views/readers.qtpl:132
//line views/readers.qtpl:136
StreamSubhyphaeHTML(qw422016, subhyphae, lc)
//line views/readers.qtpl:136
qw422016.N().S(`
</main>
`)
//line views/readers.qtpl:134
streamsiblingHyphaeHTML(qw422016, siblings)
//line views/readers.qtpl:134
//line views/readers.qtpl:138
streamsiblingHyphaeHTML(qw422016, siblings, lc)
//line views/readers.qtpl:138
qw422016.N().S(`
</div>
`)
//line views/readers.qtpl:136
//line views/readers.qtpl:140
streamviewScripts(qw422016)
//line views/readers.qtpl:136
//line views/readers.qtpl:140
qw422016.N().S(`
`)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
}
//line views/readers.qtpl:137
func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, h *hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:137
//line views/readers.qtpl:141
func WriteRevisionHTML(qq422016 qtio422016.Writer, rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) {
//line views/readers.qtpl:141
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:137
StreamRevisionHTML(qw422016, rq, h, contents, revHash)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
StreamRevisionHTML(qw422016, rq, lc, h, contents, revHash)
//line views/readers.qtpl:141
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
}
//line views/readers.qtpl:137
func RevisionHTML(rq *http.Request, h *hyphae.Hypha, contents, revHash string) string {
//line views/readers.qtpl:137
//line views/readers.qtpl:141
func RevisionHTML(rq *http.Request, lc *l18n.Localizer, h *hyphae.Hypha, contents, revHash string) string {
//line views/readers.qtpl:141
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:137
WriteRevisionHTML(qb422016, rq, h, contents, revHash)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
WriteRevisionHTML(qb422016, rq, lc, h, contents, revHash)
//line views/readers.qtpl:141
qs422016 := string(qb422016.B)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:137
//line views/readers.qtpl:141
return qs422016
//line views/readers.qtpl:137
//line views/readers.qtpl:141
}
//line views/readers.qtpl:139
//line views/readers.qtpl:143
func streamviewScripts(qw422016 *qt422016.Writer) {
//line views/readers.qtpl:139
//line views/readers.qtpl:143
qw422016.N().S(`
`)
//line views/readers.qtpl:140
//line views/readers.qtpl:144
for _, scriptPath := range cfg.ViewScripts {
//line views/readers.qtpl:140
//line views/readers.qtpl:144
qw422016.N().S(`
<script src="`)
//line views/readers.qtpl:141
//line views/readers.qtpl:145
qw422016.E().S(scriptPath)
//line views/readers.qtpl:141
//line views/readers.qtpl:145
qw422016.N().S(`"></script>
`)
//line views/readers.qtpl:142
//line views/readers.qtpl:146
}
//line views/readers.qtpl:142
//line views/readers.qtpl:146
qw422016.N().S(`
`)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
}
//line views/readers.qtpl:143
//line views/readers.qtpl:147
func writeviewScripts(qq422016 qtio422016.Writer) {
//line views/readers.qtpl:143
//line views/readers.qtpl:147
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
streamviewScripts(qw422016)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
qt422016.ReleaseWriter(qw422016)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
}
//line views/readers.qtpl:143
//line views/readers.qtpl:147
func viewScripts() string {
//line views/readers.qtpl:143
//line views/readers.qtpl:147
qb422016 := qt422016.AcquireByteBuffer()
//line views/readers.qtpl:143
//line views/readers.qtpl:147
writeviewScripts(qb422016)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
qs422016 := string(qb422016.B)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
qt422016.ReleaseByteBuffer(qb422016)
//line views/readers.qtpl:143
//line views/readers.qtpl:147
return qs422016
//line views/readers.qtpl:143
//line views/readers.qtpl:147
}

View File

@ -3,10 +3,11 @@
{% import "github.com/bouncepaw/mycorrhiza/hyphae" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
{% import "github.com/bouncepaw/mycorrhiza/l18n" %}
{% func BaseHTML(title, body string, u *user.User, headElements ...string) %}
{% func BaseHTML(title, body string, lc *l18n.Localizer, u *user.User, headElements ...string) %}
<!doctype html>
<html>
<html lang="{%s lc.Locale %}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@ -27,7 +28,7 @@
</li>
<li class="top-bar__section top-bar__section_search">
<form class="top-bar__search" method="GET" action="/title-search">
<input type="text" name="q" placeholder="Search by title" class="top-bar__search-bar">
<input type="text" name="q" placeholder="{%s lc.Get("ui.title_search") %}" class="top-bar__search-bar">
</form>
</li>
<li class="top-bar__section top-bar__section_auth">
@ -35,19 +36,19 @@
<ul class="top-bar__auth auth-links">
<li class="auth-links__box auth-links__user-box">
{% if u.Group == "anon" %}
<a href="/login" class="auth-links__link auth-links__login-link">Login</a>
<a href="/login" class="auth-links__link auth-links__login-link">{%s lc.Get("ui.login") %}</a>
{% else %}
<a href="/hypha/{%s cfg.UserHypha %}/{%s u.Name %}" class="auth-links__link auth-links__user-link">{%s util.BeautifulName(u.Name) %}</a>
{% endif %}
</li>
{% if cfg.AllowRegistration && u.Group == "anon" %}
<li class="auth-links__box auth-links__register-box">
<a href="/register" class="auth-links__link auth-links__register-link">Register</a>
<a href="/register" class="auth-links__link auth-links__register-link">{%s lc.Get("ui.register") %}</a>
</li>
{% endif %}
{% if u.Group == "admin" %}
<li class="auth-links__box auth-links__admin-box">
<a href="/admin" class="auth-links__link auth-links__admin-link">Admin panel</a>
<a href="/admin" class="auth-links__link auth-links__admin-link">{%s lc.Get("ui.admin_panel") %}</a>
</li>
{% endif %}
</ul>
@ -73,7 +74,7 @@
<div class="dialog" tabindex="0">
<div class="dialog__header">
<h1 class="dialog__title"></h1>
<button class="dialog__close-button" aria-label="Close this dialog"></button>
<button class="dialog__close-button" aria-label="{%s lc.Get("ui.close_dialog") %}"></button>
</div>
<div class="dialog__content"></div>
@ -85,11 +86,11 @@
</html>
{% endfunc %}
{% func TitleSearchHTML(query string, generator func(string) <-chan string) %}
{% func TitleSearchHTML(query string, generator func(string) <-chan string, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width title-search">
<h1>Search results for {%s query %}</h1>
<p>Every hypha name has been compared with the query. Hyphae that have matched the query are listed below.</p>
<h1>{%s lc.Get("ui.search_results_query", &l18n.Replacements{"query": query})%}</h1>
<p>{%s lc.Get("ui.search_results_desc")%}</p>
<ul class="title-search__results">
{% for hyphaName := range generator(query) %}
<li class="title-search__entry">
@ -120,11 +121,11 @@ It outputs a poorly formatted JSON, but it works and is valid.
}
{% endfunc %}
{% func BacklinksHTML(query string, generator func(string) <-chan string) %}
{% func BacklinksHTML(query string, generator func(string) <-chan string, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width backlinks">
<h1>Backlinks to {%s query %}</h1>
<p>Hyphae which have a link to the selected hypha are listed below.</p>
<h1>{%s lc.Get("ui.backlinks_query", &l18n.Replacements{"query": query})%}</h1>
<p>{%s lc.Get("ui.backlinks_desc")%}</p>
<ul class="backlinks__list">
{% for hyphaName := range generator(query) %}
<li class="backlinks__entry">
@ -135,52 +136,52 @@ It outputs a poorly formatted JSON, but it works and is valid.
</div>
{% endfunc %}
{% func HelpHTML(content string) %}
{% func HelpHTML(content, lang string, lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width help">
<article>
{%s= content %}
</article>
</main>
{%s= helpTopicsHTML() %}
{%s= helpTopicsHTML(lang, lc) %}
</div>
{% endfunc %}
{% func HelpEmptyErrorHTML() %}
<h1>This entry does not exist!</h1>
<p>Try finding a different entry that would help you.</p>
<p>If you want to write this entry by yourself, consider <a class="wikilink wikilink_external wikilink_https" href="https://github.com/bouncepaw/mycorrhiza">contributing</a> to Mycorrhiza Wiki directly.</p>
{% func HelpEmptyErrorHTML(lc *l18n.Localizer) %}
<h1>{%s lc.Get("help.empty_error_title") %}</h1>
<p>{%s lc.Get("help.empty_error_line_1") %}</p>
<p>{%s lc.Get("help.empty_error_line_2a") %} <a class="wikilink wikilink_external wikilink_https" href="https://github.com/bouncepaw/mycorrhiza">{%s lc.Get("help.empty_error_link") %}</a> {%s lc.Get("help.empty_error_line_2b") %}</p>
{% endfunc %}
{% func helpTopicsHTML() %}
{% func helpTopicsHTML(lang string, lc *l18n.Localizer) %}
<aside class="help-topics layout-card">
<h2 class="layout-card__title">Help topics</h2>
<h2 class="layout-card__title">{%s lc.GetWithLocale(lang, "help.topics") %}</h2>
<ul class="help-topics__list">
<li><a href="/help/en">Main</a></li>
<li><a href="/help/en/hypha">Hypha</a>
<li><a href="/help/{%s lang %}">{%s lc.GetWithLocale(lang, "help.main") %}</a></li>
<li><a href="/help/{%s lang %}/hypha">{%s lc.GetWithLocale(lang, "help.hypha") %}</a>
<ul>
<li><a href="/help/en/attachment">Attachment</a></li>
<li><a href="/help/{%s lang %}/attachment">{%s lc.GetWithLocale(lang, "help.attachment") %}</a></li>
</ul>
</li>
<li><a href="/help/en/mycomarkup">Mycomarkup</a></li>
<li>Interface
<li><a href="/help/{%s lang %}/mycomarkup">{%s lc.GetWithLocale(lang, "help.mycomarkup") %}</a></li>
<li>{%s lc.GetWithLocale(lang, "help.interface") %}
<ul>
<li><a href="/help/en/prevnext">Previous/next</a></li>
<li><a href="/help/en/top_bar">Top bar</a></li>
<li><a href="/help/en/sibling_hyphae_section">Sibling hyphae</a></li>
<li><a href="/help/{%s lang %}/prevnext">{%s lc.GetWithLocale(lang, "help.prevnext") %}</a></li>
<li><a href="/help/{%s lang %}/top_bar">{%s lc.GetWithLocale(lang, "help.top_bar") %}</a></li>
<li><a href="/help/{%s lang %}/sibling_hyphae_section">{%s lc.GetWithLocale(lang, "help.sibling_hyphae") %}</a></li>
<li>...</li>
</ul>
</li>
<li>Special pages
<li>{%s lc.GetWithLocale(lang, "help.special_pages") %}
<ul>
<li><a href="/help/en/recent_changes">Recent changes</a></li>
<li><a href="/help/{%s lang %}/recent_changes">{%s lc.GetWithLocale(lang, "help.recent_changes") %}</a></li>
</ul>
</li>
<li>Configuration (for administrators)
<li>{%s lc.GetWithLocale(lang, "help.configuration") %}
<ul>
<li><a href="/help/en/lock">Lock</a></li>
<li><a href="/help/en/whitelist">Whitelist</a></li>
<li><a href="/help/en/telegram">Telegram authorization</a></li>
<li><a href="/help/{%s lang %}/lock">{%s lc.GetWithLocale(lang, "help.lock") %}</a></li>
<li><a href="/help/{%s lang %}/whitelist">{%s lc.GetWithLocale(lang, "help.whitelist") %}</a></li>
<li><a href="/help/{%s lang %}/telegram">{%s lc.GetWithLocale(lang, "help.telegram") %}</a></li>
<li>...</li>
</ul>
</li>
@ -192,10 +193,10 @@ It outputs a poorly formatted JSON, but it works and is valid.
<a class="help-topic-badge" href="/help/{%s lang %}/{%s topic %}">?</a>
{% endfunc %}
{% func UserListHTML() %}
{% func UserListHTML(lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width user-list">
<h1>List of users</h1>
<h1>{%s lc.Get("ui.users_heading") %}</h1>
{% code
var (
admins = make([]string, 0)
@ -214,19 +215,19 @@ for u := range user.YieldUsers() {
}
%}
<section>
<h2>Admins</h2>
<h2>{%s lc.Get("ui.users_admins") %}</h2>
<ol>{% for _, name := range admins %}
<li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol>
</section>
<section>
<h2>Moderators</h2>
<h2>{%s lc.Get("ui.users_moderators") %}</h2>
<ol>{% for _, name := range moderators %}
<li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol>
</section>
<section>
<h2>Editors</h2>
<h2>{%s lc.Get("ui.users_editors") %}</h2>
<ol>{% for _, name := range editors %}
<li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol>
@ -235,11 +236,11 @@ for u := range user.YieldUsers() {
</div>
{% endfunc %}
{% func HyphaListHTML() %}
{% func HyphaListHTML(lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<h1>List of hyphae</h1>
<p>This wiki has {%d hyphae.Count() %} hyphae.</p>
<h1>{%s lc.Get("ui.list_heading") %}</h1>
<p>{%s lc.GetPlural("ui.list_desc", hyphae.Count()) %}</p>
<ul class="hypha-list">
{% for h := range hyphae.YieldExistingHyphae() %}
<li class="hypha-list__entry">
@ -254,25 +255,25 @@ for u := range user.YieldUsers() {
</div>
{% endfunc %}
{% func AboutHTML() %}
{% func AboutHTML(lc *l18n.Localizer) %}
<div class="layout">
<main class="main-width">
<section>
<h1>About {%s cfg.WikiName %}</h1>
<h1>{%s lc.Get("ui.about_title", &l18n.Replacements{"name": cfg.WikiName}) %}</h1>
<ul>
<li><b><a href="https://mycorrhiza.wiki">Mycorrhiza Wiki</a> version:</b> 1.5.0</li>
<li><b>{%s= lc.Get("ui.about_version", &l18n.Replacements{"pre": "<a href=\"https://mycorrhiza.wiki\">", "post": "</a>"}) %}</b> 1.5.0</li>
{%- if cfg.UseAuth -%}
<li><b>User count:</b> {%dul user.Count() %}</li>
<li><b>Home page:</b> <a href="/">{%s cfg.HomeHypha %}</a></li>
<li><b>Administrators:</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%}
<li><b>{%s lc.Get("ui.about_usercount") %}</b> {%dul user.Count() %}</li>
<li><b>{%s lc.Get("ui.about_homepage") %}</b> <a href="/">{%s cfg.HomeHypha %}</a></li>
<li><b>{%s lc.Get("ui.about_admins") %}</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%}
{%- if i > 0 -%}<span aria-hidden="true">, </span>
{%- endif -%}
<a href="/hypha/{%s cfg.UserHypha %}/{%s username %}">{%s username %}</a>{%- endfor -%}</li>
{%- else -%}
<li>This wiki does not use authorization</li>
<li>{%s lc.Get("ui.about_noauth") %}</li>
{%- endif -%}
</ul>
<p>See <a href="/list">/list</a> for information about hyphae on this wiki.</p>
<p>{%s= lc.Get("ui.about_hyphae", &l18n.Replacements{"link": "<a href=\"/list\">/list</a>"}) %}</p>
</section>
</main>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@ import (
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/cfg"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/views"
@ -32,9 +33,10 @@ func initAdmin(r *mux.Router) {
// handlerAdmin provides the admin panel.
func handlerAdmin(w http.ResponseWriter, rq *http.Request) {
var lc = l18n.FromRequest(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
io.WriteString(w, views.BaseHTML("Admin panel", views.AdminPanelHTML(), user.FromRequest(rq)))
io.WriteString(w, views.BaseHTML(lc.Get("admin.panel_title"), views.AdminPanelHTML(lc), lc, user.FromRequest(rq)))
}
// handlerAdminShutdown kills the wiki.
@ -67,8 +69,9 @@ func handlerAdminUsers(w http.ResponseWriter, rq *http.Request) {
return less
})
html := views.AdminUsersPanelHTML(userList)
html = views.BaseHTML("Manage users", html, user.FromRequest(rq))
var lc = l18n.FromRequest(rq)
html := views.AdminUsersPanelHTML(userList, lc)
html = views.BaseHTML(lc.Get("admin.users_title"), html, lc, user.FromRequest(rq))
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
io.WriteString(w, html)
@ -105,8 +108,9 @@ func handlerAdminUserEdit(w http.ResponseWriter, rq *http.Request) {
f.Put("group", u.Group)
html := views.AdminUserEditHTML(u, f)
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(rq))
var lc = l18n.FromRequest(rq)
html := views.AdminUserEditHTML(u, f, lc)
html = views.BaseHTML(fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html, lc, user.FromRequest(rq))
if f.HasError() {
w.WriteHeader(http.StatusBadRequest)
@ -134,8 +138,9 @@ func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) {
}
}
html := views.AdminUserDeleteHTML(u, util.NewFormData())
html = views.BaseHTML(fmt.Sprintf("User %s", u.Name), html, user.FromRequest(rq))
var lc = l18n.FromRequest(rq)
html := views.AdminUserDeleteHTML(u, util.NewFormData(), lc)
html = views.BaseHTML(fmt.Sprintf(lc.Get("admin.user_title"), u.Name), html, l18n.FromRequest(rq), user.FromRequest(rq))
if f.HasError() {
w.WriteHeader(http.StatusBadRequest)
@ -145,10 +150,11 @@ func handlerAdminUserDelete(w http.ResponseWriter, rq *http.Request) {
}
func handlerAdminUserNew(w http.ResponseWriter, rq *http.Request) {
var lc = l18n.FromRequest(rq)
if rq.Method == http.MethodGet {
// New user form
html := views.AdminUserNewHTML(util.NewFormData())
html = views.BaseHTML("New user", html, user.FromRequest(rq))
html := views.AdminUserNewHTML(util.NewFormData(), lc)
html = views.BaseHTML(lc.Get("admin.newuser_title"), html, lc, user.FromRequest(rq))
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
io.WriteString(w, html)
@ -159,8 +165,8 @@ func handlerAdminUserNew(w http.ResponseWriter, rq *http.Request) {
err := user.Register(f.Get("name"), f.Get("password"), f.Get("group"), "local", true)
if err != nil {
html := views.AdminUserNewHTML(f.WithError(err))
html = views.BaseHTML("New user", html, user.FromRequest(rq))
html := views.AdminUserNewHTML(f.WithError(err), lc)
html = views.BaseHTML(lc.Get("admin.newuser_title"), html, lc, user.FromRequest(rq))
w.WriteHeader(http.StatusBadRequest)
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))

View File

@ -12,6 +12,7 @@ import (
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/cfg"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/views"
@ -35,11 +36,12 @@ func initAuth(r *mux.Router) {
}
func handlerLock(w http.ResponseWriter, rq *http.Request) {
io.WriteString(w, views.LockHTML())
io.WriteString(w, views.LockHTML(l18n.FromRequest(rq)))
}
// handlerRegister both displays the register form (GET) and registers users (POST).
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq)
util.PrepareRq(rq)
if !cfg.AllowRegistration {
w.WriteHeader(http.StatusForbidden)
@ -48,8 +50,9 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) {
io.WriteString(
w,
views.BaseHTML(
"Register",
lc.Get("auth.register_title"),
views.RegisterHTML(rq),
lc,
user.FromRequest(rq),
),
)
@ -66,11 +69,13 @@ func handlerRegister(w http.ResponseWriter, rq *http.Request) {
fmt.Fprint(
w,
views.BaseHTML(
"Register",
lc.Get("auth.register_title"),
fmt.Sprintf(
`<main class="main-width"><p>%s</p><p><a href="/register">Try again<a></p></main>`,
`<main class="main-width"><p>%s</p><p><a href="/register">%s<a></p></main>`,
err.Error(),
lc.Get("auth.try_again"),
),
lc,
user.FromRequest(rq),
),
)
@ -87,6 +92,7 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) {
var (
u = user.FromRequest(rq)
can = u != nil
lc = l18n.FromRequest(rq)
)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if can {
@ -96,7 +102,7 @@ func handlerLogout(w http.ResponseWriter, rq *http.Request) {
log.Println("Unknown user tries to log out")
w.WriteHeader(http.StatusForbidden)
}
w.Write([]byte(views.BaseHTML("Logout?", views.LogoutHTML(can), u)))
w.Write([]byte(views.BaseHTML(lc.Get("auth.logout_title"), views.LogoutHTML(can, lc), lc, u)))
}
// handlerLogoutConfirm logs the user out.
@ -116,11 +122,13 @@ func handlerLogin(w http.ResponseWriter, rq *http.Request) {
} else {
w.WriteHeader(http.StatusForbidden)
}
w.Write([]byte(views.BaseHTML("Login", views.LoginHTML(), user.EmptyUser())))
lc := l18n.FromRequest(rq)
w.Write([]byte(views.BaseHTML(lc.Get("auth.login_title"), views.LoginHTML(lc), lc, user.EmptyUser())))
}
func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
// Note there is no lock here.
lc := l18n.FromRequest(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
rq.ParseForm()
var (
@ -150,11 +158,14 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
fmt.Fprint(
w,
views.BaseHTML(
"Error",
lc.Get("ui.error"),
fmt.Sprintf(
`<main class="main-width"><p>Could not authorize using Telegram.</p><p>%s</p><p><a href="/login">Go to the login page<a></p></main>`,
`<main class="main-width"><p>%s</p><p>%s</p><p><a href="/login">%s<a></p></main>`,
lc.Get("auth.error_telegram"),
err.Error(),
lc.Get("auth.go_login"),
),
lc,
user.FromRequest(rq),
),
)
@ -170,9 +181,12 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
views.BaseHTML(
"Error",
fmt.Sprintf(
`<main class="main-width"><p>Could not authorize using Telegram.</p><p>%s</p><p><a href="/login">Go to the login page<a></p></main>`,
`<main class="main-width"><p>%s</p><p>%s</p><p><a href="/login">%s<a></p></main>`,
lc.Get("auth.error_telegram"),
err.Error(),
lc.Get("auth.go_login"),
),
lc,
user.FromRequest(rq),
),
)
@ -186,6 +200,7 @@ func handlerTelegramLogin(w http.ResponseWriter, rq *http.Request) {
//
// TODO: merge into handlerLogin as POST method.
func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq)
util.PrepareRq(rq)
var (
username = util.CanonicalName(rq.PostFormValue("username"))
@ -193,7 +208,7 @@ func handlerLoginData(w http.ResponseWriter, rq *http.Request) {
err = user.LoginDataHTTP(w, rq, username, password)
)
if err != "" {
w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err), user.EmptyUser())))
w.Write([]byte(views.BaseHTML(err, views.LoginErrorHTML(err, lc), lc, user.EmptyUser())))
} else {
http.Redirect(w, rq, "/", http.StatusSeeOther)
}

View File

@ -1,13 +1,13 @@
package web
import (
"fmt"
"io"
"net/http"
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/views"
@ -20,10 +20,14 @@ func initBacklinks(r *mux.Router) {
// handlerBacklinks lists all backlinks to a hypha.
func handlerBacklinks(w http.ResponseWriter, rq *http.Request) {
hyphaName := util.HyphaNameFromRq(rq, "backlinks")
var (
hyphaName = util.HyphaNameFromRq(rq, "backlinks")
lc = l18n.FromRequest(rq)
)
util.HTTP200Page(w, views.BaseHTML(
fmt.Sprintf("Backlinks to %s", util.BeautifulName(hyphaName)),
views.BacklinksHTML(hyphaName, hyphae.YieldHyphaBacklinks),
lc.Get("ui.backlinks_title", &l18n.Replacements{"query": util.BeautifulName(hyphaName)}),
views.BacklinksHTML(hyphaName, hyphae.YieldHyphaBacklinks, lc),
lc,
user.FromRequest(rq)))
}

View File

@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/views"
@ -39,9 +40,11 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) {
}
log.Println("Found", len(revs), "revisions for", hyphaName)
var lc = l18n.FromRequest(rq)
util.HTTP200Page(w, views.BaseHTML(
fmt.Sprintf("History of %s", util.BeautifulName(hyphaName)),
views.HistoryHTML(rq, hyphaName, list),
fmt.Sprintf(lc.Get("ui.history_title"), util.BeautifulName(hyphaName)),
views.HistoryHTML(rq, hyphaName, list, lc),
lc,
user.FromRequest(rq)))
}
@ -49,7 +52,12 @@ func handlerHistory(w http.ResponseWriter, rq *http.Request) {
func handlerRecentChanges(w http.ResponseWriter, rq *http.Request) {
// Error ignored: filtered by regex
n, _ := strconv.Atoi(mux.Vars(rq)["count"])
util.HTTP200Page(w, views.BaseHTML(strconv.Itoa(n)+" recent changes", views.RecentChangesHTML(n), user.FromRequest(rq)))
var lc = l18n.FromRequest(rq)
util.HTTP200Page(w, views.BaseHTML(
lc.GetPlural("ui.recent_title", n),
views.RecentChangesHTML(n, lc),
lc,
user.FromRequest(rq)))
}
// genericHandlerOfFeeds is a helper function for the web feed handlers.

View File

@ -12,6 +12,7 @@ import (
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/shroom"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
@ -35,7 +36,7 @@ func initMutators(r *mux.Router) {
func factoryHandlerAsker(
actionPath string,
asker func(*user.User, *hyphae.Hypha) (error, string),
succTitleTemplate string,
succTitleKey string,
succPageTemplate func(*http.Request, string, bool) string,
) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, rq *http.Request) {
@ -44,10 +45,12 @@ func factoryHandlerAsker(
hyphaName = util.HyphaNameFromRq(rq, actionPath)
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
if err, errtitle := asker(u, h); err != nil {
httpErr(
w,
lc,
http.StatusInternalServerError,
hyphaName,
errtitle,
@ -57,8 +60,9 @@ func factoryHandlerAsker(
util.HTTP200Page(
w,
views.BaseHTML(
fmt.Sprintf(succTitleTemplate, util.BeautifulName(hyphaName)),
fmt.Sprintf(lc.Get(succTitleKey), util.BeautifulName(hyphaName)),
succPageTemplate(rq, hyphaName, h.Exists),
lc,
u))
}
}
@ -66,21 +70,21 @@ func factoryHandlerAsker(
var handlerUnattachAsk = factoryHandlerAsker(
"unattach-ask",
shroom.CanUnattach,
"Unattach %s?",
"ui.ask_unattach",
views.UnattachAskHTML,
)
var handlerDeleteAsk = factoryHandlerAsker(
"delete-ask",
shroom.CanDelete,
"Delete %s?",
"ui.ask_delete",
views.DeleteAskHTML,
)
var handlerRenameAsk = factoryHandlerAsker(
"rename-ask",
shroom.CanRename,
"Rename %s?",
"ui.ask_rename",
views.RenameAskHTML,
)
@ -94,9 +98,10 @@ func factoryHandlerConfirmer(
hyphaName = util.HyphaNameFromRq(rq, actionPath)
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
if hop, errtitle := confirmer(h, u, rq); hop.HasErrors() {
httpErr(w, http.StatusInternalServerError, hyphaName,
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
errtitle,
hop.FirstErrorText())
return
@ -124,6 +129,7 @@ func handlerRenameConfirm(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
var (
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
hyphaName = util.HyphaNameFromRq(rq, "rename-confirm")
oldHypha = hyphae.ByName(hyphaName)
newName = util.CanonicalName(rq.PostFormValue("new-name"))
@ -132,7 +138,7 @@ func handlerRenameConfirm(w http.ResponseWriter, rq *http.Request) {
)
hop, errtitle := shroom.RenameHypha(oldHypha, newHypha, recursive, u)
if hop.HasErrors() {
httpErr(w, http.StatusInternalServerError, hyphaName,
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
errtitle,
hop.FirstErrorText())
return
@ -150,9 +156,10 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
textAreaFill string
err error
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
if err, errtitle := shroom.CanEdit(u, h); err != nil {
httpErr(w, http.StatusInternalServerError, hyphaName,
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
errtitle,
err.Error())
return
@ -161,19 +168,20 @@ func handlerEdit(w http.ResponseWriter, rq *http.Request) {
textAreaFill, err = shroom.FetchTextPart(h)
if err != nil {
log.Println(err)
httpErr(w, http.StatusInternalServerError, hyphaName,
"Error",
"Could not fetch text data")
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
lc.Get("ui.error"),
lc.Get("ui.error_text_fetch"))
return
}
} else {
warning = `<p class="warning warning_new-hypha">You are creating a new hypha.</p>`
warning = fmt.Sprintf(`<p class="warning warning_new-hypha">%s</p>`, lc.Get("ui.edit_new_hypha"))
}
util.HTTP200Page(
w,
views.BaseHTML(
fmt.Sprintf("Edit %s", util.BeautifulName(hyphaName)),
fmt.Sprintf(lc.Get("edit.title"), util.BeautifulName(hyphaName)),
views.EditHTML(rq, hyphaName, textAreaFill, warning),
lc,
u))
}
@ -187,6 +195,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
action = rq.PostFormValue("action")
message = rq.PostFormValue("message")
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
hop *history.HistoryOp
errtitle string
)
@ -194,7 +203,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
if action != "Preview" {
hop, errtitle = shroom.UploadText(h, []byte(textData), message, u)
if hop.HasErrors() {
httpErr(w, http.StatusForbidden, hyphaName,
httpErr(w, lc, http.StatusForbidden, hyphaName,
errtitle,
hop.FirstErrorText())
return
@ -207,7 +216,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
util.HTTP200Page(
w,
views.BaseHTML(
fmt.Sprintf("Preview of %s", util.BeautifulName(hyphaName)),
fmt.Sprintf(lc.Get("edit.preview_title"), util.BeautifulName(hyphaName)),
views.PreviewHTML(
rq,
hyphaName,
@ -215,6 +224,7 @@ func handlerUploadText(w http.ResponseWriter, rq *http.Request) {
message,
"",
mycomarkup.BlocksToHTML(ctx, mycomarkup.BlockTree(ctx))),
lc,
u))
} else {
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)
@ -229,15 +239,16 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
hyphaName = util.HyphaNameFromRq(rq, "upload-binary")
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
file, handler, err = rq.FormFile("binary")
)
if err != nil {
httpErr(w, http.StatusInternalServerError, hyphaName,
"Error",
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
lc.Get("ui.error"),
err.Error())
}
if err, errtitle := shroom.CanAttach(u, h); err != nil {
httpErr(w, http.StatusInternalServerError, hyphaName,
httpErr(w, lc, http.StatusInternalServerError, hyphaName,
errtitle,
err.Error())
}
@ -257,7 +268,7 @@ func handlerUploadBinary(w http.ResponseWriter, rq *http.Request) {
)
if hop.HasErrors() {
httpErr(w, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText())
httpErr(w, lc, http.StatusInternalServerError, hyphaName, errtitle, hop.FirstErrorText())
return
}
http.Redirect(w, rq, "/hypha/"+hyphaName, http.StatusSeeOther)

View File

@ -14,6 +14,7 @@ import (
"github.com/bouncepaw/mycorrhiza/cfg"
"github.com/bouncepaw/mycorrhiza/history"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/mimetype"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
@ -41,11 +42,13 @@ func handlerAttachment(w http.ResponseWriter, rq *http.Request) {
hyphaName = util.HyphaNameFromRq(rq, "attachment")
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
util.HTTP200Page(w,
views.BaseHTML(
fmt.Sprintf("Attachment of %s", util.BeautifulName(hyphaName)),
lc.Get("ui.attach_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName)}),
views.AttachmentMenuHTML(rq, h, u),
lc,
u))
}
@ -58,11 +61,13 @@ func handlerPrimitiveDiff(w http.ResponseWriter, rq *http.Request) {
hyphaName = util.CanonicalName(shorterUrl[firstSlashIndex+1:])
h = hyphae.ByName(hyphaName)
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
util.HTTP200Page(w,
views.BaseHTML(
fmt.Sprintf("Diff of %s at %s", util.BeautifulName(hyphaName), revHash),
lc.Get("ui.diff_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}),
views.PrimitiveDiffHTML(rq, h, u, revHash),
lc,
u))
}
@ -95,12 +100,13 @@ func handlerRevisionText(w http.ResponseWriter, rq *http.Request) {
func handlerRevision(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
var (
lc = l18n.FromRequest(rq)
shorterUrl = strings.TrimPrefix(rq.URL.Path, "/rev/")
firstSlashIndex = strings.IndexRune(shorterUrl, '/')
revHash = shorterUrl[:firstSlashIndex]
hyphaName = util.CanonicalName(shorterUrl[firstSlashIndex+1:])
h = hyphae.ByName(hyphaName)
contents = fmt.Sprintf(`<p>This hypha had no text at this revision.</p>`)
contents = fmt.Sprintf(`<p>%s</p>`, lc.Get("ui.revision_no_text"))
textContents, err = history.FileAtRevision(h.TextPartPath(), revHash)
u = user.FromRequest(rq)
)
@ -110,6 +116,7 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
}
page := views.RevisionHTML(
rq,
lc,
h,
contents,
revHash,
@ -119,8 +126,9 @@ func handlerRevision(w http.ResponseWriter, rq *http.Request) {
_, _ = fmt.Fprint(
w,
views.BaseHTML(
fmt.Sprintf(`%s at %s`, util.BeautifulName(hyphaName), revHash),
lc.Get("ui.revision_title", &l18n.Replacements{"name": util.BeautifulName(hyphaName), "rev": revHash}),
page,
lc,
u,
),
)
@ -157,6 +165,7 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
contents string
openGraph string
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
if h.Exists {
fileContentsT, errT := os.ReadFile(h.TextPath)
@ -170,21 +179,23 @@ func handlerHypha(w http.ResponseWriter, rq *http.Request) {
openGraph = getOpenGraph()
}
if !os.IsNotExist(errB) {
contents = views.AttachmentHTML(h) + contents
contents = views.AttachmentHTML(h, lc) + contents
}
}
if contents == "" {
util.HTTP404Page(w,
views.BaseHTML(
util.BeautifulName(hyphaName),
views.HyphaHTML(rq, h, contents),
views.HyphaHTML(rq, lc, h, contents),
lc,
u,
openGraph))
} else {
util.HTTP200Page(w,
views.BaseHTML(
util.BeautifulName(hyphaName),
views.HyphaHTML(rq, h, contents),
views.HyphaHTML(rq, lc, h, contents),
lc,
u,
openGraph))
}

View File

@ -9,6 +9,7 @@ import (
"github.com/bouncepaw/mycorrhiza/shroom"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/views"
)
@ -23,13 +24,15 @@ func handlerTitleSearch(w http.ResponseWriter, rq *http.Request) {
var (
query = rq.FormValue("q")
u = user.FromRequest(rq)
lc = l18n.FromRequest(rq)
)
w.WriteHeader(http.StatusOK)
_, _ = io.WriteString(
w,
views.BaseHTML(
"Search: "+query,
views.TitleSearchHTML(query, shroom.YieldHyphaNamesContainingString),
lc.Get("ui.title_search_title", &l18n.Replacements{"query": query}),
views.TitleSearchHTML(query, shroom.YieldHyphaNamesContainingString, lc),
lc,
u,
),
)

View File

@ -14,6 +14,7 @@ import (
"github.com/bouncepaw/mycorrhiza/files"
"github.com/bouncepaw/mycorrhiza/help"
"github.com/bouncepaw/mycorrhiza/hyphae"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/shroom"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
@ -37,17 +38,27 @@ func initStuff(r *mux.Router) {
// handlerHelp gets the appropriate documentation or tells you where you (personally) have failed.
func handlerHelp(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq)
articlePath := strings.TrimPrefix(strings.TrimPrefix(rq.URL.Path, "/help/"), "/help")
lang := lc.Locale
if articlePath == "" {
articlePath = "en"
articlePath = lc.Locale
} else {
var slashIndex = strings.Index(articlePath, "/")
if slashIndex == -1 {
lang = articlePath
} else {
lang = articlePath[:slashIndex]
}
}
content, err := help.Get(articlePath)
if err != nil && strings.HasPrefix(err.Error(), "open") {
w.WriteHeader(http.StatusNotFound)
_, _ = io.WriteString(
w,
views.BaseHTML("Entry not found",
views.HelpHTML(views.HelpEmptyErrorHTML()),
views.BaseHTML(lc.Get("help.entry_not_found"),
views.HelpHTML(views.HelpEmptyErrorHTML(lc), lang, lc),
lc,
user.FromRequest(rq)),
)
return
@ -57,7 +68,8 @@ func handlerHelp(w http.ResponseWriter, rq *http.Request) {
_, _ = io.WriteString(
w,
views.BaseHTML(err.Error(),
views.HelpHTML(err.Error()),
views.HelpHTML(err.Error(), lang, lc),
lc,
user.FromRequest(rq)),
)
return
@ -70,8 +82,9 @@ func handlerHelp(w http.ResponseWriter, rq *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = io.WriteString(
w,
views.BaseHTML("Help",
views.HelpHTML(result),
views.BaseHTML(lc.Get("help.title"),
views.HelpHTML(result, lang, lc),
lc,
user.FromRequest(rq)),
)
}
@ -79,15 +92,17 @@ func handlerHelp(w http.ResponseWriter, rq *http.Request) {
// handlerList shows a list of all hyphae in the wiki in random order.
func handlerList(w http.ResponseWriter, rq *http.Request) {
u := user.FromRequest(rq)
var lc = l18n.FromRequest(rq)
util.PrepareRq(rq)
util.HTTP200Page(w, views.BaseHTML("List of pages", views.HyphaListHTML(), u))
util.HTTP200Page(w, views.BaseHTML(lc.Get("ui.list_title"), views.HyphaListHTML(lc), lc, u))
}
// handlerReindex reindexes all hyphae by checking the wiki storage directory anew.
func handlerReindex(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
if ok := user.CanProceed(rq, "reindex"); !ok {
httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be an admin to reindex hyphae.")
var lc = l18n.FromRequest(rq)
httpErr(w, lc, http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.no_rights"), lc.Get("ui.reindex_no_rights"))
log.Println("Rejected", rq.URL)
return
}
@ -103,7 +118,8 @@ func handlerReindex(w http.ResponseWriter, rq *http.Request) {
func handlerUpdateHeaderLinks(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
if ok := user.CanProceed(rq, "update-header-links"); !ok {
httpErr(w, http.StatusForbidden, cfg.HomeHypha, "Not enough rights", "You must be a moderator to update header links.")
var lc = l18n.FromRequest(rq)
httpErr(w, lc, http.StatusForbidden, cfg.HomeHypha, lc.Get("ui.no_rights"), lc.Get("ui.header_no_rights"))
log.Println("Rejected", rq.URL)
return
}
@ -119,8 +135,8 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
amountOfHyphae = hyphae.Count()
)
if amountOfHyphae == 0 {
httpErr(w, http.StatusNotFound, cfg.HomeHypha, "There are no hyphae",
"It is impossible to display a random hypha because the wiki does not contain any hyphae")
var lc = l18n.FromRequest(rq)
httpErr(w, lc, http.StatusNotFound, cfg.HomeHypha, lc.Get("ui.random_no_hyphae"), lc.Get("ui.random_no_hyphae_tip"))
return
}
i := rand.Intn(amountOfHyphae)
@ -137,7 +153,11 @@ func handlerRandom(w http.ResponseWriter, rq *http.Request) {
func handlerAbout(w http.ResponseWriter, rq *http.Request) {
w.Header().Set("Content-Type", "text/html;charset=utf-8")
w.WriteHeader(http.StatusOK)
_, err := io.WriteString(w, views.BaseHTML("About "+cfg.WikiName, views.AboutHTML(), user.FromRequest(rq)))
var (
lc = l18n.FromRequest(rq)
title = lc.Get("ui.about_title", &l18n.Replacements{"name": cfg.WikiName})
)
_, err := io.WriteString(w, views.BaseHTML(title, views.AboutHTML(lc), lc, user.FromRequest(rq)))
if err != nil {
log.Println(err)
}

View File

@ -14,6 +14,7 @@ import (
"github.com/gorilla/mux"
"github.com/bouncepaw/mycorrhiza/cfg"
"github.com/bouncepaw/mycorrhiza/l18n"
"github.com/bouncepaw/mycorrhiza/static"
"github.com/bouncepaw/mycorrhiza/user"
"github.com/bouncepaw/mycorrhiza/util"
@ -23,7 +24,7 @@ import (
var stylesheets = []string{"default.css", "custom.css"}
// httpErr is used by many handlers to signal errors in a compact way.
func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
func httpErr(w http.ResponseWriter, lc *l18n.Localizer, status int, name, title, errMsg string) {
log.Println(errMsg, "for", name)
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
w.WriteHeader(status)
@ -32,10 +33,12 @@ func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
views.BaseHTML(
title,
fmt.Sprintf(
`<main class="main-width"><p>%s. <a href="/hypha/%s">Go back to the hypha.<a></p></main>`,
`<main class="main-width"><p>%s. <a href="/hypha/%s">%s<a></p></main>`,
errMsg,
name,
lc.Get("ui.error_go_back"),
),
lc,
user.EmptyUser(),
),
)
@ -54,9 +57,10 @@ func handlerStyle(w http.ResponseWriter, rq *http.Request) {
}
func handlerUserList(w http.ResponseWriter, rq *http.Request) {
lc := l18n.FromRequest(rq)
w.Header().Set("Content-Type", mime.TypeByExtension(".html"))
w.WriteHeader(http.StatusOK)
w.Write([]byte(views.BaseHTML("User list", views.UserListHTML(), user.FromRequest(rq))))
w.Write([]byte(views.BaseHTML(lc.Get("ui.users_title"), views.UserListHTML(lc), lc, user.FromRequest(rq))))
}
func handlerRobotsTxt(w http.ResponseWriter, rq *http.Request) {