fix pages editing

This commit is contained in:
E. S. 2024-03-09 03:50:33 +00:00
parent 1ab8659a21
commit 68a04ab18d
8 changed files with 138 additions and 112 deletions

View File

@ -131,6 +131,10 @@ class mysql {
return $q;
}
function error() {
return $this->link?->error;
}
function fetch($q): ?array {
$row = $q->fetch_assoc();
if (!$row) {

View File

@ -39,7 +39,7 @@ function render($f, ...$vars): void {
$lang = [];
foreach ($SkinState->lang as $key)
$lang[$key] = lang($key);
$lang = !empty($lang) ? json_encode($lang, JSON_UNESCAPED_UNICODE) : '';
$lang = !empty($lang) ? jsonEncode($lang, JSON_UNESCAPED_UNICODE) : '';
$title = $SkinState->title;
if (!$SkinState->options['is_index'])

View File

@ -122,6 +122,8 @@ class AdminHandler extends request_handler {
}
function POST_ajax_md_preview() {
if (!is_xhr_request())
forbidden();
list($md, $title, $use_image_previews) = input('md, title, b:use_image_previews');
$html = markup::markdownToHtml($md, $use_image_previews);
$ctx = new SkinContext('\\skin\\admin');
@ -136,8 +138,16 @@ class AdminHandler extends request_handler {
list($name) = input('short_name');
$page = pages::getByName($name);
if ($page)
not_found();
return $this->_get_pageAdd($name);
redirect($page->getUrl(), code: HTTPCode::Found);
add_skin_strings_re('/^(err_)?pages_/');
add_skin_strings_re('/^(err_)?blog_/');
set_title(lang('pages_create_title', $name));
static::make_wide();
render('admin/pageForm',
short_name: $name,
title: '',
text: '',
langs: PostLanguage::cases());
}
function POST_page_add() {
@ -168,7 +178,7 @@ class AdminHandler extends request_handler {
}
$page = pages::getByName($name);
redirect($page->getUrl());
ajax_ok(['url' => $page->getUrl()]);
}
function GET_post_add() {
@ -265,9 +275,11 @@ class AdminHandler extends request_handler {
if (!$page)
not_found();
$url = $page->getUrl();
csrf_check('delpage'.$page->shortName);
pages::delete($page);
redirect('/');
redirect($url, code: HTTPCode::Found);
}
function GET_post_delete() {
@ -279,7 +291,7 @@ class AdminHandler extends request_handler {
csrf_check('delpost'.$post->id);
posts::delete($post);
redirect('/articles/');
redirect('/articles/', code: HTTPCode::Found);
}
function GET_post_edit() {
@ -400,55 +412,63 @@ class AdminHandler extends request_handler {
if (!$page)
not_found();
return $this->_get_pageEdit($page,
add_skin_strings_re('/^(err_)?pages_/');
add_skin_strings_re('/^(err_)?blog_/');
set_title(lang('pages_page_edit_title', $page->shortName.'.html'));
static::make_wide();
$js_text = [
'text' => $page->md,
'title' => $page->title,
];
render('admin/pageForm',
is_edit: true,
short_name: $page->shortName,
title: $page->title,
text: $page->md,
saved: $saved,
visible: $page->visible,
);
saved: $saved,
langs: PostLanguage::cases(),
js_text: $js_text);
}
function POST_auto_edit() {
function POST_page_edit() {
if (!is_xhr_request())
forbidden();
list($short_name) = input('short_name');
$page = pages::getByName($short_name);
if ($page) {
csrf_check('editpage'.$page->shortName);
if (!$page)
not_found();
list($text, $title, $visible, $short_name)
= input('text, title, b:visible, new_short_name');
csrf_check('editpage'.$page->shortName);
$text = trim($text);
$title = trim($title);
$error_code = null;
list($text, $title, $visible, $short_name)
= input('text, title, b:visible, new_short_name');
if (!$title) {
$error_code = 'no_title';
} else if (!$text) {
$error_code = 'no_text';
} else if (!$short_name) {
$error_code = 'no_short_name';
}
$text = trim($text);
$title = trim($title);
$error_code = null;
if ($error_code) {
return $this->_get_pageEdit($page,
title: $title,
text: $text,
visible: $visible,
);
}
$page->edit([
'title' => $title,
'md' => $text,
'visible' => (int)$visible,
'short_name' => $short_name,
]);
redirect($page->getUrl().'edit/?saved=1');
if (!$title) {
$error_code = 'no_title';
} else if (!$text) {
$error_code = 'no_text';
} else if (!$short_name) {
$error_code = 'no_short_name';
}
not_found();
if ($error_code)
ajax_error(['code' => $error_code]);
$page->edit([
'title' => $title,
'md' => $text,
'visible' => (int)$visible,
'short_name' => $short_name,
]);
ajax_ok(['url' => $page->getUrl().'edit/?saved=1']);
}
protected static function make_wide() {
@ -458,38 +478,4 @@ class AdminHandler extends request_handler {
]);
}
protected function _get_pageAdd(
string $name,
string $title = '',
string $text = ''
) {
add_skin_strings_re('/^(err_)?pages_/');
set_title(lang('pages_create_title', $name));
static::make_wide();
render('admin/pageForm',
short_name: $name,
title: $title,
text: $text);
}
protected function _get_pageEdit(
Page $page,
string $title = '',
string $text = '',
bool $saved = false,
bool $visible = false,
?string $error_code = null
) {
add_skin_strings_re('/^(err_)?pages_/');
set_title(lang('pages_page_edit_title', $page->shortName.'.html'));
static::make_wide();
render('admin/pageForm',
is_edit: true,
short_name: $page->shortName,
title: $title,
text: $text,
visible: $visible,
saved: $saved);
}
}

View File

@ -7,16 +7,14 @@ class AdminWriteEditForm {
this.previewRequest = null
this.tocByLang = {}
if (!this.isEditing()) {
if (!this.isEditing() && this.isPost()) {
for (const l of opts.langs) {
this.tocByLang[l] = false
}
}
this.form.addEventListener('submit', this.onSubmit)
if (this.isPost())
this.form.title.addEventListener('input', this.onInput)
this.form.title.addEventListener('input', this.onInput)
this.form.text.addEventListener('input', this.onInput)
ge('toggle_wrap').addEventListener('click', this.onToggleWrapClick)
@ -46,13 +44,18 @@ class AdminWriteEditForm {
this.draft = new Draft(draftId, lang);
if (this.isEditing()) {
for (let l in opts.texts) {
this.draft.setLang(l)
this.draft.title = opts.texts[l].title
this.draft.text = opts.texts[l].md
this.tocByLang[l] = opts.texts[l].toc
if (this.isPost()) {
for (let l in opts.texts) {
this.draft.setLang(l)
this.draft.title = opts.texts[l].title
this.draft.text = opts.texts[l].md
this.tocByLang[l] = opts.texts[l].toc
}
this.draft.setLang(lang)
} else {
this.draft.title = opts.text.title
this.draft.text = opts.text.text
}
this.draft.setLang(lang)
this.showPreview()
} else {
this.fillFromDraft()
@ -131,21 +134,32 @@ class AdminWriteEditForm {
}
// fd.append('lang', this.getCurrentLang())
fd.append('visible', ge('visible_cb').checked ? 1 : 0)
if (this.isPost())
fd.append('visible', ge('visible_cb').checked ? 1 : 0)
// language-specific fields
// text-specific fields
let atLeastOneLangIsWritten = false
const writtenLangs = []
for (const l of this.opts.langs) {
let title = this.draft.getForLang(l, 'title')
let text = this.draft.getForLang(l, 'text')
console.log(`lang: ${l}`, title, text)
if (title !== '' && text !== '')
if (this.isPost()) {
for (const l of this.opts.langs) {
const title = this.draft.getForLang(l, 'title')
const text = this.draft.getForLang(l, 'text')
console.log(`lang: ${l}`, title, text)
if (title !== '' && text !== '')
atLeastOneLangIsWritten = true
fd.append(`title:${l}`, title)
fd.append(`text:${l}`, text)
fd.append(`toc:${l}`, this.tocByLang[l] ? 1 : 0)
writtenLangs.push(l)
}
} else {
const title = this.draft.title
const text = this.draft.text
if (title !== '' && text !== '') {
atLeastOneLangIsWritten = true
fd.append(`title:${l}`, title)
fd.append(`text:${l}`, text)
fd.append(`toc:${l}`, this.tocByLang[l] ? 1 : 0)
writtenLangs.push(l)
fd.append('title', title)
fd.append('text', text)
}
}
if (!atLeastOneLangIsWritten)
throw 'no_text'
@ -153,10 +167,12 @@ class AdminWriteEditForm {
fd.append('langs', writtenLangs.join(','))
// date field
const dateInput = evt.target.elements.date;
if (!dateInput.value)
throw 'no_date'
fd.append('date', dateInput.value)
if (this.isPost()) {
const dateInput = evt.target.elements.date;
if (!dateInput.value)
throw 'no_date'
fd.append('date', dateInput.value)
}
fd.append('token', this.opts.token)
cancelEvent(evt)

View File

@ -44,13 +44,13 @@ class Page extends model {
class pages {
static function add(array $data): ?int {
static function add(array $data): bool {
$db = DB();
$data['ts'] = time();
$data['html'] = markup::markdownToHtml($data['md']);
if (!$db->insert('pages', $data))
return null;
return $db->insertId();
return false;
return true;
}
static function delete(Page $page): void {

View File

@ -269,20 +269,30 @@ function pageForm($ctx,
string|Stringable $title,
string|Stringable $text,
string|Stringable $short_name,
array $langs,
bool $is_edit = false,
$error_code = null,
?bool $saved = null,
bool $visible = false): array {
bool $visible = false,
?array $js_text = null): array {
$form_url = '/'.$short_name.'/'.($is_edit ? 'edit' : 'create').'/';
// breadcrumbs
if ($is_edit) {
$bc_html = $ctx->bc([
['url' => '/'.$short_name.'/', 'text' => $ctx->lang('view_page')]
], 'padding-bottom: 20px');
} else {
$bc_html = '';
}
$html = <<<HTML
{$ctx->if_true($error_code, fn() => '<div class="form-error">'.$ctx->lang('err_pages_'.$error_code).'</div>')}
<div class="form-error" id="form-error" style="display:none"></div>
{$ctx->if_true($saved, fn() => '<div class="form-success">'.$ctx->lang('info_saved').'</div>')}
{$bc_html}
<table cellpadding="0" cellspacing="0" class="blog-write-table">
<tr>
<td id="form_first_cell">
<form class="blog-write-form form-layout-v" name="pageForm" action="{$form_url}" method="post">
<input type="hidden" name="token" value="{$ctx->if_then_else($is_edit, $ctx->csrf('editpage'.$short_name), $ctx->csrf('addpage'))}" />
<div class="form-field-wrap clearfix">
<div class="form-field-label">{$ctx->lang('pages_write_form_title')}</div>
<div class="form-field">
@ -312,7 +322,16 @@ $html = <<<HTML
</table>
HTML;
$js_params = json_encode(['pages' => true, 'edit' => $is_edit]);
$js_params = [
'pages' => true,
'edit' => $is_edit,
'token' => $is_edit ? $ctx->csrf('editpage'.$short_name) : $ctx->csrf('addpage'),
'langs' => array_map(fn($lang) => $lang->value, $langs), // still needed for draft erasing
];
if ($js_text !== null)
$js_params['text'] = $js_text;
$js_params = jsonEncode($js_params);
$js = <<<JS
cur.form = new AdminWriteEditForm({$js_params});
JS;

View File

@ -7,7 +7,7 @@ use Stringable;
function layout($ctx, $title, $unsafe_body, $static, $meta, $js, $opts, $unsafe_lang, $theme, $exec_time, $admin_email) {
global $config;
$app_config = json_encode([
$app_config = jsonEncode([
'domain' => $config['domain'],
'devMode' => $config['is_dev'],
'cookieHost' => $config['cookie_host'],
@ -64,7 +64,7 @@ HTML;
function renderScript($ctx, $unsafe_js, $unsafe_lang) {
global $config;
$styles = json_encode($ctx->styleNames);
$styles = jsonEncode($ctx->styleNames);
if ($config['is_dev'])
$versions = '{}';
else {
@ -73,7 +73,7 @@ else {
list($type, $bname) = getStaticNameParts($name);
$versions[$type][$bname] = $v;
}
$versions = json_encode($versions);
$versions = jsonEncode($versions);
}
return <<<HTML

View File

@ -20,6 +20,7 @@ toc: 'Table of Contents'
# blog
blog_new_post: "New post"
blog_view_post: "View post"
view_page: "View page"
#blog_editing: "Editing..."
blog_latest: 'Latest posts'
blog_no: 'No posts yet.'