Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Adapter for upload files #5999

Open
felek000 opened this issue Dec 18, 2019 · 6 comments
Open

Custom Adapter for upload files #5999

felek000 opened this issue Dec 18, 2019 · 6 comments
Labels
package:upload support:2 An issue reported by a commercially licensed client. type:improvement This issue reports a possible enhancement of an existing feature.

Comments

@felek000
Copy link

felek000 commented Dec 18, 2019

Provide a description of the task

I want to upload custom adapter for handle upload files.

function ulpoadAdapterDrop(editor) {
    editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
        return new UploadDrop(loader);
    };
}

And it fires when i upload image files.
Now i want to either edit my adapter to handle example pdf or create custom adapter.
Still in my UploadDrop adapter events only works when i upload images.

export default class UploadDrop {
    constructor(loader) {
        // The file loader instance to use during the upload.
        this.loader = loader;
    }

    // Starts the upload process.
    upload() {
        console.log('aaaa', this.loader);

How can i allow adapter works also in other files types ?

Also i try solution to return other adapter.
like found on github:

const fileName = loader.file.name;

    if ( fileName.endsWith( '.mov' ) ) {
        return new FileUploadAdapter( ... );
    } else {
        return new GenericUploadAdapter( ... );
    }

but loader.file is a promise so that will no work.
Any suggestions how to handle that ?

What steps should be taken to fulfill the task?

📃 Other details

  • Browser: chrome
  • OS: windows
  • CKEditor version: 5
  • Installed CKEditor plugins: …
@felek000 felek000 added the type:task This issue reports a chore (non-production change) and other types of "todos". label Dec 18, 2019
@Reinmar Reinmar added status:confirmed type:improvement This issue reports a possible enhancement of an existing feature. package:upload and removed type:task This issue reports a chore (non-production change) and other types of "todos". labels Jan 14, 2020
@Reinmar Reinmar added this to the nice-to-have milestone Jan 14, 2020
@Reinmar
Copy link
Member

Reinmar commented Jan 14, 2020

It seems that we missed this use case somehow, or something changed in the API which makes solving this easily harder now.

What I'd do now is implementing an adapter class which will serve as a proxy to two other adapters. It seems to be the simplest option right now.

But it's a valid ticket – we should at least document how to do this.

@felek000
Copy link
Author

I don't know if is valid solution.
in ClassicEditor.builtinPlugins = [dropEvent]

function dropEvent(editor) {
    editor.editing.view.document.on('drop',async (evt, data) => {
        // Stop execute next callbacks.
        evt.stop();
        console.log('dropppppp',data);
        /**@TODO API*/
       
        const content = `<a href=""/>link file</a>`;
        const viewFragment = editor.data.processor.toView(content);
        const modelFragment = editor.data.toModel(viewFragment);

        editor.model.insertContent(modelFragment, editor.model.document.selection);

        // Stop the default event action.
        data.preventDefault();
    }, {priority: 'high'});

    editor.editing.view.document.on('dragover', (evt, data) => {
        evt.stop();
        data.preventDefault();
    }, {priority: 'high'});
}

@SimonBrazell
Copy link

SimonBrazell commented Apr 28, 2021

For those interested this is my variation of @felek000's solution above, it uploads the file and inserts an anchor tag if the file is not an image (e.g. PDF), otherwise it just uses whatever file adapter you are currently using with CKeditor, in my case the Simple Upload Adapter for images.

function InsertFile(editor) {
  editor.editing.view.document.on(
    "drop",
    async (event, data) => {
      if (
        data.dataTransfer.files &&
        !data.dataTransfer.files[0].type.includes("image")
      ) {
        event.stop();
        data.preventDefault();
        const file = data.dataTransfer.files[0];
        const form = new FormData();
        form.append("Content-Type", file.type);
        form.append("upload", file);
        let httpRequest;
        if (window.XMLHttpRequest) {
          httpRequest = new XMLHttpRequest();
        } else if (window.ActiveXObject) {
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        }
        httpRequest.upload.onprogress = (evt) => {
          let progress = undefined;
          progress = (evt.loaded / evt.total) * 100;
          // Update progress UI...
        };
        httpRequest.open("POST", "/images", true);
        httpRequest.onload = () => {
          if (httpRequest.status === 200) {
            const body = JSON.parse(httpRequest.responseText);
            const content = `<a href="${body.url}"/>${data.dataTransfer.files[0].name}</a>`;
            const viewFragment = editor.data.processor.toView(content);
            const modelFragment = editor.data.toModel(viewFragment);
            editor.model.insertContent(
              modelFragment,
              editor.model.document.selection
            );
          } else {
            alert(
              "Something went wrong while uploading your file, please check your \
              network connection and try again."
            );
            console.error(
              "Request failed.  Returned status of " + httpRequest.status
            );
          }
        };
        httpRequest.send(form);
      }
    },
    { priority: "high" }
  );

  editor.editing.view.document.on(
    "dragover",
    (event, data) => {
      event.stop();
      data.preventDefault();
    },
    { priority: "high" }
  );
}

@SimonBrazell
Copy link

A more complete solution, my project includes bootstrap so I've made use of some of components from it, but those can easily be replaced with something else.

import Plugin from "@ckeditor/ckeditor5-core/src/plugin";
import ButtonView from "@ckeditor/ckeditor5-ui/src/button/buttonview";
import icon from "@ckeditor/ckeditor5-ckfinder/theme/icons/browse-files.svg";

const progress = `
<div class="modal fade" id="progress-modal" tabindex="-1" role="dialog">
  <div class="modal-dialog modal-lg modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h4 class="modal-title">Uploading file, please wait...</h4>
      </div>
      <div class="modal-body">
        <div class="progress" style="width: 100%; max-width: 100%">
          <div
            class="progress-bar progress-bar-success progress-bar-striped active"
            role="progressbar"
            aria-valuenow="0"
            aria-valuemin="0"
            aria-valuemax="100"
            style="width: 0%"
          ></div>
        </div>
      </div>
    </div>
  </div>
</div>`;

export default class InsertFile extends Plugin {
  init() {
    const editor = this.editor;
    editor.editing.view.document.on(
      "drop",
      async (event, data) => {
        if (
          data.dataTransfer.files &&
          !data.dataTransfer.files[0].type.includes("image")
        ) {
          event.stop();
          data.preventDefault();
          this.insert(data.dataTransfer.files[0], editor);
        }
      },
      { priority: "high" }
    );

    editor.editing.view.document.on(
      "dragover",
      (event, data) => {
        event.stop();
        data.preventDefault();
      },
      { priority: "high" }
    );

    editor.ui.componentFactory.add("insertFile", (locale) => {
      const inputElement = document.createElement("input");
      inputElement.type = "file";
      inputElement.accept =
        ".doc,.docx,.pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/pdf";
      inputElement.addEventListener("change", (event) => {
        this.insert(event.target.files[0], editor);
      });

      const view = new ButtonView(locale);

      view.set({
        label: "Insert file",
        icon: icon,
        tooltip: true,
      });

      view.on("execute", () => {
        inputElement.dispatchEvent(new MouseEvent("click"));
      });

      return view;
    });
  }

  insert(file, editor) {
    if (file) {
      $("body").append(progress);
      $("#progress-modal").modal({
        backdrop: "static",
        keyboard: false,
      });
      const form = new FormData();
      form.append("Content-Type", file.type);
      form.append("upload", file);
      let httpRequest;
      if (window.XMLHttpRequest) {
        httpRequest = new XMLHttpRequest();
      } else if (window.ActiveXObject) {
        httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
      }
      httpRequest.upload.onprogress = (ev) => {
        let progress = undefined;
        progress = (ev.loaded / ev.total) * 100;
        $(".progress-bar")
          .css("width", progress + "%")
          .attr("aria-valuenow", progress);
      };
      httpRequest.open("POST", "/images", true);
      httpRequest.onload = () => {
        if (httpRequest.status === 200) {
          const body = JSON.parse(httpRequest.responseText);
          const content = `<a href="${body.url}"/>${file.name}</a>`;
          const viewFragment = editor.data.processor.toView(content);
          const modelFragment = editor.data.toModel(viewFragment);
          editor.model.insertContent(
            modelFragment,
            editor.model.document.selection
          );
          $("#progress-modal").modal("hide");
        } else {
          $("#progress-modal").modal("hide");
          alert(
            `Something went wrong while uploading your file, please check your network connection and try again.
          (${httpRequest.status} ${httpRequest.statusText})`
          );
          console.error(
            "Request failed.  Returned status of " + httpRequest.status,
            httpRequest
          );
        }
      };
      httpRequest.send(form);
    }
  }
}

@zgpnuaa
Copy link

zgpnuaa commented Sep 19, 2022

Is there any progress now? Can I customize multiple upload adapters?

@aldonace-wu aldonace-wu added support:1 An issue reported by a commercially licensed client. support:2 An issue reported by a commercially licensed client. and removed support:1 An issue reported by a commercially licensed client. labels Sep 7, 2023
@Nick87
Copy link

Nick87 commented Aug 6, 2024

It would be very nice and useful to have this featured implemented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:upload support:2 An issue reported by a commercially licensed client. type:improvement This issue reports a possible enhancement of an existing feature.
Projects
None yet
Development

No branches or pull requests

8 participants