django-tinymce icon indicating copy to clipboard operation
django-tinymce copied to clipboard

Howto multiples settings of TINYMCE_DEFAULT_CONFIG

Open gusarg81 opened this issue 5 years ago • 20 comments

Hi,

For example, with django_tinymce_lite, I could do this in a form definition:

... widgets = { 'text': TinyMCE(profile=settings.TINYMCE_BASIC_CONFIG) } ....

So, being TINYMCE_BASIC_CONFIG an alternative config in settings.py besides TINYMCE_DEFAULT_CONFIG. How can I acchieve this in here?

Thanks in advance.

gusarg81 avatar May 29 '20 22:05 gusarg81

Hi, nothing about this?

gusarg81 avatar Aug 02 '20 20:08 gusarg81

+1 If needed, I think I could work on and submit a PR that added this feature!

aitorres avatar Aug 28 '20 06:08 aitorres

I think will be needed, just imagine different scenarios where you only need to show a few tools and others the full toolbar (at least many cases in my mind).

Lets says that as an admin of a site, in certain apps you need more tools than an user doing a comment in other public app. Just to mention an example.

gusarg81 avatar Aug 28 '20 13:08 gusarg81

Hi,

Any advance on this? Is the only thing that keeps me from upgrading (still using django-tinymce4-lite that has this feature).

Thanks.

gusarg81 avatar Sep 09 '20 14:09 gusarg81

I guess a pull request should be a start...

claudep avatar Sep 09 '20 17:09 claudep

Yes, @claudep! I still want to work on it, but haven't been able these past days because of my work load. However I think I can work on it this week and upload a Pull Request

aitorres avatar Sep 09 '20 17:09 aitorres

I worked a bit on this code these last days, and it seems you can achieve what you want by filling the mce_attrs dictionary when initializing the widget, as described here: https://django-tinymce.readthedocs.io/en/latest/usage.html#using-the-widget

claudep avatar Sep 19 '20 16:09 claudep

So, lets say I have one of the settings, called TINYMCE_BASIC_CONFIG (in settings.py), then I can pass that settings dict to mce_attrs like this?:

from django.conf import settings
...
content = forms.CharField(widget=TinyMCE(attrs=settings.TINYMCE_BASIC_CONFIG))
...

gusarg81 avatar Sep 21 '20 03:09 gusarg81

The attribute should be mce_attrs, not attrs (which is reserved for standard widget attributes).

Your TINYMCE_BASIC_CONFIG will be merged with the default config. Is dict merging a possible issue?

claudep avatar Sep 21 '20 08:09 claudep

The attribute should be mce_attrs, not attrs (which is reserved for standard widget attributes).

Sorry, yes a bad typo.

Your TINYMCE_BASIC_CONFIG will be merged with the default config. Is dict merging a possible issue?

I think it will be an issue. Should not be merged, but a new one.

gusarg81 avatar Sep 21 '20 12:09 gusarg81

Your TINYMCE_BASIC_CONFIG will be merged with the default config. Is dict merging a possible issue?

I think it will be an issue. Should not be merged, but a new one.

Then that would be a new feature. We could for example imagine a special config key like '__replace' be set to True so the config is replaced instead of merged.

claudep avatar Sep 21 '20 13:09 claudep

In django-tinymce4-lite I use it like, for example in forms:

widgets = {
    'text': TinyMCE(profile=settings.TINYMCE_ALT_CONFIG)
}

Just mention again in case that helps to apply something similar.

gusarg81 avatar Sep 23 '20 23:09 gusarg81

If your alternate config has the same keys as the default config, you can do the same currently with:

widgets = {
    'text': TinyMCE(mce_attrs=settings.TINYMCE_ALT_CONFIG)
}

So the subject of this ticket could be to add an option to replace entirely the default config instead of merging its keys with the default.

claudep avatar Sep 24 '20 06:09 claudep

Hi,

Sorry to insist, but there is any progress about this?

Thanks.

gusarg81 avatar Dec 17 '20 21:12 gusarg81

Didn't my comment above help you? What problem do you encounter with the current method of providing a widget mce_attrs parameter?

claudep avatar Dec 18 '20 07:12 claudep

Didn't my comment above help you? What problem do you encounter with the current method of providing a widget mce_attrs parameter?

Didn't tested yet. But this method will do a keys merge (like you said), which is not ideal.

Anyways, in the meanwhile I will test today.

gusarg81 avatar Dec 18 '20 11:12 gusarg81

As the base config doesn't have so much keys, I'm not sure it will be a problem in real cases.

claudep avatar Dec 18 '20 12:12 claudep

Hi,

Finally I was available to test this and does not work. For example in my form:

widgets = {
	'description': TinyMCE(mce_attrs=settings.TINYMCE_BASIC_CONFIG)
}

And in the frontend, it trows the error:

Uncaught TypeError: mce_conf[fn_name].includes is not a function

Now, without mce_attrs it does works.

This is my custom TINYMCE_BASIC_CONFIG:

TINYMCE_BASIC_CONFIG = {
	'cleanup_on_startup': True,
	'selector': 'textarea',
	'plugins': '''
		link image preview lists spellchecker hr textcolor colorpicker
		''',
	'toolbar1': 'undo redo | formatselect | bold italic underline fontsizeselect | '
		'forecolor backcolor | alignleft aligncenter alignright alignjustify | '
		'bullist numlist | blockquote | outdent indent | table hr | link image | '
		'preview | spellchecker',
	'file_browser_callback': False,
	'menubar': False,
	'inline': False,
	'statusbar': True,
	'branding': False,
	'width': '100%',
	'height': '250px',
	'spellchecker_languages': 'Español AR=es_AR,Inglés US=en_US',
	'content_css': '/static/css/base/tinymce.css',
	'convert_urls': True,
	'relative_urls': False,
	'remove_script_host': False,
}

Is the same as the default, but with less items in the toolbar. It does works with django-tinymce4-lite.

gusarg81 avatar Mar 03 '21 21:03 gusarg81

Ok, seems the problem is file_browser_callback, removing it does work (which I saw it changed to file_picker_callback in current TinyMCE).

Now, how can I disable file_picker_callback? Which means, disabling image upload button.

Thanks.

EDIT: using 'file_picker_callback': 'null', did the trick. I don't know if is the right way.

gusarg81 avatar Mar 03 '21 21:03 gusarg81

To allow multiple TINYMCE_DEFAULT_CONFIG settings in django-tinymce and also provide an option to replace the default config entirely instead of merging its keys with the default, you can modify the TinyMCE widget's render method. Here's an example:

from django import forms
from tinymce.widgets import TinyMCE

class MyTinyMCE(TinyMCE):
    def render(self, name, value, attrs=None, renderer=None):
        mce_attrs = attrs.get('mce_attrs', {})
        if 'configs' in mce_attrs:
            configs = mce_attrs.pop('configs')
            replace = mce_attrs.pop('replace', False)
            if replace:
                self.attrs['data-mce-config'] = configs
            else:
                for key, value in configs.items():
                    self.attrs['data-mce-' + key] = value
        return super().render(name, value, attrs=attrs, renderer=renderer)

TINYMCE_CONFIGS = {
    'default': {
        'height': 400,
        'plugins': 'advlist autolink lists link image charmap print preview anchor',
        'toolbar': 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
        'file_browser_callback': 'filebrowser',
    },
    'simple': {
        'height': 200,
        'plugins': 'textcolor',
        'toolbar': 'undo redo | bold italic | forecolor backcolor',
        'file_browser_callback': 'filebrowser',
    },
}

class MyForm(forms.Form):
    content = forms.CharField(widget=MyTinyMCE(mce_attrs={'configs': TINYMCE_CONFIGS['simple'], 'replace': True}))

To allow multiple TINYMCE_DEFAULT_CONFIG settings in django-tinymce, you can define a dictionary of configurations and pass it to the TinyMCE widget using the attrs argument. Here's an example:


from django import forms
from tinymce.widgets import TinyMCE

TINYMCE_CONFIGS = {
    'default': {
        'height': 400,
        'plugins': 'advlist autolink lists link image charmap print preview anchor',
        'toolbar': 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
        'file_browser_callback': 'filebrowser',
    },
    'simple': {
        'height': 200,
        'plugins': 'textcolor',
        'toolbar': 'undo redo | bold italic | forecolor backcolor',
        'file_browser_callback': 'filebrowser',
    },
}

class MyForm(forms.Form):
    content = forms.CharField(widget=TinyMCE(attrs={'configs': TINYMCE_CONFIGS}))

In the above example, we define two configurations (default and simple) in a dictionary called TINYMCE_CONFIGS. We then pass this dictionary to the TinyMCE widget using the attrs argument in our form definition. The user can then select which configuration to use by setting the config attribute on the textarea element.


Unfortunately, django-tinymce does not allow for multiple TINYMCE_DEFAULT_CONFIG settings out of the box. However, you can achieve something similar by creating different tinymce widgets with different configurations, and then using these widgets in your forms.

Here's an example of how you can create two different tinymce widgets:

from django.forms.widgets import Textarea
from tinymce.widgets import TinyMCE

class CustomTinyMCE(TinyMCE):
    def init(self, args, **kwargs):
        custom_settings = kwargs.pop('custom_settings', {})
        super().init(args, kwargs)
        self.attrs.update({'data-custom-settings': json.dumps(custom_settings)})

class DefaultTinyMCE(CustomTinyMCE):
    def init(self, *args, kwargs):
        custom_settings = {
            'theme': 'modern',
            'plugins': 'link,paste,code',
        }
        super().init(args, custom_settings=custom_settings, **kwargs)

class AdvancedTinyMCE(CustomTinyMCE):
    def init(self,args, **kwargs):
        custom_settings = {
            'theme': 'advanced',
            'plugins': 'link,image,media,anchor,code,table,visualblocks,visualchars,fullscreen,layer',
            'toolbar': 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media | code | table | fullscreen | layer',
            'relative_urls': False,
            'remove_script_host': True,
            'convert_urls': True,
        }
        super().init(args, custom_settings=custom_settings, kwargs)

In this example, DefaultTinyMCE and AdvancedTinyMCE inherit from a custom CustomTinyMCE widget that allows passing custom settings to the TinyMCE widget. DefaultTinyMCE uses a simple configuration with just a few plugins and features, while AdvancedTinyMCE has a more complex configuration with many plugins and features.

You can then use these widgets in your forms like so:

from django import forms

class MyForm(forms.Form):
    content = forms.CharField(widget=DefaultTinyMCE())
    advanced_content = forms.CharField(widget=AdvancedTinyMCE())


from tinymce.widgets import TinyMCE
from django.conf import settings

# Create the default configuration dictionary
my_default_config = {
    'height': 500,
    'plugins': 'advlist autolink lists link image charmap print preview anchor',
    'toolbar': 'undo redo | styleselect | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link image'
}

# Create a second configuration dictionary
my_other_config = {
    'height': 400,
    'plugins': 'advlist autolink lists link charmap',
    'toolbar': 'undo redo | styleselect   | bold italic | alignleft aligncenter alignright | bullist numlist outdent indent | link'
}

# Custom widget to use the default config
class MyTinyMCEWidget(TinyMCE):
    def init(self, attrs=None, mce_attrs=None):
        final_attrs = {'class': 'my_tinymce_class'}
        if attrs is not None:
            final_attrs.update(attrs)
        if mce_attrs is None:
            mce_attrs = {}
        final_attrs['data-mce-config'] = json.dumps(mce_attrs)
        final_attrs['data-mce-settings'] = json.dumps(my_default_config)
        super().init(attrs=final_attrs)

# Custom widget to use the other config
class MyOtherTinyMCEWidget(TinyMCE):
    def init(self, attrs=None, mce_attrs=None):
        final_attrs = {'class': 'my_tinymce_class'}
        if attrs is not None:
            final_attrs.update(attrs)
        if mce_attrs is None:
            mce_attrs = {}
        final_attrs['data-mce-config'] = json.dumps(mce_attrs)
        final_attrs['data-mce-settings'] = json.dumps(my_other_config)



from django import forms

class MyForm(forms.Form):
    my_field = forms.CharField(widget=MyTinyMCEWidget())
    my_other_field = forms.CharField(widget=MyOtherTinyMCEWidget())

In this example, my_field will use the my_default_config settings, while my_other_field will use the my_other_config settings.

some1ataplace avatar Mar 24 '23 19:03 some1ataplace