在 Symfony 上使用 ElFinder:我不能 select 图片
Using ElFinder on Symfony: I can't select images
我想在我的 Symfony 项目中使用 ElFinder 作为我的文件管理器。我遵循了 GitHub 上的文档。在我的 routes.yaml:
elfinder:
resource: '@FMElfinderBundle/Resources/config/routing.yaml'
security.yaml
- { path: ^/efconnect, role: [ROLE_USER] }
- { path: ^/elfinder, role: [ROLE_USER] }
最后 fm_elfinder.yaml
fm_elfinder:
instances:
default:
locale: '%locale%' # defaults to current request locale
editor: ckeditor # other options are tinymce, tinymce4, fm_tinymce, form, simple, custom
connector:
roots:
uploads:
driver: LocalFileSystem
path: uploads
upload_max_size: 2M
然后我将它添加到 Sonata 的 Admin 元素上,如下所示:
受保护的函数 configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('Contenu')
->add('published', CheckboxType::class, ['required' => false, 'label' => 'Publier'])
->add('title', TextType::class, ['required' => true, 'label' => 'Titre'])
->add('textLink', TextType::class, ['required' => true, 'label' => 'Texte du lien'])
->add('media', ElFinderType::class, array(
'label' => 'Photo',
'enable' => true,
'required' => true,
'instance' => 'default',
'attr' => array('class' => 'form-control')
)
)
->end();
}
然后我继续 Sonata Admin,当我尝试添加图像时,window 打开,我添加了一个 jpeg,但是当我点击它时,似乎没有任何反应。就像,我可以 select 但我的 window 保持打开状态并且我的字段没有填满图像名称。
感谢您的帮助。
好的,我让它在我的 easyadmin 表单上工作。这是 easyAdmin 2 配置:
easy_admin:
entities:
BlogPost:
class: App\Entity\BlogPost
form:
fields:
- { property: 'title', label: 'page.title' }
- { property: 'image', type: 'App\Form\ElFinderType', label: 'blog.image.file', type_options: { enable: true, instance: 'single' } }
(我将 vendor/helios-ag/fm-elfinder-bundle/src/Form/Type/ElFinderType.php
文件复制到 App\Form\ElFinderType.php
。这不是必需的)。
我将 fm_elfinder 连接器设置为简单:
# src/packages/fm_elfinder.yaml
fm_elfinder:
instances:
single:
locale: fr
editor: simple
theme: smoothness
relative_path: false
connector:
roots:
uploads:
driver: LocalFileSystem
path: uploads/images
show_hidden: false
upload_allow: [ 'image/png', 'image/jpg', 'image/jpeg' ]
upload_deny: [ 'all' ]
upload_max_size: 2M
接下来,我将捆绑包中的两个模板文件复制到我的 templates\bundles
目录中:
{# templates/bundles/FMElfinderBundle/Form/elfinder_widget.html.twig #}
{% block elfinder_widget %}
<div class="buttons">
<input type="button" {{ block('widget_attributes') }}
data-type="elfinder-remove-button" value="Delete" class="{% if value is empty %}hide{% endif %} remove-button"/>
<input type="button" {{ block('widget_attributes') }}
data-type="elfinder-add-button" value="Add" class="{% if value is not empty %}hide{% endif %} add-button"/>
</div>
{% if value is not empty %}
<img src="{{ value }}" alt="">
{% endif %}
<input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}
data-type="elfinder-input-field" class="hide"/>
{% if enable and instance is defined %}
<script type="text/javascript" charset="utf-8">
const addButtonSelector = '[data-type="elfinder-add-button"][id="{{ id }}"]';
const removeButtonSelector = '[data-type="elfinder-remove-button"][id="{{ id }}"]';
const inputSelector = '[data-type="elfinder-input-field"][id="{{ id }}"]';
live('click', addButtonSelector, () => {
window.open("{{ path('elfinder', {'instance': instance, 'homeFolder': homeFolder }) }}?id={{ id }}", "popupWindow", "height=450, width=900");
});
removeButtonListener()
function live(eventType, elementQuerySelector, cb) {
document.addEventListener(eventType, function (event) {
const qs = document.querySelectorAll(elementQuerySelector);
if (qs) {
let el = event.target, index = -1;
while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
el = el.parentElement;
}
if (index > -1) {
cb.call(el, event);
}
}
})
}
function setValue(value) {
document.querySelector(inputSelector).value = value;
}
function displayImage(value) {
const inputElement = document.querySelector(inputSelector);
const parent = inputElement.parentElement
const image = document.createElement("img");
image.src = value;
parent.append(image)
const removeButton = document.querySelector(removeButtonSelector);
const addButton = document.querySelector(addButtonSelector);
removeButton.classList.remove('hide')
addButton.classList.add('hide')
removeButtonListener()
}
function removeButtonListener() {
const removeButtonElement = document.querySelector(removeButtonSelector);
if(removeButtonElement){
removeButtonElement.addEventListener('click', () => {
const addButtonElement = document.querySelector(addButtonSelector);
removeButtonElement.classList.remove('hide')
const parent = removeButtonElement.closest('.form-widget')
const inputElement = parent.querySelector('[data-type="elfinder-input-field"]');
inputElement.value = null
const imageElement = parent.getElementsByTagName('img')[0]
if (imageElement) {
parent.removeChild(imageElement)
}
removeButtonElement.classList.add('hide')
addButtonElement.classList.remove('hide')
document.querySelector(inputSelector).value = null;
})
}
}
</script>
{% endif %}
{% endblock %}
第一个包含字段和填写它们所需的 JavaScript。我添加了一个 Add
按钮。这将打开 elfinder,一旦选择了图像,此按钮就会隐藏,并会添加一个 Remove
按钮。
接下来是 ElFinder window :
{# templates/bundles/FMElfinderBundle/Elfinder/simple.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<script data-main="{{ path('ef_main_js') }}"
src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
<script>
function getUrlParam(paramName) {
const reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i');
const match = window.location.search.match(reParam);
return (match && match.length > 1) ? match[1] : '' ;
}
define('elFinderConfig', {
// elFinder options (REQUIRED)
// Documentation for client options:
// https://github.com/Studio-42/elFinder/wiki/Client-configuration-options
defaultOpts: {
url: '{{ path('ef_connect', { 'instance': instance, 'homeFolder': homeFolder } ) }}',
lang: '{{ locale }}',
onlyMimes: {{ onlyMimes|raw }},
getFileCallback: function (file) {
window.opener.setValue(file.url);
window.opener.displayImage(file.url);
window.close();
},
commandsOptions: {
edit: {
extraOptions: {
// set API key to enable Creative Cloud image editor
// see https://console.adobe.io/
creativeCloudApiKey: '',
// browsing manager URL for CKEditor, TinyMCE
// uses self location with the empty value
managerUrl: ''
}
},
quicklook: {
// to enable CAD-Files and 3D-Models preview with sharecad.org
sharecadMimes: ['image/vnd.dwg', 'image/vnd.dxf', 'model/vnd.dwf', 'application/vnd.hp-hpgl', 'application/plt', 'application/step', 'model/iges', 'application/vnd.ms-pki.stl', 'application/sat', 'image/cgm', 'application/x-msmetafile'],
// to enable preview with Google Docs Viewer
googleDocsMimes: ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/postscript', 'application/rtf'],
// to enable preview with Microsoft Office Online Viewer
// these MIME types override "googleDocsMimes"
officeOnlineMimes: ['application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']
}
},
// bootCallback calls at before elFinder boot up
bootCallback: function (fm, extraObj) {
/* any bind functions etc. */
fm.bind('init', function () {
});
// for example set document.title dynamically.
var title = document.title;
fm.bind('open', function () {
var path = '',
cwd = fm.cwd();
if (cwd) {
path = fm.path(cwd.hash) || null;
}
document.title = path ? path + ':' + title : title;
}).bind('destroy', function () {
document.title = title;
});
}
},
managers: {
// 'DOM Element ID': { /* elFinder options of this DOM Element */ }
'elfinder': {}
}
});
</script>
</head>
<body>
<!-- Element where elFinder will be created (REQUIRED) -->
<div id="elfinder"></div>
</body>
</html>
这里主要添加的是 getFileCallback
函数:
getFileCallback: function (file) {
window.opener.setValue(file.url);
window.opener.displayImage(file.url);
window.close();
},
现在这对我的单个图像字段工作正常并且不影响 CKEditor 集成。
我想在我的 Symfony 项目中使用 ElFinder 作为我的文件管理器。我遵循了 GitHub 上的文档。在我的 routes.yaml:
elfinder:
resource: '@FMElfinderBundle/Resources/config/routing.yaml'
security.yaml
- { path: ^/efconnect, role: [ROLE_USER] }
- { path: ^/elfinder, role: [ROLE_USER] }
最后 fm_elfinder.yaml
fm_elfinder:
instances:
default:
locale: '%locale%' # defaults to current request locale
editor: ckeditor # other options are tinymce, tinymce4, fm_tinymce, form, simple, custom
connector:
roots:
uploads:
driver: LocalFileSystem
path: uploads
upload_max_size: 2M
然后我将它添加到 Sonata 的 Admin 元素上,如下所示: 受保护的函数 configureFormFields(FormMapper $formMapper)
{
$formMapper
->with('Contenu')
->add('published', CheckboxType::class, ['required' => false, 'label' => 'Publier'])
->add('title', TextType::class, ['required' => true, 'label' => 'Titre'])
->add('textLink', TextType::class, ['required' => true, 'label' => 'Texte du lien'])
->add('media', ElFinderType::class, array(
'label' => 'Photo',
'enable' => true,
'required' => true,
'instance' => 'default',
'attr' => array('class' => 'form-control')
)
)
->end();
}
然后我继续 Sonata Admin,当我尝试添加图像时,window 打开,我添加了一个 jpeg,但是当我点击它时,似乎没有任何反应。就像,我可以 select 但我的 window 保持打开状态并且我的字段没有填满图像名称。 感谢您的帮助。
好的,我让它在我的 easyadmin 表单上工作。这是 easyAdmin 2 配置:
easy_admin:
entities:
BlogPost:
class: App\Entity\BlogPost
form:
fields:
- { property: 'title', label: 'page.title' }
- { property: 'image', type: 'App\Form\ElFinderType', label: 'blog.image.file', type_options: { enable: true, instance: 'single' } }
(我将 vendor/helios-ag/fm-elfinder-bundle/src/Form/Type/ElFinderType.php
文件复制到 App\Form\ElFinderType.php
。这不是必需的)。
我将 fm_elfinder 连接器设置为简单:
# src/packages/fm_elfinder.yaml
fm_elfinder:
instances:
single:
locale: fr
editor: simple
theme: smoothness
relative_path: false
connector:
roots:
uploads:
driver: LocalFileSystem
path: uploads/images
show_hidden: false
upload_allow: [ 'image/png', 'image/jpg', 'image/jpeg' ]
upload_deny: [ 'all' ]
upload_max_size: 2M
接下来,我将捆绑包中的两个模板文件复制到我的 templates\bundles
目录中:
{# templates/bundles/FMElfinderBundle/Form/elfinder_widget.html.twig #}
{% block elfinder_widget %}
<div class="buttons">
<input type="button" {{ block('widget_attributes') }}
data-type="elfinder-remove-button" value="Delete" class="{% if value is empty %}hide{% endif %} remove-button"/>
<input type="button" {{ block('widget_attributes') }}
data-type="elfinder-add-button" value="Add" class="{% if value is not empty %}hide{% endif %} add-button"/>
</div>
{% if value is not empty %}
<img src="{{ value }}" alt="">
{% endif %}
<input type="text" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}
data-type="elfinder-input-field" class="hide"/>
{% if enable and instance is defined %}
<script type="text/javascript" charset="utf-8">
const addButtonSelector = '[data-type="elfinder-add-button"][id="{{ id }}"]';
const removeButtonSelector = '[data-type="elfinder-remove-button"][id="{{ id }}"]';
const inputSelector = '[data-type="elfinder-input-field"][id="{{ id }}"]';
live('click', addButtonSelector, () => {
window.open("{{ path('elfinder', {'instance': instance, 'homeFolder': homeFolder }) }}?id={{ id }}", "popupWindow", "height=450, width=900");
});
removeButtonListener()
function live(eventType, elementQuerySelector, cb) {
document.addEventListener(eventType, function (event) {
const qs = document.querySelectorAll(elementQuerySelector);
if (qs) {
let el = event.target, index = -1;
while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
el = el.parentElement;
}
if (index > -1) {
cb.call(el, event);
}
}
})
}
function setValue(value) {
document.querySelector(inputSelector).value = value;
}
function displayImage(value) {
const inputElement = document.querySelector(inputSelector);
const parent = inputElement.parentElement
const image = document.createElement("img");
image.src = value;
parent.append(image)
const removeButton = document.querySelector(removeButtonSelector);
const addButton = document.querySelector(addButtonSelector);
removeButton.classList.remove('hide')
addButton.classList.add('hide')
removeButtonListener()
}
function removeButtonListener() {
const removeButtonElement = document.querySelector(removeButtonSelector);
if(removeButtonElement){
removeButtonElement.addEventListener('click', () => {
const addButtonElement = document.querySelector(addButtonSelector);
removeButtonElement.classList.remove('hide')
const parent = removeButtonElement.closest('.form-widget')
const inputElement = parent.querySelector('[data-type="elfinder-input-field"]');
inputElement.value = null
const imageElement = parent.getElementsByTagName('img')[0]
if (imageElement) {
parent.removeChild(imageElement)
}
removeButtonElement.classList.add('hide')
addButtonElement.classList.remove('hide')
document.querySelector(inputSelector).value = null;
})
}
}
</script>
{% endif %}
{% endblock %}
第一个包含字段和填写它们所需的 JavaScript。我添加了一个 Add
按钮。这将打开 elfinder,一旦选择了图像,此按钮就会隐藏,并会添加一个 Remove
按钮。
接下来是 ElFinder window :
{# templates/bundles/FMElfinderBundle/Elfinder/simple.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<script data-main="{{ path('ef_main_js') }}"
src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
<script>
function getUrlParam(paramName) {
const reParam = new RegExp('(?:[\?&]|&)' + paramName + '=([^&]+)', 'i');
const match = window.location.search.match(reParam);
return (match && match.length > 1) ? match[1] : '' ;
}
define('elFinderConfig', {
// elFinder options (REQUIRED)
// Documentation for client options:
// https://github.com/Studio-42/elFinder/wiki/Client-configuration-options
defaultOpts: {
url: '{{ path('ef_connect', { 'instance': instance, 'homeFolder': homeFolder } ) }}',
lang: '{{ locale }}',
onlyMimes: {{ onlyMimes|raw }},
getFileCallback: function (file) {
window.opener.setValue(file.url);
window.opener.displayImage(file.url);
window.close();
},
commandsOptions: {
edit: {
extraOptions: {
// set API key to enable Creative Cloud image editor
// see https://console.adobe.io/
creativeCloudApiKey: '',
// browsing manager URL for CKEditor, TinyMCE
// uses self location with the empty value
managerUrl: ''
}
},
quicklook: {
// to enable CAD-Files and 3D-Models preview with sharecad.org
sharecadMimes: ['image/vnd.dwg', 'image/vnd.dxf', 'model/vnd.dwf', 'application/vnd.hp-hpgl', 'application/plt', 'application/step', 'model/iges', 'application/vnd.ms-pki.stl', 'application/sat', 'image/cgm', 'application/x-msmetafile'],
// to enable preview with Google Docs Viewer
googleDocsMimes: ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/postscript', 'application/rtf'],
// to enable preview with Microsoft Office Online Viewer
// these MIME types override "googleDocsMimes"
officeOnlineMimes: ['application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']
}
},
// bootCallback calls at before elFinder boot up
bootCallback: function (fm, extraObj) {
/* any bind functions etc. */
fm.bind('init', function () {
});
// for example set document.title dynamically.
var title = document.title;
fm.bind('open', function () {
var path = '',
cwd = fm.cwd();
if (cwd) {
path = fm.path(cwd.hash) || null;
}
document.title = path ? path + ':' + title : title;
}).bind('destroy', function () {
document.title = title;
});
}
},
managers: {
// 'DOM Element ID': { /* elFinder options of this DOM Element */ }
'elfinder': {}
}
});
</script>
</head>
<body>
<!-- Element where elFinder will be created (REQUIRED) -->
<div id="elfinder"></div>
</body>
</html>
这里主要添加的是 getFileCallback
函数:
getFileCallback: function (file) {
window.opener.setValue(file.url);
window.opener.displayImage(file.url);
window.close();
},
现在这对我的单个图像字段工作正常并且不影响 CKEditor 集成。