add node ang page edition

This commit is contained in:
Simon Vieille 2021-03-19 12:10:52 +01:00
parent 023e6aec06
commit 237b105289
23 changed files with 583 additions and 25 deletions

View file

@ -17,4 +17,5 @@ return [
Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true], Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle::class => ['all' => true],
Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true], Scheb\TwoFactorBundle\SchebTwoFactorBundle::class => ['all' => true],
Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
App\Bundle\AppBundle::class => ['all' => true],
]; ];

8
config/packages/app.yaml Normal file
View file

@ -0,0 +1,8 @@
app:
site:
pages:
App\Site\Page\SimplePage:
name: 'Page simple'
templates:
- {name: "Template 1", file: "site/page/simple/page.html.twig"}
- {name: "Template 2", file: "site/page/simple/page2.html.twig"}

View file

@ -16,11 +16,11 @@ doctrine:
dir: '%kernel.project_dir%/src/Entity' dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity' prefix: 'App\Entity'
alias: App\Entity alias: App\Entity
App\Page: App\Site\Page:
is_bundle: false is_bundle: false
type: annotation type: annotation
dir: '%kernel.project_dir%/src/Page' dir: '%kernel.project_dir%/src/Site/Page'
prefix: 'App\Page' prefix: 'App\Site\Page'
gedmo_tree: gedmo_tree:
type: annotation type: annotation
prefix: Gedmo\Tree\Entity prefix: Gedmo\Tree\Entity

24
src/Bundle/AppBundle.php Normal file
View file

@ -0,0 +1,24 @@
<?php
/*
* This file is part of Twig.
*
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use App\DependencyInjection\AppExtension;
class AppBundle extends Bundle
{
public function getContainerExtension()
{
return new AppExtension();
}
}

View file

@ -16,6 +16,9 @@ use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use App\Site\PageLocator;
use App\Factory\Site\Page\PageFactory;
use App\Entity\Site\Page\Page;
/** /**
* @Route("/admin/site/node") * @Route("/admin/site/node")
@ -28,12 +31,16 @@ class NodeAdminController extends AdminController
public function new( public function new(
Node $node, Node $node,
EntityFactory $factory, EntityFactory $factory,
PageFactory $pageFactory,
EntityManager $entityManager, EntityManager $entityManager,
NodeRepository $nodeRepository, NodeRepository $nodeRepository,
PageLocator $pageLocator,
Request $request Request $request
): Response { ): Response {
$entity = $factory->create($node->getMenu()); $entity = $factory->create($node->getMenu());
$form = $this->createForm(EntityType::class, $entity); $form = $this->createForm(EntityType::class, $entity, [
'pages' => $pageLocator->getPages(),
]);
if ($request->isMethod('POST')) { if ($request->isMethod('POST')) {
$form->handleRequest($request); $form->handleRequest($request);
@ -46,17 +53,24 @@ class NodeAdminController extends AdminController
if ('above' === $position) { if ('above' === $position) {
$nodeRepository->persistAsLastChild($entity, $node); $nodeRepository->persistAsLastChild($entity, $node);
$entityManager->flush();
} else { } else {
if ('after' === $position) { if ('after' === $position) {
$nodeRepository->persistAsNextSiblingOf($entity, $node); $nodeRepository->persistAsNextSiblingOf($entity, $node);
} elseif ('before' === $position) { } elseif ('before' === $position) {
$nodeRepository->persistAsPrevSiblingOf($entity, $node); $nodeRepository->persistAsPrevSiblingOf($entity, $node);
} }
$entityManager->flush();
} }
$this->handlePageAssociation(
$form->get('pageAction')->getData(),
$form->get('pageEntity')->getData(),
$form->get('pageType')->getData(),
$entity,
$pageFactory
);
$entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.'); $this->addFlash('success', 'Donnée enregistrée.');
} else { } else {
$this->addFlash('warning', 'Le formulaire est invalide.'); $this->addFlash('warning', 'Le formulaire est invalide.');
@ -77,13 +91,29 @@ class NodeAdminController extends AdminController
/** /**
* @Route("/edit/{entity}", name="admin_site_node_edit") * @Route("/edit/{entity}", name="admin_site_node_edit")
*/ */
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response { public function edit(
$form = $this->createForm(EntityType::class, $entity); Entity $entity,
EntityManager $entityManager,
PageFactory $pageFactory,
PageLocator $pageLocator,
Request $request
): Response {
$form = $this->createForm(EntityType::class, $entity, [
'pages' => $pageLocator->getPages(),
]);
if ($request->isMethod('POST')) { if ($request->isMethod('POST')) {
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isValid()) { if ($form->isValid()) {
$this->handlePageAssociation(
$form->get('pageAction')->getData(),
$form->get('pageEntity')->getData(),
$form->get('pageType')->getData(),
$entity,
$pageFactory
);
$entityManager->update($entity); $entityManager->update($entity);
$this->addFlash('success', 'Donnée enregistrée.'); $this->addFlash('success', 'Donnée enregistrée.');
@ -102,6 +132,28 @@ class NodeAdminController extends AdminController
]); ]);
} }
protected function handlePageAssociation(
string $pageAction,
?Page $pageEntity,
string $pageType,
Entity $entity,
PageFactory $pageFactory
)
{
if ($pageAction === 'new') {
$page = $pageFactory->create($pageType, $entity->getLabel());
$entity->setPage($page);
} elseif ($pageAction === 'existing') {
if ($pageEntity) {
$entity->setPage($pageEntity);
} else {
$this->addFlash('info', 'Aucun changement de page effectué.');
}
} elseif ($pageAction === 'none') {
$entity->setPage(null);
}
}
/** /**
* @Route("/move/{entity}", name="admin_site_node_move") * @Route("/move/{entity}", name="admin_site_node_move")
*/ */

View file

@ -47,11 +47,6 @@ class PageAdminController extends AdminController
EntityRepositoryQuery $repositoryQuery, EntityRepositoryQuery $repositoryQuery,
Request $request Request $request
): Response { ): Response {
// $page = $factory->create(PageFoo::class);
// $page->setName('Page de test 2');
// $entityManager->update($page);
// die;
$entity = $repositoryQuery->filterById($entity)->findOne(); $entity = $repositoryQuery->filterById($entity)->findOne();
$form = $this->createForm(EntityType::class, $entity); $form = $this->createForm(EntityType::class, $entity);
@ -77,6 +72,20 @@ class PageAdminController extends AdminController
]); ]);
} }
/**
* @Route("/delete/{entity}", name="admin_site_page_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
$entityManager->delete($entity);
$this->addFlash('success', 'Données supprimée..');
}
return $this->redirectToRoute('admin_site_tree_index');
}
public function getSection(): string public function getSection(): string
{ {
return ''; return '';

View file

@ -0,0 +1,29 @@
<?php
namespace App\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use App\DependencyInjection\Configuration;
class AppExtension extends Extension
{
/**
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('app', $config);
}
/**
* {@inheritDoc}
*/
public function getConfiguration(array $configs, ContainerBuilder $container)
{
return new Configuration();
}
}

View file

@ -0,0 +1,44 @@
<?php
namespace App\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('app');
$treeBuilder->getRootNode()
->children()
->arrayNode('site')
->children()
->arrayNode('pages')
->prototype('array')
->children()
->scalarNode('name')
->isRequired()
->cannotBeEmpty()
->end()
->arrayNode('templates')
->prototype('array')
->children()
->scalarNode('name')
->cannotBeEmpty()
->end()
->scalarNode('file')
->cannotBeEmpty()
->end()
->end()
->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}

View file

@ -4,6 +4,7 @@ namespace App\Entity\Site;
use App\Doctrine\Timestampable; use App\Doctrine\Timestampable;
use App\Entity\EntityInterface; use App\Entity\EntityInterface;
use App\Entity\Site\Page\Page;
use App\Repository\Site\NodeRepository; use App\Repository\Site\NodeRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
@ -85,6 +86,12 @@ class Node implements EntityInterface
*/ */
private $children; private $children;
/**
* @ORM\ManyToOne(targetEntity=Page::class, inversedBy="nodes", cascade={"persist"})
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $page;
public function __construct() public function __construct()
{ {
$this->children = new ArrayCollection(); $this->children = new ArrayCollection();
@ -260,4 +267,16 @@ class Node implements EntityInterface
return trim($prefix.' '.$this->getLabel()); return trim($prefix.' '.$this->getLabel());
} }
public function getPage(): ?Page
{
return $this->page;
}
public function setPage(?Page $page): self
{
$this->page = $page;
return $this;
}
} }

View file

@ -33,6 +33,7 @@ class Block
/** /**
* @ORM\ManyToOne(targetEntity=Page::class, inversedBy="blocks") * @ORM\ManyToOne(targetEntity=Page::class, inversedBy="blocks")
* @ORM\JoinColumn(onDelete="CASCADE")
*/ */
private $page; private $page;

View file

@ -4,6 +4,7 @@ namespace App\Entity\Site\Page;
use App\Doctrine\Timestampable; use App\Doctrine\Timestampable;
use App\Entity\EntityInterface; use App\Entity\EntityInterface;
use App\Entity\Site\Node;
use App\Repository\Site\Page\PageRepository; use App\Repository\Site\Page\PageRepository;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection; use Doctrine\Common\Collections\Collection;
@ -62,9 +63,15 @@ class Page implements EntityInterface
*/ */
private $ogDescription; private $ogDescription;
/**
* @ORM\OneToMany(targetEntity=Node::class, mappedBy="page")
*/
private $nodes;
public function __construct() public function __construct()
{ {
$this->blocks = new ArrayCollection(); $this->blocks = new ArrayCollection();
$this->nodes = new ArrayCollection();
} }
public function getId(): ?int public function getId(): ?int
@ -208,4 +215,34 @@ class Page implements EntityInterface
return $this; return $this;
} }
/**
* @return Collection|Node[]
*/
public function getNodes(): Collection
{
return $this->nodes;
}
public function addNode(Node $node): self
{
if (!$this->nodes->contains($node)) {
$this->nodes[] = $node;
$node->setPage($this);
}
return $this;
}
public function removeNode(Node $node): self
{
if ($this->nodes->removeElement($node)) {
// set the owning side to null (unless already changed)
if ($node->getPage() === $this) {
$node->setPage(null);
}
}
return $this;
}
} }

View file

@ -11,8 +11,11 @@ use App\Entity\Site\Page\Page;
*/ */
class PageFactory class PageFactory
{ {
public function create(string $className): Page public function create(string $className, string $name): Page
{ {
return new $className(); $entity = new $className();
$entity->setName($name);
return $entity;
} }
} }

View file

@ -9,6 +9,9 @@ use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotBlank;
use App\Entity\Site\Page\Page;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Doctrine\ORM\EntityRepository;
class NodeType extends AbstractType class NodeType extends AbstractType
{ {
@ -42,6 +45,73 @@ class NodeType extends AbstractType
] ]
); );
$actions = [
'Nouvelle page' => 'new',
'Associer à une page existante' => 'existing',
'Aucune page' => 'none',
];
if ($builder->getData()->getId()) {
$actions['Garder la configuration actuelle'] = 'keep';
}
$builder->add(
'pageAction',
ChoiceType::class,
[
'label' => false,
'required' => true,
'expanded' => true,
'mapped' => false,
'choices' => $actions,
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'pageType',
ChoiceType::class,
[
'label' => false,
'required' => true,
'mapped' => false,
'choices' => call_user_func(function() use ($options) {
$choices = [];
foreach ($options['pages'] as $page) {
$choices[$page->getName()] = $page->getClassName();
}
return $choices;
}),
'constraints' => [
new NotBlank(),
],
]
);
$builder->add(
'pageEntity',
EntityType::class,
[
'label' => false,
'required' => true,
'mapped' => false,
'class' => Page::class,
'choice_label' => 'name',
'query_builder' => function (EntityRepository $repo) {
return $repo->createQueryBuilder('p')
->orderBy('p.name', 'ASC')
;
},
'constraints' => [
new NotBlank(),
],
]
);
if ($builder->getData()->getId() === null) { if ($builder->getData()->getId() === null) {
$builder->add( $builder->add(
'position', 'position',
@ -69,7 +139,7 @@ class NodeType extends AbstractType
{ {
$resolver->setDefaults([ $resolver->setDefaults([
'data_class' => Node::class, 'data_class' => Node::class,
'pages' => null, 'pages' => [],
]); ]);
} }
} }

View file

@ -7,11 +7,26 @@ use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
class PageType extends AbstractType class PageType extends AbstractType
{ {
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder->add(
'name',
TextType::class,
[
'label' => 'Nom',
'required' => true,
'attr' => [
],
'constraints' => [
new NotBlank(),
],
]
);
$builder->add( $builder->add(
'metaTitle', 'metaTitle',
TextType::class, TextType::class,

View file

@ -1,6 +1,6 @@
<?php <?php
namespace App\Page; namespace App\Site\Page;
use App\Entity\Site\Page\Block; use App\Entity\Site\Page\Block;
use App\Entity\Site\Page\Page; use App\Entity\Site\Page\Page;

View file

@ -0,0 +1,51 @@
<?php
namespace App\Site;
/**
* class PageConfiguration.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageConfiguration
{
protected string $className;
protected string $name;
protected array $templates;
public function setClassName(string $className): self
{
$this->className = $className;
return $this;
}
public function getClassName(): string
{
return $this->className;
}
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
public function getName(): string
{
return $this->name;
}
public function setTemplates(array $templates): self
{
$this->templates = $templates;
return $this;
}
public function getTemplates(): array
{
return $this->templates;
}
}

48
src/Site/PageLocator.php Normal file
View file

@ -0,0 +1,48 @@
<?php
namespace App\Site;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* class PageLocator.
*
* @author Simon Vieille <simon@deblan.fr>
*/
class PageLocator
{
protected array $params;
protected array $pages;
public function __construct(ParameterBagInterface $bag)
{
$this->params = $bag->get('app');
$this->loadPages();
}
protected function loadPages(): void
{
$params = $this->params['site']['pages'] ?? [];
foreach ($params as $className => $conf) {
$pageConfiguration = new PageConfiguration();
$pageConfiguration
->setClassName($className)
->setName($conf['name'])
->setTemplates($conf['templates'])
;
$this->pages[$className] = $pageConfiguration;
}
}
public function getPages(): array
{
return $this->pages;
}
public function getPage($className)
{
return $this->pages[$className] ?? null;
}
}

View file

@ -0,0 +1,108 @@
{{ form_row(form.label) }}
{{ form_row(form.url) }}
{% if form.position is defined %}
{{ form_row(form.position) }}
{% endif %}
<div class="accordion" id="node-page-action">
<div class="card">
{% set action = form.pageAction[0] %}
{% set options = not entity.id ? {'attr': {'checked': 'checked'}} : {} %}
<div class="card-header p-0">
<h2 class="mb-0">
<label class="btn btn-link btn-block text-left"
for="{{ action.vars.id }}"
data-toggle="collapse"
data-target="#form-node-page-action-new">
{{ action.vars.label }}
</label>
<div class="d-none">
{{ form_row(action, options) }}
</div>
</h2>
</div>
<div id="form-node-page-action-new" class="collapse {% if not entity.id %}show{% endif %}" data-parent="#node-page-action">
<div class="card-body">
{{ form_row(form.pageType) }}
</div>
</div>
</div>
<div class="card">
{% set action = form.pageAction[1] %}
<div class="card-header p-0">
<h2 class="mb-0">
<label class="btn btn-link btn-block text-left"
for="{{ action.vars.id }}"
data-toggle="collapse"
data-target="#form-node-page-action-existing">
{{ action.vars.label }}
</label>
<div class="d-none">
{{ form_row(action) }}
</div>
</h2>
</div>
<div id="form-node-page-action-existing" class="collapse" data-parent="#node-page-action">
<div class="card-body">
{{ form_row(form.pageEntity) }}
</div>
</div>
</div>
<div class="card">
{% set action = form.pageAction[2] %}
<div class="card-header p-0">
<h2 class="mb-0">
<label class="btn btn-link btn-block text-left"
for="{{ action.vars.id }}"
data-toggle="collapse"
data-target="#form-node-page-action-none">
{{ action.vars.label }}
</label>
<div class="d-none">
{{ form_row(action) }}
</div>
</h2>
</div>
<div id="form-node-page-action-none" class="collapse" data-parent="#node-page-action">
<div class="card-body">
Aucune action
</div>
</div>
</div>
{% if entity.id %}
<div class="card">
{% set action = form.pageAction[3] %}
{% set options = {'attr': {'checked': 'checked'}} %}
<div class="card-header p-0">
<h2 class="mb-0">
<label class="btn btn-link btn-block text-left"
for="{{ action.vars.id }}"
data-toggle="collapse"
data-target="#form-node-page-action-keep">
{{ action.vars.label }}
</label>
<div class="d-none">
{{ form_row(action, options) }}
</div>
</h2>
</div>
<div id="form-node-page-action-keep" class="collapse show" data-parent="#node-page-action">
<div class="card-body">
Aucune action
</div>
</div>
</div>
{% endif %}
</div>
{{ form_rest(form) }}

View file

@ -8,7 +8,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="{{ path('admin_site_node_edit', {entity: entity.id}) }}" id="form-node-edit" method="POST"> <form action="{{ path('admin_site_node_edit', {entity: entity.id}) }}" id="form-node-edit" method="POST">
{{ form_widget(form) }} {{ include('site/node_admin/_form.html.twig') }}
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View file

@ -8,7 +8,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form action="{{ path('admin_site_node_new', {node: node.id}) }}" id="form-node-new" method="POST"> <form action="{{ path('admin_site_node_new', {node: node.id}) }}" id="form-node-new" method="POST">
{{ form_widget(form) }} {{ include('site/node_admin/_form.html.twig') }}
</form> </form>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View file

@ -10,6 +10,12 @@
{% endfor %} {% endfor %}
{% endset %} {% endset %}
{% set formOthers %}
{% for item in ['name'] %}
{{ form_row(form[item]) }}
{% endfor %}
{% endset %}
{% set formSitemap %} {% set formSitemap %}
{% endset %} {% endset %}
@ -25,6 +31,9 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#form-page-og">OpenGraph</a> <a class="nav-link" data-toggle="tab" href="#form-page-og">OpenGraph</a>
</li> </li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#form-page-others">Autres</a>
</li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
@ -34,7 +43,9 @@
<div class="tab-pane p-3" id="form-page-og"> <div class="tab-pane p-3" id="form-page-og">
{{ formOpenGraph|raw }} {{ formOpenGraph|raw }}
</div> </div>
<div class="tab-pane p-3" id="form-page-others">
{{ formOthers|raw }}
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -13,6 +13,17 @@
<span class="fa fa-save pr-1"></span> <span class="fa fa-save pr-1"></span>
Enregistrer Enregistrer
</button> </button>
<button type="button" class="btn btn-white dropdown-toggle dropdown-toggle-hide-after" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="font-weight-bold">
⋅⋅⋅
</span>
</button>
<div class="dropdown-menu dropdown-menu-right">
<button type="submit" form="form-delete" class="dropdown-item">
Supprimer
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -29,4 +40,9 @@
{{ form_rest(form) }} {{ form_rest(form) }}
</form> </form>
<form method="post" action="{{ path('admin_site_page_delete', {entity: entity.id}) }}" id="form-delete" data-form-confirm>
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ entity.id) }}">
</form>
{% endblock %} {% endblock %}

View file

@ -70,30 +70,42 @@
{% set move = path('admin_site_node_move', {entity: node.id}) %} {% set move = path('admin_site_node_move', {entity: node.id}) %}
{% set edit = path('admin_site_node_edit', {entity: node.id}) %} {% set edit = path('admin_site_node_edit', {entity: node.id}) %}
{% set new = path('admin_site_node_new', {node: node.id}) %} {% set new = path('admin_site_node_new', {node: node.id}) %}
<div class="list-group-item"> <div class="list-group-item">
<div class="float-right"> <div class="float-right">
{% if node.page %}
<a href="{{ path('admin_site_page_edit', {entity: node.page.id}) }}" class="btn btn-sm btn-warning text-white mr-1">
<span class="fa fa-file-alt"></span>
Page
</a>
{% endif %}
<button data-modal="{{ edit }}" type="submit" class="btn btn-sm btn-success mr-1"> <button data-modal="{{ edit }}" type="submit" class="btn btn-sm btn-success mr-1">
<span data-modal="{{ edit }}" class="fa fa-pen"></span> <span data-modal="{{ edit }}" class="fa fa-pen"></span>
</button> Éditer
<button data-modal="{{ move }}" type="submit" class="btn btn-sm btn-dark mr-1">
<span data-modal="{{ move }}" class="fa fa-arrows-alt"></span>
</button> </button>
<button type="submit" form="form-node-visibility-{{ node.id }}" class="btn btn-sm btn-light border-dark mr-1"> <button type="submit" form="form-node-visibility-{{ node.id }}" class="btn btn-sm btn-light border-dark mr-1">
{% if node.isVisible %} {% if node.isVisible %}
<span class="fa fa-eye"></span> <span class="fa fa-eye"></span>
Visible
{% else %} {% else %}
<span class="fa fa-eye-slash"></span> <span class="fa fa-eye-slash"></span>
Caché
{% endif %} {% endif %}
</button> </button>
<button data-modal="{{ move }}" type="submit" class="btn btn-sm btn-dark mr-1">
<span data-modal="{{ move }}" class="fa fa-arrows-alt"></span>
</button>
<button data-modal="{{ new }}" type="submit" class="btn btn-sm btn-primary mr-1"> <button data-modal="{{ new }}" type="submit" class="btn btn-sm btn-primary mr-1">
<span data-modal="{{ new }}" class="fa fa-plus"></span> <span data-modal="{{ new }}" class="fa fa-plus"></span>
</button> </button>
<button type="submit" form="form-node-delete-{{ node.id }}" class="btn btn-sm btn-danger"> <button type="submit" form="form-node-delete-{{ node.id }}" class="btn btn-sm btn-danger">
<span class="fa fa-trash"></span> <span class="fa fa-trash"></span>
Supprimer
</button> </button>
</div> </div>