- Added a new ArrayCollection
- Changed Action attribute and transformed it into an abstract class
This commit is contained in:
parent
0443f5a811
commit
9b360c4010
@ -10,7 +10,7 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"php": "^8.4",
|
||||
"php-di/php-di": "dev-master",
|
||||
"ext-json": "*",
|
||||
"mcnd/lean": "dev-master"
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
use Ulmus\ConnectionAdapter;
|
||||
|
||||
use function DI\{ get, env };
|
||||
|
||||
define('LEAN_API_PROJECT_PATH', $path = dirname(__DIR__, 2));
|
||||
|
||||
return [
|
||||
@ -56,6 +58,11 @@ return [
|
||||
return $adapter;
|
||||
},
|
||||
|
||||
'app.middlewares' => \DI\add([
|
||||
Lean\Api\Middleware\CORS::class,
|
||||
]),
|
||||
|
||||
Lean\Api\Lib\RenderCORS::class => DI\create(Lean\Api\Lib\RenderCORS::class)->constructor(get(\Psr\Http\Message\ServerRequestInterface::class), env('LEAN_API_CORS_ORIGIN', '*')),
|
||||
Lean\ApplicationStrategy\NotFoundDecoratorInterface::class => DI\autowire(Lean\Api\ApplicationStrategy\NotFoundDecorator::class),
|
||||
Lean\ApplicationStrategy\MethodNotAllowedInterface::class => DI\autowire(Lean\Api\ApplicationStrategy\MethodNotAllowedDecorator::class),
|
||||
Lean\Api\Factory\MessageFactoryInterface::class => DI\autowire(Lean\Api\Lib\Message::class),
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace Lean\Api\ApplicationStrategy;
|
||||
|
||||
use DI\Attribute\Inject;
|
||||
use Lean\Api\Lib\RenderCORS;
|
||||
use Lean\ApplicationStrategy;
|
||||
use Lean\Factory\HttpFactoryInterface;
|
||||
use Picea\Picea;
|
||||
@ -13,17 +14,17 @@ use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class MethodNotAllowedDecorator implements \Lean\ApplicationStrategy\MethodNotAllowedInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected RenderCORS $cors,
|
||||
) {}
|
||||
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
if ($request->getMethod() === 'OPTIONS') {
|
||||
return $this->cors->fromResponse($handler->handle($request), true);
|
||||
}
|
||||
|
||||
if ($request->getMethod() === 'OPTIONS') {
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: *');
|
||||
header('Access-Control-Allow-Headers: *');
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return $handler->handle($request);;
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
11
src/Attribute/Action.php
Normal file
11
src/Attribute/Action.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute;
|
||||
|
||||
use Lean\Api\Attribute\Action\ActionTypeEnum;
|
||||
use Picea\Ui\Method\FormContextInterface;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
abstract class Action {
|
||||
abstract public function action(EntityInterface $entity, string $key, FormContextInterface $context, string $field): ActionTypeEnum;
|
||||
}
|
||||
9
src/Attribute/Action/ActionTypeEnum.php
Normal file
9
src/Attribute/Action/ActionTypeEnum.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute\Action;
|
||||
|
||||
enum ActionTypeEnum
|
||||
{
|
||||
case ValueModifier;
|
||||
case Setter;
|
||||
}
|
||||
21
src/Attribute/Action/Trim.php
Normal file
21
src/Attribute/Action/Trim.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute\Action;
|
||||
|
||||
use Picea\Ui\Method\FormContextInterface;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::IS_REPEATABLE)]
|
||||
class Trim extends \Lean\Api\Attribute\Action
|
||||
{
|
||||
public function __construct(
|
||||
public string $characters = " \n\r\t\v\0"
|
||||
) {}
|
||||
|
||||
public function action(EntityInterface $entity, string $key, FormContextInterface $context, string $field): ActionTypeEnum
|
||||
{
|
||||
$context->$field = trim($context->$field, $this->characters);
|
||||
|
||||
return ActionTypeEnum::ValueModifier;
|
||||
}
|
||||
}
|
||||
18
src/Attribute/Action/ValueAppend.php
Normal file
18
src/Attribute/Action/ValueAppend.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute\Action;
|
||||
|
||||
use Picea\Ui\Method\FormContextInterface;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class ValueAppend extends \Lean\Api\Attribute\Action
|
||||
{
|
||||
public function action(EntityInterface $entity, string $key, FormContextInterface $context, string $field): ActionTypeEnum
|
||||
{
|
||||
dump($entity->$key);
|
||||
array_push($entity->$key, $context->$field);
|
||||
|
||||
return ActionTypeEnum::Setter;
|
||||
}
|
||||
}
|
||||
17
src/Attribute/Action/ValuePrepend.php
Normal file
17
src/Attribute/Action/ValuePrepend.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute\Action;
|
||||
|
||||
use Picea\Ui\Method\FormContextInterface;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class ValuePrepend extends \Lean\Api\Attribute\Action
|
||||
{
|
||||
public function action(EntityInterface $entity, string $key, FormContextInterface $context, string $field): ActionTypeEnum
|
||||
{
|
||||
array_unshift($entity->$key, $context->$field);
|
||||
|
||||
return ActionTypeEnum::Setter;
|
||||
}
|
||||
}
|
||||
17
src/Attribute/Action/ValueSet.php
Normal file
17
src/Attribute/Action/ValueSet.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute\Action;
|
||||
|
||||
use Picea\Ui\Method\FormContextInterface;
|
||||
use Ulmus\Entity\EntityInterface;
|
||||
|
||||
#[\Attribute(\Attribute::TARGET_PROPERTY)]
|
||||
class ValueSet extends \Lean\Api\Attribute\Action
|
||||
{
|
||||
public function action(EntityInterface $entity, string $key, FormContextInterface $context, string $field): ActionTypeEnum
|
||||
{
|
||||
$entity->$key = $context->$field;
|
||||
|
||||
return ActionTypeEnum::Setter;
|
||||
}
|
||||
}
|
||||
11
src/Attribute/ContextFieldActionEnum.php
Normal file
11
src/Attribute/ContextFieldActionEnum.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Attribute;
|
||||
|
||||
enum ContextFieldActionEnum: string
|
||||
{
|
||||
case Replace = "replace";
|
||||
case ArrayAppend = "array-append";
|
||||
case ArrayPrepend = "array-prepend";
|
||||
case Trim = "trim";
|
||||
}
|
||||
@ -28,7 +28,7 @@ use Psr\Http\Message\{ServerRequestInterface, ResponseInterface};
|
||||
#[color:gray, bg: black]║ ║[#]
|
||||
#[color:gray, bg: black]╚═══════════════════════════════════════════════════════════════════╝[#]
|
||||
|
||||
Try #[color:gray, bg: black]'lean api --help'[#] for more information.
|
||||
Try #[color:gray, bg: black]'cli lean-api --help'[#] for more information.
|
||||
CLI
|
||||
, command: 'lean-api')]
|
||||
#[Option(switch: ['-h', '--help'], description: "Display help for the given command. When no command is given display help for the list command")]
|
||||
|
||||
13
src/Entity/ArrayCollection.php
Normal file
13
src/Entity/ArrayCollection.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Entity;
|
||||
|
||||
use Picea\Ui\Method\Context\FormContextCastableInterface;
|
||||
|
||||
class ArrayCollection extends \Ulmus\Entity\ArrayCollection implements FormContextCastableInterface
|
||||
{
|
||||
public static function instance(mixed $value = [], null|string $entityClass = null) : self
|
||||
{
|
||||
return parent::instance($value, $entityClass);
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@ namespace Lean\Api\Form;
|
||||
use CSLSJ\Lean\Form\Session\EmailContext;
|
||||
use Picea\Ui\Method\{FormContext, FormContextInterface};
|
||||
|
||||
use Lean\Api\Attribute\ContextField;
|
||||
use Lean\Api\Attribute\{Action, Action\ActionTypeEnum, ContextField, Action\ValueSet};
|
||||
use Lean\Api\Exception\LeanApiException;
|
||||
use Lean\Api\Exception\MandatoryFieldException;
|
||||
use Lean\Api\Exception\MinimumLengthException;
|
||||
@ -130,29 +130,36 @@ abstract class Save extends Form implements \Picea\Ui\Method\FormInterface {
|
||||
|
||||
$apiField = $entityField[0]->object ;
|
||||
$var = $apiField->field ?: $key;
|
||||
$attr = $this->reflectedProperties($context)[$var] ?? false;
|
||||
|
||||
if ( property_exists($context, $var) && ( new \ReflectionProperty($context, $var) )->isInitialized($context) ) {
|
||||
$contextField = $attr ? $attr->getAttribute(ContextField::class) : null;
|
||||
|
||||
if ( property_exists($context, $var) && new \ReflectionProperty($context, $var)->isInitialized($context) ) {
|
||||
if ($apiField->setterMethod) {
|
||||
# Use a setter method
|
||||
call_user_func([ $entity, $apiField->setterMethod ], $context->{$var});
|
||||
}
|
||||
else {
|
||||
# Direct property set
|
||||
$entity->$key = $context->{$var};
|
||||
elseif($attr) {
|
||||
$actions = [];
|
||||
|
||||
foreach($attr->getAttributes(Action::class) as $item) {
|
||||
$actions[] = $item->object->action($entity, $key, $context, $var);
|
||||
}
|
||||
|
||||
if (! in_array(ActionTypeEnum::Setter, $actions)) {
|
||||
new ValueSet()->action($entity, $key, $context, $var);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
elseif (! $entity->isLoaded()) {
|
||||
elseif (! $entity->isLoaded() && $contextField) {
|
||||
# Applies 'default' value assigned to ContextField property
|
||||
$attr = $this->reflectedProperties($context)[$var] ?? null;
|
||||
|
||||
if ($attr) {
|
||||
$contextField = $attr->getAttribute(ContextField::class);
|
||||
|
||||
if ($contextField) {
|
||||
if (isset($contextField->object->default)) {
|
||||
|
||||
$entity->$key = $contextField->object->default;
|
||||
}
|
||||
if (isset($contextField->object->default)) {
|
||||
if (is_callable($contextField->object->default)) {
|
||||
$entity->$key = call_user_func_array($contextField->object->default, [ $context, ]);
|
||||
}
|
||||
else {
|
||||
$entity->$key = $contextField->object->default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,42 +10,41 @@ use Ulmus\Entity\EntityInterface;
|
||||
class FormContext extends \Picea\Ui\Method\FormContext {
|
||||
|
||||
public function __construct(
|
||||
protected LanguageHandler $languageHandler,
|
||||
protected MessageFactoryInterface $message,
|
||||
ServerRequestInterface $request,
|
||||
protected LanguageHandler $formLanguageHandler,
|
||||
protected MessageFactoryInterface $formMessage,
|
||||
ServerRequestInterface $formContextRequest,
|
||||
? string $formName = null
|
||||
)
|
||||
{
|
||||
parent::__construct($request, $formName);
|
||||
) {
|
||||
parent::__construct($formContextRequest, $formName);
|
||||
}
|
||||
|
||||
# public function initializeEntity(EntityInterface $entity) : void {}
|
||||
|
||||
public function lang(string $key, array $variables = [])
|
||||
{
|
||||
return $this->languageHandler->languageFromKey($key, $variables);
|
||||
return $this->formLanguageHandler->languageFromKey($key, $variables);
|
||||
}
|
||||
|
||||
public function pushSuccessMessage($key, $variables = []) : void {
|
||||
$this->pushMessage($this->message::generateSuccess(
|
||||
$this->pushMessage($this->formMessage::generateSuccess(
|
||||
$this->lang($key, $variables)
|
||||
));
|
||||
}
|
||||
|
||||
public function pushWarningMessage($key, $variables = []) : void {
|
||||
$this->pushMessage($this->message::generateWarning(
|
||||
$this->pushMessage($this->formMessage::generateWarning(
|
||||
$this->lang($key, $variables)
|
||||
));
|
||||
}
|
||||
|
||||
public function pushErrorMessage($key, $variables = []) : void {
|
||||
$this->pushMessage($this->message::generateError(
|
||||
$this->pushMessage($this->formMessage::generateError(
|
||||
$a = $this->lang($key, $variables)
|
||||
));
|
||||
}
|
||||
|
||||
public function pushInfoMessage($key, $variables = []) : void {
|
||||
$this->pushMessage($this->message::generateInfo(
|
||||
$this->pushMessage($this->formMessage::generateInfo(
|
||||
$this->lang($key, $variables)
|
||||
));
|
||||
}
|
||||
|
||||
93
src/Lib/RenderCORS.php
Normal file
93
src/Lib/RenderCORS.php
Normal file
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Lean\Api\Lib;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Ulmus\Api\Stream\Stream;
|
||||
|
||||
class RenderCORS
|
||||
{
|
||||
public function __construct(
|
||||
protected ServerRequestInterface $request,
|
||||
public string|array $origin = "http://localhost,https://localhost",
|
||||
public bool $allowCredentials = true,
|
||||
public string|array $methods = [ "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", ],
|
||||
public string|array $headers = [ "Content-Type", "Authorization", "X-Requested-With" ],
|
||||
) {
|
||||
if (is_string($this->origin)) {
|
||||
$this->origin = explode(',', $this->origin);
|
||||
}
|
||||
}
|
||||
|
||||
public function renderHeader(ServerRequestInterface $request) : void
|
||||
{
|
||||
$matched = $this->matchOrigin($this->request->getServerParams()['HTTP_ORIGIN'] ?? null, $this->origin);
|
||||
|
||||
if (! $matched) {
|
||||
return;
|
||||
}
|
||||
|
||||
$render = fn(string|array $e) => is_string($e) ? $e : sprintf('%s', implode(', ', $e));
|
||||
|
||||
header('Access-Control-Allow-Origin: ' . $matched);
|
||||
header(sprintf('Access-Control-Allow-Methods: %s', $render($this->methods)));
|
||||
header(sprintf('Access-Control-Allow-Headers: %s', $render($this->headers)));
|
||||
header('Access-Control-Allow-Credentials: ' . ($this->allowCredentials ? 'true' : 'false'));
|
||||
}
|
||||
|
||||
public function fromResponse(ResponseInterface $response, bool $emptyResponse = false) : ResponseInterface
|
||||
{
|
||||
$matched = $this->matchOrigin($this->request->getServerParams()['HTTP_ORIGIN'] ?? null, $this->origin);
|
||||
|
||||
if (! $matched) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$render = fn(string|array $e) => is_string($e) ? $e : sprintf('%s', implode(', ', $e));
|
||||
|
||||
$response = $response
|
||||
->withHeader('Access-Control-Allow-Origin', $matched)
|
||||
->withHeader('Access-Control-Allow-Methods', $render($this->methods))
|
||||
->withHeader('Access-Control-Allow-Headers', $render($this->headers))
|
||||
->withHeader('Access-Control-Allow-Credentials', $this->allowCredentials ? 'true' : 'false');
|
||||
|
||||
if ($emptyResponse) {
|
||||
$response = $response->withBody(Stream::fromMemory())->withStatus(200);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function matchOrigin(?string $origin, string|array $allowList): ?string
|
||||
{
|
||||
if ($origin === null || $origin === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ((array) $allowList as $rule) {
|
||||
if ($rule === '*') {
|
||||
return '*';
|
||||
}
|
||||
|
||||
// Regex rule: "/.../"
|
||||
if (is_string($rule) && strlen($rule) >= 2 && $rule[0] === '/' && substr($rule, -1) === '/') {
|
||||
if (@preg_match($rule, $origin) === 1) {
|
||||
return $origin;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exact match
|
||||
if (is_string($rule) && hash_equals($rule, $origin)) {
|
||||
return $origin;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,23 +2,20 @@
|
||||
|
||||
namespace Lean\Api\Middleware;
|
||||
|
||||
use Laminas\Diactoros\Response\JsonResponse;
|
||||
use Lean\Factory\HttpFactory;
|
||||
use Picea\Ui\Method\FormHandler;
|
||||
use Lean\Api\Lib\RenderCORS;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use Lean\Api\{Factory\DebugFormFactoryInterface, Form, Entity};
|
||||
|
||||
class CORS implements MiddlewareInterface {
|
||||
class CORS implements MiddlewareInterface
|
||||
{
|
||||
public function __construct(
|
||||
protected RenderCORS $cors,
|
||||
) {}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
|
||||
{
|
||||
if ($request->getMethod() === "option") {
|
||||
die("an option :)");
|
||||
}
|
||||
|
||||
return $handler->handle($request);
|
||||
return $this->cors->fromResponse($handler->handle($request));
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,47 +13,50 @@
|
||||
<div class='description'>{{ $form['description'] }}</div>
|
||||
<hr style="margin-top:15px">
|
||||
|
||||
{% if $form['fields'] %}
|
||||
<div class="fields-wrapper">
|
||||
<div class="header-fields">Champs</div>
|
||||
|
||||
<div class="fields-wrapper">
|
||||
<div class="header-fields">Champs</div>
|
||||
|
||||
<ol class='fields'>
|
||||
{% foreach $form['fields'] as $field %}
|
||||
<li class="odd-even">
|
||||
<div class="title">
|
||||
<div>
|
||||
<strong style="font-family:monospace">{{ $field['name'] }} {% if $field['mandatory'] %}<span style="color:red">*</span>{% endif %}</strong>
|
||||
<span style='margin-left:15px'>{{ $field['description'] }}</span>
|
||||
<ol class='fields'>
|
||||
{% foreach $form['fields'] as $field %}
|
||||
<li class="odd-even">
|
||||
<div class="title">
|
||||
<div>
|
||||
<strong style="font-family:monospace">{{ $field['name'] }} {% if $field['mandatory'] %}<span style="color:red">*</span>{% endif %}</strong>
|
||||
<span style='margin-left:15px'>{{ $field['description'] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
|
||||
<div><u>Variable POST / champ JSON</u> : {{ $field['name'] }}</div>
|
||||
<div><u>Type(s)</u> : {{ implode(' | ', array_map(fn($e) => $e->type, $field['type'])) }}</div>
|
||||
<div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
|
||||
{% if $field['regexPattern'] !== null %}
|
||||
<div><u>Pattern regex</u> : {{ $field['regexPattern'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['minLength'] !== null %}
|
||||
<div><u>Taille min.</u> : {{ $field['minLength'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['maxLength'] !== null %}
|
||||
<div><u>Taille max.</u> : {{ $field['maxLength'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['example'] !== null || $field['values'] %}
|
||||
<div><u>Exemple</u> : {{ $field['example'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['default'] !== null %}
|
||||
<div><u>Valeur par défaut</u> : {{ $field['default'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['values'] %}
|
||||
<div><u>Valeurs possibles</u> : [ <u class="enum-value">{{= implode('</u><u class="enum-value">', $field['values']) }}</u> ]</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endforeach %}
|
||||
</ol>
|
||||
</div>
|
||||
<div class="field-desc" style="margin-top:10px;;background:#fff;padding:5px;font-size:0.9em">
|
||||
<div><u>Variable POST / champ JSON</u> : {{ $field['name'] }}</div>
|
||||
<div><u>Type(s)</u> : {{ implode(' | ', array_map(fn($e) => $e->type, $field['type'])) }}</div>
|
||||
<div><u>Nullable</u> : {{ yesOrNo($field['allowNulls']) }}</div>
|
||||
{% if $field['regexPattern'] !== null %}
|
||||
<div><u>Pattern regex</u> : {{ $field['regexPattern'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['minLength'] !== null %}
|
||||
<div><u>Taille min.</u> : {{ $field['minLength'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['maxLength'] !== null %}
|
||||
<div><u>Taille max.</u> : {{ $field['maxLength'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['example'] !== null || $field['values'] %}
|
||||
<div><u>Exemple</u> : {{ $field['example'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['default'] !== null %}
|
||||
<div><u>Valeur par défaut</u> : {{ $field['default'] }}</div>
|
||||
{% endif %}
|
||||
{% if $field['values'] %}
|
||||
<div><u>Valeurs possibles</u> : [ <u class="enum-value">{{= implode('</u><u class="enum-value">', $field['values']) }}</u> ]</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</li>
|
||||
{% endforeach %}
|
||||
</ol>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty">Aucun champ adressable pour ce context</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% or %}
|
||||
<i style="color:#585858; padding:0 12px">{% _ "none" %}</i>
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
|
||||
h2 + p {font-family: monospace, serif;font-size: 0.9rem;}
|
||||
.hide {display:none!important}
|
||||
.empty {font-size:0.9rem; color:gray; text-align:center; line-height:2.5rem; background: rgba(0, 0, 0, 0.07); margin:0 0 10px 0}
|
||||
|
||||
ul {background:#f4f4f4; list-style: none; padding-left:20px}
|
||||
ul ul {margin: 0;border: 0;padding: 5px 30px;}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user