Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace CKEditor by TinyMCE in Pod V4 #1227

Open
wants to merge 13 commits into
base: pod_V4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ module.exports = {
"interpolate": "readonly",
"bootstrap": "readonly",
"videojs": "readonly",
"CKEDITOR": "readonly",
"tinyMCE": "readonly",
"send_form_data": "writable",
"showalert": "writable",
"showLoader": "writable",
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/pod_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ run-name: ${{ github.actor }} is testing Pod encoding in Dev 🚀
on:
push:
branches:
- develop
- dev_v4
- features/**
- dependabot/**
pull_request:
branches:
- develop
- dev_v4
- pod_v4
workflow_dispatch:

env:
Expand Down
4 changes: 2 additions & 2 deletions pod/completion/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from django.template.defaultfilters import slugify
from ckeditor.fields import RichTextField
from tinymce.models import HTMLField
from pod.video.models import Video
from pod.video.utils import verify_field_length
from pod.main.models import get_nextautoincrement
Expand Down Expand Up @@ -352,7 +352,7 @@ class Overlay(models.Model):
default=2,
help_text=_("End time of the overlay, in seconds."),
)
content = RichTextField(_("Content"), null=False, blank=False, config_name="complete")
content = HTMLField(_("Content"), null=False, blank=False)
position = models.CharField(
_("Position"),
max_length=100,
Expand Down
4 changes: 2 additions & 2 deletions pod/enrichment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from django.utils.translation import gettext as _
from django.template.defaultfilters import slugify

from ckeditor.fields import RichTextField
from tinymce.models import HTMLField
from tempfile import NamedTemporaryFile
from webvtt import WebVTT, Caption

Expand Down Expand Up @@ -156,7 +156,7 @@ class Enrichment(models.Model):
on_delete=models.CASCADE,
help_text=_("Integrate a document (PDF, text, html)"),
)
richtext = RichTextField(_("Richtext"), config_name="complete", blank=True)
richtext = HTMLField(_("Richtext"), blank=True)
weblink = models.URLField(_("Web link"), max_length=200, null=True, blank=True)
embed = models.TextField(
_("Embed code"),
Expand Down
7 changes: 3 additions & 4 deletions pod/live/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import hashlib
import os

from ckeditor.fields import RichTextField
from tinymce.models import HTMLField
from django.conf import settings
from django.contrib.auth.models import Group
from django.contrib.auth.models import User
Expand Down Expand Up @@ -146,7 +146,7 @@ class Broadcaster(models.Model):
building = models.ForeignKey(
"Building", verbose_name=_("Building"), on_delete=models.CASCADE
)
description = RichTextField(_("description"), config_name="complete", blank=True)
description = HTMLField(_("description"), blank=True)
poster = models.ForeignKey(
CustomImageModel, models.SET_NULL, blank=True, null=True, verbose_name=_("Poster")
)
Expand Down Expand Up @@ -331,9 +331,8 @@ class Event(models.Model):
"of the content. (max length: 250 characters)"
),
)
description = RichTextField(
description = HTMLField(
_("Description"),
config_name="complete",
blank=True,
help_text=_(
"In this field you can describe your content, "
Expand Down
6 changes: 2 additions & 4 deletions pod/main/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Esup-Pod main admin page."""

from ckeditor.widgets import CKEditorWidget
from tinymce.widgets import TinyMCE
from django.contrib import admin
from django import forms
from django.contrib.flatpages.admin import FlatpageForm
Expand All @@ -18,9 +18,7 @@
SITE_ID = getattr(settings, "SITE_ID", 1)
content_widget = {}
for key, value in settings.LANGUAGES:
content_widget["content_%s" % key.replace("-", "_")] = CKEditorWidget(
config_name="complete"
)
content_widget["content_%s" % key.replace("-", "_")] = TinyMCE()


class PageForm(FlatpageForm):
Expand Down
5 changes: 2 additions & 3 deletions pod/main/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.db.models import Max
import os
import mimetypes
from ckeditor.fields import RichTextField
from tinymce.models import HTMLField


FILES_DIR = getattr(settings, "FILES_DIR", "files")
Expand Down Expand Up @@ -289,8 +289,7 @@ class Block(models.Model):
help_text=_("Select the playlist you want to link with."),
)

html = RichTextField(
config_name="complete",
html = HTMLField(
verbose_name=_("HTML"),
null=True,
blank=True,
Expand Down
54 changes: 0 additions & 54 deletions pod/main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,60 +133,6 @@
# WARNING: this folder must have previously been created.
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
##
# CKeditor settings
#
# CKEDITOR_BASEPATH = os.path.join(STATIC_URL, 'ckeditor', "/")
CKEDITOR_UPLOAD_PATH = os.path.join(MEDIA_ROOT, "uploads")
CKEDITOR_CONFIGS = {
"complete": {"toolbar": "full", "height": 300, "width": "100%"},
"default": {
"height": 300,
"width": "100%",
"toolbar": "custom",
"language": "fr",
"toolbar_custom": [
{
"name": "basicstyles",
"items": [
"Bold",
"Italic",
"Underline",
"Strike",
"Subscript",
"Superscript",
"-",
"RemoveFormat",
],
},
{
"name": "paragraph",
"items": [
"NumberedList",
"BulletedList",
"-",
"Outdent",
"Indent",
"-",
"Blockquote",
"CreateDiv",
"-",
"JustifyLeft",
"JustifyCenter",
"JustifyRight",
"JustifyBlock",
"-",
"BidiLtr",
"BidiRtl",
],
},
{"name": "links", "items": ["Link", "Unlink", "Anchor"]},
{"name": "tools", "items": ["Maximize"]},
],
"removePlugins": "exportpdf",
},
}


##
# Video tiers apps settings
Expand Down
5 changes: 5 additions & 0 deletions pod/main/static/css/pod-admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,8 @@
fieldset.collapse:not(.show) {
display: block;
}

/* Corrections on Django admin base.css */
select {
height: auto;
}
5 changes: 0 additions & 5 deletions pod/main/static/css/pod.css
Original file line number Diff line number Diff line change
Expand Up @@ -719,11 +719,6 @@ div.card a img {
content: "▲";
}

/** ckeditor **/
.django-ckeditor-widget {
width: 100%;
}

/** Dashboard **/
#bulk-update-container {
background-color: var(--pod-background-neutre2-bloc);
Expand Down
52 changes: 34 additions & 18 deletions pod/main/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,34 +148,32 @@ var slideToggle = (target, duration = 500) => {
};

/**
* [fadeIn description]
* @param {[type]} el [description]
* @param {[type]} display [description]
* @return {[type]} [description]
* Show HTML element whith fade effect
* @param {HTMLElement} el Dom element to show
* @param {string} display Display property (default: block)
*/
function fadeIn(el, display) {
el.style.opacity = 0;
el.classList.remove("d-none");
el.style.display = display || "block";
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += 0.1) > 1)) {
if (!((val += 0.04) > 1)) {
el.style.opacity = val;
requestAnimationFrame(fade);
}
})();
}

/**
* [fadeOut description]
* @param {[type]} elem [description]
* Hide element whith fade effect
* @param {HTMLElement} elem Dom element to hide
* @param {[type]} speed [description]
* @return {[type]} [description]
*/
function fadeOut(elem, speed) {
if (!elem.style.opacity) {
elem.style.opacity = 1;
} // end if
}

var outInterval = setInterval(function () {
elem.style.opacity -= 0.02;
Expand All @@ -185,9 +183,10 @@ function fadeOut(elem, speed) {
elem.style.opacity = Number(elem.style.opacity) + 0.02;
if (elem.style.opacity >= 1) clearInterval(inInterval);
}, speed / 50);
} // end if
}
}, speed / 50);
}

/**
* [isJson description]
* @param {[type]} str [description]
Expand Down Expand Up @@ -1104,6 +1103,7 @@ var append_picture_form = async function (data) {
userPictureModal.show();
}
};

/**
* [show_form_theme description]
* @param {[type]} data [description]
Expand All @@ -1112,22 +1112,38 @@ var append_picture_form = async function (data) {
function show_form_theme(data) {
let div_form = document.getElementById("div_form_theme");
div_form.style.display = "none";

// Destroy all WYSIWYG before replacing content
var theme_descriptions = document.querySelectorAll(
"textarea[id^='id_description']",
);

theme_descriptions.forEach((el) => {
let t=tinyMCE.get(el.id);
if (t) {
t.remove();
}
});

div_form.innerHTML = data;

// Reinit WYSIWYG on newly loaded textarea
theme_descriptions = document.querySelectorAll(
"textarea[id^='id_description']",
);

theme_descriptions.forEach((el) => {
let mce_conf = JSON.parse(el.dataset.mceConf);
tinyMCE.init(mce_conf);
});

fadeIn(div_form);
if (data != "")
document.querySelector("form.get_form_theme").style.display = "none";
window.scrollTo({
top: parseInt(document.getElementById("div_form_theme").offsetTop, 10),
behavior: "smooth",
});
// Add CKEditor when edit a theme
// For all descriptions, except description help
const theme_descriptions = document.querySelectorAll(
"textarea[id^='id_description']",
);
theme_descriptions.forEach((theme_description) => {
CKEDITOR.replace(theme_description.id);
});
}
/**
* [show_list_theme description]
Expand Down
4 changes: 2 additions & 2 deletions pod/recorder/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os
import importlib

from ckeditor.fields import RichTextField
from tinymce.models import HTMLField
from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -89,7 +89,7 @@ class Recorder(models.Model):
# Recorder name
name = models.CharField(_("name"), max_length=200, unique=True)
# Description of the recorder
description = RichTextField(_("description"), config_name="complete", blank=True)
description = HTMLField(_("description"), blank=True)
# IP address of the recorder
address_ip = models.GenericIPAddressField(
_("Address IP"), unique=True, help_text=_("IP address of the recorder.")
Expand Down
2 changes: 1 addition & 1 deletion pod/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"django.contrib.sites",
"django.contrib.flatpages",
# Exterior Applications
"ckeditor",
"tinymce",
"sorl.thumbnail",
# "tagging",
"tagulous",
Expand Down
2 changes: 2 additions & 0 deletions pod/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
path("robots.txt", robots_txt),
path("info_pod.json", info_pod),
re_path(r"^admin/", admin.site.urls),
# WYSIWYG editor
path('tinymce/', include('tinymce.urls')),
# Translation
path("i18n/", include("django.conf.urls.i18n")),
path("jsi18n/", JavaScriptCatalog.as_view(), name="javascript-catalog"),
Expand Down
7 changes: 4 additions & 3 deletions pod/video/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def get_form(self, request, obj=None, **kwargs):
exclude += (
"video",
"owner",
"thumbnail"
)
if not USE_TRANSCRIPTION:
exclude += ("transcript",)
Expand All @@ -228,19 +229,19 @@ def get_form(self, request, obj=None, **kwargs):
actions = ["encode_video", "draft_video"]

@admin.action(description=_("Set as draft"))
def draft_video(self, request, queryset):
def draft_video(self, request, queryset) -> None:
for item in queryset:
item.is_draft = True
item.save()

@admin.action(description=_("Encode selected"))
def encode_video(self, request, queryset):
def encode_video(self, request, queryset) -> None:
for item in queryset:
item.launch_encode = True
item.save()

@admin.action(description=_("Transcript selected"))
def transcript_video(self, request, queryset):
def transcript_video(self, request, queryset) -> None:
for item in queryset:
if item.get_video_mp3() and not item.encoding_in_progress:
transcript_video = getattr(transcript, TRANSCRIPT_VIDEO)
Expand Down
Loading
Loading