# Copyright (c) 2008 Joost Cassee
# Licensed under the terms of the MIT License (see LICENSE.txt)
"""
This TinyMCE widget was copied and extended from this code by John D'Agostino:
http://code.djangoproject.com/wiki/CustomWidgetsTinyMCE
"""
from __future__ import unicode_literals
from collections import OrderedDict
import json
from django import forms
from django.conf import settings
from django.contrib.admin import widgets as admin_widgets
from django.urls import reverse
from django.forms.utils import flatatt
from django.utils.encoding import smart_text
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import get_language, gettext as _
from dash.lib.tinymce import settings as tinymce_settings
[docs]class TinyMCE(forms.Textarea):
"""TinyMCE widget.
Set settings.TINYMCE_JS_URL to set the location of the
javascript file. Default is "MEDIA_URL + 'js/tiny_mce/tiny_mce.js'".
You can customize the configuration with the mce_attrs argument to the
constructor.
In addition to the standard configuration you can set the
'content_language' parameter. It takes the value of the 'language'
parameter by default.
In addition to the default settings from settings.TINYMCE_DEFAULT_CONFIG,
this widget sets the 'language', 'directionality' and
'spellchecker_languages' parameters by default. The first is derived from
the current Django language, the others from the 'content_language'
parameter.
"""
def __init__(self, content_language=None, attrs=None, mce_attrs=None):
super(TinyMCE, self).__init__(attrs)
if mce_attrs is None:
mce_attrs = {}
self.mce_attrs = mce_attrs
if content_language is None:
content_language = mce_attrs.get('language', None)
self.content_language = content_language
[docs] def render(self, name, value, attrs=None, renderer=None):
"""Render."""
if value is None:
value = ''
value = smart_text(value)
final_attrs = self.build_attrs(attrs)
final_attrs['name'] = name
assert 'id' in final_attrs, "TinyMCE widget attributes must " \
"contain 'id'"
mce_config = tinymce_settings.DEFAULT_CONFIG.copy()
mce_config.update(get_language_config(self.content_language))
if tinymce_settings.USE_FILEBROWSER:
mce_config['file_browser_callback'] = "djangoFileBrowser"
mce_config.update(self.mce_attrs)
if 'mode' not in mce_config:
mce_config['mode'] = 'exact'
if mce_config['mode'] == 'exact':
mce_config['elements'] = final_attrs['id']
mce_config['strict_loading_mode'] = 1
# Fix for js functions
js_functions = {}
for k in ('paste_preprocess', 'paste_postprocess'):
if k in mce_config:
js_functions[k] = mce_config[k]
del mce_config[k]
mce_json = json.dumps(mce_config)
pos = final_attrs['id'].find('__prefix__')
if pos != -1:
mce_json = mce_json.replace('"%s"' % final_attrs['id'], 'elements')
for k in js_functions:
index = mce_json.rfind('}')
mce_json = mce_json[:index] + \
', ' + \
k + \
':' + \
js_functions[k].strip() + \
mce_json[index:]
html = [
'<textarea%s>%s</textarea>' % (flatatt(final_attrs), escape(value))
]
if tinymce_settings.USE_COMPRESSOR:
compressor_config = {
'plugins': mce_config.get('plugins', ''),
'themes': mce_config.get('theme', 'advanced'),
'languages': mce_config.get('language', ''),
'diskcache': True,
'debug': False,
}
compressor_json = json.dumps(compressor_config)
html.append(
'<script type="text/javascript">tinyMCE_GZ.init(%s)'
'</script>' % compressor_json
)
if pos != -1:
html.append('''<script type="text/javascript">
setTimeout(function () {
var id = '%s';
if (typeof(window._tinymce_inited) == 'undefined') {
window._tinymce_inited = [];
}
if (typeof(window._tinymce_inited[id]) == 'undefined') {
window._tinymce_inited[id] = true;
} else {
var elements = id.replace(
/__prefix__/,
parseInt(document.getElementById('%sTOTAL_FORMS').value) - 1
);
if (document.getElementById(elements)) {
tinymce.init(%s);
}
}
}, 0);
</script>''' % (final_attrs['id'], final_attrs['id'][0:pos], mce_json))
else:
html.append('<script type="text/javascript">tinyMCE.init(%s)'
'</script>' % mce_json)
return mark_safe('\n'.join(html))
def _media(self):
"""Media."""
if tinymce_settings.USE_COMPRESSOR:
js = [reverse('tinymce-compressor')]
else:
js = [tinymce_settings.JS_URL]
if tinymce_settings.USE_FILEBROWSER:
js.append(reverse('tinymce-filebrowser'))
return forms.Media(js=js)
media = property(_media)
[docs]class AdminTinyMCE(admin_widgets.AdminTextareaWidget, TinyMCE):
"""Admin TinyMce."""
[docs]def get_language_config(content_language=None):
"""Get language config."""
language = get_language()[:2]
if content_language:
content_language = content_language[:2]
else:
content_language = language
config = {
'language': language,
}
lang_names = OrderedDict()
for lang, name in settings.LANGUAGES:
if lang[:2] not in lang_names:
lang_names[lang[:2]] = []
lang_names[lang[:2]].append(_(name))
sp_langs = []
for lang, names in lang_names.items():
if lang == content_language:
default = '+'
else:
default = ''
sp_langs.append('%s%s=%s' % (default, ' / '.join(names), lang))
config['spellchecker_languages'] = ','.join(sp_langs)
if content_language in settings.LANGUAGES_BIDI:
config['directionality'] = 'rtl'
else:
config['directionality'] = 'ltr'
if tinymce_settings.USE_SPELLCHECKER:
config['spellchecker_rpc_url'] = reverse('tinymce.views.spell_check')
return config