diff --git a/adhocracy-plus/config/settings/base.py b/adhocracy-plus/config/settings/base.py index 046a9ddc3c..7e05b2407e 100644 --- a/adhocracy-plus/config/settings/base.py +++ b/adhocracy-plus/config/settings/base.py @@ -35,7 +35,6 @@ "rules.apps.AutodiscoverRulesConfig", "easy_thumbnails", "ckeditor", - "ckeditor_uploader", "parler", # Wagtail cms components "wagtail.contrib.forms", @@ -305,120 +304,110 @@ ], } -# CKEditor - -CKEDITOR_UPLOAD_PATH = "uploads/" -CKEDITOR_RESTRICT_BY_USER = "username" -CKEDITOR_ALLOW_NONIMAGE_FILES = True - -CKEDITOR_CONFIGS = { +BLEACH_LIST = { "default": { - "width": "100%", - "toolbar": "Custom", - "toolbar_Custom": [ - ["Bold", "Italic", "Underline"], - ["NumberedList", "BulletedList"], - ["Link", "Unlink"], + "tags": [ + "p", + "strong", + "em", + "u", + "ol", + "li", + "ul", + "a", + "img", + "iframe", + "div", ], + "attributes": { + "a": ["href", "rel", "target"], + "img": ["src", "alt", "style"], + "div": ["class"], + "iframe": ["src", "alt", "style"], + }, }, "image-editor": { - "width": "100%", - "toolbar": "Custom", - "toolbar_Custom": [ - ["Bold", "Italic", "Underline"], - ["Image"], - ["NumberedList", "BulletedList"], - ["Link", "Unlink"], - ], - "removeDialogTabs": "image:Link", - }, - "collapsible-image-editor": { - "width": "100%", - "title": _("Rich text editor"), - "toolbar": "Custom", - "toolbar_Custom": [ - ["Bold", "Italic", "Underline"], - ["Image"], - ["NumberedList", "BulletedList"], - ["Link", "Unlink"], - ["CollapsibleItem"], - ["Embed", "EmbedBase"], + "tags": [ + "a", + "em", + "figcaption", + "figure", + "img", + "li", + "ol", + "p", + "span", + "strong", + "u", + "ul", ], - "removePlugins": "stylesheetparser", - "extraAllowedContent": "iframe[*]; div[*]", - "removeDialogTabs": "image:Link", - }, - "video-editor": { - "width": "100%", - "title": _("Rich text editor"), - "toolbar": "Custom", - "toolbar_Custom": [["Embed", "EmbedBase"]], - "removePlugins": "stylesheetparser", - "extraAllowedContent": "iframe[*]; div[*]", - }, -} - -BLEACH_LIST = { - "default": { - "tags": ["p", "strong", "em", "u", "ol", "li", "ul", "a"], "attributes": { "a": ["href", "rel", "target"], + "figure": ["class", "style"], + "figcaption": ["class"], + "img": ["class", "src", "alt", "style", "height", "width"], + "span": ["class", "style"], }, - }, - "image-editor": { - "tags": ["p", "strong", "em", "u", "ol", "li", "ul", "a", "img"], - "attributes": {"a": ["href", "rel", "target"], "img": ["src", "alt", "style"]}, "styles": [ + "aspect-ratio", "float", - "margin", - "padding", - "width", "height", + "margin", "margin-bottom", - "margin-top", "margin-left", "margin-right", + "margin-top", + "padding", + "width", ], }, "collapsible-image-editor": { "tags": [ + "a", + "div", + "em", + "figcaption", + "figure", + "iframe", + "img", + "li", + "ol", "p", + "span", "strong", - "em", "u", - "ol", - "li", "ul", - "a", - "img", - "div", - "iframe", ], "attributes": { "a": ["href", "rel", "target"], - "img": ["src", "alt", "style"], - "div": ["class"], - "iframe": ["src", "alt", "style"], + "div": ["class", "data-oembed-url"], + "figure": ["class", "style"], + "figcaption": ["class"], + "iframe": ["src", "alt"], + "img": ["class", "src", "alt", "style", "height", "width"], + "span": ["class", "style"], }, "styles": [ + "aspect-ratio", "float", - "margin", - "padding", - "width", "height", + "margin", "margin-bottom", - "margin-top", "margin-left", "margin-right", + "margin-top", + "padding", + "width", ], }, "video-editor": { - "tags": ["a", "img", "div", "iframe"], + "tags": ["a", "img", "div", "iframe", "figure"], "attributes": { "a": ["href", "rel", "target"], "img": ["src", "alt", "style"], - "div": ["class"], - "iframe": ["src", "alt", "style"], + "div": ["class", "data-oembed-url"], + "iframe": ["src", "alt"], + "figure": ["class", "div", "iframe"], }, }, } @@ -560,3 +549,134 @@ CELERY_RESULT_BACKEND = "redis://localhost:6379" CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = True CELERY_RESULT_EXTENDED = True + +# CKEditor config +CKEDITOR_UPLOAD_PATH = "uploads/" +CKEDITOR_5_FILE_STORAGE = "adhocracy4.ckeditor.storage.CustomStorage" +CKEDITOR_5_PATH_FROM_USERNAME = True +CKEDITOR_5_ALLOW_ALL_FILE_TYPES = True +CKEDITOR_5_UPLOAD_FILE_TYPES = ["jpg", "jpeg", "png", "gif", "pdf", "docx"] +CKEDITOR_5_CONFIGS = { + "default": { + "language": "de", + "toolbar": [ + "bold", + "italic", + "underline", + "|", + "link", + "bulletedList", + "numberedList", + ], + "list": { + "properties": { + "styles": "true", + "startIndex": "true", + "reversed": "true", + } + }, + "link": {"defaultProtocol": "https://"}, + }, + "image-editor": { + "language": "de", + "toolbar": { + "items": [ + "bold", + "italic", + "underline", + "bulletedList", + "numberedList", + "link", + "imageUpload", + "fileUpload", + ], + "shouldNotGroupWhenFull": "true", + }, + "image": { + "toolbar": [ + "imageUpload", + "imageTextAlternative", + "toggleImageCaption", + "imageStyle:inline", + "imageStyle:wrapText", + "imageStyle:breakText", + "imageStyle:alignLeft", + "imageStyle:alignRight", + ], + "insert": {"type": "auto"}, + }, + "list": { + "properties": { + "styles": "true", + "startIndex": "true", + "reversed": "true", + } + }, + "link": {"defaultProtocol": "https://"}, + }, + "collapsible-image-editor": { + "language": "de", + "toolbar": [ + "bold", + "italic", + "underline", + "bulletedList", + "numberedList", + "link", + "imageUpload", + "fileUpload", + "mediaEmbed", + "accordionButton", + "fontSize", + ], + "image": { + "toolbar": [ + "imageUpload", + "imageTextAlternative", + "toggleImageCaption", + "imageStyle:inline", + "imageStyle:wrapText", + "imageStyle:breakText", + "imageStyle:alignLeft", + "imageStyle:alignRight", + ], + "insert": {"type": "auto"}, + }, + "list": { + "properties": { + "styles": "true", + "startIndex": "true", + "reversed": "true", + } + }, + "link": {"defaultProtocol": "https://"}, + "mediaEmbed": { + "removeProviders": [ + "dailymotion", + "spotify", + "facebook", + "flickr", + "googleMaps", + "instagram", + "twitter", + ], + "previewsInData": True, + }, + }, + "video-editor": { + "language": "de", + "toolbar": ["mediaEmbed"], + "mediaEmbed": { + "removeProviders": [ + "dailymotion", + "spotify", + "facebook", + "flickr", + "googleMaps", + "instagram", + "twitter", + ], + "previewsInData": True, + }, + }, +} diff --git a/adhocracy-plus/config/urls.py b/adhocracy-plus/config/urls.py index 501076c0f8..45c52ae32f 100644 --- a/adhocracy-plus/config/urls.py +++ b/adhocracy-plus/config/urls.py @@ -1,6 +1,5 @@ """adhocracy+ URL Configuration.""" -from ckeditor_uploader import views as ck_views from django.conf import settings from django.conf.urls import i18n from django.contrib import admin @@ -107,14 +106,6 @@ re_path(r"^api/", include(router.urls)), re_path(r"^api/login", obtain_auth_token, name="api-login"), re_path(r"^api/account/", AccountViewSet.as_view(), name="api-account"), - re_path( - r"^upload/", user_is_project_admin(ck_views.upload), name="ckeditor_upload" - ), - re_path( - r"^browse/", - never_cache(user_is_project_admin(ck_views.browse)), - name="ckeditor_browse", - ), re_path(r"^components/$", contrib_views.ComponentLibraryView.as_view()), re_path(r"^jsi18n/$", JavaScriptCatalog.as_view(), name="javascript-catalog"), re_path( @@ -176,6 +167,9 @@ ] ), ), + path( + "ckeditor5/", include("django_ckeditor_5.urls"), name="ck_editor_5_upload_file" + ), path("sitemap.xml", static_sitemap_index, name="static-sitemap-index"), path("sitemap-wagtail.xml", wagtail_sitemap, name="wagtail-sitemap"), path( diff --git a/apps/activities/admin.py b/apps/activities/admin.py index 783ef6e146..7c31a246c1 100644 --- a/apps/activities/admin.py +++ b/apps/activities/admin.py @@ -1,6 +1,6 @@ -from ckeditor_uploader.widgets import CKEditorUploadingWidget from django import forms from django.contrib import admin +from django_ckeditor_5.widgets import CKEditor5Widget from . import models @@ -9,7 +9,7 @@ class ActivityAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields["description"].widget = CKEditorUploadingWidget( + self.fields["description"].widget = CKEditor5Widget( config_name="collapsible-image-editor", ) diff --git a/apps/contrib/templates/a4_candy_contrib/item_detail.html b/apps/contrib/templates/a4_candy_contrib/item_detail.html index ec0144b6d9..3f29803276 100644 --- a/apps/contrib/templates/a4_candy_contrib/item_detail.html +++ b/apps/contrib/templates/a4_candy_contrib/item_detail.html @@ -57,7 +57,9 @@

{{ object.name }}

- {{ object.description | richtext }} +
+ {{ object.description | richtext }} +
{% block additional_content %}{% endblock %} @@ -144,7 +146,7 @@

{% translate 'Official Feedback' %}

{% html_date object.moderator_feedback_text.created %}
-
+
{{ object.moderator_feedback_text.feedback_text | safe }}
diff --git a/apps/documents/assets/ParagraphForm.jsx b/apps/documents/assets/ParagraphForm.jsx index a4206e3104..46ae752f74 100644 --- a/apps/documents/assets/ParagraphForm.jsx +++ b/apps/documents/assets/ParagraphForm.jsx @@ -10,6 +10,21 @@ const ckReplace = function (id, config) { return window.CKEDITOR.replace(id, config) } +// translations +const translations = { + headline: django.gettext('Headline'), + paragraph: django.gettext('Paragraph'), + moveUp: django.gettext('Move up'), + moveDown: django.gettext('Move down'), + delete: django.gettext('Delete'), + helpText: django.gettext( + 'If you add an image, please provide an ' + + 'alternate text. It serves as a textual description of the image ' + + 'content and is read out by screen readers. Describe the image in ' + + 'approx. 80 characters. Example: A busy square with people in summer.' + ) +} + class ParagraphForm extends React.Component { handleNameChange (e) { const name = e.target.value @@ -68,7 +83,7 @@ class ParagraphForm extends React.Component {