backports murph-skeleton

This commit is contained in:
Simon Vieille 2021-09-09 13:57:54 +02:00
parent 3bf661d059
commit f1fce6d6db
23 changed files with 175 additions and 56 deletions

View File

@ -54,6 +54,7 @@ export default {
}
if (['image/png', 'image/jpg', 'image/jpeg', 'image/gif'].indexOf(this.mime) === -1) {
this.thumbnail = null
return
}

View File

@ -5,6 +5,11 @@
<li class="breadcrumb-item" v-for="item in breadcrumb">
<a class="btn btn-sm" href="#" v-on:click="setDirectory(item.path)" v-html="item.label"></a>
</li>
<li v-if="isLoading" class="ml-3">
<div class="spinner-border spinner-border-sm" role="status">
<span class="sr-only">Loading...</span>
</div>
</li>
</ol>
<div class="d-flex">
@ -200,7 +205,8 @@ export default {
files: [],
parent: null,
modalUrl: null,
ajax: 0
ajax: 0,
isLoading: false
}
},
methods: {
@ -266,17 +272,22 @@ export default {
},
refresh () {
const that = this
this.isLoading = true
this.files = []
this.directories = []
axios.get(Routing.generate('admin_file_manager_api_directory', {
directory: that.directory,
context: that.context,
ajax: this.ajax
ajax: this.ajax,
time: Date.now(),
}))
.then((response) => {
that.buildBreadcrum(response.data.breadcrumb)
that.parent = response.data.parent
that.directories = response.data.directories
that.files = response.data.files
that.isLoading = false
const query = new URLSearchParams(window.location.search)
query.set('path', that.directory)

View File

@ -64,8 +64,19 @@ module.exports = function () {
fileManagerBrowser((value) => {
value = value.replace(/^\//, '')
picker.parent('.form-filepicker-container').find('input.form-filepicker-picker').val(value)
picker.parents('.form-filepicker-container').find('input.form-filepicker-picker').val(value)
input.val(value)
})
})
$('body').on('click', '.form-filepicker-reset', (e) => {
e.preventDefault()
const button = $(e.target)
const id = '#' + button.attr('data-target')
const input = $(id)
input.val('')
button.parents('.form-filepicker-container').find('input.form-filepicker-picker').val('')
})
}

View File

@ -25,8 +25,15 @@ const openModal = function (url) {
module.exports = function () {
let click = 0
const body = $('body')
$('body').on('click', '*[data-modal]', (e) => {
body.on('hidden.bs.modal', '.modal', (e) => {
if ($('.modal.show').length) {
$('body').addClass('modal-open')
}
})
body.on('click', '*[data-modal]', (e) => {
e.preventDefault()
e.stopPropagation()

View File

@ -15,6 +15,8 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
use App\Core\Event\Page\PageEditEvent;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class PageAdminController extends CrudController
{
@ -50,12 +52,17 @@ class PageAdminController extends CrudController
EntityManager $entityManager,
RepositoryQuery $repositoryQuery,
PageLocator $pageLocator,
EventDispatcherInterface $eventDispatcher,
Request $request
): Response {
$entity = $repositoryQuery->filterById($entity)->findOne();
$event = new PageEditEvent($entity);
$eventDispatcher->dispatch($event, PageEditEvent::FORM_INIT_EVENT);
$this->getConfiguration()->setFormOptions('edit', [
'pageConfiguration' => $pageLocator->getPage(get_class($entity)),
'page_configuration' => $pageLocator->getPage(get_class($entity)),
'page_builder_options' => $event->getPageBuilderOptions(),
]);
return $this->doEdit($entity, $entityManager, $request);

View File

@ -28,6 +28,7 @@ class CrudConfiguration
protected array $isSortableCollection = [];
protected string $sortableCollectionProperty = 'sortOrder';
protected ?string $defaultLocale = null;
protected bool $showActions = true;
protected static $self;
@ -314,4 +315,16 @@ class CrudConfiguration
{
return $this->sortableCollectionProperty;
}
public function setShowActions(bool $showActions): self
{
$this->showActions = $showActions;
return $this;
}
public function getShowActions(): bool
{
return $this->showActions;
}
}

View File

@ -36,7 +36,7 @@ class FileInformation implements EntityInterface
public function getAttributes()
{
return json_decode($this->attributes, true);
return (array) json_decode($this->attributes, true);
}
public function setAttributes($attributes): self

View File

@ -225,12 +225,30 @@ class Node implements EntityInterface
/**
* @return Collection|Node[]
*/
public function getChildren(): Collection
public function getChildren(array $criteria = []): Collection
{
if (null === $this->children) {
$this->children = new ArrayCollection();
}
if (!empty($criteria)) {
$children = new ArrayCollection();
foreach ($this->children as $child) {
$add = true;
if (isset($criteria['visible']) && $child->getIsVisible() !== $criteria['visible']) {
$add = false;
}
if ($add) {
$children->add($child);
}
}
return $children;
}
return $this->children;
}
@ -256,7 +274,7 @@ class Node implements EntityInterface
return $this;
}
public function getAllChildren(): ArrayCollection
public function getAllChildren(array $criteria = []): ArrayCollection
{
$children = [];
@ -274,6 +292,14 @@ class Node implements EntityInterface
return $a->getTreeLeft() < $b->getTreeLeft() ? -1 : 1;
});
if (!empty($criteria)) {
foreach ($children as $key => $child) {
if (isset($criteria['visible']) && $child->getIsVisible() !== $criteria['visible']) {
unset($children[$key]);
}
}
}
return new ArrayCollection($children);
}
@ -308,6 +334,19 @@ class Node implements EntityInterface
return $string->startsWith('http://') || $string->startsWith('https://');
}
public function hasAppUrl(): bool
{
$string = u($this->getUrl());
foreach (['tel:', 'fax:', 'mailto:'] as $prefix) {
if ($string->startsWith($prefix)) {
return true;
}
}
return false;
}
public function getIsVisible(): ?bool
{
return $this->isVisible;

View File

@ -140,7 +140,7 @@ class Page implements EntityInterface
return $this;
}
public function buildForm(FormBuilderInterface $builder)
public function buildForm(FormBuilderInterface $builder, array $options)
{
}

View File

@ -133,7 +133,13 @@ class NodeEventSubscriber extends EntityManagerEventSubscriber
$generatedUrl = $generatedUrl.'-'.$number;
}
if (!u($generatedUrl)->startsWith('https://') && !u($generatedUrl)->startsWith('http://')) {
if (
!u($generatedUrl)->startsWith('https://')
&& !u($generatedUrl)->startsWith('http://')
&& !u($generatedUrl)->startsWith('tel:')
&& !u($generatedUrl)->startsWith('mailto:')
&& !u($generatedUrl)->startsWith('fax:')
) {
$generatedUrl = '/'.$generatedUrl;
$generatedUrl = preg_replace('#/{2,}#', '/', $generatedUrl);
}

View File

@ -16,7 +16,7 @@ class CollectionBlockType extends AbstractType
{
$builder->add(
'value',
CollectionType::class,
$options['collection_type'],
array_merge([
'required' => false,
'label' => false,
@ -40,6 +40,7 @@ class CollectionBlockType extends AbstractType
{
$resolver->setDefaults([
'data_class' => Block::class,
'collection_type' => CollectionType::class,
'collection_name' => '',
'label_add' => 'Add',
'label_delete' => 'Delete',

View File

@ -105,7 +105,7 @@ class PageType extends AbstractType
'choices' => call_user_func(function () use ($options) {
$choices = [];
foreach ($options['pageConfiguration']->getTemplates() as $template) {
foreach ($options['page_configuration']->getTemplates() as $template) {
$choices[$template['name']] = $template['file'];
}
@ -119,14 +119,15 @@ class PageType extends AbstractType
]
);
$builder->getData()->buildForm($builder);
$builder->getData()->buildForm($builder, $options['page_builder_options']);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Page::class,
'pageConfiguration' => null,
'page_configuration' => null,
'page_builder_options' => [],
]);
}
}

View File

@ -71,6 +71,7 @@
"Page": "Page"
"Administration": "Administration"
"Users": "Utilisateurs"
"New user": "Nouvel utilisateur⋅trice"
"Back to the list": "Retour à la liste"
"Edit": "Éditer"
"New password": "Nouveau mot de passe"

View File

@ -139,9 +139,11 @@
</th>
{% endblock %}
{% endfor %}
<th class="crud-action-column col-2 miw-100 text-right">
{{ 'Actions'|trans }}
</th>
{% if configuration.showActions %}
<th class="crud-action-column col-2 miw-100 text-right">
{{ 'Actions'|trans }}
</th>
{% endif %}
</tr>
</thead>
{% endblock %}
@ -205,34 +207,36 @@
</td>
{% endfor %}
<td class="crud-action-column col-2 miw-200 text-right">
{% block list_item_actions_before %}{% endblock %}
{% if configuration.showActions %}
<td class="crud-action-column col-2 miw-200 text-right">
{% block list_item_actions_before %}{% endblock %}
{% if configuration.action(context, 'show', true) %}
<a href="{{ path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }}" class="btn btn-sm btn-secondary mr-1">
<span class="fa fa-eye"></span>
</a>
{% endif %}
{% if configuration.action(context, 'show', true) %}
<a href="{{ path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }}" class="btn btn-sm btn-secondary mr-1">
<span class="fa fa-eye"></span>
</a>
{% endif %}
{% if configuration.action(context, 'edit', true) %}
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('edit'))) }}" class="btn btn-sm btn-primary mr-1">
<span class="fa fa-edit"></span>
</a>
{% endif %}
{% if configuration.action(context, 'edit', true) %}
<a href="{{ path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('edit'))) }}" class="btn btn-sm btn-primary mr-1">
<span class="fa fa-edit"></span>
</a>
{% endif %}
{% if configuration.action(context, 'delete', true) %}
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
<span class="fa fa-trash"></span>
</button>
{% if configuration.action(context, 'delete', true) %}
<button type="submit" form="form-delete-{{ item.id }}" class="btn btn-sm btn-danger">
<span class="fa fa-trash"></span>
</button>
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: item.id}|merge(configuration.pageRouteParams('delete'))) }}" id="form-delete-{{ item.id }}" data-form-confirm>
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
</form>
{% endif %}
<form method="post" action="{{ path(configuration.pageRoute('delete'), {entity: item.id}|merge(configuration.pageRouteParams('delete'))) }}" id="form-delete-{{ item.id }}" data-form-confirm>
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token('delete' ~ item.id) }}">
</form>
{% endif %}
{% block list_item_actions_after %}{% endblock %}
</td>
{% block list_item_actions_after %}{% endblock %}
</td>
{% endif %}
</tr>
{% endblock %}

View File

@ -44,14 +44,14 @@
{% for child in item %}
{{ form_row(child) }}
{% endfor %}
</div>
<div class="text-right">
<span data-collection-delete-container class="btn btn-sm btn-danger">
<span data-collection-delete="{{ loop.index }}">
{{ label_delete|trans }}
<div class="text-right">
<span data-collection-delete-container class="btn btn-sm btn-danger">
<span data-collection-delete="{{ loop.index }}">
{{ label_delete|trans }}
</span>
</span>
</span>
</div>
</div>
{% endfor %}
</div>
@ -145,19 +145,27 @@
<div class="p-2 text-center">
<span class="form-filepicker-container">
<input class="form-control form-filepicker-picker mb-3" data-target="{{ id }}" readonly type="text" value="{{ value }}">
<span class="btn btn-sm btn-primary form-filepicker-picker" data-target="{{ id }}">
<div class="input-group mb-3">
<input class="form-control form-filepicker-picker" data-target="{{ id }}" readonly type="text" value="{{ value }}">
<div class="input-group-append form-filepicker-reset" data-target="{{ id }}">
<div class="input-group-text btn" data-target="{{ id }}">
<span class="fa fa-backspace" data-target="{{ id }}"></span>
</div>
</div>
</div>
<span class="btn btn-sm btn-primary form-filepicker-picker mb-1" data-target="{{ id }}">
{{ 'Choose'|trans }}
</span>
</span>
{% if value %}
{% if value.pathname is defined %}
<a class="btn btn-sm btn-success ml-1" href="{{ asset(value.pathname) }}" target="_blank">
<a class="btn btn-sm btn-success ml-1 mb-1" href="{{ asset(value.pathname) }}" target="_blank">
{{ 'Download'|trans }}
</a>
{% else %}
<a class="btn btn-sm btn-success ml-1" href="{{ asset(value) }}" target="_blank">
<a class="btn btn-sm btn-success ml-1 mb-1" href="{{ asset(value) }}" target="_blank">
{{ 'Download'|trans }}
</a>
{% endif %}

View File

@ -87,6 +87,10 @@
<a href="{{ safe_node_url(node) }}" class="btn btn-sm border border-secondary btn-light">
<span class="fa fa-sign-out-alt text-muted"></span>
</a>
{% elseif node.hasAppUrl %}
<a href="{{ node.url }}" class="btn btn-sm border border-secondary btn-light">
<span class="fa fa-sign-out-alt text-muted"></span>
</a>
{% else %}
{% if not node.disableUrl %}
{% if node.parameters|length %}

View File

@ -57,6 +57,10 @@ class SiteRouteLoader extends Loader
continue;
}
if ($node->hasAppUrl()) {
continue;
}
if (null !== $node->getAliasNode()) {
continue;
}

View File

@ -25,6 +25,7 @@ class SiteStore
public function getNavigations(): array
{
return $this->navigationRepositoryQuery->create()
->orderBy('.sortOrder')
->find()
;
}

View File

@ -13,7 +13,7 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
class RssPage extends Page
{
public function buildForm(FormBuilderInterface $builder)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'title',

View File

@ -13,7 +13,7 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
class SimplePage extends TitledPage
{
public function buildForm(FormBuilderInterface $builder)
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder);

View File

@ -14,7 +14,7 @@ use App\Core\Entity\Site\Page\Page;
*/
class TextPage extends Page
{
public function buildForm(FormBuilderInterface $builder)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'content',

View File

@ -13,7 +13,7 @@ use Symfony\Component\Form\FormBuilderInterface;
*/
class TitledPage extends Page
{
public function buildForm(FormBuilderInterface $builder)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add(
'title',

View File

@ -36,8 +36,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
<meta property="og:description" content="{{ _page.ogDescription }}" />
{% if _page.ogImage %}
<meta property="og:image" content="{{ asset(_page.ogImage) }}" />
<meta property="og:image:secure_url" content="{{ asset(_page.ogImage) }}" />
<meta property="og:image" content="{{ absolute_url(asset(_page.ogImage)) }}" />
<meta property="og:image:secure_url" content="{{ absolute_url(asset(_page.ogImage)) }}" />
{% endif %}
{% endif %}
{% endblock %}