mirror of
https://github.com/typemill/typemill.git
synced 2025-08-01 11:50:28 +02:00
V2 first draft
This commit is contained in:
@@ -141,6 +141,7 @@ class User extends WriteYaml
|
||||
if($user)
|
||||
{
|
||||
$user['lastlogin'] = time();
|
||||
$user['tmpApiKey'] = ;
|
||||
|
||||
$_SESSION['user'] = $user['username'];
|
||||
$_SESSION['role'] = $user['userrole'];
|
||||
|
@@ -31,6 +31,33 @@ abstract class Controller
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
protected function setUrlCollection($uri)
|
||||
{
|
||||
$scheme = $uri->getScheme();
|
||||
$authority = $uri->getAuthority();
|
||||
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
|
||||
|
||||
$this->basePath = $this->c->get('basePath');
|
||||
$this->currentPath = $uri->getPath();
|
||||
$this->fullBaseUrl = $protocol . $this->basePath;
|
||||
$this->fullCurrentUrl = $protocol . $this->currentPath;
|
||||
|
||||
$this->urlCollection = [
|
||||
'basePath' => $this->basePath,
|
||||
'currentPath' => $this->currentPath,
|
||||
'fullBaseUrl' => $this->fullBaseUrl,
|
||||
'fullCurrentUrl' => $this->fullCurrentUrl
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
# holds the pimple container
|
||||
protected $c;
|
||||
|
90
system/typemill/Controllers/ControllerData.php
Normal file
90
system/typemill/Controllers/ControllerData.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Typemill\Models\Yaml;
|
||||
use Typemill\Events\OnSystemnaviLoaded;
|
||||
|
||||
# this controller handels data for web and api
|
||||
# web will use data for twig output
|
||||
# api will use data for json output
|
||||
# data controller will provide neutral data
|
||||
|
||||
class ControllerData extends Controller
|
||||
{
|
||||
protected function getMainNavigation($userrole)
|
||||
{
|
||||
$yaml = new Yaml('\Typemill\Models\Storage');
|
||||
|
||||
$mainnavi = $yaml->getYaml('system/typemill/settings', 'mainnavi.yaml');
|
||||
|
||||
$allowedmainnavi = [];
|
||||
|
||||
$acl = $this->c->get('acl');
|
||||
|
||||
foreach($mainnavi as $name => $naviitem)
|
||||
{
|
||||
if($acl->isAllowed($userrole, $naviitem['aclresource'], $naviitem['aclprivilege']))
|
||||
{
|
||||
# not nice: check if the navi-item is active (e.g if segments like "content" or "system" is in current url)
|
||||
if($name == 'content' && strpos($this->settings['routepath'], 'tm/content'))
|
||||
{
|
||||
$naviitem['active'] = true;
|
||||
}
|
||||
elseif($name == 'account' && strpos($this->settings['routepath'], 'tm/account'))
|
||||
{
|
||||
$naviitem['active'] = true;
|
||||
}
|
||||
elseif($name == 'system')
|
||||
{
|
||||
$naviitem['active'] = true;
|
||||
}
|
||||
|
||||
$allowedmainnavi[$name] = $naviitem;
|
||||
}
|
||||
}
|
||||
|
||||
# if system is there, then we do not need the account item
|
||||
if(isset($allowedmainnavi['system']))
|
||||
{
|
||||
unset($allowedmainnavi['account']);
|
||||
}
|
||||
|
||||
# set correct editor mode according to user settings
|
||||
if(isset($allowedmainnavi['content']) && $this->settings['editor'] == 'raw')
|
||||
{
|
||||
$allowedmainnavi['content']['routename'] = "content.raw";
|
||||
}
|
||||
|
||||
return $allowedmainnavi;
|
||||
}
|
||||
|
||||
protected function getSystemNavigation($userrole)
|
||||
{
|
||||
$yaml = new Yaml('\Typemill\Models\Storage');
|
||||
|
||||
$systemnavi = $yaml->getYaml('system/typemill/settings', 'systemnavi.yaml');
|
||||
$systemnavi = $this->c->get('dispatcher')->dispatch(new OnSystemnaviLoaded($systemnavi), 'onSystemnaviLoaded')->getData();
|
||||
|
||||
$allowedsystemnavi = [];
|
||||
|
||||
$acl = $this->c->get('acl');
|
||||
|
||||
foreach($systemnavi as $name => $naviitem)
|
||||
{
|
||||
# check if the navi-item is active (e.g if segments like "content" or "system" is in current url)
|
||||
# a bit fragile because url-segment and name/key in systemnavi.yaml and plugins have to be the same
|
||||
if(strpos($this->settings['routepath'], 'tm/' . $name))
|
||||
{
|
||||
$naviitem['active'] = true;
|
||||
}
|
||||
|
||||
if($acl->isAllowed($userrole, $naviitem['aclresource'], $naviitem['aclprivilege']))
|
||||
{
|
||||
$allowedsystemnavi[$name] = $naviitem;
|
||||
}
|
||||
}
|
||||
|
||||
return $allowedsystemnavi;
|
||||
}
|
||||
}
|
1248
system/typemill/Controllers/ControllerSystem.php
Normal file
1248
system/typemill/Controllers/ControllerSystem.php
Normal file
File diff suppressed because it is too large
Load Diff
37
system/typemill/Controllers/ControllerSystemApi.php
Normal file
37
system/typemill/Controllers/ControllerSystemApi.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Controllers;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
|
||||
class ControllerSystemApi extends ControllerData
|
||||
{
|
||||
public function getSettings(Request $request, Response $response)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'settings' => $this->settings
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
|
||||
public function getSystemNavi(Request $request, Response $response)
|
||||
{
|
||||
# won't work because api has no session, instead you have to pass user
|
||||
$response->getBody()->write(json_encode([
|
||||
'systemnavi' => $this->getSystemNavigation('member'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
|
||||
public function getMainNavi(Request $request, Response $response)
|
||||
{
|
||||
$response->getBody()->write(json_encode([
|
||||
'mainnavi' => $this->getMainNavigation('member'),
|
||||
]));
|
||||
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
|
||||
}
|
||||
}
|
@@ -10,6 +10,7 @@ class ControllerWeb extends Controller
|
||||
{
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
/*
|
||||
parent::__construct($container);
|
||||
|
||||
echo '<br>add twig';
|
||||
@@ -47,8 +48,26 @@ class ControllerWeb extends Controller
|
||||
|
||||
return $twig;
|
||||
});
|
||||
|
||||
protected function setUrlCollection($uri)
|
||||
{
|
||||
$scheme = $uri->getScheme();
|
||||
$authority = $uri->getAuthority();
|
||||
$protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : '');
|
||||
|
||||
$this->currentPath = $uri->getPath();
|
||||
$this->fullBaseUrl = $protocol . $this->basePath;
|
||||
$this->fullCurrentUrl = $protocol . $this->currentPath;
|
||||
|
||||
$this->urlCollection = [
|
||||
'basePath' => $this->basePath,
|
||||
'currentPath' => $this->currentPath,
|
||||
'fullBaseUrl' => $this->fullBaseUrl,
|
||||
'fullCurrentUrl' => $this->fullCurrentUrl
|
||||
];
|
||||
}
|
||||
|
||||
$this->c->get('dispatcher')->dispatch(new OnTwigLoaded(false), 'onTwigLoaded');
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
@@ -21,11 +21,10 @@ use Typemill\Events\OnHtmlLoaded;
|
||||
use Typemill\Events\OnRestrictionsLoaded;
|
||||
*/
|
||||
|
||||
class ControllerWebFrontend extends ControllerWeb
|
||||
class ControllerWebFrontend extends Controller
|
||||
{
|
||||
public function index(Request $request, Response $response)
|
||||
{
|
||||
die('hallo');
|
||||
return $this->c->get('view')->render($response, 'home.twig', [
|
||||
'title' => 'Typemill Version 2',
|
||||
'description' => 'Typemill Version 2 wird noch besser als Version 1.'
|
||||
|
@@ -5,104 +5,89 @@ namespace Typemill\Controllers;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
use Slim\Views\Twig;
|
||||
use Typemill\Models\Validation;
|
||||
use Typemill\Models\User;
|
||||
use Typemill\Models\WriteYaml;
|
||||
use Typemill\Extensions\ParsedownExtension;
|
||||
|
||||
class ControllerWebLogin extends ControllerWeb
|
||||
class ControllerWebLogin extends Controller
|
||||
{
|
||||
# redirect if visit /setup route
|
||||
public function redirect(Request $request, Response $response)
|
||||
{
|
||||
if(isset($_SESSION['login']))
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('content.raw'));
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('content.raw'))->withStatus(302);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('auth.show'))->withStatus(302);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* show login form
|
||||
*
|
||||
* @param obj $request the slim request object.
|
||||
* @param obj $response the slim response object.
|
||||
* @param array $args with arguments past to the slim router
|
||||
* @return obj $response and string route.
|
||||
*/
|
||||
|
||||
public function show(Request $request, Response $response, $args)
|
||||
public function show(Request $request, Response $response)
|
||||
{
|
||||
return $this->c->get('view')->render($response, 'login.twig', [
|
||||
return $this->c->get('view')->render($response, 'auth/login.twig', [
|
||||
#'captcha' => $this->checkIfAddCaptcha(),
|
||||
#'url' => $this->urlCollection,
|
||||
]);
|
||||
|
||||
# $settings = $this->c->get('settings');
|
||||
|
||||
# return $this->render($response, '/auth/login.twig', ['settings' => $settings]);
|
||||
}
|
||||
|
||||
/**
|
||||
* signin an existing user
|
||||
*
|
||||
* @param obj $request the slim request object with form data in the post params.
|
||||
* @param obj $response the slim response object.
|
||||
* @return obj $response with redirect to route.
|
||||
*/
|
||||
|
||||
public function login(Request $request, Response $response)
|
||||
{
|
||||
if( ( null !== $request->getattribute('csrf_result') ) OR ( $request->getattribute('csrf_result') === false ) )
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'The form has a timeout, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('auth.show'));
|
||||
}
|
||||
|
||||
/* authentication */
|
||||
$params = $request->getParams();
|
||||
$input = $request->getParsedBody();
|
||||
$validation = new Validation();
|
||||
$settings = $this->c->get('settings');
|
||||
|
||||
if($validation->signin($params))
|
||||
if($validation->signin($input))
|
||||
{
|
||||
$user = new User();
|
||||
$userdata = $user->getUser($params['username']);
|
||||
|
||||
if($userdata && password_verify($params['password'], $userdata['password']))
|
||||
if(!$user->setUserWithPassword($input['username']))
|
||||
{
|
||||
# return error
|
||||
}
|
||||
|
||||
$userdata = $user->getUserData();
|
||||
|
||||
if($userdata && password_verify($input['password'], $userdata['password']))
|
||||
{
|
||||
# check if user has confirmed the account
|
||||
if(isset($userdata['optintoken']) && $userdata['optintoken'])
|
||||
{
|
||||
$this->c->flash->addMessage('error', 'Your registration is not confirmed yet. Please check your e-mails and use the confirmation link.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
$this->c->get('flash')->addMessage('error', 'Your registration is not confirmed yet. Please check your e-mails and use the confirmation link.');
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('auth.show'))->withStatus(302);
|
||||
}
|
||||
|
||||
$user->login($userdata['username']);
|
||||
$user->login();
|
||||
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('settings.show'))->withStatus(302);
|
||||
|
||||
/*
|
||||
# if user is allowed to view content-area
|
||||
if($this->c->acl->hasRole($userdata['userrole']) && $this->c->acl->isAllowed($userdata['userrole'], 'content', 'view'))
|
||||
$acl = $this->c->get('acl');
|
||||
if($acl->hasRole($userdata['userrole']) && $acl->isAllowed($userdata['userrole'], 'content', 'view'))
|
||||
{
|
||||
$settings = $this->c->get('settings');
|
||||
$editor = (isset($settings['editor']) && $settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
$editor = (isset($this->settings['editor']) && $this->settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
|
||||
return $response->withRedirect($this->c->router->pathFor('content.' . $editor));
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('content.' . $editor))->withStatus(302);
|
||||
}
|
||||
return $response->withRedirect($this->c->router->pathFor('user.account'));
|
||||
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('user.account'))->withStatus(302);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($this->settings['securitylog']) && $this->settings['securitylog'])
|
||||
{
|
||||
\Typemill\Models\Helpers::addLogEntry('wrong login');
|
||||
\Typemill\Static\Helpers::addLogEntry('wrong login');
|
||||
}
|
||||
|
||||
$this->c->flash->addMessage('error', 'Ups, wrong password or username, please try again.');
|
||||
return $response->withRedirect($this->c->router->pathFor('auth.show'));
|
||||
$this->c->get('flash')->addMessage('error', 'Ups, wrong password or username, please try again.');
|
||||
|
||||
return $response->withHeader('Location', $this->routeParser->urlFor('auth.show'))->withStatus(302);
|
||||
}
|
||||
}
|
@@ -2,9 +2,10 @@
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class TwigCsrfExtension extends \Twig\Extension\AbstractExtension
|
||||
class TwigCsrfExtension extends AbstractExtension
|
||||
{
|
||||
protected $csrf;
|
||||
|
||||
@@ -22,8 +23,8 @@ class TwigCsrfExtension extends \Twig\Extension\AbstractExtension
|
||||
|
||||
public function csrf()
|
||||
{
|
||||
$csrf = '<p>TokenNameValue: '. $this->csrf->getTokenName() .'</p><input type="hidden" name="' . $this->csrf->getTokenNameKey(). '" value="' . $this->csrf->getTokenName() . '">
|
||||
<input type="hidden" name="' . $this->csrf->getTokenValueKey(). '" value="' . $this->csrf->getTokenValue(). '">';
|
||||
$csrf = '<p>TokenNameValue: '. $this->csrf->getTokenName() .'</p><input type="hidden" id="csrf_name" name="' . $this->csrf->getTokenNameKey(). '" value="' . $this->csrf->getTokenName() . '">
|
||||
<input type="hidden" id="csrf_value" name="' . $this->csrf->getTokenValueKey(). '" value="' . $this->csrf->getTokenValue(). '">';
|
||||
|
||||
return $csrf;
|
||||
}
|
||||
|
63
system/typemill/Extensions/TwigLanguageExtension.php
Normal file
63
system/typemill/Extensions/TwigLanguageExtension.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
use Typemill\Models\WriteYaml;
|
||||
|
||||
class TwigLanguageExtension extends AbstractExtension
|
||||
{
|
||||
protected $labels;
|
||||
|
||||
public function __construct($labels)
|
||||
{
|
||||
$this->labels = $labels;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('translate', [$this, 'translate'] ),
|
||||
];
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new TwigFunction('translate', array($this, 'translate' ))
|
||||
];
|
||||
}
|
||||
|
||||
public function translate( $label, $labels_from_plugin = NULL )
|
||||
{
|
||||
# replaces spaces, dots, comma and dash with underscores
|
||||
$string = str_replace(" ", "_", $label);
|
||||
$string = str_replace(".", "_", $string);
|
||||
$string = str_replace(",", "_", $string);
|
||||
$string = str_replace("-", "_", $string);
|
||||
|
||||
# transforms to uppercase
|
||||
$string = strtoupper( $string );
|
||||
|
||||
# translates the string
|
||||
if(isset($labels_from_plugin))
|
||||
{
|
||||
$translated_label = isset($labels_from_plugin[$string]) ? $labels_from_plugin[$string] : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$translated_label = isset($this->labels[$string]) ? $this->labels[$string] : null;
|
||||
}
|
||||
|
||||
# if the string is not present, set the original string
|
||||
if( empty($translated_label) )
|
||||
{
|
||||
$translated_label = $label;
|
||||
}
|
||||
|
||||
# returns the string in the set language
|
||||
return $translated_label;
|
||||
}
|
||||
}
|
47
system/typemill/Extensions/TwigUrlExtension.php
Normal file
47
system/typemill/Extensions/TwigUrlExtension.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
|
||||
class TwigUrlExtension extends AbstractExtension
|
||||
{
|
||||
protected $uri;
|
||||
protected $basepath;
|
||||
protected $scheme;
|
||||
protected $authority;
|
||||
protected $protocol;
|
||||
|
||||
public function __construct($uri, $basepath)
|
||||
{
|
||||
$this->uri = $uri;
|
||||
$this->basepath = $basepath;
|
||||
$this->scheme = $uri->getScheme();
|
||||
$this->authority = $uri->getAuthority();
|
||||
$this->protocol = ($this->scheme ? $this->scheme . ':' : '') . ($this->authority ? '//' . $this->authority : '');
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new \Twig\TwigFunction('base_url', array($this, 'baseUrl' )),
|
||||
new \Twig\TwigFunction('current_url', array($this, 'currentUrl' )),
|
||||
new \Twig\TwigFunction('current_path', array($this, 'currentPath' ))
|
||||
];
|
||||
}
|
||||
|
||||
public function baseUrl()
|
||||
{
|
||||
return $this->protocol . $this->basepath;
|
||||
}
|
||||
|
||||
public function currentUrl()
|
||||
{
|
||||
return $this->protocol . $this->uri->getPath();
|
||||
}
|
||||
|
||||
public function currentPath()
|
||||
{
|
||||
return $this->uri->getPath();
|
||||
}
|
||||
}
|
57
system/typemill/Extensions/TwigUserExtension.php
Normal file
57
system/typemill/Extensions/TwigUserExtension.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Extensions;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
|
||||
class TwigUserExtension extends AbstractExtension
|
||||
{
|
||||
public function getFunctions()
|
||||
{
|
||||
return [
|
||||
new \Twig\TwigFunction('is_role', array($this, 'isRole' )),
|
||||
new \Twig\TwigFunction('get_role', array($this, 'getRole' )),
|
||||
new \Twig\TwigFunction('get_username', array($this, 'getUsername' )),
|
||||
new \Twig\TwigFunction('is_loggedin', array($this, 'isLoggedin' ))
|
||||
];
|
||||
}
|
||||
|
||||
public function isLoggedin()
|
||||
{
|
||||
if(isset($_SESSION['login']) && $_SESSION['login'])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isRole($role)
|
||||
{
|
||||
if(isset($_SESSION['role']) && $_SESSION['role'] == $role)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getRole()
|
||||
{
|
||||
if(isset($_SESSION['role']))
|
||||
{
|
||||
return $_SESSION['role'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUsername()
|
||||
{
|
||||
if(isset($_SESSION['user']))
|
||||
{
|
||||
return $_SESSION['user'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Routing\RouteContext;
|
||||
|
||||
class CreateSession implements MiddlewareInterface
|
||||
{
|
||||
protected $sessionSegments = [];
|
||||
|
||||
protected $routepath = false;
|
||||
|
||||
public function __construct($session_segments, $routepath)
|
||||
{
|
||||
$this->sessionSegments = $session_segments;
|
||||
|
||||
$this->routepath = $routepath;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
foreach($this->sessionSegments as $segment)
|
||||
{
|
||||
if(substr( $this->routepath, 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
echo '<br>Create Session';
|
||||
|
||||
// configure session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
ini_set('session.cookie_samesite', 'lax');
|
||||
/*
|
||||
if($uri->getScheme() == 'https')
|
||||
{
|
||||
ini_set('session.cookie_secure', 1);
|
||||
session_name('__Secure-typemill-session');
|
||||
}
|
||||
else
|
||||
{
|
||||
session_name('typemill-session');
|
||||
}
|
||||
*/
|
||||
// start session
|
||||
session_start();
|
||||
|
||||
$request = $request->withAttribute('session', $_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class CsrfProtection implements MiddlewareInterface
|
||||
{
|
||||
protected $container;
|
||||
|
||||
protected $responseFactory;
|
||||
|
||||
public function __construct($container, $responseFactory)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->responseFactory = $responseFactory;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
{
|
||||
echo '<br> csrf protection';
|
||||
|
||||
$responseFactory = $this->responseFactory;
|
||||
|
||||
# Register Middleware On Container
|
||||
$this->container->set('csrf', function () use ($responseFactory)
|
||||
{
|
||||
return new Guard($responseFactory);
|
||||
});
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Slim\Csrf\Guard;
|
||||
|
||||
class CsrfProtectionToMiddleware
|
||||
{
|
||||
protected $container;
|
||||
|
||||
public function __construct($container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
public function __invoke(Request $request, RequestHandler $handler)
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
{
|
||||
echo '<br> csrf protection to middleware';
|
||||
|
||||
return $this->container->get('csrf');
|
||||
}
|
||||
}
|
||||
}
|
@@ -2,31 +2,24 @@
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Flash\Messages;
|
||||
use Slim\Views\Twig;
|
||||
|
||||
class FlashMessages implements MiddlewareInterface
|
||||
{
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __construct($container)
|
||||
class FlashMessages
|
||||
{
|
||||
public function __construct(Twig $view)
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
|
||||
public function __invoke(Request $request, RequestHandler $handler)
|
||||
{
|
||||
if(is_array($request->getAttribute('session')))
|
||||
if(isset($_SESSION['slimFlash']) && is_array($_SESSION['slimFlash']))
|
||||
{
|
||||
echo '<br> flash messages';
|
||||
|
||||
$this->container->set('flash', function(){
|
||||
return new Messages();
|
||||
});
|
||||
$this->view->getEnvironment()->addGlobal('flash', $_SESSION['slimFlash']);
|
||||
|
||||
unset($_SESSION['slimFlash']);
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
|
@@ -11,7 +11,7 @@ class JsonBodyParser implements MiddlewareInterface
|
||||
{
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
echo '<br> JSON Body parser';
|
||||
#echo '<br> JSON Body parser';
|
||||
|
||||
$contentType = $request->getHeaderLine('Content-Type');
|
||||
|
||||
|
@@ -2,12 +2,11 @@
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteParser;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
# use Slim\Routing\RouteContext;
|
||||
use Slim\Routing\RouteParser;
|
||||
use Slim\Psr7\Response;
|
||||
|
||||
class RedirectIfAuthenticated implements MiddlewareInterface
|
||||
{
|
||||
@@ -17,18 +16,25 @@ class RedirectIfAuthenticated implements MiddlewareInterface
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :Response
|
||||
{
|
||||
$editor = (isset($this->settings['editor']) && $this->settings['editor'] == 'visual') ? 'visual' : 'raw';
|
||||
|
||||
if(isset($_SESSION['login']))
|
||||
$authenticated = (
|
||||
(isset($_SESSION['username'])) &&
|
||||
(isset($_SESSION['login']))
|
||||
)
|
||||
? true : false;
|
||||
|
||||
if($authenticated)
|
||||
{
|
||||
return $response->withHeader('Location', $this->router->pathFor('content.' . $editor))->withStatus(302);
|
||||
# $response = $response->withRedirect($this->router->pathFor('content.' . $editor));
|
||||
$response = new Response();
|
||||
|
||||
return $response->withHeader('Location', $this->router->urlFor('content.' . $editor))->withStatus(302);
|
||||
}
|
||||
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
39
system/typemill/Middleware/RedirectIfUnauthenticated.php
Normal file
39
system/typemill/Middleware/RedirectIfUnauthenticated.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Slim\Routing\RouteParser;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Psr7\Response;
|
||||
|
||||
class RedirectIfUnauthenticated implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(RouteParser $router)
|
||||
{
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
public function process(Request $request, RequestHandler $handler) :response
|
||||
{
|
||||
$authenticated = (
|
||||
(isset($_SESSION['username'])) &&
|
||||
(isset($_SESSION['login']))
|
||||
)
|
||||
? true : false;
|
||||
|
||||
if(!$authenticated)
|
||||
{
|
||||
# this executes only middleware code and not code from route
|
||||
$response = new Response();
|
||||
|
||||
return $response->withHeader('Location', $this->router->urlFor('auth.show'))->withStatus(302);
|
||||
}
|
||||
|
||||
# this executes code from routes first and then executes middleware
|
||||
$response = $handler->handle($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
66
system/typemill/Middleware/RestrictApiAccess.php
Normal file
66
system/typemill/Middleware/RestrictApiAccess.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Middleware;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Routing\RouteContext;
|
||||
use Slim\Psr7\Response;
|
||||
|
||||
class RestrictApiAccess
|
||||
{
|
||||
public function __invoke(Request $request, RequestHandler $handler)
|
||||
{
|
||||
$routeContext = RouteContext::fromRequest($request);
|
||||
$baseURL = $routeContext->getBasePath();
|
||||
|
||||
if ($request->hasHeader('X-Session-Auth')) {
|
||||
|
||||
session_start();
|
||||
|
||||
$authenticated = (
|
||||
(isset($_SESSION['username'])) &&
|
||||
(isset($_SESSION['userrole'])) &&
|
||||
(isset($_SESSION['login']))
|
||||
)
|
||||
? true : false;
|
||||
|
||||
if($authenticated)
|
||||
{
|
||||
$response = $handler->handle($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
# elseif ($request->getHeaderLine('X-Requested-With') === 'XMLHttpRequest') {
|
||||
# advantage: all xhr-calls to the api will be session based
|
||||
# no direct calls from javascript possible
|
||||
# only from server
|
||||
# }
|
||||
|
||||
|
||||
$user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : false;
|
||||
$apikey = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : false;
|
||||
|
||||
if($user && $apikey)
|
||||
{
|
||||
# get user
|
||||
# check if user has tmpApiKey
|
||||
# check if user has permanentApiKey
|
||||
# check if user has tmpApiKey
|
||||
# check if tmpApiKey has expired
|
||||
# check if user keys are correct
|
||||
|
||||
$response = $handler->handle($request);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
$response = new Response();
|
||||
|
||||
$response->getBody()->write('Zugriff nicht erlaubt.');
|
||||
|
||||
return $response->withStatus(401);
|
||||
}
|
||||
}
|
336
system/typemill/Models/Storage.php
Normal file
336
system/typemill/Models/Storage.php
Normal file
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
class Storage
|
||||
{
|
||||
protected $basepath;
|
||||
|
||||
public $error = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->basepath = getcwd() . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
public function checkFolder($folder)
|
||||
{
|
||||
$folderpath = $this->basepath . $folder;
|
||||
|
||||
if(!is_dir($folderpath) OR !is_writable($folderpath))
|
||||
{
|
||||
$this->error = "The folder $folder does not exist or is not writable.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function createFolder($folder)
|
||||
{
|
||||
$folderpath = $this->basepath . $folder;
|
||||
|
||||
if(is_dir($folderpath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!mkdir($folderpath, 0755, true))
|
||||
{
|
||||
$this->error = "Could not create folder $folder.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkFile($folder, $filename)
|
||||
{
|
||||
if(!file_exists($this->basepath . $folder . DIRECTORY_SEPARATOR . $filename))
|
||||
{
|
||||
$this->error = "The file $filename in folder $folder does not exist.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeFile($folder, $filename, $data)
|
||||
{
|
||||
if(!$this->checkFolder($folder))
|
||||
{
|
||||
if(!$this->createFolder($folder))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$filepath = $this->basepath . $folder . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
$openfile = @fopen($filepath, "w");
|
||||
if(!$openfile)
|
||||
{
|
||||
$this->error = "Could not open and read the file $filename in folder $folder.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
fwrite($openfile, $data);
|
||||
fclose($openfile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getFile($folder, $filename)
|
||||
{
|
||||
if($this->checkFile($folder, $filename))
|
||||
{
|
||||
# ??? should be with basepath???
|
||||
$fileContent = file_get_contents($folder . DIRECTORY_SEPARATOR . $filename);
|
||||
return $fileContent;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function renameFile($folder, $oldname, $newname)
|
||||
{
|
||||
|
||||
$oldFilePath = $this->basepath . $folder . DIRECTORY_SEPARATOR . $oldname;
|
||||
$newFilePath = $this->basepath . $folder . DIRECTORY_SEPARATOR . $newname;
|
||||
|
||||
if(!file_exists($oldFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function deleteFile($filepath)
|
||||
{
|
||||
if($this->checkFileWithPath($filepath))
|
||||
{
|
||||
unlink($this->basePath . $filepath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
public function checkPath($folder)
|
||||
{
|
||||
$folderPath = $this->basepath . $folder;
|
||||
|
||||
if(!is_dir($folderPath))
|
||||
{
|
||||
if(@mkdir($folderPath, 0774, true))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception("The folder '{$folderPath}' is missing and we could not create it. Please create the folder manually on your server.");
|
||||
# return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(@is_writable($folderPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \Exception("Please make the folder '{$folderPath}' writable.");
|
||||
# return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
public function checkFile($folder, $file)
|
||||
{
|
||||
if(!file_exists($this->basePath . $folder . DIRECTORY_SEPARATOR . $file))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkFileWithPath($filepath)
|
||||
{
|
||||
if(!file_exists($this->basePath . $filepath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeFile($folder, $file, $data)
|
||||
{
|
||||
if($this->checkPath($folder))
|
||||
{
|
||||
$filePath = $this->basePath . $folder . DIRECTORY_SEPARATOR . $file;
|
||||
|
||||
$openFile = @fopen($filePath, "w");
|
||||
|
||||
if(!$openFile)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
fwrite($openFile, $data);
|
||||
fclose($openFile);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFile($folderName, $fileName)
|
||||
{
|
||||
if($this->checkFile($folderName, $fileName))
|
||||
{
|
||||
$fileContent = file_get_contents($folderName . DIRECTORY_SEPARATOR . $fileName);
|
||||
return $fileContent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFileWithPath($filepath)
|
||||
{
|
||||
if($this->checkFileWithPath($filepath))
|
||||
{
|
||||
$fileContent = file_get_contents($filepath);
|
||||
return $fileContent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function deleteFileWithPath($filepath)
|
||||
{
|
||||
if($this->checkFileWithPath($filepath))
|
||||
{
|
||||
unlink($this->basePath . $filepath);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function renameFile($folder, $oldname, $newname)
|
||||
{
|
||||
|
||||
$oldFilePath = $this->basePath . $folder . DIRECTORY_SEPARATOR . $oldname;
|
||||
$newFilePath = $this->basePath . $folder . DIRECTORY_SEPARATOR . $newname;
|
||||
|
||||
if(!file_exists($oldFilePath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if(@rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function renamePost($oldPathWithoutType, $newPathWithoutType)
|
||||
{
|
||||
$filetypes = array('md', 'txt', 'yaml');
|
||||
|
||||
$oldPath = $this->basePath . 'content' . $oldPathWithoutType;
|
||||
$newPath = $this->basePath . 'content' . $newPathWithoutType;
|
||||
|
||||
$result = true;
|
||||
|
||||
foreach($filetypes as $filetype)
|
||||
{
|
||||
$oldFilePath = $oldPath . '.' . $filetype;
|
||||
$newFilePath = $newPath . '.' . $filetype;
|
||||
|
||||
#check if file with filetype exists and rename
|
||||
if($oldFilePath != $newFilePath && file_exists($oldFilePath))
|
||||
{
|
||||
if(@rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
$result = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function moveElement($item, $folderPath, $index, $date = null)
|
||||
{
|
||||
$filetypes = array('md', 'txt', 'yaml');
|
||||
|
||||
# set new order as string
|
||||
$newOrder = ($index < 10) ? '0' . $index : $index;
|
||||
|
||||
# create new path with foldername or filename but without file-type
|
||||
# $newPath = $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . str_replace(" ", "-", $item->name);
|
||||
|
||||
$newPath = $this->basePath . 'content' . $folderPath . DIRECTORY_SEPARATOR . $newOrder . '-' . $item->slug;
|
||||
|
||||
if($item->elementType == 'folder')
|
||||
{
|
||||
$oldPath = $this->basePath . 'content' . $item->path;
|
||||
if(@rename($oldPath, $newPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# create old path but without filetype
|
||||
$oldPath = substr($item->path, 0, strpos($item->path, "."));
|
||||
$oldPath = $this->basePath . 'content' . $oldPath;
|
||||
|
||||
$result = true;
|
||||
|
||||
foreach($filetypes as $filetype)
|
||||
{
|
||||
$oldFilePath = $oldPath . '.' . $filetype;
|
||||
$newFilePath = $newPath . '.' . $filetype;
|
||||
|
||||
#check if file with filetype exists and rename
|
||||
if($oldFilePath != $newFilePath && file_exists($oldFilePath))
|
||||
{
|
||||
if(@rename($oldFilePath, $newFilePath))
|
||||
{
|
||||
$result = $result;
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
*/
|
||||
}
|
28
system/typemill/Models/StorageWrapper.php
Normal file
28
system/typemill/Models/StorageWrapper.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
class StorageWrapper
|
||||
{
|
||||
public $object;
|
||||
|
||||
public function __construct(string $classname)
|
||||
{
|
||||
if (!class_exists($classname))
|
||||
{
|
||||
throw new \RuntimeException(sprintf('Callable class %s does not exist', $classname));
|
||||
}
|
||||
$this->object = new $classname();
|
||||
}
|
||||
|
||||
function __call($method, $args)
|
||||
{
|
||||
if(!method_exists($this->object, $method))
|
||||
{
|
||||
throw new \RuntimeException(sprintf('Callable method %s does not exist', $method));
|
||||
}
|
||||
|
||||
# Invoke original method on our proxied object
|
||||
return call_user_func_array([$this->object, $method], $args);
|
||||
}
|
||||
}
|
485
system/typemill/Models/User.php
Normal file
485
system/typemill/Models/User.php
Normal file
@@ -0,0 +1,485 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
use Typemill\Models\Yaml;
|
||||
|
||||
class User
|
||||
{
|
||||
private $userDir;
|
||||
|
||||
private $yaml;
|
||||
|
||||
private $user = false;
|
||||
|
||||
private $password = false;
|
||||
|
||||
public $error = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userDir = getcwd() . '/system/settings/users';
|
||||
$this->yaml = new Yaml('\Typemill\Models\Storage');
|
||||
}
|
||||
|
||||
public function setUser(string $username)
|
||||
{
|
||||
if(!$this->user)
|
||||
{
|
||||
$this->user = $this->yaml->getYaml('settings/users', $username . '.yaml');
|
||||
|
||||
if(!$this->user)
|
||||
{
|
||||
$this->error = 'User not found';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# store password in private property so it is not accessible outside
|
||||
$this->password = $this->user['password'];
|
||||
|
||||
# delete password from public userdata
|
||||
unset($this->user['password']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setUserWithPassword(string $username)
|
||||
{
|
||||
if(!$this->user)
|
||||
{
|
||||
$this->user = $this->yaml->getYaml('settings/users', $username . '.yaml');
|
||||
|
||||
if(!$this->user)
|
||||
{
|
||||
$this->error = 'User not found.';
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
public function getUserData()
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function getAllUsers()
|
||||
{
|
||||
# check if users directory exists
|
||||
if(!is_dir($this->userDir))
|
||||
{
|
||||
$this->error = 'Directory $this->userDir does not exist.';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
# get all user files
|
||||
$userfiles = array_diff(scandir($this->userDir), array('..', '.', '.logins', 'tmuserindex-mail.txt', 'tmuserindex-role.txt'));
|
||||
|
||||
$usernames = [];
|
||||
|
||||
if(!empty($userfiles))
|
||||
{
|
||||
foreach($userfiles as $key => $userfile)
|
||||
{
|
||||
$usernames[] = str_replace('.yaml', '', $userfile);
|
||||
}
|
||||
|
||||
usort($usernames, 'strnatcasecmp');
|
||||
}
|
||||
|
||||
return $usernames;
|
||||
}
|
||||
|
||||
public function createUser(array $params)
|
||||
{
|
||||
$params['password'] = $this->generatePassword($params['password']);
|
||||
|
||||
if($this->yaml->updateYaml('settings/users', $params['username'] . '.yaml', $params))
|
||||
{
|
||||
$this->deleteUserIndex();
|
||||
|
||||
return $params['username'];
|
||||
}
|
||||
|
||||
$this->error = $this->yaml->getError();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function unsetFromUser(array $keys)
|
||||
{
|
||||
if(empty($keys) OR !$this->user)
|
||||
{
|
||||
$this->error = 'Keys are empty or user does not exist.';
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($keys as $key)
|
||||
{
|
||||
if(isset($this->user[$key]))
|
||||
{
|
||||
unset($this->user[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->yaml->updateYaml('settings/users', $this->user['username'] . '.yaml', $this->user);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function updateUser()
|
||||
{
|
||||
# add password back to userdata before you store/update user
|
||||
if($this->password)
|
||||
{
|
||||
$this->user['password'] = $this->password;
|
||||
}
|
||||
|
||||
if($this->yaml->updateYaml('settings/users', $this->user['username'] . '.yaml', $this->user))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->error = $this->yaml->getError();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function updateUserWithInput(array $input)
|
||||
{
|
||||
if(!isset($input['username']) OR !$this->user)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# make sure new password is not stored
|
||||
if(isset($input['newpassword']))
|
||||
{
|
||||
unset($input['newpassword']);
|
||||
}
|
||||
|
||||
# make sure password is set correctly
|
||||
if(isset($input['password']))
|
||||
{
|
||||
if(empty($input['password']))
|
||||
{
|
||||
unset($input['password']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$input['password'] = $this->generatePassword($input['password']);
|
||||
}
|
||||
}
|
||||
|
||||
# set old password back to original userdate
|
||||
if($this->password)
|
||||
{
|
||||
$this->user['password'] = $this->password;
|
||||
}
|
||||
|
||||
# overwrite old userdata with new userdata
|
||||
$updatedUser = array_merge($this->user, $input);
|
||||
|
||||
# cleanup data here
|
||||
|
||||
$this->updateYaml('settings/users', $this->user['username'] . '.yaml', $updatedUser);
|
||||
|
||||
$this->deleteUserIndex();
|
||||
|
||||
# if user updated his own profile, update session data
|
||||
if(isset($_SESSION['username']) && $_SESSION['username'] == $input['username'])
|
||||
{
|
||||
$_SESSION['userrole'] = $updatedUser['userrole'];
|
||||
|
||||
if(isset($updatedUser['firstname']))
|
||||
{
|
||||
$_SESSION['firstname'] = $updatedUser['firstname'];
|
||||
}
|
||||
if(isset($updatedUser['lastname']))
|
||||
{
|
||||
$_SESSION['lastname'] = $updatedUser['lastname'];
|
||||
}
|
||||
}
|
||||
|
||||
return $this->user['username'];
|
||||
}
|
||||
|
||||
public function deleteUser(string $username)
|
||||
{
|
||||
if($this->getUser($username))
|
||||
{
|
||||
unlink('settings/users/' . $username . '.yaml');
|
||||
|
||||
$this->deleteUserIndex();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function login()
|
||||
{
|
||||
if($this->user)
|
||||
{
|
||||
$this->user['lastlogin'] = time();
|
||||
# $this->user['internalApiKey'] = bin2hex(random_bytes(32));
|
||||
|
||||
$_SESSION['username'] = $this->user['username'];
|
||||
# $_SESSION['userrole'] = $this->user['userrole'];
|
||||
$_SESSION['login'] = $this->user['lastlogin'];
|
||||
/*
|
||||
if(isset($this->user['firstname']))
|
||||
{
|
||||
$_SESSION['firstname'] = $this->user['firstname'];
|
||||
}
|
||||
if(isset($this->user['lastname']))
|
||||
{
|
||||
$_SESSION['lastname'] = $this->user['lastname'];
|
||||
}
|
||||
*/
|
||||
if(isset($this->user['recovertoken']) OR isset($this->user['recoverdate']))
|
||||
{
|
||||
$this->unsetFromUser($this->user['username'], ['recovertoken', 'recoverdate']);
|
||||
}
|
||||
|
||||
# update user last login
|
||||
$this->updateUser();
|
||||
}
|
||||
}
|
||||
|
||||
public function generatePassword($password)
|
||||
{
|
||||
return \password_hash($password, PASSWORD_DEFAULT, ['cost' => 10]);
|
||||
}
|
||||
|
||||
public function getBasicAuth()
|
||||
{
|
||||
$basicauth = $this->user['username'] . ":" . $this->user['internalApiKey'];
|
||||
|
||||
return base64_encode($basicauth);
|
||||
}
|
||||
|
||||
# accepts email with or without asterix and returns userdata
|
||||
public function findUsersByEmail($email)
|
||||
{
|
||||
$usernames = [];
|
||||
|
||||
# Make sure that we scan only the first 11 files even if there are some thousand users.
|
||||
if ($dh = opendir($this->userDir))
|
||||
{
|
||||
$count = 1;
|
||||
$exclude = array('..', '.', '.logins', 'tmuserindex-mail.txt', 'tmuserindex-role.txt');
|
||||
|
||||
while ( ($userfile = readdir($dh)) !== false && $count <= 11 )
|
||||
{
|
||||
if(in_array($userfile, $exclude)){ continue; }
|
||||
|
||||
$usernames[] = str_replace('.yaml', '', $userfile);
|
||||
$count++;
|
||||
}
|
||||
|
||||
closedir($dh);
|
||||
}
|
||||
|
||||
$countusers = count($usernames);
|
||||
|
||||
if($countusers == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# use a simple dirty search if there are less than 10 users (only in use for new user registrations)
|
||||
if($countusers <= 10)
|
||||
{
|
||||
foreach($usernames as $username)
|
||||
{
|
||||
$userdata = $this->getSecureUser($username);
|
||||
|
||||
if($userdata['email'] == $email)
|
||||
{
|
||||
return $userdata;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
# if there are more than 10 users, search with an index
|
||||
$usermails = $this->getUserMailIndex();
|
||||
|
||||
# search with starting asterix, ending asterix or without asterix
|
||||
if($email[0] == '*')
|
||||
{
|
||||
$userdata = [];
|
||||
$search = substr($email, 1);
|
||||
$length = strlen($search);
|
||||
|
||||
foreach($usermails as $usermail => $username)
|
||||
{
|
||||
if(substr($usermail, -$length) == $search)
|
||||
{
|
||||
$userdata[] = $username;
|
||||
}
|
||||
}
|
||||
|
||||
$userdata = empty($userdata) ? false : $userdata;
|
||||
|
||||
return $userdata;
|
||||
}
|
||||
elseif(substr($email, -1) == '*')
|
||||
{
|
||||
$userdata = [];
|
||||
$search = substr($email, 0, -1);
|
||||
$length = strlen($search);
|
||||
|
||||
foreach($usermails as $usermail => $username)
|
||||
{
|
||||
if(substr($usermail, 0, $length) == $search)
|
||||
{
|
||||
$userdata[] = $username;
|
||||
}
|
||||
}
|
||||
|
||||
$userdata = empty($userdata) ? false : $userdata;
|
||||
|
||||
return $userdata;
|
||||
}
|
||||
elseif(isset($usermails[$email]))
|
||||
{
|
||||
$userdata[] = $usermails[$email];
|
||||
return $userdata;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserMailIndex()
|
||||
{
|
||||
if(file_exists($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-mail.txt'))
|
||||
{
|
||||
# unserialize and return the file
|
||||
$usermailindex = unserialize(file_get_contents($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-mail.txt'));
|
||||
|
||||
if($usermailindex)
|
||||
{
|
||||
return $usermailindex;
|
||||
}
|
||||
}
|
||||
|
||||
$usernames = $this->getUsers();
|
||||
$usermailindex = [];
|
||||
|
||||
foreach($usernames as $username)
|
||||
{
|
||||
$userdata = $this->getSecureUser($username);
|
||||
|
||||
$usermailindex[$userdata['email']] = $username;
|
||||
}
|
||||
|
||||
file_put_contents($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-mail.txt', serialize($usermailindex));
|
||||
|
||||
return $usermailindex;
|
||||
}
|
||||
|
||||
# accepts email with or without asterix and returns usernames
|
||||
public function findUsersByRole($role)
|
||||
{
|
||||
|
||||
/*
|
||||
# get all user files
|
||||
$usernames = $this->getUsers();
|
||||
|
||||
$countusers = count($usernames);
|
||||
|
||||
if($countusers == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# use a simple dirty search if there are less than 10 users (not in use right now)
|
||||
if($countusers <= 4)
|
||||
{
|
||||
$userdata = [];
|
||||
foreach($usernames as $key => $username)
|
||||
{
|
||||
$userdetails = $this->getSecureUser($username);
|
||||
|
||||
if($userdetails['userrole'] == $role)
|
||||
{
|
||||
$userdata[] = $userdetails;
|
||||
}
|
||||
}
|
||||
if(empty($userdata))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return $userdata;
|
||||
}
|
||||
*/
|
||||
$userroles = $this->getUserRoleIndex();
|
||||
|
||||
if(isset($userroles[$role]))
|
||||
{
|
||||
return $userroles[$role];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserRoleIndex()
|
||||
{
|
||||
if(file_exists($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-role.txt'))
|
||||
{
|
||||
# unserialize and return the file
|
||||
$userroleindex = unserialize(file_get_contents($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-role.txt'));
|
||||
if($userroleindex)
|
||||
{
|
||||
return $userroleindex;
|
||||
}
|
||||
}
|
||||
|
||||
$usernames = $this->getUsers();
|
||||
$userroleindex = [];
|
||||
|
||||
foreach($usernames as $username)
|
||||
{
|
||||
$userdata = $this->getSecureUser($username);
|
||||
|
||||
$userroleindex[$userdata['userrole']][] = $username;
|
||||
}
|
||||
|
||||
file_put_contents($this->userDir . DIRECTORY_SEPARATOR . 'tmuserindex-role.txt', serialize($userroleindex));
|
||||
|
||||
return $userroleindex;
|
||||
}
|
||||
|
||||
protected function deleteUserIndex()
|
||||
{
|
||||
$userDir = __DIR__ . '/../../settings/users';
|
||||
|
||||
if(file_exists($userDir . DIRECTORY_SEPARATOR . 'tmuserindex-mail.txt'))
|
||||
{
|
||||
# read and return the file
|
||||
unlink($userDir . DIRECTORY_SEPARATOR . 'tmuserindex-mail.txt');
|
||||
}
|
||||
}
|
||||
|
||||
# deprecated
|
||||
public function getSecureUser(string $username)
|
||||
{
|
||||
$user = $this->getYaml('settings/users', $username . '.yaml');
|
||||
unset($user['password']);
|
||||
return $user;
|
||||
}
|
||||
}
|
609
system/typemill/Models/Validation.php
Normal file
609
system/typemill/Models/Validation.php
Normal file
@@ -0,0 +1,609 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
use Typemill\Models\User;
|
||||
use Valitron\Validator;
|
||||
|
||||
class Validation
|
||||
{
|
||||
/**
|
||||
* Constructor with custom validation rules
|
||||
*
|
||||
* @param obj $db the database connection.
|
||||
*/
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
Validator::langDir(getcwd() . '/system/vendor/vlucas/valitron/lang'); // always set langDir before lang.
|
||||
Validator::lang('en');
|
||||
|
||||
Validator::addRule('values_allowed', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$badvalues = array_diff($value, $params[0]);
|
||||
if(empty($badvalues)){ return true; }
|
||||
return false;
|
||||
}, 'invalid values');
|
||||
|
||||
Validator::addRule('image_types', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$allowed = ['jpg', 'jpeg', 'png', 'webp', 'svg'];
|
||||
$pathinfo = pathinfo($value);
|
||||
$extension = strtolower($pathinfo['extension']);
|
||||
if(in_array($extension, $allowed)){ return true; }
|
||||
return false;
|
||||
}, 'only jpg, jpeg, png, webp, svg allowed');
|
||||
|
||||
# checks if email is available if user is created
|
||||
Validator::addRule('emailAvailable', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$email = trim($value);
|
||||
if($user->findUsersByEmail($email)){ return false; }
|
||||
return true;
|
||||
}, 'taken');
|
||||
|
||||
# checks if email is available if userdata is updated
|
||||
Validator::addRule('emailChanged', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$userdata = $user->getSecureUser($fields['username']);
|
||||
if($userdata['email'] == $value){ return true; } # user has not updated his email
|
||||
|
||||
$email = trim($value);
|
||||
if($user->findUsersByEmail($email)){ return false; }
|
||||
return true;
|
||||
}, 'taken');
|
||||
|
||||
# checks if username is free when create new user
|
||||
Validator::addRule('userAvailable', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$activeUser = $user->getUser($value);
|
||||
$inactiveUser = $user->getUser("_" . $value);
|
||||
if($activeUser OR $inactiveUser){ return false; }
|
||||
return true;
|
||||
}, 'taken');
|
||||
|
||||
# checks if user exists when userdata is updated
|
||||
Validator::addRule('userExists', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$userdata = $user->getUser($value);
|
||||
if($userdata){ return true; }
|
||||
return false;
|
||||
}, 'does not exist');
|
||||
|
||||
Validator::addRule('iplist', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$iplist = explode(",", $value);
|
||||
foreach($iplist as $ip)
|
||||
{
|
||||
if( filter_var( trim($ip), \FILTER_VALIDATE_IP) === false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, 'contains one or more invalid ip-adress.');
|
||||
|
||||
Validator::addRule('customfields', function($field, $customfields, array $params, array $fields) use ($user)
|
||||
{
|
||||
if(empty($customfields))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
foreach($customfields as $key => $value)
|
||||
{
|
||||
if(!isset($key) OR empty($key) OR (preg_match('/^([a-z0-9])+$/i', $key) == false) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($value) OR empty($value) OR ( $value != strip_tags($value) ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}, 'some fields are empty or contain invalid values.');
|
||||
|
||||
Validator::addRule('checkPassword', function($field, $value, array $params, array $fields) use ($user)
|
||||
{
|
||||
$userdata = $user->getUser($fields['username']);
|
||||
if($userdata && password_verify($value, $userdata['password'])){ return true; }
|
||||
return false;
|
||||
}, 'wrong password');
|
||||
|
||||
Validator::addRule('navigation', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
$format = '/[@#^*()=\[\]{};:"\\|,.<>\/]/';
|
||||
if ( preg_match($format, $value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, 'contains special characters');
|
||||
|
||||
Validator::addRule('noSpecialChars', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
$format = '/[!@#$%^&*()_+=\[\]{};\':"\\|,.<>\/?]/';
|
||||
if ( preg_match($format, $value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, 'contains special characters');
|
||||
|
||||
Validator::addRule('noHTML', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
if ( $value == strip_tags($value) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, 'contains html');
|
||||
|
||||
Validator::addRule('markdownSecure', function($field, $value, array $params, array $fields)
|
||||
{
|
||||
/* strip out code blocks and blockquotes */
|
||||
$value = preg_replace('/`{4,}[\s\S]+?`{4,}/', '', $value);
|
||||
$value = preg_replace('/`{3,}[\s\S]+?`{3,}/', '', $value);
|
||||
$value = preg_replace('/`{2,}[\s\S]+?`{2,}/', '', $value);
|
||||
$value = preg_replace('/`{1,}[\s\S]+?`{1,}/', '', $value);
|
||||
$value = preg_replace('/>[\s\S]+?[\n\r]/', '', $value);
|
||||
|
||||
if ( $value == strip_tags($value) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}, 'not secure. For code please use markdown `inline-code` or ````fenced code blocks````.');
|
||||
}
|
||||
|
||||
# return valitron standard object
|
||||
public function returnValidator(array $params)
|
||||
{
|
||||
return new Validator($params);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validation for signup form
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function signin(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['username', 'password'])->message("Required");
|
||||
$v->rule('alphaNum', 'username')->message("Invalid characters");
|
||||
$v->rule('lengthBetween', 'password', 5, 20)->message("Length between 5 - 20");
|
||||
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for signup form
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function newUser(array $params, $userroles)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['username', 'email', 'password'])->message("required");
|
||||
$v->rule('alphaNum', 'username')->message("invalid characters");
|
||||
$v->rule('lengthBetween', 'password', 5, 20)->message("Length between 5 - 20");
|
||||
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
|
||||
$v->rule('userAvailable', 'username')->message("User already exists");
|
||||
$v->rule('noHTML', 'firstname')->message(" contains HTML");
|
||||
$v->rule('lengthBetween', 'firstname', 2, 40);
|
||||
$v->rule('noHTML', 'lastname')->message(" contains HTML");
|
||||
$v->rule('lengthBetween', 'lastname', 2, 40);
|
||||
$v->rule('email', 'email')->message("e-mail is invalid");
|
||||
$v->rule('emailAvailable', 'email')->message("Email already taken");
|
||||
$v->rule('in', 'userrole', $userroles);
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
public function existingUser(array $params, $userroles)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['username', 'email', 'userrole'])->message("required");
|
||||
$v->rule('alphaNum', 'username')->message("invalid");
|
||||
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
|
||||
$v->rule('userExists', 'username')->message("user does not exist");
|
||||
$v->rule('noHTML', 'firstname')->message(" contains HTML");
|
||||
$v->rule('lengthBetween', 'firstname', 2, 40);
|
||||
$v->rule('noHTML', 'lastname')->message(" contains HTML");
|
||||
$v->rule('lengthBetween', 'lastname', 2, 40);
|
||||
$v->rule('email', 'email')->message("e-mail is invalid");
|
||||
$v->rule('emailChanged', 'email')->message("Email already taken");
|
||||
$v->rule('in', 'userrole', $userroles);
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
public function username($username)
|
||||
{
|
||||
$v = new Validator($username);
|
||||
$v->rule('alphaNum', 'username')->message("Only alpha-numeric characters allowed");
|
||||
$v->rule('lengthBetween', 'username', 3, 20)->message("Length between 3 - 20");
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for changing the password
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function newPassword(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['password', 'newpassword']);
|
||||
$v->rule('lengthBetween', 'newpassword', 5, 20);
|
||||
$v->rule('checkPassword', 'password')->message("Password is wrong");
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for password recovery
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function recoverPassword(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
$v->rule('required', ['password', 'passwordrepeat']);
|
||||
$v->rule('lengthBetween', 'password', 5, 20);
|
||||
$v->rule('equals', 'passwordrepeat', 'password');
|
||||
|
||||
return $this->validationResult($v);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for system settings
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function settings(array $params, array $copyright, array $formats, $name = false)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['title', 'author', 'copyright', 'year', 'editor']);
|
||||
$v->rule('lengthBetween', 'title', 2, 50);
|
||||
$v->rule('lengthBetween', 'author', 2, 50);
|
||||
$v->rule('noHTML', 'title');
|
||||
# $v->rule('regex', 'title', '/^[\pL0-9_ \-]*$/u');
|
||||
$v->rule('regex', 'author', '/^[\pL_ \-]*$/u');
|
||||
$v->rule('integer', 'year');
|
||||
$v->rule('length', 'year', 4);
|
||||
$v->rule('length', 'langattr', 2);
|
||||
$v->rule('in', 'editor', ['raw', 'visual']);
|
||||
$v->rule('values_allowed', 'formats', $formats);
|
||||
$v->rule('in', 'copyright', $copyright);
|
||||
$v->rule('noHTML', 'restrictionnotice');
|
||||
$v->rule('lengthBetween', 'restrictionnotice', 2, 1000 );
|
||||
$v->rule('email', 'recoverfrom');
|
||||
$v->rule('noHTML', 'recoversubject');
|
||||
$v->rule('lengthBetween', 'recoversubject', 2, 80 );
|
||||
$v->rule('noHTML', 'recovermessage');
|
||||
$v->rule('lengthBetween', 'recovermessage', 2, 1000 );
|
||||
$v->rule('iplist', 'trustedproxies');
|
||||
|
||||
return $this->validationResult($v, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for content editor
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return true or $v->errors with array of errors to use in json-response
|
||||
*/
|
||||
|
||||
public function editorInput(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['title', 'content', 'url']);
|
||||
$v->rule('lengthBetween', 'title', 2, 100);
|
||||
$v->rule('noHTML', 'title');
|
||||
$v->rule('markdownSecure', 'content');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
public function blockInput(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['markdown', 'block_id', 'url']);
|
||||
$v->rule('markdownSecure', 'markdown');
|
||||
$v->rule('regex', 'block_id', '/^[0-9.]+$/i');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for resort navigation
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return true or $v->errors with array of errors to use in json-response
|
||||
*/
|
||||
|
||||
public function navigationSort(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['item_id', 'parent_id_from', 'parent_id_to']);
|
||||
$v->rule('regex', 'item_id', '/^[0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_from', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('regex', 'parent_id_to', '/^[a-zA-Z0-9.]+$/i');
|
||||
$v->rule('integer', 'index_new');
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for new navigation items
|
||||
*
|
||||
* @param array $params with form data.
|
||||
* @return true or $v->errors with array of errors to use in json-response
|
||||
*/
|
||||
|
||||
public function navigationItem(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['folder_id', 'item_name', 'type', 'url']);
|
||||
$v->rule('regex', 'folder_id', '/^[0-9.]+$/i');
|
||||
# $v->rule('noSpecialChars', 'item_name');
|
||||
$v->rule('navigation', 'item_name');
|
||||
$v->rule('lengthBetween', 'item_name', 1, 60);
|
||||
$v->rule('in', 'type', ['file', 'folder']);
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
public function navigationBaseItem(array $params)
|
||||
{
|
||||
$v = new Validator($params);
|
||||
|
||||
$v->rule('required', ['item_name', 'type', 'url']);
|
||||
# $v->rule('noSpecialChars', 'item_name');
|
||||
$v->rule('navigation', 'item_name');
|
||||
$v->rule('lengthBetween', 'item_name', 1, 40);
|
||||
$v->rule('in', 'type', ['file', 'folder']);
|
||||
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* validation for dynamic fields ( settings for themes and plugins)
|
||||
*
|
||||
* @param string $fieldName with the name of the field.
|
||||
* @param array or string $fieldValue with the values of the field.
|
||||
* @param string $objectName with the name of the plugin or theme.
|
||||
* @param array $fieldDefinitions with the field definitions as multi-dimensional array.
|
||||
* @return obj $v the validation object passed to a result method.
|
||||
*/
|
||||
|
||||
public function objectField($fieldName, $fieldValue, $objectName, $fieldDefinitions, $skiprequired = NULL)
|
||||
{
|
||||
$v = new Validator(array($fieldName => $fieldValue));
|
||||
|
||||
if(isset($fieldDefinitions['required']) && !$skiprequired)
|
||||
{
|
||||
$v->rule('required', $fieldName);
|
||||
}
|
||||
if(isset($fieldDefinitions['maxlength']))
|
||||
{
|
||||
$v->rule('lengthMax', $fieldName, $fieldDefinitions['maxlength']);
|
||||
}
|
||||
if(isset($fieldDefinitions['max']))
|
||||
{
|
||||
$v->rule('max', $fieldName, $fieldDefinitions['max']);
|
||||
}
|
||||
if(isset($fieldDefinitions['min']))
|
||||
{
|
||||
$v->rule('min', $fieldName, $fieldDefinitions['min']);
|
||||
}
|
||||
if(isset($fieldDefinitions['pattern']))
|
||||
{
|
||||
$v->rule('regex', $fieldName, '/^' . $fieldDefinitions['pattern'] . '$/');
|
||||
}
|
||||
|
||||
switch($fieldDefinitions['type'])
|
||||
{
|
||||
case "select":
|
||||
/* create array with option keys as value */
|
||||
$options = array();
|
||||
foreach($fieldDefinitions['options'] as $key => $value){ $options[] = $key; }
|
||||
$v->rule('in', $fieldName, $options);
|
||||
break;
|
||||
case "radio":
|
||||
$v->rule('in', $fieldName, $fieldDefinitions['options']);
|
||||
break;
|
||||
case "checkboxlist":
|
||||
if(isset($fieldValue) && is_array($fieldValue))
|
||||
{
|
||||
/* create array with option keys as value */
|
||||
$options = array();
|
||||
foreach($fieldDefinitions['options'] as $key => $value){ $options[] = $key; }
|
||||
|
||||
/* loop over input values and check, if the options of the field definitions (options for checkboxlist) contains the key (input from user, key is used as value, value is used as label) */
|
||||
foreach($fieldValue as $key => $value)
|
||||
{
|
||||
$v->rule('in', $key, $options);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "color":
|
||||
$v->rule('regex', $fieldName, '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/');
|
||||
break;
|
||||
case "email":
|
||||
$v->rule('email', $fieldName);
|
||||
break;
|
||||
case "date":
|
||||
$v->rule('date', $fieldName);
|
||||
break;
|
||||
case "checkbox":
|
||||
if(isset($fieldDefinitions['required']))
|
||||
{
|
||||
$v->rule('accepted', $fieldName);
|
||||
}
|
||||
break;
|
||||
case "url":
|
||||
$v->rule('url', $fieldName);
|
||||
$v->rule('lengthMax', $fieldName, 200);
|
||||
break;
|
||||
case "text":
|
||||
$v->rule('noHTML', $fieldName);
|
||||
$v->rule('lengthMax', $fieldName, 500);
|
||||
# $v->rule('regex', $fieldName, '/^[\pL0-9_ \-\.\?\!\/\:]*$/u');
|
||||
break;
|
||||
case "textarea":
|
||||
# it understands array, json, yaml
|
||||
if(is_array($fieldValue))
|
||||
{
|
||||
$v = $this->checkArray($fieldValue, $v);
|
||||
}
|
||||
else
|
||||
{
|
||||
$v->rule('noHTML', $fieldName);
|
||||
$v->rule('lengthMax', $fieldName, 10000);
|
||||
}
|
||||
break;
|
||||
case "paragraph":
|
||||
$v->rule('noHTML', $fieldName);
|
||||
$v->rule('lengthMax', $fieldName, 10000);
|
||||
break;
|
||||
case "password":
|
||||
$v->rule('lengthMax', $fieldName, 100);
|
||||
break;
|
||||
case "image":
|
||||
$v->rule('noHTML', $fieldName);
|
||||
$v->rule('lengthMax', $fieldName, 1000);
|
||||
$v->rule('image_types', $fieldName);
|
||||
break;
|
||||
case "customfields":
|
||||
$v->rule('array', $fieldName);
|
||||
$v->rule('customfields', $fieldName);
|
||||
break;
|
||||
default:
|
||||
$v->rule('lengthMax', $fieldName, 1000);
|
||||
$v->rule('regex', $fieldName, '/^[\pL0-9_ \-]*$/u');
|
||||
}
|
||||
return $this->validationResult($v, $objectName);
|
||||
}
|
||||
|
||||
/**
|
||||
* result for validation
|
||||
*
|
||||
* @param obj $v the validation object.
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
public function checkArray($arrayvalues, $v)
|
||||
{
|
||||
foreach($arrayvalues as $key => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
{
|
||||
$this->checkArray($value, $v);
|
||||
}
|
||||
$v->rule('noHTML', $value);
|
||||
$v->rule('lengthMax', $value, 1000);
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
public function validationResult($v, $name = false)
|
||||
{
|
||||
if($v->validate())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if($name == 'meta')
|
||||
{
|
||||
return $v->errors();
|
||||
}
|
||||
elseif($name)
|
||||
{
|
||||
if(isset($_SESSION['errors'][$name]))
|
||||
{
|
||||
foreach ($v->errors() as $key => $val)
|
||||
{
|
||||
$_SESSION['errors'][$name][$key] = $val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['errors'][$name] = $v->errors();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['errors'] = $v->errors();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
40
system/typemill/Models/Yaml.php
Normal file
40
system/typemill/Models/Yaml.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Models;
|
||||
|
||||
class Yaml extends StorageWrapper
|
||||
{
|
||||
/**
|
||||
* Get the a yaml file.
|
||||
* @param string $fileName is the name of the Yaml Folder.
|
||||
* @param string $yamlFileName is the name of the Yaml File.
|
||||
*/
|
||||
public function getYaml($folderName, $yamlFileName)
|
||||
{
|
||||
$yaml = $this->getFile($folderName, $yamlFileName);
|
||||
|
||||
if($yaml)
|
||||
{
|
||||
return \Symfony\Component\Yaml\Yaml::parse($yaml);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a yaml file.
|
||||
* @param string $fileName is the name of the Yaml Folder.
|
||||
* @param string $yamlFileName is the name of the Yaml File.
|
||||
* @param array $contentArray is the content as an array.
|
||||
*/
|
||||
public function updateYaml($folderName, $yamlFileName, $contentArray)
|
||||
{
|
||||
$yaml = \Symfony\Component\Yaml\Yaml::dump($contentArray,6);
|
||||
if($this->writeFile($folderName, $yamlFileName, $yaml))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -2,8 +2,89 @@
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
class Helpers{
|
||||
|
||||
public static function getUserIP()
|
||||
{
|
||||
$client = @$_SERVER['HTTP_CLIENT_IP'];
|
||||
$forward = @$_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
$remote = $_SERVER['REMOTE_ADDR'];
|
||||
|
||||
if(filter_var($client, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $client;
|
||||
}
|
||||
elseif(filter_var($forward, FILTER_VALIDATE_IP))
|
||||
{
|
||||
$ip = $forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
$ip = $remote;
|
||||
}
|
||||
|
||||
return $ip;
|
||||
}
|
||||
|
||||
|
||||
public static function addLogEntry($action)
|
||||
{
|
||||
$line = self::getUserIP();
|
||||
$line .= ';' . date("Y-m-d H:i:s");
|
||||
$line .= ';' . $action;
|
||||
|
||||
$storage = new StorageWrapper('\Typemill\Models\Storage');
|
||||
$logfile = $storage->getFile('cache', 'securitylog.txt');
|
||||
|
||||
if($logfile)
|
||||
{
|
||||
$logfile .= $line . PHP_EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
$logfile = $line . PHP_EOL;
|
||||
}
|
||||
|
||||
$storage->writeFile('cache', 'securitylog.txt', $logfile);
|
||||
}
|
||||
|
||||
public static function array_sort($array, $on, $order=SORT_ASC)
|
||||
{
|
||||
$new_array = array();
|
||||
$sortable_array = array();
|
||||
|
||||
if (count($array) > 0) {
|
||||
foreach ($array as $k => $v) {
|
||||
if (is_array($v)) {
|
||||
foreach ($v as $k2 => $v2) {
|
||||
if ($k2 == $on) {
|
||||
$sortable_array[$k] = $v2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$sortable_array[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
switch ($order) {
|
||||
case SORT_ASC:
|
||||
asort($sortable_array);
|
||||
break;
|
||||
case SORT_DESC:
|
||||
arsort($sortable_array);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($sortable_array as $k => $v) {
|
||||
$new_array[] = $array[$k];
|
||||
}
|
||||
}
|
||||
|
||||
return $new_array;
|
||||
}
|
||||
|
||||
public static function printTimer($timer)
|
||||
{
|
||||
$lastTime = NULL;
|
||||
|
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
class Languages
|
||||
{
|
||||
public static function whichLanguage()
|
||||
{
|
||||
# Check which languages are available
|
||||
$langs = [];
|
||||
$path = __DIR__ . '/author/languages/*.yaml';
|
||||
|
||||
foreach (glob($path) as $filename)
|
||||
{
|
||||
$langs[] = basename($filename,'.yaml');
|
||||
}
|
||||
|
||||
# Detect browser language
|
||||
$accept_lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) : false;
|
||||
$lang = in_array($accept_lang, $langs) ? $accept_lang : 'en';
|
||||
|
||||
return $lang;
|
||||
}
|
||||
}
|
@@ -4,8 +4,9 @@ namespace Typemill\Static;
|
||||
|
||||
class Plugins
|
||||
{
|
||||
public static function loadPlugins($rootpath)
|
||||
public static function loadPlugins()
|
||||
{
|
||||
$rootpath = getcwd();
|
||||
$pluginFolder = self::scanPluginFolder($rootpath);
|
||||
$classNames = [];
|
||||
|
||||
|
@@ -10,11 +10,11 @@ class Session
|
||||
|
||||
foreach($sessionSegments as $segment)
|
||||
{
|
||||
echo '<br>' . $segment;
|
||||
echo '<br>' . $routepath;
|
||||
#echo '<br>' . $segment;
|
||||
#echo '<br>' . $routepath;
|
||||
if(substr( $routepath, 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
echo '<br>Create Session';
|
||||
#echo '<br>Create Session';
|
||||
|
||||
# configure session
|
||||
ini_set('session.cookie_httponly', 1 );
|
||||
|
@@ -4,8 +4,9 @@ namespace Typemill\Static;
|
||||
|
||||
class Settings
|
||||
{
|
||||
public static function loadSettings($rootpath)
|
||||
public static function loadSettings()
|
||||
{
|
||||
$rootpath = getcwd();
|
||||
$defaultsettings = self::getDefaultSettings($rootpath);
|
||||
$usersettings = self::getUserSettings($rootpath);
|
||||
|
||||
|
110
system/typemill/Static/Translations.php
Normal file
110
system/typemill/Static/Translations.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Typemill\Static;
|
||||
|
||||
use Typemill\Models\Yaml;
|
||||
|
||||
class Translations
|
||||
{
|
||||
public static function loadTranslations($settings)
|
||||
{
|
||||
$yaml = new Yaml($settings['storage']);
|
||||
|
||||
$urlsegments = explode('/',trim($settings['routepath'],'/'));
|
||||
|
||||
$environment = 'frontend';
|
||||
if( ($urlsegments[0] === 'tm' OR $urlsegments[0] === 'setup') )
|
||||
{
|
||||
$environment = 'admin';
|
||||
}
|
||||
|
||||
$language = self::whichLanguage();
|
||||
if(isset($settings['language']))
|
||||
{
|
||||
$language = $settings['language'];
|
||||
}
|
||||
|
||||
$theme_translations = [];
|
||||
$system_translations = [];
|
||||
$plugins_translations = [];
|
||||
|
||||
# theme labels selected according to the environment: admin or user
|
||||
$theme_language_folder = 'themes' . DIRECTORY_SEPARATOR . $settings['theme'] . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR . $environment . DIRECTORY_SEPARATOR;
|
||||
$theme_language_file = $language . '.yaml';
|
||||
if (file_exists($theme_language_folder . $theme_language_file))
|
||||
{
|
||||
$theme_translations = $yaml->getYaml($theme_language_folder, $theme_language_file);
|
||||
}
|
||||
|
||||
if($environment == 'admin')
|
||||
{
|
||||
$system_language_folder = 'system' . DIRECTORY_SEPARATOR . 'typemill' . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR . 'translations' . DIRECTORY_SEPARATOR;
|
||||
$system_language_file = $language . '.yaml';
|
||||
if(file_exists($system_language_folder . $system_language_file))
|
||||
{
|
||||
$system_translations = $yaml->getYaml($system_language_folder, $system_language_file);
|
||||
}
|
||||
|
||||
# Next change, to provide labels for the admin and user environments.
|
||||
# There may be plugins that only work in the user environment, only in the admin environment, or in both environments.
|
||||
$plugin_labels = [];
|
||||
if(isset($settings['plugins']) && !empty($settings['plugins']))
|
||||
{
|
||||
foreach($settings['plugins'] as $plugin => $config)
|
||||
{
|
||||
if($config['active'] == 'on')
|
||||
{
|
||||
$plugin_language_folder = 'plugins' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . 'languages' . DIRECTORY_SEPARATOR;
|
||||
$plugin_language_file = $language . '.yaml';
|
||||
if (file_exists($plugin_language_folder . $plugin_language_file))
|
||||
{
|
||||
$plugins_translations[$plugin] = $yaml->getYaml($plugin_language_folder, $plugin_language_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($plugins_translations as $key => $value)
|
||||
{
|
||||
if(is_array($value))
|
||||
{
|
||||
$plugins_translations = array_merge($plugins_translations, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$translations = [];
|
||||
if(!empty($plugins_translations))
|
||||
{
|
||||
$translations = array_merge($translations, $plugins_translations);
|
||||
}
|
||||
if(!empty($system_translations))
|
||||
{
|
||||
$translations = array_merge($translations, $system_translations);
|
||||
}
|
||||
if(!empty($theme_translations))
|
||||
{
|
||||
$translations = array_merge($translations, $theme_translations);
|
||||
}
|
||||
|
||||
return $translations;
|
||||
}
|
||||
|
||||
public static function whichLanguage()
|
||||
{
|
||||
# Check which languages are available
|
||||
$langs = [];
|
||||
$path = __DIR__ . '/author/languages/*.yaml';
|
||||
|
||||
foreach (glob($path) as $filename)
|
||||
{
|
||||
$langs[] = basename($filename,'.yaml');
|
||||
}
|
||||
|
||||
# Detect browser language
|
||||
$accept_lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2) : false;
|
||||
$lang = in_array($accept_lang, $langs) ? $accept_lang : 'en';
|
||||
|
||||
return $lang;
|
||||
}
|
||||
}
|
83
system/typemill/author/auth/login.twig
Normal file
83
system/typemill/author/auth/login.twig
Normal file
@@ -0,0 +1,83 @@
|
||||
{% extends 'layouts/layoutAuth.twig' %}
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="flex justify-end">
|
||||
|
||||
<div class="bg-rose-600 text-white min-h-screen w-1/2 flex justify-center items-center">
|
||||
<div class="max-w-md content-center">
|
||||
|
||||
<h1 class="text-6xl py-5">Login</h1>
|
||||
|
||||
<form method="POST" action="{{ url_for("auth.login") }}" autocomplete="off">
|
||||
|
||||
<fieldset class="">
|
||||
|
||||
<div class="my-2 {{ errors.username ? ' errors' : '' }}">
|
||||
<label for="username">{{ 'Username'|translate }} <abbr title="{{ 'required'|translate }}">*</abbr></label>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
value="{{ old.username }}"
|
||||
class="form-control block w-full px-3 py-1.5 text-base font-normal text-gray-700 bg-white bg-clip-padding border border-solid border-gray-300 transition ease-in-out m-0 focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none"
|
||||
required>
|
||||
{% if errors.signup_username %}
|
||||
<span class="">{{ errors.username|first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="my-2 {{ errors.password ? ' errors' : '' }}">
|
||||
<label for="password">{{ 'Password'|translate }} <abbr title="{{ 'required'|translate }}">*</abbr></label>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
autoomplete="off"
|
||||
class="form-control block w-full px-3 py-1.5 text-base font-normal text-gray-700 bg-white bg-clip-padding border border-solid border-gray-300 transition ease-in-out m-0 focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none"
|
||||
required>
|
||||
{% if errors.password %}
|
||||
<span class="error">{{ errors.password|first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="personal-mail hidden">
|
||||
<label>Personal Mail</label>
|
||||
<input type="text" name="personal-honey-mail">
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="submit"
|
||||
value="{{ 'Login'|translate }}"
|
||||
class="block w-full mt-6 px-3 py-3 border-0 font-medium text-xs leading-tight uppercase bg-white text-rose-600 pointer hover:bg-gray-200 cursor-pointer focus:outline-none focus:ring-0 transition duration-150 ease-in-out"
|
||||
/>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div id="loginarea" class="hidden">{{ csrf() | raw }}</div>
|
||||
|
||||
{% if settings.recoverpw %}
|
||||
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class=""></div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-center w-1/2 flex justify-center items-center">
|
||||
<div class="max-w-md content-center">
|
||||
<h2>Latest from Typemill</h2>
|
||||
<p>Hey, get the latest news from Typemill please!</p>
|
||||
<p>base_url(): {{ base_url() }}</p>
|
||||
<p>current_url(): {{ current_url() }}</p>
|
||||
<p>current_path(): {{ current_path() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
17
system/typemill/author/css/custom.css
Normal file
17
system/typemill/author/css/custom.css
Normal file
@@ -0,0 +1,17 @@
|
||||
/********************
|
||||
* SVG ICONS *
|
||||
********************/
|
||||
|
||||
.icon {
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
stroke-width: 0;
|
||||
stroke: currentColor;
|
||||
fill: currentColor;
|
||||
}
|
||||
.icon.baseline{
|
||||
top: 0.125em;
|
||||
position: relative;
|
||||
}
|
||||
|
3
system/typemill/author/css/input.css
Normal file
3
system/typemill/author/css/input.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
1140
system/typemill/author/css/output.css
Normal file
1140
system/typemill/author/css/output.css
Normal file
File diff suppressed because it is too large
Load Diff
3
system/typemill/author/js/axios.min.js
vendored
Normal file
3
system/typemill/author/js/axios.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
296
system/typemill/author/js/vue-system.js
Normal file
296
system/typemill/author/js/vue-system.js
Normal file
@@ -0,0 +1,296 @@
|
||||
const { createApp } = Vue
|
||||
|
||||
createApp({
|
||||
delimiters: ['${', '}'],
|
||||
data() {
|
||||
return {
|
||||
message: 'Add system forms with vue here',
|
||||
root: document.getElementById("main").dataset.url,
|
||||
currentTab: 'System',
|
||||
tabs: ['System', 'Media', 'Editor', 'Access', 'Password Recovery', 'Advanced'],
|
||||
formDefinitions: [],
|
||||
formData: [],
|
||||
formErrors: {},
|
||||
formErrorsReset: {},
|
||||
item: false,
|
||||
userroles: false,
|
||||
saved: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentTabComponent: function () {
|
||||
if(this.currentTab == 'Content')
|
||||
{
|
||||
editor.showEditor = 'show';
|
||||
posts.showPosts = 'show';
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.showEditor = 'hidden';
|
||||
posts.showPosts = 'hidden';
|
||||
return 'tab-' + this.currentTab.toLowerCase()
|
||||
}
|
||||
}
|
||||
},
|
||||
}).mount('#systemsettings')
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
let system = new Vue({
|
||||
delimiters: ['${', '}'],
|
||||
el: '#wrong',
|
||||
data: function () {
|
||||
return {
|
||||
root: document.getElementById("main").dataset.url,
|
||||
currentTab: 'Content',
|
||||
tabs: ['Content'],
|
||||
formDefinitions: [],
|
||||
formData: [],
|
||||
formErrors: {},
|
||||
formErrorsReset: {},
|
||||
item: false,
|
||||
userroles: false,
|
||||
saved: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currentTabComponent: function () {
|
||||
if(this.currentTab == 'Content')
|
||||
{
|
||||
editor.showEditor = 'show';
|
||||
posts.showPosts = 'show';
|
||||
}
|
||||
else
|
||||
{
|
||||
editor.showEditor = 'hidden';
|
||||
posts.showPosts = 'hidden';
|
||||
return 'tab-' + this.currentTab.toLowerCase()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
|
||||
var self = this;
|
||||
|
||||
myaxios.get('/api/v1/article/metaobject',{
|
||||
params: {
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
}
|
||||
})
|
||||
.then(function (response) {
|
||||
|
||||
var formdefinitions = response.data.metadefinitions;
|
||||
|
||||
for (var key in formdefinitions) {
|
||||
if (formdefinitions.hasOwnProperty(key)) {
|
||||
self.tabs.push(key);
|
||||
self.formErrors[key] = false;
|
||||
}
|
||||
}
|
||||
|
||||
self.formErrorsReset = self.formErrors;
|
||||
self.formDefinitions = formdefinitions;
|
||||
|
||||
self.formData = response.data.metadata;
|
||||
|
||||
self.userroles = response.data.userroles;
|
||||
|
||||
self.item = response.data.item;
|
||||
|
||||
if(self.item.elementType == "folder" && self.item.contains == "posts")
|
||||
{
|
||||
posts.posts = self.item.folderContent;
|
||||
posts.folderid = self.item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
/* update single value or array
|
||||
this.$set(this.someObject, 'b', 2) *
|
||||
FormBus.$on('forminput', formdata => {
|
||||
this.$set(this.formData[this.currentTab], formdata.name, formdata.value);
|
||||
});
|
||||
|
||||
/* update values that are objects
|
||||
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 }) *
|
||||
|
||||
FormBus.$on('forminputobject', formdata => {
|
||||
this.formData[this.currentTab][formdata.name] = Object.assign({}, this.formData[this.currentTab][formdata.name], formdata.value);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
saveForm: function()
|
||||
{
|
||||
this.saved = false;
|
||||
|
||||
self = this;
|
||||
|
||||
myaxios.post('/api/v1/article/metadata',{
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
'tab': self.currentTab,
|
||||
'data': self.formData[self.currentTab]
|
||||
})
|
||||
.then(function (response) {
|
||||
self.saved = true;
|
||||
self.formErrors = self.formErrorsReset;
|
||||
if(response.data.structure)
|
||||
{
|
||||
navi.items = response.data.structure;
|
||||
}
|
||||
|
||||
var item = response.data.item;
|
||||
if(item.elementType == "folder" && item.contains == "posts")
|
||||
{
|
||||
posts.posts = item.folderContent;
|
||||
posts.folderid = item.keyPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
posts.posts = false;
|
||||
}
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response)
|
||||
{
|
||||
self.formErrors = error.response.data.errors;
|
||||
}
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('tab-meta', {
|
||||
props: ['saved', 'errors', 'formdata', 'schema', 'userroles'],
|
||||
data: function () {
|
||||
return {
|
||||
slug: false,
|
||||
originalSlug: false,
|
||||
slugerror: false,
|
||||
disabled: "disabled",
|
||||
}
|
||||
},
|
||||
template: '<section><form>' +
|
||||
'<div v-if="slug !== false"><div class="large relative">' +
|
||||
'<label>Slug / Name in URL</label><input type="text" v-model="slug" pattern="[a-z0-9\- ]" @input="changeSlug()"><button @click.prevent="storeSlug()" :disabled="disabled" class="button slugbutton bn br2 bg-tm-green white absolute">change slug</button>' +
|
||||
'<div v-if="slugerror" class="f6 tm-red mt1">{{ slugerror }}</div>' +
|
||||
'</div></div>' +
|
||||
'<div v-for="(field, index) in schema.fields">' +
|
||||
'<fieldset v-if="field.type == \'fieldset\'" class="fs-formbuilder"><legend>{{field.legend}}</legend>' +
|
||||
'<component v-for="(subfield, index) in field.fields "' +
|
||||
' :key="index"' +
|
||||
' :is="selectComponent(subfield)"' +
|
||||
' :errors="errors"' +
|
||||
' :name="index"' +
|
||||
' :userroles="userroles"' +
|
||||
' v-model="formdata[index]"' +
|
||||
' v-bind="subfield">' +
|
||||
'</component>' +
|
||||
'</fieldset>' +
|
||||
'<component v-else' +
|
||||
' :key="index"' +
|
||||
' :is="selectComponent(field)"' +
|
||||
' :errors="errors"' +
|
||||
' :name="index"' +
|
||||
' :userroles="userroles"' +
|
||||
' v-model="formdata[index]"' +
|
||||
' v-bind="field">' +
|
||||
'</component>' +
|
||||
'</div>' +
|
||||
'<div v-if="saved" class="metasubmit"><div class="metaSuccess">{{ \'Saved successfully\'|translate }}</div></div>' +
|
||||
'<div v-if="errors" class="metasubmit"><div class="metaErrors">{{ \'Please correct the errors above\'|translate }}</div></div>' +
|
||||
'<div class="metasubmit"><input type="submit" @click.prevent="saveInput" :value="\'save\'|translate"></input></div>' +
|
||||
'</form></section>',
|
||||
mounted: function()
|
||||
{
|
||||
if(this.$parent.item.slug != '')
|
||||
{
|
||||
this.slug = this.$parent.item.slug;
|
||||
this.originalSlug = this.slug;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectComponent: function(field)
|
||||
{
|
||||
return 'component-'+field.type;
|
||||
},
|
||||
saveInput: function()
|
||||
{
|
||||
this.$emit('saveform');
|
||||
},
|
||||
changeSlug: function()
|
||||
{
|
||||
if(this.slug == this.originalSlug)
|
||||
{
|
||||
this.slugerror = false;
|
||||
this.disabled = "disabled";
|
||||
return;
|
||||
}
|
||||
if(this.slug == '')
|
||||
{
|
||||
this.slugerror = 'empty slugs are not allowed';
|
||||
this.disabled = "disabled";
|
||||
return;
|
||||
}
|
||||
|
||||
this.slug = this.slug.replace(/ /g, '-');
|
||||
|
||||
if(this.slug.match(/^[a-z0-9\-]*$/))
|
||||
{
|
||||
this.slugerror = false;
|
||||
this.disabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.slugerror = 'Only lowercase a-z and 0-9 and "-" is allowed for slugs.';
|
||||
this.disabled = "disabled";
|
||||
}
|
||||
},
|
||||
storeSlug: function()
|
||||
{
|
||||
|
||||
if(this.slug.match(/^[a-z0-9\-]*$/) && this.slug != this.originalSlug)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
myaxios.post('/api/v1/article/rename',{
|
||||
'url': document.getElementById("path").value,
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
'slug': this.slug,
|
||||
})
|
||||
.then(function (response)
|
||||
{
|
||||
window.location.replace(response.data.url);
|
||||
})
|
||||
.catch(function (error)
|
||||
{
|
||||
if(error.response.data.errors.message)
|
||||
{
|
||||
publishController.errors.message = error.response.data.errors.message;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
*/
|
15988
system/typemill/author/js/vue.js
Normal file
15988
system/typemill/author/js/vue.js
Normal file
File diff suppressed because it is too large
Load Diff
43
system/typemill/author/layouts/layoutAuth.twig
Normal file
43
system/typemill/author/layouts/layoutAuth.twig
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<meta name="description" content="Welcome to your new TYPEMILL website" />
|
||||
<meta name="robots" content="noindex" />
|
||||
|
||||
<meta name="msapplication-TileColor" content="#F9F8F6" />
|
||||
<meta name="msapplication-TileImage" content="{{ base_url() }}/system/author/img/favicon-144.png" />
|
||||
<link rel="icon" type="image/png" href="{{ base_url() }}/system/author/img/favicon-16.png" sizes="16x16" />
|
||||
<link rel="icon" type="image/png" href="{{ base_url() }}/system/author/img/favicon-32.png" sizes="32x32" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="{{ base_url() }}/system/author/img/favicon-72.png" />
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="{{ base_url() }}/system/author/img/favicon-114.png" />
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url() }}/system/author/img/favicon-144.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url() }}/system/author/img/favicon-180.png" />
|
||||
|
||||
<link rel="stylesheet" href="{{ base_url() }}/system/typemill/author/css/output.css?v={{ settings.version }}" />
|
||||
|
||||
{{ assets.renderCSS() }}
|
||||
|
||||
</head>
|
||||
<body class="text-base">
|
||||
<svg style="position: absolute; width: 0; height: 0; overflow: hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<symbol id="icon-bookmark-o" viewBox="0 0 20 28">
|
||||
<title>bookmark-o</title>
|
||||
<path d="M18 4h-16v19.406l8-7.672 1.391 1.328 6.609 6.344v-19.406zM18.188 2c0.234 0 0.469 0.047 0.688 0.141 0.688 0.266 1.125 0.906 1.125 1.609v20.141c0 0.703-0.438 1.344-1.125 1.609-0.219 0.094-0.453 0.125-0.688 0.125-0.484 0-0.938-0.172-1.297-0.5l-6.891-6.625-6.891 6.625c-0.359 0.328-0.812 0.516-1.297 0.516-0.234 0-0.469-0.047-0.688-0.141-0.688-0.266-1.125-0.906-1.125-1.609v-20.141c0-0.703 0.438-1.344 1.125-1.609 0.219-0.094 0.453-0.141 0.688-0.141h16.375z"></path>
|
||||
</symbol>
|
||||
</defs>
|
||||
</svg>
|
||||
|
||||
{% include 'partials/flash.twig' %}
|
||||
|
||||
<div class="">
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
85
system/typemill/author/layouts/layoutSystem.twig
Normal file
85
system/typemill/author/layouts/layoutSystem.twig
Normal file
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<meta name="description" content="Configure your TYPEMILL website"/>
|
||||
|
||||
<meta name="msapplication-TileColor" content="#F9F8F6" />
|
||||
<meta name="msapplication-TileImage" content="{{ base_url() }}/system/author/img/favicon-144.png" />
|
||||
<link rel="icon" type="image/png" href="{{ base_url() }}/system/author/img/favicon-16.png" sizes="16x16" />
|
||||
<link rel="icon" type="image/png" href="{{ base_url() }}/system/author/img/favicon-32.png" sizes="32x32" />
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="{{ base_url() }}/system/author/img/favicon-72.png" />
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="{{ base_url() }}/system/author/img/favicon-114.png" />
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="{{ base_url() }}/system/author/img/favicon-144.png" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{{ base_url() }}/system/author/img/favicon-180.png" />
|
||||
|
||||
<link rel="stylesheet" href="{{ base_url() }}/system/typemill/author/css/output.css?v={{ settings.version }}" />
|
||||
<link rel="stylesheet" href="{{ base_url() }}/system/typemill/author/css/custom.css?v={{ settings.version }}" />
|
||||
|
||||
<!-- <link rel="stylesheet" href="{{ base_url() }}/system/author/css/tachyons.min.css?v={{ settings.version }}" />
|
||||
<link rel="stylesheet" href="{{ base_url() }}/system/author/css/style.css?v={{ settings.version }}" />
|
||||
-->
|
||||
{{ assets.renderCSS() }}
|
||||
|
||||
</head>
|
||||
<body class="bg-stone-100">
|
||||
|
||||
{% include 'partials/symbols.twig' %}
|
||||
|
||||
<header class="border-b-2 border-stone-200">
|
||||
{% include 'partials/mainNavi.twig' %}
|
||||
</header>
|
||||
|
||||
{% include 'partials/flash.twig' %}
|
||||
|
||||
<div class="max-w-6xl m-auto mt-7 flex justify-between" id="main" data-url="{{ base_url() }}">
|
||||
<aside class="w-1/4">
|
||||
{% include 'partials/systemNavi.twig' %}
|
||||
</aside>
|
||||
<article class="w-3/4 bg-stone-50 drop-shadow-md">
|
||||
{% block content %}{% endblock %}
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<footer class="max-w-6xl m-auto bg-stone-50">
|
||||
Typemill version xyz
|
||||
</footer>
|
||||
|
||||
{{ csrf() | raw }}
|
||||
|
||||
<script>
|
||||
|
||||
var data = {{ jsdata | json_encode() | raw }}
|
||||
|
||||
var eventBus = false;
|
||||
|
||||
</script>
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/axios.min.js?v={{ settings.version }}"></script>
|
||||
<script>
|
||||
const tmaxios = axios.create();
|
||||
tmaxios.defaults.baseURL = "{{ base_url() }}";
|
||||
/* tmaxios.defaults.headers.common['Authorization'] = "Basic {{ basicauth }}"; */
|
||||
tmaxios.defaults.headers.common['X-Session-Auth'] = "true";
|
||||
</script>
|
||||
<!-- <script src="{{ base_url() }}/system/typemill/author/js/autosize.min.js?v={{ settings.version }}"></script> -->
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue.js?v={{ settings.version }}"></script>
|
||||
<!--
|
||||
<script>
|
||||
const FormBus = new Vue();
|
||||
</script>
|
||||
<script src="{{ base_url() }}/system/author/js/vue-shared.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/author/js/author.js?v={{ settings.version }}"></script>
|
||||
<script src="{{ base_url() }}/system/author/js/typemillutils.js?v={{ settings.version }}"></script>
|
||||
<script>
|
||||
typemillUtilities.start()
|
||||
</script>
|
||||
-->
|
||||
{% block javascript %}{% endblock %}
|
||||
|
||||
{{ assets.renderJS() }}
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -1,56 +0,0 @@
|
||||
|
||||
{% block title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="setupWrapper">
|
||||
|
||||
<div class="setupContent">
|
||||
|
||||
</div>
|
||||
<div class="authformWrapper">
|
||||
<form method="POST" action="{{ url_for("auth.login") }}" autocomplete="off">
|
||||
|
||||
<fieldset class="auth">
|
||||
<div class="formElement{{ errors.username ? ' errors' : '' }}">
|
||||
|
||||
<input type="text" name="username" value="{{ old.username }}" required>
|
||||
{% if errors.signup_username %}
|
||||
<span class="error">{{ errors.username | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="formElement{{ errors.password ? ' errors' : '' }}">
|
||||
|
||||
<input type="password" name="password" required autoomplete="off">
|
||||
{% if errors.password %}
|
||||
<span class="error">{{ errors.password | first }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="personal-mail">
|
||||
<label>Personal Mail</label>
|
||||
<input type="text" name="personal-honey-mail">
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<div class="loginarea" id="loginarea">
|
||||
|
||||
{{ csrf() | raw }}
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% if settings.recoverpw %}
|
||||
|
||||
|
||||
{% else %}
|
||||
|
||||
<div class="setupContent">
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<footer></footer>
|
||||
{% endblock %}
|
15
system/typemill/author/partials/flash.twig
Normal file
15
system/typemill/author/partials/flash.twig
Normal file
@@ -0,0 +1,15 @@
|
||||
{% if flash.info %}
|
||||
|
||||
<div class="alert alert-info" id="flash-message">
|
||||
{{ flash.info | first }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if flash.error %}
|
||||
|
||||
<div class="alert alert-error" id="flash-message">
|
||||
{{ flash.error | first }}
|
||||
</div>
|
||||
|
||||
{% endif %}
|
12
system/typemill/author/partials/mainNavi.twig
Normal file
12
system/typemill/author/partials/mainNavi.twig
Normal file
@@ -0,0 +1,12 @@
|
||||
<nav class="max-w-6xl m-auto flex justify-between">
|
||||
<div class="p-3 text-2xl font-bold">
|
||||
<a href="{{ base_url }}/tm/content/{{ settings.editor }}">Typemill</a>
|
||||
</div>
|
||||
<ul class="flex border-l-2 border-stone-200">
|
||||
{% for name,navitem in mainnavi %}
|
||||
<li class="border-r-2 border-stone-200">
|
||||
<a class="inline-block px-4 pt-4 pb-3 border-b-4 hover:border-stone-700 hover:bg-stone-50 focus:bg-stone-50 active:bg-stone-50{{ navitem.active ? ' bg-stone-50 border-stone-700' : ' border-stone-100' }}" href="{{ url_for(navitem.routename) }}">{{ translate(navitem.title)|capitalize }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
182
system/typemill/author/partials/symbols.twig
Normal file
182
system/typemill/author/partials/symbols.twig
Normal file
@@ -0,0 +1,182 @@
|
||||
<svg style="position: absolute; width: 0; height: 0; overflow: hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<symbol id="icon-external-link" viewBox="0 0 28 28">
|
||||
<title>{{ translate('EXTERNAL_LINK') }}</title>
|
||||
<path d="M22 14.5v5c0 2.484-2.016 4.5-4.5 4.5h-13c-2.484 0-4.5-2.016-4.5-4.5v-13c0-2.484 2.016-4.5 4.5-4.5h11c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-1.375 0-2.5 1.125-2.5 2.5v13c0 1.375 1.125 2.5 2.5 2.5h13c1.375 0 2.5-1.125 2.5-2.5v-5c0-0.281 0.219-0.5 0.5-0.5h1c0.281 0 0.5 0.219 0.5 0.5zM28 1v8c0 0.547-0.453 1-1 1-0.266 0-0.516-0.109-0.703-0.297l-2.75-2.75-10.187 10.187c-0.094 0.094-0.234 0.156-0.359 0.156s-0.266-0.063-0.359-0.156l-1.781-1.781c-0.094-0.094-0.156-0.234-0.156-0.359s0.063-0.266 0.156-0.359l10.187-10.187-2.75-2.75c-0.187-0.187-0.297-0.438-0.297-0.703 0-0.547 0.453-1 1-1h8c0.547 0 1 0.453 1 1z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-file-text-o" viewBox="0 0 24 28">
|
||||
<title>{{ translate('TEXT_FILE') }}</title>
|
||||
<path d="M22.937 5.938c0.578 0.578 1.062 1.734 1.062 2.562v18c0 0.828-0.672 1.5-1.5 1.5h-21c-0.828 0-1.5-0.672-1.5-1.5v-25c0-0.828 0.672-1.5 1.5-1.5h14c0.828 0 1.984 0.484 2.562 1.062zM16 2.125v5.875h5.875c-0.094-0.266-0.234-0.531-0.344-0.641l-4.891-4.891c-0.109-0.109-0.375-0.25-0.641-0.344zM22 26v-16h-6.5c-0.828 0-1.5-0.672-1.5-1.5v-6.5h-12v24h20zM6 12.5c0-0.281 0.219-0.5 0.5-0.5h11c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1zM17.5 16c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h11zM17.5 20c0.281 0 0.5 0.219 0.5 0.5v1c0 0.281-0.219 0.5-0.5 0.5h-11c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h11z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cog" viewBox="0 0 24 28">
|
||||
<title>{{ translate('COG') }}</title>
|
||||
<path d="M16 14c0-2.203-1.797-4-4-4s-4 1.797-4 4 1.797 4 4 4 4-1.797 4-4zM24 12.297v3.469c0 0.234-0.187 0.516-0.438 0.562l-2.891 0.438c-0.172 0.5-0.359 0.969-0.609 1.422 0.531 0.766 1.094 1.453 1.672 2.156 0.094 0.109 0.156 0.25 0.156 0.391s-0.047 0.25-0.141 0.359c-0.375 0.5-2.484 2.797-3.016 2.797-0.141 0-0.281-0.063-0.406-0.141l-2.156-1.687c-0.453 0.234-0.938 0.438-1.422 0.594-0.109 0.953-0.203 1.969-0.453 2.906-0.063 0.25-0.281 0.438-0.562 0.438h-3.469c-0.281 0-0.531-0.203-0.562-0.469l-0.438-2.875c-0.484-0.156-0.953-0.344-1.406-0.578l-2.203 1.672c-0.109 0.094-0.25 0.141-0.391 0.141s-0.281-0.063-0.391-0.172c-0.828-0.75-1.922-1.719-2.578-2.625-0.078-0.109-0.109-0.234-0.109-0.359 0-0.141 0.047-0.25 0.125-0.359 0.531-0.719 1.109-1.406 1.641-2.141-0.266-0.5-0.484-1.016-0.641-1.547l-2.859-0.422c-0.266-0.047-0.453-0.297-0.453-0.562v-3.469c0-0.234 0.187-0.516 0.422-0.562l2.906-0.438c0.156-0.5 0.359-0.969 0.609-1.437-0.531-0.75-1.094-1.453-1.672-2.156-0.094-0.109-0.156-0.234-0.156-0.375s0.063-0.25 0.141-0.359c0.375-0.516 2.484-2.797 3.016-2.797 0.141 0 0.281 0.063 0.406 0.156l2.156 1.672c0.453-0.234 0.938-0.438 1.422-0.594 0.109-0.953 0.203-1.969 0.453-2.906 0.063-0.25 0.281-0.438 0.562-0.438h3.469c0.281 0 0.531 0.203 0.562 0.469l0.438 2.875c0.484 0.156 0.953 0.344 1.406 0.578l2.219-1.672c0.094-0.094 0.234-0.141 0.375-0.141s0.281 0.063 0.391 0.156c0.828 0.766 1.922 1.734 2.578 2.656 0.078 0.094 0.109 0.219 0.109 0.344 0 0.141-0.047 0.25-0.125 0.359-0.531 0.719-1.109 1.406-1.641 2.141 0.266 0.5 0.484 1.016 0.641 1.531l2.859 0.438c0.266 0.047 0.453 0.297 0.453 0.562z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-power-off" viewBox="0 0 24 28">
|
||||
<title>{{ translate('POWER_OFF') }}</title>
|
||||
<path d="M24 14c0 6.609-5.391 12-12 12s-12-5.391-12-12c0-3.797 1.75-7.297 4.797-9.578 0.891-0.672 2.141-0.5 2.797 0.391 0.672 0.875 0.484 2.141-0.391 2.797-2.031 1.531-3.203 3.859-3.203 6.391 0 4.406 3.594 8 8 8s8-3.594 8-8c0-2.531-1.172-4.859-3.203-6.391-0.875-0.656-1.062-1.922-0.391-2.797 0.656-0.891 1.922-1.062 2.797-0.391 3.047 2.281 4.797 5.781 4.797 9.578zM14 2v10c0 1.094-0.906 2-2 2s-2-0.906-2-2v-10c0-1.094 0.906-2 2-2s2 0.906 2 2z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-minus" viewBox="0 0 22 28">
|
||||
<title>{{ translate('DELETE') }}</title>
|
||||
<path d="M22 11.5v3c0 0.828-0.672 1.5-1.5 1.5h-19c-0.828 0-1.5-0.672-1.5-1.5v-3c0-0.828 0.672-1.5 1.5-1.5h19c0.828 0 1.5 0.672 1.5 1.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-plus" viewBox="0 0 22 28">
|
||||
<title>{{ translate('ADD') }}</title>
|
||||
<path d="M22 11.5v3c0 0.828-0.672 1.5-1.5 1.5h-6.5v6.5c0 0.828-0.672 1.5-1.5 1.5h-3c-0.828 0-1.5-0.672-1.5-1.5v-6.5h-6.5c-0.828 0-1.5-0.672-1.5-1.5v-3c0-0.828 0.672-1.5 1.5-1.5h6.5v-6.5c0-0.828 0.672-1.5 1.5-1.5h3c0.828 0 1.5 0.672 1.5 1.5v6.5h6.5c0.828 0 1.5 0.672 1.5 1.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-close" viewBox="0 0 22 28">
|
||||
<title>{{ translate('DELETE_CLOSE') }}</title>
|
||||
<path d="M20.281 20.656c0 0.391-0.156 0.781-0.438 1.062l-2.125 2.125c-0.281 0.281-0.672 0.438-1.062 0.438s-0.781-0.156-1.062-0.438l-4.594-4.594-4.594 4.594c-0.281 0.281-0.672 0.438-1.062 0.438s-0.781-0.156-1.062-0.438l-2.125-2.125c-0.281-0.281-0.438-0.672-0.438-1.062s0.156-0.781 0.438-1.062l4.594-4.594-4.594-4.594c-0.281-0.281-0.438-0.672-0.438-1.062s0.156-0.781 0.438-1.062l2.125-2.125c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l4.594 4.594 4.594-4.594c0.281-0.281 0.672-0.438 1.062-0.438s0.781 0.156 1.062 0.438l2.125 2.125c0.281 0.281 0.438 0.672 0.438 1.062s-0.156 0.781-0.438 1.062l-4.594 4.594 4.594 4.594c0.281 0.281 0.438 0.672 0.438 1.062z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-home" viewBox="0 0 26 28">
|
||||
<title>{{ translate('HOME') }}</title>
|
||||
<path d="M22 15.5v7.5c0 0.547-0.453 1-1 1h-6v-6h-4v6h-6c-0.547 0-1-0.453-1-1v-7.5c0-0.031 0.016-0.063 0.016-0.094l8.984-7.406 8.984 7.406c0.016 0.031 0.016 0.063 0.016 0.094zM25.484 14.422l-0.969 1.156c-0.078 0.094-0.203 0.156-0.328 0.172h-0.047c-0.125 0-0.234-0.031-0.328-0.109l-10.813-9.016-10.813 9.016c-0.109 0.078-0.234 0.125-0.375 0.109-0.125-0.016-0.25-0.078-0.328-0.172l-0.969-1.156c-0.172-0.203-0.141-0.531 0.063-0.703l11.234-9.359c0.656-0.547 1.719-0.547 2.375 0l3.813 3.187v-3.047c0-0.281 0.219-0.5 0.5-0.5h3c0.281 0 0.5 0.219 0.5 0.5v6.375l3.422 2.844c0.203 0.172 0.234 0.5 0.063 0.703z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-arrows-v" viewBox="0 0 12 28">
|
||||
<title>{{ translate('MOVE_VERTICAL') }}</title>
|
||||
<path d="M11 5c0 0.547-0.453 1-1 1h-2v16h2c0.547 0 1 0.453 1 1 0 0.266-0.109 0.516-0.297 0.703l-4 4c-0.187 0.187-0.438 0.297-0.703 0.297s-0.516-0.109-0.703-0.297l-4-4c-0.187-0.187-0.297-0.438-0.297-0.703 0-0.547 0.453-1 1-1h2v-16h-2c-0.547 0-1-0.453-1-1 0-0.266 0.109-0.516 0.297-0.703l4-4c0.187-0.187 0.438-0.297 0.703-0.297s0.516 0.109 0.703 0.297l4 4c0.187 0.187 0.297 0.438 0.297 0.703z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-folder-o" viewBox="0 0 26 28">
|
||||
<title>{{ translate('FOLDER') }}</title>
|
||||
<path d="M24 20.5v-11c0-0.828-0.672-1.5-1.5-1.5h-11c-0.828 0-1.5-0.672-1.5-1.5v-1c0-0.828-0.672-1.5-1.5-1.5h-5c-0.828 0-1.5 0.672-1.5 1.5v15c0 0.828 0.672 1.5 1.5 1.5h19c0.828 0 1.5-0.672 1.5-1.5zM26 9.5v11c0 1.922-1.578 3.5-3.5 3.5h-19c-1.922 0-3.5-1.578-3.5-3.5v-15c0-1.922 1.578-3.5 3.5-3.5h5c1.922 0 3.5 1.578 3.5 3.5v0.5h10.5c1.922 0 3.5 1.578 3.5 3.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-upload" viewBox="0 0 26 28">
|
||||
<title>{{ translate('UPLOAD') }}</title>
|
||||
<path d="M20 23c0-0.547-0.453-1-1-1s-1 0.453-1 1 0.453 1 1 1 1-0.453 1-1zM24 23c0-0.547-0.453-1-1-1s-1 0.453-1 1 0.453 1 1 1 1-0.453 1-1zM26 19.5v5c0 0.828-0.672 1.5-1.5 1.5h-23c-0.828 0-1.5-0.672-1.5-1.5v-5c0-0.828 0.672-1.5 1.5-1.5h6.672c0.422 1.156 1.531 2 2.828 2h4c1.297 0 2.406-0.844 2.828-2h6.672c0.828 0 1.5 0.672 1.5 1.5zM20.922 9.375c-0.156 0.375-0.516 0.625-0.922 0.625h-4v7c0 0.547-0.453 1-1 1h-4c-0.547 0-1-0.453-1-1v-7h-4c-0.406 0-0.766-0.25-0.922-0.625-0.156-0.359-0.078-0.797 0.219-1.078l7-7c0.187-0.203 0.453-0.297 0.703-0.297s0.516 0.094 0.703 0.297l7 7c0.297 0.281 0.375 0.719 0.219 1.078z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-image" viewBox="0 0 32 32">
|
||||
<title>{{ translate('IMAGE') }}</title>
|
||||
<path d="M29.996 4c0.001 0.001 0.003 0.002 0.004 0.004v23.993c-0.001 0.001-0.002 0.003-0.004 0.004h-27.993c-0.001-0.001-0.003-0.002-0.004-0.004v-23.993c0.001-0.001 0.002-0.003 0.004-0.004h27.993zM30 2h-28c-1.1 0-2 0.9-2 2v24c0 1.1 0.9 2 2 2h28c1.1 0 2-0.9 2-2v-24c0-1.1-0.9-2-2-2v0z"></path>
|
||||
<path d="M26 9c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z"></path>
|
||||
<path d="M28 26h-24v-4l7-12 8 10h2l7-6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-exclamation-circle" viewBox="0 0 24 28">
|
||||
<title>{{ translate('NOTICE') }}</title>
|
||||
<path d="M12 2c6.625 0 12 5.375 12 12s-5.375 12-12 12-12-5.375-12-12 5.375-12 12-12zM14 21.484v-2.969c0-0.281-0.219-0.516-0.484-0.516h-3c-0.281 0-0.516 0.234-0.516 0.516v2.969c0 0.281 0.234 0.516 0.516 0.516h3c0.266 0 0.484-0.234 0.484-0.516zM13.969 16.109l0.281-9.703c0-0.109-0.047-0.219-0.156-0.281-0.094-0.078-0.234-0.125-0.375-0.125h-3.437c-0.141 0-0.281 0.047-0.375 0.125-0.109 0.063-0.156 0.172-0.156 0.281l0.266 9.703c0 0.219 0.234 0.391 0.531 0.391h2.891c0.281 0 0.516-0.172 0.531-0.391z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-paperclip" viewBox="0 0 22 28">
|
||||
<title>{{ translate('PAPERCLIP') }}</title>
|
||||
<path d="M21.938 21.641c0 2.438-1.859 4.297-4.297 4.297-1.375 0-2.703-0.594-3.672-1.563l-12.141-12.125c-1.109-1.125-1.766-2.656-1.766-4.234 0-3.313 2.609-5.953 5.922-5.953 1.594 0 3.125 0.641 4.266 1.766l9.453 9.469c0.094 0.094 0.156 0.219 0.156 0.344 0 0.328-0.875 1.203-1.203 1.203-0.141 0-0.266-0.063-0.359-0.156l-9.469-9.484c-0.75-0.734-1.766-1.203-2.828-1.203-2.219 0-3.938 1.797-3.938 4 0 1.062 0.438 2.078 1.188 2.828l12.125 12.141c0.594 0.594 1.422 0.984 2.266 0.984 1.328 0 2.312-0.984 2.312-2.312 0-0.859-0.391-1.672-0.984-2.266l-9.078-9.078c-0.25-0.234-0.594-0.375-0.938-0.375-0.594 0-1.047 0.438-1.047 1.047 0 0.344 0.156 0.672 0.391 0.922l6.406 6.406c0.094 0.094 0.156 0.219 0.156 0.344 0 0.328-0.891 1.219-1.219 1.219-0.125 0-0.25-0.063-0.344-0.156l-6.406-6.406c-0.625-0.609-0.984-1.469-0.984-2.328 0-1.719 1.344-3.062 3.063-3.062 0.875 0 1.719 0.359 2.328 0.984l9.078 9.078c0.984 0.969 1.563 2.297 1.563 3.672z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-play" viewBox="0 0 32 32">
|
||||
<title>{{ translate('VIDEO') }}</title>
|
||||
<path d="M30.662 5.003c-4.488-0.645-9.448-1.003-14.662-1.003s-10.174 0.358-14.662 1.003c-0.86 3.366-1.338 7.086-1.338 10.997s0.477 7.63 1.338 10.997c4.489 0.645 9.448 1.003 14.662 1.003s10.174-0.358 14.662-1.003c0.86-3.366 1.338-7.086 1.338-10.997s-0.477-7.63-1.338-10.997zM12 22v-12l10 6-10 6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-quotes-left" viewBox="0 0 32 32">
|
||||
<title>{{ translate('QUOTES') }}</title>
|
||||
<path d="M7.031 14c3.866 0 7 3.134 7 7s-3.134 7-7 7-7-3.134-7-7l-0.031-1c0-7.732 6.268-14 14-14v4c-2.671 0-5.182 1.040-7.071 2.929-0.364 0.364-0.695 0.751-0.995 1.157 0.357-0.056 0.724-0.086 1.097-0.086zM25.031 14c3.866 0 7 3.134 7 7s-3.134 7-7 7-7-3.134-7-7l-0.031-1c0-7.732 6.268-14 14-14v4c-2.671 0-5.182 1.040-7.071 2.929-0.364 0.364-0.695 0.751-0.995 1.157 0.358-0.056 0.724-0.086 1.097-0.086z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-list-numbered" viewBox="0 0 32 32">
|
||||
<title>{{ translate('NUMBERED_LIST') }}</title>
|
||||
<path d="M12 26h20v4h-20zM12 14h20v4h-20zM12 2h20v4h-20zM6 0v8h-2v-6h-2v-2zM4 16.438v1.563h4v2h-6v-4.563l4-1.875v-1.563h-4v-2h6v4.563zM8 22v10h-6v-2h4v-2h-4v-2h4v-2h-4v-2z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-list2" viewBox="0 0 32 32">
|
||||
<title>{{ translate('BULLET_LIST') }}</title>
|
||||
<path d="M12 2h20v4h-20v-4zM12 14h20v4h-20v-4zM12 26h20v4h-20v-4zM0 4c0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.209-1.791 4-4 4s-4-1.791-4-4zM0 16c0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.209-1.791 4-4 4s-4-1.791-4-4zM0 28c0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.209-1.791 4-4 4s-4-1.791-4-4z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-link" viewBox="0 0 32 32">
|
||||
<title>{{ translate('LINK') }}</title>
|
||||
<path d="M13.757 19.868c-0.416 0-0.832-0.159-1.149-0.476-2.973-2.973-2.973-7.81 0-10.783l6-6c1.44-1.44 3.355-2.233 5.392-2.233s3.951 0.793 5.392 2.233c2.973 2.973 2.973 7.81 0 10.783l-2.743 2.743c-0.635 0.635-1.663 0.635-2.298 0s-0.635-1.663 0-2.298l2.743-2.743c1.706-1.706 1.706-4.481 0-6.187-0.826-0.826-1.925-1.281-3.094-1.281s-2.267 0.455-3.094 1.281l-6 6c-1.706 1.706-1.706 4.481 0 6.187 0.635 0.635 0.635 1.663 0 2.298-0.317 0.317-0.733 0.476-1.149 0.476z"></path>
|
||||
<path d="M8 31.625c-2.037 0-3.952-0.793-5.392-2.233-2.973-2.973-2.973-7.81 0-10.783l2.743-2.743c0.635-0.635 1.664-0.635 2.298 0s0.635 1.663 0 2.298l-2.743 2.743c-1.706 1.706-1.706 4.481 0 6.187 0.826 0.826 1.925 1.281 3.094 1.281s2.267-0.455 3.094-1.281l6-6c1.706-1.706 1.706-4.481 0-6.187-0.635-0.635-0.635-1.663 0-2.298s1.663-0.635 2.298 0c2.973 2.973 2.973 7.81 0 10.783l-6 6c-1.44 1.44-3.355 2.233-5.392 2.233z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-bold" viewBox="0 0 32 32">
|
||||
<title>{{ translate('BOLD') }}</title>
|
||||
<path d="M22.121 15.145c1.172-1.392 1.879-3.188 1.879-5.145 0-4.411-3.589-8-8-8h-10v28h12c4.411 0 8-3.589 8-8 0-2.905-1.556-5.453-3.879-6.855zM12 6h3.172c1.749 0 3.172 1.794 3.172 4s-1.423 4-3.172 4h-3.172v-8zM16.969 26h-4.969v-8h4.969c1.827 0 3.313 1.794 3.313 4s-1.486 4-3.313 4z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-italic" viewBox="0 0 32 32">
|
||||
<title>{{ translate('ITALIC') }}</title>
|
||||
<path d="M28 2v2h-4l-10 24h4v2h-14v-2h4l10-24h-4v-2z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-pagebreak" viewBox="0 0 32 32">
|
||||
<title>{{ translate('HORIZONTAL_LINE') }}</title>
|
||||
<path d="M8 12v-12h24v12h-2v-10h-20v10zM32 18v14h-24v-14h2v12h20v-12zM16 14h4v2h-4zM10 14h4v2h-4zM22 14h4v2h-4zM28 14h4v2h-4zM0 9l6 6-6 6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-table2" viewBox="0 0 32 32">
|
||||
<title>{{ translate('TABLE') }}</title>
|
||||
<path d="M0 2v28h32v-28h-32zM12 20v-6h8v6h-8zM20 22v6h-8v-6h8zM20 6v6h-8v-6h8zM10 6v6h-8v-6h8zM2 14h8v6h-8v-6zM22 14h8v6h-8v-6zM22 12v-6h8v6h-8zM2 22h8v6h-8v-6zM22 28v-6h8v6h-8z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-pilcrow" viewBox="0 0 32 32">
|
||||
<title>{{ translate('PARAGRAPH') }}</title>
|
||||
<path d="M12 0h16v4h-4v28h-4v-28h-4v28h-4v-16c-4.418 0-8-3.582-8-8s3.582-8 8-8z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-embed" viewBox="0 0 32 32">
|
||||
<title>{{ translate('CODE') }}</title>
|
||||
<path d="M18 23l3 3 10-10-10-10-3 3 7 7z"></path>
|
||||
<path d="M14 9l-3-3-10 10 10 10 3-3-7-7z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-header" viewBox="0 0 28 28">
|
||||
<title>{{ translate('HEADLINE') }}</title>
|
||||
<path d="M26.281 26c-1.375 0-2.766-0.109-4.156-0.109-1.375 0-2.75 0.109-4.125 0.109-0.531 0-0.781-0.578-0.781-1.031 0-1.391 1.563-0.797 2.375-1.328 0.516-0.328 0.516-1.641 0.516-2.188l-0.016-6.109c0-0.172 0-0.328-0.016-0.484-0.25-0.078-0.531-0.063-0.781-0.063h-10.547c-0.266 0-0.547-0.016-0.797 0.063-0.016 0.156-0.016 0.313-0.016 0.484l-0.016 5.797c0 0.594 0 2.219 0.578 2.562 0.812 0.5 2.656-0.203 2.656 1.203 0 0.469-0.219 1.094-0.766 1.094-1.453 0-2.906-0.109-4.344-0.109-1.328 0-2.656 0.109-3.984 0.109-0.516 0-0.75-0.594-0.75-1.031 0-1.359 1.437-0.797 2.203-1.328 0.5-0.344 0.516-1.687 0.516-2.234l-0.016-0.891v-12.703c0-0.75 0.109-3.156-0.594-3.578-0.781-0.484-2.453 0.266-2.453-1.141 0-0.453 0.203-1.094 0.75-1.094 1.437 0 2.891 0.109 4.328 0.109 1.313 0 2.641-0.109 3.953-0.109 0.562 0 0.781 0.625 0.781 1.094 0 1.344-1.547 0.688-2.312 1.172-0.547 0.328-0.547 1.937-0.547 2.5l0.016 5c0 0.172 0 0.328 0.016 0.5 0.203 0.047 0.406 0.047 0.609 0.047h10.922c0.187 0 0.391 0 0.594-0.047 0.016-0.172 0.016-0.328 0.016-0.5l0.016-5c0-0.578 0-2.172-0.547-2.5-0.781-0.469-2.344 0.156-2.344-1.172 0-0.469 0.219-1.094 0.781-1.094 1.375 0 2.75 0.109 4.125 0.109 1.344 0 2.688-0.109 4.031-0.109 0.562 0 0.781 0.625 0.781 1.094 0 1.359-1.609 0.672-2.391 1.156-0.531 0.344-0.547 1.953-0.547 2.516l0.016 14.734c0 0.516 0.031 1.875 0.531 2.188 0.797 0.5 2.484-0.141 2.484 1.219 0 0.453-0.203 1.094-0.75 1.094z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-list-alt" viewBox="0 0 28 28">
|
||||
<title>{{ translate('TABLE_OF_CONTENTS') }}</title>
|
||||
<path d="M6 18.5v1c0 0.266-0.234 0.5-0.5 0.5h-1c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h1c0.266 0 0.5 0.234 0.5 0.5zM6 14.5v1c0 0.266-0.234 0.5-0.5 0.5h-1c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h1c0.266 0 0.5 0.234 0.5 0.5zM6 10.5v1c0 0.266-0.234 0.5-0.5 0.5h-1c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h1c0.266 0 0.5 0.234 0.5 0.5zM24 18.5v1c0 0.266-0.234 0.5-0.5 0.5h-15c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h15c0.266 0 0.5 0.234 0.5 0.5zM24 14.5v1c0 0.266-0.234 0.5-0.5 0.5h-15c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h15c0.266 0 0.5 0.234 0.5 0.5zM24 10.5v1c0 0.266-0.234 0.5-0.5 0.5h-15c-0.266 0-0.5-0.234-0.5-0.5v-1c0-0.266 0.234-0.5 0.5-0.5h15c0.266 0 0.5 0.234 0.5 0.5zM26 21.5v-13c0-0.266-0.234-0.5-0.5-0.5h-23c-0.266 0-0.5 0.234-0.5 0.5v13c0 0.266 0.234 0.5 0.5 0.5h23c0.266 0 0.5-0.234 0.5-0.5zM28 4.5v17c0 1.375-1.125 2.5-2.5 2.5h-23c-1.375 0-2.5-1.125-2.5-2.5v-17c0-1.375 1.125-2.5 2.5-2.5h23c1.375 0 2.5 1.125 2.5 2.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-dots-two-vertical" viewBox="0 0 20 20">
|
||||
<title>{{ translate('DEFINITION') }}</title>
|
||||
<path d="M10.001 8.2c1.215 0 2.199-0.986 2.199-2.2s-0.984-2.2-2.199-2.2c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2zM10.001 11.8c-1.215 0-2.201 0.985-2.201 2.2s0.986 2.2 2.201 2.2c1.215 0 2.199-0.985 2.199-2.2s-0.984-2.2-2.199-2.2z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-check" viewBox="0 0 20 20">
|
||||
<title>{{ translate('CHECK') }}</title>
|
||||
<path d="M8.294 16.998c-0.435 0-0.847-0.203-1.111-0.553l-3.573-4.721c-0.465-0.613-0.344-1.486 0.27-1.951 0.615-0.467 1.488-0.344 1.953 0.27l2.351 3.104 5.911-9.492c0.407-0.652 1.267-0.852 1.921-0.445s0.854 1.266 0.446 1.92l-6.984 11.21c-0.242 0.391-0.661 0.635-1.12 0.656-0.022 0.002-0.042 0.002-0.064 0.002z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cross" viewBox="0 0 20 20">
|
||||
<title>{{ translate('CROSS') }}</title>
|
||||
<path d="M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-trash-o" viewBox="0 0 22 28">
|
||||
<title>{{ translate('TRASH') }}</title>
|
||||
<path d="M8 11.5v9c0 0.281-0.219 0.5-0.5 0.5h-1c-0.281 0-0.5-0.219-0.5-0.5v-9c0-0.281 0.219-0.5 0.5-0.5h1c0.281 0 0.5 0.219 0.5 0.5zM12 11.5v9c0 0.281-0.219 0.5-0.5 0.5h-1c-0.281 0-0.5-0.219-0.5-0.5v-9c0-0.281 0.219-0.5 0.5-0.5h1c0.281 0 0.5 0.219 0.5 0.5zM16 11.5v9c0 0.281-0.219 0.5-0.5 0.5h-1c-0.281 0-0.5-0.219-0.5-0.5v-9c0-0.281 0.219-0.5 0.5-0.5h1c0.281 0 0.5 0.219 0.5 0.5zM18 22.813v-14.812h-14v14.812c0 0.75 0.422 1.188 0.5 1.188h13c0.078 0 0.5-0.438 0.5-1.188zM7.5 6h7l-0.75-1.828c-0.047-0.063-0.187-0.156-0.266-0.172h-4.953c-0.094 0.016-0.219 0.109-0.266 0.172zM22 6.5v1c0 0.281-0.219 0.5-0.5 0.5h-1.5v14.812c0 1.719-1.125 3.187-2.5 3.187h-13c-1.375 0-2.5-1.406-2.5-3.125v-14.875h-1.5c-0.281 0-0.5-0.219-0.5-0.5v-1c0-0.281 0.219-0.5 0.5-0.5h4.828l1.094-2.609c0.313-0.766 1.25-1.391 2.078-1.391h5c0.828 0 1.766 0.625 2.078 1.391l1.094 2.609h4.828c0.281 0 0.5 0.219 0.5 0.5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-info" viewBox="0 0 32 32">
|
||||
<title>{{ translate('INFO') }}</title>
|
||||
<path d="M14 9.5c0-0.825 0.675-1.5 1.5-1.5h1c0.825 0 1.5 0.675 1.5 1.5v1c0 0.825-0.675 1.5-1.5 1.5h-1c-0.825 0-1.5-0.675-1.5-1.5v-1z"></path>
|
||||
<path d="M20 24h-8v-2h2v-6h-2v-2h6v8h2z"></path>
|
||||
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-eye-blocked" viewBox="0 0 32 32">
|
||||
<title>{{ translate('EYE_BLOCKED') }}</title>
|
||||
<path d="M29.561 0.439c-0.586-0.586-1.535-0.586-2.121 0l-6.318 6.318c-1.623-0.492-3.342-0.757-5.122-0.757-6.979 0-13.028 4.064-16 10 1.285 2.566 3.145 4.782 5.407 6.472l-4.968 4.968c-0.586 0.586-0.586 1.535 0 2.121 0.293 0.293 0.677 0.439 1.061 0.439s0.768-0.146 1.061-0.439l27-27c0.586-0.586 0.586-1.536 0-2.121zM13 10c1.32 0 2.44 0.853 2.841 2.037l-3.804 3.804c-1.184-0.401-2.037-1.521-2.037-2.841 0-1.657 1.343-3 3-3zM3.441 16c1.197-1.891 2.79-3.498 4.67-4.697 0.122-0.078 0.246-0.154 0.371-0.228-0.311 0.854-0.482 1.776-0.482 2.737 0 1.715 0.54 3.304 1.459 4.607l-1.904 1.904c-1.639-1.151-3.038-2.621-4.114-4.323z"></path>
|
||||
<path d="M24 13.813c0-0.849-0.133-1.667-0.378-2.434l-10.056 10.056c0.768 0.245 1.586 0.378 2.435 0.378 4.418 0 8-3.582 8-8z"></path>
|
||||
<path d="M25.938 9.062l-2.168 2.168c0.040 0.025 0.079 0.049 0.118 0.074 1.88 1.199 3.473 2.805 4.67 4.697-1.197 1.891-2.79 3.498-4.67 4.697-2.362 1.507-5.090 2.303-7.889 2.303-1.208 0-2.403-0.149-3.561-0.439l-2.403 2.403c1.866 0.671 3.873 1.036 5.964 1.036 6.978 0 13.027-4.064 16-10-1.407-2.81-3.504-5.2-6.062-6.938z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-search" viewBox="0 0 26 28">
|
||||
<title>{{ translate('SEARCH') }}</title>
|
||||
<path d="M18 13c0-3.859-3.141-7-7-7s-7 3.141-7 7 3.141 7 7 7 7-3.141 7-7zM26 26c0 1.094-0.906 2-2 2-0.531 0-1.047-0.219-1.406-0.594l-5.359-5.344c-1.828 1.266-4.016 1.937-6.234 1.937-6.078 0-11-4.922-11-11s4.922-11 11-11 11 4.922 11 11c0 2.219-0.672 4.406-1.937 6.234l5.359 5.359c0.359 0.359 0.578 0.875 0.578 1.406z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-cancel-circle" viewBox="0 0 32 32">
|
||||
<title>{{ translate('CANCEL') }}</title>
|
||||
<path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
|
||||
<path d="M21 8l-5 5-5-5-3 3 5 5-5 5 3 3 5-5 5 5 3-3-5-5 5-5z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-bookmark-o" viewBox="0 0 20 28">
|
||||
<title> translate('BOOKMARK')</title>
|
||||
<path d="M18 4h-16v19.406l8-7.672 1.391 1.328 6.609 6.344v-19.406zM18.188 2c0.234 0 0.469 0.047 0.688 0.141 0.688 0.266 1.125 0.906 1.125 1.609v20.141c0 0.703-0.438 1.344-1.125 1.609-0.219 0.094-0.453 0.125-0.688 0.125-0.484 0-0.938-0.172-1.297-0.5l-6.891-6.625-6.891 6.625c-0.359 0.328-0.812 0.516-1.297 0.516-0.234 0-0.469-0.047-0.688-0.141-0.688-0.266-1.125-0.906-1.125-1.609v-20.141c0-0.703 0.438-1.344 1.125-1.609 0.219-0.094 0.453-0.141 0.688-0.141h16.375z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-user" viewBox="0 0 20 28">
|
||||
<path d="M20 21.859c0 2.281-1.5 4.141-3.328 4.141h-13.344c-1.828 0-3.328-1.859-3.328-4.141 0-4.109 1.016-8.859 5.109-8.859 1.266 1.234 2.984 2 4.891 2s3.625-0.766 4.891-2c4.094 0 5.109 4.75 5.109 8.859zM16 8c0 3.313-2.688 6-6 6s-6-2.688-6-6 2.688-6 6-6 6 2.688 6 6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-group" viewBox="0 0 30 28">
|
||||
<path d="M9.266 14c-1.625 0.047-3.094 0.75-4.141 2h-2.094c-1.563 0-3.031-0.75-3.031-2.484 0-1.266-0.047-5.516 1.937-5.516 0.328 0 1.953 1.328 4.062 1.328 0.719 0 1.406-0.125 2.078-0.359-0.047 0.344-0.078 0.688-0.078 1.031 0 1.422 0.453 2.828 1.266 4zM26 23.953c0 2.531-1.672 4.047-4.172 4.047h-13.656c-2.5 0-4.172-1.516-4.172-4.047 0-3.531 0.828-8.953 5.406-8.953 0.531 0 2.469 2.172 5.594 2.172s5.063-2.172 5.594-2.172c4.578 0 5.406 5.422 5.406 8.953zM10 4c0 2.203-1.797 4-4 4s-4-1.797-4-4 1.797-4 4-4 4 1.797 4 4zM21 10c0 3.313-2.688 6-6 6s-6-2.688-6-6 2.688-6 6-6 6 2.688 6 6zM30 13.516c0 1.734-1.469 2.484-3.031 2.484h-2.094c-1.047-1.25-2.516-1.953-4.141-2 0.812-1.172 1.266-2.578 1.266-4 0-0.344-0.031-0.688-0.078-1.031 0.672 0.234 1.359 0.359 2.078 0.359 2.109 0 3.734-1.328 4.062-1.328 1.984 0 1.937 4.25 1.937 5.516zM28 4c0 2.203-1.797 4-4 4s-4-1.797-4-4 1.797-4 4-4 4 1.797 4 4z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-wrench" viewBox="0 0 26 28">
|
||||
<path d="M6 23c0-0.547-0.453-1-1-1s-1 0.453-1 1 0.453 1 1 1 1-0.453 1-1zM16.063 16.438l-10.656 10.656c-0.359 0.359-0.875 0.578-1.406 0.578s-1.047-0.219-1.422-0.578l-1.656-1.687c-0.375-0.359-0.594-0.875-0.594-1.406s0.219-1.047 0.594-1.422l10.641-10.641c0.812 2.047 2.453 3.687 4.5 4.5zM25.969 9.641c0 0.516-0.187 1.156-0.359 1.656-0.984 2.781-3.656 4.703-6.609 4.703-3.859 0-7-3.141-7-7s3.141-7 7-7c1.141 0 2.625 0.344 3.578 0.984 0.156 0.109 0.25 0.25 0.25 0.438 0 0.172-0.109 0.344-0.25 0.438l-4.578 2.641v3.5l3.016 1.672c0.516-0.297 4.141-2.578 4.453-2.578s0.5 0.234 0.5 0.547z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-plug" viewBox="0 0 28 28">
|
||||
<path d="M27.422 7.078c0.766 0.781 0.766 2.047 0 2.828l-6.266 6.25 2.344 2.344-2.5 2.5c-3.422 3.422-8.641 3.906-12.516 1.344l-5.656 5.656h-2.828v-2.828l5.656-5.656c-2.562-3.875-2.078-9.094 1.344-12.516l2.5-2.5 2.344 2.344 6.25-6.266c0.781-0.766 2.047-0.766 2.828 0 0.781 0.781 0.781 2.063 0 2.828l-6.25 6.266 3.656 3.656 6.266-6.25c0.781-0.781 2.047-0.781 2.828 0z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-paint-brush" viewBox="0 0 28 28">
|
||||
<path d="M25.234 0c1.422 0 2.734 1.062 2.734 2.547 0 0.828-0.328 1.625-0.703 2.359-1.219 2.312-5.313 9.953-7.266 11.75-0.953 0.891-2.078 1.422-3.406 1.422-2.641 0-4.797-2.25-4.797-4.875 0-1.25 0.516-2.469 1.437-3.313l9.969-9.047c0.547-0.5 1.266-0.844 2.031-0.844zM11.031 16.156c0.812 1.578 2.297 2.766 4.016 3.219l0.016 1.109c0.094 4.453-3 7.516-7.469 7.516-5.297 0-7.594-4.219-7.594-9.016 0.578 0.391 2.594 2 3.25 2 0.391 0 0.719-0.219 0.859-0.578 1.328-3.469 3.406-4.094 6.922-4.25z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-enlarge2" viewBox="0 0 32 32">
|
||||
<path d="M32 0v13l-5-5-6 6-3-3 6-6-5-5zM14 21l-6 6 5 5h-13v-13l5 5 6-6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-shrink2" viewBox="0 0 32 32">
|
||||
<path d="M14 18v13l-5-5-6 6-3-3 6-6-5-5zM32 3l-6 6 5 5h-13v-13l5 5 6-6z"></path>
|
||||
</symbol>
|
||||
<symbol id="icon-square-brackets" viewBox="0 0 21 21">
|
||||
<path d="M 4.791 18.885 L 4.791 20.518 L 0 20.518 L 0 0 L 4.791 0 L 4.791 1.622 L 2.052 1.622 L 2.052 18.885 L 4.791 18.885 Z M 20.958 0 L 20.958 20.518 L 16.178 20.518 L 16.178 18.885 L 18.906 18.885 L 18.906 1.622 L 16.178 1.622 L 16.178 0 L 20.958 0 Z M 6.542 4.952 A 1.326 1.326 0 0 0 6.404 5.11 Q 6.102 5.516 6.102 6.166 A 2.167 2.167 0 0 0 6.15 6.638 A 1.453 1.453 0 0 0 6.553 7.38 A 1.472 1.472 0 0 0 7.616 7.82 A 1.702 1.702 0 0 0 7.626 7.82 A 1.445 1.445 0 0 0 8.669 7.385 Q 9.109 6.95 9.109 6.166 A 2.149 2.149 0 0 0 9.058 5.685 A 1.429 1.429 0 0 0 8.658 4.958 A 1.482 1.482 0 0 0 7.595 4.522 Q 6.982 4.522 6.542 4.952 Z M 12.311 4.952 A 1.326 1.326 0 0 0 12.173 5.11 Q 11.87 5.516 11.87 6.166 A 2.167 2.167 0 0 0 11.919 6.638 A 1.453 1.453 0 0 0 12.321 7.38 A 1.472 1.472 0 0 0 13.385 7.82 A 1.702 1.702 0 0 0 13.394 7.82 A 1.445 1.445 0 0 0 14.437 7.385 Q 14.878 6.95 14.878 6.166 A 2.149 2.149 0 0 0 14.827 5.685 A 1.429 1.429 0 0 0 14.427 4.958 A 1.482 1.482 0 0 0 13.363 4.522 Q 12.751 4.522 12.311 4.952 Z M 9.06 14.192 A 1.427 1.427 0 0 0 8.653 13.455 Q 8.196 13.02 7.584 13.02 A 1.442 1.442 0 0 0 6.542 13.449 A 1.326 1.326 0 0 0 6.404 13.607 Q 6.102 14.013 6.102 14.663 A 2.679 2.679 0 0 0 6.102 14.698 Q 6.105 14.959 6.16 15.18 A 1.407 1.407 0 0 0 6.542 15.866 A 1.455 1.455 0 0 0 7.595 16.296 Q 8.207 16.296 8.658 15.866 A 1.405 1.405 0 0 0 9.056 15.154 A 2.131 2.131 0 0 0 9.109 14.663 A 2.134 2.134 0 0 0 9.06 14.192 Z M 14.829 14.192 A 1.427 1.427 0 0 0 14.421 13.455 Q 13.965 13.02 13.353 13.02 A 1.442 1.442 0 0 0 12.311 13.449 A 1.326 1.326 0 0 0 12.173 13.607 Q 11.87 14.013 11.87 14.663 A 2.679 2.679 0 0 0 11.87 14.698 Q 11.874 14.959 11.928 15.18 A 1.407 1.407 0 0 0 12.311 15.866 A 1.455 1.455 0 0 0 13.363 16.296 Q 13.976 16.296 14.427 15.866 A 1.405 1.405 0 0 0 14.825 15.154 A 2.131 2.131 0 0 0 14.878 14.663 A 2.134 2.134 0 0 0 14.829 14.192 Z" />
|
||||
</symbol>
|
||||
{{ assets.renderSvg() }}
|
||||
<defs>
|
||||
</svg>
|
After Width: | Height: | Size: 27 KiB |
14
system/typemill/author/partials/systemNavi.twig
Normal file
14
system/typemill/author/partials/systemNavi.twig
Normal file
@@ -0,0 +1,14 @@
|
||||
<nav id="sidebar-menu" class="sidebar-menu">
|
||||
<div id="mobile-menu" class="menu-action">{{ translate('Menu') }} <span class="button-arrow"></span></div>
|
||||
<ul class="mr-4">
|
||||
|
||||
{% for name,navitem in systemnavi %}
|
||||
<li class="mb-1">
|
||||
<a class="block p-2 border-l-4 border-slate-200 hover:bg-stone-50 hover:border-cyan-500{{ navitem.active ? ' active' : '' }}" href="{{ url_for(navitem.routename) }}">
|
||||
<svg class="icon {{ navitem.icon }} mr-2"><use xlink:href="#{{ navitem.icon }}"></use></svg> {{ translate(name) }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
</ul>
|
||||
</nav>
|
34
system/typemill/author/system/system.twig
Normal file
34
system/typemill/author/system/system.twig
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends 'layouts/layoutSystem.twig' %}
|
||||
{% block title %}{{ translate('System Settings') }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="formWrapper">
|
||||
|
||||
<h1>{{ translate('System') }} </h1>
|
||||
|
||||
<div id="systemsettings" v-cloak>
|
||||
|
||||
<systemsettings :userdata="userdata">${ message }</systemsettings>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script src="{{ base_url() }}/system/typemill/author/js/vue-system.js?v={{ settings.version }}"></script>
|
||||
<script>
|
||||
tmaxios.get('/api/v1/mainnavi',{
|
||||
'csrf_name': document.getElementById("csrf_name").value,
|
||||
'csrf_value': document.getElementById("csrf_value").value,
|
||||
})
|
||||
.then(function (response) {
|
||||
console.info(response);
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.info(error);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
268
system/typemill/author/translations/de.yaml
Normal file
268
system/typemill/author/translations/de.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# German (Deutsche)
|
||||
# Author:
|
||||
ACCOUNT: Account
|
||||
ACTIVE: Aktiv
|
||||
ACTUAL_PASSWORD: Aktuelles Passwort
|
||||
ADD: hinzufügen
|
||||
ADD_CONTENT_BLOCK: + Inhalts-Block
|
||||
ADD_DEFINITION: + Definition
|
||||
ADD_FILE: + Seite
|
||||
ADD_FOLDER: + Ordner
|
||||
ADD_FOLDER_TO_BASE_LEVEL: + Ordner in Basis-Ebene
|
||||
ADD_ITEM: + Element
|
||||
ADD_LEFT_COLUMN: + Linke Spalte
|
||||
ADD_RIGHT_COLUMN: + Rechte Spalte
|
||||
ADD_ROW_ABOVE: + Reihe oberhalb
|
||||
ADD_ROW_BELOW: + Reihe unterhalb
|
||||
ADMINISTRATOR: administrator
|
||||
ALL: All visitors
|
||||
ALL_USERS: Alle Nutzer
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: Alternativ-Text für das Hero-Image
|
||||
ALT_TEXT: Alt-Text
|
||||
AUTHOR: Autor
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): Autoren-Beschreibung (Markdown)
|
||||
BACK_TO_STARTPAGE: Zurück zur Startseite
|
||||
BOLD: fett
|
||||
BOTTOM: Unten
|
||||
BROWSE: WÄHLEN
|
||||
BULLET_LIST: Auflistung
|
||||
BY: von
|
||||
CANCEL: abbrechen
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Kann als Autorenzeile im Frontend benutzt werden.
|
||||
CAPTION: Bild-Unterschrift
|
||||
CELL: Zelle
|
||||
CENTER: Mitte
|
||||
CHECK: prüfen
|
||||
CHOOSE_FILE: Datei wählen
|
||||
CLASS: Class
|
||||
CLOSE_LIBRARY: Medialib schließen
|
||||
CODE: Code
|
||||
COG: Einstellungen
|
||||
CONTENT: Inhalt
|
||||
COPYRIGHT: Copyright
|
||||
CREATED_AT_(READONLY): Erstellt am (nur lesend)
|
||||
CREATED_AT_(READ_ONLY): Erstellt am (nur lesend)
|
||||
CREATE_NEW_USER: + Neuen Nutzer
|
||||
CREATE_USER: + Nutzer
|
||||
CROSS: Kreuz
|
||||
CUSTOM_CSS: Eigenes CSS
|
||||
DEFINITION: Definitions-Liste
|
||||
DEFINITION_LIST: Definitions-Liste
|
||||
DELETE: löschen
|
||||
DELETE_CLOSE: löschen
|
||||
DELETE_COLUMN: Spalte löschen
|
||||
DELETE_CONTENT_BLOCK: Inhaltsblock löschen
|
||||
DELETE_PAGE: Seite löschen
|
||||
DELETE_ROW: Reihe löschen
|
||||
DELETE_USER: Nutzer löschen
|
||||
DESCRIPTION: Beschreibung
|
||||
DISCARD: Verwerfen
|
||||
DISCARD_CHANGES: Änderungen verwerfen
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Soll der Nutzer wirklich gelöscht werden?
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Soll die Seite wirklich gelöscht werden?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Sollen die Änderungen wirklich verworfen und der Inhalt auf den Live-Zustand zurückgesetzt werden?
|
||||
DRAFT: Entwurf
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: Bild hochladen
|
||||
DUTCH__FLEMISH: Dänisch, Flämisch
|
||||
EDIT: editieren
|
||||
EDITOR: editor
|
||||
EDIT_USER: Nutzer bearbeiten
|
||||
ENGLISH: Englisch
|
||||
EXTERNAL_LINK: externer Link
|
||||
E_G_: z.B.
|
||||
E_MAIL: E-Mail
|
||||
FAVICON: Favicon
|
||||
FILE: Datei
|
||||
FILES: Dateien
|
||||
FIRST_NAME: Vorname
|
||||
FOLDER: Ordner
|
||||
FORGOT_PASSWORD: Passwort vergessen
|
||||
FORMAT: Format
|
||||
FRENCH: French
|
||||
GENERAL_PRESENTATION: Generelle Darstellung
|
||||
GERMAN: Deutsch
|
||||
GOOGLE_SITEMAP: Google Sitemap
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Hat Schreib-Rechte für diesen Artikel.
|
||||
HEAD: Kopf
|
||||
HEADLINE: Überschrift
|
||||
HEADLINE_ANCHORS: Überschriften-Anker
|
||||
HERO_IMAGE: Hero Image
|
||||
HIDE: Verbergen
|
||||
HIDE_PAGE_FROM_NAVIGATION: Seite in Navigation verbergen
|
||||
HOME: Home
|
||||
HOMEPAGE: Homepage
|
||||
HORIZONTAL_LINE: Horizontale Linie
|
||||
HR: Horizontale Linie
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: Wenn leer wird die Beschreibung vom Inhalt extrahiert.
|
||||
IMAGE: Bild
|
||||
IMAGES: Bilder
|
||||
IMAGE_URL: Bild URL
|
||||
IMAGE_URL_(READ_ONLY): Bild URL (nur lesend)
|
||||
ITALIAN: Italienisch
|
||||
ITALIC: kursiv
|
||||
LANGUAGE: Sprache
|
||||
LANGUAGE_ADMIN: Sprache (Admin-UI)
|
||||
LANGUAGE_ATTR: Sprach-Attribut (website)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Zuletzt live geändert (nur lesend)
|
||||
LAST_NAME: Zuname
|
||||
LEFT: Links
|
||||
LICENCE: Lizenz
|
||||
LINK: Link
|
||||
LINK_TO_VIDEO: Link zum Video
|
||||
LOGIN: Anmelden
|
||||
LOGO: Logo
|
||||
LOGOUT: Abmelden
|
||||
MANUAL_DATE: Manuelles Datum
|
||||
MARKDOWN: Markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: Die maximale Größe beträgt 5 MB. Hero-Images werden nicht von allen Themes unterstützt.
|
||||
MEMBER: Member
|
||||
MENU: Menü
|
||||
META: Meta
|
||||
META_DESCRIPTION: Meta description
|
||||
META_TITLE: Meta title
|
||||
MISSING_REQUIREMENTS: Fehlende Anforderungen
|
||||
MOVE_VERTICAL: vertikal verschieben
|
||||
NAVIGATION_TITLE: Navigationstitel
|
||||
NEW_PASSWORD: Neues Passwort
|
||||
NONE: Keine
|
||||
NOTICE: Hinweis
|
||||
NOT_EDITABLE: Nicht editierbar
|
||||
NO_DESCRIPTION: Keine Beschreibung
|
||||
NO_PREVIEW: Keine Vorschau
|
||||
NO_SETTINGS: Keine Einstellungen
|
||||
NUMBERED_LIST: Aufzählung
|
||||
OLIST: olist
|
||||
ONLINE: online
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: Nur die folgenden Sonderzeichen sind erlaubt
|
||||
OWNER_(USERNAME): Besitzer (username)
|
||||
PARAGRAPH: Absatz
|
||||
PASSWORD: Passwort
|
||||
PLEASE_CONFIRM: Bitte bestätigen
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Bitte korrigiere die Fehler oben
|
||||
PLUGINS: Plugins
|
||||
PLUGIN_STORE: Plugin Store
|
||||
POWER_OFF: Energie aus
|
||||
PROFILE_IMAGE: Profil-Bild
|
||||
PUBLISH: Publizieren
|
||||
QUOTE: Zitat
|
||||
QUOTES: Zitate
|
||||
RAW: raw
|
||||
RAW_CONTENT_EDITOR: Raw Content Editor
|
||||
RAW_MARKDOWN_EDITOR: Raw Markdown Editor
|
||||
RAW_MODE: Raw Modus
|
||||
RAW_USERDATA_(READONLY_FOR_ADMINS): Raw Nutzerdaten (nur lesend für Admins)
|
||||
READONLY: Nur lesend
|
||||
REGISTERED_USERS_ONLY: Nur registrierte Nutzer
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: Bookmark nicht vergessen
|
||||
REQUIRED: erforderlich
|
||||
RIGHT: Recht
|
||||
ROLE: Rolle
|
||||
RUSSIAN: Russisch
|
||||
SAVE: speichern
|
||||
SAVED_SUCCESSFULLY: Erfolgreich gespeichert
|
||||
SAVE_ALL_SETTINGS: Alle Einstellungen speichern
|
||||
SAVE_THEME: Theme speichern
|
||||
SELECT_FROM_MEDIALIB: Aus Medialib wählen
|
||||
SETTINGS: Einstellungen
|
||||
SETTINGS_ARE_STORED: Einstellungen sind gespeichert
|
||||
SETUP: Setup
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Anker neben Überschrift anzeigen
|
||||
STANDARD_EDITOR_MODE: Standard Editor-Modus
|
||||
START: Start
|
||||
SYSTEM: System
|
||||
TABLE: Tabelle
|
||||
TABLE_OF_CONTENTS: Inhaltsverzeichnis
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Vom Nutzer-Account genommen falls vorhanden.
|
||||
TERM: Bedingung
|
||||
TEXT_FILE: Text-Datei
|
||||
THEMES: Themes
|
||||
THEME_STORE: Theme Store
|
||||
THE_FORMAT_BUTTONS: Die Formatierungs-Buttons
|
||||
TITLE: Titel
|
||||
TOC: IHV
|
||||
TOP: Oben
|
||||
TYPEMILL_DESCRIPTION: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. No JavaScript is used.
|
||||
ULIST: ulist
|
||||
UNKNOWN: Unbekannt
|
||||
UPDATE_USER: Nutzer aktualisieren
|
||||
UPLOAD: hochladen
|
||||
UPLOAD_AN_IMAGE: Bild hochladen
|
||||
UPLOAD_FILE: Datei hochladen
|
||||
UPS__WRONG_PASSWORD_OR_USERNAME__PLEASE_TRY_AGAIN_: Ups, wrong password or username, please try again.
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Wird alternativ zum manuellen Datum genutzt.
|
||||
USER: Nutzer
|
||||
USERNAME: Nutzername
|
||||
USERNAME_(READ_ONLY): Nutzername (nur lesend)
|
||||
USERS: Nutzer
|
||||
USE_2_TO_20_CHARACTERS: 2 bis 20 Anschläge erlaubt.
|
||||
USE_2_TO_40_CHARACTERS: 2 to 40 Anschläge erlaubt.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Gültiges Language Attribut erforderlich.
|
||||
USE_A_VALID_YEAR: Gültiges Jahr erforderlich.
|
||||
VIDEO: Video
|
||||
VIEW_SITE: Zur Webseite
|
||||
VISUAL: visuell
|
||||
VISUAL_CONTENT_EDITOR: Visueller Inhalts-Editor
|
||||
VISUAL_EDITOR: Visueller Editor
|
||||
VISUAL_MARKDOWN_EDITOR: Visueller Markdown Editor
|
||||
VISUAL_MODE: visueller Modus
|
||||
WAIT: warte
|
||||
WEB: Web
|
||||
WEBSITE_TITLE: Webseiten-Titel
|
||||
WEBSITE_VISIBLE_FOR: Website sichtbar für
|
||||
WRITING: Schreiben
|
||||
YEAR: Jahr
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: Du kannst das CSS des Themes hier überschreiben.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Füge mit Plugins neue Funktionen hinzu.
|
||||
BY_THE: von der
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Richte ein Theme für deine Webseite ein.
|
||||
CODED_WITH: Entwickelt mit
|
||||
COMMUNITY: Community
|
||||
CONFIGURE_YOUR_WEBSITE: Zur Autorenoberfläche
|
||||
DOCS: Dokumentation
|
||||
GET_HELP: Hilfe erhalten
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Konfiguriere das System.
|
||||
HURRA: Hurra
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: Wenn du Fragen hast, lies bitte die
|
||||
NEXT_STEP: Nächster Schritt
|
||||
OR_OPEN_A_NEW_ISSUE_ON: oder erstelle ein neues Issue auf
|
||||
SETUP_WELCOME: Setup Willkommen
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Besuche die Autorenoberfläche und richte die Seite ein. Du kannst das System konfigurieren, Themes auswählen and Plugins hinzufügen.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Dein Account wurde erstellt und du bist jetzt angemeldet.
|
||||
|
||||
ACCESS_CONTROL: Access Control
|
||||
ACTIVATE_INDIVIDUAL_RESTRICTIONS_FOR_PAGES_IN_THE_META_TAB_OF_EACH_PAGE_: Aktiviere die individuellen Seiten-Beschränkungen im Meta-Tab einer jeden Seite.
|
||||
ADD_ONE_OR_MORE_USERNAMES_SEPARATED_WITH_COMMA_: Ein oder mehrere Nutzernamen mit Komma getrennt.
|
||||
CUT_RESTRICTED_CONTENT_AFTER_THE_FIRST_HR_ELEMENT_ON_A_PAGE_(PER_DEFAULT_CONTENT_WILL_BE_CUT_AFTER_TITLE)_: Verberge den Inhalt nach dem ersten Trennstrich (andernfalls werden alle Inhalte nach dem Titel verborgen).
|
||||
FOR_ACCESS_THE_USER_MUST_HAVE_THIS_MINIMUM_ROLE: Für einen Zugriff muss der Nutzer diese minimale Rolle haben
|
||||
LIMIT_THE_ACCESS_FOR_THE_WHOLE_WEBSITE_OR_FOR_EACH_PAGE_INDIVIDUALLY__IF_YOU_ACTIVATE_THE_WEBSITE_RESTRICTION_OR_THE_PAGE_RESTRICTIONS__THEN_SESSIONS_WILL_BE_USED_IN_FRONTEND_: Begrenze den Zugriff auf die gesamte Webseite oder für jede Seite individuell. Wenn die Website-Beschränkungen oder die Seiten-Beschränkungen aktiviert werden, dann werden im Frontend Sessions genutzt.
|
||||
ONLY_THE_FOLLOWING_USERS_HAVE_ACCESS: Nur die folgenden Nutzer haben Zugriff
|
||||
PAGE_RESTRICTIONS___ACTIVATE: Seiten-Beschränkungen - Aktivieren
|
||||
PAGE_RESTRICTIONS___CUT_RESTRICTED_CONTENT: Seiten-Beschränkungen - Verberge die Inhalte
|
||||
PAGE_RESTRICTIONS___NOTICE: Seiten-Beschränkungen - Hinweis-Text
|
||||
PAGE_RESTRICTIONS___WRAP_NOTICE_INTO_A_BOX: Seiten-Beschränkungen - Hinweis in Box-Design
|
||||
SELECT_THE_LOWEST_USERROLE__HIGHER_ROLES_WILL_HAVE_ACCESS_TOO_: Wähle die niedrigste Nutzerrolle. Höhere Nutzerrollen haben ebenfalls Zugriff.
|
||||
SHOW_THE_WEBSITE_ONLY_TO_AUTHENTICATED_USERS_AND_REDIRECT_ALL_OTHER_USERS_TO_THE_LOGIN_PAGE_: Zeige die Webseite nur authentifizierten Nutzern und leite alle anderen Nutzer zur Login-Seite um.
|
||||
USE_MARKDOWN: Markdown erlaubt
|
||||
WEBSITE_RESTRICTION: Website Beschränkungen
|
||||
WRAP_THE_RESTRICTION_NOTICE_ABOVE_INTO_A_NOTICE_4_ELEMENT_(WHICH_CAN_BE_DESIGNED_AS_SPECIAL_BOX): Gestalte den Hinweis als Notiz-Box (das Design hängt vom Theme ab)
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Aktiviere den Cache für Twig-Templates
|
||||
ADD_MORE_URL_SCHEMES_FOR_EXTERNAL_LINKS_E_G__LIKE_DICT://_(COMMA_SEPARATED_LIST): URL Schemes für externe Links hinzufügen, z.B. dict:// (mit Komma getrennte Liste)
|
||||
CLEAR_CACHE: Cache reinigen
|
||||
DELETE_ALL_CACHE_FILES: Alle Dateien im Cache löschen
|
||||
DEVELOPER: Entwickler
|
||||
DISABLE_HEADERS: Header deaktivieren
|
||||
DISABLE_TYPEMILL_HEADERS_AND_SEND_YOUR_OWN: Typemill Header deaktivieren und eigene Header senden
|
||||
DISPLAY_APPLICATION_ERRORS: Zeige Fehler-Reports der Applikation
|
||||
ERROR_REPORTING: Fehler-Reports
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: Wenn eine Angabe für die Höhe gemacht wird, wird das Bild ausgeschnitten
|
||||
PROXY: Proxy
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Standard-Höhe für Bilder
|
||||
STANDARD_WIDTH_FOR_IMAGES: Standard-Breite für Bilder
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: Die folgenden Einstellungen sind nur für Entwickler und erfahrene Administratoren. Ändere nur Einstellungen, die du wirklich verstehst. Beispielsweise dürfen niemals die Fehler-Berichte im Frontend dauerhaft aktiviert werden, sondern nur für kurze Fehler-Analysen.
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: Die Einstellung greift nur bei Bildern im Content-Bereich, die in der Zukunft hochgeladen werden.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): Vertrauenswürdige IPs für Proxy (mit Komma getrennte Liste)
|
||||
TWIG_CACHE: Twig Cache
|
||||
USE_X_FORWARDED_HEADERS: Nutze die X-Forwarded Headers
|
268
system/typemill/author/translations/en.yaml
Normal file
268
system/typemill/author/translations/en.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# English
|
||||
# Author: Sebastian Schuermanns
|
||||
ACCOUNT: Account
|
||||
ACTIVE: Active
|
||||
ACTUAL_PASSWORD: Actual Password
|
||||
ADD: add
|
||||
ADD_CONTENT_BLOCK: add content-block
|
||||
ADD_DEFINITION: add definition
|
||||
ADD_FILE: add file
|
||||
ADD_FOLDER: add folder
|
||||
ADD_FOLDER_TO_BASE_LEVEL: add folder to base level
|
||||
ADD_ITEM: add item
|
||||
ADD_LEFT_COLUMN: add left column
|
||||
ADD_RIGHT_COLUMN: add right column
|
||||
ADD_ROW_ABOVE: add row above
|
||||
ADD_ROW_BELOW: add row below
|
||||
ADMINISTRATOR: administrator
|
||||
ALL: all
|
||||
ALL_USERS: all users
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: alternative text for the hero image
|
||||
ALT_TEXT: alt-text
|
||||
AUTHOR: author
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): author-description (markdown)
|
||||
BACK_TO_STARTPAGE: back to startpage
|
||||
BOLD: bold
|
||||
BOTTOM: bottom
|
||||
BROWSE: BROWSE
|
||||
BULLET_LIST: bullet list
|
||||
BY: by
|
||||
CANCEL: cancel
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Can be used for author line in frontend.
|
||||
CAPTION: caption
|
||||
CELL: cell
|
||||
CENTER: center
|
||||
CHECK: check
|
||||
CHOOSE_FILE: choose file
|
||||
CLASS: class
|
||||
CLOSE_LIBRARY: close library
|
||||
CODE: code
|
||||
COG: cog
|
||||
CONTENT: content
|
||||
COPYRIGHT: copyright
|
||||
CREATED_AT_(READONLY): Created at (read only)
|
||||
CREATED_AT_(READ_ONLY): Created at (readonly)
|
||||
CREATE_NEW_USER: Create new user
|
||||
CREATE_USER: Create user
|
||||
CROSS: cross
|
||||
CUSTOM_CSS: Custom CSS
|
||||
DEFINITION: definition list
|
||||
DEFINITION_LIST: definition list
|
||||
DELETE: delete
|
||||
DELETE_CLOSE: delete/close
|
||||
DELETE_COLUMN: delete column
|
||||
DELETE_CONTENT_BLOCK: delete content-block
|
||||
DELETE_PAGE: delete page
|
||||
DELETE_ROW: delete row
|
||||
DELETE_USER: delete user
|
||||
DESCRIPTION: description
|
||||
DISCARD: discard
|
||||
DISCARD_CHANGES: discard changes
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Do you really want to delete the user
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Do you really want to delete this page?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Do you want to discard your changes and set the content back to the live version?
|
||||
DRAFT: draft
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: upload an image
|
||||
DUTCH__FLEMISH: Dutch, Flemish
|
||||
EDIT: edit
|
||||
EDITOR: editor
|
||||
EDIT_USER: edit user
|
||||
ENGLISH: English
|
||||
EXTERNAL_LINK: external-link
|
||||
E_G_: e.g.
|
||||
E_MAIL: e-mail
|
||||
FAVICON: favicon
|
||||
FILE: file
|
||||
FILES: Files
|
||||
FIRST_NAME: first name
|
||||
FOLDER: folder
|
||||
FORGOT_PASSWORD: forgot password
|
||||
FORMAT: format
|
||||
FRENCH: French
|
||||
GENERAL_PRESENTATION: General Presentation
|
||||
GERMAN: German
|
||||
GOOGLE_SITEMAP: google sitemap
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Has edit rights for this article.
|
||||
HEAD: Head
|
||||
HEADLINE: Headline
|
||||
HEADLINE_ANCHORS: Headline anchors
|
||||
HERO_IMAGE: Hero image
|
||||
HIDE: Hide
|
||||
HIDE_PAGE_FROM_NAVIGATION: Hide page from navigation
|
||||
HOME: home
|
||||
HOMEPAGE: Homepage
|
||||
HORIZONTAL_LINE: Horizontal Line
|
||||
HR: hr
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: If not filled, the description is extracted from content.
|
||||
IMAGE: Image
|
||||
IMAGES: Images
|
||||
IMAGE_URL: Image URL
|
||||
IMAGE_URL_(READ_ONLY): Image URL (read only)
|
||||
ITALIAN: Italian
|
||||
ITALIC: italic
|
||||
LANGUAGE: Language
|
||||
LANGUAGE_ADMIN: Language (admin-ui)
|
||||
LANGUAGE_ATTR: Language Attribute (website)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Last modified live (readonly)
|
||||
LAST_NAME: Last Name
|
||||
LEFT: Left
|
||||
LICENCE: Licence
|
||||
LINK: Link
|
||||
LINK_TO_VIDEO: Link to video
|
||||
LOGIN: Login
|
||||
LOGO: Logo
|
||||
LOGOUT: Logout
|
||||
MANUAL_DATE: Manual date
|
||||
MARKDOWN: markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: Maximum size for an image is 5 MB. Hero images are not supported by all themes.
|
||||
MEMBER: member
|
||||
MENU: Menu
|
||||
META: meta
|
||||
META_DESCRIPTION: Meta description
|
||||
META_TITLE: Meta title
|
||||
MISSING_REQUIREMENTS: Missing Requirements
|
||||
MOVE_VERTICAL: move vertical
|
||||
NAVIGATION_TITLE: Navigation Title
|
||||
NEW_PASSWORD: New Password
|
||||
NONE: None
|
||||
NOTICE: Notice
|
||||
NOT_EDITABLE: not editable
|
||||
NO_DESCRIPTION: No description
|
||||
NO_PREVIEW: No Preview
|
||||
NO_SETTINGS: No Settings
|
||||
NUMBERED_LIST: Numbered List
|
||||
OLIST: olist
|
||||
ONLINE: online
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: Only the following special characters are allowed
|
||||
OWNER_(USERNAME): owner (username)
|
||||
PARAGRAPH: Paragraph
|
||||
PASSWORD: Password
|
||||
PLEASE_CONFIRM: Please confirm
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Please correct the errors above
|
||||
PLUGINS: Plugins
|
||||
PLUGIN_STORE: Plugin Store
|
||||
POWER_OFF: power-off
|
||||
PROFILE_IMAGE: Profile-Image
|
||||
PUBLISH: Publish
|
||||
QUOTE: Quote
|
||||
QUOTES: Quote
|
||||
RAW: raw
|
||||
RAW_CONTENT_EDITOR: Raw Content Editor
|
||||
RAW_MARKDOWN_EDITOR: Raw Markdown Editor
|
||||
RAW_MODE: raw mode
|
||||
RAW_USERDATA_(READONLY_FOR_ADMINS): Raw Userdata (readonly for admins)
|
||||
READONLY: Readonly
|
||||
REGISTERED_USERS_ONLY: registered users only
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: Remember to bookmark this page
|
||||
REQUIRED: Required
|
||||
RIGHT: Right
|
||||
ROLE: Role
|
||||
RUSSIAN: Russian
|
||||
SAVE: Save
|
||||
SAVED_SUCCESSFULLY: Saved successfully
|
||||
SAVE_ALL_SETTINGS: Save All Settings
|
||||
SAVE_THEME: Save Theme
|
||||
SELECT_FROM_MEDIALIB: select from medialib
|
||||
SETTINGS: Settings
|
||||
SETTINGS_ARE_STORED: Settings are stored
|
||||
SETUP: Setup
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Show anchors next to headlines
|
||||
STANDARD_EDITOR_MODE: Standard Editor Mode
|
||||
START: Start
|
||||
SYSTEM: System
|
||||
TABLE: Table
|
||||
TABLE_OF_CONTENTS: Table of Contents
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Taken from your user account if set.
|
||||
TERM: term
|
||||
TEXT_FILE: text-file
|
||||
THEMES: Themes
|
||||
THEME_STORE: Theme Store
|
||||
THE_FORMAT_BUTTONS: The Format Buttons
|
||||
TITLE: Title
|
||||
TOC: toc
|
||||
TOP: Top
|
||||
TYPEMILL_DESCRIPTION: The standard theme for Typemill. Responsive, minimal and without any dependencies. It uses the system fonts Calibri and Helvetica. No JavaScript is used.
|
||||
ULIST: ulist
|
||||
UNKNOWN: Unknown
|
||||
UPDATE_USER: Update User
|
||||
UPLOAD: upload
|
||||
UPLOAD_AN_IMAGE: upload an image
|
||||
UPLOAD_FILE: Upload a file
|
||||
UPS__WRONG_PASSWORD_OR_USERNAME__PLEASE_TRY_AGAIN_: Ups, wrong password or username, please try again.
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Used as fallback when no manual date is set.
|
||||
USER: User
|
||||
USERNAME: Username
|
||||
USERNAME_(READ_ONLY): Username (read only)
|
||||
USERS: Users
|
||||
USE_2_TO_20_CHARACTERS: Use 2 to 20 characters.
|
||||
USE_2_TO_40_CHARACTERS: Use 2 to 40 characters.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Use a valid language attribute
|
||||
USE_A_VALID_YEAR: Use a valid year
|
||||
VIDEO: Video
|
||||
VIEW_SITE: View Site
|
||||
VISUAL: visual
|
||||
VISUAL_CONTENT_EDITOR: Visual Content Editor
|
||||
VISUAL_EDITOR: Visual Editor
|
||||
VISUAL_MARKDOWN_EDITOR: Visual Markdown Editor
|
||||
VISUAL_MODE: visual mode
|
||||
WAIT: wait
|
||||
WEB: Web
|
||||
WEBSITE_TITLE: Website Title
|
||||
WEBSITE_VISIBLE_FOR: Website visible for
|
||||
WRITING: Writing
|
||||
YEAR: Year
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: You can overwrite the theme-css with your own css here.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Add new features to your website with plugins and configure them.
|
||||
BY_THE: by the
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Choose a theme for your website and configure the theme details.
|
||||
CODED_WITH: Coded with
|
||||
COMMUNITY: community
|
||||
CONFIGURE_YOUR_WEBSITE: Configure your website
|
||||
DOCS: docs
|
||||
GET_HELP: Get help
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Give your new website a name, add the author and choose a copyright.
|
||||
HURRA: Hurra
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: If you have any questions, please read the
|
||||
NEXT_STEP: Next step
|
||||
OR_OPEN_A_NEW_ISSUE_ON: or open a new issue on
|
||||
SETUP_WELCOME: Setup Welcome
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Visit the author panel and setup your new website. You can configure the system, choose themes and add plugins.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Your account has been created and you are logged in now.
|
||||
|
||||
ACCESS_CONTROL: Access Control
|
||||
ACTIVATE_INDIVIDUAL_RESTRICTIONS_FOR_PAGES_IN_THE_META_TAB_OF_EACH_PAGE_: Activate individual restrictions for pages in the meta-tab of each page.
|
||||
ADD_ONE_OR_MORE_USERNAMES_SEPARATED_WITH_COMMA_: Add one or more usernames separated with comma.
|
||||
CUT_RESTRICTED_CONTENT_AFTER_THE_FIRST_HR_ELEMENT_ON_A_PAGE_(PER_DEFAULT_CONTENT_WILL_BE_CUT_AFTER_TITLE)_: Cut restricted content after the first hr-element on a page (per default content will be cut after title).
|
||||
FOR_ACCESS_THE_USER_MUST_HAVE_THIS_MINIMUM_ROLE: For access the user must have this minimum role
|
||||
LIMIT_THE_ACCESS_FOR_THE_WHOLE_WEBSITE_OR_FOR_EACH_PAGE_INDIVIDUALLY__IF_YOU_ACTIVATE_THE_WEBSITE_RESTRICTION_OR_THE_PAGE_RESTRICTIONS__THEN_SESSIONS_WILL_BE_USED_IN_FRONTEND_: Limit the access for the whole website or for each page individually. If you activate the website restriction or the page restrictions, then sessions will be used in frontend.
|
||||
ONLY_THE_FOLLOWING_USERS_HAVE_ACCESS: Only the following users have access
|
||||
PAGE_RESTRICTIONS___ACTIVATE: Page Restrictions - Activate
|
||||
PAGE_RESTRICTIONS___CUT_RESTRICTED_CONTENT: Page Restrictions - Cut Restricted Content
|
||||
PAGE_RESTRICTIONS___NOTICE: Page Restrictions - Notice
|
||||
PAGE_RESTRICTIONS___WRAP_NOTICE_INTO_A_BOX: Page Restrictions - Wrap Notice into a Box
|
||||
SELECT_THE_LOWEST_USERROLE__HIGHER_ROLES_WILL_HAVE_ACCESS_TOO_: Select the lowest userrole. Higher roles will have access too.
|
||||
SHOW_THE_WEBSITE_ONLY_TO_AUTHENTICATED_USERS_AND_REDIRECT_ALL_OTHER_USERS_TO_THE_LOGIN_PAGE_: Show the website only to authenticated users and redirect all other users to the login page.
|
||||
USE_MARKDOWN: use markdown
|
||||
WEBSITE_RESTRICTION: Website Restriction
|
||||
WRAP_THE_RESTRICTION_NOTICE_ABOVE_INTO_A_NOTICE_4_ELEMENT_(WHICH_CAN_BE_DESIGNED_AS_SPECIAL_BOX): Wrap the restriction notice above into a notice-4 element (which can be designed as special box)
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Activate Cache for Twig Templates
|
||||
ADD_MORE_URL_SCHEMES_FOR_EXTERNAL_LINKS_E_G__LIKE_DICT://_(COMMA_SEPARATED_LIST): Add more url schemes for external links e.g. like dict:// (comma separated list)
|
||||
CLEAR_CACHE: Clear Cache
|
||||
DELETE_ALL_CACHE_FILES: Delete all cache files
|
||||
DEVELOPER: Developer
|
||||
DISABLE_HEADERS: Disable Headers
|
||||
DISABLE_TYPEMILL_HEADERS_AND_SEND_YOUR_OWN: Disable Typemill Headers And Send Your Own
|
||||
DISPLAY_APPLICATION_ERRORS: Display Application Errors
|
||||
ERROR_REPORTING: Error Reporting
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: If you add a value for the height, then the image will be cropped.
|
||||
PROXY: Proxy
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Standard height for images
|
||||
STANDARD_WIDTH_FOR_IMAGES: Standard width for images
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: The following options are only for developers and experienced administrators. Only change the options if you really understand them. For example, never activate the error reporting for a live website, use this option only for bug-fixing.
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: This applies only for future images in the content area.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): Trusted IPs for proxy (comma separated)
|
||||
TWIG_CACHE: Twig Cache
|
||||
USE_X_FORWARDED_HEADERS: Use X-Forwarded Headers
|
268
system/typemill/author/translations/fr.yaml
Normal file
268
system/typemill/author/translations/fr.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# French (Français)
|
||||
# Author:
|
||||
ACCOUNT: Compte
|
||||
ACTIVE: Actif
|
||||
ACTUAL_PASSWORD: Mot de passe actuel
|
||||
ADD: Ajouter
|
||||
ADD_CONTENT_BLOCK: ajouter un bloc
|
||||
ADD_DEFINITION: ajouter une définition
|
||||
ADD_FILE: Ajouter un article
|
||||
ADD_FOLDER: Ajouter un dossier
|
||||
ADD_FOLDER_TO_BASE_LEVEL: Ajouter un dossier de premier niveau
|
||||
ADD_ITEM: Ajouter un élément
|
||||
ADD_LEFT_COLUMN: Ajouter une colonne à gauche
|
||||
ADD_RIGHT_COLUMN: Ajouter une colonne à droite
|
||||
ADD_ROW_ABOVE: Ajouter une rangée en haut
|
||||
ADD_ROW_BELOW: Ajouter une rangée en bas
|
||||
ADMINISTRATOR: administrateur
|
||||
ALL: tous
|
||||
ALL_USERS: Tous les utilisateurs
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: Texte alternatif pour la bannière d'accueil
|
||||
ALT_TEXT: Texte alternatif
|
||||
AUTHOR: Auteur
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): Auteur-Description (Markdown)
|
||||
BACK_TO_STARTPAGE: Revenir à la page d'accueil
|
||||
BOLD: Gras
|
||||
BOTTOM: En bas
|
||||
BROWSE: Parcourir
|
||||
BULLET_LIST: Liste à puces
|
||||
BY: de
|
||||
CANCEL: Annuler
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Sera affiché comme auteur sur le site web.
|
||||
CAPTION: Légende
|
||||
CELL: Cellule
|
||||
CENTER: Center
|
||||
CHECK: Vérifier
|
||||
CHOOSE_FILE: Sélectionner un fichier
|
||||
CLASS: Classe
|
||||
CLOSE_LIBRARY: Fermer la bibliothèque
|
||||
CODE: Code
|
||||
COG: cog
|
||||
CONTENT: Contenu
|
||||
COPYRIGHT: Copyright
|
||||
CREATED_AT_(READONLY): Date de création (lecture seule)
|
||||
CREATED_AT_(READ_ONLY): Date de création (lecture seule)
|
||||
CREATE_NEW_USER: Créer un nouvel utilisateur
|
||||
CREATE_USER: Créer un utilisateur
|
||||
CROSS: croix
|
||||
CUSTOM_CSS: CSS personnalisé
|
||||
DEFINITION: Liste de définition
|
||||
DEFINITION_LIST: Liste de définition
|
||||
DELETE: Supprimer
|
||||
DELETE_CLOSE: Supprimer/Fermer
|
||||
DELETE_COLUMN: Supprimer cette colonne
|
||||
DELETE_CONTENT_BLOCK: Supprimer un bloc
|
||||
DELETE_PAGE: Supprimer la page
|
||||
DELETE_ROW: Supprimer une rangée
|
||||
DELETE_USER: Supprimer l'utilisateur
|
||||
DESCRIPTION: Description
|
||||
DISCARD: Annuler les modifications
|
||||
DISCARD_CHANGES: Ne pas sauvegarder les modifications
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Voulez-vous vraiment supprimer cet utilisateur ?
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Voulez-vous vraiment supprimer cette page ?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Voulez-vous annuler les modifications et revenir à la version précédente ?
|
||||
DRAFT: comme brouillon
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: faire glisser une image ou cliquer pour sélectionner
|
||||
DUTCH__FLEMISH: Néerlandais, Flamand
|
||||
EDIT: Éditer
|
||||
EDITOR: editor
|
||||
EDIT_USER: Modifier l'utilisateur
|
||||
ENGLISH: Anglais
|
||||
EXTERNAL_LINK: Lien externe
|
||||
E_G_: ex.:
|
||||
E_MAIL: Courriel
|
||||
FAVICON: Favicon
|
||||
FILE: Fichier
|
||||
FILES: Fichiers
|
||||
FIRST_NAME: Nom
|
||||
FOLDER: Dossier
|
||||
FORGOT_PASSWORD: Mot de passe oublié
|
||||
FORMAT: Mise en forme
|
||||
FRENCH: Français
|
||||
GENERAL_PRESENTATION: Presentation générale
|
||||
GERMAN: Allemand
|
||||
GOOGLE_SITEMAP: Google Sitemap
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Possède les droits d'édition sur cette article.
|
||||
HEAD: Tête de colonne
|
||||
HEADLINE: Titre
|
||||
HEADLINE_ANCHORS: Ancres de titre
|
||||
HERO_IMAGE: Bannière d'accueil (Hero image)
|
||||
HIDE: Masquer
|
||||
HIDE_PAGE_FROM_NAVIGATION: Masquer dans le menu de navigation du site
|
||||
HOME: Accueil
|
||||
HOMEPAGE: Page d'accueil
|
||||
HORIZONTAL_LINE: Ligne horizontale
|
||||
HR: Ligne horizontale
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: Si non renseignée ici, la description est extraite du contenu.
|
||||
IMAGE: Image
|
||||
IMAGES: Images
|
||||
IMAGE_URL: URL de l'image
|
||||
IMAGE_URL_(READ_ONLY): URL de l'image (lecture seule)
|
||||
ITALIAN: Italien
|
||||
ITALIC: Italique
|
||||
LANGUAGE: Langue
|
||||
LANGUAGE_ADMIN: Langue de l'interface d'administration
|
||||
LANGUAGE_ATTR: Langue du site (website)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Dernière modification (lecture seule)
|
||||
LAST_NAME: Prénom
|
||||
LEFT: Gauche
|
||||
LICENCE: Licence
|
||||
LINK: Lien
|
||||
LINK_TO_VIDEO: Lien vers une vidéo
|
||||
LOGIN: Connexion
|
||||
LOGO: Logo
|
||||
LOGOUT: Déconnexion
|
||||
MANUAL_DATE: Date manuelle
|
||||
MARKDOWN: Markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: La taille maximale pour une image est 5 Mo. Les bannières d'accueil ne sont pas gérées dans tous les thèmes.
|
||||
MEMBER: membre
|
||||
MENU: Menu
|
||||
META: Métadonnées
|
||||
META_DESCRIPTION: Meta description
|
||||
META_TITLE: Meta titre
|
||||
MISSING_REQUIREMENTS: Prérequis non satisfaits
|
||||
MOVE_VERTICAL: Déplacer verticalement
|
||||
NAVIGATION_TITLE: Titre dans le menu de navigation
|
||||
NEW_PASSWORD: Nouveau mot de passe
|
||||
NONE: Aucune
|
||||
NOTICE: Note
|
||||
NOT_EDITABLE: Non modifiable
|
||||
NO_DESCRIPTION: Aucune description
|
||||
NO_PREVIEW: Pas de prévisualisation
|
||||
NO_SETTINGS: Aucun paramètre
|
||||
NUMBERED_LIST: Liste numérotée
|
||||
OLIST: Liste ordonnée
|
||||
ONLINE: Online
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: Seuls sont autorisés les caractères spéciaux suivants
|
||||
OWNER_(USERNAME): propriétaire (nom d'utilisateur)
|
||||
PARAGRAPH: Paragraphe
|
||||
PASSWORD: Mot de passe
|
||||
PLEASE_CONFIRM: Confirmer
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Veuillez corriger les erreurs ci-dessus
|
||||
PLUGINS: Plugins
|
||||
PLUGIN_STORE: Dépôt des plugins
|
||||
POWER_OFF: Éteindre
|
||||
PROFILE_IMAGE: Image du Profil
|
||||
PUBLISH: Publier
|
||||
QUOTE: Citation
|
||||
QUOTES: Citations
|
||||
RAW: Texte brut
|
||||
RAW_CONTENT_EDITOR: Editeur de contenu brut
|
||||
RAW_MARKDOWN_EDITOR: Editeur Markdown brut
|
||||
RAW_MODE: Mode texte brut
|
||||
RAW_USERDATA_(READONLY_FOR_ADMINS): Données utilisateur brutes (lecture seule pour les administrateurs)
|
||||
READONLY: Lecture seule
|
||||
REGISTERED_USERS_ONLY: réservé aux utilisateurs enregistrés
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: Pensez à marquer cette page
|
||||
REQUIRED: Requis
|
||||
RIGHT: Droit
|
||||
ROLE: Rôle
|
||||
RUSSIAN: Russe
|
||||
SAVE: Enregistrer
|
||||
SAVED_SUCCESSFULLY: Enregistré avec succès
|
||||
SAVE_ALL_SETTINGS: Sauvegarder tous les paramètres
|
||||
SAVE_THEME: Enregistrer et activer ce thème
|
||||
SELECT_FROM_MEDIALIB: Sélectionner dans la bibliothèque de médias
|
||||
SETTINGS: Paramètres
|
||||
SETTINGS_ARE_STORED: Les paramètres sont mis en mémoire
|
||||
SETUP: Configuration
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Afficher les ancres à coté des titres
|
||||
STANDARD_EDITOR_MODE: Mode éditeur standard
|
||||
START: Démarrer
|
||||
SYSTEM: Système
|
||||
TABLE: Tableau
|
||||
TABLE_OF_CONTENTS: Sommaire
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Si non renseigné ici, le nom est tiré du compte utilisateur courant.
|
||||
TERM: Terme
|
||||
TEXT_FILE: Fichier texte
|
||||
THEMES: Thèmes
|
||||
THEME_STORE: Dépôt des thèmes
|
||||
THE_FORMAT_BUTTONS: Boutons de mise en forme
|
||||
TITLE: Titre
|
||||
TOC: Sommaire
|
||||
TOP: En haut
|
||||
TYPEMILL_DESCRIPTION: Le thème standard pour Typemill. Responsive, minimal et sans aucune dépendance. Il emploie les polices système Calibri et Helvetica. Pas de javascript utilisé.
|
||||
ULIST: Liste simple
|
||||
UNKNOWN: Inconnu
|
||||
UPDATE_USER: Mettre à jour l'utilisateur
|
||||
UPLOAD: Télécharger
|
||||
UPLOAD_AN_IMAGE: Télécharger une image
|
||||
UPLOAD_FILE: Télécharger un fichier
|
||||
UPS__WRONG_PASSWORD_OR_USERNAME__PLEASE_TRY_AGAIN_: Oups, mot de passe ou nom d'utilisateur incorrect, veuillez réessayer.
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Utilisée si aucune date manuelle n'est définie.
|
||||
USER: Utilisateur
|
||||
USERNAME: Nom de l'utilisateur
|
||||
USERNAME_(READ_ONLY): Nom de l'utilisateur (lecture seule)
|
||||
USERS: Utilisateurs
|
||||
USE_2_TO_20_CHARACTERS: Vous devez saisir au moins 2 caractères et au maximum 20.
|
||||
USE_2_TO_40_CHARACTERS: Vous devez saisir au moins 2 caractères et au maximum 40.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Veuillez indiquer un attribut de langue valide
|
||||
USE_A_VALID_YEAR: Entrez une année valide
|
||||
VIDEO: Vidéo
|
||||
VIEW_SITE: Voir le site
|
||||
VISUAL: Visuel
|
||||
VISUAL_CONTENT_EDITOR: Editeur visuel de contenu
|
||||
VISUAL_EDITOR: Editeur visuel
|
||||
VISUAL_MARKDOWN_EDITOR: Editeur visuel Markdown
|
||||
VISUAL_MODE: Mode visuel
|
||||
WAIT: Attendez
|
||||
WEB: Site
|
||||
WEBSITE_TITLE: Titre du site
|
||||
WEBSITE_VISIBLE_FOR: Site visible pour
|
||||
WRITING: Rédaction
|
||||
YEAR: Année
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: Vous pouvez surcharger ici le css du thème avec vos propres styles.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Ajoutez de nouvelles fonctionnalités à votre site grâce aux plugins et configurez-les.
|
||||
BY_THE: par la
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Choisissez un thème pour votre site et configurez les details du thème.
|
||||
CODED_WITH: Codé avec
|
||||
COMMUNITY: Communauté
|
||||
CONFIGURE_YOUR_WEBSITE: Configurez votre site
|
||||
DOCS: documentation
|
||||
GET_HELP: Obtenir de l'aide
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Donnez un nom à votre nouveau site, ajouter un auteur et choisissez un copyright.
|
||||
HURRA: Hourrah
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: Pour toutes questions, veuillez consulter la
|
||||
NEXT_STEP: Prochaine étape
|
||||
OR_OPEN_A_NEW_ISSUE_ON: ou ouvrir un nouveau bug sur
|
||||
SETUP_WELCOME: Bienvenue dans l'installation
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Visitez le volet Auteur et configurez votre nouveau site. Vous pouvez paramétrer le système, choisir un thème et ajouter des plugins.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Votre compte a été créé et vous êtes maintenant connecté
|
||||
|
||||
ACCESS_CONTROL: Contrôle d'accès
|
||||
ACTIVATE_INDIVIDUAL_RESTRICTIONS_FOR_PAGES_IN_THE_META_TAB_OF_EACH_PAGE_: Activer les restrictions par page dans l'onglet Métadonnées de chaque page.
|
||||
ADD_ONE_OR_MORE_USERNAMES_SEPARATED_WITH_COMMA_: Ajouter un ou plusieurs noms séparés par une virgule.
|
||||
CUT_RESTRICTED_CONTENT_AFTER_THE_FIRST_HR_ELEMENT_ON_A_PAGE_(PER_DEFAULT_CONTENT_WILL_BE_CUT_AFTER_TITLE)_: Couper le contenu restreint après le premier élément hr de la page (par défaut, le contenu sera coupé après le titre).
|
||||
FOR_ACCESS_THE_USER_MUST_HAVE_THIS_MINIMUM_ROLE: Pour accéder l'utlisateur doit avoir au moins le rôle minimal.
|
||||
LIMIT_THE_ACCESS_FOR_THE_WHOLE_WEBSITE_OR_FOR_EACH_PAGE_INDIVIDUALLY__IF_YOU_ACTIVATE_THE_WEBSITE_RESTRICTION_OR_THE_PAGE_RESTRICTIONS__THEN_SESSIONS_WILL_BE_USED_IN_FRONTEND_: Limitez l'accès pour la totalité du site ou pour chaque page séparément. Si vous activez la restriction globale ou par page, les sessions seront utilisées en frontend.
|
||||
ONLY_THE_FOLLOWING_USERS_HAVE_ACCESS: Seuls les utilisateurs suivants ont accès
|
||||
PAGE_RESTRICTIONS___ACTIVATE: Restrictions par page - Activer
|
||||
PAGE_RESTRICTIONS___CUT_RESTRICTED_CONTENT: Restrictions par page - Retirer le contenu restreint
|
||||
PAGE_RESTRICTIONS___NOTICE: Restrictions par page - Avis
|
||||
PAGE_RESTRICTIONS___WRAP_NOTICE_INTO_A_BOX: Restrictions par page - Insérer la note dans une box
|
||||
SELECT_THE_LOWEST_USERROLE__HIGHER_ROLES_WILL_HAVE_ACCESS_TOO_: Selectionner le rôle minimal. Les rôles plus élevés accèderont également.
|
||||
SHOW_THE_WEBSITE_ONLY_TO_AUTHENTICATED_USERS_AND_REDIRECT_ALL_OTHER_USERS_TO_THE_LOGIN_PAGE_: Afficher le site uniquement pour les utilisateurs authentifiés et rediriger tous les autres vers la page de login.
|
||||
USE_MARKDOWN: Utiliser le markdown
|
||||
WEBSITE_RESTRICTION: Restriction sur le site
|
||||
WRAP_THE_RESTRICTION_NOTICE_ABOVE_INTO_A_NOTICE_4_ELEMENT_(WHICH_CAN_BE_DESIGNED_AS_SPECIAL_BOX): Insérer l'avis de restriction ci-dessus dans un élément notice-4 (qui peut être conçu comme special box)
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Activer le cache pour les templates Twig
|
||||
ADD_MORE_URL_SCHEMES_FOR_EXTERNAL_LINKS_E_G__LIKE_DICT://_(COMMA_SEPARATED_LIST): "Ajouter d'autres schémas d'url pour les liens externes. ex: dict:// (liste séparée par des virgules)"
|
||||
CLEAR_CACHE: Vider le cache
|
||||
DELETE_ALL_CACHE_FILES: Vider tous les fichiers de cache
|
||||
DEVELOPER: Développeur
|
||||
DISABLE_HEADERS: Désactiver les entêtes
|
||||
DISABLE_TYPEMILL_HEADERS_AND_SEND_YOUR_OWN: Désactiver les entêtes de Typemill et envoyer le vôtre
|
||||
DISPLAY_APPLICATION_ERRORS: Afficher les erreurs de l'application
|
||||
ERROR_REPORTING: Rapport d'erreur
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: Si vous ajoutez une valeur pour la hauteur, l'image sera recadrée.
|
||||
PROXY: Proxy
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Hauteur standard pour les images
|
||||
STANDARD_WIDTH_FOR_IMAGES: Largeur standard pour les images
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: Les options suivantes sont destinés uniquement aux développeurs et administrateurs expérimentés. Ne les modifiez que si vous les comprenez vraiment. Par exemple, n'activez jamais un rapport d'erreur sur un site en production. Ne l'utilisez que pour une résolution de bug.
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: Ceci s'applique seulement aux futures images qui seront stockées dans la zone de contenu.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): IPs de confiance pour le proxy (séparateur virgule)
|
||||
TWIG_CACHE: Cache Twig
|
||||
USE_X_FORWARDED_HEADERS: Utiliser des entêtes X-Forwarded
|
246
system/typemill/author/translations/it.yaml
Normal file
246
system/typemill/author/translations/it.yaml
Normal file
@@ -0,0 +1,246 @@
|
||||
# Italian (Italiano) pls ignore autoupdates
|
||||
# Author: Severo Iuliano (https://github.com/iusvar)
|
||||
ACCOUNT: Utenza
|
||||
ACTIVE: Attivo
|
||||
ACTUAL_PASSWORD: Parola d'ordine corrente
|
||||
ADD: aggiungi
|
||||
ADD_CONTENT_BLOCK: aggiungi blocco contenuto
|
||||
ADD_DEFINITION: aggiungi definizione
|
||||
ADD_FILE: aggiungi file
|
||||
ADD_FOLDER: aggiungi cartella
|
||||
ADD_FOLDER_TO_BASE_LEVEL: aggiungi cartella al livello base
|
||||
ADD_ITEM: aggiungi articolo
|
||||
ADD_LEFT_COLUMN: aggiungi colonna a sinistra
|
||||
ADD_RIGHT_COLUMN: aggiungi colonna a destra
|
||||
ADD_ROW_ABOVE: aggiungi la riga sopra
|
||||
ADD_ROW_BELOW: aggiungi la riga sotto
|
||||
ADMINISTRATOR: administrator
|
||||
ALL: All visitors
|
||||
ALL_USERS: Tutti gli utenti
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: Testo alternativo per l'immagine hero
|
||||
ALT_TEXT: Testo alternativo
|
||||
AUTHOR: Autore
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): Author-Description (Markdown)
|
||||
BACK_TO_STARTPAGE: torna alla pagina iniziale
|
||||
BOLD: grassetto
|
||||
BOTTOM: Sotto
|
||||
BROWSE: Sfoglia
|
||||
BULLET_LIST: Elenco puntato
|
||||
BY: di
|
||||
CANCEL: Annulla
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Can be used for author line in frontend.
|
||||
CAPTION: Didascalia
|
||||
CELL: cella
|
||||
CENTER: Centro
|
||||
CHECK: controllo
|
||||
CHOOSE_FILE: Scegli il file
|
||||
CLASS: Classe
|
||||
CLOSE_LIBRARY: Chiudi libreria
|
||||
CODE: Codice
|
||||
COG: ingranaggio
|
||||
CONTENT: Contenuto
|
||||
COPYRIGHT: Diritti d'autore
|
||||
CREATED_AT_(READONLY): Created at (read only)
|
||||
CREATED_AT_(READ_ONLY): Created at (readonly)
|
||||
CREATE_NEW_USER: Crea nuovo utente
|
||||
CREATE_USER: Crea utente
|
||||
CROSS: croce
|
||||
CUSTOM_CSS: CSS personalizzato
|
||||
DEFINITION: Elenco delle definizioni
|
||||
DEFINITION_LIST: Elenco delle definizioni
|
||||
DELETE: elimina
|
||||
DELETE_CLOSE: elimina/chiudi
|
||||
DELETE_COLUMN: elimina colonna
|
||||
DELETE_CONTENT_BLOCK: elimina blocco contenuto
|
||||
DELETE_PAGE: Elimina pagina
|
||||
DELETE_ROW: elimina riga
|
||||
DELETE_USER: Elimina utente
|
||||
DESCRIPTION: descrizione
|
||||
DISCARD: Scarta
|
||||
DISCARD_CHANGES: Non salvare le modifiche
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Vuoi veramente eliminare l'utente
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Vuoi veramente cancellare questa pagina?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Vuoi annullare le modifiche e ripristinare i contenuti alla versione precedente?
|
||||
DRAFT: Bozza
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: trascina un'immagine o fai clic per selezionare
|
||||
DUTCH__FLEMISH: Olandese, Fiammingo
|
||||
EDIT: modifica
|
||||
EDITOR: editor
|
||||
EDIT_USER: Modifica utente
|
||||
ENGLISH: Inglese
|
||||
EXTERNAL_LINK: collegamento esterno
|
||||
E_G_: per es.:
|
||||
E_MAIL: Posta elettronica
|
||||
FAVICON: Favicon
|
||||
FILE: Archivio
|
||||
FILES: Archivi
|
||||
FIRST_NAME: Nome
|
||||
FOLDER: cartella
|
||||
FORGOT_PASSWORD: Parola d'ordine dimenticata
|
||||
FORMAT: Format
|
||||
FRENCH: French
|
||||
GENERAL_PRESENTATION: Presentazione generale
|
||||
GERMAN: Tedesco
|
||||
GOOGLE_SITEMAP: Sitemap di Google
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Has edit rights for this article.
|
||||
HEAD: Intestazione
|
||||
HEADLINE: Titolo
|
||||
HEADLINE_ANCHORS: Ancoraggi del titolo
|
||||
HERO_IMAGE: Immagine Hero
|
||||
HIDE: Nascondi
|
||||
HIDE_PAGE_FROM_NAVIGATION: Nasconde la pagina dalla navigazione
|
||||
HOME: home
|
||||
HOMEPAGE: Homepage
|
||||
HORIZONTAL_LINE: Linea orizzontale
|
||||
HR: Linea orizzontale
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: Se non compilato, la descrizione viene estratta dal contenuto.
|
||||
IMAGE: Immagine
|
||||
IMAGES: Immagini
|
||||
IMAGE_URL: Image URL
|
||||
IMAGE_URL_(READ_ONLY): Image URL (read only)
|
||||
ITALIAN: Italiano
|
||||
ITALIC: corsivo
|
||||
LANGUAGE: Lingua
|
||||
LANGUAGE_ADMIN: Lingua (admin-ui)
|
||||
LANGUAGE_ATTR: Attributo Lingua (sito)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Last modified live (readonly)
|
||||
LAST_NAME: Cognome
|
||||
LEFT: Sinistra
|
||||
LICENCE: Licenza
|
||||
LINK: Collegamento
|
||||
LINK_TO_VIDEO: Collega al video
|
||||
LOGIN: Accesso
|
||||
LOGO: Logo
|
||||
LOGOUT: Esci
|
||||
MANUAL_DATE: Data manuale
|
||||
MARKDOWN: Markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: La dimensione massima per un'immagine è di 5 MB. Le immagini hero non sono supportate da tutti i temi.
|
||||
MEMBER: member
|
||||
MENU: Menu
|
||||
META: Metadati
|
||||
META_DESCRIPTION: Descrizione
|
||||
META_TITLE: Titolo
|
||||
MISSING_REQUIREMENTS: Requisiti mancanti
|
||||
MOVE_VERTICAL: spostare in verticale
|
||||
NAVIGATION_TITLE: Titolo di navigazione
|
||||
NEW_PASSWORD: Nuova parola d'ordine
|
||||
NONE: Nessuna
|
||||
NOTICE: Avviso
|
||||
NOT_EDITABLE: non modificabile
|
||||
NO_DESCRIPTION: Nessuna descrizione
|
||||
NO_PREVIEW: Nessuna anteprima
|
||||
NO_SETTINGS: Nessuna impostazione
|
||||
NUMBERED_LIST: Elenco numerato
|
||||
OLIST: Elenchi ordinati
|
||||
ONLINE: in linea
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: Sono ammessi solo i seguenti caratteri speciali:
|
||||
OWNER_(USERNAME): owner (username)
|
||||
PARAGRAPH: Paragrafo
|
||||
PASSWORD: Parola d'ordine
|
||||
PLEASE_CONFIRM: Per favore conferma
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Si prega di correggere gli errori sopra
|
||||
PLUGINS: Plugin
|
||||
PLUGIN_STORE: Deposito plugin
|
||||
POWER_OFF: spegni
|
||||
PROFILE_IMAGE: Profile image
|
||||
PUBLISH: Pubblica
|
||||
QUOTE: Citazione
|
||||
QUOTES: Citazione
|
||||
RAW: grezzo
|
||||
RAW_CONTENT_EDITOR: Editore contenuto grezzo
|
||||
RAW_MARKDOWN_EDITOR: Editore grezzo Markdown
|
||||
RAW_MODE: modo grezzo
|
||||
READONLY: Sola lettura
|
||||
REGISTERED_USERS_ONLY: Registered users only
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: Ricorda di aggiungere questa pagina ai segnalibri
|
||||
REQUIRED: Richiesto
|
||||
RIGHT: Destra
|
||||
ROLE: Ruolo
|
||||
RUSSIAN: Russo
|
||||
SAVE: Salva
|
||||
SAVED_SUCCESSFULLY: Salvato con successo
|
||||
SAVE_ALL_SETTINGS: Salva tutte le impostazioni
|
||||
SAVE_THEME: Salva tema
|
||||
SELECT_FROM_MEDIALIB: seleziona da medialib
|
||||
SETTINGS: Impostazioni
|
||||
SETTINGS_ARE_STORED: Le impostazioni sono memorizzate
|
||||
SETUP: Configurazione
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Mostra le ancore accanto ai titoli
|
||||
STANDARD_EDITOR_MODE: Modalità editore standard
|
||||
START: Comincia
|
||||
SYSTEM: Sistema
|
||||
TABLE: Tabella
|
||||
TABLE_OF_CONTENTS: Sommario
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Tratto dalla tua utenza, se impostata.
|
||||
TERM: termine
|
||||
TEXT_FILE: file di testo
|
||||
THEMES: Temi
|
||||
THEME_STORE: Deposito temi
|
||||
THE_FORMAT_BUTTONS: pulsanti di formattazione
|
||||
TITLE: Titolo
|
||||
TOC: Sommario
|
||||
TOP: Sopra
|
||||
TYPEMILL_DESCRIPTION: Il tema standard per Typemill. Reattivo, minimo e senza dipendenze. Utilizza i caratteri di sistema Calibri ed Helvetica. Non viene utilizzato JavaScript.
|
||||
ULIST: Elenchi non ordinati
|
||||
UNKNOWN: Ignoto
|
||||
UPDATE_USER: Aggiorna utente
|
||||
UPLOAD: carica
|
||||
UPLOAD_AN_IMAGE: carica un'immagine
|
||||
UPLOAD_FILE: Carica un file
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Utilizzato come ripiego quando non è impostata alcuna data manuale.
|
||||
USER: Utente
|
||||
USERNAME: Nome utente
|
||||
USERNAME_(READ_ONLY): Username (read only)
|
||||
USERS: Utenti
|
||||
USE_2_TO_20_CHARACTERS: Usa da 2 a 20 caratteri.
|
||||
USE_2_TO_40_CHARACTERS: Usa da 2 a 40 caratteri.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Use a valid language attribute
|
||||
USE_A_VALID_YEAR: Usa un anno valido
|
||||
VIDEO: Video
|
||||
VIEW_SITE: Mostra sito
|
||||
VISUAL: visivo
|
||||
VISUAL_CONTENT_EDITOR: Editore contenuto visivo
|
||||
VISUAL_EDITOR: Editore visivo
|
||||
VISUAL_MARKDOWN_EDITOR: Editore visivo Markdown
|
||||
VISUAL_MODE: modo visivo
|
||||
WAIT: aspetta
|
||||
WEB: Sito
|
||||
WEBSITE_TITLE: Titolo del sito
|
||||
WEBSITE_VISIBLE_FOR: Website visible for
|
||||
WRITING: Scrittura
|
||||
YEAR: Anno
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: È possibile sovrascrivere il css del tema con il proprio CSS qui.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Aggiungi nuove funzionalità al tuo sito mediante plugin e configurali.
|
||||
BY_THE: dalla
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Scegli un tema per il tuo sito e configura i dettagli del tema.
|
||||
CODED_WITH: Codificato con
|
||||
COMMUNITY: comunità
|
||||
CONFIGURE_YOUR_WEBSITE: Configura il tuo sito
|
||||
DOCS: documentazione
|
||||
GET_HELP: Chiedi aiuto
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Dai un nome al tuo nuovo sito, aggiungi l'autore e scegli un diritto d'autore.
|
||||
HURRA: Evviva
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: In caso di domande, si prega di leggere la
|
||||
NEXT_STEP: Prossimo passo
|
||||
OR_OPEN_A_NEW_ISSUE_ON: o aprire un nuovo problema su
|
||||
SETUP_WELCOME: Benvenuto all'installazione
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Visita il pannello autore e configura il tuo nuovo sito. Puoi configurare il sistema, scegliere i temi e aggiungere plugin.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Il tuo account è stato creato e ora sei connesso.
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Attiva la cache per i modelli Twig
|
||||
CLEAR_CACHE: Cancella cache
|
||||
DELETE_ALL_CACHE_FILES: Elimina tutti i file della cache
|
||||
DEVELOPER: Sviluppatore
|
||||
DISPLAY_APPLICATION_ERRORS: Visualizza errori dell'applicazione
|
||||
ERROR_REPORTING: Segnalazione errori
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: Se aggiungi un valore per l'altezza, l'immagine verrà ritagliata.
|
||||
PROXY: Proxy
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Altezza standard per le immagini
|
||||
STANDARD_WIDTH_FOR_IMAGES: Larghezza standard per le immagini
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: "Le seguenti opzioni sono solo per sviluppatori e amministratori esperti. Cambia le opzioni solo se le capisci davvero. Ad esempio: non attivare mai la segnalazione degli errori per un sito Web live, utilizzare questa opzione solo per la correzione dei bug."
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: Questo vale solo per le immagini future nell'area del contenuto.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): IP affidabili per proxy (separati da virgole)
|
||||
TWIG_CACHE: Twig Cache
|
||||
USE_X_FORWARDED_HEADERS: Usa intestazioni con X-Forwarded
|
268
system/typemill/author/translations/nl.yaml
Normal file
268
system/typemill/author/translations/nl.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# Dutch (Nederlands)
|
||||
# Author:
|
||||
ACCOUNT: Account
|
||||
ACTIVE: Actief
|
||||
ACTUAL_PASSWORD: Actueel wachtwoord
|
||||
ADD: toevoegen
|
||||
ADD_CONTENT_BLOCK: inhoudblok toevoegen
|
||||
ADD_DEFINITION: definitie toevoegen
|
||||
ADD_FILE: Bestand toevoegen
|
||||
ADD_FOLDER: Map toevoegen
|
||||
ADD_FOLDER_TO_BASE_LEVEL: map toevoegen op basisniveau
|
||||
ADD_ITEM: Item toevoegen
|
||||
ADD_LEFT_COLUMN: linkerkolom toevoegen
|
||||
ADD_RIGHT_COLUMN: rechter kolom toevoegen
|
||||
ADD_ROW_ABOVE: rij boven toevoegen
|
||||
ADD_ROW_BELOW: rij hieronder toevoegen
|
||||
ADMINISTRATOR: administrator
|
||||
ALL: All visitors
|
||||
ALL_USERS: Alle gebruikers
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: Alternative Text for the hero image
|
||||
ALT_TEXT: Alt-tekst
|
||||
AUTHOR: Auteur
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): Author-Description (Markdown)
|
||||
BACK_TO_STARTPAGE: terug naar startpagina
|
||||
BOLD: vetgedrukt
|
||||
BOTTOM: bodem
|
||||
BROWSE: BROWSE
|
||||
BULLET_LIST: Lijst met opsommingstekens
|
||||
BY: door
|
||||
CANCEL: annuleren
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Can be used for author line in frontend.
|
||||
CAPTION: Bijschrift
|
||||
CELL: cel
|
||||
CENTER: Midden
|
||||
CHECK: check
|
||||
CHOOSE_FILE: Choose file
|
||||
CLASS: Class
|
||||
CLOSE_LIBRARY: Close Library
|
||||
CODE: Code
|
||||
COG: tandwiel
|
||||
CONTENT: Inhoud
|
||||
COPYRIGHT: Auteursrecht
|
||||
CREATED_AT_(READONLY): Created at (read only)
|
||||
CREATED_AT_(READ_ONLY): Created at (readonly)
|
||||
CREATE_NEW_USER: Nieuwe gebruiker maken
|
||||
CREATE_USER: Gebruiker maken
|
||||
CROSS: kruis
|
||||
CUSTOM_CSS: Custom CSS
|
||||
DEFINITION: Definitielijst
|
||||
DEFINITION_LIST: Definitielijst
|
||||
DELETE: verwijderen
|
||||
DELETE_CLOSE: verwijderen / sluiten
|
||||
DELETE_COLUMN: kolom verwijderen
|
||||
DELETE_CONTENT_BLOCK: content-block verwijderen
|
||||
DELETE_PAGE: pagina verwijderen
|
||||
DELETE_ROW: rij verwijderen
|
||||
DELETE_USER: Gebruiker verwijderen
|
||||
DESCRIPTION: omschrijving
|
||||
DISCARD: weggooien
|
||||
DISCARD_CHANGES: Wijzigingen negeren
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Wilt u de gebruiker echt verwijderen
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Wilt u deze pagina echt verwijderen?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Wilt u uw wijzigingen annuleren en de inhoud terugzetten naar de live versie?
|
||||
DRAFT: Ontwerp
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: sleep een foto of klik om te selecteren
|
||||
DUTCH__FLEMISH: Dutch, Flemish
|
||||
EDIT: bewerken
|
||||
EDITOR: editor
|
||||
EDIT_USER: Gebruiker bewerken
|
||||
ENGLISH: English
|
||||
EXTERNAL_LINK: externe link
|
||||
E_G_: bijv.
|
||||
E_MAIL: e-mail
|
||||
FAVICON: Favicon
|
||||
FILE: File
|
||||
FILES: Files
|
||||
FIRST_NAME: Voornaam
|
||||
FOLDER: map
|
||||
FORGOT_PASSWORD: Wachtwoord vergeten
|
||||
FORMAT: Formaat
|
||||
FRENCH: French
|
||||
GENERAL_PRESENTATION: General Presentation
|
||||
GERMAN: German
|
||||
GOOGLE_SITEMAP: Google Sitemap
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Has edit rights for this article.
|
||||
HEAD: Kop
|
||||
HEADLINE: Kop
|
||||
HEADLINE_ANCHORS: Headline Anchors
|
||||
HERO_IMAGE: Hero Image
|
||||
HIDE: Hide
|
||||
HIDE_PAGE_FROM_NAVIGATION: Hide page from navigation
|
||||
HOME: home
|
||||
HOMEPAGE: Homepage
|
||||
HORIZONTAL_LINE: Horizontale lijn
|
||||
HR: hr
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: Indien niet ingevuld, wordt de beschrijving uit de inhoud gehaald.
|
||||
IMAGE: Afbeelding
|
||||
IMAGES: Images
|
||||
IMAGE_URL: Image URL
|
||||
IMAGE_URL_(READ_ONLY): Image URL (read only)
|
||||
ITALIAN: Italian
|
||||
ITALIC: cursief
|
||||
LANGUAGE: Taal
|
||||
LANGUAGE_ADMIN: Taal (admin-ui)
|
||||
LANGUAGE_ATTR: Taal Attribute (website)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Last modified live (readonly)
|
||||
LAST_NAME: achternaam
|
||||
LEFT: Links
|
||||
LICENCE: Licentie
|
||||
LINK: Link
|
||||
LINK_TO_VIDEO: Link naar video
|
||||
LOGIN: Inloggen
|
||||
LOGO: Logo
|
||||
LOGOUT: Uitloggen
|
||||
MANUAL_DATE: Handmatige datum
|
||||
MARKDOWN: Markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: Maximum size for an image is 5 MB. Hero images are not supported by all themes.
|
||||
MEMBER: Lid
|
||||
MENU: Menu
|
||||
META: Meta
|
||||
META_DESCRIPTION: Metabeschrijving
|
||||
META_TITLE: Metatitel
|
||||
MISSING_REQUIREMENTS: ontbrekende vereisten
|
||||
MOVE_VERTICAL: verplaats verticaal
|
||||
NAVIGATION_TITLE: Navigation Title
|
||||
NEW_PASSWORD: Nieuw wachtwoord
|
||||
NONE: Geen
|
||||
NOTICE: Opmerking
|
||||
NOT_EDITABLE: niet bewerkbaar
|
||||
NO_DESCRIPTION: Geen beschrijving
|
||||
NO_PREVIEW: Geen voorbeeld
|
||||
NO_SETTINGS: Geen instellingen
|
||||
NUMBERED_LIST: Genummerde lijst
|
||||
OLIST: olist
|
||||
ONLINE: online
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: alleen de volgende speciale tekens zijn toegestaan:
|
||||
OWNER_(USERNAME): owner (username)
|
||||
PARAGRAPH: Paragraaf
|
||||
PASSWORD: Wachtwoord
|
||||
PLEASE_CONFIRM: bevestig alstublieft
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Corrigeer bovenstaande fouten
|
||||
PLUGINS: plug-ins
|
||||
PLUGIN_STORE: Plugin Store
|
||||
POWER_OFF: power-off
|
||||
PROFILE_IMAGE: Profiel afbeelding
|
||||
PUBLISH: Publiceren
|
||||
QUOTE: Citeer
|
||||
QUOTES: Citeren
|
||||
RAW: rauw
|
||||
RAW_CONTENT_EDITOR: Ruwe Content Editor
|
||||
RAW_MARKDOWN_EDITOR: Ruwe Markdown Editor
|
||||
RAW_MODE: onbewerkte modus
|
||||
RAW_USERDATA_(READONLY_FOR_ADMINS): Ruwe Gebruikersdata (alleen lezen voor admins)
|
||||
READONLY: Alleen lezen
|
||||
REGISTERED_USERS_ONLY: Alleen geregistreerde gebruikers
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: vergeet deze pagina niet te bookmarken
|
||||
REQUIRED: verplicht
|
||||
RIGHT: Rechts
|
||||
ROLE: rol
|
||||
RUSSIAN: Russisch
|
||||
SAVE: Opslaan
|
||||
SAVED_SUCCESSFULLY: Succesvol opgeslagen
|
||||
SAVE_ALL_SETTINGS: Sla alle instellingen op
|
||||
SAVE_THEME: Thema opslaan
|
||||
SELECT_FROM_MEDIALIB: Selecteer uit medialib
|
||||
SETTINGS: Instellingen
|
||||
SETTINGS_ARE_STORED: Instellingen zijn opgeslagen
|
||||
SETUP: Instellen
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Ankers naast koppen weergeven
|
||||
STANDARD_EDITOR_MODE: Standaardeditormodus
|
||||
START: Start
|
||||
SYSTEM: Systeem
|
||||
TABLE: Tabel
|
||||
TABLE_OF_CONTENTS: Inhoudsopgave
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Genomen uit uw gebruikersaccount indien ingesteld.
|
||||
TERM: term
|
||||
TEXT_FILE: tekstbestand
|
||||
THEMES: Themes
|
||||
THEME_STORE: Theme Store
|
||||
THE_FORMAT_BUTTONS: De opmaakknoppen
|
||||
TITLE: Titel
|
||||
TOC: Toc
|
||||
TOP: Top
|
||||
TYPEMILL_DESCRIPTION: Het standaardthema voor typemill. Responsief, minimaal en zonder afhankelijkheden. Het gebruikt de systeemlettertypen Calibri en Helvetica. Er is geen JavaScript gebruikt.
|
||||
ULIST: ulist
|
||||
UNKNOWN: onbekend
|
||||
UPDATE_USER: Gebruiker bijwerken
|
||||
UPLOAD: Upload
|
||||
UPLOAD_AN_IMAGE: Upload een afbeelding
|
||||
UPLOAD_FILE: Upload een bestand
|
||||
UPS__WRONG_PASSWORD_OR_USERNAME__PLEASE_TRY_AGAIN_: Oops, verkeerd wachtwoord of gebruikersnaam, probeer het opnieuw.
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Gebruikt als fallback als er geen handmatige datum is ingesteld.
|
||||
USER: Gebruiker
|
||||
USERNAME: Gebruikersnaam
|
||||
USERNAME_(READ_ONLY): Gebruikersnaam (alleen lezen)
|
||||
USERS: Gebruikers
|
||||
USE_2_TO_20_CHARACTERS: Gebruik 2 tot 20 tekens.
|
||||
USE_2_TO_40_CHARACTERS: Gebruik 2 tot 40 tekens.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Gebruik een geldig taalkenmerk
|
||||
USE_A_VALID_YEAR: Gebruik een geldig jaar
|
||||
VIDEO: Video
|
||||
VIEW_SITE: Site bekijken
|
||||
VISUAL: visual
|
||||
VISUAL_CONTENT_EDITOR: Visual Content Editor
|
||||
VISUAL_EDITOR: visuele editor
|
||||
VISUAL_MARKDOWN_EDITOR: Visual Markdown Editor
|
||||
VISUAL_MODE: visuele modus
|
||||
WAIT: wacht
|
||||
WEB: Web
|
||||
WEBSITE_TITLE: Titel van de website
|
||||
WEBSITE_VISIBLE_FOR: Website visible for
|
||||
WRITING: Schrijven
|
||||
YEAR: Jaar
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: Je kunt de thema-css hier overschrijven met je eigen css.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Voeg nieuwe functies toe aan uw website met plug-ins en configureer ze.
|
||||
BY_THE: door de
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Kies een thema voor uw website en configureer de themadetails.
|
||||
CODED_WITH: Geprogrammeerd met
|
||||
COMMUNITY: gemeenschap
|
||||
CONFIGURE_YOUR_WEBSITE: Configureer uw website
|
||||
DOCS: Documentatie
|
||||
GET_HELP: Krijg hulp
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Geef je nieuwe website een naam, voeg de auteur toe en kies een copyright.
|
||||
HURRA: Hoera
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: Als je vragen hebt, lees dan de
|
||||
NEXT_STEP: Volgende stap
|
||||
OR_OPEN_A_NEW_ISSUE_ON: of open een nieuw issue op
|
||||
SETUP_WELCOME: Installatie Welkom
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Ga naar het auteurspaneel en stel uw nieuwe website in. U kunt het systeem configureren, thema's kiezen en plug-ins toevoegen.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Uw account is aangemaakt en u bent nu ingelogd.
|
||||
|
||||
ACCESS_CONTROL: Toegangscontrole
|
||||
ACTIVATE_INDIVIDUAL_RESTRICTIONS_FOR_PAGES_IN_THE_META_TAB_OF_EACH_PAGE_: Activeer individuele beperkingen voor pagina's in de meta-tab van elke pagina.
|
||||
ADD_ONE_OR_MORE_USERNAMES_SEPARATED_WITH_COMMA_: Voeg een of meer gebruikersnamen toe, gescheiden door komma's.
|
||||
CUT_RESTRICTED_CONTENT_AFTER_THE_FIRST_HR_ELEMENT_ON_A_PAGE_(PER_DEFAULT_CONTENT_WILL_BE_CUT_AFTER_TITLE)_: Beperkte inhoud knippen na het eerste hr-element op een pagina (standaard wordt inhoud na titel geknipt).
|
||||
FOR_ACCESS_THE_USER_MUST_HAVE_THIS_MINIMUM_ROLE: Voor toegang moet de gebruiker deze minimale rol hebben
|
||||
LIMIT_THE_ACCESS_FOR_THE_WHOLE_WEBSITE_OR_FOR_EACH_PAGE_INDIVIDUALLY__IF_YOU_ACTIVATE_THE_WEBSITE_RESTRICTION_OR_THE_PAGE_RESTRICTIONS__THEN_SESSIONS_WILL_BE_USED_IN_FRONTEND_: Beperk de toegang voor de hele website of voor elke pagina afzonderlijk. Als u de websitebeperking of de paginabeperkingen activeert, worden sessies in de frontend gebruikt.
|
||||
ONLY_THE_FOLLOWING_USERS_HAVE_ACCESS: Alleen de volgende gebruikers hebben toegang
|
||||
PAGE_RESTRICTIONS___ACTIVATE: Paginabeperkingen - Activeren
|
||||
PAGE_RESTRICTIONS___CUT_RESTRICTED_CONTENT: Paginabeperkingen - Beperkte inhoud knippen
|
||||
PAGE_RESTRICTIONS___NOTICE: Paginabeperkingen - Kennisgeving
|
||||
PAGE_RESTRICTIONS___WRAP_NOTICE_INTO_A_BOX: Paginabeperkingen - Verpak kennisgeving in een doos
|
||||
SELECT_THE_LOWEST_USERROLE__HIGHER_ROLES_WILL_HAVE_ACCESS_TOO_: Selecteer de laagste gebruikersrol. Hogere rollen hebben ook toegang.
|
||||
SHOW_THE_WEBSITE_ONLY_TO_AUTHENTICATED_USERS_AND_REDIRECT_ALL_OTHER_USERS_TO_THE_LOGIN_PAGE_: Toon de website alleen aan geverifieerde gebruikers en stuur alle andere gebruikers door naar de inlogpagina.
|
||||
USE_MARKDOWN: gebruik markdown
|
||||
WEBSITE_RESTRICTION: Websitebeperking
|
||||
WRAP_THE_RESTRICTION_NOTICE_ABOVE_INTO_A_NOTICE_4_ELEMENT_(WHICH_CAN_BE_DESIGNED_AS_SPECIAL_BOX): Wikkel de beperkingskennisgeving hierboven in een bericht-4-element (dat kan worden ontworpen als een speciaal vak)
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Cache activeren voor Twig-sjablonen
|
||||
ADD_MORE_URL_SCHEMES_FOR_EXTERNAL_LINKS_E_G__LIKE_DICT://_(COMMA_SEPARATED_LIST): Voeg meer url-schema's toe voor externe links, b.v. zoals dict:// (door komma's gescheiden lijst)
|
||||
CLEAR_CACHE: Cache wissen
|
||||
DELETE_ALL_CACHE_FILES: Alle cachebestanden verwijderen
|
||||
DEVELOPER: Ontwikkelaar
|
||||
DISABLE_HEADERS: Headers uitschakelen
|
||||
DISABLE_TYPEMILL_HEADERS_AND_SEND_YOUR_OWN: Schakel Typemill-headers uit en verzend uw eigen
|
||||
DISPLAY_APPLICATION_ERRORS: Applicatiefouten weergeven
|
||||
ERROR_REPORTING: Foutmelding
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: Als u een waarde voor de hoogte toevoegt, wordt de afbeelding bijgesneden.
|
||||
PROXY: Proxy
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Standaard hoogte voor afbeeldingen
|
||||
STANDARD_WIDTH_FOR_IMAGES: Standaardbreedte voor afbeeldingen
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: De volgende opties zijn alleen voor ontwikkelaars en ervaren beheerders. Wijzig de opties alleen als u ze echt begrijpt. Bijvoorbeeld: Activeer nooit de foutrapportage voor een live website, gebruik deze optie alleen voor het oplossen van fouten.
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: Dit geldt alleen voor toekomstige afbeeldingen in het inhoudsgebied.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): Vertrouwde IP's voor proxy (gescheiden door komma's)
|
||||
TWIG_CACHE: Twig Cache
|
||||
USE_X_FORWARDED_HEADERS: Gebruik X-Forwarded Headers
|
268
system/typemill/author/translations/ru.yaml
Normal file
268
system/typemill/author/translations/ru.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
# Russian (Русский)
|
||||
# Author: Paul (https://paul.bid) paulbid@protonmail.com
|
||||
ACCOUNT: Аккаунт
|
||||
ACTIVE: Активный
|
||||
ACTUAL_PASSWORD: Текущий пароль
|
||||
ADD: Добавить
|
||||
ADD_CONTENT_BLOCK: Добавить блок
|
||||
ADD_DEFINITION: добавить определение
|
||||
ADD_FILE: добавить запись
|
||||
ADD_FOLDER: добавить раздел
|
||||
ADD_FOLDER_TO_BASE_LEVEL: добавить раздел на корневой уровень
|
||||
ADD_ITEM: Добавить
|
||||
ADD_LEFT_COLUMN: добавить колонку слева
|
||||
ADD_RIGHT_COLUMN: добавить колонку справа
|
||||
ADD_ROW_ABOVE: добавить строку выше
|
||||
ADD_ROW_BELOW: добавить строку ниже
|
||||
ADMINISTRATOR: Администратор
|
||||
ALL: Всех посетителей
|
||||
ALL_USERS: Все пользователи
|
||||
ALTERNATIVE_TEXT_FOR_THE_HERO_IMAGE: Альтернативный текст-описание главного изображения для записи
|
||||
ALT_TEXT: Альтернативный текст
|
||||
AUTHOR: Автор
|
||||
AUTHOR_DESCRIPTION_(MARKDOWN): Об авторе (Markdown)
|
||||
BACK_TO_STARTPAGE: Назад на главную страницу
|
||||
BOLD: Полужирный
|
||||
BOTTOM: Внизу
|
||||
BROWSE: ОБЗОР
|
||||
BULLET_LIST: Маркированный список
|
||||
BY: от
|
||||
CANCEL: Отмена
|
||||
CAN_BE_USED_FOR_AUTHOR_LINE_IN_FRONTEND_: Может использоваться в качестве описания автора на странице с записью.
|
||||
CAPTION: Название
|
||||
CELL: ячейка
|
||||
CENTER: По центру
|
||||
CHECK: проверить
|
||||
CHOOSE_FILE: Выберите файл
|
||||
CLASS: Класс
|
||||
CLOSE_LIBRARY: Закрыть библиотеку
|
||||
CODE: Код
|
||||
COG: cog
|
||||
CONTENT: Контент
|
||||
COPYRIGHT: Копирайт
|
||||
CREATED_AT_(READONLY): Создано (нельзя изменить)
|
||||
CREATED_AT_(READ_ONLY): Создано (нельзя изменить)
|
||||
CREATE_NEW_USER: Создание нового пользователя
|
||||
CREATE_USER: Создать пользователя
|
||||
CROSS: Зачёркнутый
|
||||
CUSTOM_CSS: Дополнительный CSS
|
||||
DEFINITION: Список определений
|
||||
DEFINITION_LIST: Список определений
|
||||
DELETE: Удалить
|
||||
DELETE_CLOSE: Удалить/закрыть
|
||||
DELETE_COLUMN: Удалить колонку
|
||||
DELETE_CONTENT_BLOCK: Удалить блок
|
||||
DELETE_PAGE: Удалить страницу
|
||||
DELETE_ROW: Удалить строку
|
||||
DELETE_USER: Удалить пользователя
|
||||
DESCRIPTION: описание
|
||||
DISCARD: Сбросить
|
||||
DISCARD_CHANGES: Сбросить изменения
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THE_USER: Вы действительно хотите удалить пользователя
|
||||
DO_YOU_REALLY_WANT_TO_DELETE_THIS_PAGE: Вы действительно хотите удалить эту страницу?
|
||||
DO_YOU_WANT_TO_DISCARD_YOUR_CHANGES_AND_SET_THE_CONTENT_BACK_TO_THE_LIVE_VERSION: Вы хотите сбросить изменения и вернуться к предыдущей версии?
|
||||
DRAFT: Черновик
|
||||
DRAG_A_PICTURE_OR_CLICK_TO_SELECT: загрузить изображение
|
||||
DUTCH__FLEMISH: Dutch, Flemish (Голландский, Фламандский)
|
||||
EDIT: редактировать
|
||||
EDITOR: Редактор
|
||||
EDIT_USER: Редактирование профиля
|
||||
ENGLISH: English (Английский)
|
||||
EXTERNAL_LINK: внешняя ссылка
|
||||
E_G_: например
|
||||
E_MAIL: Email
|
||||
FAVICON: Иконка сайта (Favicon)
|
||||
FILE: Файл
|
||||
FILES: Файлы
|
||||
FIRST_NAME: Имя
|
||||
FOLDER: раздел
|
||||
FORGOT_PASSWORD: Забыл пароль
|
||||
FORMAT: Формат
|
||||
FRENCH: French (Французский)
|
||||
GENERAL_PRESENTATION: Графическая атрибутика
|
||||
GERMAN: German (Немецкий)
|
||||
GOOGLE_SITEMAP: Google Sitemap
|
||||
HAS_EDIT_RIGHTS_FOR_THIS_ARTICLE_: Имеет права на редактирование этой записи.
|
||||
HEAD: Заголовок
|
||||
HEADLINE: Заголовок
|
||||
HEADLINE_ANCHORS: Якорные ссылки в заголовках
|
||||
HERO_IMAGE: Главное изображение для записи
|
||||
HIDE: Скрыть
|
||||
HIDE_PAGE_FROM_NAVIGATION: Скрыть страницу из меню навигации
|
||||
HOME: главная
|
||||
HOMEPAGE: Главная
|
||||
HORIZONTAL_LINE: Горизонтальная линия
|
||||
HR: Горизонтальная линия
|
||||
IF_NOT_FILLED__THE_DESCRIPTION_IS_EXTRACTED_FROM_CONTENT_: Если не заполнено, описание генерируется из содержимого.
|
||||
IMAGE: Изображение
|
||||
IMAGES: Изображения
|
||||
IMAGE_URL: URL изображения
|
||||
IMAGE_URL_(READ_ONLY): URL изображения (нельзя изменить)
|
||||
ITALIAN: Italian (Итальянский)
|
||||
ITALIC: Наклонный
|
||||
LANGUAGE: Язык
|
||||
LANGUAGE_ADMIN: Язык (для панели администратора)
|
||||
LANGUAGE_ATTR: Атрибут языка (для сайта)
|
||||
LAST_MODIFIED_LIVE_(READONLY): Последнее изменение было (нельзя изменить)
|
||||
LAST_NAME: Фамилия
|
||||
LEFT: Слева
|
||||
LICENCE: Лицензия
|
||||
LINK: Ссылка
|
||||
LINK_TO_VIDEO: Ссылка на видео
|
||||
LOGIN: Войти
|
||||
LOGO: Логотип
|
||||
LOGOUT: Выйти
|
||||
MANUAL_DATE: Выбор даты вручную
|
||||
MARKDOWN: Markdown
|
||||
MAXIMUM_SIZE_FOR_AN_IMAGE_IS_5_MB__HERO_IMAGES_ARE_NOT_SUPPORTED_BY_ALL_THEMES_: Максимальный размер изображения - 5 MB. Главные изображения для записей поддерживаются не всеми темами.
|
||||
MEMBER: Зарегистрированный пользователь
|
||||
MENU: Меню
|
||||
META: Метаданные
|
||||
META_DESCRIPTION: Мета-описание
|
||||
META_TITLE: Мета-заголовок
|
||||
MISSING_REQUIREMENTS: Отсутствующие требования
|
||||
MOVE_VERTICAL: двигаться по вертикали
|
||||
NAVIGATION_TITLE: Название страницы в меню навигации
|
||||
NEW_PASSWORD: Новый пароль
|
||||
NONE: Нет
|
||||
NOTICE: Заметка
|
||||
NOT_EDITABLE: нельзя отредактировать
|
||||
NO_DESCRIPTION: Нет описания
|
||||
NO_PREVIEW: Нет предпросмотра
|
||||
NO_SETTINGS: Нет настроек
|
||||
NUMBERED_LIST: Упорядоченный список
|
||||
OLIST: Упорядоченный список
|
||||
ONLINE: онлайн
|
||||
ONLY_THE_FOLLOWING_SPECIAL_CHARACTERS_ARE_ALLOWED: Разрешены только следующие специальные символы -
|
||||
OWNER_(USERNAME): Владелец (имя пользователя)
|
||||
PARAGRAPH: Параграф
|
||||
PASSWORD: Пароль
|
||||
PLEASE_CONFIRM: Пожалуйста подтвердите
|
||||
PLEASE_CORRECT_THE_ERRORS_ABOVE: Пожалуйста, исправьте ошибки выше
|
||||
PLUGINS: Плагины
|
||||
PLUGIN_STORE: Магазин Плагинов
|
||||
POWER_OFF: выключить
|
||||
PROFILE_IMAGE: Изображение профиля (аватар)
|
||||
PUBLISH: Опубликовать
|
||||
QUOTE: Цитата
|
||||
QUOTES: Цитирует
|
||||
RAW: исходный код
|
||||
RAW_CONTENT_EDITOR: Редактор исходного кода
|
||||
RAW_MARKDOWN_EDITOR: Редактор кода Markdown
|
||||
RAW_MODE: Режим исходного кода
|
||||
RAW_USERDATA_(READONLY_FOR_ADMINS): Пользовательские данные (только для администраторов и только просмотр)
|
||||
READONLY: Нельзя изменить
|
||||
REGISTERED_USERS_ONLY: Только зарегистрированных пользователей
|
||||
REMEMBER_TO_BOOKMARK_THIS_PAGE: Не забудьте добавить в закладки эту страницу
|
||||
REQUIRED: Обязательно
|
||||
RIGHT: Справа
|
||||
ROLE: Роль
|
||||
RUSSIAN: Russian (Русский)
|
||||
SAVE: Сохранить
|
||||
SAVED_SUCCESSFULLY: Успешно сохранено
|
||||
SAVE_ALL_SETTINGS: Сохранить все настройки
|
||||
SAVE_THEME: Сохранить настройки Темы
|
||||
SELECT_FROM_MEDIALIB: Выбрать из библиотеки
|
||||
SETTINGS: Настройки
|
||||
SETTINGS_ARE_STORED: Настройки сохранены
|
||||
SETUP: Установка
|
||||
SHOW_ANCHORS_NEXT_TO_HEADLINES: Показывать якорные ссылки рядом с заголовками
|
||||
STANDARD_EDITOR_MODE: Стандартный режим редактора
|
||||
START: Начать
|
||||
SYSTEM: Настройки
|
||||
TABLE: Таблица
|
||||
TABLE_OF_CONTENTS: Оглавление
|
||||
TAKEN_FROM_YOUR_USER_ACCOUNT_IF_SET_: Взято из вашего профиля, если в профиле заполнено
|
||||
TERM: термин
|
||||
TEXT_FILE: текстовый файл
|
||||
THEMES: Темы
|
||||
THEME_STORE: Магазин Тем
|
||||
THE_FORMAT_BUTTONS: Кнопки для форматирования
|
||||
TITLE: Название
|
||||
TOC: Оглавление
|
||||
TOP: Наверху
|
||||
TYPEMILL_DESCRIPTION: Стандартная тема для Typemill. Отзывчивая, минималистичная и без каких-либо зависимостей. Используются системные шрифты Calibri и Helvetica. А вот JavaScript не используется.
|
||||
ULIST: Маркированный список
|
||||
UNKNOWN: Неизвестен
|
||||
UPDATE_USER: Обновить данные профиля
|
||||
UPLOAD: загрузить
|
||||
UPLOAD_AN_IMAGE: Загрузить изображение
|
||||
UPLOAD_FILE: Загрузить файл
|
||||
UPS__WRONG_PASSWORD_OR_USERNAME__PLEASE_TRY_AGAIN_: Упс... неправильный пароль или имя пользователя, попробуйте войти ещё раз.
|
||||
USED_AS_FALLBACK_WHEN_NO_MANUAL_DATE_IS_SET_: Используется как запасной вариант, когда дата не установлена в ручную.
|
||||
USER: Пользователь
|
||||
USERNAME: Имя пользователя
|
||||
USERNAME_(READ_ONLY): Имя пользователя (не изменяется)
|
||||
USERS: Пользователи
|
||||
USE_2_TO_20_CHARACTERS: Изпользуйте от 2 до 20 символов.
|
||||
USE_2_TO_40_CHARACTERS: Используйте от 2 до 40 символов.
|
||||
USE_A_VALID_LANGUAGE_ATTRIBUTE: Используйте допустимый языковой атрибут
|
||||
USE_A_VALID_YEAR: Используйте правильный формат для указания года
|
||||
VIDEO: Видео
|
||||
VIEW_SITE: На сайт
|
||||
VISUAL: визуально
|
||||
VISUAL_CONTENT_EDITOR: Визуальный редактор контента
|
||||
VISUAL_EDITOR: Визуальный редактор
|
||||
VISUAL_MARKDOWN_EDITOR: Визуальный редактор Markdown
|
||||
VISUAL_MODE: визульный режим
|
||||
WAIT: подождите
|
||||
WEB: Сайт
|
||||
WEBSITE_TITLE: Название сайта
|
||||
WEBSITE_VISIBLE_FOR: Сайт виден для
|
||||
WRITING: Настройки редактора
|
||||
YEAR: Год
|
||||
YOU_CAN_OVERWRITE_THE_THEME_CSS_WITH_YOUR_OWN_CSS_HERE_: Вы можете изменить CSS стиль Темы на свой собственный CSS здесь.
|
||||
|
||||
ADD_NEW_FEATURES_TO_YOUR_WEBSITE_WITH_PLUGINS_AND_CONFIGURE_THEM_: Добавляйте новые функции на свой сайт с помощью плагинов и настраивайте их.
|
||||
BY_THE: от
|
||||
CHOOSE_A_THEME_FOR_YOUR_WEBSITE_AND_CONFIGURE_THE_THEME_DETAILS_: Выберите тему для своего сайта и настройте детали темы.
|
||||
CODED_WITH: Разработано с
|
||||
COMMUNITY: сообщество
|
||||
CONFIGURE_YOUR_WEBSITE: Настройте свой сайт
|
||||
DOCS: документация
|
||||
GET_HELP: Помощь
|
||||
GIVE_YOUR_NEW_WEBSITE_A_NAME__ADD_THE_AUTHOR_AND_CHOOSE_A_COPYRIGHT_: Дайте вашему новому сайту имя, добавьте автора и выберите тип авторского права (лицензии).
|
||||
HURRA: Урашечки
|
||||
IF_YOU_HAVE_ANY_QUESTIONS__PLEASE_READ_THE: Если у вас есть вопросы, пожалуйста прочтите
|
||||
NEXT_STEP: Следующий шаг
|
||||
OR_OPEN_A_NEW_ISSUE_ON: или откройте новое обсуждение проблемы на
|
||||
SETUP_WELCOME: Первоначальные настройки
|
||||
TRENDSCHAU_DIGITAL: Trendschau Digital
|
||||
VISIT_THE_AUTHOR_PANEL_AND_SETUP_YOUR_NEW_WEBSITE__YOU_CAN_CONFIGURE_THE_SYSTEM__CHOOSE_THEMES_AND_ADD_PLUGINS_: Посетите панель администратора и настройте свой новый сайт. Вы можете настроить систему, выбрать темы и добавить плагины.
|
||||
YOUR_ACCOUNT_HAS_BEEN_CREATED_AND_YOU_ARE_LOGGED_IN_NOW_: Ваша учётная запись создана, и вы вошли в систему.
|
||||
|
||||
ACCESS_CONTROL: Настройки доступа
|
||||
ACTIVATE_INDIVIDUAL_RESTRICTIONS_FOR_PAGES_IN_THE_META_TAB_OF_EACH_PAGE_: Активировать индивидуальные ограничения для страниц во вкладке метаданные у каждой страницы.
|
||||
ADD_ONE_OR_MORE_USERNAMES_SEPARATED_WITH_COMMA_: Добавьте одно или несколько имен пользователей через запятую.
|
||||
CUT_RESTRICTED_CONTENT_AFTER_THE_FIRST_HR_ELEMENT_ON_A_PAGE_(PER_DEFAULT_CONTENT_WILL_BE_CUT_AFTER_TITLE)_: Скрыть контент после первого hr-элемента на странице (по умолчанию контент скрывается после заголовка).
|
||||
FOR_ACCESS_THE_USER_MUST_HAVE_THIS_MINIMUM_ROLE: Для доступа к этой странице пользователь должен иметь как минимум выбранную роль
|
||||
LIMIT_THE_ACCESS_FOR_THE_WHOLE_WEBSITE_OR_FOR_EACH_PAGE_INDIVIDUALLY__IF_YOU_ACTIVATE_THE_WEBSITE_RESTRICTION_OR_THE_PAGE_RESTRICTIONS__THEN_SESSIONS_WILL_BE_USED_IN_FRONTEND_: Ограничьте доступ для всего сайта или для каждой страницы в отдельности. Если вы активируете ограничение сайта или ограничения страниц, то сеансы пользователей (сессии) будут храниться на стороне пользователей (во фронтенд части).
|
||||
ONLY_THE_FOLLOWING_USERS_HAVE_ACCESS: Только следующие пользователи имеют доступ к этой странице
|
||||
PAGE_RESTRICTIONS___ACTIVATE: Настройки страниц - Активация ограничения доступа
|
||||
PAGE_RESTRICTIONS___CUT_RESTRICTED_CONTENT: Настройки страниц - Скрытие ограниченного контента
|
||||
PAGE_RESTRICTIONS___NOTICE: Настройки страниц - Примечание об ограничении доступа
|
||||
PAGE_RESTRICTIONS___WRAP_NOTICE_INTO_A_BOX: Настройки страниц - Оборачивание примечания об ограничении доступа в рамку
|
||||
SELECT_THE_LOWEST_USERROLE__HIGHER_ROLES_WILL_HAVE_ACCESS_TOO_: Выберите роль пользователя. Более важные роли также будут иметь доступ к странице.
|
||||
SHOW_THE_WEBSITE_ONLY_TO_AUTHENTICATED_USERS_AND_REDIRECT_ALL_OTHER_USERS_TO_THE_LOGIN_PAGE_: Показывать сайт только аутентифицированным пользователям и перенаправлять всех остальных пользователей на страницу входа.
|
||||
USE_MARKDOWN: поддерживается Markdown
|
||||
WEBSITE_RESTRICTION: Ограничения доступа к сайту
|
||||
WRAP_THE_RESTRICTION_NOTICE_ABOVE_INTO_A_NOTICE_4_ELEMENT_(WHICH_CAN_BE_DESIGNED_AS_SPECIAL_BOX): Обернуть указанное выше примечание об ограничении доступа в элемент notice-4 (который может быть выполнен в виде специальной рамки).
|
||||
|
||||
ACTIVATE_CACHE_FOR_TWIG_TEMPLATES: Активировать кэш для шаблонов Twig
|
||||
ADD_MORE_URL_SCHEMES_FOR_EXTERNAL_LINKS_E_G__LIKE_DICT://_(COMMA_SEPARATED_LIST): Добавьте дополнительные схемы URL для внешних ссылок, например как dict:// (список, разделенный запятыми)
|
||||
CLEAR_CACHE: Очистить кэш
|
||||
DELETE_ALL_CACHE_FILES: Удалить все файлы кэша
|
||||
DEVELOPER: Настройки разработчика
|
||||
DISABLE_HEADERS: Отключение заголовков
|
||||
DISABLE_TYPEMILL_HEADERS_AND_SEND_YOUR_OWN: Отключить заголовки Typemill и отправлять свои заголовки
|
||||
DISPLAY_APPLICATION_ERRORS: Отображение ошибок
|
||||
ERROR_REPORTING: Отчёты об ошибках
|
||||
IF_YOU_ADD_A_VALUE_FOR_THE_HEIGHT__THEN_THE_IMAGE_WILL_BE_CROPPED_: Если вы добавите значение высоты, изображение будет обрезано.
|
||||
PROXY: Прокси
|
||||
STANDARD_HEIGHT_FOR_IMAGES: Стандартная высота для изображений
|
||||
STANDARD_WIDTH_FOR_IMAGES: Стандартная ширина для изображений
|
||||
THE_FOLLOWING_OPTIONS_ARE_ONLY_FOR_DEVELOPERS: Следующие параметры предназначены только для разработчиков и опытных администраторов. Изменяйте параметры только в том случае, если вы действительно их понимаете. Например: никогда не активируйте отчет об ошибках для действующего сайта, используйте эту опцию только для исправления ошибок.
|
||||
THIS_APPLIES_ONLY_FOR_FUTURE_IMAGES_IN_THE_CONTENT_AREA_: Это относится только к будущим изображениям в области содержимого.
|
||||
TRUSTED_IPS_FOR_PROXY_(COMMA_SEPARATED): Список надежных IP-адресов для прокси (список, разделенный запятыми)
|
||||
TWIG_CACHE: Twig кэш
|
||||
USE_X_FORWARDED_HEADERS: Использовать X-Forwarded Заголовки
|
@@ -1,5 +1,29 @@
|
||||
<?php
|
||||
|
||||
use Typemill\Controllers\ControllerSystemApi;
|
||||
use Typemill\Middleware\RestrictApiAccess;
|
||||
|
||||
|
||||
# https://stackoverflow.blog/2021/10/06/best-practices-for-authentication-and-authorization-for-rest-apis/
|
||||
|
||||
# INTERNAL API
|
||||
# on login generate token
|
||||
# tmpApiKey: store token in userfile
|
||||
# tmpApiDate: store date in userfile
|
||||
# send username and token to frontend
|
||||
# AUTHORIZATION: apikey username.tmpapikey
|
||||
# validy equals session length from settings
|
||||
|
||||
# PUBLIC API
|
||||
# ApiKey:
|
||||
# AUTHORIZATION: apikey username.apikey
|
||||
|
||||
|
||||
$app->get('/api/v1/settings', ControllerSystemApi::class . ':getSettings')->setName('api.settings.get')->add(new RestrictApiAccess());
|
||||
$app->get('/api/v1/systemnavi', ControllerSystemApi::class . ':getSystemnavi')->setName('api.systemnavi.get')->add(new RestrictApiAccess());
|
||||
$app->get('/api/v1/mainnavi', ControllerSystemApi::class . ':getMainnavi')->setName('api.mainnavi.get')->add(new RestrictApiAccess());
|
||||
|
||||
|
||||
/*
|
||||
use Typemill\Controllers\ControllerAuthorArticleApi;
|
||||
use Typemill\Controllers\ControllerAuthorBlockApi;
|
||||
|
@@ -2,15 +2,26 @@
|
||||
|
||||
use Typemill\Controllers\ControllerWebFrontend;
|
||||
use Typemill\Controllers\ControllerWebLogin;
|
||||
use Typemill\Middleware\RedirectIfUnauthenticated;
|
||||
use Typemill\Controllers\ControllerSystem;
|
||||
use Typemill\Middleware\RedirectIfAuthenticated;
|
||||
use Typemill\Middleware\RedirectIfUnauthenticated;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
|
||||
$app->get('/tm/login', ControllerWebLogin::class . ':show')->setName('auth.show')->add(new RedirectIfAuthenticated($routeParser, $settings));
|
||||
$app->post('/tm/login', ControllerWebLogin::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($routeParser, $settings));
|
||||
|
||||
$app->get('/tm/system', ControllerSystem::class . ':showSettings')->setName('settings.show')->add(new RedirectIfUnauthenticated($routeParser));
|
||||
$app->get('/tm/themes', ControllerSystem::class . ':showThemes')->setName('themes.show');
|
||||
$app->get('/tm/plugins', ControllerSystem::class . ':showPlugins')->setName('plugins.show');
|
||||
$app->get('/tm/account', ControllerSystem::class . ':showAccount')->setName('user.account');
|
||||
$app->get('/tm/user/new', ControllerSystem::class . ':newUser')->setName('user.new');
|
||||
$app->get('/tm/users', ControllerSystem::class . ':listUser')->setName('user.list');
|
||||
|
||||
|
||||
|
||||
|
||||
$app->get('/tm/content/visual[/{params:.*}]', ControllerAuthorEditor::class . ':showBlox')->setName('content.visual');
|
||||
|
||||
$app->get('/tm/login', ControllerWebLogin::class . ':show')->setName('auth.show')
|
||||
->add(new RedirectIfAuthenticated($container->get('routeParser'), $container->get('settings')))
|
||||
->add(TwigMiddleware::createFromContainer($app));
|
||||
#$app->post('/tm/login', ControllerWebLogin::class . ':login')->setName('auth.login')->add(new RedirectIfAuthenticated($container['router'], $container['settings']));
|
||||
$app->get('/[{params:.*}]', ControllerWebFrontend::class . ':index')->setName('home');
|
||||
|
||||
/*
|
||||
|
@@ -12,6 +12,7 @@ contentFolder: 'content'
|
||||
authorFolder: '/system/typemill/author'
|
||||
adminSegment: 'tm'
|
||||
editor: 'visual'
|
||||
storage: '\Typemill\Models\Storage'
|
||||
formats:
|
||||
- 'markdown'
|
||||
- 'headline'
|
||||
|
25
system/typemill/settings/mainnavi.yaml
Normal file
25
system/typemill/settings/mainnavi.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
'content':
|
||||
'title': 'Content'
|
||||
'routename': 'content.visual'
|
||||
'aclresource': 'content'
|
||||
'aclprivilege': 'view'
|
||||
'system':
|
||||
'title': 'System'
|
||||
'routename': 'settings.show'
|
||||
'aclresource': 'system'
|
||||
'aclprivilege': 'view'
|
||||
'account':
|
||||
'title': 'Account'
|
||||
'routename': 'user.account'
|
||||
'aclresource': 'user'
|
||||
'aclprivilege': 'view'
|
||||
'frontend':
|
||||
'title': 'Frontend'
|
||||
'routename': 'home'
|
||||
'aclresource': 'user'
|
||||
'aclprivilege': 'view'
|
||||
'logout':
|
||||
'title': 'Logout'
|
||||
'routename': 'auth.login'
|
||||
'aclresource': 'user'
|
||||
'aclprivilege': 'view'
|
30
system/typemill/settings/systemnavi.yaml
Normal file
30
system/typemill/settings/systemnavi.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
'system':
|
||||
'title': 'System'
|
||||
'routename': 'settings.show'
|
||||
'icon': 'icon-wrench'
|
||||
'aclresource': 'system'
|
||||
'aclprivilege': 'view'
|
||||
'themes':
|
||||
'title': 'Themes'
|
||||
'routename': 'themes.show'
|
||||
'icon': 'icon-paint-brush'
|
||||
'aclresource': 'system'
|
||||
'aclprivilege': 'view'
|
||||
'plugins':
|
||||
'title': 'Plugins'
|
||||
'routename': 'plugins.show'
|
||||
'icon': 'icon-plug'
|
||||
'aclresource': 'system'
|
||||
'aclprivilege': 'view'
|
||||
'account':
|
||||
'title': 'Account'
|
||||
'routename': 'user.account'
|
||||
'icon': 'icon-user'
|
||||
'aclresource': 'user'
|
||||
'aclprivilege': 'view'
|
||||
'users':
|
||||
'title': 'Users'
|
||||
'routename': 'user.list'
|
||||
'icon': 'icon-group'
|
||||
'aclresource': 'userlist'
|
||||
'aclprivilege': 'view'
|
@@ -3,28 +3,33 @@
|
||||
# included from /public/index.php
|
||||
|
||||
use DI\Container;
|
||||
#use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
|
||||
use Slim\Exception\HttpNotFoundException;
|
||||
use Slim\Middleware\ErrorMiddleware;
|
||||
use Slim\Psr7\Response as Response;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Csrf\Guard;
|
||||
use Slim\Views\Twig;
|
||||
use Slim\Views\TwigMiddleware;
|
||||
use Slim\Psr7\Factory\UriFactory;
|
||||
use Slim\Flash\Messages;
|
||||
use Twig\Extension\DebugExtension;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Typemill\Static\Settings;
|
||||
use Typemill\Static\Plugins;
|
||||
use Typemill\Static\Translations;
|
||||
use Typemill\Static\Permissions;
|
||||
use Typemill\Static\Session;
|
||||
use Typemill\Events\OnSettingsLoaded;
|
||||
use Typemill\Events\OnPluginsLoaded;
|
||||
use Typemill\Events\OnSessionSegmentsLoaded;
|
||||
use Typemill\Events\OnRolesPermissionsLoaded;
|
||||
use Typemill\Events\OnResourcesLoaded;
|
||||
use Typemill\Middleware\JsonBodyParser;
|
||||
use Typemill\Middleware\CreateSession;
|
||||
use Typemill\Middleware\TwigView;
|
||||
use Typemill\Middleware\CsrfProtection;
|
||||
use Typemill\Middleware\CsrfProtectionToMiddleware;
|
||||
use Typemill\Middleware\FlashMessages;
|
||||
#use Typemill\Middleware\ValidationErrors;
|
||||
use Typemill\Extensions\TwigCsrfExtension;
|
||||
use Typemill\Extensions\TwigUrlExtension;
|
||||
use Typemill\Extensions\TwigUserExtension;
|
||||
use Typemill\Models\StorageWrapper;
|
||||
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
# require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$timer = [];
|
||||
$timer['start'] = microtime(true);
|
||||
@@ -37,13 +42,11 @@ ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
|
||||
/****************************
|
||||
* LOAD SETTINGS *
|
||||
****************************/
|
||||
|
||||
$settings = Typemill\Static\Settings::loadSettings($rootpath);
|
||||
|
||||
$settings = Settings::loadSettings();
|
||||
|
||||
/****************************
|
||||
* HANDLE DISPLAY ERRORS *
|
||||
@@ -55,6 +58,18 @@ if(isset($settings['displayErrorDetails']) && $settings['displayErrorDetails'])
|
||||
ini_set('display_startup_errors', 1);
|
||||
}
|
||||
|
||||
/****************************
|
||||
* ADD PATH-INFOS FOR LATER *
|
||||
****************************/
|
||||
|
||||
# ADD THEM TO THE SETTINGS AND YOU HAVE THEM EVERYWHERE??
|
||||
$uriFactory = new UriFactory();
|
||||
$uri = $uriFactory->createFromGlobals($_SERVER);
|
||||
|
||||
$settings['fullpath'] = $uri->getPath();
|
||||
$settings['basepath'] = preg_replace('/(.*)\/.*/', '$1', $_SERVER['SCRIPT_NAME']);
|
||||
$settings['routepath'] = str_replace($settings['basepath'], '', $settings['fullpath']);
|
||||
|
||||
$timer['settings'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
@@ -71,43 +86,29 @@ $container = $app->getContainer();
|
||||
$responseFactory = $app->getResponseFactory();
|
||||
$routeParser = $app->getRouteCollector()->getRouteParser();
|
||||
|
||||
# add route parser to conatiner to use named routes in controller
|
||||
# add route parser to container to use named routes in controller
|
||||
$container->set('routeParser', $routeParser);
|
||||
|
||||
$timer['container'] = microtime(true);
|
||||
|
||||
/****************************
|
||||
* BASE URL AND ROOT PATH *
|
||||
****************************/
|
||||
|
||||
$uriFactory = new \Slim\Psr7\Factory\UriFactory();
|
||||
$uri = $uriFactory->createFromGlobals($_SERVER);
|
||||
$uripath = $uri->getPath();
|
||||
$basepath = preg_replace('/(.*)\/.*/', '$1', $_SERVER['SCRIPT_NAME']);
|
||||
$routepath = str_replace($basepath, '', $uripath);
|
||||
|
||||
# in slim 4 you alsways have to set application basepath
|
||||
$app->setBasePath($basepath);
|
||||
$app->setBasePath($settings['basepath']);
|
||||
|
||||
$container->set('basePath', $basepath);
|
||||
$container->set('rootPath', $rootpath);
|
||||
$container->set('uriPath', $uripath);
|
||||
$container->set('routePath', $routepath);
|
||||
$timer['container'] = microtime(true);
|
||||
|
||||
|
||||
/****************************
|
||||
* CREATE EVENT DISPATCHER *
|
||||
****************************/
|
||||
|
||||
$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
|
||||
$dispatcher = new EventDispatcher();
|
||||
|
||||
|
||||
/****************************
|
||||
* LOAD & UPDATE PLUGINS *
|
||||
****************************/
|
||||
|
||||
$plugins = Typemill\Static\Plugins::loadPlugins($rootpath);
|
||||
$pluginSettings = $routes = $middleware = [];
|
||||
$plugins = Plugins::loadPlugins();
|
||||
$routes = [];
|
||||
$middleware = [];
|
||||
|
||||
# if there are less plugins in the scan than in the settings, then a plugin has been removed
|
||||
if(count($plugins) < count($settings['plugins']))
|
||||
@@ -133,8 +134,8 @@ foreach($plugins as $plugin)
|
||||
# if the plugin is activated, add routes/middleware and add plugin as event subscriber
|
||||
if($settings['plugins'][$pluginName]['active'])
|
||||
{
|
||||
$routes = Typemill\Static\Plugins::getNewRoutes($className, $routes);
|
||||
$middleware = Typemill\Static\Plugins::getNewMiddleware($className, $middleware);
|
||||
$routes = Plugins::getNewRoutes($className, $routes);
|
||||
$middleware = Plugins::getNewMiddleware($className, $middleware);
|
||||
|
||||
$dispatcher->addSubscriber(new $className($container));
|
||||
}
|
||||
@@ -144,7 +145,7 @@ foreach($plugins as $plugin)
|
||||
if(isset($updateSettings))
|
||||
{
|
||||
# update stored settings file
|
||||
Typemill\settings::updateSettings($settings);
|
||||
Settings::updateSettings($settings);
|
||||
}
|
||||
|
||||
# add final settings to the container
|
||||
@@ -163,20 +164,16 @@ $timer['plugins'] = microtime(true);
|
||||
* LOAD ROLES & PERMISSIONS *
|
||||
****************************/
|
||||
|
||||
# load roles and permissions
|
||||
$rolesAndPermissions = Typemill\Static\Permissions::loadRolesAndPermissions($settings['defaultSettingsPath']);
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
# load roles and permissions and dispatch to plugins
|
||||
$rolesAndPermissions = Permissions::loadRolesAndPermissions($settings['defaultSettingsPath']);
|
||||
$rolesAndPermissions = $dispatcher->dispatch(new OnRolesPermissionsLoaded($rolesAndPermissions), 'onRolesPermissionsLoaded')->getData();
|
||||
|
||||
# load resources
|
||||
$resources = Typemill\Static\Permissions::loadResources($settings['defaultSettingsPath']);
|
||||
|
||||
# dispatch roles so plugins can enhance them
|
||||
# load resources and dispatch to plugins
|
||||
$resources = Permissions::loadResources($settings['defaultSettingsPath']);
|
||||
$resources = $dispatcher->dispatch(new OnResourcesLoaded($resources), 'onResourcesLoaded')->getData();
|
||||
|
||||
# create acl-object
|
||||
$acl = Typemill\Static\Permissions::createAcl($rolesAndPermissions, $resources);
|
||||
$acl = Permissions::createAcl($rolesAndPermissions, $resources);
|
||||
|
||||
# add acl to container
|
||||
$container->set('acl', function() use ($acl){ return $acl; });
|
||||
@@ -192,11 +189,11 @@ $timer['permissions'] = microtime(true);
|
||||
if( ( isset($settings['access']) && $settings['access'] ) || ( isset($settings['pageaccess']) && $settings['pageaccess'] ) )
|
||||
{
|
||||
# activate session for all routes
|
||||
$session_segments = [$routepath];
|
||||
$session_segments = [$settings['routepath']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$session_segments = ['setup', 'tm/', 'api/'];
|
||||
$session_segments = ['setup', 'tm/'];
|
||||
|
||||
# let plugins add own segments for session, eg. to enable csrf for forms
|
||||
$client_segments = $dispatcher->dispatch(new OnSessionSegmentsLoaded([]), 'onSessionSegmentsLoaded')->getData();
|
||||
@@ -204,7 +201,7 @@ else
|
||||
}
|
||||
|
||||
# start session
|
||||
# Typemill\Static\Session::startSessionForSegments($session_segments, $routepath);
|
||||
Session::startSessionForSegments($session_segments, $settings['routepath']);
|
||||
|
||||
$timer['session segments'] = microtime(true);
|
||||
|
||||
@@ -212,72 +209,90 @@ $timer['session segments'] = microtime(true);
|
||||
* OTHER CONTAINER ITEMS *
|
||||
****************************/
|
||||
|
||||
# Register Middleware On Container
|
||||
if(isset($_SESSION)){
|
||||
$container->set('csrf', function () use ($responseFactory){ return new Guard($responseFactory); });
|
||||
}
|
||||
|
||||
# dispatcher to container
|
||||
$container->set('dispatcher', function() use ($dispatcher){ return $dispatcher; });
|
||||
|
||||
# asset function for plugins
|
||||
$container->set('assets', function() use ($basepath){ return new \Typemill\Assets($basepath); });
|
||||
$container->set('assets', function() use ($settings){ return new \Typemill\Assets($settings['basepath']); });
|
||||
|
||||
$timer['other container'] = microtime(true);
|
||||
# Register Middleware On Container
|
||||
$csrf = false;
|
||||
if(isset($_SESSION))
|
||||
{
|
||||
# add flash messsages
|
||||
$container->set('flash', function(){ return new Messages(); });
|
||||
|
||||
# Register Middleware On Container
|
||||
$csrf = new Guard($responseFactory);
|
||||
$container->set('csrf', function () use ($csrf){ return $csrf; });
|
||||
|
||||
# Add Validation Errors Middleware
|
||||
# $app->add(new ValidationErrors($container->get('view')));
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
* TWIG TO CONTAINER *
|
||||
****************************/
|
||||
|
||||
$container->set('view', function() use ($settings, $csrf, $uri) {
|
||||
|
||||
$twig = Twig::create(
|
||||
[
|
||||
# path to templates
|
||||
$settings['rootPath'] . $settings['authorFolder'],
|
||||
$settings['rootPath'] . DIRECTORY_SEPARATOR . 'themes' . DIRECTORY_SEPARATOR . $settings['theme'],
|
||||
],
|
||||
[
|
||||
# settings
|
||||
'cache' => ( isset($settings['twigcache']) && $settings['twigcache'] ) ? $settings['rootPath'] . '/cache/twig' : false,
|
||||
'debug' => isset($settings['displayErrorDetails'])
|
||||
]
|
||||
);
|
||||
|
||||
$twig->getEnvironment()->addGlobal('errors', NULL);
|
||||
$twig->getEnvironment()->addGlobal('flash', NULL);
|
||||
|
||||
# add extensions
|
||||
$twig->addExtension(new DebugExtension());
|
||||
$twig->addExtension(new TwigUserExtension());
|
||||
$twig->addExtension(new TwigUrlExtension($uri, $settings['basepath']));
|
||||
|
||||
# $twig->addExtension(new \Nquire\Extensions\TwigUserExtension());
|
||||
|
||||
if($csrf)
|
||||
{
|
||||
$twig->addExtension(new TwigCsrfExtension($csrf));
|
||||
}
|
||||
|
||||
# translations
|
||||
$translations = Translations::loadTranslations($settings);
|
||||
# $twig->getEnvironment()->addGlobal('translations', $translations);
|
||||
$twig->addExtension(new Typemill\Extensions\TwigLanguageExtension( $translations ));
|
||||
|
||||
return $twig;
|
||||
|
||||
});
|
||||
|
||||
|
||||
/****************************
|
||||
* MIDDLEWARE *
|
||||
****************************/
|
||||
|
||||
# Add Validation Errors Middleware
|
||||
# $app->add(new ValidationErrors($container->get('view')));
|
||||
|
||||
# Add Flash Messages Middleware
|
||||
# $app->add(new FlashMessages($container->get('view')));
|
||||
|
||||
# Add Twig-View Middleware
|
||||
# $app->add(TwigMiddleware::createFromContainer($app));
|
||||
|
||||
# if session add flash messages
|
||||
$app->add(new FlashMessages($container));
|
||||
|
||||
/*
|
||||
if(isset($_SESSION))
|
||||
{
|
||||
echo '<br>add csrf';
|
||||
# Register Middleware To Be Executed On All Routes
|
||||
# Add Validation Errors Middleware
|
||||
#$app->add(new ValidationErrors($container->get('view')));
|
||||
|
||||
# Add Flash Messages Middleware
|
||||
$app->add(new FlashMessages($container->get('view')));
|
||||
|
||||
# Add csrf middleware globally
|
||||
$app->add('csrf');
|
||||
}
|
||||
*/
|
||||
|
||||
# $container->set('csrf', null);
|
||||
|
||||
# $app->add('csrf');
|
||||
# $app->add(new CsrfProtectionToMiddleware($container));
|
||||
|
||||
|
||||
$app->add(function($request, $handler) use ($container){
|
||||
$response = $handler->handle($request);
|
||||
$existingContent = (string) $response->getBody();
|
||||
|
||||
$response = new Response();
|
||||
$response->getBody()->write('BEFORE' . $existingContent);
|
||||
|
||||
return $response;
|
||||
});
|
||||
|
||||
# if session add csrf protection
|
||||
$app->add(new CsrfProtection($container, $responseFactory));
|
||||
|
||||
# add session
|
||||
$app->add(new CreateSession($session_segments, ltrim($routepath, '/') ));
|
||||
|
||||
# check if user : apikey
|
||||
# if yes
|
||||
# validate it as normal password
|
||||
# do not create sessions
|
||||
# set authentication to true somehow
|
||||
# Add Twig-View Middleware
|
||||
$app->add(TwigMiddleware::createFromContainer($app));
|
||||
|
||||
# add JsonBodyParser Middleware
|
||||
$app->add(new JsonBodyParser());
|
||||
@@ -317,15 +332,16 @@ require __DIR__ . '/routes/web.php';
|
||||
$timer['routes'] = microtime(true);
|
||||
|
||||
/************************
|
||||
* RUN APP *
|
||||
* RUN APP *
|
||||
************************/
|
||||
|
||||
$app->run();
|
||||
|
||||
$timer['run'] = microtime(true);
|
||||
|
||||
Typemill\Static\Helpers::printTimer($timer);
|
||||
# Typemill\Static\Helpers::printTimer($timer);
|
||||
|
||||
die();
|
||||
die('After app run');
|
||||
|
||||
|
||||
@@ -367,8 +383,8 @@ foreach($session_segments as $segment)
|
||||
|
||||
$test = substr( $trimmedRoute, 0, strlen($segment) );
|
||||
|
||||
echo '<br>' . $test . ' = ' . $segment;
|
||||
continue;
|
||||
# echo '<br>' . $test . ' = ' . $segment;
|
||||
# continue;
|
||||
|
||||
if(substr( $uri->getPath(), 0, strlen($segment) ) === ltrim($segment, '/'))
|
||||
{
|
||||
@@ -448,7 +464,7 @@ $container->set('view', function() use ($container) {
|
||||
|
||||
return $twig;
|
||||
});
|
||||
|
||||
|
||||
/****************************
|
||||
* SET ROUTE PARSER TO USE NAMED ROUTES IN CONTROLLER *
|
||||
****************************/
|
||||
|
Reference in New Issue
Block a user