Compare commits
2 commits
a1c187ec8d
...
7bf700c29d
Author | SHA1 | Date | |
---|---|---|---|
Simon Vieille | 7bf700c29d | ||
Simon Vieille | 3ed1e8845e |
|
@ -501,6 +501,10 @@ form {
|
|||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
z-index: 3000;
|
||||
}
|
||||
|
||||
.modal-dialog-large {
|
||||
max-width: 80%;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<Files />
|
||||
<Files v-bind:context="context" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -16,6 +16,13 @@ import Files from './Files'
|
|||
|
||||
export default {
|
||||
name: 'FileManager',
|
||||
props: {
|
||||
context: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: 'crud',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Files
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<nav aria-label="breadcrumb bg-light">
|
||||
<div class="float-right">
|
||||
</div>
|
||||
|
||||
<ol class="breadcrumb mb-0 float-right file-manager-views">
|
||||
<li class="breadcrumb-item">
|
||||
<span class="fa fa-grip-horizontal" v-on:click="setView('grid')"></span>
|
||||
|
@ -13,7 +10,7 @@
|
|||
</li>
|
||||
</ol>
|
||||
|
||||
<ol class="breadcrumb mb-0 float-right file-manager-actions">
|
||||
<ol v-if="['crud'].indexOf(context) > -1" class="breadcrumb mb-0 float-right file-manager-actions">
|
||||
<li class="breadcrumb-item">
|
||||
<span class="fa fa-upload text-primary" v-bind:data-modal="generateUploadLink(directory)"></span>
|
||||
<span class="fa fa-folder-plus text-primary" v-bind:data-modal="generateNewDirectoryLink(directory)"></span>
|
||||
|
@ -44,7 +41,7 @@
|
|||
|
||||
<div v-for="item in directories" class="card mt-3 ml-3 mb-3 border-0">
|
||||
<div class="card-body p-2">
|
||||
<div class="card-text" v-on:dblclick="setDirectory(item.path)" v-bind:data-modal="generateInfoLink(item, true)">
|
||||
<div class="card-text" v-on:dblclick="setDirectory(item.path)" v-bind:data-modal="generateInfoLink(item, true, context)">
|
||||
<div class="text-center">
|
||||
<div class="display-4 text-warning">
|
||||
<span class="fa fa-folder"></span>
|
||||
|
@ -63,7 +60,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="item in files" class="card mt-3 ml-3 mb-3 border-0" v-bind:data-modal="generateInfoLink(item)">
|
||||
<div v-for="item in files" class="card mt-3 ml-3 mb-3 border-0" v-bind:data-modal="generateInfoLink(item, null, context)">
|
||||
<div class="card-body p-2">
|
||||
<div class="card-text">
|
||||
<div class="text-center">
|
||||
|
@ -97,7 +94,7 @@
|
|||
</td>
|
||||
</tr>
|
||||
|
||||
<tr v-for="item in directories" v-on:dblclick="setDirectory(item.path)" v-bind:data-modal="generateInfoLink(item, true)">
|
||||
<tr v-for="item in directories" v-on:dblclick="setDirectory(item.path)" v-bind:data-modal="generateInfoLink(item, true, context)">
|
||||
<td width="10">
|
||||
<span class="fa fa-folder text-warning"></span>
|
||||
</td>
|
||||
|
@ -115,7 +112,7 @@
|
|||
<td width="10">
|
||||
<FileIcon v-bind:mime="item.mime" />
|
||||
</td>
|
||||
<td v-bind:data-modal="generateInfoLink(item)">
|
||||
<td v-bind:data-modal="generateInfoLink(item, null, context)">
|
||||
<div v-if="item.locked" class="float-right">
|
||||
<span class="btn btn-sm btn-light">
|
||||
<span class="fa fa-lock"></span>
|
||||
|
@ -178,6 +175,12 @@ export default {
|
|||
components: {
|
||||
FileIcon
|
||||
},
|
||||
props: {
|
||||
context: {
|
||||
type: String,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
view: 'list',
|
||||
|
@ -197,14 +200,16 @@ export default {
|
|||
|
||||
localStorage.setItem('file-manager.view', view)
|
||||
},
|
||||
generateInfoLink (item, directory) {
|
||||
generateInfoLink (item, directory, context) {
|
||||
if (directory) {
|
||||
return Routing.generate('admin_file_manager_info', {
|
||||
file: item.path
|
||||
file: item.path,
|
||||
context: context
|
||||
})
|
||||
} else {
|
||||
return Routing.generate('admin_file_manager_info', {
|
||||
file: item.path + '/' + item.basename
|
||||
file: item.path + '/' + item.basename,
|
||||
context: context
|
||||
})
|
||||
}
|
||||
},
|
||||
|
@ -259,7 +264,8 @@ export default {
|
|||
watch: {
|
||||
directory (directory) {
|
||||
axios.get(Routing.generate('admin_file_manager_api_directory', {
|
||||
directory: this.directory
|
||||
directory: this.directory,
|
||||
context: this.context
|
||||
}))
|
||||
.then((response) => {
|
||||
this.buildBreadcrum(response.data.breadcrumb)
|
||||
|
|
|
@ -1,4 +1,53 @@
|
|||
const $ = require('jquery')
|
||||
const Vue = require('vue').default
|
||||
const FileManager = require('../components/file-manager/FileManager').default
|
||||
|
||||
const createModal = function (url) {
|
||||
let container = $('#file-manager-modal-container')
|
||||
const body = $('body')
|
||||
|
||||
if (!container.length) {
|
||||
container = $('<div id="file-manager-modal-container" class="modal">')
|
||||
|
||||
body.append(container)
|
||||
}
|
||||
|
||||
container.html(`
|
||||
<div class="modal-dialog modal-dialog-large">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div id="file-manager-modal-content">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`)
|
||||
|
||||
$(container).modal('show')
|
||||
|
||||
return $(container)
|
||||
}
|
||||
|
||||
const fileManagerBrowser = function (callback) {
|
||||
const container = createModal()
|
||||
|
||||
$('body').on('click', '#file-manager-insert', (e) => {
|
||||
callback($(e.target).attr('data-value'), {})
|
||||
$('#modal-container').modal('hide')
|
||||
container.modal('hide')
|
||||
})
|
||||
|
||||
new Vue({
|
||||
el: '#file-manager-modal-content',
|
||||
template: '<FileManager context="tinymce" />',
|
||||
components: {
|
||||
FileManager
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (typeof tinymce !== 'undefined') {
|
||||
tinymce.murph = tinymce.murph || {}
|
||||
|
@ -13,6 +62,8 @@ if (typeof tinymce !== 'undefined') {
|
|||
spellchecker_dialog: true,
|
||||
tinycomments_mode: 'embedded',
|
||||
convert_urls: false,
|
||||
file_picker_callback: fileManagerBrowser,
|
||||
file_picker_types: 'image',
|
||||
init_instance_callback: function (editor) {
|
||||
editor.on('SetContent', () => {
|
||||
tinymce.triggerSave(false, true)
|
||||
|
@ -29,7 +80,7 @@ if (typeof tinymce !== 'undefined') {
|
|||
tinymce.murph.modes.default = tinymce.murph.modes.default || {
|
||||
plugins: 'print preview importcss searchreplace visualblocks visualchars fullscreen template table charmap hr pagebreak nonbreaking toc insertdatetime advlist lists wordcount textpattern noneditable help charmap quickbars link image code autoresize',
|
||||
menubar: 'file edit view insert format tools table tc help',
|
||||
toolbar: 'undo redo | bold italic underline strikethrough | link image | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap | fullscreen preview',
|
||||
toolbar: 'undo redo | bold italic underline strikethrough | link image | fontselect fontsizeselect formatselect | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap | fullscreen preview',
|
||||
quickbars_selection_toolbar: 'bold italic | quicklink h2 h3 blockquote quickimage quicktable',
|
||||
contextmenu: 'link image imagetools table configurepermanentpen'
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
// file-manager
|
||||
const Vue = require('vue').default
|
||||
|
||||
const FileManager = require('../components/file-manager/FileManager').default
|
||||
|
|
|
@ -1,5 +1,28 @@
|
|||
const $ = require('jquery')
|
||||
|
||||
const openModal = function (url) {
|
||||
let container = $('#modal-container')
|
||||
const body = $('body')
|
||||
|
||||
if (!container.length) {
|
||||
container = $('<div id="modal-container" class="modal">')
|
||||
|
||||
body.append(container)
|
||||
}
|
||||
|
||||
const loader = $('<div style="position: absolute; top: 25vh; left: 50vw; z-index: 2000">')
|
||||
loader.html('<div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div>')
|
||||
body.append(loader)
|
||||
|
||||
container.html('')
|
||||
|
||||
$(container).modal('show')
|
||||
|
||||
container.load(url, function () {
|
||||
loader.remove()
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function () {
|
||||
let click = 0
|
||||
|
||||
|
@ -18,32 +41,13 @@ module.exports = function () {
|
|||
|
||||
click = 0
|
||||
|
||||
let container = $('#modal-container')
|
||||
const body = $('body')
|
||||
|
||||
if (!container.length) {
|
||||
container = $('<div id="modal-container" class="modal">')
|
||||
|
||||
body.append(container)
|
||||
}
|
||||
|
||||
const loader = $('<div style="position: absolute; top: 25vh; left: 50vw; z-index: 2000">')
|
||||
loader.html('<div class="spinner-border text-primary" role="status"><span class="sr-only">Loading...</span></div>')
|
||||
body.append(loader)
|
||||
|
||||
container.html('')
|
||||
|
||||
let url = $(e.target).attr('data-modal')
|
||||
|
||||
if (!url) {
|
||||
url = $(e.target).parents('*[data-modal]').first().attr('data-modal')
|
||||
}
|
||||
|
||||
$(container).modal('show')
|
||||
|
||||
container.load(url, function () {
|
||||
loader.remove()
|
||||
})
|
||||
openModal(url)
|
||||
}, 250)
|
||||
})
|
||||
|
||||
|
@ -51,6 +55,6 @@ module.exports = function () {
|
|||
const dataModal = urlParams.get('data-modal')
|
||||
|
||||
if (dataModal) {
|
||||
$('*[data-modal="' + dataModal + '"]').first().click()
|
||||
openModal(dataModal)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,14 @@ abstract class AdminController extends AbstractController
|
|||
$this->coreParameters = $parameters->get('core');
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/_ping", name="_ping")
|
||||
*/
|
||||
public function ping()
|
||||
{
|
||||
return $this->json(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -29,12 +37,4 @@ abstract class AdminController extends AbstractController
|
|||
}
|
||||
|
||||
abstract protected function getSection(): string;
|
||||
|
||||
/**
|
||||
* @Route("/_ping", name="_ping")
|
||||
*/
|
||||
public function ping()
|
||||
{
|
||||
return $this->json(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ abstract class CrudController extends AdminController
|
|||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
if ($beforeCreate !== null) {
|
||||
if (null !== $beforeCreate) {
|
||||
call_user_func_array($beforeCreate, [$entity, $form, $request]);
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ abstract class CrudController extends AdminController
|
|||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
if ($beforeUpdate !== null) {
|
||||
if (null !== $beforeUpdate) {
|
||||
call_user_func_array($beforeUpdate, [$entity, $form, $request]);
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ abstract class CrudController extends AdminController
|
|||
|
||||
foreach ($pager as $key => $entity) {
|
||||
if (isset($items[$key + 1])) {
|
||||
$entity->$setter($items[$key + 1] + $orderStart);
|
||||
$entity->{$setter}($items[$key + 1] + $orderStart);
|
||||
|
||||
$entityManager->update($entity);
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ abstract class CrudController extends AdminController
|
|||
|
||||
$query->useFilters($this->filters);
|
||||
|
||||
if ($target === 'selection') {
|
||||
if ('selection' === $target) {
|
||||
$isSelection = true;
|
||||
$pager = $query->paginate($page, $configuration->getMaxPerPage($context));
|
||||
} else {
|
||||
|
@ -216,7 +216,7 @@ abstract class CrudController extends AdminController
|
|||
$configuration = $this->getConfiguration();
|
||||
|
||||
if ($this->isCsrfTokenValid('delete'.$entity->getId(), $request->request->get('_token'))) {
|
||||
if ($beforeDelete !== null) {
|
||||
if (null !== $beforeDelete) {
|
||||
call_user_func($beforeDelete, $entity);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@ use App\Core\Controller\Admin\AdminController;
|
|||
use App\Core\FileManager\FsFileManager;
|
||||
use App\Core\Form\FileManager\DirectoryCreateType;
|
||||
use App\Core\Form\FileManager\DirectoryRenameType;
|
||||
use App\Core\Form\FileManager\FileInformationType;
|
||||
use App\Core\Form\FileManager\FileUploadType;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
|
@ -35,22 +37,53 @@ class FileManagerAdminController extends AdminController
|
|||
}
|
||||
|
||||
/**
|
||||
* @Route("/info", name="admin_file_manager_info", options={"expose"=true})
|
||||
* @Route("/info/{tab}/{context}", name="admin_file_manager_info", options={"expose"=true})
|
||||
*/
|
||||
public function info(FsFileManager $manager, Request $request): Response
|
||||
{
|
||||
$info = $manager->info($request->query->get('file'));
|
||||
public function info(
|
||||
FsFileManager $manager,
|
||||
Request $request,
|
||||
EntityManager $entityManager,
|
||||
string $context = 'crud',
|
||||
string $tab = 'information'
|
||||
): Response {
|
||||
$splInfo = $manager->getSplInfo($request->query->get('file'));
|
||||
|
||||
if (!$info) {
|
||||
if (!$splInfo) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
$path = $manager->getPathUri().'/'.$info->getRelativePathname();
|
||||
$fileInfo = $manager->getFileInformation($request->query->get('file'));
|
||||
$path = $manager->getPathUri().'/'.$splInfo->getRelativePathname();
|
||||
|
||||
$form = $this->createForm(FileInformationType::class, $fileInfo);
|
||||
|
||||
if ($request->isMethod('POST')) {
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$entityManager->update($fileInfo);
|
||||
|
||||
$this->addFlash('success', 'The data has been saved.');
|
||||
} else {
|
||||
$this->addFlash('warning', 'The form is not valid.');
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_file_manager_index', [
|
||||
'data-modal' => $this->generateUrl('admin_file_manager_info', [
|
||||
'file' => $request->query->get('file'),
|
||||
'tab' => 'attributes',
|
||||
]),
|
||||
'path' => $splInfo->getRelativePath(),
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->render('@Core/file_manager/info.html.twig', [
|
||||
'info' => $info,
|
||||
'splInfo' => $splInfo,
|
||||
'path' => $path,
|
||||
'isLocked' => $manager->isLocked($info->getRelativePathname()),
|
||||
'isLocked' => $manager->isLocked($splInfo->getRelativePathname()),
|
||||
'tab' => $tab,
|
||||
'form' => $form->createView(),
|
||||
'context' => $context,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -59,13 +92,13 @@ class FileManagerAdminController extends AdminController
|
|||
*/
|
||||
public function directoryNew(FsFileManager $manager, Request $request): Response
|
||||
{
|
||||
$info = $manager->info($request->query->get('file'));
|
||||
$splInfo = $manager->getSplInfo($request->query->get('file'));
|
||||
|
||||
if (!$info) {
|
||||
if (!$splInfo) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
if (!$info->isDir()) {
|
||||
if (!$splInfo->isDir()) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
|
@ -92,7 +125,7 @@ class FileManagerAdminController extends AdminController
|
|||
}
|
||||
|
||||
return $this->redirectToRoute('admin_file_manager_index', [
|
||||
'path' => $info->getRelativePath(),
|
||||
'path' => $splInfo->getRelativePath(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -108,13 +141,13 @@ class FileManagerAdminController extends AdminController
|
|||
*/
|
||||
public function directoryRename(FsFileManager $manager, Request $request): Response
|
||||
{
|
||||
$info = $manager->info($request->query->get('file'));
|
||||
$splInfo = $manager->getSplInfo($request->query->get('file'));
|
||||
|
||||
if (!$info) {
|
||||
if (!$splInfo) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
if (!$info->isDir()) {
|
||||
if (!$splInfo->isDir()) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
|
@ -142,7 +175,7 @@ class FileManagerAdminController extends AdminController
|
|||
}
|
||||
|
||||
return $this->redirectToRoute('admin_file_manager_index', [
|
||||
'path' => $info->getRelativePath(),
|
||||
'path' => $splInfo->getRelativePath(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -158,13 +191,13 @@ class FileManagerAdminController extends AdminController
|
|||
*/
|
||||
public function upload(FsFileManager $manager, Request $request): Response
|
||||
{
|
||||
$info = $manager->info($request->query->get('file'));
|
||||
$splInfo = $manager->getSplInfo($request->query->get('file'));
|
||||
|
||||
if (!$info) {
|
||||
if (!$splInfo) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
if (!$info->isDir()) {
|
||||
if (!$splInfo->isDir()) {
|
||||
throw $this->createAccessDeniedException();
|
||||
}
|
||||
|
||||
|
@ -189,7 +222,7 @@ class FileManagerAdminController extends AdminController
|
|||
}
|
||||
|
||||
return $this->redirectToRoute('admin_file_manager_index', [
|
||||
'path' => $info->getRelativePathname(),
|
||||
'path' => $splInfo->getRelativePathname(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -206,9 +239,9 @@ class FileManagerAdminController extends AdminController
|
|||
public function delete(FsFileManager $manager, Request $request): Response
|
||||
{
|
||||
$path = $request->request->get('file');
|
||||
$info = $manager->info($request->request->get('file'));
|
||||
$splInfo = $manager->getSplInfo($request->request->get('file'));
|
||||
|
||||
if (!$info) {
|
||||
if (!$splInfo) {
|
||||
throw $this->createNotFoundException();
|
||||
}
|
||||
|
||||
|
@ -221,7 +254,7 @@ class FileManagerAdminController extends AdminController
|
|||
}
|
||||
|
||||
return $this->redirectToRoute('admin_file_manager_index', [
|
||||
'path' => $info->getRelativePath(),
|
||||
'path' => $splInfo->getRelativePath(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ use App\Core\Form\Site\NodeMoveType;
|
|||
use App\Core\Form\Site\NodeType as EntityType;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Repository\Site\NodeRepository;
|
||||
use App\Core\Site\ControllerLocator;
|
||||
use App\Core\Site\PageLocator;
|
||||
use App\Core\Sitemap\SitemapBuilder;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
@ -20,7 +21,6 @@ use Symfony\Component\Form\FormError;
|
|||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use App\Core\Site\ControllerLocator;
|
||||
|
||||
/**
|
||||
* @Route("/admin/site/node")
|
||||
|
@ -278,7 +278,8 @@ class NodeAdminController extends AdminController
|
|||
|
||||
$entity
|
||||
->setPage($page)
|
||||
->setAliasNode(null);
|
||||
->setAliasNode(null)
|
||||
;
|
||||
} elseif ('existing' === $pageAction) {
|
||||
if ($pageEntity) {
|
||||
$entity->setPage($pageEntity);
|
||||
|
@ -291,7 +292,8 @@ class NodeAdminController extends AdminController
|
|||
} elseif ('none' === $pageAction) {
|
||||
$entity
|
||||
->setPage(null)
|
||||
->setAliasNode(null);
|
||||
->setAliasNode(null)
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,18 +5,16 @@ namespace App\Core\Controller\Site;
|
|||
use App\Core\Controller\Admin\Crud\CrudController;
|
||||
use App\Core\Crud\CrudConfiguration;
|
||||
use App\Core\Crud\Field;
|
||||
use App\Core\Entity\EntityInterface;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Entity\Site\Page\Page as Entity;
|
||||
use App\Core\Form\Site\Page\PageType as Type;
|
||||
use App\Core\Form\Site\Page\Filter\PageFilterType as FilterType;
|
||||
use App\Core\Form\Site\Page\PageType as Type;
|
||||
use App\Core\Manager\EntityManager;
|
||||
use App\Core\Repository\Site\Page\PageRepositoryQuery as RepositoryQuery;
|
||||
use App\Core\Site\PageLocator;
|
||||
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\Site\PageLocator;
|
||||
use App\Core\Repository\Site\Page\PageRepositoryQuery;
|
||||
|
||||
class PageAdminController extends CrudController
|
||||
{
|
||||
|
@ -53,8 +51,7 @@ class PageAdminController extends CrudController
|
|||
RepositoryQuery $repositoryQuery,
|
||||
PageLocator $pageLocator,
|
||||
Request $request
|
||||
): Response
|
||||
{
|
||||
): Response {
|
||||
$entity = $repositoryQuery->filterById($entity)->findOne();
|
||||
|
||||
$this->getConfiguration()->setFormOptions('edit', [
|
||||
|
@ -98,12 +95,13 @@ class PageAdminController extends CrudController
|
|||
])
|
||||
->setField('index', 'Elements', Field\TextField::class, [
|
||||
'view' => '@Core/site/page_admin/fields/nodes.html.twig',
|
||||
'sort' => ['navigation', function(RepositoryQuery $query, $direction) {
|
||||
'sort' => ['navigation', function (RepositoryQuery $query, $direction) {
|
||||
$query
|
||||
->leftJoin('.nodes', 'node')
|
||||
->leftJoin('node.menu', 'menu')
|
||||
->leftJoin('menu.navigation', 'navigation')
|
||||
->orderBy('navigation.label', $direction);
|
||||
->orderBy('navigation.label', $direction)
|
||||
;
|
||||
}],
|
||||
])
|
||||
;
|
||||
|
|
|
@ -31,7 +31,7 @@ class PageController extends AbstractController
|
|||
{
|
||||
$parameters = array_merge($this->getDefaultRenderParameters(), $parameters);
|
||||
|
||||
if ($response === null) {
|
||||
if (null === $response) {
|
||||
$contentType = $this->siteRequest->getNode()->getContentType();
|
||||
|
||||
$response = new Response(null, 200, [
|
||||
|
|
|
@ -33,7 +33,8 @@ class TreeAdminController extends AdminController
|
|||
if (null === $navigation) {
|
||||
$navigation = $navigationQuery->create()
|
||||
->orderBy('.sortOrder')
|
||||
->findOne();
|
||||
->findOne()
|
||||
;
|
||||
}
|
||||
|
||||
if (null === $navigation) {
|
||||
|
|
|
@ -5,13 +5,13 @@ namespace App\Core\Controller\Task;
|
|||
use App\Core\Controller\Admin\AdminController;
|
||||
use App\Core\Event\Task\TaskInitEvent;
|
||||
use App\Core\Event\Task\TaskRunRequestedEvent;
|
||||
use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
|
||||
use SensioLabs\AnsiConverter\Theme\SolarizedTheme;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
|
||||
use SensioLabs\AnsiConverter\Theme\SolarizedTheme;
|
||||
|
||||
/**
|
||||
* @Route("/admin/task")
|
||||
|
|
|
@ -14,19 +14,27 @@ class Configuration implements ConfigurationInterface
|
|||
'image/jpg',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/svg+xml',
|
||||
'video/mp4',
|
||||
'audio/mpeg3',
|
||||
'audio/x-mpeg-3',
|
||||
'multipart/x-zip',
|
||||
'multipart/x-gzip',
|
||||
'application/pdf',
|
||||
'application/ogg',
|
||||
'video/mp4',
|
||||
'application/zip',
|
||||
'multipart/x-zip',
|
||||
'application/rar',
|
||||
'application/x-rar-compressed',
|
||||
'application/x-zip-compressed',
|
||||
'application/tar',
|
||||
'application/x-tar',
|
||||
'application/x-bzip',
|
||||
'application/x-bzip2',
|
||||
'application/x-gzip',
|
||||
'application/octet-stream',
|
||||
'application/msword',
|
||||
'text/plain',
|
||||
'text/x-asm',
|
||||
'application/octet-stream'
|
||||
'text/css',
|
||||
];
|
||||
|
||||
$defaultLocked = [
|
||||
|
|
48
core/Entity/FileInformation.php
Normal file
48
core/Entity/FileInformation.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Entity;
|
||||
|
||||
use App\Repository\Entity\FileInformationRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
/**
|
||||
* @ORM\Entity(repositoryClass=FileInformationRepository::class)
|
||||
*/
|
||||
class FileInformation implements EntityInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue(strategy="NONE")
|
||||
* @ORM\Column(type="string", length=255, unique=true)
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=true)
|
||||
*/
|
||||
protected $attributes;
|
||||
|
||||
public function getId(): ?string
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(string $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAttributes()
|
||||
{
|
||||
return json_decode($this->attributes, true);
|
||||
}
|
||||
|
||||
public function setAttributes($attributes): self
|
||||
{
|
||||
$this->attributes = json_encode($attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@
|
|||
namespace App\Core\Entity\Site\Page;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
|
|
|
@ -242,7 +242,7 @@ class Page implements EntityInterface
|
|||
|
||||
public function setOgImage($ogImage): self
|
||||
{
|
||||
if ($this->ogImage !== null && $ogImage === null) {
|
||||
if (null !== $this->ogImage && null === $ogImage) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
16
core/Factory/FileInformationFactory.php
Normal file
16
core/Factory/FileInformationFactory.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Factory;
|
||||
|
||||
use App\Core\Entity\FileInformation as Entity;
|
||||
|
||||
class FileInformationFactory implements FactoryInterface
|
||||
{
|
||||
public function create(string $id): Entity
|
||||
{
|
||||
$entity = new Entity();
|
||||
$entity->setId($id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
}
|
|
@ -18,7 +18,8 @@ class NavigationSettingFactory implements FactoryInterface
|
|||
|
||||
$entity
|
||||
->setNavigation($navigation)
|
||||
->setCode($code);
|
||||
->setCode($code)
|
||||
;
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
namespace App\Core\FileManager;
|
||||
|
||||
use App\Core\Entity\FileInformation;
|
||||
use App\Core\Factory\FileInformationFactory;
|
||||
use App\Core\Form\FileUploadHandler;
|
||||
use App\Core\Repository\FileInformationRepositoryQuery;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
@ -21,12 +24,21 @@ class FsFileManager
|
|||
protected string $pathUri;
|
||||
protected array $pathLocked;
|
||||
protected FileUploadHandler $uploadHandler;
|
||||
protected FileInformationFactory $fileInformationFactory;
|
||||
protected FileInformationRepositoryQuery $fileInformationRepositoryQuery;
|
||||
|
||||
public function __construct(ParameterBagInterface $params, FileUploadHandler $uploadHandler)
|
||||
{
|
||||
public function __construct(
|
||||
ParameterBagInterface $params,
|
||||
FileUploadHandler $uploadHandler,
|
||||
FileInformationFactory $fileInformationFactory,
|
||||
FileInformationRepositoryQuery $fileInformationRepositoryQuery
|
||||
) {
|
||||
$config = $params->get('core')['file_manager'];
|
||||
|
||||
$this->uploadHandler = $uploadHandler;
|
||||
$this->fileInformationFactory = $fileInformationFactory;
|
||||
$this->fileInformationRepositoryQuery = $fileInformationRepositoryQuery;
|
||||
|
||||
$this->mimes = $config['mimes'];
|
||||
$this->path = $config['path'];
|
||||
$this->pathUri = $this->normalizePath($config['path_uri']);
|
||||
|
@ -85,7 +97,7 @@ class FsFileManager
|
|||
return $data;
|
||||
}
|
||||
|
||||
public function info(string $path): ?SplFileInfo
|
||||
public function getSplInfo(string $path): ?SplFileInfo
|
||||
{
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
|
@ -95,6 +107,7 @@ class FsFileManager
|
|||
|
||||
$finder = new Finder();
|
||||
$finder->in($this->path)
|
||||
->depth('== '.substr_count($path, '/'))
|
||||
->name(basename($path))
|
||||
;
|
||||
|
||||
|
@ -113,9 +126,36 @@ class FsFileManager
|
|||
return null;
|
||||
}
|
||||
|
||||
public function getFileInformation(string $path): ?FileInformation
|
||||
{
|
||||
$file = $this->getSplInfo($path);
|
||||
|
||||
if (!$file) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($file->isDir()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$hash = hash_file('sha384', $file->getPathName());
|
||||
|
||||
$info = $this->fileInformationRepositoryQuery
|
||||
->where('.id = :hash')
|
||||
->setParameter(':hash', $hash)
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if (!$info) {
|
||||
$info = $this->fileInformationFactory->create($hash);
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public function createDirectory(string $name, string $path): bool
|
||||
{
|
||||
$file = $this->info($path);
|
||||
$file = $this->getSplInfo($path);
|
||||
|
||||
if (!$file || $this->isLocked($path)) {
|
||||
return false;
|
||||
|
@ -135,7 +175,7 @@ class FsFileManager
|
|||
|
||||
public function renameDirectory(string $name, string $path): bool
|
||||
{
|
||||
$file = $this->info($path);
|
||||
$file = $this->getSplInfo($path);
|
||||
|
||||
if (!$file || $this->isLocked($path)) {
|
||||
return false;
|
||||
|
@ -166,7 +206,7 @@ class FsFileManager
|
|||
|
||||
public function delete(string $path): bool
|
||||
{
|
||||
$file = $this->info($path);
|
||||
$file = $this->getSplInfo($path);
|
||||
|
||||
if ($this->isLocked($file)) {
|
||||
return false;
|
||||
|
@ -182,7 +222,7 @@ class FsFileManager
|
|||
|
||||
public function isLocked($path): bool
|
||||
{
|
||||
$file = $this->info($path);
|
||||
$file = $this->getSplInfo($path);
|
||||
|
||||
if (!$file) {
|
||||
return false;
|
||||
|
|
|
@ -3,14 +3,11 @@
|
|||
namespace App\Core\Form\FileManager;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
use Symfony\Component\Validator\Constraints\All;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Validator\Constraints\Regex;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\Regex;
|
||||
|
||||
class DirectoryCreateType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -3,14 +3,11 @@
|
|||
namespace App\Core\Form\FileManager;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
use Symfony\Component\Validator\Constraints\All;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Validator\Constraints\Regex;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\Regex;
|
||||
|
||||
class DirectoryRenameType extends AbstractType
|
||||
{
|
||||
|
|
49
core/Form/FileManager/FileInformationAttributeType.php
Normal file
49
core/Form/FileManager/FileInformationAttributeType.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Form\FileManager;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class FileInformationAttributeType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add(
|
||||
'label',
|
||||
TextType::class,
|
||||
[
|
||||
'label' => 'Label',
|
||||
'required' => true,
|
||||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
new NotBlank(),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$builder->add(
|
||||
'value',
|
||||
TextType::class,
|
||||
[
|
||||
'label' => 'Value',
|
||||
'required' => false,
|
||||
'attr' => [
|
||||
],
|
||||
'constraints' => [
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => null,
|
||||
]);
|
||||
}
|
||||
}
|
34
core/Form/FileManager/FileInformationType.php
Normal file
34
core/Form/FileManager/FileInformationType.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Form\FileManager;
|
||||
|
||||
use App\Core\Entity\FileInformation;
|
||||
use App\Core\Form\Type\CollectionType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class FileInformationType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder->add(
|
||||
'attributes',
|
||||
CollectionType::class,
|
||||
[
|
||||
'entry_type' => FileInformationAttributeType::class,
|
||||
'by_reference' => false,
|
||||
'allow_add' => true,
|
||||
'allow_delete' => true,
|
||||
'prototype' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => FileInformation::class,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -3,11 +3,11 @@
|
|||
namespace App\Core\Form\FileManager;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
use Symfony\Component\Validator\Constraints\All;
|
||||
use Symfony\Component\Validator\Constraints\File;
|
||||
|
||||
class FileUploadType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
namespace App\Core\Form\Site;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
|
||||
class NavigationAdditionalDomainType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -4,14 +4,13 @@ namespace App\Core\Form\Site;
|
|||
|
||||
use App\Core\Entity\Site\Navigation;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use App\Core\Form\Site\NavigationAdditionalDomainType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
|
||||
class NavigationType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -7,13 +7,13 @@ use App\Core\Entity\Site\Page\Page;
|
|||
use Doctrine\ORM\EntityRepository;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
|
||||
class NodeType extends AbstractType
|
||||
{
|
||||
|
@ -181,7 +181,7 @@ class NodeType extends AbstractType
|
|||
'required' => false,
|
||||
'class' => Node::class,
|
||||
'choice_label' => 'label',
|
||||
'choices' => call_user_func(function() use ($options, $builder) {
|
||||
'choices' => call_user_func(function () use ($options, $builder) {
|
||||
$nodes = [];
|
||||
|
||||
foreach ($options['navigation']->getMenus() as $menu) {
|
||||
|
|
|
@ -4,13 +4,11 @@ namespace App\Core\Form\Site\Page;
|
|||
|
||||
use App\Core\Entity\Site\Page\Block;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\CallbackTransformer;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class CollectionBlockType extends AbstractType
|
||||
{
|
||||
|
|
|
@ -48,9 +48,9 @@ class MakeRepositoryQuery extends AbstractMaker
|
|||
);
|
||||
|
||||
$queryDetails = $generator->createClassNameDetails(
|
||||
$repositoryClass,
|
||||
$repositoryClass.'Query',
|
||||
'Repository\\',
|
||||
'Query'
|
||||
''
|
||||
);
|
||||
|
||||
$id = u($queryDetails->getShortName())
|
||||
|
|
21
core/Repository/FileInformationRepository.php
Normal file
21
core/Repository/FileInformationRepository.php
Normal file
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository;
|
||||
|
||||
use App\Core\Entity\FileInformation;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @method FileInformation|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method FileInformation|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method FileInformation[] findAll()
|
||||
* @method FileInformation[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class FileInformationRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, FileInformation::class);
|
||||
}
|
||||
}
|
14
core/Repository/FileInformationRepositoryQuery.php
Normal file
14
core/Repository/FileInformationRepositoryQuery.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Repository;
|
||||
|
||||
use App\Core\Repository\FileInformationRepository as Repository;
|
||||
use Knp\Component\Pager\PaginatorInterface;
|
||||
|
||||
class FileInformationRepositoryQuery extends RepositoryQuery
|
||||
{
|
||||
public function __construct(Repository $repository, PaginatorInterface $paginator)
|
||||
{
|
||||
parent::__construct($repository, 'f', $paginator);
|
||||
}
|
||||
}
|
|
@ -186,3 +186,5 @@
|
|||
"Rename": "Renommer"
|
||||
"Rename directory": "Renommer le répertoire"
|
||||
"New directory": "Nouveau répertoire"
|
||||
"Preview": "Aperçu"
|
||||
"Insert": "Insérer"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
{% set tab = tab ?? 'information' %}
|
||||
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
|
@ -9,85 +11,216 @@
|
|||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
{% if info.type == 'file' %}
|
||||
<div class="form-group">
|
||||
<label for="file-manager-url">{{ 'Absolute URL'|trans }}</label><br>
|
||||
<input class="form-control" type="text" readonly value="{{ absolute_url(asset(path)) }}" id="file-manager-url" />
|
||||
</div>
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if tab == 'information' %}active{% endif %}" data-toggle="tab" href="#tab-fm-information">
|
||||
{{ 'Information'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<p>
|
||||
<label for="file-manager-url2">{{ 'Relative URL'|trans }}</label><br>
|
||||
<input class="form-control" type="text" readonly value="{{ asset(path) }}" id="file-manager-url2" />
|
||||
</p>
|
||||
{% endif %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if tab == 'attributes' %}active{% endif %}" data-toggle="tab" href="#tab-fm-attributes">
|
||||
{{ 'Attributes'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<ul class="list-group mb-3">
|
||||
{% if info.type == 'file' %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'File size'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ info.size|readable_filesize }}</button>
|
||||
{% if splInfo.extension in ['jpeg', 'jpg', 'gif', 'png', 'svg'] %}
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if tab == 'preview' %}active{% endif %}" data-toggle="tab" href="#tab-fm-preview">
|
||||
{{ 'Preview'|trans }}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'Creation date'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ info.mTime|date('Y-m-d H:i') }}</button>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'Modification date'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ info.cTime|date('Y-m-d H:i') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% if info.extension in ['jpeg', 'jpg', 'gif', 'png', 'svg'] %}
|
||||
<div class="card">
|
||||
<div class="card-img-top bg-tiles text-center">
|
||||
<a href="{{ asset(path) }}" target="_blank">
|
||||
<img src="{{ asset(path) }}" class="img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="modal-footer justify-content-between">
|
||||
{% if not isLocked %}
|
||||
<div>
|
||||
<button type="submit" form="form-file-delete" class="btn btn-danger" form="form-file-delete">
|
||||
{{ 'Delete'|trans }}
|
||||
</button>
|
||||
<div class="tab-content pt-4">
|
||||
<div class="tab-pane {% if tab == 'information' %}show active{% endif %}" id="tab-fm-information">
|
||||
{% if splInfo.type == 'file' %}
|
||||
<div class="form-group">
|
||||
<label for="file-manager-url">{{ 'Absolute URL'|trans }}</label><br>
|
||||
<input class="form-control" type="text" readonly value="{{ absolute_url(asset(path)) }}" id="file-manager-url" />
|
||||
</div>
|
||||
|
||||
{% if info.isDir %}
|
||||
<button form="form-file-delete" class="btn btn-primary" data-modal="{{ path('admin_file_manager_directory_rename', {file: info.relativePathname}) }}">
|
||||
{{ 'Rename'|trans }}
|
||||
</button>
|
||||
<p>
|
||||
<label for="file-manager-url2">{{ 'Relative URL'|trans }}</label><br>
|
||||
<input class="form-control" type="text" readonly value="{{ asset(path) }}" id="file-manager-url2" />
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<ul class="list-group mb-3">
|
||||
{% if splInfo.type == 'file' %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'File size'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ splInfo.size|readable_filesize }}</button>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'Creation date'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ splInfo.mTime|date('Y-m-d H:i') }}</button>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ 'Modification date'|trans }}
|
||||
|
||||
<button class="btn btn-sm btn-light">{{ splInfo.cTime|date('Y-m-d H:i') }}</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane {% if tab == 'attributes' %}show active{% endif %}" id="tab-fm-attributes">
|
||||
{% if context == 'tinymce' %}
|
||||
<div class="accordion mb-3" id="fm-attributes">
|
||||
{% for item in form.attributes %}
|
||||
<div class="card">
|
||||
<div class="card-header p-0">
|
||||
<span class="btn btn-link btn-block text-left" data-toggle="collapse" data-target="#fm-attribute-{{ loop.index }}">
|
||||
{{ item.vars.data.label }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="collapse" data-parent="#fm-attributes" id="fm-attribute-{{ loop.index }}">
|
||||
<div class="card-body">
|
||||
<div>{{ 'Value'|trans }}</div>
|
||||
<code>{{ item.vars.data.value }}</code>
|
||||
|
||||
{% set code = 'fattr://' ~ form.vars.data.id ~ '/' ~ item.vars.data.label %}
|
||||
{% set code = '{{' ~ code ~ '}}' %}
|
||||
|
||||
<div class="mt-1">{{ 'Tag to insert in content'|trans }}</div>
|
||||
<code>{{ code }}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<form method="post" action="{{ path('admin_file_manager_info', {tab: 'attributes', file: splInfo.relativePathname}) }}" id="form-fm-attributes">
|
||||
<div class="accordion mb-3" data-collection="collection-fm-attributes" id="form-fm-attributes-collection">
|
||||
{% for item in form.attributes %}
|
||||
<div class="card" data-collection-item="{{ loop.index }}">
|
||||
<div class="card-header p-0">
|
||||
<span class="btn btn-link btn-block text-left" data-toggle="collapse" data-target="#form-fm-attribute-{{ loop.index }}">
|
||||
{{ item.vars.data.label }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="collapse" data-parent="#form-fm-attributes-collection" id="form-fm-attribute-{{ loop.index }}">
|
||||
<div class="card-body">
|
||||
{{ form_row(item.label) }}
|
||||
{{ form_row(item.value) }}
|
||||
|
||||
{% set code = 'fattr://' ~ form.vars.data.id ~ '/' ~ item.vars.data.label %}
|
||||
{% set code = '{{' ~ code ~ '}}' %}
|
||||
|
||||
<div>{{ 'Tag to insert in content'|trans }}</div>
|
||||
<code>{{ code }}</code>
|
||||
|
||||
|
||||
<div class="text-right">
|
||||
<span data-collection-delete-container class="btn btn-sm btn-danger">
|
||||
<span data-collection-delete="{{ loop.index }}" class="fa fa-trash"></span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{ form_rest(item) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div data-collection-add="collection-fm-attributes" class="collection-add">
|
||||
<span class="btn btn-primary" data-collection-add="collection-fm-attributes">
|
||||
<span class="fa fa-plus"></span>
|
||||
{{ 'New attribut'|trans }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{{ form_row(form._token) }}
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="btn btn-light">
|
||||
<span class="fa fa-lock"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
<div class="div">
|
||||
{% if info.type == 'file' %}
|
||||
<a class="btn btn-primary" href="{{ asset(path) }}" target="_blank">
|
||||
{{ 'Download'|trans }}
|
||||
</a>
|
||||
{% if splInfo.extension in ['jpeg', 'jpg', 'gif', 'png', 'svg'] %}
|
||||
<div class="tab-pane {% if tab == 'preview' %}show active{% endif %}" id="tab-fm-preview">
|
||||
<div class="card">
|
||||
<div class="card-img-top bg-tiles text-center">
|
||||
<a href="{{ asset(path) }}" target="_blank">
|
||||
<img src="{{ asset(path) }}" class="img-fluid">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Close'|trans }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer {% if context != 'tinymce' %}justify-content-between{% endif %}">
|
||||
{% if context == 'tinymce' %}
|
||||
<div>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Close'|trans }}</button>
|
||||
<button type="button" class="btn btn-primary" id="file-manager-insert" data-value="{{ asset(path) }}">{{ 'Insert'|trans }}</button>
|
||||
</div>
|
||||
{% else %}
|
||||
<div>
|
||||
{% if not isLocked %}
|
||||
<button type="submit" form="form-fm-delete" class="btn btn-danger">
|
||||
{{ 'Delete'|trans }}
|
||||
</button>
|
||||
|
||||
{% if splInfo.isDir %}
|
||||
<button form="form-file-delete" class="btn btn-primary" data-modal="{{ path('admin_file_manager_directory_rename', {file: splInfo.relativePathname}) }}">
|
||||
{{ 'Rename'|trans }}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<span class="btn btn-light">
|
||||
<span class="fa fa-lock"></span>
|
||||
</span>
|
||||
{% endif %}
|
||||
|
||||
{% if splInfo.type == 'file' %}
|
||||
<a class="btn btn-success" href="{{ asset(path) }}" target="_blank">
|
||||
{{ 'Download'|trans }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{{ 'Close'|trans }}</button>
|
||||
<button type="submit" class="btn btn-primary" form="form-fm-attributes">{{ 'Save'|trans }}</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if not isLocked %}
|
||||
<form method="post" action="{{ path('admin_file_manager_delete') }}" id="form-file-delete" data-form-confirm>
|
||||
<input type="hidden" name="file" value="{{ info.relativePathname }}">
|
||||
<form method="post" action="{{ path('admin_file_manager_delete') }}" id="form-fm-delete" data-form-confirm>
|
||||
<input type="hidden" name="file" value="{{ splInfo.relativePathname }}">
|
||||
<input type="hidden" name="_token" value="{{ csrf_token('delete') }}">
|
||||
<input type="hidden" name="_method" value="DELETE">
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
<template type="text/template" id="collection-fm-attributes">
|
||||
<div class="card" data-collection-item="__name__">
|
||||
<div class="card-header p-0">
|
||||
<span class="btn btn-link btn-block text-left" data-toggle="collapse" data-target="#form-fm-attribute-__name__">
|
||||
{{ 'New attribut'|trans }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="collapse show" id="form-fm-__name__" data-parent="#form-fm-attributes-collection">
|
||||
<div class="card-body">
|
||||
{{ form_row(form.attributes.vars.prototype.label) }}
|
||||
{{ form_row(form.attributes.vars.prototype.value) }}
|
||||
|
||||
<div class="text-right">
|
||||
<span data-collection-delete-container class="btn btn-sm btn-danger"></span>
|
||||
</div>
|
||||
|
||||
{{ form_rest(form.attributes.vars.prototype) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<ul class="nav nav-pills" id="myTab" role="tablist">
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link {% if tab == 'content' %}active{% endif %}" data-toggle="tab" href="#form-node-edit-content">
|
||||
{{ 'Content'|trans }}
|
||||
|
|
85
core/Twig/Extension/FileInformationExtension.php
Normal file
85
core/Twig/Extension/FileInformationExtension.php
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
|
||||
namespace App\Core\Twig\Extension;
|
||||
|
||||
use App\Core\FileManager\FsFileManager;
|
||||
use App\Core\Repository\FileInformationRepositoryQuery;
|
||||
use function Symfony\Component\String\u;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class FileInformationExtension extends AbstractExtension
|
||||
{
|
||||
protected FsFileManager $fsManage²r;
|
||||
protected FileInformationRepositoryQuery $query;
|
||||
|
||||
public function __construct(FsFileManager $fsManager, FileInformationRepositoryQuery $query)
|
||||
{
|
||||
$this->fsManager = $fsManager;
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('file_attribute', [$this, 'fileAttribute']),
|
||||
new TwigFilter('file_attributes', [$this, 'fileAttributes']),
|
||||
];
|
||||
}
|
||||
|
||||
public function fileAttribute(string $file, string $label): ?string
|
||||
{
|
||||
$file = u($file);
|
||||
$pathUri = $this->fsManager->getPathUri();
|
||||
$pathUri2 = '/'.$pathUri;
|
||||
|
||||
if ($file->startsWith($pathUri) || $file->startsWith($pathUri2)) {
|
||||
$file = $file->replaceMatches('#^'.preg_quote($pathUri).'#', '');
|
||||
$file = $file->replaceMatches('#^'.preg_quote($pathUri2).'#', '');
|
||||
}
|
||||
|
||||
$fileInfo = $this->fsManager->getFileInformation((string) $file);
|
||||
|
||||
if ($fileInfo) {
|
||||
foreach ($fileInfo->getAttributes() as $attribute) {
|
||||
if ($attribute['label'] === $label) {
|
||||
return $attribute['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function fileAttributes(?string $content): ?string
|
||||
{
|
||||
preg_match_all('#\{\{\s*fattr://(?P<hash>[a-z0-9]+)\/(?P<label>.+)\s*\}\}#isU', $content, $match, PREG_SET_ORDER);
|
||||
|
||||
foreach ($match as $block) {
|
||||
$hash = $block['hash'];
|
||||
$label = $block['label'];
|
||||
$value = null;
|
||||
|
||||
$fileInfo = $this->query->create()
|
||||
->where('.id LIKE :hash')
|
||||
->setParameter(':hash', $hash.'%')
|
||||
->findOne()
|
||||
;
|
||||
|
||||
if ($fileInfo) {
|
||||
foreach ($fileInfo->getAttributes() as $attribute) {
|
||||
if ($attribute['label'] === $label) {
|
||||
$value = $attribute['value'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content = str_replace($block[0], $value, $content);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
class BlockExtension extends AbstractExtension
|
||||
class UrlExtension extends AbstractExtension
|
||||
{
|
||||
protected UrlGeneratorInterface $urlGenerator;
|
||||
|
||||
|
@ -25,7 +25,7 @@ class BlockExtension extends AbstractExtension
|
|||
];
|
||||
}
|
||||
|
||||
public function replaceUrl($content)
|
||||
public function replaceUrl(?string $content)
|
||||
{
|
||||
preg_match_all('#\{\{\s*url://(?P<route>[a-z_]+)(\?(?P<params>.*))?\s*\}\}#isU', $content, $match, PREG_SET_ORDER);
|
||||
|
Loading…
Reference in a new issue