title: Ckeditor5 connection
body: <p>I use ElFinder as my image editor and ckeditor5 as my editor.</p>
  <p>When I call the CKEditor script, it doesn't work :</p>
  <pre><code>Uncaught (in promise) TypeError: $(...).dialogelfinder is not a function
  </code></pre>
  <p>The problem comes from the connector URL :</p>
  <pre><code>/var/www/......./Sites/Admin/CkEditor5.php:101: string(80) &quot;http://localhost/domain/external/elFinder-master/php/connector.minimal.php&quot; 
  </code></pre>
  <p>Both, the link and the hash are correct. When I click on the image icon it creates this error.</p>
  <p>The script inside a function</p>
  <pre><code>  $connector = static::getElFinderConnector(); // connector URL (see above for example)
  
    $field .= &quot;&lt;script&gt;
    // elfinder folder hash of the destination folder to be uploaded in this CKeditor 5
    const uploadTargetHashImage = 'l2_Q0stRmlsZXM_' . $name;
  
    // elFinder connector URL
    //const connectorUrl = 'php/connector.minimal.php';
    const connectorUrlImage = '{$connector}'; ================&gt; here the problem
  
    // To create CKEditor 5 classic editor
    CKEDITOR.ClassicEditor
       .create(document.getElementById('{$name}'), {
            toolbar: {
                    items: [
                        'ckfinder', '|',
                        'sourceEditing'
                        ],
                     shouldNotGroupWhenFull: true
            },
  
            removePlugins: [
                // These two are commercial, but you can try them out without registering to a trial.
                // 'ExportPdf',
                // 'ExportWord',
                'CKBox',
                //'CKFinder',
                'EasyImage',
                // This sample uses the Base64UploadAdapter to handle image uploads as it requires no configuration.
                // https://ckeditor.com/docs/ckeditor5/latest/features/images/image-upload/base64-upload-adapter.html
                // Storing images as Base64 is usually a very bad idea.
                // Replace it on production website with other solutions:
                // https://ckeditor.com/docs/ckeditor5/latest/features/images/image-upload/image-upload.html
                // 'Base64UploadAdapter',
                'RealTimeCollaborativeComments',
                'RealTimeCollaborativeTrackChanges',
                'RealTimeCollaborativeRevisionHistory',
                'PresenceList',
                'Comments',
                'TrackChanges',
                'TrackChangesData',
                'RevisionHistory',
                'Pagination',
                'WProofreader',
                // Careful, with the Mathtype plugin CKEditor will not load when loading this sample
                // from a local file system (file://) - load this site via HTTP server if you enable MathType
                'MathType'
            ]
        } )
      .then(editor =&gt; {
        const ckf = editor.commands.get('ckfinder'),
          fileRepo = editor.plugins.get('FileRepository'),
          ntf = editor.plugins.get('Notification'),
          i18 = editor.locale.t,
          // Insert images to editor window
          insertImages = urls =&gt; {
            const imgCmd = editor.commands.get('imageUpload');
            if (!imgCmd.isEnabled) {
                ntf.showWarning(i18('Could not insert image at the current position.'), {
                    title: i18('Inserting image failed'),
                    namespace: 'ckfinder'
                });
            return;
            }
            editor.execute('imageInsert', { source: urls });
          },
          // To get elFinder instance
          getfm = open =&gt; {
          return new Promise((resolve, reject) =&gt; {
            // Execute when the elFinder instance is created
            const done = () =&gt; {
              if (open) {
                // request to open folder specify
                if (!Object.keys(_fm.files()).length) {
                  // when initial request
                  _fm.one('open', () =&gt; {
                    _fm.file(open)? resolve(_fm) : reject(_fm, 'errFolderNotFound');
                  });
                                  } else {
                  // elFinder has already been initialized
                  new Promise((res, rej) =&gt; {
                    if (_fm.file(open)) {
                      res();
                    } else {
                      // To acquire target folder information
                      _fm.request({cmd: 'parents', target: open}).done(e =&gt;{
                        _fm.file(open)? res() : rej();
                      }).fail(() =&gt; {
                        rej();
                      });
                                          }
                  }).then(() =&gt; {
                    // Open folder after folder information is acquired
                    _fm.exec('open', open).done(() =&gt; {
                      resolve(_fm);
                    }).fail(err =&gt; {
                      reject(_fm, err? err : 'errFolderNotFound');
                    });
                  }).catch((err) =&gt; {
                    reject(_fm, err? err : 'errFolderNotFound');
                  });
                }
              } else {
                // show elFinder manager only
                resolve(_fm);
              }
            };
  
            // Check elFinder instance
            if (_fm) {
              // elFinder instance has already been created
              done();
            } else {
              // To create elFinder instance
              _fm = $('&lt;div/&gt;').dialogelfinder({
                // dialog title
                title : 'File Manager',
                // connector URL
                url : connectorUrlImage,
                // start folder setting
                startPathHash : open? open : void(0),
                // Set to do not use browser history to un-use location.hash
                useBrowserHistory : false,
                // Disable auto open
                autoOpen : false,
                // elFinder dialog width
                width : '80%',
                // set getfile command options
                commandsOptions : {
                getfile: {
                    oncomplete : 'close',
                    multiple : true
                }
              },
              // Insert in CKEditor when choosing files
              getFileCallback : (files, fm) =&gt; {
              let imgs = [];
              fm.getUI('cwd').trigger('unselectall');
              $.each(files, function(i, f) {
                if (f &amp;&amp; f.mime.match(/^image\//i)) {
                  imgs.push(fm.convAbsUrl(f.url));
                } else {
                    editor.execute('link', fm.convAbsUrl(f.url));
                }
              });
              if (imgs.length) {
                insertImages(imgs);
              }
             }
            }).elfinder('instance');
                done();
            }
          });
        };
  
        // elFinder instance
        let _fm;
  
        if (ckf) {
          // Take over ckfinder execute()
          ckf.execute = () =&gt; {
            getfm().then(fm =&gt; {
              fm.getUI().dialogelfinder('open');
            });
            };
        }
  
        // Make uploader
        const uploder = function(loader) {
          let upload = function(file, resolve, reject) {
            getfm(uploadTargetHashImage).then(fm =&gt; {
              let fmNode = fm.getUI();
                  fmNode.dialogelfinder('open');
                  fm.exec('upload', {files: [file], target: uploadTargetHashImage}, void(0), uploadTargetHashImage)
                .done(data =&gt; {
                if (data.added &amp;&amp; data.added.length) {
                  fm.url(data.added[0].hash, { async: true }).done(function(url) {
                    resolve({
                        'default': fm.convAbsUrl(url)
                        });
                        fmNode.dialogelfinder('close');
                      }).fail(function() {
                    reject('errFileNotFound');
                  });
                            } else {
                  reject(fm.i18n(data.error? data.error : 'errUpload'));
                  fmNode.dialogelfinder('close');
                }
              })
              .fail(err =&gt; {
                const error = fm.parseError(err);
                reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles'));
              });
              }).catch((fm, err) =&gt; {
              const error = fm.parseError(err);
              reject(fm.i18n(error? (error === 'userabort'? 'errAbort' : error) : 'errUploadNoFiles'));
            });
            };
  
              this.upload = function() {
                return new Promise(function(resolve, reject) {
                  if (loader.file instanceof Promise || (loader.file &amp;&amp; typeof loader.file.then === 'function')) {
                    loader.file.then(function(file) {
                      upload(file, resolve, reject);
                    });
                  } else {
                    upload(loader.file, resolve, reject);
                  }
                  });
              };
              this.abort = function() {
                _fm &amp;&amp; _fm.getUI().trigger('uploadabort');
              };
            };
  
            // Set up image uploader
            fileRepo.createUploadAdapter = loader =&gt; {
            return new uploder(loader);
          };
        })
        .catch(error =&gt; {
        console.error( error );
      });
                  &lt;/script&gt;&quot;;
  </code></pre>