tinymce / tinymce-vue

Official TinyMCE Vue component
MIT License
2.01k stars 202 forks source link

Problem with Image Upload Credentials property or Image Upload Handler function #343

Open phyothiha opened 1 year ago

phyothiha commented 1 year ago

What is the current behavior? Hi, this plugin is magnificent. I'm using the TinyMCE free version for my current project but I have a slight problem with image uploading.

First problem is credentials didn't not send in the request header using along with images_upload_url property as per documentation.

images_upload_credentials

There is also an error with the Image Upload Handler function. I follow the code as per documentation and slightly change according to my project but alert an error with "Cannot read properties of undefined (reading 'then')" after successfully uploading to the server and returning json response as location object.

function example_image_upload_handler(blobInfo, success, failure, progress) {
  console.log("success", success);
  console.log("failure", failure); // this return undefined
  console.log("progress", progress); // this return undefined

  var xhr, formData;
  xhr = new XMLHttpRequest();
  xhr.withCredentials = true;
  xhr.open("POST", process.env.API_BASE_URL + "/api/file-upload");
  var start = document.cookie.search("=");
  var token = document.cookie.slice(start + 1).replace("%3D", "=");
  xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  xhr.setRequestHeader("X-XSRF-Token", token);
  xhr.onload = function () {
    var json;
    if (xhr.status === 403) {
      failure("HTTP Error: " + xhr.status, { remove: true });
      return;
    }
    if (xhr.status < 200 || xhr.status >= 300) {
      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);
  };
  xhr.onerror = function () {
    failure(
      "Image upload failed due to a XHR Transport error. Code: " + xhr.status
    );
  };
  formData = new FormData();
  formData.append("file", blobInfo.blob(), blobInfo.filename());
  xhr.send(formData);
}

Which versions of TinyMCE, and which browser / OS are affected by this issue? Did this work in previous versions of TinyMCE or tinymce-vue?

Quasar: 2.6.0 Vue: 3.0.0 TinyMCE: 5.0.0 Browser: Microsoft Edge OS: OSX

exalate-issue-sync[bot] commented 1 year ago

Ref: INT-3042

jscasca commented 1 year ago

@phyothiha do you have a small replication or can you post your configuration?

phyothiha commented 1 year ago

@jscasca For clarity, I just paste full configuration in Vue Component.

<script setup>
import Editor from "@tinymce/tinymce-vue";

const apiKey = process.env.API_KEY_TINYMCE_EDITOR;

function example_image_upload_handler(blobInfo, success, failure, progress) {
  console.log("success", success);
  console.log("failure", failure);
  console.log("progress", progress);

  var xhr, formData;
  xhr = new XMLHttpRequest();
  xhr.withCredentials = true;
  xhr.open("POST", process.env.API_BASE_URL + "/api/file-upload");
  var start = document.cookie.search("=");
  var token = document.cookie.slice(start + 1).replace("%3D", "=");
  xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  xhr.setRequestHeader("X-XSRF-Token", token);
  xhr.onload = function () {
    var json;
    if (xhr.status === 403) {
      failure("HTTP Error: " + xhr.status, { remove: true });
      return;
    }
    if (xhr.status < 200 || xhr.status >= 300) {
      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);
  };
  xhr.onerror = function () {
    failure(
      "Image upload failed due to a XHR Transport error. Code: " + xhr.status
    );
  };
  formData = new FormData();
  formData.append("file", blobInfo.blob(), blobInfo.filename());
  xhr.send(formData);
}

const editorConfig = {
  height: 350,

  branding: false,

  placeholder: "Type something",

  menubar: false,

  plugins: [
    "advlist",
    "anchor",
    "autolink",
    "codesample",
    "fullscreen",
    "image",
    "link",
    "lists",
    "searchreplace",
    "media",
    "table",
    "visualblocks",
    "visualchars",
  ],

  toolbar:
    "undo redo | fontsize forecolor backcolor removeformat | bold italic underline superscript subscript | alignleft aligncenter alignright alignjustify | outdent indent numlist bullist | image media link table codesample | visualblocks visualchars | fullscreen",

  advlist_number_styles:
    "default,lower-alpha,lower-roman,upper-alpha,upper-roman",

  link_default_protocol: "https",

  font_size_formats:
    "12px 13px 14px 16px 18px 24px 30px 36px 48px 60px 72px 96px",

  content_style: "body { font-size: 14px }",

  images_upload_handler: example_image_upload_handler,
};
</script>

<template>
  <editor :api-key="apiKey" :init="editorConfig" />
</template>
phyothiha commented 1 year ago

@jscasca This code is using images_upload_url and images_upload_credentials property

<script setup>
import Editor from "@tinymce/tinymce-vue";

const apiKey = process.env.API_KEY_TINYMCE_EDITOR;

const imageConfig = {
  images_upload_url: process.env.API_BASE_URL + "/api/file-upload",

  images_upload_credentials: true,
};

const editorConfig = {
  // same as above config
  ...imageConfig,
};
</script>

<template>
  <editor :api-key="apiKey" :init="editorConfig" />
</template>
jscasca commented 1 year ago

I cannot replicate usage with the uploader function (adapted to my local environment), everything seems to work properly. Do you have a sample repo where you have this running?

I have not tried using images_uploade_credentials yet

phyothiha commented 1 year ago

@jscasca You mean the image uploader function works with your local environment? Ok I'll try with only Vue without using the UI framework. I do not have a sample repo for this. Maybe that might have an issue with the quasar framework.

jscasca commented 1 year ago

Yes, even none of the console.logs at the start of the function return undefined for me. They all have functions while using vanilla Vue. I have never tried Quasar so I'm not sure how it interacts with the rest of the components but that might be the issue. If you can create a replication I can look further into it

phyothiha commented 1 year ago

@jscasca I set it up on codesandbox with image uploader function contains outputting function result.

jscasca commented 1 year ago

Thanks for the replication. That's definitely Quasar breaking stuff. I guess that's the same reason the credentials are not being passed when using the credentials setting.

I would need to look deeper into what Quasar is actually doing to break the function calls.

phyothiha commented 1 year ago

@jscasca Doing images_upload_credentials: true didn't pass along credentials such as cookies or authorization headers. I tested it out with vanilla Vue. If I want to pass credentials, I will have to use custom image_upload_handler function and manually set headers.