Compare commits
No commits in common. "master" and "0.0073" have entirely different histories.
44 changed files with 167 additions and 412 deletions
|
@ -4,9 +4,6 @@
|
|||
#
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
#Options +FollowSymLinks # For extensions with symlinks
|
||||
##Options -FollowSymLinks +SymLinksIfOwnerMatch # or this (more security(?), more checks(!!!))
|
||||
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
|
|
25
.gitignore
vendored
25
.gitignore
vendored
|
@ -1,32 +1,19 @@
|
|||
/_*
|
||||
/.htaccess
|
||||
/index.php
|
||||
/app/config/main.php
|
||||
/app/config/_*
|
||||
/app/config/db/*
|
||||
/app/config/ext/*
|
||||
/app/cache/*
|
||||
/app/cache/**/*.php
|
||||
/app/cache/**/*.lock
|
||||
/app/cache/**/*.tmp
|
||||
/app/log/*
|
||||
/ext/*
|
||||
/public/img/avatars/*
|
||||
/public/img/og/*
|
||||
/public/.htaccess
|
||||
/public/index.php
|
||||
/public/img/*
|
||||
/public/style/*
|
||||
/public/upload/**/*
|
||||
!/public/img/sm/big_smile.png
|
||||
!/public/img/sm/cool.png
|
||||
!/public/img/sm/hmm.png
|
||||
!/public/img/sm/lol.png
|
||||
!/public/img/sm/mad.png
|
||||
!/public/img/sm/neutral.png
|
||||
!/public/img/sm/roll.png
|
||||
!/public/img/sm/sad.png
|
||||
!/public/img/sm/smile.png
|
||||
!/public/img/sm/tongue.png
|
||||
!/public/img/sm/wink.png
|
||||
!/public/img/sm/yikes.png
|
||||
!/public/style/font/*
|
||||
!/public/style/ForkBB/*
|
||||
!/public/style/sc/*
|
||||
/public/style/ForkBB_old/*
|
||||
!/public/upload/index.html
|
||||
!.gitkeep
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2017-2023 Visman (mio.visman@yandex.ru, https://github.com/MioVisman)
|
||||
Copyright (c) 2017-2023 Visman (mio.visman@yandex.ru)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -46,6 +46,7 @@ class Primary
|
|||
$confChange = [
|
||||
'multiple' => [
|
||||
'CtrlRouting' => \ForkBB\Controllers\Update::class,
|
||||
|
||||
'AdminUpdate' => \ForkBB\Models\Pages\Admin\Update::class,
|
||||
],
|
||||
];
|
||||
|
|
|
@ -104,18 +104,6 @@ class Routing
|
|||
}
|
||||
|
||||
// OAuth
|
||||
if (
|
||||
1 === $config->b_oauth_allow
|
||||
|| $user->isAdmin
|
||||
) {
|
||||
$r->add(
|
||||
$r::GET,
|
||||
'/reglog/callback/{name}',
|
||||
'RegLog:callback',
|
||||
'RegLogCallback'
|
||||
);
|
||||
}
|
||||
|
||||
if (1 === $config->b_oauth_allow) {
|
||||
$r->add(
|
||||
$r::PST,
|
||||
|
@ -123,6 +111,15 @@ class Routing
|
|||
'RegLog:redirect',
|
||||
'RegLogRedirect'
|
||||
);
|
||||
|
||||
if ($user->isAdmin) {
|
||||
$r->add(
|
||||
$r::GET,
|
||||
'/reglog/callback/{name}',
|
||||
'RegLog:callback',
|
||||
'RegLogCallback'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// просмотр разрешен
|
||||
|
@ -639,6 +636,7 @@ class Routing
|
|||
'Moderate:action',
|
||||
'Moderate'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// только админ
|
||||
|
|
|
@ -226,6 +226,8 @@ class FileCache implements CacheInterface
|
|||
{
|
||||
if (\function_exists('\\opcache_invalidate')) {
|
||||
\opcache_invalidate($file, true);
|
||||
} elseif (\function_exists('\\apc_delete_file')) {
|
||||
\apc_delete_file($file);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,6 @@ class Config
|
|||
switch ($type) {
|
||||
case 'ZERO':
|
||||
$type = 'NEW';
|
||||
|
||||
break;
|
||||
case 'NEW':
|
||||
case '=>':
|
||||
|
@ -181,7 +180,6 @@ class Config
|
|||
$value_before = $other;
|
||||
$other = '';
|
||||
$type = 'VALUE';
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ForkException('Config array cannot be parsed (3)');
|
||||
|
@ -221,7 +219,6 @@ class Config
|
|||
case 'VALUE':
|
||||
case 'VALUE_OR_KEY':
|
||||
$type = 'NEW';
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ForkException('Config array cannot be parsed (6)');
|
||||
|
@ -237,7 +234,6 @@ class Config
|
|||
$value = null;
|
||||
$value_before = '';
|
||||
$type = '=>';
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ForkException('Config array cannot be parsed (7)');
|
||||
|
@ -255,8 +251,7 @@ class Config
|
|||
case 'VALUE_OR_KEY':
|
||||
case 'VALUE':
|
||||
case '=>':
|
||||
$other .= $token;
|
||||
|
||||
$other .= $token;
|
||||
break;
|
||||
default:
|
||||
throw new ForkException('Config array cannot be parsed (8)');
|
||||
|
@ -296,11 +291,9 @@ class Config
|
|||
}
|
||||
|
||||
$type = 'VALUE_OR_KEY';
|
||||
|
||||
break;
|
||||
case '=>':
|
||||
$type = 'VALUE';
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ForkException('Config array cannot be parsed (10)');
|
||||
|
@ -318,11 +311,11 @@ class Config
|
|||
protected function isFormat(mixed $data): bool
|
||||
{
|
||||
return \is_array($data)
|
||||
&& \array_key_exists('value', $data)
|
||||
&& \array_key_exists('value_before', $data)
|
||||
&& \array_key_exists('value_after', $data)
|
||||
&& \array_key_exists('key_before', $data)
|
||||
&& \array_key_exists('key_after', $data);
|
||||
&& \array_key_exists('value', $data)
|
||||
&& \array_key_exists('value_before', $data)
|
||||
&& \array_key_exists('value_after', $data)
|
||||
&& \array_key_exists('key_before', $data)
|
||||
&& \array_key_exists('key_after', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -436,7 +429,6 @@ class Config
|
|||
return false;
|
||||
} else {
|
||||
$result = $config[$key];
|
||||
|
||||
unset($config[$key]);
|
||||
|
||||
return $result;
|
||||
|
|
|
@ -226,12 +226,10 @@ class DB
|
|||
case 's':
|
||||
case 'f':
|
||||
$value = [1];
|
||||
|
||||
break;
|
||||
default:
|
||||
$value = [1];
|
||||
$type = 's';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -67,8 +67,8 @@ class ErrorHandler
|
|||
\set_error_handler([$this, 'errorHandler'], \E_ALL);
|
||||
\set_exception_handler([$this, 'exceptionHandler']);
|
||||
\register_shutdown_function([$this, 'shutdownHandler']);
|
||||
\ob_start();
|
||||
|
||||
\ob_start();
|
||||
$this->obLevel = \ob_get_level();
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,6 @@ class ErrorHandler
|
|||
if (isset($error['exception'])) {
|
||||
$context['exception'] = $error['exception'];
|
||||
}
|
||||
|
||||
$context['headers'] = false;
|
||||
|
||||
$this->c->Log->{$method}($this->message($error), $context);
|
||||
|
@ -280,19 +279,15 @@ EOT;
|
|||
switch ($type) {
|
||||
case 'boolean':
|
||||
$type = $arg ? 'true' : 'false';
|
||||
|
||||
break;
|
||||
case 'array':
|
||||
$type .= '(' . \count($arg) . ')';
|
||||
|
||||
break;
|
||||
case 'resource':
|
||||
$type = \get_resource_type($arg);
|
||||
|
||||
break;
|
||||
case 'object':
|
||||
$type .= '{' . \get_class($arg) . '}';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -301,8 +296,8 @@ EOT;
|
|||
}
|
||||
}
|
||||
$line .= ')';
|
||||
$line = $this->e(\str_replace($this->hidePath, '...', $line));
|
||||
|
||||
$line = $this->e(\str_replace($this->hidePath, '...', $line));
|
||||
echo "<li>{$line}</li>";
|
||||
}
|
||||
|
||||
|
|
|
@ -1271,7 +1271,7 @@ class Files
|
|||
/**
|
||||
* Переменные конфига подключения
|
||||
*/
|
||||
protected int $actMaxRedir = 5;
|
||||
protected int $actMaxRedir = 10;
|
||||
protected float $actTimeout = 15.0;
|
||||
protected string $actUAgent = 'ForkBB downloader (%s)';
|
||||
protected array $actHeader = [
|
||||
|
@ -1291,8 +1291,6 @@ class Files
|
|||
return false;
|
||||
}
|
||||
|
||||
\curl_setopt($ch, \CURLOPT_PROTOCOLS, \CURLPROTO_HTTPS | \CURLPROTO_HTTP);
|
||||
\curl_setopt($ch, \CURLOPT_REDIR_PROTOCOLS, \CURLPROTO_HTTPS);
|
||||
\curl_setopt($ch, \CURLOPT_HTTPGET, true);
|
||||
\curl_setopt($ch, \CURLOPT_HEADER, false);
|
||||
\curl_setopt($ch, \CURLOPT_HTTPHEADER, $this->actHeader);
|
||||
|
|
|
@ -55,7 +55,7 @@ class Func
|
|||
|
||||
public function __construct(protected Container $c)
|
||||
{
|
||||
$this->fUrl = $c->isInit('FRIENDLY_URL') ? $c->FRIENDLY_URL : [];
|
||||
$this->fUrl = $this->c->FRIENDLY_URL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@ class Mail
|
|||
|
||||
public function __construct(string $host, string $user, #[SensitiveParameter] string $pass, int $ssl, string $eol, protected Container $c)
|
||||
{
|
||||
if ('' !== $host) {
|
||||
if ('' != $host) {
|
||||
$hp = \explode(':', $host, 2);
|
||||
|
||||
if (
|
||||
|
@ -103,10 +103,11 @@ class Mail
|
|||
return false;
|
||||
}
|
||||
|
||||
if (true === $strict) {
|
||||
|
||||
if ($strict) {
|
||||
$level = $this->c->ErrorHandler->logOnly(\E_WARNING);
|
||||
|
||||
if (\is_string($ip)) {
|
||||
if ($ip) {
|
||||
$mx = \checkdnsrr($ip, 'MX'); // ipv6 в пролёте :(
|
||||
} else {
|
||||
$mx = \dns_get_record($domainASCII, \DNS_MX);
|
||||
|
|
|
@ -140,7 +140,13 @@ class Validator
|
|||
public function addRules(array $list): Validator
|
||||
{
|
||||
foreach ($list as $field => $raw) {
|
||||
$rules = [];
|
||||
$rules = [];
|
||||
$suffix = null;
|
||||
|
||||
// правило для элементов массива
|
||||
if (\strpos($field, '.') > 0) {
|
||||
list($field, $suffix) = \explode('.', $field, 2);
|
||||
}
|
||||
|
||||
if (! \is_array($raw)) {
|
||||
$raw = \explode('|', $raw);
|
||||
|
@ -176,34 +182,13 @@ class Validator
|
|||
$rules[$name] = $rule ?? '';
|
||||
}
|
||||
|
||||
if (\strpos($field, '.') > 0) {
|
||||
$fields = \explode('.', $field);
|
||||
$n = \count($fields);
|
||||
$start = true;
|
||||
$r = &$this->rules;
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (true === $start) {
|
||||
$this->fields[$field] = $field;
|
||||
$start = false;
|
||||
}
|
||||
|
||||
if (--$n) {
|
||||
if (! isset($r[$field]['array'])) {
|
||||
$r[$field]['array'] = [];
|
||||
}
|
||||
|
||||
$r = &$r[$field]['array'];
|
||||
} else {
|
||||
$r[$field] = $rules;
|
||||
}
|
||||
}
|
||||
|
||||
unset ($r);
|
||||
if (isset($suffix)) {
|
||||
$this->rules[$field]['array'][$suffix] = $rules;
|
||||
} else {
|
||||
$this->rules[$field] = $rules;
|
||||
$this->fields[$field] = $field;
|
||||
$this->rules[$field] = $rules;
|
||||
}
|
||||
|
||||
$this->fields[$field] = $field;
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@ -654,32 +639,35 @@ class Validator
|
|||
if ('' === $name) {
|
||||
$result = $this->checkValue($value, $rules, $field);
|
||||
} else {
|
||||
if (false !== \strpos($name, '.')) {
|
||||
if (! \preg_match('%^([^.]+)(?:\.(.+))?$%', $name, $matches)) {
|
||||
throw new RuntimeException("Bad path '{$name}'");
|
||||
}
|
||||
|
||||
$key = $matches[1];
|
||||
$name = $matches[2] ?? '';
|
||||
|
||||
if (
|
||||
'*' === $name
|
||||
'*' === $key
|
||||
&& \is_array($value)
|
||||
) {
|
||||
foreach ($value as $i => $cur) {
|
||||
$this->recArray($value[$i], $result[$i], '', $rules, $field);
|
||||
$this->recArray($value[$i], $result[$i], $name, $rules, $field);
|
||||
}
|
||||
} elseif (
|
||||
'*' !== $name
|
||||
'*' !== $key
|
||||
&& \is_array($value)
|
||||
&& \array_key_exists($name, $value)
|
||||
&& \array_key_exists($key, $value)
|
||||
) {
|
||||
$this->recArray($value[$name], $result[$name], '', $rules, $field);
|
||||
$this->recArray($value[$key], $result[$key], $name, $rules, $field);
|
||||
} elseif (isset($rules['required'])) {
|
||||
$tmp1 = null;
|
||||
$tmp2 = null;
|
||||
$this->recArray($tmp1, $tmp2, '', $rules, $field);
|
||||
} elseif ('*' === $name) {
|
||||
$this->recArray($tmp1, $tmp2, $name, $rules, $field);
|
||||
} elseif ('*' === $key) {
|
||||
$result = []; // ???? а может там не отсутствие элемента, а не array?
|
||||
} else {
|
||||
$value[$name] = null;
|
||||
$this->recArray($value[$name], $result[$name], '', $rules, $field);
|
||||
$value[$key] = null;
|
||||
$this->recArray($value[$key], $result[$key], $name, $rules, $field);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,8 @@ class BBCodeList extends Model
|
|||
{
|
||||
if (\function_exists('\\opcache_invalidate')) {
|
||||
\opcache_invalidate($this->fileCache, true);
|
||||
} elseif (\function_exists('\\apc_delete_file')) {
|
||||
\apc_delete_file($this->fileCache);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -161,10 +161,7 @@ class Extension extends Model
|
|||
|
||||
$path = $this->fileData['path'] . '/' . \ltrim($cur['file'], '\\/');
|
||||
|
||||
if (
|
||||
$this->c->Files->isBadPath($path)
|
||||
|| ! \is_file($path)
|
||||
) {
|
||||
if (! \is_file($path)) {
|
||||
return ['Template file \'%s\' not found', $cur['file']];
|
||||
}
|
||||
|
||||
|
@ -184,49 +181,6 @@ class Extension extends Model
|
|||
}
|
||||
}
|
||||
|
||||
if ($this->fileData['extra']['symlinks']) {
|
||||
foreach ($this->fileData['extra']['symlinks'] as $cur) {
|
||||
switch($cur['type']) {
|
||||
case 'public':
|
||||
if (
|
||||
empty($cur['target'])
|
||||
|| empty($cur['link'])
|
||||
|| $this->c->Files->isBadPath($cur['target'])
|
||||
|| $this->c->Files->isBadPath($cur['link'])
|
||||
) {
|
||||
return 'Bad symlink';
|
||||
}
|
||||
|
||||
$target = $this->fileData['path'] . '/' . \trim($cur['target'], '\\/');
|
||||
|
||||
if (
|
||||
! \is_file($target)
|
||||
&& ! \is_dir($target)
|
||||
) {
|
||||
return ['Target \'%s\' not found', $cur['target']];
|
||||
}
|
||||
|
||||
$link = $this->c->DIR_PUBLIC . '/' . \trim($cur['link'], '\\/');
|
||||
|
||||
if (
|
||||
! \is_link($link)
|
||||
&& (
|
||||
\is_file($link)
|
||||
|| \is_dir($link)
|
||||
)
|
||||
) {
|
||||
return ['Link \'%s\' already exists', $cur['link']];
|
||||
}
|
||||
|
||||
$this->prepareData['symlinks'][$target] = $link;
|
||||
|
||||
break;
|
||||
default:
|
||||
return 'Invalid symlink type';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -150,10 +150,6 @@ class Extensions extends Manager
|
|||
'extra' => 'required|array',
|
||||
'extra.display-name' => 'required|string',
|
||||
'extra.requirements' => 'array',
|
||||
'extra.symlinks' => 'array',
|
||||
'extra.symlinks.*.type' => 'required|string|in:public',
|
||||
'extra.symlinks.*.target' => 'required|string',
|
||||
'extra.symlinks.*.link' => 'required|string',
|
||||
'extra.templates' => 'array',
|
||||
'extra.templates.*.type' => 'required|string|in:pre',
|
||||
'extra.templates.*.template' => 'required|string',
|
||||
|
@ -168,28 +164,15 @@ class Extensions extends Manager
|
|||
$result = [];
|
||||
|
||||
foreach ($files as $path => $file) {
|
||||
$context = null;
|
||||
|
||||
if (! \is_array($file)) {
|
||||
$context = [
|
||||
'errors' => ['Bad json'],
|
||||
];
|
||||
continue;
|
||||
} elseif (! $v->validation($file)) {
|
||||
$context = [
|
||||
'errors' => \array_map('\\ForkBB\__', $v->getErrorsWithoutType()),
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $context) {
|
||||
$data = $v->getData(true);
|
||||
$data['path'] = $path;
|
||||
$result[$v->name] = $data;
|
||||
} else {
|
||||
$context['headers'] = false;
|
||||
$path = \preg_replace('%^.+((?:[\\\\/]+[^\\\\/]+){3})$%', '$1', $path);
|
||||
|
||||
$this->c->Log->debug("Extension: Bad structure for {$path}", $context);
|
||||
}
|
||||
$data = $v->getData(true);
|
||||
$data['path'] = $path;
|
||||
$result[$v->name] = $data;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -255,7 +238,6 @@ class Extensions extends Manager
|
|||
return false;
|
||||
}
|
||||
|
||||
$this->setSymlinks($ext);
|
||||
$this->updateIndividual();
|
||||
|
||||
$this->c->DB->exec($query, $vars);
|
||||
|
@ -290,8 +272,6 @@ class Extensions extends Manager
|
|||
'fileData' => $ext->fileData,
|
||||
]);
|
||||
|
||||
$this->removeSymlinks($ext);
|
||||
|
||||
if (true !== $this->updateCommon($ext)) {
|
||||
$this->error = 'An error occurred in updateCommon';
|
||||
|
||||
|
@ -360,10 +340,6 @@ class Extensions extends Manager
|
|||
'fileData' => $ext->fileData,
|
||||
]);
|
||||
|
||||
if ($oldStatus) {
|
||||
$this->removeSymlinks($ext);
|
||||
}
|
||||
|
||||
if (true !== $this->updateCommon($ext)) {
|
||||
$this->error = 'An error occurred in updateCommon';
|
||||
|
||||
|
@ -371,7 +347,6 @@ class Extensions extends Manager
|
|||
}
|
||||
|
||||
if ($oldStatus) {
|
||||
$this->setSymlinks($ext);
|
||||
$this->updateIndividual();
|
||||
}
|
||||
|
||||
|
@ -404,7 +379,6 @@ class Extensions extends Manager
|
|||
'fileData' => $ext->fileData,
|
||||
]);
|
||||
|
||||
$this->setSymlinks($ext);
|
||||
$this->updateIndividual();
|
||||
|
||||
$this->c->DB->exec($query, $vars);
|
||||
|
@ -436,7 +410,6 @@ class Extensions extends Manager
|
|||
'fileData' => $ext->fileData,
|
||||
]);
|
||||
|
||||
$this->removeSymlinks($ext);
|
||||
$this->updateIndividual();
|
||||
|
||||
$this->c->DB->exec($query, $vars);
|
||||
|
@ -484,6 +457,8 @@ class Extensions extends Manager
|
|||
} else {
|
||||
if (\function_exists('\\opcache_invalidate')) {
|
||||
\opcache_invalidate($file, true);
|
||||
} elseif (\function_exists('\\apc_delete_file')) {
|
||||
\apc_delete_file($file);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -569,37 +544,4 @@ class Extensions extends Manager
|
|||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создает симлинки для расширения
|
||||
*/
|
||||
protected function setSymlinks(Extension $ext): bool
|
||||
{
|
||||
$data = $this->loadDataFromFile($this->commonFile);
|
||||
$symlinks = $data[$ext->name]['symlinks'] ?? [];
|
||||
|
||||
foreach ($symlinks as $target => $link) {
|
||||
\symlink($target, $link);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет симлинки расширения
|
||||
*/
|
||||
protected function removeSymlinks(Extension $ext): bool
|
||||
{
|
||||
$data = $this->loadDataFromFile($this->commonFile);
|
||||
$symlinks = $data[$ext->name]['symlinks'] ?? [];
|
||||
|
||||
foreach ($symlinks as $target => $link) {
|
||||
if (\is_link($link)) {
|
||||
\is_file($link) ? \unlink($link) : \rmdir($link);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ class Delete extends Action
|
|||
$uids[$arg->id] = $arg->id;
|
||||
$isUser = 1;
|
||||
} elseif ($arg instanceof Forum) {
|
||||
if (! $this->manager->get($arg->id) instanceof Forum) {
|
||||
if (! $this->c->forums->get($arg->id) instanceof Forum) {
|
||||
throw new RuntimeException('Forum unavailable');
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class Forum extends DataModel
|
|||
|
||||
return null;
|
||||
} else {
|
||||
return $this->manager->get($this->parent_forum_id);
|
||||
return $this->c->forums->get($this->parent_forum_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ class Forum extends DataModel
|
|||
|
||||
if (\is_array($attr)) {
|
||||
foreach ($attr as $id) {
|
||||
$sub[$id] = $this->manager->get($id);
|
||||
$sub[$id] = $this->c->forums->get($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ class Forum extends DataModel
|
|||
|
||||
if (\is_array($attr)) {
|
||||
foreach ($attr as $id) {
|
||||
$all[$id] = $this->manager->get($id);
|
||||
$all[$id] = $this->c->forums->get($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,7 +360,7 @@ class Forum extends DataModel
|
|||
}
|
||||
}
|
||||
|
||||
$attr = $this->manager->create([
|
||||
$attr = $this->c->forums->create([
|
||||
'num_topics' => $numT,
|
||||
'num_posts' => $numP,
|
||||
'last_post' => $time,
|
||||
|
|
|
@ -34,7 +34,7 @@ class Forums extends Manager
|
|||
*/
|
||||
public function create(array $attrs = []): Forum
|
||||
{
|
||||
return $this->c->ForumModel->setManager($this)->setModelAttrs($attrs);
|
||||
return $this->c->ForumModel->setModelAttrs($attrs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -44,7 +44,7 @@ class UpdateUsername extends Action
|
|||
$isMod = true;
|
||||
$forum->modAdd($user); // переименование модератора
|
||||
|
||||
$this->manager->update($forum);
|
||||
$this->c->forums->update($forum);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ declare(strict_types=1);
|
|||
namespace ForkBB\Models;
|
||||
|
||||
use ForkBB\Core\Container;
|
||||
use ForkBB\Models\Manager;
|
||||
|
||||
class Model
|
||||
{
|
||||
|
@ -35,11 +34,6 @@ class Model
|
|||
*/
|
||||
protected array $zDepend = [];
|
||||
|
||||
/**
|
||||
* Текущий Manager для модели
|
||||
*/
|
||||
protected Manager $manager;
|
||||
|
||||
public function __construct(protected Container $c)
|
||||
{
|
||||
}
|
||||
|
@ -171,14 +165,4 @@ class Model
|
|||
|
||||
return $this->c->$key->setModel($this)->$name(...$args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Объявление менеджера
|
||||
*/
|
||||
public function setManager(Manager $manager): Model
|
||||
{
|
||||
$this->manager = $manager;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ class Categories extends Admin
|
|||
$v = $this->c->Validator->reset()
|
||||
->addRules([
|
||||
'token' => 'token:AdminCategories',
|
||||
'form' => 'required|array',
|
||||
'form.*.cat_name' => 'required|string:trim|max:80',
|
||||
'form.*.disp_position' => 'required|integer|min:0|max:9999999999',
|
||||
'new' => 'exist|string:trim|max:80'
|
||||
|
|
|
@ -29,9 +29,8 @@ class Censoring extends Admin
|
|||
->addRules([
|
||||
'token' => 'token:AdminCensoring',
|
||||
'b_censoring' => 'required|integer|in:0,1',
|
||||
'form' => 'required|array',
|
||||
'form.*.search_for' => 'exist|string:trim|max:60',
|
||||
'form.*.replace_with' => 'exist|string:trim|max:60',
|
||||
'form.*.search_for' => 'string:trim|max:60',
|
||||
'form.*.replace_with' => 'string:trim|max:60',
|
||||
])->addAliases([
|
||||
])->addArguments([
|
||||
])->addMessages([
|
||||
|
|
|
@ -102,7 +102,6 @@ class Forums extends Admin
|
|||
$v = $this->c->Validator->reset()
|
||||
->addRules([
|
||||
'token' => 'token:AdminForums',
|
||||
'form' => 'required|array',
|
||||
'form.*.disp_position' => 'required|integer|min:0|max:9999999999',
|
||||
])->addAliases([
|
||||
])->addArguments([
|
||||
|
@ -367,7 +366,7 @@ class Forums extends Admin
|
|||
'forum_desc' => 'exist|string:trim|max:65000 bytes|html',
|
||||
'parent' => 'required|integer|in:' . \implode(',', $this->listOfIndexes),
|
||||
'sort_by' => 'required|integer|in:0,1,2,4,5,6',
|
||||
'redirect_url' => 'string:trim|max:255|regex:%^(?:https?://.+)?$%', //???? это поле может быть отключено в форме
|
||||
'redirect_url' => 'string:trim|max:255', //???? это поле может быть отключено в форме
|
||||
'no_sum_mess' => 'required|integer|in:0,1',
|
||||
'perms.*.read_forum' => 'checkbox',
|
||||
'perms.*.post_replies' => 'checkbox',
|
||||
|
|
|
@ -68,10 +68,7 @@ class Forum extends Page
|
|||
$this->formMod = $this->formMod($forum);
|
||||
}
|
||||
|
||||
if (
|
||||
$this->c->config->i_feed_type > 0
|
||||
&& $forum->num_posts > 0
|
||||
) {
|
||||
if ($this->c->config->i_feed_type > 0) {
|
||||
$feedType = 2 === $this->c->config->i_feed_type ? 'atom' : 'rss';
|
||||
|
||||
$this->pageHeader('feed', 'link', 0, [
|
||||
|
|
|
@ -613,7 +613,7 @@ class Moderate extends Page
|
|||
$delLinks = [];
|
||||
|
||||
foreach ($this->c->forums->depthList($root, 0) as $forum) {
|
||||
if ($forum->redirect_url) {
|
||||
if ('' != $forum->redirect_url) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -720,7 +720,7 @@ class Moderate extends Page
|
|||
'type' => 'checkbox',
|
||||
'value' => $forum->id,
|
||||
'checked' => ! empty($ft[$forum->id]),
|
||||
'disabled' => ! empty($forum->redirect_url),
|
||||
'disabled' => '' != $forum->redirect_url,
|
||||
'caption' => 'Redir label',
|
||||
];
|
||||
$form['sets']["forum{$forum->id}"] = [
|
||||
|
|
|
@ -31,7 +31,7 @@ abstract class AbstractPM extends Page
|
|||
$this->fIndex = self::FI_PM;
|
||||
$this->onlinePos = 'pm';
|
||||
$this->robots = 'noindex, nofollow';
|
||||
// $this->hhsLevel = 'secure';
|
||||
$this->hhsLevel = 'secure';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,14 +38,12 @@ class Poll extends Page
|
|||
->addValidators([
|
||||
])->addRules([
|
||||
'token' => 'token:Poll',
|
||||
'poll_vote' => 'required|array',
|
||||
'poll_vote.*.*' => 'required|integer',
|
||||
'vote' => 'required|string',
|
||||
])->addAliases([
|
||||
])->addArguments([
|
||||
'token' => $args,
|
||||
])->addMessages([
|
||||
'poll_vote' => 'The poll structure is broken',
|
||||
'poll_vote.*.*' => 'The poll structure is broken',
|
||||
]);
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ class Mod extends Profile
|
|||
'type' => 'checkbox',
|
||||
'value' => $forum->id,
|
||||
'checked' => isset($this->curForums[$forum->id]) && $this->curUser->isModerator($forum),
|
||||
'disabled' => ! isset($this->curForums[$forum->id]) || ! empty($this->curForums[$forum->id]->redirect_url),
|
||||
'disabled' => ! isset($this->curForums[$forum->id]) || '' != $this->curForums[$forum->id]->redirect_url,
|
||||
'caption' => 'Moderator label',
|
||||
];
|
||||
$form['sets']["forum{$forum->id}"] = [
|
||||
|
|
|
@ -52,15 +52,7 @@ class Search extends Profile
|
|||
|
||||
if ($v->validation($_POST)) {
|
||||
if (! empty($v->follow)) {
|
||||
$unfollow = [];
|
||||
|
||||
foreach ($this->curForums as $id => $forum) {
|
||||
if (empty($forum->redirect_url)) {
|
||||
$unfollow[$id] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
$unfollow = \array_diff($unfollow, $v->follow);
|
||||
$unfollow = \array_diff(\array_keys($this->curForums), $v->follow);
|
||||
|
||||
\sort($unfollow, \SORT_NUMERIC);
|
||||
|
||||
|
@ -194,7 +186,7 @@ class Search extends Profile
|
|||
'type' => 'checkbox',
|
||||
'value' => $forum->id,
|
||||
'checked' => ! isset($this->curUnfollowed[$forum->id]),
|
||||
'disabled' => ! empty($this->curForums[$forum->id]->redirect_url),
|
||||
'disabled' => '' != $this->curForums[$forum->id]->redirect_url,
|
||||
'caption' => 'Follow label',
|
||||
];
|
||||
$form['sets']["forum{$forum->id}"] = [
|
||||
|
|
|
@ -257,10 +257,7 @@ class View extends Profile
|
|||
];
|
||||
|
||||
if ($this->curUser->last_post > 0) {
|
||||
if (
|
||||
1 === $this->user->g_search
|
||||
&& ! $this->user->isBot
|
||||
) {
|
||||
if (1 === $this->user->g_search) {
|
||||
$fields['posts'] = [
|
||||
'class' => ['pline'],
|
||||
'type' => 'link',
|
||||
|
@ -274,7 +271,6 @@ class View extends Profile
|
|||
]
|
||||
),
|
||||
'title' => __('Show posts'),
|
||||
'rel' => 'nofollow',
|
||||
];
|
||||
$fields['topics'] = [
|
||||
'class' => ['pline'],
|
||||
|
@ -289,7 +285,6 @@ class View extends Profile
|
|||
]
|
||||
),
|
||||
'title' => __('Show topics'),
|
||||
'rel' => 'nofollow',
|
||||
];
|
||||
} elseif ($this->userRules->showPostCount) {
|
||||
$fields['posts'] = [
|
||||
|
|
|
@ -501,10 +501,7 @@ class Search extends Page
|
|||
case 'topics':
|
||||
case 'topics_subscriptions':
|
||||
case 'forums_subscriptions':
|
||||
if (
|
||||
! isset($uid)
|
||||
|| $this->user->isBot
|
||||
) {
|
||||
if (! isset($uid)) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace ForkBB\Models\Post;
|
|||
use ForkBB\Models\Action;
|
||||
use ForkBB\Models\Topic\Topic;
|
||||
use ForkBB\Models\Forum\Forum;
|
||||
use PDO;
|
||||
|
||||
class Feed extends Action
|
||||
{
|
||||
|
@ -51,28 +50,13 @@ class Feed extends Action
|
|||
$vars = [
|
||||
':forums' => $ids,
|
||||
];
|
||||
$query = 'SELECT p.id
|
||||
$query = 'SELECT p.id as pid, p.poster as username, p.poster_id as uid, p.message as content,
|
||||
p.hide_smilies, p.posted, p.edited, t.id as tid, t.subject as topic_name, t.forum_id as fid
|
||||
FROM ::posts AS p
|
||||
INNER JOIN ::topics AS t ON t.id=p.topic_id
|
||||
WHERE t.forum_id IN (?ai:forums)
|
||||
ORDER BY p.id DESC
|
||||
LIMIT 50';
|
||||
|
||||
$ids = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
if (empty($ids)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$vars = [
|
||||
':ids' => $ids,
|
||||
];
|
||||
$query = 'SELECT p.id as pid, p.poster as username, p.poster_id as uid, p.message as content,
|
||||
p.hide_smilies, p.posted, p.edited, t.id as tid, t.subject as topic_name, t.forum_id as fid
|
||||
FROM ::posts AS p
|
||||
INNER JOIN ::topics AS t ON t.id=p.topic_id
|
||||
WHERE p.id IN (?ai:ids)
|
||||
ORDER BY p.id DESC';
|
||||
}
|
||||
|
||||
return $this->c->DB->query($query, $vars)->fetchAll();
|
||||
|
|
|
@ -267,9 +267,7 @@ abstract class Driver extends Model
|
|||
break;
|
||||
}
|
||||
|
||||
\curl_setopt($ch, \CURLOPT_PROTOCOLS, \CURLPROTO_HTTPS | \CURLPROTO_HTTP);
|
||||
\curl_setopt($ch, \CURLOPT_REDIR_PROTOCOLS, \CURLPROTO_HTTPS);
|
||||
\curl_setopt($ch, \CURLOPT_MAXREDIRS, 5);
|
||||
\curl_setopt($ch, \CURLOPT_MAXREDIRS, 10);
|
||||
\curl_setopt($ch, \CURLOPT_TIMEOUT, 10);
|
||||
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
|
||||
\curl_setopt($ch, \CURLOPT_HEADER, false);
|
||||
|
|
|
@ -31,66 +31,49 @@ class ActionP extends Method
|
|||
return [];
|
||||
}
|
||||
|
||||
$query = null;
|
||||
|
||||
switch ($action) {
|
||||
case 'search':
|
||||
$list = $this->model->queryIds;
|
||||
|
||||
$this->model->numPages = (int) \ceil(($this->model->count($list) ?: 1) / $this->c->user->disp_posts);
|
||||
|
||||
break;
|
||||
case 'posts':
|
||||
$vars = [
|
||||
':forums' => $forums,
|
||||
':uid' => $uid,
|
||||
];
|
||||
$query = 'SELECT COUNT(p.id)
|
||||
$query = 'SELECT p.id
|
||||
FROM ::posts AS p
|
||||
INNER JOIN ::topics AS t ON t.id=p.topic_id
|
||||
WHERE p.poster_id=?i:uid AND t.forum_id IN (?ai:forums)';
|
||||
|
||||
$count = (int) $this->c->DB->query($query, $vars)->fetchColumn();
|
||||
|
||||
$this->model->numPages = (int) \ceil(($count ?: 1) / $this->c->user->disp_posts);
|
||||
WHERE p.poster_id=?i:uid AND t.forum_id IN (?ai:forums)
|
||||
ORDER BY p.posted DESC';
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException('Unknown action: ' . $action);
|
||||
}
|
||||
|
||||
if (null !== $query) {
|
||||
$vars = [
|
||||
':forums' => $forums,
|
||||
':uid' => $uid,
|
||||
];
|
||||
|
||||
$list = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
$this->model->numPages = (int) \ceil(($this->model->count($list) ?: 1) / $this->c->user->disp_posts);
|
||||
|
||||
// нет такой страницы в результате поиска
|
||||
if (! $this->model->hasPage()) {
|
||||
return false;
|
||||
// результат пуст
|
||||
} elseif (empty($list)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
switch ($action) {
|
||||
case 'search':
|
||||
// результат пуст
|
||||
if (empty($list)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->model->idsList = $this->model->slice(
|
||||
$list,
|
||||
($this->model->page - 1) * $this->c->user->disp_posts,
|
||||
(int) $this->c->user->disp_posts
|
||||
);
|
||||
|
||||
break;
|
||||
case 'posts':
|
||||
$vars[':offset'] = ($this->model->page - 1) * $this->c->user->disp_posts;
|
||||
$vars[':rows'] = (int) $this->c->user->disp_posts;
|
||||
|
||||
$query = 'SELECT p.id
|
||||
FROM ::posts AS p
|
||||
INNER JOIN ::topics AS t ON t.id=p.topic_id
|
||||
WHERE p.poster_id=?i:uid AND t.forum_id IN (?ai:forums)
|
||||
ORDER BY p.posted DESC
|
||||
LIMIT ?i:rows OFFSET ?i:offset';
|
||||
|
||||
$this->model->idsList = $this->c->DB->query($query, $vars)->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
break;
|
||||
}
|
||||
$this->model->idsList = $this->model->slice(
|
||||
$list,
|
||||
($this->model->page - 1) * $this->c->user->disp_posts,
|
||||
(int) $this->c->user->disp_posts
|
||||
);
|
||||
|
||||
return $this->c->posts->view($this->model);
|
||||
}
|
||||
|
|
|
@ -78,8 +78,8 @@ class ActionT extends Method
|
|||
*/
|
||||
// упрощенный запрос для больших форумов, дополнительная обработка ниже
|
||||
$query = 'SELECT DISTINCT t.id, t.last_post
|
||||
FROM ::topics AS t
|
||||
INNER JOIN ::posts AS p ON t.id=p.topic_id
|
||||
FROM forum_topics AS t
|
||||
INNER JOIN forum_posts AS p ON t.id=p.topic_id
|
||||
WHERE t.forum_id IN (?ai:forums) AND t.moved_to=0 AND p.poster_id=?i:uid';
|
||||
|
||||
break;
|
||||
|
|
|
@ -119,15 +119,3 @@ msgstr "An error occurred in updateCommon."
|
|||
|
||||
msgid "Empty"
|
||||
msgstr "Empty"
|
||||
|
||||
msgid "Invalid symlink type"
|
||||
msgstr "Invalid symlink type."
|
||||
|
||||
msgid "Bad symlink"
|
||||
msgstr "Bad symlink."
|
||||
|
||||
msgid "Target '%s' not found"
|
||||
msgstr "Target '%s' not found."
|
||||
|
||||
msgid "Link '%s' already exists"
|
||||
msgstr "Link '%s' already exists."
|
||||
|
|
|
@ -119,15 +119,3 @@ msgstr "Возникла ошибка в updateCommon."
|
|||
|
||||
msgid "Empty"
|
||||
msgstr "Пусто"
|
||||
|
||||
msgid "Invalid symlink type"
|
||||
msgstr "Неверный тип символической ссылки."
|
||||
|
||||
msgid "Bad symlink"
|
||||
msgstr "Плохая символическая ссылка."
|
||||
|
||||
msgid "Target '%s' not found"
|
||||
msgstr "Target '%s' отсутствует."
|
||||
|
||||
msgid "Link '%s' already exists"
|
||||
msgstr "Link '%s' уже существует."
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<aside id="fork-debug">
|
||||
<!-- PRE inStart -->
|
||||
<p class="f-sim-header">{!! __('Debug table') !!}</p>
|
||||
<p id="id-fdebugtime">t = {{ num(\microtime(true) - $p->start, 3) }} : q = {{ $p->numQueries}} : m = {{ size(\memory_get_usage()) }} / {{ size(\memory_get_peak_usage()) }}</p>
|
||||
<p id="id-fdebugtime">[ {!! __(['Generated in %1$s, %2$s queries', num(\microtime(true) - $p->start, 3), $p->numQueries]) !!} - {!! __(['Memory %1$s, Peak %2$s', size(\memory_get_usage()), size(\memory_get_peak_usage())]) !!} ]</p>
|
||||
@if ($p->queries)
|
||||
<table id="fork-dgtable">
|
||||
<thead id="fork-dgthead">
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
#
|
||||
AddDefaultCharset UTF-8
|
||||
|
||||
#Options +FollowSymLinks # For extensions with symlinks
|
||||
##Options -FollowSymLinks +SymLinksIfOwnerMatch # or this (more security(?), more checks(!!!))
|
||||
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
|
|
|
@ -10,6 +10,17 @@
|
|||
top: 1rem;
|
||||
}
|
||||
|
||||
#fork-a-menu .f-menu-a.active {
|
||||
background-color: var(--bg-active);
|
||||
color: var(--c-active);
|
||||
}
|
||||
|
||||
#fork-a-menu .f-menu-a:hover,
|
||||
#fork-a-menu .f-menu-a:focus {
|
||||
background-color: var(--c-a-and-btn);
|
||||
color: var(--c-nav-focus);
|
||||
}
|
||||
|
||||
#fork-a-menu #id-an-label {
|
||||
position: absolute;
|
||||
top: -2.875rem;
|
||||
|
@ -1327,6 +1338,6 @@
|
|||
width: auto;
|
||||
}
|
||||
|
||||
#forka .f-fbtn[name="uninstall"]:not(.origin) {
|
||||
#forka .f-fbtn[data-name="uninstall"]:not(.origin) {
|
||||
color: red;
|
||||
}
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
--bg-fh1: hsl(220, 5%, 12%);
|
||||
--br-fh1: hsl(0, 0%, 80%);
|
||||
--c-icon-sub: hsl(0, 0%, 70%);
|
||||
--c-icon-new: hsl(50, 100%, 50%);
|
||||
--c-focus-v: hsl(30, 100%, 50%);
|
||||
--c-a-focus: hsl(50, 100%, 40%);
|
||||
--c-focus: hsl(220, 5%, 12%);
|
||||
--bg-focus: hsl(50, 100%, 50%);
|
||||
--bg-post-h: hsl(0, 20%, 26%);
|
||||
|
@ -37,7 +34,6 @@
|
|||
--bg-poll-res: hsl(50, 100%, 50%);
|
||||
--c-sel: hsl(0, 0%, 0%);
|
||||
--bg-sel: hsl(0, 0%, 60%);
|
||||
--c-highlighted: hsl(39, 100%, 50%);
|
||||
}
|
||||
|
||||
html,
|
||||
|
@ -209,16 +205,15 @@ blockquote cite {
|
|||
margin: -0.625rem -0.625rem 0.625rem -0.625rem;
|
||||
}
|
||||
|
||||
a, span.f-bb-hashtag {
|
||||
a {
|
||||
color: var(--c-a-and-btn);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: color 0.5s, background-color 0.5s;
|
||||
}
|
||||
|
||||
a:hover, a:focus, span.f-bb-hashtag:hover, span.f-bb-hashtag:focus {
|
||||
color: var(--c-a-focus);
|
||||
text-decoration: underline;
|
||||
a:hover, a:focus {
|
||||
color: var(--c-focus);
|
||||
background-color: var(--bg-focus);
|
||||
}
|
||||
|
||||
table {
|
||||
|
@ -290,6 +285,7 @@ div.f-bb-s-body {
|
|||
}
|
||||
|
||||
span.f-bb-hashtag {
|
||||
color: var(--c-a-and-btn);
|
||||
border-bottom-style: dashed;
|
||||
border-bottom-width: 0.0625rem;
|
||||
}
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
--br-fh1: hsl(0, 0%, 80%);
|
||||
--c-icon-sub: hsl(0, 0%, 70%);
|
||||
--c-icon-new: hsl(50, 100%, 50%);
|
||||
--c-focus-v: hsl(30, 100%, 50%);
|
||||
--c-a-focus: hsl(50, 100%, 40%);
|
||||
--c-focus: hsl(220, 5%, 12%);
|
||||
--bg-focus: hsl(50, 100%, 50%);
|
||||
--bg-post-h: hsl(0, 20%, 26%);
|
||||
|
@ -261,7 +259,7 @@ body,
|
|||
}
|
||||
|
||||
#fork select {
|
||||
background-color: var(--bg-fprimary);
|
||||
background-color: var(--bg-focus);
|
||||
}
|
||||
|
||||
#fork select:not([multiple]) option {
|
||||
|
@ -331,7 +329,7 @@ body,
|
|||
color: var(--c-a-and-btn);
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
transition: color 0.5s, background-color 0.5s;
|
||||
transition-duration: 1s;
|
||||
}
|
||||
|
||||
#fork .f-btn {
|
||||
|
@ -354,31 +352,18 @@ body,
|
|||
}
|
||||
|
||||
#fork a:hover,
|
||||
#fork a:focus {
|
||||
color: var(--c-a-focus);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#fork a:focus-visible,
|
||||
#fork .f-btn:focus-visible {
|
||||
outline: 0.25rem double var(--c-focus-v);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#fork a:focus,
|
||||
#fork .f-btn:hover,
|
||||
#fork .f-btn:focus,
|
||||
#fork a.f-page:hover,
|
||||
#fork a.f-page:focus {
|
||||
#fork .f-btn:focus {
|
||||
color: var(--c-focus);
|
||||
background-color: var(--bg-focus);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/*#fork a:active,
|
||||
#fork a:active,
|
||||
#fork .f-btn:active {
|
||||
color: var(--c-active);
|
||||
background-color: var(--bg-active);
|
||||
}*/
|
||||
}
|
||||
|
||||
#fork .f-inline > dt,
|
||||
#fork .f-inline > dd {
|
||||
|
@ -422,6 +407,7 @@ body,
|
|||
background-color: var(--bg-like-nav);
|
||||
}
|
||||
|
||||
|
||||
/********/
|
||||
/* Меню */
|
||||
/********/
|
||||
|
@ -487,18 +473,6 @@ body,
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#fork .f-menu-a.active {
|
||||
background-color: var(--bg-active);
|
||||
color: var(--c-active);
|
||||
}
|
||||
|
||||
#fork .f-menu-a:hover,
|
||||
#fork .f-menu-a:focus {
|
||||
background-color: var(--c-a-and-btn);
|
||||
color: var(--c-nav-focus);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 50rem) {
|
||||
#fork .f-menu-checkbox {
|
||||
display: none;
|
||||
|
@ -540,6 +514,17 @@ body,
|
|||
padding: 0.3125rem 0.625rem;
|
||||
}
|
||||
|
||||
#fork-nav .f-menu-a.active {
|
||||
background-color: var(--bg-active);
|
||||
color: var(--c-active);
|
||||
}
|
||||
|
||||
#fork-nav .f-menu-a:hover,
|
||||
#fork-nav .f-menu-a:focus {
|
||||
background-color: var(--c-a-and-btn);
|
||||
color: var(--c-nav-focus);
|
||||
}
|
||||
|
||||
#fork-nav .f-menu-user-items {
|
||||
background-color: var(--bg-nav);
|
||||
display: flex;
|
||||
|
@ -970,6 +955,7 @@ body,
|
|||
|
||||
#fork-debug #id-fdebugtime {
|
||||
padding: 0.3125rem 0.625rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#fork-debug #fork-dgtable {
|
||||
|
@ -1297,9 +1283,9 @@ body,
|
|||
width: calc(100% - 2rem);
|
||||
}
|
||||
|
||||
/*#fork .f-ftlist .f-ftname {
|
||||
#fork .f-ftlist .f-ftname {
|
||||
max-width: 100%;
|
||||
}*/
|
||||
}
|
||||
|
||||
#fork .f-ftlist .f-cstats {
|
||||
display: flex;
|
||||
|
@ -2741,6 +2727,17 @@ body,
|
|||
top: 1rem;
|
||||
}
|
||||
|
||||
#fork-pm-menu a.f-menu-a.active {
|
||||
background-color: var(--bg-active);
|
||||
color: var(--c-active);
|
||||
}
|
||||
|
||||
#fork-pm-menu a.f-menu-a:hover,
|
||||
#fork-pm-menu a.f-menu-a:focus {
|
||||
background-color: var(--c-a-and-btn);
|
||||
color: var(--c-nav-focus);
|
||||
}
|
||||
|
||||
#fork-pm-menu #id-pmn-label {
|
||||
position: absolute;
|
||||
top: -2.875rem;
|
||||
|
|
|
@ -43,8 +43,6 @@ Disallow: /reg
|
|||
Disallow: /search
|
||||
Disallow: /post
|
||||
Disallow: /forum/scroll
|
||||
Disallow: /forum/*/new/topic
|
||||
Disallow: /topic/*/new/reply
|
||||
Disallow: /userlist/*/DESC/
|
||||
Disallow: /userlist/*/ASC/
|
||||
```
|
||||
|
|
Loading…
Add table
Reference in a new issue