Add moderate functions for forum page

This commit is contained in:
Visman 2020-06-24 15:06:59 +07:00
parent 3fb3a5e1e3
commit b09c359d59
14 changed files with 864 additions and 17 deletions

View file

@ -162,6 +162,9 @@ class Routing
$r->add(self::GET, '/admin/reports', 'AdminReports:view', 'AdminReports');
$r->add(self::GET, '/admin/reports/zap/{id:[1-9]\d*}/{token}', 'AdminReports:zap', 'AdminReportsZap');
}
$r->add(self::PST, '/moderate', 'Moderate:action', 'Moderate');
}
// только админ
if ($user->isAdmin) {

View file

@ -3,6 +3,7 @@
namespace ForkBB\Models\Pages;
use ForkBB\Models\Page;
use ForkBB\Models\Forum\Model as ForumModel;
class Forum extends Page
{
@ -18,8 +19,8 @@ class Forum extends Page
$this->c->Lang->load('forum');
$this->c->Lang->load('subforums');
$forum = $this->c->forums->loadTree($args['id']);
if (null === $forum) {
$forum = $this->c->forums->loadTree((int) $args['id']);
if (! $forum instanceof ForumModel) {
return $this->c->Message->message('Bad request');
}
@ -43,8 +44,60 @@ class Forum extends Page
if (empty($this->topics)) {
$this->fIswev = ['i', \ForkBB\__('Empty forum')];
} elseif ($this->user->isAdmin || $this->user->isModerator($forum)) {
$this->c->Lang->load('misc');
$this->enableMod = true;
$this->formMod = $this->formMod($forum->id, $forum->page);
}
return $this;
}
/**
* Создает массив данных для формы модерации
*
* @param int $id
* @param int $page
*
* @return array
*/
protected function formMod(int $id, int $page): array
{
$form = [
'id' => 'id-form-mod',
'action' => $this->c->Router->link('Moderate'),
'hidden' => [
'token' => $this->c->Csrf->create('Moderate'),
'forum' => $id,
'page' => $page,
'step' => 1,
],
'sets' => [],
'btns' => [
'open' => [
'type' => 'submit',
'value' => \ForkBB\__('Open'),
],
'close' => [
'type' => 'submit',
'value' => \ForkBB\__('Close'),
],
'delete' => [
'type' => 'submit',
'value' => \ForkBB\__('Delete'),
],
'move' => [
'type' => 'submit',
'value' => \ForkBB\__('Move'),
],
'merge' => [
'type' => 'submit',
'value' => \ForkBB\__('Merge'),
],
],
];
return $form;
}
}

View file

@ -0,0 +1,436 @@
<?php
namespace ForkBB\Models\Pages;
use ForkBB\Core\Container;
use ForkBB\Core\Validator;
use ForkBB\Models\Page;
use ForkBB\Models\Forum\Model as Forum;
use ForkBB\Models\Topic\Model as Topic;
class Moderate extends Page
{
/**
* Список действий
* @var array
*/
protected $actions = [
'open' => true,
'close' => true,
'delete' => true,
'move' => true,
'merge' => true,
'cancel' => true,
];
/**
* Конструктор
*
* @param Container $container
*/
public function __construct(Container $container)
{
parent::__construct($container);
$this->fIndex = 'index';
$this->nameTpl = 'moderate';
$this->onlinePos = 'moderate';
$this->robots = 'noindex, nofollow';
$container->Lang->load('misc');
}
/**
* Составление списка категорий/разделов для выбора
*/
protected function calcList(int $curForum): void
{
$cid = null;
$options = [];
$idxs = [];
$root = $this->c->forums->get(0);
if ($root instanceof Forum) {
foreach ($this->c->forums->depthList($root, -1) as $f) {
if ($cid !== $f->cat_id) {
$cid = $f->cat_id;
$options[] = [\ForkBB\__('Category prefix') . $f->cat_name];
}
$indent = \str_repeat(\ForkBB\__('Forum indent'), $f->depth);
if ($f->redirect_url || $f->id === $curForum) {
$options[] = [$f->id, $indent . \ForkBB\__('Forum prefix') . $f->forum_name, true];
} else {
$options[] = [$f->id, $indent . \ForkBB\__('Forum prefix') . $f->forum_name];
$idxs[] = $f->id;
}
}
}
$this->listOfIndexes = $idxs;
$this->listForOptions = $options;
}
/**
* Определяет действие
*
* @param Validator $v
* @param null|string $action
*
* @return string
*/
public function vActionProcess(Validator $v, $action)
{
if (empty($v->getErrors())) {
$sum = 0;
foreach ($this->actions as $key => $val) {
if (isset($v->{$key})) {
$action = $key;
++$sum;
}
}
// нажата только одна кнопка из доступных
if (1 !== $sum) {
$v->addError('Action not available');
}
// объединение тем
if ('merge' === $action && \count($v->ids) < 2) {
$v->addError('Not enough topics selected');
// перенос тем
} elseif ('move' === $action) {
$this->calcList($v->forum);
if (empty($this->listOfIndexes)) {
$v->addError('Nowhere to move');
} elseif (1 === $v->confirm && ! \in_array($v->destination, $this->listOfIndexes)) {
$v->addError('Invalid destination');
}
}
}
return $action;
}
/**
* Обрабатывает модерирование разделов
*
* @param array $args
*
* @return Page
*/
public function action(array $args): Page
{
$v = $this->c->Validator->reset()
->addValidators([
'action_process' => [$this, 'vActionProcess'],
])->addRules([
'token' => 'token:Moderate',
'step' => 'required|integer|min:1',
'forum' => 'required|integer|min:1|max:9999999999',
'topic' => 'integer|min:1|max:9999999999',
'page' => 'integer|min:1',
'ids' => 'required|array',
'ids.*' => 'required|integer|min:1|max:9999999999',
'confirm' => 'integer',
'redirect' => 'integer',
'destination' => 'integer',
'open' => 'string',
'close' => 'string',
'delete' => 'string',
'move' => 'string',
'merge' => 'string',
'cancel' => 'string',
'action' => 'action_process',
])->addAliases([
])->addArguments([
])->addMessages([
'ids' => 'No object selected',
]);
if (! $v->validation($_POST)) {
$message = $this->c->Message->message('Bad request');
$message->fIswev = $v->getErrors();
return $message;
}
$this->curForum = $this->c->forums->loadTree($v->forum);
if (! $this->curForum instanceof Forum) {
return $this->c->Message->message('Bad request');
} elseif (! $this->user->isAdmin && ! $this->user->isModerator($this->curForum)) {
return $this->c->Message->message('No permission', true, 403);
}
$page = $v->page ?? 1;
if ($v->topic) {
$this->curTopic = $this->c->topics->load($v->topic);
if (! $this->curTopic instanceof Topic || $this->curTopic->parent !== $this->curForum) {
return $this->c->Message->message('Bad request');
}
// посты
$this->backLink = $this->c->Router->link('Topic', [
'id' => $this->curTopic->id,
'name' => $this->curTopic->subject,
'page' => $page
]);
} else {
$objects = $this->c->topics->loadByIds($v->ids, false);
foreach ($objects as $topic) {
if (! $topic instanceof Topic || $topic->parent !== $this->curForum) {
return $this->c->Message->message('Bad request');
}
}
$this->backLink = $this->c->Router->link('Forum', [
'id' => $this->curForum->id,
'name' => $this->curForum->forum_name,
'page' => $page
]);
}
return $this->{'action' . \ucfirst($v->action)}($objects, $v);
}
protected function actionCancel(array $objects, Validator $v): Page
{
return $this->c->Redirect->url($this->backLink)->message('No confirm redirect');
}
protected function actionOpen(array $topics, Validator $v): Page
{
switch ($v->step) {
case 1:
$this->formTitle = \ForkBB\__('Open topics');
$this->buttonValue = \ForkBB\__('Open');
$this->crumbs = $this->crumbs($this->formTitle, \ForkBB\__('Moderate'), $this->curForum);
$this->form = $this->formConfirm($topics, $v);
return $this;
case 2:
if (1 === $v->confirm) {
$this->c->topics->access(true, ...$topics);
$message = 1 === \count($topics) ? 'Open topic redirect' : 'Open topics redirect';
return $this->c->Redirect->url($this->backLink)->message($message);
} else {
return $this->actionCancel($topics, $v);
}
default:
return $this->c->Message->message('Bad request');
}
}
protected function actionClose(array $topics, Validator $v): Page
{
switch ($v->step) {
case 1:
$this->formTitle = \ForkBB\__('Close topics');
$this->buttonValue = \ForkBB\__('Close');
$this->crumbs = $this->crumbs($this->formTitle, \ForkBB\__('Moderate'), $this->curForum);
$this->form = $this->formConfirm($topics, $v);
return $this;
case 2:
if (1 === $v->confirm) {
$this->c->topics->access(false, ...$topics);
$message = 1 === \count($topics) ? 'Close topic redirect' : 'Close topics redirect';
return $this->c->Redirect->url($this->backLink)->message($message);
} else {
return $this->actionCancel($topics, $v);
}
default:
return $this->c->Message->message('Bad request');
}
}
protected function actionDelete(array $topics, Validator $v): Page
{
if (! $this->user->isAdmin) { //???? разобраться с правами на удаление
foreach ($topics as $topic) {
if (isset($this->c->admins->list[$topic->poster_id])) {
return $this->c->Message->message('No permission', true, 403); //???? причина
}
}
}
switch ($v->step) {
case 1:
$this->formTitle = \ForkBB\__('Delete topics');
$this->buttonValue = \ForkBB\__('Delete');
$this->crumbs = $this->crumbs($this->formTitle, \ForkBB\__('Moderate'), $this->curForum);
$this->form = $this->formConfirm($topics, $v);
return $this;
case 2:
if (1 === $v->confirm) {
$this->c->topics->delete(...$topics);
return $this->c->Redirect->url($this->curForum->link)->message('Delete topics redirect');
} else {
return $this->actionCancel($topics, $v);
}
default:
return $this->c->Message->message('Bad request');
}
}
protected function actionMove(array $topics, Validator $v): Page
{
switch ($v->step) {
case 1:
$this->formTitle = \ForkBB\__('Move topics');
$this->buttonValue = \ForkBB\__('Move');
$this->crumbs = $this->crumbs($this->formTitle, \ForkBB\__('Moderate'), $this->curForum);
$this->chkRedirect = true;
$this->form = $this->formConfirm($topics, $v);
return $this;
case 2:
if (1 === $v->confirm) {
$forum = $this->c->forums->get($v->destination);
$this->c->topics->move(1 === $v->redirect, $forum, ...$topics);
$message = 1 === \count($topics) ? 'Move topic redirect' : 'Move topics redirect';
return $this->c->Redirect->url($this->curForum->link)->message($message);
} else {
return $this->actionCancel($topics, $v);
}
default:
return $this->c->Message->message('Bad request');
}
}
protected function actionMerge(array $topics, Validator $v): Page
{
foreach ($topics as $topic) {
if ($topic->moved_to) {
return $this->c->Message->message('Topic links cannot be merged');
}
if (! $this->firstTopic instanceof Topic
|| $topic->first_post_id < $this->firstTopic->first_post_id
) {
$this->firstTopic = $topic;
}
}
switch ($v->step) {
case 1:
$this->formTitle = \ForkBB\__('Merge topics');
$this->buttonValue = \ForkBB\__('Merge');
$this->crumbs = $this->crumbs($this->formTitle, \ForkBB\__('Moderate'), $this->curForum);
$this->chkRedirect = true;
$this->form = $this->formConfirm($topics, $v);
return $this;
case 2:
if (1 === $v->confirm) {
$this->c->topics->merge(1 === $v->redirect, ...$topics);
return $this->c->Redirect->url($this->curForum->link)->message('Merge topics redirect');
} else {
return $this->actionCancel($topics, $v);
}
default:
return $this->c->Message->message('Bad request');
}
}
/**
* Подготавливает массив данных для формы подтверждения
*
* @param array $objects
* @param Validator $v
*
* @return array
*/
protected function formConfirm(array $objects, Validator $v): array
{
$form = [
'action' => $this->c->Router->link('Moderate'),
'hidden' => [
'token' => $this->c->Csrf->create('Moderate'),
'step' => $v->step + 1,
'forum' => $v->forum,
],
'sets' => [],
'btns' => [],
];
if ($v->topic) {
$form['hidden']['topic'] = $v->topic;
}
$headers = [];
$ids = [];
foreach ($objects as $object) {
if ($object instanceof Topic) {
$headers[] = \ForkBB\__('Topic «%s»', \ForkBB\cens(($object->subject)));
$ids[] = $object->id;
}
}
$form['hidden']['ids'] = $ids;
$form['sets']['info'] = [
'info' => [
'info1' => [
'type' => '', //????
'value' => \implode('<br>', $headers),
'html' => true,
],
],
];
if ($this->firstTopic instanceof Topic) {
$form['sets']['info']['info']['info2'] = [
'type' => '', //????
'value' => \ForkBB\__('All posts will be posted in the «%s» topic', $this->firstTopic->subject),
// 'html' => true,
];
}
if ($this->listForOptions) {
$form['sets']['destination'] = [
'fields' => [
'destination' => [
'type' => 'select',
'options' => $this->listForOptions,
'value' => null,
'caption' => \ForkBB\__('Move to'),
'required' => true,
],
],
];
}
if (true === $this->chkRedirect) {
$form['sets']['redirect'] = [
'fields' => [
'redirect' => [
'type' => 'checkbox',
'label' => \ForkBB\__('Leave redirect'),
'value' => '1',
'checked' => true,
],
],
];
}
$form['sets']['confirm'] = [
'fields' => [
'confirm' => [
'type' => 'checkbox',
'label' => \ForkBB\__('Confirm action'),
'value' => '1',
'checked' => false,
],
],
];
$form['btns'][$v->action] = [
'type' => 'submit',
'value' => $this->buttonValue,
// 'accesskey' => 's',
];
$form['btns']['cancel'] = [
'type' => 'submit',
'value' => \ForkBB\__('Cancel'),
];
return $form;
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace ForkBB\Models\Topic;
use ForkBB\Models\Action;
use ForkBB\Models\Topic\Model as Topic;
class Access extends Action
{
/**
* Устанавливает/снимает флаг закрытия тем(ы)
*
* @param bool $open
* @param Topic ...$topics
*/
public function access(bool $open, Topic ...$topics): void
{
$ids = [];
foreach ($topics as $topic) {
$ids[] = $topic->id;
$topic->__closed = $open ? 0 : 1;
}
if (! empty($ids)) {
$vars = [
':ids' => $ids,
':closed' => $open ? 0 : 1,
];
$sql = 'UPDATE ::topics SET closed=?i:closed WHERE id IN (?ai:ids)';
$this->c->DB->exec($sql, $vars);
}
}
}

View file

@ -118,6 +118,8 @@ class Delete extends Action
//???? подписки, опросы, предупреждения
// удаление тем-ссылок на удаляемые темы
if ($users) {
$vars = [
':users' => $users,
@ -168,7 +170,7 @@ class Delete extends Action
WHERE id IN (?ai:topics)';
$this->c->DB->exec($sql, $vars);
foreach($parents as $forum) {
foreach ($parents as $forum) {
$this->c->forums->update($forum->calcStat());
}
}

112
app/Models/Topic/Merge.php Normal file
View file

@ -0,0 +1,112 @@
<?php
namespace ForkBB\Models\Topic;
use ForkBB\Models\Action;
use ForkBB\Models\Topic\Model as Topic;
use PDO;
use InvalidArgumentException;
use RuntimeException;
class Merge extends Action
{
/**
* Объединяет темы
*
* @param bool $redirect
* @param Topic ...$topics
*
* @throws InvalidArgumentException
* @throws RuntimeException
*/
public function merge(bool $redirect, Topic ...$topics): void
{
if (\count($topics) < 2) {
throw new InvalidArgumentException('Expected at least 2 topics.');
}
$ids = [];
$users = [];
$forums = [];
$firstTopic = null;
$otherTopics = [];
foreach ($topics as $topic) {
if ($topic->moved_to) {
throw new RuntimeException('Topic links cannot be merged');
}
$users[$topic->poster_id] = $topic->poster_id;
$forums[$topic->forum_id] = $topic->parent;
if (! $firstTopic instanceof Topic) {
$firstTopic = $topic;
} elseif ($topic->first_post_id < $firstTopic->first_post_id) {
$otherTopics[] = $firstTopic;
$ids[] = $firstTopic->id;
$firstTopic = $topic;
} else {
$otherTopics[] = $topic;
$ids[] = $topic->id;
}
}
//???? перенести обработку в посты?
$vars = [
'start' => "[from]",
'end' => "[/from]\n",
'topics' => $ids,
];
$sql = 'UPDATE ::posts AS p, ::topics as t
SET p.message=CONCAT(?s:start, t.subject, ?s:end, p.message)
WHERE p.topic_id IN (?ai:topics) AND t.id=p.topic_id';
$this->c->DB->exec($sql, $vars);
$vars = [
'id' => $firstTopic->id,
'topics' => $ids,
];
$sql = 'UPDATE ::posts AS p
SET p.topic_id=?i:id
WHERE p.topic_id IN (?ai:topics)';
$this->c->DB->exec($sql, $vars);
// добавить перенос подписок на первую тему?
if ($redirect) {
foreach ($otherTopics as $topic) {
$topic->moved_to = $firstTopic->id;
$this->c->topics->update($topic->calcStat());
}
$vars = [
'topics' => $ids,
];
$sql = 'SELECT t.id
FROM ::topics AS t
WHERE t.moved_to IN (?ai:topics)';
$linkTopics = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_COLUMN);
foreach ($linkTopics as $topic) {
$topic->moved_to = $firstTopic->id;
$this->c->topics->update($topic->calcStat());
}
$this->c->topics->update($firstTopic->calcStat());
foreach ($forums as $forum) {
$this->c->forums->update($forum->calcStat());
}
if ($users) {
$this->c->users->UpdateCountTopics(...$users);
}
} else {
$this->c->topics->update($firstTopic->calcStat());
$this->manager->delete(...$otherTopics);
$this->c->forums->update($firstTopic->parent->calcStat());
}
}
}

47
app/Models/Topic/Move.php Normal file
View file

@ -0,0 +1,47 @@
<?php
namespace ForkBB\Models\Topic;
use ForkBB\Models\Action;
use ForkBB\Models\Forum\Model as Forum;
use ForkBB\Models\Topic\Model as Topic;
class Move extends Action
{
/**
* Перенос тем
*
* @param bool $redirect
* @param Forum $toForum
* @param Topic ...$topics
*/
public function move(bool $redirect, Forum $toForum, Topic ...$topics): void
{
$forums = [
$toForum->id => $toForum,
];
foreach ($topics as $topic) {
if ($topic->parent === $toForum) {
continue;
}
if ($redirect) {
$rTopic = clone $topic;
$rTopic->id = null;
$rTopic->moved_to = $topic->id;
$rTopic->num_replies = 0;
$this->c->topics->insert($rTopic);
}
$forums[$topic->forum_id] = $topic->parent;
$topic->forum_id = $toForum->id;
$this->c->topics->update($topic);
}
foreach ($forums as $forum) {
$this->c->forums->update($forum->calcStat());
}
}
}

View file

@ -159,6 +159,7 @@ return [
'Ban' => \ForkBB\Models\Pages\Ban::class,
'Debug' => \ForkBB\Models\Pages\Debug::class,
'Misc' => \ForkBB\Models\Pages\Misc::class,
'Moderate' => \ForkBB\Models\Pages\Moderate::class,
'Report' => \ForkBB\Models\Pages\Report::class,
'ProfileView' => \ForkBB\Models\Pages\Profile\View::class,
'ProfileEdit' => \ForkBB\Models\Pages\Profile\Edit::class,
@ -248,6 +249,9 @@ return [
'TopicManagerSave' => \ForkBB\Models\Topic\Save::class,
'TopicManagerDelete' => \ForkBB\Models\Topic\Delete::class,
'TopicManagerView' => \ForkBB\Models\Topic\View::class,
'TopicManagerAccess' => \ForkBB\Models\Topic\Access::class,
'TopicManagerMerge' => \ForkBB\Models\Topic\Merge::class,
'TopicManagerMove' => \ForkBB\Models\Topic\Move::class,
'PostModel' => \ForkBB\Models\Post\Model::class,
'PostManagerLoad' => \ForkBB\Models\Post\Load::class,

View file

@ -123,8 +123,8 @@ msgstr "Move topic"
msgid "Move topics"
msgstr "Move topics"
msgid "Move legend"
msgstr "Select destination of move"
msgid "Invalid destination"
msgstr "Invalid destination."
msgid "Move to"
msgstr "Move to"
@ -148,7 +148,7 @@ msgid "Delete topics"
msgstr "Delete topics"
msgid "Delete topics comply"
msgstr "Are you sure you want to delete the selected topics?"
msgstr "Delete the selected topics (<b>All posts from these topics will be deleted</b>)"
msgid "Delete topics redirect"
msgstr "Topics deleted. Redirecting …"
@ -165,9 +165,6 @@ msgstr "Topic closed. Redirecting …"
msgid "Close topics redirect"
msgstr "Topics closed. Redirecting …"
msgid "No topics selected"
msgstr "You must select at least one topic for move/delete/open/close."
msgid "Not enough topics selected"
msgstr "You must select at least two topics for merge."
@ -208,7 +205,7 @@ msgid "Cannot select first"
msgstr "First post cannot be selected for split/delete."
msgid "Delete posts comply"
msgstr "Are you sure you want to delete the selected posts?"
msgstr "Delete the selected posts"
msgid "Delete posts redirect"
msgstr "Posts deleted. Redirecting …"
@ -233,3 +230,36 @@ msgstr "Posts moved. Redirecting …"
msgid "Post from topic"
msgstr "This post is moved from topic"
msgid "Topic «%s»"
msgstr "Topic «%s»"
msgid "All posts will be posted in the «%s» topic"
msgstr "All posts will be posted in the «%s» topic."
msgid "Action not available"
msgstr "Action not available."
msgid "No object selected"
msgstr "You must select at least one object for the action."
msgid "Open topics"
msgstr "Open topics"
msgid "Close topics"
msgstr "Close topics"
msgid "Confirm action"
msgstr "Confirm action"
msgid "Topic links cannot be merged"
msgstr "Topic links cannot be merged."
msgid "Category prefix"
msgstr ""
msgid "Forum prefix"
msgstr ""
msgid "Forum indent"
msgstr "◦ ◦ "

View file

@ -123,8 +123,8 @@ msgstr "Перенос темы"
msgid "Move topics"
msgstr "Перенос тем"
msgid "Move legend"
msgstr "Выберите раздел-получатель"
msgid "Invalid destination"
msgstr "Неверная цель переноса."
msgid "Move to"
msgstr "Перенести в"
@ -148,7 +148,7 @@ msgid "Delete topics"
msgstr "Удаление тем"
msgid "Delete topics comply"
msgstr "Вы уверены, что хотите удалить отмеченные темы?"
msgstr "Удалить выбранные темы (<b>Все сообщения из этих тем будут удалены</b>)"
msgid "Delete topics redirect"
msgstr "Темы удалены. Переадресация &hellip;"
@ -165,9 +165,6 @@ msgstr "Тема закрыта. Переадресация &hellip;"
msgid "Close topics redirect"
msgstr "Темы закрыты. Переадресация &hellip;"
msgid "No topics selected"
msgstr "Вы должны выбрать хотя бы одну тему для переноса/удаления/открытия/закрытия."
msgid "Not enough topics selected"
msgstr "Вы должны выбрать хотя бы две темы для объединения."
@ -208,7 +205,7 @@ msgid "Cannot select first"
msgstr "Первое сообщение не может быть выбрано."
msgid "Delete posts comply"
msgstr "Вы уверены, что хотите удалить выбранные сообщения?"
msgstr "Удалить выбранные сообщения"
msgid "Delete posts redirect"
msgstr "Сообщения удалены. Переадресация &hellip;"
@ -233,3 +230,36 @@ msgstr "Сообщения перенесены. Переадресация &hel
msgid "Post from topic"
msgstr "Это сообщение перенесено из темы"
msgid "Topic «%s»"
msgstr "Тема «%s»"
msgid "All posts will be posted in the «%s» topic"
msgstr "Все сообщения будут размещены в теме «%s»."
msgid "Action not available"
msgstr "Действие недоступно."
msgid "No object selected"
msgstr "Вы должны выбрать хотя бы один объект для действия."
msgid "Open topics"
msgstr "Открытие тем"
msgid "Close topics"
msgstr "Закрытие тем"
msgid "Confirm action"
msgstr "Подтвердить действие"
msgid "Topic links cannot be merged"
msgstr "Ссылки на темы не могут быть объединены."
msgid "Category prefix"
msgstr ""
msgid "Forum prefix"
msgstr ""
msgid "Forum indent"
msgstr "◦ ◦ "

View file

@ -84,7 +84,12 @@
@elseif ($topic->moved_to)
<li id="topic-{!! $topic->id !!}" class="f-row f-fredir">
<div class="f-cell f-cmain">
@if ($p->enableMod)
<input id="checkbox-{!! $topic->id !!}" class="f-fch" type="checkbox" name="ids[{!! $topic->id !!}]" value="{!! $topic->id !!}" form="id-form-mod">
<label class="f-ficon" for="checkbox-{!! $topic->id !!}"></label>
@else
<div class="f-ficon"></div>
@endif
<div class="f-finfo">
<h3><span class="f-fredirtext">{!! __('Moved') !!}</span> <a class="f-ftname" href="{!! $topic->link !!}">{{ cens($topic->subject) }}</a></h3>
</div>
@ -93,7 +98,12 @@
@else
<li id="topic-{!! $topic->id !!}" class="f-row @if (false !== $topic->hasNew) f-fnew @endif @if (false !== $topic->hasUnread) f-funread @endif @if ($topic->sticky) f-fsticky @endif @if ($topic->closed) f-fclosed @endif @if ($topic->poll_type) f-fpoll @endif @if ($topic->dot) f-fposted @endif">
<div class="f-cell f-cmain">
@if ($p->enableMod)
<input id="checkbox-{!! $topic->id !!}" class="f-fch" type="checkbox" name="ids[{!! $topic->id !!}]" value="{!! $topic->id !!}" form="id-form-mod">
<label class="f-ficon" for="checkbox-{!! $topic->id !!}"></label>
@else
<div class="f-ficon"></div>
@endif
<div class="f-finfo">
<h3>
@if ($topic->dot)
@ -170,3 +180,11 @@
@yield ('crumbs')
</div>
@endif
@if ($p->enableMod && $form = $p->formMod)
<section class="f-moderate">
<h2>{!! __('Moderate') !!}</h2>
<div class="f-fdivm">
@include ('layouts/form')
</div>
</section>
@endif

View file

@ -2,7 +2,13 @@
<form @if ($form['id']) id="{!! $form['id'] !!}" @endif class="f-form" method="post" action="{!! $form['action'] !!}" @if ($form['enctype']) enctype="{{ $form['enctype'] }}" @endif>
@if ($form['hidden'])
@foreach ($form['hidden'] as $key => $val)
@if (\is_array($val))
@foreach ($val as $k => $v)
<input type="hidden" name="{{ $key }}[{{ $k }}]" value="{{ $v }}">
@endforeach
@else
<input type="hidden" name="{{ $key }}" value="{{ $val }}">
@endif
@endforeach
@endif
@endif

View file

@ -0,0 +1,25 @@
@section ('crumbs')
<ul class="f-crumbs">
@foreach ($p->crumbs as $cur)
<li class="f-crumb"><!-- inline -->
@if ($cur[0])
<a href="{!! $cur[0] !!}" @if ($cur[2]) class="active" @endif>{{ $cur[1] }}</a>
@else
<span @if ($cur[2]) class="active" @endif>{{ $cur[1] }}</span>
@endif
</li><!-- endinline -->
@endforeach
</ul>
@endsection
@extends ('layouts/main')
<div class="f-nav-links">
@yield ('crumbs')
</div>
@if ($form = $p->form)
<section class="f-moderate-form f-main">
<h2>{!! $p->formTitle !!}</h2>
<div class="f-fdiv">
@include ('layouts/form')
</div>
</section>
@endif

View file

@ -515,6 +515,10 @@ body,
width: 100%;
}
#fork .f-fdiv .f-btn[name=delete] {
color: red;
}
#fork .f-fdiv .f-label {
font-size: 1rem;
display: inline-block;
@ -1168,6 +1172,23 @@ body,
width: 2rem;
}
#fork .f-ftlist .f-fch {
display: none;
}
#fork .f-ftlist .f-fch + .f-ficon {
position: relative;
cursor: pointer;
}
#fork .f-ftlist .f-fch:checked + .f-ficon:after {
content: "\2713";
color: red;
position: absolute;
bottom: 0;
left: 0;
}
#fork .f-ftlist .f-finfo {
width: calc(100% - 2rem);
}
@ -1741,6 +1762,33 @@ body,
display: none;
}
/*****************/
/* Модерирование */
/*****************/
#fork .f-moderate {
border-top: 0.0625rem solid #AA7939;
margin: 1rem 0;
position: relative;
}
#fork .f-moderate .f-fdivm {
padding: 1rem 0.625rem 0 0.625rem;
}
#fork .f-moderate .f-btn {
opacity: 0.4;
}
#fork .f-moderate .f-btns:hover .f-btn,
#fork .f-moderate .f-btn:focus {
opacity: 1;
}
#fork .f-moderate-form .f-btn {
width: auto;
display: inline-block;
}
/*********************/
/* Админка/Категории */
/*********************/