2

I'm using TinyMCE 5 with PHP 7.

Currently:

1. images_upload_handler (working)

Following the TinyMCE guide on Drag-in uploading images, and my own PHP upload AJAX handler, I got an image to upload successfully to my uploads directory:

enter image description here

  • This correctly uploads the file and keeps the correct name, using AJAX.
  • It uses a function for images_upload_handler, calling my AJAX handler.

2. file_picker_callback (incomplete)

Following the TinyMCE demo on uploading files, I got these two toolbar buttons (image, media) to show an upload button in their dialogs:

image & media lead to dialog with upload button

  • This works for image, not media.
  • It uses a function for file_picker_callback, uploading its own way.

3. The problem

I can't get the file_picker_callback from 2. to upload from media and I want it to use my own AJAX upload handler anyway, which I can't.

Using the image tool to upload, it will save the file after clicking "Save" in the dialog. But, when used in the media tool, it will not upload or insert anything at all.

It seems that this JavaScript demo provided by TinyMCE has a heavy interaction with the TinyMCE API itself. It has a system of caching and blobs to find the file that TinyMCE uploaded on its own. So pure AJAX-JS knowledge isn't sufficient to tell me how to tell TinyMCE to use my own AJAX upload PHP file. I'd rather just override TinyMCE's upload handler in file_picker_callback so I can use my own PHP upload script to be compatible with the rest of my app.

Goal:

I need a function for file_picker_callback (the file upload button) to use my own AJAX upload handler and preserve the name just as images_upload_handler succeeds in doing.

  • I am not worried about filename and mimetype validation; I plan to have PHP sanitize and filter later on.
  • This Question addresses another file uploader and the problem of TinyMCE 4 solutions not always working with TinyMCE 5.
  • This Question is about image description, and only for images; I want to upload any filetype.
  • I do not want any dependencies, not even jQuery. Vanilla JS only.

Current Code:

| upload.php :

$temp_file = $_FILES['file']['tmp_name'];

$file_path_dest =  'uploads/'.$_FILES['file']['name'];

move_uploaded_file($temp_file, $file_path_dest);

$json_file_is_here = json_encode(array('filepath' => $file_path_dest));

echo $json_file_is_here;

| tinyinit.js :

tinymce.init({
  selector: 'textarea',
  plugins: [ 'image media imagetools', ],

  automatic_uploads: true,
  images_reuse_filename: true,
  images_upload_url: 'upload.php',

  // From #1. Successful AJAX Upload
  images_upload_handler: function(fileHere, success, fail) {

    var ajax = new XMLHttpRequest();
    ajax.withCredentials = false;
    ajax.open('post', 'upload.php');
    ajax.upload.onprogress = function (e) {
      progress(e.loaded / e.total * 100);
    };

    ajax.onload = function() {

      if (ajax.status == 200) {

        if ( (!JSON.parse(ajax.responseText))
        || (typeof JSON.parse(ajax.responseText).filepath != 'string') ) {
          fail('Invalid: <code>'+ajax.responseText+'</code>');
          return;
        }

        success(JSON.parse(ajax.responseText).filepath);

        } else {
          fail('Upload error: <code>'+ajax.status+'</code>');
          return;
        }

      };

      var fileInfo = new FormData();
      fileInfo.append('file', fileHere.blob(), fileHere.filename());
      ajax.send(fileInfo);

    },


  file_browser_callback_types: 'file image media',
  file_picker_types: 'file image media',

  // From #2. Neither uploads from "media" nor uses my upload handler
  file_picker_callback: function(cb, value, meta) {
    var input = document.createElement('input');
    input.setAttribute('type', 'file');

    input.onchange = function() {
      var file = this.files[0];

      var reader = new FileReader();
      reader.onload = function () {
        var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
        var base64 = reader.result.split(',')[1];
        var blobInfo = blobCache.create(file.name, file, base64);
        blobCache.add(blobInfo);
        cb(blobInfo.blobUri(), { title: file.name });
      };
      reader.readAsDataURL(file);
    };
    input.click();
  }
});
Jesse
  • 750
  • 1
  • 9
  • 25

3 Answers3

3

Editing @Aulia's Answer :

file_picker_callback: function (cb, value, meta) {
    var input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.onchange = function () {
        var file = this.files[0];
        var reader = new FileReader();
                        
        // FormData
        var fd = new FormData();
        var files = file;
        fd.append('filetype',meta.filetype);
        fd.append("file",files);

        var filename = "";

        // AJAX
        var xhr, formData;
        xhr = new XMLHttpRequest();
        xhr.withCredentials = false;
        xhr.open('POST', '/your-endpoint');

        xhr.onload = function() {
            var json;
            if (xhr.status != 200) {
                alert('HTTP Error: ' + xhr.status);
                return;
            }
            json = JSON.parse(xhr.responseText);
            if (!json || typeof json.location != 'string') {
                alert('Invalid JSON: ' + xhr.responseText);
                return;
            }
            filename = json.location;
            reader.onload = function(e) {
                cb(filename);
            };
            reader.readAsDataURL(file);
        };
        xhr.send(fd);
        return
    };

    input.click();
}
zukayu
  • 101
  • 1
  • 9
1

Hope it will helps mate, make your file_picker_callback looks like below codes

file_picker_callback: function (cb, value, meta) {
    var input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.onchange = function () {
        var file = this.files[0];
        var reader = new FileReader();
                        
        // FormData
        var fd = new FormData();
        var files = file;
        fd.append('filetype',meta.filetype);
        fd.append("file",files);

        var filename = "";

        // AJAX
        var xhr, formData;
        xhr = new XMLHttpRequest();
        xhr.withCredentials = false;
        xhr.open('POST', '/your-endpoint');

        xhr.onload = function() {
            var json;
            if (xhr.status != 200) {
                failure('HTTP Error: ' + xhr.status);
                return;
            }
            json = JSON.parse(xhr.responseText);
            if (!json || typeof json.location != 'string') {
                failure('Invalid JSON: ' + xhr.responseText);
                return;
            }
            success(json.location);
            filename = json.location;
        };
        xhr.send(fd);
                                                                
        reader.onload = function(e) {
            cb(filename);
        };
        reader.readAsDataURL(file);
        return
    };

    input.click();
},                 

       
 
Aulia Wiguna
  • 406
  • 3
  • 8
  • I see you are new. Other users may downvote your answer because the OP specifically says it does *not* want any dependencies, including jQuery specifically. If you can convert your jQuery code to Vanilla JS yourself, and if it then works for me, I would credit you with the "correct" answer. Kudos. – Jesse Jan 07 '21 at 00:49
  • 1
    Hi Jesse, apologise for my last answer. I've changed the codes to pure javascript, it works on my side within production server. Hope it works in yours. Cheers – Aulia Wiguna Jan 27 '21 at 02:04
  • Thanks, I will surely have a look and if it works, I'll mark it correct. – Jesse Jan 27 '21 at 03:32
0

In the configuration you've provided, #2 doesn't have any logic to upload the data to your server. The code from Tiny's documentation you've copied is just for demo purposes and won't allow you to upload files to Tiny's servers.

You will need to setup the file_picker_callback callback to send data similar to images_upload_handler. On your server, you will need to send the URI and title in the response so the following line will be fulfilled:

cb(blobInfo.blobUri(), { title: file.name });
Dallas Clark
  • 4,064
  • 3
  • 30
  • 36
  • You have simply restated my Question, which is about setting up `file_picker_callback` to send data similar to `images_upload_handler`. What would that code look like given the rest of my code shown? It seems like you know something; I want you to please share your knowledge, so far I don't see what you are thinking. – Jesse Jul 30 '20 at 05:31