Skip to content

Commit

Permalink
Migrate from TinyMCE 5 to TinyMCE 6
Browse files Browse the repository at this point in the history
  • Loading branch information
claudep committed Mar 1, 2024
1 parent 5e4d420 commit f04e1c8
Show file tree
Hide file tree
Showing 243 changed files with 5,520 additions and 44,216 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ Changelog

This document describes changes between each past release.

4.0.0 (?)
=========

- Upgrade embedded tinyMCE from 5.10.7 to 6.8.3

The spellchecker plugin is gone (including ``USE_SPELLCHECKER`` setting). Use
the `browser_spellcheck` TinyMCE option (activated by default) to enable
browser-based spellchecking.


3.7.1 (2024-02-06)
==================

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Releases

Latest release is 3.7.1. It supports Python 3.8+ and Django 3.2 to 5.0.

Using TinyMCE 5.10.7.
Using TinyMCE 6.8.3.

Previous releases can be found on github, but they are no longer maintained.

Expand Down
10 changes: 3 additions & 7 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,20 @@ as a TinyMCE_ editor.
Features:
* Use as a form widget or with a view.
* Enhanced support for content languages.
* Integration with the TinyMCE spellchecker.
* Enables predefined link and image lists for dialogs.
* Support for django-staticfiles
* Can compress the TinyMCE Javascript code.
* Integration with `django-filebrowser`_.

The django-tinymce code is licensed under the `MIT License`_. See the ``LICENSE.txt``
file in the distribution. Note that the TinyMCE editor is distributed under
the `LGPL v2.1 license`_.
The django-tinymce code is licensed under the `MIT License`_, the same licence
as the TinyMCE editor itself. See the ``LICENSE.txt`` file in the distribution.

Starting with django-tinymce v1.5.1 TinyMCE editor is bundled with django-tinymce to enable easy installation and usage.
Note that django-tinymce and TinyMCE licenses are compatible (although different) and we have permission to bundle TinyMCE with django-tinymce.

.. _Django: https://www.djangoproject.com/
.. _TinyMCE: https://www.tiny.cloud/
.. _`django-filebrowser`: https://github.com/sehmaschine/django-filebrowser/
.. _`MIT License`: https://www.opensource.org/licenses/mit-license.php
.. _`LGPL v2.1 license`: https://www.tinymce.com/license/
.. _`MIT License`: https://opensource.org/license/mit/

Documentation
-------------
Expand Down
31 changes: 6 additions & 25 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,11 @@ The django-tinymce application requires a supported `Django`_ version.
If you use the `django-filebrowser`_ application in your project, the tinymce
application can use it as a browser when including media.

If you want to use the `spellchecker plugin`_ using the supplied view (no PHP
needed) you must install the `PyEnchant`_ package and dictionaries for your
project languages. Note that the Enchant needs a dictionary that exactly
matches your language codes. For example, a dictionary for code ``'en-us'``
will not automatically be used for ``'en'``. You can check the availability of
the Enchant dictionary for the ``'en'`` language code using the following
Python code::

import enchant
enchant.dict_exists('en')

Note that the documentation will use 'TinyMCE' (capitalized) to refer the
editor itself and 'django-tinymce' (lower case) to refer to the Django application.

.. _`Django`: https://www.djangoproject.com/download/
.. _`TinyMCE`: https://www.tiny.cloud/get-tiny/
.. _`language pack`: https://www.tiny.cloud/get-tiny/language-packages/
.. _`spellchecker plugin`: https://www.tiny.cloud/docs/plugins/spellchecker/
.. _`PyEnchant`: https://pyenchant.github.io/pyenchant/install.html
.. _`django-filebrowser`: https://github.com/sehmaschine/django-filebrowser

Installation
Expand Down Expand Up @@ -131,8 +117,8 @@ file.
"theme": "silver",
"height": 500,
"menubar": False,
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
"plugins": "advlist,autolink,lists,link,image,charmap,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,"
"code,help,wordcount",
"toolbar": "undo redo | formatselect | "
"bold italic backcolor | alignleft aligncenter "
Expand All @@ -141,11 +127,6 @@ file.
}


``TINYMCE_SPELLCHECKER`` (default: ``False``)
Whether to use the spell checker through the supplied view. You must add
``spellchecker`` to the TinyMCE plugin list yourself, it is not added
automatically.

``TINYMCE_COMPRESSOR`` (default: ``False``)
Whether to use the TinyMCE compressor, which gzips all Javascript files into
a single stream. This makes the overall download size 75% smaller and also
Expand All @@ -166,17 +147,17 @@ Example::
"height": "320px",
"width": "960px",
"menubar": "file edit view insert format tools table help",
"plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code "
"fullscreen insertdatetime media table paste code help wordcount spellchecker",
"plugins": "advlist autolink lists link image charmap preview anchor searchreplace visualblocks code "
"fullscreen insertdatetime media table code help wordcount",
"toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft "
"aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor "
"backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | "
"fullscreen preview save print | insertfile image media pageembed template link anchor codesample | "
"a11ycheck ltr rtl | showcomments addcomment code",
"custom_undo_redo_levels": 10,
"language": "es_ES", # To force a specific language instead of the Django current language.
"language": "es", # To force a specific language instead of the Django current language.
"browser_spellcheck": True,
}
TINYMCE_SPELLCHECKER = True
TINYMCE_COMPRESSOR = True
TINYMCE_EXTRA_MEDIA = {
'css': {
Expand Down
14 changes: 6 additions & 8 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ The tinymce application adds one TinyMCE configuration option that can be set
using ``mce_attrs`` (it is not useful as a default configuration):

``content_language`` (default: ``django.utils.translation.get_language_code()``)
The language of the widget content. Will be used to set the ``language``,
``directionality`` and ``spellchecker_languages`` configuration options of
the TinyMCE editor. It may be different from the interface language, which
defaults to the current Django language and can be changed using the
``language`` configuration option in ``mce_attrs``)
The language of the widget content. Will be used to set the ``language`` and
``directionality`` configuration options of the TinyMCE editor. It may be
different from the interface language, which defaults to the current Django
language and can be changed using the ``language`` configuration option in
``mce_attrs``)

Templates
^^^^^^^^^
Expand Down Expand Up @@ -119,11 +119,9 @@ Example::
tinyMCE.init({
mode: "textareas",
theme: "silver",
plugins: "spellchecker,directionality,paste,searchreplace",
plugins: "directionality,searchreplace",
language: "{{ language }}",
directionality: "{{ directionality }}",
spellchecker_languages : "{{ spellchecker_languages }}",
spellchecker_rpc_url : "{{ spellchecker_rpc_url }}"
});

This example also shows the variables you can use in the template. The language
Expand Down
4 changes: 2 additions & 2 deletions tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@
"theme": "silver",
"height": 500,
"menubar": False,
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
"plugins": "advlist,autolink,lists,link,image,charmap,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,"
"code,help,wordcount",
"toolbar": "undo redo | formatselect | "
"bold italic backcolor | alignleft aligncenter "
Expand Down
4 changes: 2 additions & 2 deletions tests/test_compressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ def test_compressor(self):
"js": "true",
"compress": "true",
"languages": "en",
"plugins": "example",
"themes": "advanced",
"plugins": "codesample",
"themes": "silver",
},
)
response = gzip_compressor(request)
Expand Down
86 changes: 1 addition & 85 deletions tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import os
from unittest.mock import Mock, patch
from urllib.parse import urlencode
from unittest.mock import patch

from django.contrib.flatpages.models import FlatPage
from django.http import HttpResponse
Expand All @@ -17,89 +16,6 @@ def compress_whitespace(s):


class TestViews(TestCase):
@patch("tinymce.views.enchant")
def test_spell_check_words(self, enchant_mock):
checker_mock = Mock()
checker_mock.check.return_value = True
enchant_mock.Dict.return_value = checker_mock

body = urlencode({"method": "spellcheck", "text": "tesat", "lang": "en"})
response = self.client.post(
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
)

output = {"words": {}}

self.assertEqual(200, response.status_code)
self.assertEqual("application/json", response["Content-Type"])
self.assertEqual(output, response.json())

@patch("tinymce.views.enchant")
def test_spell_check_suggest(self, enchant_mock):
result = ["sample"]
checker_mock = Mock()
checker_mock.check.return_value = False
checker_mock.suggest.return_value = result
enchant_mock.Dict.return_value = checker_mock

body = urlencode({"method": "spellcheck", "text": "smaple", "lang": "en"})
response = self.client.post(
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
)

output = {"words": {"smaple": ["sample"]}}

self.assertEqual(200, response.status_code)
self.assertEqual("application/json", response["Content-Type"])
self.assertEqual(output, response.json())

@patch("tinymce.views.enchant")
def test_spell_check_empty(self, enchant_mock):
checker_mock = Mock()
checker_mock.check.return_value = True
enchant_mock.Dict.return_value = checker_mock

body = urlencode({"method": "spellcheck", "text": "", "lang": "en"})
response = self.client.post(
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
)

output = {"words": {}}

self.assertEqual(200, response.status_code)
self.assertEqual("application/json", response["Content-Type"])
self.assertEqual(output, response.json())

@patch("tinymce.views.enchant")
def test_spell_check_unknown_method(self, enchant_mock):
body = urlencode({"method": "test", "text": "test", "lang": "en"})
with patch("sys.stderr", devnull):
response = self.client.post(
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
)

output = {"error": "Got an unexpected method 'test'"}

self.assertEqual(200, response.status_code)
self.assertEqual("application/json", response["Content-Type"])
self.assertEqual(output, response.json())

@patch("tinymce.views.enchant")
def test_spell_check_unknown_lang(self, enchant_mock):
enchant_mock.dict_exists.return_value = False

body = urlencode({"method": "spellcheck", "text": "test", "lang": "en"})
with patch("sys.stderr", devnull):
response = self.client.post(
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
)

output = {"error": "Dictionary not found for language 'en', check pyenchant."}

self.assertEqual(200, response.status_code)
self.assertEqual("application/json", response["Content-Type"])
self.assertEqual(output, response.json())

def test_flatpages_link_list(self):
FlatPage.objects.create(
url="/test/url",
Expand Down
25 changes: 4 additions & 21 deletions tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ class TestWidgets(SimpleTestCase):
def test_default_config(self):
config = get_language_config("en")
config_ok = {
"spellchecker_languages": "+English=en",
"directionality": "ltr",
"spellchecker_rpc_url": "/tinymce/spellchecker/",
}
self.assertEqual(config, config_ok)

Expand All @@ -37,17 +35,11 @@ def test_no_active_language(self):
with override(None):
config = widget.get_mce_config(attrs={"id": "id"})
self.assertNotIn("language", config.keys())
self.assertEqual(config["spellchecker_languages"], "+English=en")

@override_settings(LANGUAGES_BIDI=["en"])
def test_default_config_rtl(self):
config = get_language_config("en")
config_ok = {
"spellchecker_languages": "+English=en",
"directionality": "rtl",
"spellchecker_rpc_url": "/tinymce/spellchecker/",
}
self.assertEqual(config, config_ok)
self.assertEqual(config["directionality"], "rtl")

def test_config_from_language_code(self):
langs = [
Expand Down Expand Up @@ -85,26 +77,17 @@ def test_language_override_from_config(self):
"""language in DEFAULT_CONFIG has priority over current Django language."""
widget = TinyMCE()
orig_config = tinymce.settings.DEFAULT_CONFIG
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es_ES"}):
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es"}):
config = widget.get_mce_config(attrs={"id": "id"})
self.assertEqual(config["language"], "es_ES")
self.assertEqual(config["language"], "es")

def test_mce_attrs_language_priority(self):
widget = TinyMCE(mce_attrs={"language": "ru"})
orig_config = tinymce.settings.DEFAULT_CONFIG
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es_ES"}):
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es"}):
config = widget.get_mce_config(attrs={"id": "id"})
self.assertEqual(config["language"], "ru")

def test_content_language(self):
config = get_language_config("ru-ru")
config_ok = {
"spellchecker_languages": "English=en",
"directionality": "ltr",
"spellchecker_rpc_url": "/tinymce/spellchecker/",
}
self.assertEqual(config, config_ok)

def test_tinymce_widget(self):
widget = TinyMCE()
html = widget.render("foobar", "lorem ipsum", attrs={"id": "id_foobar"})
Expand Down
2 changes: 2 additions & 0 deletions tinymce/compressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def split_commas(str):
def gzip_compressor(request):
plugins = split_commas(request.GET.get("plugins", ""))
languages = split_commas(request.GET.get("languages", ""))
if "en" in languages:
languages.remove("en")
themes = split_commas(request.GET.get("themes", ""))
files = split_commas(request.GET.get("files", ""))
source = request.GET.get("src", "") == "true"
Expand Down
7 changes: 3 additions & 4 deletions tinymce/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
"theme": "silver",
"height": 500,
"menubar": False,
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
"browser_spellcheck": True,
"plugins": "advlist,autolink,lists,link,image,charmap,preview,anchor,"
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,"
"code,help,wordcount",
"toolbar": "undo redo | formatselect | "
"bold italic backcolor | alignleft aligncenter "
Expand All @@ -18,8 +19,6 @@
},
)

USE_SPELLCHECKER = getattr(settings, "TINYMCE_SPELLCHECKER", False)

USE_COMPRESSOR = getattr(settings, "TINYMCE_COMPRESSOR", False)

USE_EXTRA_MEDIA = getattr(settings, "TINYMCE_EXTRA_MEDIA", None)
Expand Down
1 change: 0 additions & 1 deletion tinymce/static/django_tinymce/init_tinymce.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@

// Call function fn when the DOM is loaded and ready. If it is already
// loaded, call the function now.
// https://youmightnotneedjquery.com/#ready
function ready(fn) {
if (document.readyState !== 'loading') {
fn();
Expand Down
2 changes: 1 addition & 1 deletion tinymce/static/tinymce/icons/default/icons.min.js

Large diffs are not rendered by default.

Loading

0 comments on commit f04e1c8

Please sign in to comment.