123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746 |
- <?php
- /**
- * This file is part of the ForkBB <https://github.com/forkbb>.
- *
- * @copyright (c) Visman <mio.visman@yandex.ru, https://github.com/MioVisman>
- * @license The MIT License (MIT)
- */
- declare(strict_types=1);
- namespace ForkBB\Models\Pages\Admin\Parser;
- use ForkBB\Core\Container;
- use ForkBB\Core\Validator;
- use ForkBB\Models\Page;
- use ForkBB\Models\BBCodeList\Structure;
- use ForkBB\Models\Pages\Admin\Parser;
- use function \ForkBB\__;
- class BBCode extends Parser
- {
- public function __construct(Container $container)
- {
- parent::__construct($container);
- $this->AdminBBCodeUrl = $this->c->Router->link('AdminBBCode');
- }
- /**
- * Редактирование натроек bbcode
- */
- public function view(array $args, string $method): Page
- {
- $this->c->bbcode->load();
- if ('POST' === $method) {
- $v = $this->c->Validator->reset()
- ->addValidators([
- ])->addRules([
- 'token' => 'token:AdminBBCode',
- 'bbcode.*.in_mes' => 'required|integer|min:0|max:2',
- 'bbcode.*.in_sig' => 'required|integer|min:0|max:2',
- ])->addAliases([
- ])->addArguments([
- ])->addMessages([
- ]);
- if ($v->validation($_POST)) {
- $mesClear = true;
- $sigClear = true;
- $white_mes = [];
- $black_mes = [];
- $white_sig = [];
- $black_sig = [];
- foreach ($this->c->bbcode->bbcodeTable as $id => $tagData) {
- $tag = $tagData['bb_tag'];
- $bbcode = $v->bbcode;
- if ('ROOT' === $tag) {
- continue;
- }
- if (! isset($bbcode[$tag]['in_mes'], $bbcode[$tag]['in_sig'])) {
- $mesClear = false;
- $sigClear = false;
- continue;
- }
- switch ($bbcode[$tag]['in_mes']) {
- case 2:
- $white_mes[] = $tag;
- break;
- case 0:
- $black_mes[] = $tag;
- default:
- $mesClear = false;
- break;
- }
- switch ($bbcode[$tag]['in_sig']) {
- case 2:
- $white_sig[] = $tag;
- break;
- case 0:
- $black_sig[] = $tag;
- default:
- $sigClear = false;
- break;
- }
- }
- $this->c->config->a_bb_white_mes = $mesClear ? [] : $white_mes;
- $this->c->config->a_bb_black_mes = $mesClear ? [] : $black_mes;
- $this->c->config->a_bb_white_sig = $sigClear ? [] : $white_sig;
- $this->c->config->a_bb_black_sig = $sigClear ? [] : $black_sig;
- $this->c->config->save();
- return $this->c->Redirect->url($this->AdminBBCodeUrl)->message('Parser settings updated redirect');
- }
- $this->fIswev = $v->getErrors();
- }
- $this->nameTpl = 'admin/form';
- $this->aCrumbs[] = [$this->AdminBBCodeUrl, 'BBCode management'];
- $this->form = $this->formView();
- $this->titleForm = 'BBCode head';
- $this->classForm = ['bbcode'];
- return $this;
- }
- /**
- * Формирует данные для формы
- */
- protected function formView(): array
- {
- $form = [
- 'action' => $this->AdminBBCodeUrl,
- 'hidden' => [
- 'token' => $this->c->Csrf->create('AdminBBCode'),
- ],
- 'sets' => [
- 'bbcode-legend' => [
- 'class' => ['bbcode-legend'],
- 'legend' => 'BBCode list subhead',
- 'fields' => [],
- ],
- ],
- 'btns' => [
- 'new' => [
- 'type' => 'btn',
- 'value' => __('New BBCode'),
- 'link' => $this->c->Router->link('AdminBBCodeNew'),
- ],
- 'save' => [
- 'type' => 'submit',
- 'value' => __('Save changes'),
- ],
- ],
- ];
- $selectList = [
- 2 => __('BBCode allowed'),
- 1 => __('BBCode display only'),
- 0 => __('BBCode not allowed'),
- ];
- foreach ($this->c->bbcode->bbcodeTable as $id => $tagData) {
- $fields = [];
- $tag = $tagData['bb_tag'];
- $fields["bbcode{$id}-tag"] = [
- 'class' => ['bbcode', 'tag'],
- 'type' => $tagData['bb_edit'] > 0 ? 'link' : 'str',
- 'value' => $tag,
- 'caption' => 'BBCode tag label',
- 'title' => __('BBCode tag title'),
- 'href' => 1 === $tagData['bb_edit']
- ? $this->c->Router->link('AdminBBCodeEdit', ['id' => $id])
- : null,
- ];
- $fields["bbcode[{$tag}][in_mes]"] = [
- 'class' => ['bbcode', 'in_mes'],
- 'type' => 'select',
- 'options' => $selectList,
- 'value' => $this->getValue($tag, $this->c->config->a_bb_white_mes, $this->c->config->a_bb_black_mes),
- 'caption' => 'BBCode mes label',
- 'disabled' => 'ROOT' === $tag,
- ];
- $fields["bbcode[{$tag}][in_sig]"] = [
- 'class' => ['bbcode', 'in_sig'],
- 'type' => 'select',
- 'options' => $selectList,
- 'value' => $this->getValue($tag, $this->c->config->a_bb_white_sig, $this->c->config->a_bb_black_sig),
- 'caption' => 'BBCode sig label',
- 'disabled' => 'ROOT' === $tag,
- ];
- $fields["bbcode{$id}-del"] = [
- 'class' => ['bbcode', 'delete'],
- 'type' => 'btn',
- 'value' => '❌',
- 'caption' => 'Delete',
- 'title' => __('Delete'),
- 'link' => 1 === $tagData['bb_delete']
- ? $this->c->Router->link('AdminBBCodeDelete', ['id' => $id])
- : null,
- 'disabled' => 1 !== $tagData['bb_delete'],
- ];
- $form['sets']["bbcode{$id}"] = [
- 'class' => ['bbcode'],
- 'legend' => ['BBCode %s', $tag],
- 'fields' => $fields,
- ];
- }
- return $form;
- }
- /**
- * Вычисляет значение для select на основе белого и черного списков bbcode
- */
- protected function getValue(string $tag, array $white, array $black): int
- {
- if ('ROOT' === $tag) {
- return 1;
- } elseif (empty($white) && empty($black)) {
- return 2;
- } elseif (\in_array($tag, $black)) {
- return 0;
- } elseif (\in_array($tag, $white)) {
- return 2;
- } else {
- return 1;
- }
- }
- /**
- * Удаляет bbcode
- */
- public function delete(array $args, string $method): Page
- {
- $this->c->bbcode->load();
- $tagData = $this->c->bbcode->bbcodeTable[$args['id']] ?? null;
- if (
- empty($tagData['bb_delete'])
- || 1 !== $tagData['bb_delete']
- ) {
- return $this->c->Message->message('Bad request');
- }
- if ('POST' === $method) {
- $v = $this->c->Validator->reset()
- ->addRules([
- 'token' => 'token:AdminBBCodeDelete',
- 'confirm' => 'checkbox',
- 'delete' => 'required|string',
- ])->addAliases([
- ])->addArguments([
- 'token' => $args,
- ]);
- if (
- ! $v->validation($_POST)
- || '1' !== $v->confirm
- ) {
- return $this->c->Redirect->url($this->AdminBBCodeUrl)->message('No confirm redirect');
- }
- $this->c->bbcode->delete($args['id']);
- return $this->c->Redirect->url($this->AdminBBCodeUrl)->message('BBCode deleted redirect');
- }
- $formAction = $this->c->Router->link('AdminBBCodeDelete', $args);
- $this->nameTpl = 'admin/form';
- $this->classForm = ['deletebbcode'];
- $this->titleForm = 'Delete bbcode head';
- $this->form = $this->formDelete($args, $formAction, $tagData['bb_tag']);
- $this->aCrumbs[] = [$formAction, $this->titleForm];
- $this->aCrumbs[] = [null, ['"%s"', $tagData['bb_tag']]];
- $this->aCrumbs[] = [$this->AdminBBCodeUrl, 'BBCode management'];
- return $this;
- }
- /**
- * Формирует данные для формы
- */
- protected function formDelete(array $args, string $formAction, string $name): array
- {
- return [
- 'action' => $formAction,
- 'hidden' => [
- 'token' => $this->c->Csrf->create('AdminBBCodeDelete', $args),
- ],
- 'sets' => [
- 'info' => [
- 'info' => [
- [
- 'value' => __(['BBCode %s', $name]),
- ],
- ],
- ],
- 'confirm' => [
- 'fields' => [
- 'confirm' => [
- 'type' => 'checkbox',
- 'label' => 'Confirm action',
- 'checked' => false,
- ],
- ],
- ],
- ],
- 'btns' => [
- 'delete' => [
- 'type' => 'submit',
- 'value' => __('Delete bbcode btn'),
- ],
- 'cancel' => [
- 'type' => 'btn',
- 'value' => __('Cancel'),
- 'link' => $this->AdminBBCodeUrl,
- ],
- ],
- ];
- }
- /**
- * Редактирование/добавление нового bbcode
- */
- public function edit(array $args, string $method): Page
- {
- $this->c->bbcode->load();
- $structure = $this->c->BBStructure;
- $id = $args['id'] ?? 0;
- if ($id > 0) {
- if (
- empty($this->c->bbcode->bbcodeTable[$id])
- || 1 !== $this->c->bbcode->bbcodeTable[$id]['bb_edit']
- ) {
- return $this->c->Message->message('Bad request');
- }
- $structure = $structure->fromString($this->c->bbcode->bbcodeTable[$id]['bb_structure']);
- }
- $bbTypes = [];
- $bbNames = [];
- foreach ($this->c->bbcode->bbcodeTable as $cur) {
- $type = $this->c->BBStructure->fromString($cur['bb_structure'])->type;
- $bbTypes[$type] = $type;
- $bbNames[$cur['bb_tag']] = $cur['bb_tag'];
- }
- $this->bbTypes = $bbTypes;
- if ($id > 0) {
- $title = 'Edit bbcode head';
- $page = 'AdminBBCodeEdit';
- $pageArgs = ['id' => $id];
- } else {
- $title = 'Add bbcode head';
- $page = 'AdminBBCodeNew';
- $pageArgs = [];
- }
- $this->formAction = $this->c->Router->link($page, $pageArgs);
- $this->formToken = $this->c->Csrf->create($page, $pageArgs);
- if ('POST' === $method) {
- $v = $this->c->Validator->reset()
- ->addValidators([
- 'check_all' => [$this, 'vCheckAll'],
- ])->addRules([
- 'token' => 'token:' . $page,
- 'tag' => $id > 0 ? 'absent' : 'required|string:trim|regex:%^[a-z\*][a-z\d-]{0,10}$%|not_in:' . \implode(',', $bbNames),
- 'type' => 'required|string|in:' . \implode(',', $bbTypes),
- 'type_new' => 'exist|string:trim,empty|regex:%^[a-z][a-z\d-]{0,19}$%',
- 'parents.*' => 'required|string|in:' . \implode(',', $bbTypes),
- 'handler' => 'exist|string:trim|max:65535',
- 'text_handler' => 'exist|string:trim|max:65535',
- 'recursive' => 'required|integer|in:0,1',
- 'text_only' => 'required|integer|in:0,1',
- 'tags_only' => 'required|integer|in:0,1',
- 'pre' => 'required|integer|in:0,1',
- 'single' => 'required|integer|in:0,1',
- 'auto' => 'required|integer|in:0,1',
- 'self_nesting' => 'required|integer|min:0|max:10',
- 'no_attr.allowed' => 'required|integer|in:0,1',
- 'no_attr.body_format' => 'exist|string:trim|max:1024',
- 'no_attr.text_only' => 'required|integer|in:0,1',
- 'def_attr.allowed' => 'required|integer|in:0,1',
- 'def_attr.required' => 'required|integer|in:0,1',
- 'def_attr.format' => 'exist|string:trim|max:1024',
- 'def_attr.body_format' => 'exist|string:trim|max:1024',
- 'def_attr.text_only' => 'required|integer|in:0,1',
- 'new_attr.name' => 'exist|string:trim,empty|regex:%^[a-z-]{2,15}$%',
- 'new_attr.allowed' => 'required|integer|in:0,1',
- 'new_attr.required' => 'required|integer|in:0,1',
- 'new_attr.format' => 'exist|string:trim|max:1024',
- 'new_attr.body_format' => 'exist|string:trim|max:1024',
- 'new_attr.text_only' => 'required|integer|in:0,1',
- ])->addAliases([
- ])->addArguments([
- 'token' => $pageArgs,
- 'save' => $structure,
- ])->addMessages([
- ]);
- if ($structure->other_attrs) {
- $v->addRules([
- 'other_attrs.*.allowed' => 'required|integer|in:0,1',
- 'other_attrs.*.required' => 'required|integer|in:0,1',
- 'other_attrs.*.format' => 'exist|string:trim|max:1024',
- 'other_attrs.*.body_format' => 'exist|string:trim|max:1024',
- 'other_attrs.*.text_only' => 'required|integer|in:0,1',
- ]);
- }
- $v->addRules([
- 'save' => 'required|check_all',
- ]);
- if ($v->validation($_POST)) {
- if ($id > 0) {
- $this->c->bbcode->update($id, $structure);
- $message = 'BBCode updated redirect';
- } else {
- $id = $this->c->bbcode->insert($structure);
- $message = 'BBCode added redirect';
- }
- return $this->c->Redirect->page('AdminBBCodeEdit', ['id' => $id])->message($message);
- }
- $this->fIswev = $v->getErrors();
- }
- $this->aCrumbs[] = [$this->formAction, $title];
- if ($id > 0) {
- $this->aCrumbs[] = [null, ['"%s"', $this->c->bbcode->bbcodeTable[$id]['bb_tag']]];
- }
- $this->aCrumbs[] = [$this->AdminBBCodeUrl, 'BBCode management'];
- $this->form = $this->formEdit($id, $structure);
- $this->titleForm = $title;
- $this->classForm = ['editbbcode'];
- $this->nameTpl = 'admin/form';
- return $this;
- }
- /**
- * Проверяет данные bb-кода
- */
- public function vCheckAll(Validator $v, string $txt, $attrs, Structure $structure): string
- {
- if (! empty($v->getErrors())) {
- return $txt;
- }
- $data = $v->getData();
- unset($data['token'], $data['save']);
- foreach ($data as $key => $value) {
- if ('type_new' === $key) {
- if (isset($value[0])) {
- $structure->type = $value;
- }
- } else {
- $structure->{$key} = $value;
- }
- }
- $error = $structure->getError();
- if (\is_array($error)) {
- if (1 === \count($error)) {
- $v->addError(\reset($error));
- } else {
- $v->addError($error);
- }
- }
- return $txt;
- }
- /**
- * Формирует данные для формы
- */
- protected function formEdit(int $id, Structure $structure): array
- {
- $form = [
- 'action' => $this->formAction,
- 'hidden' => [
- 'token' => $this->formToken,
- ],
- 'sets' => [],
- 'btns' => [
- 'reset' => [
- 'class' => ['f-opacity'],
- 'type' => 'btn',
- 'value' => __('Default structure'),
- 'link' => $this->c->Router->link(
- 'AdminBBCodeDefault',
- [
- 'id' => $id,
- ]
- ),
- ],
- 'save' => [
- 'type' => 'submit',
- 'value' => __('Save'),
- ],
- ],
- ];
- if (! $structure->isInDefault()) {
- unset($form['btns']['reset']);
- }
- $yn = [1 => __('Yes'), 0 => __('No')];
- $form['sets']['structure'] = [
- 'class' => ['structure'],
- // 'legend' => ,
- 'fields' => [
- 'tag' => [
- 'type' => $id > 0 ? 'str' : 'text',
- 'value' => $structure->tag,
- 'caption' => 'Tag label',
- 'help' => 'Tag info',
- 'maxlength' => '11',
- 'pattern' => '^[a-z\*][a-z\d-]{0,10}$',
- 'required' => true,
- ],
- 'type' => [
- 'type' => 'select',
- 'options' => $this->bbTypes,
- 'value' => $structure->type,
- 'caption' => 'Type label',
- 'help' => 'Type info',
- ],
- 'type_new' => [
- 'type' => 'text',
- 'value' => isset($this->bbTypes[$structure->type]) ? '' : $structure->type,
- 'caption' => 'Type label',
- 'help' => 'New type info',
- 'maxlength' => '20',
- 'pattern' => '^[a-z][a-z\d-]{0,19}$',
- ],
- 'parents' => [
- 'type' => 'multiselect',
- 'options' => $this->bbTypes,
- 'value' => $structure->parents,
- 'caption' => 'Parents label',
- 'help' => 'Parents info',
- 'size' => \min(15, \count($this->bbTypes)),
- 'required' => true,
- ],
- 'handler' => [
- 'class' => ['handler'],
- 'type' => 'textarea',
- 'value' => $structure->handler,
- 'caption' => 'Handler label',
- 'help' => 'Handler info',
- ],
- 'text_handler' => [
- 'class' => ['handler'],
- 'type' => 'textarea',
- 'value' => $structure->text_handler,
- 'caption' => 'Text handler label',
- 'help' => 'Text handler info',
- ],
- 'recursive' => [
- 'type' => 'radio',
- 'value' => true === $structure->recursive ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Recursive label',
- 'help' => 'Recursive info',
- ],
- 'text_only' => [
- 'type' => 'radio',
- 'value' => true === $structure->text_only ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Text only label',
- 'help' => 'Text only info',
- ],
- 'tags_only' => [
- 'type' => 'radio',
- 'value' => true === $structure->tags_only ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Tags only label',
- 'help' => 'Tags only info',
- ],
- 'pre' => [
- 'type' => 'radio',
- 'value' => true === $structure->pre ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Pre label',
- 'help' => 'Pre info',
- ],
- 'single' => [
- 'type' => 'radio',
- 'value' => true === $structure->single ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Single label',
- 'help' => 'Single info',
- ],
- 'auto' => [
- 'type' => 'radio',
- 'value' => true === $structure->auto ? 1 : 0,
- 'values' => $yn,
- 'caption' => 'Auto label',
- 'help' => 'Auto info',
- ],
- 'self_nesting' => [
- 'type' => 'number',
- 'value' => $structure->self_nesting > 0 ? $structure->self_nesting : 0,
- 'min' => '0',
- 'max' => '10',
- 'caption' => 'Self nesting label',
- 'help' => 'Self nesting info',
- ],
- ],
- ];
- $tagStr = $id > 0 ? $structure->tag : 'TAG';
- $form['sets']['no_attr'] = $this->formEditSub(
- $structure->no_attr,
- 'no_attr',
- 'no_attr',
- ['No attr subhead', $tagStr],
- 'Allowed no_attr info'
- );
- $form['sets']['def_attr'] = $this->formEditSub(
- $structure->def_attr,
- 'def_attr',
- 'def_attr',
- ['Def attr subhead', $tagStr],
- 'Allowed def_attr info'
- );
- foreach ($structure->other_attrs as $name => $attr) {
- $form['sets']["{$name}_attr"] = $this->formEditSub(
- $attr,
- $name,
- "{$name}_attr",
- ['Other attr subhead', $tagStr, $name],
- ['Allowed %s attr info', $name]
- );
- }
- $form['sets']['new_attr'] = $this->formEditSub(
- $structure->new_attr,
- 'new_attr',
- 'new_attr',
- 'New attr subhead',
- 'Allowed new_attr info'
- );
- return $form;
- }
- /**
- * Формирует данные для формы
- */
- protected function formEditSub(
- /* mixed */ $data,
- string $name,
- string $class,
- /* string|array */ $legend,
- /* string|array */ $info
- ): array {
- $yn = [1 => __('Yes'), 0 => __('No')];
- $fields = [];
- $other = '_attr' !== \substr($name, -5);
- $key = $other ? "other_attrs[{$name}]" : $name;
- if ('new_attr' === $name) {
- $fields["{$key}[name]"] = [
- 'type' => 'text',
- 'value' => $data['name'] ?? '',
- 'caption' => 'Attribute name label',
- 'help' => 'Attribute name info',
- 'maxlength' => '15',
- 'pattern' => '^[a-z-]{2,15}$',
- ];
- }
- $fields["{$key}[allowed]"] = [
- 'type' => 'radio',
- 'value' => null === $data ? 0 : 1,
- 'values' => $yn,
- 'caption' => 'Allowed label',
- 'help' => $info,
- ];
- if ('no_attr' !== $name) {
- $fields["{$key}[required]"] = [
- 'type' => 'radio',
- 'value' => empty($data['required']) ? 0 : 1,
- 'values' => $yn,
- 'caption' => 'Required label',
- 'help' => 'Required info',
- ];
- $fields["{$key}[format]"] = [
- 'class' => ['format'],
- 'type' => 'text',
- 'value' => $data['format'] ?? '',
- 'caption' => 'Format label',
- 'help' => 'Format info',
- ];
- }
- $fields["{$key}[body_format]"] = [
- 'class' => ['format'],
- 'type' => 'text',
- 'value' => $data['body_format'] ?? '',
- 'caption' => 'Body format label',
- 'help' => 'Body format info',
- ];
- $fields["{$key}[text_only]"] = [
- 'type' => 'radio',
- 'value' => empty($data['text_only']) ? 0 : 1,
- 'values' => $yn,
- 'caption' => 'Text only label',
- 'help' => 'Text only info',
- ];
- return [
- 'class' => ['attr', $class],
- 'legend' => $legend,
- 'fields' => $fields,
- ];
- }
- /**
- * Устанавливает структуру bb-кода по умолчанию
- */
- public function default(array $args, string $method): Page
- {
- if (! $this->c->Csrf->verify($args['token'], 'AdminBBCodeDefault', $args)) {
- return $this->c->Message->message($this->c->Csrf->getError());
- }
- $id = $args['id'];
- $structure = $this->c->BBStructure
- ->fromString($this->c->bbcode->load()->bbcodeTable[$id]['bb_structure'])
- ->setDefault();
- $this->c->bbcode->update($id, $structure);
- return $this->c->Redirect->page('AdminBBCodeEdit', ['id' => $id])->message('BBCode updated redirect');
- }
- }
|