widgets.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from django import forms
  2. from django.conf import settings
  3. from django.core.exceptions import ImproperlyConfigured
  4. from django.core.serializers.json import DjangoJSONEncoder
  5. from django.forms.widgets import Media
  6. from django.templatetags.static import static
  7. from django.utils.encoding import force_str
  8. from django.utils.functional import Promise
  9. from django.utils.translation import get_language
  10. from js_asset import JS
  11. from .configs import DEFAULT_CONFIG
  12. class LazyEncoder(DjangoJSONEncoder):
  13. def default(self, obj):
  14. if isinstance(obj, Promise):
  15. return force_str(obj)
  16. return super().default(obj)
  17. json_encode = LazyEncoder().encode
  18. class CKEditorWidget(forms.Textarea):
  19. """
  20. Widget providing CKEditor for Rich Text Editing.
  21. Supports direct image uploads and embed.
  22. """
  23. def __init__(
  24. self,
  25. config_name="default",
  26. extra_plugins=None,
  27. external_plugin_resources=None,
  28. template_name="ckeditor/widget.html",
  29. *args,
  30. **kwargs
  31. ):
  32. self.template_name = template_name
  33. super().__init__(*args, **kwargs)
  34. self.config_name = config_name
  35. # Setup config from defaults.
  36. self.config = DEFAULT_CONFIG.copy()
  37. # Try to get valid config from settings.
  38. configs = getattr(settings, "CKEDITOR_CONFIGS", None)
  39. if configs:
  40. if isinstance(configs, dict):
  41. # Make sure the config_name exists.
  42. if self.config_name in configs:
  43. config = configs[self.config_name]
  44. # Make sure the configuration is a dictionary.
  45. if not isinstance(config, dict):
  46. raise ImproperlyConfigured(
  47. 'CKEDITOR_CONFIGS["%s"] \
  48. setting must be a dictionary type.'
  49. % self.config_name
  50. )
  51. # Override defaults with settings config.
  52. self.config.update(config)
  53. else:
  54. raise ImproperlyConfigured(
  55. "No configuration named '%s' \
  56. found in your CKEDITOR_CONFIGS setting."
  57. % self.config_name
  58. )
  59. else:
  60. raise ImproperlyConfigured(
  61. "CKEDITOR_CONFIGS setting must be a\
  62. dictionary type."
  63. )
  64. extra_plugins = extra_plugins or self.config.pop("extra_plugins", None) or []
  65. if extra_plugins:
  66. self.config["extraPlugins"] = ",".join(extra_plugins)
  67. self.external_plugin_resources = (
  68. external_plugin_resources
  69. or self.config.pop("external_plugin_resources", None)
  70. or []
  71. )
  72. @property
  73. def media(self):
  74. return Media(
  75. css={"all": ["ckeditor/ckeditor.css"]},
  76. js=(
  77. JS(
  78. "ckeditor/ckeditor-init.js",
  79. {
  80. "id": "ckeditor-init-script",
  81. "data-ckeditor-basepath": getattr(
  82. settings,
  83. "CKEDITOR_BASEPATH",
  84. None,
  85. )
  86. or static("ckeditor/ckeditor/"),
  87. },
  88. ),
  89. "ckeditor/ckeditor/ckeditor.js",
  90. "ckeditor/fixups.js",
  91. ),
  92. )
  93. def get_context(self, name, value, attrs):
  94. context = super().get_context(name, value, attrs)
  95. self._set_config()
  96. context["widget"]["config"] = json_encode(self.config)
  97. external_plugin_resources = [
  98. [force_str(a), force_str(b), force_str(c)]
  99. for a, b, c in self.external_plugin_resources
  100. ]
  101. context["widget"]["external_plugin_resources"] = json_encode(
  102. external_plugin_resources
  103. )
  104. return context
  105. def _set_config(self):
  106. lang = get_language().lower()
  107. if lang == "zh-hans":
  108. lang = "zh-cn"
  109. elif lang == "zh-hant":
  110. lang = "zh"
  111. self.config["language"] = lang
  112. self.config["versionCheck"] = False