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

drag and drop images doesn't work #337

Open
gurugeek opened this issue Jan 15, 2021 · 4 comments
Open

drag and drop images doesn't work #337

gurugeek opened this issue Jan 15, 2021 · 4 comments

Comments

@gurugeek
Copy link

gurugeek commented Jan 15, 2021

Thanks for your package :)

Drag and Drop images using the paste plugin doesn't seem to work:


TINYMCE_DEFAULT_CONFIG = {
"menubar": "file edit view insert format tools table help",
  "plugins": "paste, code, link, codesample, fullscreen, insertdatetime, media, table, paste, code, help, wordcount, spellchecker",
  "block_unsupported_drop":"false",
  "images_upload_url": "zirkusupload",
  "images_upload_base_path": "/some/basepath",
   "toolbar": "undo redo styleselect fontselect bold italic alignleft aligncenter alignright bullist numlist outdent indent code link codesample paste", 
  "content_style":
   "@import url('https://use.typekit');body { font-family: calibri, sans-serif; font-size:22px; }",
   "paste_data_images": "true",
  "block_unsupported_drop": "false",

  }
  

returns "dropped file top not supported".
It works fine in the plain JS version so I was wondering if this is disabled on Django ?

I would appreciate any assistance on how to use drag and drop images OR add images easily. Thanks!

@mr-nazari
Copy link

mr-nazari commented Mar 3, 2021

I have the same problem, please solve it

@Natim
Copy link
Collaborator

Natim commented Mar 3, 2021

@mr-nazari feel free to provide a patch I will make the release.

@Abednego97
Copy link

Can anyone help me with how to insert a local image?

@StevenMapes
Copy link

You need to write the JS uploader and then the Django view to handle the upload yourself. Here's what I did to achieve this where I use Django Storages as the backend but I use default_storage to write the file to the backend so everything should work for you with the exception of the full URL to the uploaded file.

Step 1.
Ensure the the these two keys are set within the TINYMCE_DEFAULT_CONFIG

    "images_upload_url": "/tinymce/upload",
    "images_upload_handler": "tinymce_image_upload_handler"

The first is the path to which you would like the javascript to make the POST. The 2nd is the name of the javascript function to handle the upload

Step 2
Because of CSRF you need to be able to read the token. In order to do this I use the js-cookie lib mentioned within the Django docs

Add the below into your settings.py to tell it yo include two additional JS file. I'm using the jsdelivr CDN hosted version for the above package

TINYMCE_EXTRA_MEDIA = {
    'css': {
        'all': [
        ],
    },
    'js': [
        "https://cdn.jsdelivr.net/npm/[email protected]/dist/js.cookie.min.js",
        "admin/js/tinymce-upload.js",
    ], 
}

The second file is holds the custom JS file upload handler I will post below.

Step 3.
Here are the contents of the tinymce-upload.js file I created. Note it uses cookie-js to read the value of the CSRF token and add it to the headers of the AJAX POST. I also hardset the URL path to post to as the same value as the one I add in the settings.py. You may be able to read it from somewhere but I haven't looked into that yet.

function tinymce_image_upload_handler (blobInfo, success, failure, progress) {
    let xhr, formData;
    xhr = new XMLHttpRequest();
    xhr.withCredentials = false;
    xhr.open('POST', '/tinymce/upload');
    xhr.setRequestHeader('X-CSRFToken', Cookies.get("csrftoken"));
    xhr.upload.onprogress = function (e) {
        progress(e.loaded / e.total * 100);
    };
    xhr.onload = function() {
        let 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);
}

Step 4
Write the view to handle the upload.
In my case I want to use a subfolder of media called tinymce with a uuid4 named folder to then hold the file in to avoid name clashes.

The key part is to return a JSONResponse with the location of the image you just uploaded.

In my case I am using Django Storages to store files on S3 but I serve them from AWS Cloudfront using a custom domain that I have set within settings.py so I append that to the start

def tinymce_upload(request):
    """Uplaod file to S3 and return the location"""
    file = request.FILES.get('file')
    filename = f"tinymce/{uuid4()}/{str(file)}"
    with default_storage.open(filename, "wb") as f:
        f.write(file.read())

    return JsonResponse({"location": f"https://{settings.AWS_S3_CUSTOM_DOMAIN}/media/{filename}"})

Now I can upload images using the TinvMCE plugin ensuring that CSRF checks are made

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants