暂无描述

widgets.py 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. # -- coding: utf-8 --
  2. """simditor widgets."""
  3. from __future__ import absolute_import
  4. from django import forms
  5. from django.conf import settings
  6. from django.core.exceptions import ImproperlyConfigured
  7. from django.core.serializers.json import DjangoJSONEncoder
  8. from django.template.loader import render_to_string
  9. from django.utils.encoding import force_text
  10. from django.utils.functional import Promise
  11. from django.utils.html import conditional_escape
  12. from django.utils.safestring import mark_safe
  13. try:
  14. # Django >=2.1
  15. from django.forms.widgets import get_default_renderer
  16. IS_NEW_WIDGET = True
  17. except ImportError:
  18. IS_NEW_WIDGET = False
  19. try:
  20. # Django >=1.7
  21. from django.forms.utils import flatatt
  22. except ImportError:
  23. # Django <1.7
  24. from django.forms.util import flatatt # pylint disable=E0611, E0401
  25. class LazyEncoder(DjangoJSONEncoder):
  26. """LazyEncoder."""
  27. # pylint disable=E0202
  28. def default(self, obj):
  29. if isinstance(obj, Promise):
  30. return force_text(obj)
  31. return super(LazyEncoder, self).default(obj)
  32. JSON_ENCODE = LazyEncoder().encode
  33. FULL_TOOLBAR = [
  34. 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
  35. 'color', '|', 'ol', 'ul', 'blockquote', 'code', 'table', '|', 'link',
  36. 'image', 'hr', '|', 'indent', 'outdent', 'alignment', 'checklist',
  37. 'markdown', 'fullscreen'
  38. ]
  39. DEFAULT_TOOLBAR = [
  40. 'title', 'bold', 'italic', 'underline', 'strikethrough', 'fontScale',
  41. 'color', '|', 'ol', 'ul', 'blockquote', 'table', '|', 'link',
  42. 'image', 'hr', '|', 'indent', 'outdent', 'alignment'
  43. ]
  44. DEFAULT_CONFIG = {
  45. 'toolbar': DEFAULT_TOOLBAR,
  46. 'cleanPaste': True,
  47. 'tabIndent': True,
  48. 'pasteImage': True,
  49. 'upload': {
  50. 'url': '/',
  51. 'fileKey': 'file'
  52. }
  53. }
  54. class SimditorWidget(forms.Textarea):
  55. """
  56. Widget providing Simditor for Rich Text Editing.abs
  57. Supports direct image uploads and embed.
  58. """
  59. class Media:
  60. """Media."""
  61. css_list = [
  62. 'simditor/styles/simditor.min.css'
  63. ]
  64. if 'emoji' in settings.SIMDITOR_TOOLBAR:
  65. css_list.append('simditor/styles/simditor-emoji.css')
  66. if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
  67. css_list.append('simditor/styles/simditor-fullscreen.min.css')
  68. if 'checklist' in settings.SIMDITOR_TOOLBAR:
  69. css_list.append('simditor/styles/simditor-checklist.min.css')
  70. if 'markdown' in settings.SIMDITOR_TOOLBAR:
  71. css_list.append('simditor/styles/simditor-markdown.min.css')
  72. css = {'all': tuple(settings.STATIC_URL + url for url in css_list)}
  73. jquery_list = ['simditor/scripts/jquery.min.js',
  74. 'simditor/scripts/module.min.js',
  75. 'simditor/scripts/hotkeys.min.js',
  76. 'simditor/scripts/uploader.min.js',
  77. 'simditor/scripts/simditor.min.js']
  78. if 'fullscreen' in settings.SIMDITOR_TOOLBAR:
  79. jquery_list.append('simditor/scripts/simditor-fullscreen.min.js')
  80. if 'checklist' in settings.SIMDITOR_TOOLBAR:
  81. jquery_list.append('simditor/scripts/simditor-checklist.min.js')
  82. if 'markdown' in settings.SIMDITOR_TOOLBAR:
  83. jquery_list.append('simditor/scripts/marked.min.js')
  84. jquery_list.append('simditor/scripts/to-markdown.min.js')
  85. jquery_list.append('simditor/scripts/simditor-markdown.min.js')
  86. if 'image' in settings.SIMDITOR_TOOLBAR:
  87. jquery_list.append('simditor/scripts/simditor-dropzone.min.js')
  88. if 'emoji' in settings.SIMDITOR_TOOLBAR:
  89. jquery_list.append('simditor/scripts/simditor-emoji.js')
  90. js = tuple(settings.STATIC_URL + url for url in jquery_list)
  91. try:
  92. js += (settings.STATIC_URL + 'simditor/simditor-init.js',)
  93. except AttributeError:
  94. raise ImproperlyConfigured("django-simditor requires \
  95. SIMDITOR_MEDIA_PREFIX setting. This setting specifies a \
  96. URL prefix to the ckeditor JS and CSS media (not \
  97. uploaded media). Make sure to use a trailing slash: \
  98. SIMDITOR_MEDIA_PREFIX = '/media/simditor/'")
  99. def __init__(self, *args, **kwargs):
  100. super(SimditorWidget, self).__init__(*args, **kwargs)
  101. # Setup config from defaults.
  102. self.config = DEFAULT_CONFIG.copy()
  103. # Try to get valid config from settings.
  104. configs = getattr(settings, 'SIMDITOR_CONFIGS', None)
  105. if configs:
  106. if isinstance(configs, dict):
  107. self.config.update(configs)
  108. else:
  109. raise ImproperlyConfigured(
  110. 'SIMDITOR_CONFIGS setting must be a dictionary type.')
  111. def build_attrs(self, base_attrs, extra_attrs=None, **kwargs):
  112. """
  113. Helper function for building an attribute dictionary.
  114. This is combination of the same method from Django<=1.10 and Django1.11
  115. """
  116. attrs = dict(base_attrs, **kwargs)
  117. if extra_attrs:
  118. attrs.update(extra_attrs)
  119. return attrs
  120. def render(self, name, value, attrs=None, renderer=None):
  121. if value is None:
  122. value = ''
  123. final_attrs = self.build_attrs(self.attrs, attrs, name=name)
  124. params = ('simditor/widget.html', {
  125. 'final_attrs': flatatt(final_attrs),
  126. 'value': conditional_escape(force_text(value)),
  127. 'id': final_attrs['id'],
  128. 'config': JSON_ENCODE(self.config)
  129. })
  130. if renderer is None and IS_NEW_WIDGET:
  131. renderer = get_default_renderer()
  132. data = renderer.render(*params) if IS_NEW_WIDGET else render_to_string(*params)
  133. return mark_safe(data)