CKEditor 4 file manager integration sample

Play on CodePen External link All samples on CodePen External link

Read the explanation of this demo below
Demo
HTML
JavaScript
CSS
<h1 class="h5 mb-3">Flmngr: CKEditor 4 file manager</h1>

<textarea id="editor"></textarea>

<div class="my-4">
  <div>
    <div class="h5 mb-2">Attached images</div>
    <div id="btn" class="btn btn-primary" style="opacity:0.2;cursor:default">Select files...</div>
    <div id="loading" style="font-size:12px">Loading file manager...</div>
    <p class="hint"><b>Hint</b>: after you selected gallery images,<br/> you can re-manage the existing gallery.</p>
  </div>
  <div id="images">
  </div>
</div>
"use strict";
let editor = CKEDITOR.replace("editor", {
    extraPlugins: "file-manager",
    skin: "n1theme",
    toolbar: [
        { name: 'standard', items: ['Bold', 'Italic', '-', 'FontSize', 'Format', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'TextColor', 'BGColor', '-', 'RemoveFormat'] },
        '/',
        { name: 'flmngr', items: ['Upload', 'Flmngr', 'ImgPen'] }
    ],
    Flmngr: {
        apiKey: "FLMNFLMN",
        urlFileManager: 'https://fm.flmngr.com/fileManager',
        urlFiles: 'https://fm.flmngr.com/files', // demo file storage
    }
});
// Let's wait for CKEditor is initialized...
editor.on('instanceReady', function () {
    // ...and get Flmngr API
    editor.getFlmngr((Flmngr) => {
        // In this demo we pass Flmngr API into inner functions and callbacks.
        // You can save it somewhere and reuse without passing as an argument.
        attachOnClickListenerToButton(Flmngr);
    });
});
function attachOnClickListenerToButton(Flmngr) {
    let elBtn = document.getElementById("btn");
    // Style button as ready to be pressed
    elBtn.style.opacity = 1;
    elBtn.style.cursor = "pointer";
    let elLoading = document.getElementById("loading");
    elLoading.parentElement.removeChild(elLoading);
    // Add a listener for selecting files
    elBtn.addEventListener("click", () => {
        selectFiles(Flmngr);
    });
}
function selectFiles(Flmngr) {
    // Collect URLs of images of existing gallery set
    let elsExistingImages = document.querySelectorAll("#images img");
    let urls = [];
    for (let i = 0; i < elsExistingImages.length; i++)
        urls.push(elsExistingImages.item(i).src);
    Flmngr.open({
        list: urls,
        isMultiple: true,
        acceptExtensions: ["png", "jpeg", "jpg", "webp", "gif"],
        onFinish: (files) => {
            showSelectedImages(Flmngr, files);
        }
    });
}
function showSelectedImages(Flmngr, files) {
    let elImages = document.getElementById("images");
    elImages.innerHTML = "";
    /*let elP =  document.createElement("p");
    elP.textContent = files.length + " images selected";
    elImages.appendChild(elP);*/
    for (let file of files) {
        let urlOriginal = Flmngr.getNoCacheUrl(file.url);
        let el = document.createElement("div");
        el.className = "image";
        elImages.appendChild(el);
        let elDiv = document.createElement("div");
        el.appendChild(elDiv);
        let elImg = document.createElement("img");
        elImg.src = urlOriginal;
        elImg.alt = "Image selected in Flmngr";
        elDiv.appendChild(elImg);
        let elP = document.createElement("p");
        elP.textContent = file.url;
        el.appendChild(elP);
    }
}
body {
  padding: 20px;
  background-color: #F4F4F4;
}

#images {
  margin-top: 20px;
  display: flex;
}
#images .image {
  border: 1px solid #DDD;
  box-shadow: 5px 5px 0 0 #DDD;
  background-color: white;
  padding: 10px;
  display: inline-flex;
  flex-direction: column;
  margin: 0 25px 25px 0;
  align-items: center;
}
#images .image div {
  height: 250px;
  max-width: 350px;
  text-align: center;
}
#images .image div img {
  max-height: 100%;
  max-width: 100%;
  margin: auto;
}
#images .image p {
  margin: 5px 0 0 0;
  font-size: 14px;
  color: #444;
}

.hint {
  color: #007FFF;
  font-size: 14px;
  margin-top: 10px;
  line-height: 16px;
}

In this sample we show how to:

  1. Enable Flmngr file manager in CKEditor after you copied the plugin.
  2. Configure paths and URLs of Flmngr inside CKEditor.
  3. Call Flmngr outside of CKEditor (your custom external widgets).

Here is a standard practice to enable a CKEditor plugin: pass the name of its directory as extraPlugins parameter on CKEditor initialization (CKEDITOR.replace(id, {params}) function or in config.js file of CKEditor).

Then you add a config section Flmngr in order to configure Flmngr-specific parameters. CKEditor will call Flmngr.load({param}) method with exactly these parameters on the initialization.

Also do not forget to add the buttons of Flmngr on the CKEditor toolbar in toolbar parameter.

Now CKEditor is initialized and ready and you can use Flmngr there. In most cases, this is the end of the configuration of CKEditor.

But what if you want to implement some custom files field outside of CKEditor. For example you need to call Flmngr file manager to let the user pick some images from the same storage and reuse the configuration you passed into CKEditor. To do this you need to retrieve Flmngr API object from the instance of CKEditor. In this sample we have one CKEditor instance, but you can have two or more editors on the page, so they may have different initialization parameters (only apiKey parameter must be the same within one web page).

So we do it using standard CKEditor API: we get an instance of CKEditor editor as the result of CKEDITOR.replace function and wait for its initialization (to be sure the Flmngr plugin was loaded) by subscribing on instanceReady event.

At this moment in editor variable you have the instance of CKEditor. Let's get an instance of Flmngr API object. Use editor.getFlmngr((Flmngr) => void) function to wait for Flmngr is initialized too and passed Flmngr argument of the callback function will contain the interface with whole Flmngr API, already loaded (please do not call Flmngr.load({params}) again).'.

Now with the Flmngr API object, you can implement managing file gallery on your custom field. This is fully the same as in the Manage image gallery sample. Just attach a listener to a button of your control and call there Flmngr.open({params}) method with some parameters to let the user pick images.

We experience problems with Zendesk, our ticket system, mail sent there won't be delivered. Please write us directly to support@flmngr.com until the problem is resolved.