WYSIWYG editor integration

Written by Walter on 19/1/2021

< >

 

During this weekend I added the great ck editor to my starlette pages. I've got the save and most features working (like bootstrap grid).

It now is already able to edit archive items. And it should be fairly easy to make it work on the other page routes as well. Allowing wysiwyg (what you see is what you get) editing in browser is pretty handy.

However before pushing this online I've got to get authorization in starlette + a login/pass working here. Most likely for next weekend just add this Starlette auth pip package.

For now I'm leaving the edit with disabled saving until authorization is fully working. Then I'm finally where my blog was in functionality in the early 2000's but now it looks more modern, runs on python/starlette and the code is a lot cleaner ;).

The main trick is configuring your ckeditor so it allows file uploads to your backend, then implementing a route with post request to receive the file. This is a minimal example in starlette that saves your uploaded image (scaling and saving multiple versions, can be added easily enough using Pillow ):


@app.route('/ckeditor/pictures', methods=['POST'])
async def upload_picture(request):
    form_data = await request.form()

    image_filename = form_data["upload"].filename
    image_data = await form_data["upload"].read()

    image_file = open( f"/app/assets/images/uploaded/{image_filename}", "wb" )
    image_file.write( image_data )
    image_file.close()

    template = "upload_response.html"
    context = {
        "request": request,
        "image_file": image_filename,
        "image_url": '/static/images/uploaded/{}'.format(image_filename)
    }
    return templates.TemplateResponse("upload_response.html", context)

I also added some syntax highlighting on pre tags and am in the process of applying it on various pages. And improving most blog items. An example is this one here that looks way nicer now that we use the javascript highlighting in pre tags: Ruby include vs require blog post.

In rails integration with ckeditor is less manual work. There's an excellent ckeditor gem for it.

But studying this gem I could figure out some things like setting custom routes that the editor will call and allowing more tags (relaxing filtering). This extra config allows everything I need to be able to do and it's in js/editor/config.js:


  config.allowedContent = true;

  /* Filebrowser customization */
  // The location of an external file browser, that should be launched when "Browse Server" button is pressed.
  config.filebrowserBrowseUrl = "/ckeditor/attachment_files";

  // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Flash dialog.
  config.filebrowserFlashBrowseUrl = "/ckeditor/attachment_files";

  // The location of a script that handles file uploads in the Flash dialog.
  config.filebrowserFlashUploadUrl = "/ckeditor/attachment_files";

  // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Link tab of Image dialog.
  config.filebrowserImageBrowseLinkUrl = "/ckeditor/pictures";

  // The location of an external file browser, that should be launched when "Browse Server" button is pressed in the Image dialog.
  config.filebrowserImageBrowseUrl = "/ckeditor/pictures";

  // The location of a script that handles file uploads in the Image dialog.
  config.filebrowserImageUploadUrl = "/ckeditor/pictures?";

  // The location of a script that handles file uploads.
  config.filebrowserUploadUrl = "/ckeditor/attachment_files";

  config.allowedContent = true;
  config.filebrowserUploadMethod = 'form';
  config.image_prefillDimensions = false; //do not set width/height style tag on uploaded image
  config.extraAllowedContent = 'class(*); img{*}[*](*)';
  /* Filebrowser end */

 

Finally you need a view to return a javascript tag that tells ckeditor after the upload to show your uploaded image in the upload_response.html jinja template:


<script>
  //with CKEditorFuncNum = 1 hardcoded here (however we can refactor because it's passed in with query_params)
  window.parent.CKEDITOR.tools.callFunction(1,'{{image_url}}');
</script>

Back to archive