backports murph-skeleton
This commit is contained in:
parent
d34ce1b585
commit
68cf917168
|
@ -189,6 +189,12 @@ tr.table-primary-light {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*[data-sortable-item] {
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
|
31
assets/js/addons/sortable.js
Normal file
31
assets/js/addons/sortable.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
const $ = require('jquery')
|
||||||
|
const Sortable = require('sortablejs').Sortable
|
||||||
|
|
||||||
|
module.exports = () => {
|
||||||
|
$('*[data-sortable]').each((i, list) => {
|
||||||
|
const element = $(list)
|
||||||
|
const route = element.attr('data-sortable-route')
|
||||||
|
|
||||||
|
new Sortable(list, {
|
||||||
|
handle: '*[data-sortable-item]',
|
||||||
|
sort: true,
|
||||||
|
onEnd: (e) => {
|
||||||
|
if (!route) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = element.find('*[data-sortable-item]')
|
||||||
|
let datas = {items: []}
|
||||||
|
|
||||||
|
items.each((order, v) => {
|
||||||
|
datas.items[$(v).attr('data-sortable-item')] = order + 1;
|
||||||
|
})
|
||||||
|
|
||||||
|
$.post(route, datas)
|
||||||
|
.always((data) => {
|
||||||
|
document.location.href = document.location.href
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,29 +1,20 @@
|
||||||
/*const imagesContext = require.context(
|
|
||||||
'../images',
|
|
||||||
true, /\.(png|jpg|jpeg|gif|ico|svg|webp)$/
|
|
||||||
);
|
|
||||||
|
|
||||||
imagesContext.keys().forEach(imagesContext);*/
|
|
||||||
|
|
||||||
import '../css/admin.scss';
|
import '../css/admin.scss';
|
||||||
|
|
||||||
require('../../node_modules/bootstrap/dist/js/bootstrap.min.js');
|
require('../../node_modules/bootstrap/dist/js/bootstrap.min.js');
|
||||||
// require('./admin/table-selectable.js')();
|
require('./addons/table-fixed.js')();
|
||||||
require('./admin/table-fixed.js')();
|
require('./addons/form-confirm.js')();
|
||||||
// require('./admin/document-selector.js')();
|
require('./addons/form.js')();
|
||||||
require('./admin/form-confirm.js')();
|
require('./addons/dbclick.js')();
|
||||||
require('./admin/form.js')();
|
require('./addons/toast.js')();
|
||||||
require('./admin/dbclick.js')();
|
require('./addons/modal.js')();
|
||||||
require('./admin/toast.js')();
|
require('./addons/push-state.js')();
|
||||||
require('./admin/modal.js')();
|
require('./addons/password.js')();
|
||||||
require('./admin/push-state.js')();
|
require('./addons/tooltip.js')();
|
||||||
require('./admin/password.js')();
|
require('./addons/editor.js')();
|
||||||
require('./admin/tooltip.js')();
|
require('./addons/panel.js')();
|
||||||
require('./admin/editor.js')();
|
require('./addons/choices.js')();
|
||||||
require('./admin/panel.js')();
|
require('./addons/checkbox-checker.js')();
|
||||||
require('./admin/choices.js')();
|
require('./addons/rest-choices.js')();
|
||||||
require('./admin/checkbox-checker.js')();
|
require('./addons/form-collection.js')();
|
||||||
require('./admin/rest-choices.js')();
|
require('./addons/datepicker.js')();
|
||||||
require('./admin/form-collection.js')();
|
require('./addons/sortable.js')();
|
||||||
require('./admin/datepicker.js')();
|
|
||||||
require('./admin/simplemde.js')();
|
|
||||||
|
|
|
@ -3,18 +3,18 @@ core:
|
||||||
name: "Blog"
|
name: "Blog"
|
||||||
logo: "build/images/core/logo.svg"
|
logo: "build/images/core/logo.svg"
|
||||||
controllers:
|
controllers:
|
||||||
- {name: 'PostController::posts', action: 'App\Controller\Blog\PostController::posts'}
|
|
||||||
- {name: 'CategoryController::categories', action: 'App\Controller\Blog\CategoryController::categories'}
|
|
||||||
- {name: 'PostController::category', action: 'App\Controller\Blog\PostController::category'}
|
|
||||||
- {name: 'PostController::search', action: 'App\Controller\Blog\PostController::search'}
|
|
||||||
- {name: 'LinkController:links', action: 'App\Controller\LinkController:links'}
|
- {name: 'LinkController:links', action: 'App\Controller\LinkController:links'}
|
||||||
- {name: 'ContactController::contact', action: 'App\Controller\ContactController::contact'}
|
- {name: 'ContactController::contact', action: 'App\Controller\ContactController::contact'}
|
||||||
- {name: 'PostController::post', action: 'App\Controller\Blog\PostController::post'}
|
|
||||||
- {name: '\Blog\PostController::rss', action: 'App\Controller\Blog\PostController::rss'}
|
|
||||||
- {name: 'BotController::formWithoutJavascript', action: 'App\Controller\BotController::formWithoutJavascript'}
|
- {name: 'BotController::formWithoutJavascript', action: 'App\Controller\BotController::formWithoutJavascript'}
|
||||||
- {name: 'LinkController:rss', action: 'App\Controller\LinkController:rss'}
|
- {name: 'LinkController:rss', action: 'App\Controller\LinkController:rss'}
|
||||||
- {name: 'PostController::jsonApi', action: 'App\Controller\Blog\PostController::jsonApi'}
|
|
||||||
- {name: 'TextController:text', action: 'App\Controller\TextController:text'}
|
- {name: 'TextController:text', action: 'App\Controller\TextController:text'}
|
||||||
|
- {name: 'Blog\PostController::search', action: 'App\Controller\Blog\PostController::search'}
|
||||||
|
- {name: 'Blog\PostController::posts', action: 'App\Controller\Blog\PostController::posts'}
|
||||||
|
- {name: 'Blog\PostController::category', action: 'App\Controller\Blog\PostController::category'}
|
||||||
|
- {name: 'Blog\PostController::post', action: 'App\Controller\Blog\PostController::post'}
|
||||||
|
- {name: 'Blog\PostController::rss', action: 'App\Controller\Blog\PostController::rss'}
|
||||||
|
- {name: 'Blog\PostController::jsonApi', action: 'App\Controller\Blog\PostController::jsonApi'}
|
||||||
|
- {name: 'Blog\CategoryController::categories', action: 'App\Controller\Blog\CategoryController::categories'}
|
||||||
pages:
|
pages:
|
||||||
App\Entity\Page\SimplePage:
|
App\Entity\Page\SimplePage:
|
||||||
name: 'Page de contenu'
|
name: 'Page de contenu'
|
||||||
|
|
|
@ -31,11 +31,11 @@ abstract class CrudController extends AdminController
|
||||||
$configuration = $this->getConfiguration();
|
$configuration = $this->getConfiguration();
|
||||||
|
|
||||||
$this->applySort('index', $query, $request);
|
$this->applySort('index', $query, $request);
|
||||||
$this->updateFilters($request, $session);
|
$this->updatefilters($request, $session);
|
||||||
|
|
||||||
$pager = $query
|
$pager = $query
|
||||||
->useFilters($this->filters)
|
->usefilters($this->filters)
|
||||||
->paginate($page, $configuration->getMaxPerPage('index'))
|
->paginate($page, $configuration->getmaxperpage('index'))
|
||||||
;
|
;
|
||||||
|
|
||||||
return $this->render($this->getConfiguration()->getView('index'), [
|
return $this->render($this->getConfiguration()->getView('index'), [
|
||||||
|
@ -125,6 +125,44 @@ abstract class CrudController extends AdminController
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function doSort(int $page = 1, RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session): Response
|
||||||
|
{
|
||||||
|
$configuration = $this->getConfiguration();
|
||||||
|
$context = $request->query->get('context', 'index');
|
||||||
|
|
||||||
|
if (!$configuration->getIsSortableCollection($context)) {
|
||||||
|
throw $this->createNotFoundException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->applySort($context, $query, $request);
|
||||||
|
$this->updateFilters($request, $session);
|
||||||
|
|
||||||
|
$pager = $query
|
||||||
|
->useFilters($this->filters)
|
||||||
|
->paginate($page, $configuration->getMaxPerPage($context))
|
||||||
|
;
|
||||||
|
|
||||||
|
if ($this->isCsrfTokenValid('sort', $request->query->get('_token'))) {
|
||||||
|
$items = $request->request->get('items', []);
|
||||||
|
$setter = 'set'.$configuration->getSortableCollectionProperty();
|
||||||
|
$orderStart = ($page - 1) * $configuration->getMaxPerPage($context);
|
||||||
|
|
||||||
|
foreach ($pager as $key => $entity) {
|
||||||
|
if (isset($items[$key + 1])) {
|
||||||
|
$entity->$setter($items[$key + 1] + $orderStart);
|
||||||
|
|
||||||
|
$entityManager->update($entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addFlash('success', 'The data has been saved.');
|
||||||
|
} else {
|
||||||
|
$this->addFlash('warning', 'The form is not valid.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json([]);
|
||||||
|
}
|
||||||
|
|
||||||
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null): Response
|
protected function doDelete(EntityInterface $entity, EntityManager $entityManager, Request $request, callable $beforeDelete = null): Response
|
||||||
{
|
{
|
||||||
$configuration = $this->getConfiguration();
|
$configuration = $this->getConfiguration();
|
||||||
|
@ -208,6 +246,13 @@ abstract class CrudController extends AdminController
|
||||||
protected function applySort(string $context, RepositoryQuery $query, Request $request)
|
protected function applySort(string $context, RepositoryQuery $query, Request $request)
|
||||||
{
|
{
|
||||||
$configuration = $this->getConfiguration();
|
$configuration = $this->getConfiguration();
|
||||||
|
|
||||||
|
if ($configuration->getIsSortableCollection($context)) {
|
||||||
|
$query->orderBy(sprintf('.%s', $configuration->getSortableCollectionProperty()));
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$defaultSort = $configuration->getDefaultSort($context);
|
$defaultSort = $configuration->getDefaultSort($context);
|
||||||
|
|
||||||
$name = $request->query->get('_sort', $defaultSort['label'] ?? null);
|
$name = $request->query->get('_sort', $defaultSort['label'] ?? null);
|
||||||
|
|
|
@ -23,6 +23,8 @@ class CrudConfiguration
|
||||||
protected array $maxPerPage = [];
|
protected array $maxPerPage = [];
|
||||||
protected array $locales = [];
|
protected array $locales = [];
|
||||||
protected array $defaultSort = [];
|
protected array $defaultSort = [];
|
||||||
|
protected array $isSortableCollection = [];
|
||||||
|
protected string $sortableCollectionProperty = 'sortOrder';
|
||||||
protected ?string $defaultLocale = null;
|
protected ?string $defaultLocale = null;
|
||||||
|
|
||||||
protected static $self;
|
protected static $self;
|
||||||
|
@ -245,4 +247,28 @@ class CrudConfiguration
|
||||||
{
|
{
|
||||||
return $this->defaultSort[$context] ?? null;
|
return $this->defaultSort[$context] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setIsSortableCollection(string $page, bool $isSortableCollection): self
|
||||||
|
{
|
||||||
|
$this->isSortableCollection[$page] = $isSortableCollection;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIsSortableCollection(string $page): bool
|
||||||
|
{
|
||||||
|
return $this->isSortableCollection[$page] ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSortableCollectionProperty(string $sortableCollectionProperty): self
|
||||||
|
{
|
||||||
|
$this->sortableCollectionProperty = $sortableCollectionProperty;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSortableCollectionProperty(): string
|
||||||
|
{
|
||||||
|
return $this->sortableCollectionProperty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,14 @@ class <?= $class_name; ?> extends CrudController
|
||||||
return $this->doEdit($entity, $entityManager, $request);
|
return $this->doEdit($entity, $entityManager, $request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/admin/<?= $route; ?>/sort/{page}", name="admin_<?= $route; ?>_sort", methods={"POST"})
|
||||||
|
*/
|
||||||
|
public function sort(int $page = 1, RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session): Response
|
||||||
|
{
|
||||||
|
return $this->doSort($page, $query, $entityManager, $request, $session);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Route("/admin/<?= $route; ?>/delete/{entity}", name="admin_<?= $route; ?>_delete", methods={"DELETE"})
|
* @Route("/admin/<?= $route; ?>/delete/{entity}", name="admin_<?= $route; ?>_delete", methods={"DELETE"})
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -157,3 +157,4 @@
|
||||||
"Tasks": "Tâches"
|
"Tasks": "Tâches"
|
||||||
"Results": "Résultats"
|
"Results": "Résultats"
|
||||||
"Clean all cache": "Nettoyer tout le cache"
|
"Clean all cache": "Nettoyer tout le cache"
|
||||||
|
"You can sort items by drag & drop": "Vous pouvez trier les élements via un glisser/déposer"
|
||||||
|
|
|
@ -62,6 +62,8 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block list %}
|
{% block list %}
|
||||||
|
{% set isSortable = configuration.isSortableCollection('index') %}
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table">
|
<table class="table">
|
||||||
{% block list_header %}
|
{% block list_header %}
|
||||||
|
@ -119,8 +121,29 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block list_items %}
|
{% block list_items %}
|
||||||
<tbody>
|
{% if isSortable %}
|
||||||
|
{% set dataSortable = 'data-sortable' %}
|
||||||
|
{% set dataSortableRoute = 'data-sortable-route="' ~ path(
|
||||||
|
configuration.pageRoute('sort'),
|
||||||
|
{
|
||||||
|
_token: csrf_token('sort'),
|
||||||
|
page: pager.currentPageNumber,
|
||||||
|
context: 'index',
|
||||||
|
}
|
||||||
|
) ~ '"' %}
|
||||||
|
{% else %}
|
||||||
|
{% set dataSortable = '' %}
|
||||||
|
{% set dataSortableRoute = '' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<tbody {{ dataSortable }} {{ dataSortableRoute|raw }}>
|
||||||
{% for item in pager %}
|
{% for item in pager %}
|
||||||
|
{% if isSortable %}
|
||||||
|
{% set dataSortableItem = 'data-sortable-item="' ~ loop.index ~ '"' %}
|
||||||
|
{% else %}
|
||||||
|
{% set dataSortableItem = '' %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block list_item %}
|
{% block list_item %}
|
||||||
{%- set dbClick %}
|
{%- set dbClick %}
|
||||||
{% if configuration.action('index', 'show', true) %}
|
{% if configuration.action('index', 'show', true) %}
|
||||||
|
@ -130,7 +153,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endset -%}
|
{% endset -%}
|
||||||
|
|
||||||
<tr data-dblclick="{{ dbClick }}" class="{{ loop.index is odd ? 'is-odd' : 'is-even' }}">
|
<tr {{ dataSortableItem|raw }} data-dblclick="{{ dbClick }}" class="{{ loop.index is odd ? 'is-odd' : 'is-even' }}">
|
||||||
{% for config in configuration.fields('index') %}
|
{% for config in configuration.fields('index') %}
|
||||||
{% set attr = config.options.attr is defined ? config.options.attr : [] %}
|
{% set attr = config.options.attr is defined ? config.options.attr : [] %}
|
||||||
{% set action = config.options.action is defined ? config.options.action : null %}
|
{% set action = config.options.action is defined ? config.options.action : null %}
|
||||||
|
@ -180,6 +203,15 @@
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% if loop.last and isSortable %}
|
||||||
|
<tr>
|
||||||
|
<td class="col-12 text-black-50 border-0" colspan="{{ configuration.fields('index')|length + 1 }}">
|
||||||
|
<span class="fa fa-hand-pointer"></span>
|
||||||
|
{{ 'You can sort items by drag & drop'|trans }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="col-12 text-center p-4 text-black-50" colspan="{{ configuration.fields('index')|length + 1 }}">
|
<td class="col-12 text-center p-4 text-black-50" colspan="{{ configuration.fields('index')|length + 1 }}">
|
||||||
|
@ -187,7 +219,7 @@
|
||||||
<span class="fa fa-search"></span>
|
<span class="fa fa-search"></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="display-5 mt-3">
|
<div class="display-5 mt-3">
|
||||||
Aucun résultat
|
{{ 'No result'|trans }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
"prismjs": "^1.23.0",
|
"prismjs": "^1.23.0",
|
||||||
"qrcodejs": "^1.0.0",
|
"qrcodejs": "^1.0.0",
|
||||||
"simplemde": "^1.11.2",
|
"simplemde": "^1.11.2",
|
||||||
|
"sortablejs": "^1.13.0",
|
||||||
"tinymce": "^5.7.1",
|
"tinymce": "^5.7.1",
|
||||||
"vanillajs-datepicker": "^1.1.4",
|
"vanillajs-datepicker": "^1.1.4",
|
||||||
"wire.css": "^1.2.5",
|
"wire.css": "^1.2.5",
|
||||||
|
|
|
@ -5481,6 +5481,11 @@ sockjs@0.3.21:
|
||||||
uuid "^3.4.0"
|
uuid "^3.4.0"
|
||||||
websocket-driver "^0.7.4"
|
websocket-driver "^0.7.4"
|
||||||
|
|
||||||
|
sortablejs@^1.13.0:
|
||||||
|
version "1.13.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.13.0.tgz#3ab2473f8c69ca63569e80b1cd1b5669b51269e9"
|
||||||
|
integrity sha512-RBJirPY0spWCrU5yCmWM1eFs/XgX2J5c6b275/YyxFRgnzPhKl/TDeU2hNR8Dt7ITq66NRPM4UlOt+e5O4CFHg==
|
||||||
|
|
||||||
source-list-map@^2.0.0, source-list-map@^2.0.1:
|
source-list-map@^2.0.0, source-list-map@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
|
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
|
||||||
|
|
Loading…
Reference in a new issue