widgets.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. from __future__ import absolute_import
  2. from django import forms
  3. from django.conf import settings
  4. from django.core.exceptions import ImproperlyConfigured
  5. from django.template.loader import render_to_string
  6. from django.utils.encoding import force_text
  7. from django.utils.html import conditional_escape
  8. from django.utils.safestring import mark_safe
  9. try:
  10. # Django >=1.7
  11. from django.forms.utils import flatatt
  12. except ImportError:
  13. # Django <1.7
  14. from django.forms.util import flatatt
  15. DEFAULT_CONFIG = {
  16. 'width': '90%',
  17. 'heigth': 500,
  18. 'toolbar': ["undo", "redo", "|",
  19. "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|",
  20. "h1", "h2", "h3", "h5", "h6", "|",
  21. "list-ul", "list-ol", "hr", "|",
  22. "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime",
  23. "emoji", "html-entities", "pagebreak", "goto-line", "|",
  24. "help", "info",
  25. "||", "preview", "watch", "fullscreen"],
  26. 'upload_image_formats': ["jpg", "JPG", "jpeg", "JPEG", "gif", "GIF", "png",
  27. "PNG", "bmp", "BMP", "webp", "WEBP"],
  28. 'image_floder': 'editor',
  29. 'theme': 'default', # dark / default
  30. 'preview_theme': 'default', # dark / default
  31. 'editor_theme': 'default', # pastel-on-dark / default
  32. 'toolbar_autofixed': True,
  33. 'search_replace': True,
  34. 'emoji': True,
  35. 'tex': True,
  36. 'flow_chart': True,
  37. 'sequence': True,
  38. 'mermaid': True,
  39. 'vega': True
  40. }
  41. class MDEditorWidget(forms.Textarea):
  42. """
  43. Widget providing Editor.md for Rich Text Editing.
  44. see Editor.md docs: https://pandao.github.io/editor.md/examples/index.html
  45. """
  46. def __init__(self, config_name='default', *args, **kwargs):
  47. super(MDEditorWidget, self).__init__(*args, **kwargs)
  48. # Setup config from defaults.
  49. self.config = DEFAULT_CONFIG.copy()
  50. # Try to get valid config from settings.
  51. configs = getattr(settings, 'MDEDITOR_CONFIGS', None)
  52. if configs:
  53. if isinstance(configs, dict):
  54. # Make sure the config_name exists.
  55. if config_name in configs:
  56. config = configs[config_name]
  57. # Make sure the configuration is a dictionary.
  58. if not isinstance(config, dict):
  59. raise ImproperlyConfigured('MDEDITOR_CONFIGS["%s"] \
  60. setting must be a dictionary type.' %
  61. config_name)
  62. # Override defaults with settings config.
  63. self.config.update(config)
  64. else:
  65. raise ImproperlyConfigured("No configuration named '%s' \
  66. found in your CKEDITOR_CONFIGS setting." %
  67. config_name)
  68. else:
  69. raise ImproperlyConfigured('CKEDITOR_CONFIGS setting must be a\
  70. dictionary type.')
  71. def render(self, name, value, attrs=None):
  72. if value is None:
  73. value = ''
  74. final_attrs = self.build_attrs(self.attrs, attrs, name=name)
  75. return mark_safe(render_to_string('markdown.html', {
  76. 'final_attrs': flatatt(final_attrs),
  77. 'value': conditional_escape(force_text(value)),
  78. 'id': final_attrs['id'],
  79. 'config': self.config,
  80. }))
  81. def build_attrs(self, base_attrs, extra_attrs=None, **kwargs):
  82. """
  83. Helper function for building an attribute dictionary.
  84. This is combination of the same method from Django<=1.10 and Django1.11+
  85. """
  86. attrs = dict(base_attrs, **kwargs)
  87. if extra_attrs:
  88. attrs.update(extra_attrs)
  89. return attrs
  90. def _get_media(self):
  91. return forms.Media(
  92. css={
  93. "all": ("mdeditor/css/editormd.css",)
  94. },
  95. js=(
  96. "mdeditor/js/jquery.min.js",
  97. "mdeditor/js/editormd.js",
  98. ))
  99. media = property(_get_media)