uploads: notes on english and russian

This commit is contained in:
E. S. 2024-03-14 21:53:34 +00:00
parent 53d8861dbb
commit 699affded9
14 changed files with 162 additions and 133 deletions

View File

@ -243,13 +243,14 @@ class AdminHandler extends request_handler {
set_title('$blog_upload'); set_title('$blog_upload');
render('admin/uploads', render('admin/uploads',
error: $error, error: $error,
uploads: $uploads); uploads: $uploads,
langs: PostLanguage::cases());
} }
function POST_uploads() { function POST_uploads() {
csrf_check('addupl'); csrf_check('addupl');
list($custom_name, $note) = input('name, note'); list($custom_name, $note_en, $note_ru) = input('name, note_en, note_ru');
if (!isset($_FILES['files'])) if (!isset($_FILES['files']))
redirect('/admin/uploads/?error='.urlencode('no file')); redirect('/admin/uploads/?error='.urlencode('no file'));
@ -266,7 +267,8 @@ class AdminHandler extends request_handler {
} }
if (count($files) > 1) { if (count($files) > 1) {
$note = ''; $note_en = '';
$note_ru = '';
$custom_name = ''; $custom_name = '';
} }
@ -285,12 +287,13 @@ class AdminHandler extends request_handler {
$upload_id = uploads::add( $upload_id = uploads::add(
$f['tmp_name'], $f['tmp_name'],
$name, $name,
$note); $note_en,
$note_ru);
if (!$upload_id) if (!$upload_id)
redirect('/admin/uploads/?error='.urlencode('failed to create upload')); redirect('/admin/uploads/?error='.urlencode('failed to create upload'));
admin_log(new \AdminActions\UploadsAdd($upload_id, $name, $note)); admin_log(new \AdminActions\UploadsAdd($upload_id, $name, $note_en, $note_ru));
} }
redirect('/admin/uploads/'); redirect('/admin/uploads/');
@ -308,7 +311,10 @@ class AdminHandler extends request_handler {
} }
function POST_upload_edit_note() { function POST_upload_edit_note() {
list($id, $note) = input('i:id, note'); list($id, $note, $lang) = input('i:id, note, lang');
$lang = PostLanguage::tryFrom($lang);
if (!$lang)
not_found();
$upload = uploads::get($id); $upload = uploads::get($id);
if (!$upload) if (!$upload)
@ -316,16 +322,19 @@ class AdminHandler extends request_handler {
csrf_check('editupl'.$id); csrf_check('editupl'.$id);
$upload->setNote($note); $upload->setNote($lang, $note);
admin_log(new \AdminActions\UploadsEditNote($id, $note)); admin_log(new \AdminActions\UploadsEditNote($id, $note, $lang->value));
redirect('/admin/uploads/'); redirect('/admin/uploads/');
} }
function POST_ajax_md_preview() { function POST_ajax_md_preview() {
ensure_xhr(); ensure_xhr();
list($md, $title, $use_image_previews) = input('md, title, b:use_image_previews'); list($md, $title, $use_image_previews, $lang) = input('md, title, b:use_image_previews, lang');
$html = markup::markdownToHtml($md, $use_image_previews); $lang = PostLanguage::tryFrom($lang);
if (!$lang)
invalid_request();
$html = markup::markdownToHtml($md, $use_image_previews, $lang);
$ctx = skin('admin'); $ctx = skin('admin');
$html = $ctx->markdownPreview( $html = $ctx->markdownPreview(
unsafe_html: $html, unsafe_html: $html,

View File

@ -81,7 +81,8 @@ extend(AdminWriteEditForm.prototype, {
this.previewRequest.abort(); this.previewRequest.abort();
var params = { var params = {
md: this.form.elements.text.value, md: this.form.elements.text.value,
use_image_previews: this.isPage() ? 1 : 0 use_image_previews: this.isPage() ? 1 : 0,
lang: this.getCurrentLang()
}; };
if (this.isPost()) if (this.isPost())
params.title = this.form.elements.title.value; params.title = this.form.elements.title.value;

View File

@ -95,7 +95,13 @@
font-size: $fs - 2px; font-size: $fs - 2px;
} }
.blog-upload-item-note { .blog-upload-item-note {
padding: 0 0 4px; padding: 8px 0 0;
> span {
background-color: $hover-hl;
padding: 1px 5px;
color: $dark-grey;
margin-right: 6px;
}
} }
.blog-upload-item-md { .blog-upload-item-md {
margin-top: 3px; margin-top: 3px;
@ -376,51 +382,43 @@ body.wide .blog-post {
color: $grey; color: $grey;
} }
.blog-list-table-wrap {
.blog-list {
&-wrap {
padding: 5px 0; padding: 5px 0;
} }
.blog-list-table {
border-collapse: collapse; &-item {
display: block;
padding: 6px 8px;
margin-left: -8px;
margin-right: -8px;
font-size: $fs;
//line-height: 140%;
&:hover {
text-decoration: none;
background-color: $hover-hl;
@include radius(3px);
} }
.blog-list-table td {
vertical-align: top; &-date {
padding: 0 0 13px;
}
.blog-list-table tr:last-child td {
padding-bottom: 0;
}
td.blog-item-date-cell {
width: 1px;
white-space: nowrap;
//text-align: right;
padding-right: 10px;
}
.blog-item-date {
color: $grey; color: $grey;
//text-transform: lowercase; float: left;
} }
td.blog-item-title-cell { &-title {
margin-left: 70px;
text-align: left; text-align: left;
} }
.blog-item-title { &.is-hidden &-title {
//font-weight: bold;
}
.blog-item-row {
font-size: $fs;
line-height: 140%;
}
.blog-item-row.ishidden a.blog-item-title {
color: $fg; color: $fg;
} }
.blog-item-row-year {
td {
padding-top: 10px;
//text-align: right;
font-size: $fs + 2px;
//letter-spacing: -0.5px;
}
&:first-child td {
padding-top: 0;
} }
} }
.blog-list-title {
font-size: $fs + 2px;
padding-top: 14px;
margin-bottom: 8px;
&:first-child { padding-top: 0; }
}

View File

@ -282,9 +282,10 @@ table.contacts div.note {
max-width: 100%; max-width: 100%;
} }
.md-image-note { .md-image-note {
line-height: 150%; line-height: 130%;
color: $dark-grey; color: $dark-grey;
padding: 2px 0 4px; padding: 8px 0 4px;
font-style: italic;
} }
.md-video video { .md-video video {

View File

@ -1,6 +1,6 @@
@import '../vars'; @import '../vars';
$form-field-label-width: 120px; $form-field-label-width: 160px;
form { display: block; margin: 0; } form { display: block; margin: 0; }

View File

@ -7,7 +7,8 @@ class UploadsAdd extends BaseAction {
public function __construct( public function __construct(
public int $uploadId, public int $uploadId,
public string $name, public string $name,
public string $note public string $noteEn,
public string $noteRu
) {} ) {}
} }

View File

@ -6,7 +6,8 @@ class UploadsEditNote extends BaseAction {
public function __construct( public function __construct(
public int $uploadId, public int $uploadId,
public string $note public string $note,
public string $lang
) {} ) {}
} }

View File

@ -1,12 +1,16 @@
<?php <?php
require_once 'engine/skin.php';
require_once 'lib/posts.php';
class MyParsedown extends ParsedownExtended { class MyParsedown extends ParsedownExtended {
protected array $options; protected array $options;
function __construct( function __construct(
?array $opts = null, ?array $opts = null,
protected bool $useImagePreviews = false protected bool $useImagePreviews = false,
protected ?PostLanguage $lang = null,
) { ) {
$parsedown_opts = [ $parsedown_opts = [
'tables' => [ 'tables' => [
@ -44,15 +48,13 @@ class MyParsedown extends ParsedownExtended {
unset($result['element']['text']); unset($result['element']['text']);
$ctx = self::getSkinContext(); $ctx = self::getSkinContext();
$result['element']['rawHtml'] = $ctx->fileupload($upload->name, $upload->getDirectUrl(), $upload->note, $upload->getSize()); $result['element']['rawHtml'] = $ctx->fileupload($upload->name, $upload->getDirectUrl(), $upload->noteRu, $upload->getSize());
return $result; return $result;
} }
} }
protected function inlineImage($excerpt) { protected function inlineImage($excerpt) {
global $config;
if (preg_match('/^{image:([\w]{8}),(.*?)}{\/image}/', $excerpt['text'], $matches)) { if (preg_match('/^{image:([\w]{8}),(.*?)}{\/image}/', $excerpt['text'], $matches)) {
$random_id = $matches[1]; $random_id = $matches[1];
@ -115,7 +117,7 @@ class MyParsedown extends ParsedownExtended {
url: $image_url, url: $image_url,
direct_url: $image->getDirectUrl(), direct_url: $image->getDirectUrl(),
note: $image->note note: $this->lang !== null && $this->lang == PostLanguage::Russian ? $image->noteRu : $image->noteEn
); );
return $result; return $result;

View File

@ -1,11 +1,14 @@
<?php <?php
require_once 'lib/ext/MyParsedown.php'; require_once 'lib/ext/MyParsedown.php';
require_once 'lib/posts.php';
class markup { class markup {
public static function markdownToHtml(string $md, bool $use_image_previews = true): string { public static function markdownToHtml(string $md,
$pd = new MyParsedown(useImagePreviews: $use_image_previews); bool $use_image_previews = true,
?PostLanguage $lang = null): string {
$pd = new MyParsedown(useImagePreviews: $use_image_previews, lang: $lang);
return $pd->text($md); return $pd->text($md);
} }

View File

@ -21,7 +21,7 @@ class Post extends model {
protected array $texts = []; protected array $texts = [];
public function addText(PostLanguage $lang, string $title, string $md, bool $toc): ?PostText { public function addText(PostLanguage $lang, string $title, string $md, bool $toc): ?PostText {
$html = markup::markdownToHtml($md); $html = markup::markdownToHtml($md, lang: $lang);
$text = markup::htmlToText($html); $text = markup::htmlToText($html);
$data = [ $data = [
@ -128,7 +128,7 @@ class PostText extends model {
public function edit(array $fields) { public function edit(array $fields) {
if ($fields['md'] != $this->md) { if ($fields['md'] != $this->md) {
$fields['html'] = markup::markdownToHtml($fields['md']); $fields['html'] = markup::markdownToHtml($fields['md'], lang: $this->lang);
$fields['text'] = markup::htmlToText($fields['html']); $fields['text'] = markup::htmlToText($fields['html']);
} }
@ -141,13 +141,13 @@ class PostText extends model {
} }
public function updateHtml(): void { public function updateHtml(): void {
$html = markup::markdownToHtml($this->md); $html = markup::markdownToHtml($this->md, lang: $this->lang);
$this->html = $html; $this->html = $html;
DB()->query("UPDATE posts_texts SET html=? WHERE id=?", $html, $this->id); DB()->query("UPDATE posts_texts SET html=? WHERE id=?", $html, $this->id);
} }
public function updateText(): void { public function updateText(): void {
$html = markup::markdownToHtml($this->md); $html = markup::markdownToHtml($this->md, lang: $this->lang);
$text = markup::htmlToText($html); $text = markup::htmlToText($html);
$this->text = $text; $this->text = $text;
DB()->query("UPDATE posts_texts SET text=? WHERE id=?", $text, $this->id); DB()->query("UPDATE posts_texts SET text=? WHERE id=?", $text, $this->id);

View File

@ -19,7 +19,7 @@ class uploads {
return in_array($ext, UPLOADS_ALLOWED_EXTENSIONS); return in_array($ext, UPLOADS_ALLOWED_EXTENSIONS);
} }
static function add(string $tmp_name, string $name, string $note): ?int { static function add(string $tmp_name, string $name, string $note_en, string $note_ru): ?int {
global $config; global $config;
$name = sanitize_filename($name); $name = sanitize_filename($name);
@ -44,7 +44,8 @@ class uploads {
'image' => (int)$is_image, 'image' => (int)$is_image,
'image_w' => $image_w, 'image_w' => $image_w,
'image_h' => $image_h, 'image_h' => $image_h,
'note' => $note, 'note_ru' => $note_ru,
'note_en' => $note_en,
'downloads' => 0, 'downloads' => 0,
])) { ])) {
return null; return null;
@ -163,7 +164,8 @@ class Upload extends model {
public int $image; // TODO: remove public int $image; // TODO: remove
public int $imageW; public int $imageW;
public int $imageH; public int $imageH;
public string $note; public string $noteRu;
public string $noteEn;
function getDirectory(): string { function getDirectory(): string {
global $config; global $config;
@ -212,9 +214,9 @@ class Upload extends model {
return $md; return $md;
} }
function setNote(string $note) { function setNote(PostLanguage $lang, string $note) {
$db = DB(); $db = DB();
$db->query("UPDATE uploads SET note=? WHERE id=?", $note, $this->id); $db->query("UPDATE uploads SET note_{$lang->value}=? WHERE id=?", $note, $this->id);
} }
function isImage(): bool { function isImage(): bool {

View File

@ -2,6 +2,7 @@
namespace skin\admin; namespace skin\admin;
use PostLanguage;
use Stringable; use Stringable;
use function skin\base\layout; use function skin\base\layout;
@ -64,7 +65,7 @@ HTML;
// uploads page // uploads page
// ------------ // ------------
function uploads($ctx, $uploads, $error) { function uploads($ctx, $uploads, $error, array $langs) {
return <<<HTML return <<<HTML
{$ctx->if_true($error, $ctx->formError, $error)} {$ctx->if_true($error, $ctx->formError, $error)}
@ -91,12 +92,8 @@ return <<<HTML
</div> </div>
</div> </div>
<div class="form-field-wrap clearfix"> {$ctx->for_each($langs,
<div class="form-field-label">{$ctx->lang('blog_upload_form_note')}:</div> fn($l) => $ctx->uploads_form_note_field($l))}
<div class="form-field">
<input type="text" name="note" size="55">
</div>
</div>
<div class="form-field-wrap clearfix"> <div class="form-field-wrap clearfix">
<div class="form-field-label"></div> <div class="form-field-label"></div>
@ -108,12 +105,14 @@ return <<<HTML
</div> </div>
<div class="blog-upload-list"> <div class="blog-upload-list">
{$ctx->for_each($uploads, fn($u) => $ctx->uploadsItem( {$ctx->for_each($uploads, fn($u) => $ctx->uploads_item(
id: $u->id, id: $u->id,
name: $u->name, name: $u->name,
direct_url: $u->getDirectUrl(), direct_url: $u->getDirectUrl(),
note: $u->note, note_ru: $u->noteRu,
addslashes_note: $u->note, note_en: $u->noteEn,
addslashes_note_ru: $u->noteRu,
addslashes_note_en: $u->noteEn,
markdown: $u->getMarkdown(), markdown: $u->getMarkdown(),
size: $u->getSize(), size: $u->getSize(),
))} ))}
@ -121,17 +120,35 @@ return <<<HTML
HTML; HTML;
} }
function uploadsItem($ctx, $id, $direct_url, $note, $addslashes_note, $markdown, $name, $size) { function uploads_form_note_field($ctx, PostLanguage $lang) {
$label = $ctx->lang('blog_upload_form_note');
$label .= ' ('.$lang->name.')';
return <<<HTML
<div class="form-field-wrap clearfix">
<div class="form-field-label">{$label}:</div>
<div class="form-field">
<input type="text" name="note_{$lang->value}" size="55">
</div>
</div>
HTML;
}
function uploads_item($ctx, $id, $direct_url, $note_en, $note_ru, $addslashes_note_en, $addslashes_note_ru, $markdown, $name, $size) {
return <<<HTML return <<<HTML
<div class="blog-upload-item"> <div class="blog-upload-item">
<div class="blog-upload-item-actions"> <div class="blog-upload-item-actions">
<a href="javascript:void(0)" onclick="var mdel = ge('upload{$id}_md'); mdel.style.display = (mdel.style.display === 'none' ? 'block' : 'none')">{$ctx->lang('blog_upload_show_md')}</a> <a href="javascript:void(0)" onclick="var mdel = ge('upload{$id}_md'); mdel.style.display = (mdel.style.display === 'none' ? 'block' : 'none')">{$ctx->lang('blog_upload_show_md')}</a>
| <a href="javascript:void(0)" onclick="BlogUploadList.submitNoteEdit('/admin/uploads/edit_note/{$id}/?token={$ctx->csrf('editupl'.$id)}', prompt('Note:', '{$addslashes_note}'))">Edit note</a> | <a href="javascript:void(0)" onclick="BlogUploadList.submitNoteEdit('/admin/uploads/edit_note/{$id}/?lang=ru&token={$ctx->csrf('editupl'.$id)}', prompt('Note (Ru):', '{$addslashes_note_ru}'))">Edit note Ru</a>
| <a href="javascript:void(0)" onclick="BlogUploadList.submitNoteEdit('/admin/uploads/edit_note/{$id}/?lang=en&token={$ctx->csrf('editupl'.$id)}', prompt('Note (En):', '{$addslashes_note_en}'))">Edit note En</a>
| <a href="/admin/uploads/delete/{$id}/?token={$ctx->csrf('delupl'.$id)}" onclick="return confirm('{$ctx->lang('blog_upload_delete_confirmation')}')">{$ctx->lang('blog_upload_delete')}</a> | <a href="/admin/uploads/delete/{$id}/?token={$ctx->csrf('delupl'.$id)}" onclick="return confirm('{$ctx->lang('blog_upload_delete_confirmation')}')">{$ctx->lang('blog_upload_delete')}</a>
</div> </div>
<div class="blog-upload-item-name"><a href="{$direct_url}">{$name}</a></div> <div class="blog-upload-item-name"><a href="{$direct_url}">{$name}</a></div>
{$ctx->if_true($note, '<div class="blog-upload-item-note">'.$note.'</div>')}
<div class="blog-upload-item-info">{$size}</div> <div class="blog-upload-item-info">{$size}</div>
{$ctx->if_true($note_en,
fn() => '<div class="blog-upload-item-note"><span>En</span>'.$note_en.'</div>')}
{$ctx->if_true($note_ru,
fn() => '<div class="blog-upload-item-note"><span>Ru</span>'.$note_ru.'</div>')}
<div class="blog-upload-item-md" id="upload{$id}_md" style="display: none"> <div class="blog-upload-item-md" id="upload{$id}_md" style="display: none">
<input type="text" value="{$markdown}" onclick="this.select()" readonly size="30"> <input type="text" value="{$markdown}" onclick="this.select()" readonly size="30">
</div> </div>

View File

@ -45,36 +45,35 @@ HTML;
function articles($ctx, array $posts, PostLanguage $selected_lang): string { function articles($ctx, array $posts, PostLanguage $selected_lang): string {
if (empty($posts)) if (empty($posts))
return $ctx->articlesEmpty($selected_lang); return $ctx->articles_empty($selected_lang);
return <<<HTML return <<<HTML
<div class="blog-list"> <div class="blog-list">
{$ctx->articlesPostsTable($posts, $selected_lang)} {$ctx->articles_posts_table($posts, $selected_lang)}
</div> </div>
HTML; HTML;
} }
function articlesEmpty($ctx, PostLanguage $selected_lang) { function articles_empty($ctx, PostLanguage $selected_lang) {
return <<<HTML return <<<HTML
<div class="empty"> <div class="empty">
{$ctx->lang('blog_no')} {$ctx->lang('blog_no')}
{$ctx->articlesRightLinks($selected_lang->value)} {$ctx->articles_right_links($selected_lang->value)}
</div> </div>
HTML; HTML;
} }
function articlesPostsTable($ctx, array $posts, PostLanguage $selected_lang): string { function articles_posts_table($ctx, array $posts, PostLanguage $selected_lang): string {
$ctx->year = 3000; $ctx->year = 3000;
return <<<HTML return <<<HTML
<div class="blog-list-table-wrap"> <div class="blog-list-wrap">
<table class="blog-list-table" width="100%" cellspacing="0" cellpadding="0"> {$ctx->for_each($posts,
{$ctx->for_each($posts, fn($post, $i) => $ctx->articlesPostRow($i, $post, $selected_lang))} fn($post, $i) => $ctx->articles_post_row($i, $post, $selected_lang))}
</table>
</div> </div>
HTML; HTML;
} }
function articlesPostRow($ctx, int $index, Post $post, PostLanguage $selected_lang): string { function articles_post_row($ctx, int $index, Post $post, PostLanguage $selected_lang): string {
$year = $post->getYear(); $year = $post->getYear();
$date = $post->getDate(); $date = $post->getDate();
$url = $post->getUrl($selected_lang); $url = $post->getUrl($selected_lang);
@ -83,32 +82,29 @@ $pt = $post->getText($selected_lang);
$title = $pt->title; $title = $pt->title;
return <<<HTML return <<<HTML
{$ctx->if_true($ctx->year > $year, $ctx->articlesIndexYearLine, $year, $index === 0, $selected_lang->value)} {$ctx->if_true($ctx->year > $year,
<tr class="blog-item-row{$ctx->if_not($post->visible, ' ishidden')}"> fn() => $ctx->articles_index_year_line($year, $index === 0, $selected_lang->value))}
<td class="blog-item-date-cell">
<span class="blog-item-date">{$date}</span> <a href="{$url}" class="blog-list-item clearfix{$ctx->if_not($post->visible, ' is-hidden')}">
</td> <div class="blog-list-item-date">{$date}</div>
<td class="blog-item-title-cell"> <div class="blog-list-item-title">{$title}</div>
<a class="blog-item-title" href="{$url}">{$title}</a> </a>
</td>
</tr>
HTML; HTML;
} }
function articlesIndexYearLine($ctx, $year, $show_right_links, string $selected_lang): string { function articles_index_year_line($ctx, $year, $show_right_links, string $selected_lang): string {
$ctx->year = $year; $ctx->year = $year;
return <<<HTML return <<<HTML
<tr class="blog-item-row-year"> <div class="blog-list-title">
<td class="blog-item-date-cell"><span>{$year}</span></td> {$year}
<td>
{$ctx->if_true($show_right_links, $ctx->articlesRightLinks($selected_lang))} {$ctx->if_true($show_right_links,
</td> fn() => $ctx->articles_right_links($selected_lang))}
</tr> </div>
HTML; HTML;
} }
function articles_right_links($ctx, string $selected_lang) {
function articlesRightLinks($ctx, string $selected_lang) {
$links = [ $links = [
['url' => $selected_lang != 'en' ? '/articles/' : null, 'label' => lang('lang_en')], ['url' => $selected_lang != 'en' ? '/articles/' : null, 'label' => lang('lang_en')],
['url' => $selected_lang != 'ru' ? '/articles/?lang=ru' : null, 'label' => lang('lang_ru')], ['url' => $selected_lang != 'ru' ? '/articles/?lang=ru' : null, 'label' => lang('lang_ru')],
@ -119,12 +115,12 @@ if (is_admin()) {
return <<<HTML return <<<HTML
<div class="blog-item-right-links"> <div class="blog-item-right-links">
{$ctx->for_each($links, fn($link, $index) => $ctx->articlesRightLink($link['url'], $link['label'], $index))} {$ctx->for_each($links, fn($link, $index) => $ctx->articles_right_link($link['url'], $link['label'], $index))}
</div> </div>
HTML; HTML;
} }
function articlesRightLink($ctx, $url, string $label, int $index) { function articles_right_link($ctx, $url, string $label, int $index) {
$buf = ''; $buf = '';
if ($index > 0) if ($index > 0)
$buf .= ' <span class="blog-links-separator">|</span> '; $buf .= ' <span class="blog-links-separator">|</span> ';
@ -142,15 +138,15 @@ $html = <<<HTML
<!--<div class="blog-post-title-nav"> <!--<div class="blog-post-title-nav">
<a href="/">{$ctx->lang('index')}</a> <span>&rsaquo;</span> <a href="/">{$ctx->lang('index')}</a> <span>&rsaquo;</span>
</div>--> </div>-->
{$ctx->if_admin($ctx->pageAdminLinks, $page_url, $short_name)} {$ctx->if_admin($ctx->page_admin_links, $page_url, $short_name)}
<div class="blog-post-text">{$unsafe_html}</div> <div class="blog-post-text">{$unsafe_html}</div>
</div> </div>
HTML; HTML;
return [$html, markdownThemeChangeListener()]; return [$html, js_markdownThemeChangeListener()];
} }
function pageAdminLinks($ctx, $url, $short_name) { function page_admin_links($ctx, $url, $short_name) {
return <<<HTML return <<<HTML
<div class="page-edit-links"> <div class="page-edit-links">
<a href="{$url}edit/">{$ctx->lang('edit')}</a> <a href="{$url}edit/">{$ctx->lang('edit')}</a>
@ -177,8 +173,8 @@ $html = <<<HTML
<div class="blog-post-date"> <div class="blog-post-date">
{$ctx->if_not($visible, $ctx->lang('blog_post_hidden').' |')} {$ctx->if_not($visible, $ctx->lang('blog_post_hidden').' |')}
{$date} {$date}
{$ctx->if_true($other_langs, $ctx->postOtherLangs($url, $other_langs))} {$ctx->if_true($other_langs, $ctx->post_other_langs($url, $other_langs))}
{$ctx->if_admin($ctx->postAdminLinks, $url, $id, $lang)} {$ctx->if_admin($ctx->post_admin_links, $url, $id, $lang)}
</div> </div>
</div> </div>
<div class="blog-post-text">{$unsafe_html}</div> <div class="blog-post-text">{$unsafe_html}</div>
@ -188,10 +184,10 @@ $html = <<<HTML
</div> </div>
HTML; HTML;
return [$html, markdownThemeChangeListener()]; return [$html, js_markdownThemeChangeListener()];
} }
function postOtherLangs($ctx, $url, $other_langs) { function post_other_langs($ctx, $url, $other_langs) {
$buf = ''; $buf = '';
foreach ($other_langs as $lang) { foreach ($other_langs as $lang) {
$buf .= ' | <a href="'.$url.'?lang='.$lang.'">'.$ctx->lang('blog_read_in_'.$lang).'</a>'; $buf .= ' | <a href="'.$url.'?lang='.$lang.'">'.$ctx->lang('blog_read_in_'.$lang).'</a>';
@ -213,14 +209,14 @@ HTML;
} }
function postAdminLinks($ctx, $url, $id, string $lang) { function post_admin_links($ctx, $url, $id, string $lang) {
return <<<HTML return <<<HTML
| <a href="{$url}edit/?lang={$lang}">{$ctx->lang('edit')}</a> | <a href="{$url}edit/?lang={$lang}">{$ctx->lang('edit')}</a>
| <a href="{$url}delete/?token={$ctx->csrf('delpost'.$id)}" onclick="return confirm('{$ctx->lang('blog_post_delete_confirmation')}')">{$ctx->lang('delete')}</a> | <a href="{$url}delete/?token={$ctx->csrf('delpost'.$id)}" onclick="return confirm('{$ctx->lang('blog_post_delete_confirmation')}')">{$ctx->lang('delete')}</a>
HTML; HTML;
} }
function markdownThemeChangeListener() { function js_markdownThemeChangeListener() {
return <<<JS return <<<JS
ThemeSwitcher.addOnChangeListener(function(isDark) { ThemeSwitcher.addOnChangeListener(function(isDark) {
var nodes = document.querySelectorAll('.md-image-wrap'); var nodes = document.querySelectorAll('.md-image-wrap');

View File

@ -23,11 +23,9 @@ return <<<HTML
<a href="{$direct_url}"> <a href="{$direct_url}">
<div style="background: url('{$url}') no-repeat; background-size: contain; width: {$w}px; padding-top: {$padding_top}%;"></div> <div style="background: url('{$url}') no-repeat; background-size: contain; width: {$w}px; padding-top: {$padding_top}%;"></div>
</a> </a>
{$ctx->if_true(
$note != '' && !$nolabel,
'<div class="md-image-note">'.$note.'</div>'
)}
</div> </div>
{$ctx->if_true($note != '' && !$nolabel,
fn() => '<div class="md-image-note">'.$note.'</div>')}
</div> </div>
HTML; HTML;
} }