helloflask / flask-ckeditor

CKEditor integration for Flask, including image upload, code syntax highlight, and more.
https://flask-ckeditor.readthedocs.io
MIT License
200 stars 67 forks source link

[Example] Need simpler or better example for mongoengine and Flask Admin #8

Closed bekab95 closed 6 years ago

bekab95 commented 6 years ago

I am using Flask-Admin and have already integrated ckeditor and works with only texts but I need to upload images with text too and I need more examples if it is possible

Without WTF

greyli commented 6 years ago

Here are some basic examples. However, image upload behavior changed since CKEditor 4.5, I will release a new version to support it today.

bekab95 commented 6 years ago

I need it to use with flask admin, upload image or better is to browse directory too and if you can help me that would be great

greyli commented 6 years ago

I just updated the newer example for image upload and release 0.4.0.

bekab95 commented 6 years ago

@greyli where are you telling ckeditor to override image field ? I need it to use with flask-admin and maybe it has to be without WTF..

greyli commented 6 years ago

I don't understand your question. What's the image field?

When you set CKEDITOR_FILE_UPOLOADER with proper value, you can just drag and drop the image file into the editor or upload with image widget.

These resources may be helpful:

bekab95 commented 6 years ago

@greyli Are you planning adding directory browser ? I think it is CKfinder

greyli commented 6 years ago

I did think about it, but currently, I don't have time to investigate and implement it. Happy to accept PR addressing this.

bekab95 commented 6 years ago

Can I use it without FlaskForm class ?

greyli commented 6 years ago

Sure, check out this example.

bekab95 commented 6 years ago

In Flask Admin Standard way is to override StringField but for your extension I can not understand for images how to get worked it..

greyli commented 6 years ago
  1. Override StringField with flask_ckeditor.CKEditorField
  2. Implement a view function which handles upload files
  3. Set CKEDITOR_FILE_UPLOADER to the upload handler view's endpoint
bekab95 commented 6 years ago

So.. tried several things and not working, may Flask-Admin needs different details to upload images within ckeditor

greyli commented 6 years ago

Provide the error traceback and a minimal application will be helpful.

bekab95 commented 6 years ago
class CKTextAreaWidget(widgets.TextArea):
    def __call__(self, field, **kwargs):
        # add WYSIWYG class to existing classes
        existing_classes = kwargs.pop('class', '') or kwargs.pop('class_', '')
        kwargs['class'] = u'%s %s' % (existing_classes, "ckeditor")
        return super(CKTextAreaWidget, self).__call__(field, **kwargs)

class CKTextAreaField(TextAreaField):
    widget = CKTextAreaWidget()
class OffersView(ModelView):
    column_list = ["title_ka", "title_en", "title_ru", "is_main", "is_enabled", "position"]
    form_overrides = dict(desc_ka=CKTextAreaField,desc_en=CKTextAreaField,desc_ru=CKTextAreaField)
    create_template = 'edit.html'
    edit_template = 'edit.html'
    def is_accessible(self):
        if flask_login.current_user.is_authenticated:
            user = CustomUser.objects.get(email=flask_login.current_user.id)
            return user.is_superuser

    def inaccessible_callback(self, name, **kwargs):
        # redirect to login page if user doesn't have access
        return redirect(url_for('login', next=request.url))
bekab95 commented 6 years ago
{% extends 'admin/model/edit.html' %}

{% block tail %}
    {{ super() }}
    <script src="//cdn.ckeditor.com/4.9.2/full/ckeditor.js"></script>
    <script type="text/javascript">
        $('.control-group a').click( function(e) {e.preventDefault(); 
        for(var instanceName in CKEDITOR.instances)
                CKEDITOR.remove(CKEDITOR.instances[instanceName]);        
                CKEDITOR.replaceAll('ckeditor');
         return false; } );

    </script>
{% endblock %}
bekab95 commented 6 years ago

form override does not work for your extension, you may test it for flask-admin

greyli commented 6 years ago

I never used Flask-Admin before, so I can't help you too much. IMO, you should replace your code like this:

from flask_ckeditor import CKEditorField

class OffersView(ModelView):
    column_list = ["title_ka", "title_en", "title_ru", "is_main", "is_enabled", "position"]
    form_overrides = dict(desc_ka=CKEditorField, desc_en=CKEditorField, desc_ru=CKEditorField)
    create_template = 'edit.html'
    edit_template = 'edit.html'
    def is_accessible(self):
        if flask_login.current_user.is_authenticated:
            user = CustomUser.objects.get(email=flask_login.current_user.id)
            return user.is_superuser

    def inaccessible_callback(self, name, **kwargs):
        # redirect to login page if user doesn't have access
        return redirect(url_for('login', next=request.url))

You should provide the error traceback or I can't know what's the actual problem. Besides, Expected behavior and Actual behavior also helpful.

bekab95 commented 6 years ago

I will see further in future thanks.

https://stackoverflow.com/questions/50675748/can-not-catch-ckeditor-id-and-reload-instance-on-it

this is other issue if you can help me ?

bekab95 commented 6 years ago

So, I have done some tests with flask admin and I got upload option but when I am attempting to upload image it has 404 error (there is extra parameters in form action='/upload?some_params_of_ckeditor may this is the issue ? )

bekab95 commented 6 years ago

As I have seen it needs csrf token or I am doing something wrong with flask admin

bekab95 commented 6 years ago

SO I avoid csrf but now I am getting {"filename":"","uploaded":1,"url":"/files/GeoAdsCover_1.png"} this response when uploading image in ckeditor, so it is not parsing name

bekab95 commented 6 years ago

4.9.2 it is working on this version, I will test fully for flask admin and bring you full example :)

bekab95 commented 6 years ago
from flask_ckeditor import *
csrf = CSRFProtect(app)
csrf.init_app(app)

ckeditor = CKEditor(app)

app.config['CKEDITOR_SERVE_LOCAL'] = False
app.config['CKEDITOR_HEIGHT'] = 400
app.config['CKEDITOR_FILE_UPLOADER'] = 'upload'
app.config['UPLOADED_PATH'] = os.path.join(basedir, 'uploads')

@app.route('/files/<filename>')
@csrf.exempt
def uploaded_files(filename):
    path = app.config['UPLOADED_PATH']
    return send_from_directory(path, filename)

import uuid

@app.route('/upload', methods=['POST'])
@csrf.exempt
def upload():
    f = request.files.get('upload')
    extension = f.filename.split('.')[1].lower()
    if extension not in ['jpg', 'gif', 'png', 'jpeg']:
        return upload_fail(message='Image only!')
    unique_filename = str(uuid.uuid4())
    f.filename = unique_filename + '.' + extension
    f.save(os.path.join(app.config['UPLOADED_PATH'], f.filename))
    url = url_for('uploaded_files', filename=f.filename)
    return upload_success(url=url)

f.filename = unique_filename + '.' + extension

in flask admin edit.html

    CKEDITOR.plugins.addExternal( 'filebrowser', '/static/ckeditor/filebrowser/', 'plugin.js' );
    CKEDITOR.config.extraPlugins = 'filebrowser';

    CKEDITOR.config.filebrowserBrowseUrl  = '/upload';
bekab95 commented 6 years ago

If I will use {{ ckeditor.load() }} it will load CKEDITOR but it will not add plugin to ckeditor window and that is a issue left

app.config['CKEDITOR_FILE_UPLOADER'] = 'upload'

does not have any impact

greyli commented 6 years ago

How do you create the textarea? Did you call {{ ckeditor.config() }} in the template?

bekab95 commented 6 years ago

@greyli Yes I have Called But did not work, I will test it again with some details and tell you

greyli commented 6 years ago

Currently, I do not know too much about Flask-Admin, I will try to learn how to integrate Flask-Admin with Flask-CKEditor when I have free time.

bekab95 commented 6 years ago

@greyli integration is not problem, I have to add additional JS to get work image uploads

CKEDITOR.plugins.addExternal( 'filebrowser', '/static/ckeditor/filebrowser/', 'plugin.js' );
CKEDITOR.config.extraPlugins = 'filebrowser';

CKEDITOR.config.filebrowserBrowseUrl  = '/upload';
greyli commented 6 years ago

When calling {{ ckeditor.config() }}, Flask-CKEditor initialize a CKEditor for a <textarea> named ckeditor. You may need to find out what is the name used when Flask-Admin create the <textarea>, and pass it to config() (e.g. {{ ckeditor.config(name='the_name_attr') }}).

bekab95 commented 6 years ago

@greyli that is not a problem. ckeditor is working, only image upload window is not working without adding extra plugin, I will test it again.

bekab95 commented 6 years ago

In addition can you write documentation about adding extra plugins ? for example adding responsive table plugin.

bekab95 commented 6 years ago

I confirm without this

    <script>
    CKEDITOR.config.filebrowserUploadUrl  = '/upload';
    </script>

Image Upload is not showing up in ckeditor in flask admin

greyli commented 6 years ago

The filebrowserUploadUrl config will be added after calling ckedtior.config() (flask_ckeditor/init.py#L101), so it's important to pass correct name attribute.

You can pass extra plugins name as a list in CKEDITOR_EXTRA_PLUGINS, such as ['responsive_table'], it also needs to call ckedtior.config() to make it work.

bekab95 commented 6 years ago

Show me ckedtior.config() example please

greyli commented 6 years ago

https://github.com/greyli/flask-ckeditor/blob/master/examples/basic/templates/index.html#L21

bekab95 commented 6 years ago

name=body is that for to load ckeditor on body ? I need to know how to tell ckeditor cobfig that image upload url is /upload

greyli commented 6 years ago

ckeditor.config() is the way to tell CKEditor what is the upload URL. The name should be the name value of CKEditor <textarea>, you need to render the page, click F12 and find the textarea element, then you will get the correct name value.

bekab95 commented 6 years ago

it is not required for me to tell which is the textarea ckeditor already loads without telling that. i need to tell config that to use url for upload.

greyli commented 6 years ago

You set app.config['CKEDITOR_FILE_UPLOADER'] = 'upload', then Flask-CKEditor will turn it into url, and when you call ckeditor.config(), it will generate JavaScript code to set the url (i.e. filebrowserUploadUrl: "/upload").

bekab95 commented 6 years ago

So I only was loading ckeditor without

ckeditor.config()

and do I have to call ckeditor.config() too ??

greyli commented 6 years ago

If you want to write config code yourself, for example:

CKEDITOR.plugins.addExternal( 'filebrowser', '/static/ckeditor/filebrowser/', 'plugin.js' );
CKEDITOR.config.extraPlugins = 'filebrowser';
CKEDITOR.config.filebrowserBrowseUrl  = '/upload';

then you can skip cdeditor.config()

bekab95 commented 6 years ago

only calling cdeditor.config() is not working

app.config['CKEDITOR_FILE_UPLOADER'] = 'upload' does not have any impact that is problem

bekab95 commented 6 years ago

https://github.com/zrq495/flask-ckfinder Can you also fork this ?

greyli commented 6 years ago

As I said, you need to find out the name of CKEditor <textarea> and pass it as cdeditor.config(name='the_name').

I'll try to integrate a file browser when I have free time.

bekab95 commented 6 years ago

@greyli So

cdeditor.config(name='the_name') does not needed, ckeditor is loading without it, but app.config['CKEDITOR_FILE_UPLOADER'] = 'upload' this does not work when pressing image icon in ckeditor, it is not loading upload tab

to load upload tag it needs

CKEDITOR.plugins.addExternal( 'filebrowser', '/static/ckeditor/filebrowser/', 'plugin.js' ); CKEDITOR.config.extraPlugins = 'filebrowser'; CKEDITOR.config.filebrowserBrowseUrl = '/upload';

and how to tell ckeditor upload url without extra JS above ?

greyli commented 6 years ago

If you want to tell CKEditor the upload URL without extra JS, set this in Python:

app.config['CKEDITOR_FILE_UPLOADER'] = 'upload' 

And call it in Jinja:

ckeditor.config(name='the_name') 
bekab95 commented 6 years ago

So that I was talking about that this: app.config['CKEDITOR_FILE_UPLOADER'] = 'upload' is not working without extra JS that is bug

greyli commented 6 years ago

Do you notice the "And" in my last comment? As I said, ckeditor.config(name='the_name') will generate the JS code, so you have to call it to make the configuration work.

bekab95 commented 6 years ago

Nope, I have tried that too and other combinations too.. but not working without extra JS

greyli commented 6 years ago

You have to pass the correct name value.