在 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('(?:[\?&]|&amp;)' + 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 集成。