Skip to content

Commit f04e1c8

Browse files
committed
Migrate from TinyMCE 5 to TinyMCE 6
1 parent 5e4d420 commit f04e1c8

File tree

243 files changed

+5520
-44216
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

243 files changed

+5520
-44216
lines changed

CHANGELOG.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ Changelog
33

44
This document describes changes between each past release.
55

6+
4.0.0 (?)
7+
=========
8+
9+
- Upgrade embedded tinyMCE from 5.10.7 to 6.8.3
10+
11+
The spellchecker plugin is gone (including ``USE_SPELLCHECKER`` setting). Use
12+
the `browser_spellcheck` TinyMCE option (activated by default) to enable
13+
browser-based spellchecking.
14+
15+
616
3.7.1 (2024-02-06)
717
==================
818

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Releases
7373

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

76-
Using TinyMCE 5.10.7.
76+
Using TinyMCE 6.8.3.
7777

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

docs/index.rst

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,20 @@ as a TinyMCE_ editor.
77
Features:
88
* Use as a form widget or with a view.
99
* Enhanced support for content languages.
10-
* Integration with the TinyMCE spellchecker.
1110
* Enables predefined link and image lists for dialogs.
1211
* Support for django-staticfiles
1312
* Can compress the TinyMCE Javascript code.
1413
* Integration with `django-filebrowser`_.
1514

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

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

2320
.. _Django: https://www.djangoproject.com/
2421
.. _TinyMCE: https://www.tiny.cloud/
2522
.. _`django-filebrowser`: https://github.com/sehmaschine/django-filebrowser/
26-
.. _`MIT License`: https://www.opensource.org/licenses/mit-license.php
27-
.. _`LGPL v2.1 license`: https://www.tinymce.com/license/
23+
.. _`MIT License`: https://opensource.org/license/mit/
2824

2925
Documentation
3026
-------------

docs/installation.rst

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,11 @@ The django-tinymce application requires a supported `Django`_ version.
1515
If you use the `django-filebrowser`_ application in your project, the tinymce
1616
application can use it as a browser when including media.
1717

18-
If you want to use the `spellchecker plugin`_ using the supplied view (no PHP
19-
needed) you must install the `PyEnchant`_ package and dictionaries for your
20-
project languages. Note that the Enchant needs a dictionary that exactly
21-
matches your language codes. For example, a dictionary for code ``'en-us'``
22-
will not automatically be used for ``'en'``. You can check the availability of
23-
the Enchant dictionary for the ``'en'`` language code using the following
24-
Python code::
25-
26-
import enchant
27-
enchant.dict_exists('en')
28-
2918
Note that the documentation will use 'TinyMCE' (capitalized) to refer the
3019
editor itself and 'django-tinymce' (lower case) to refer to the Django application.
3120

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

3925
Installation
@@ -131,8 +117,8 @@ file.
131117
"theme": "silver",
132118
"height": 500,
133119
"menubar": False,
134-
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
135-
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
120+
"plugins": "advlist,autolink,lists,link,image,charmap,preview,anchor,"
121+
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,"
136122
"code,help,wordcount",
137123
"toolbar": "undo redo | formatselect | "
138124
"bold italic backcolor | alignleft aligncenter "
@@ -141,11 +127,6 @@ file.
141127
}
142128

143129

144-
``TINYMCE_SPELLCHECKER`` (default: ``False``)
145-
Whether to use the spell checker through the supplied view. You must add
146-
``spellchecker`` to the TinyMCE plugin list yourself, it is not added
147-
automatically.
148-
149130
``TINYMCE_COMPRESSOR`` (default: ``False``)
150131
Whether to use the TinyMCE compressor, which gzips all Javascript files into
151132
a single stream. This makes the overall download size 75% smaller and also
@@ -166,17 +147,17 @@ Example::
166147
"height": "320px",
167148
"width": "960px",
168149
"menubar": "file edit view insert format tools table help",
169-
"plugins": "advlist autolink lists link image charmap print preview anchor searchreplace visualblocks code "
170-
"fullscreen insertdatetime media table paste code help wordcount spellchecker",
150+
"plugins": "advlist autolink lists link image charmap preview anchor searchreplace visualblocks code "
151+
"fullscreen insertdatetime media table code help wordcount",
171152
"toolbar": "undo redo | bold italic underline strikethrough | fontselect fontsizeselect formatselect | alignleft "
172153
"aligncenter alignright alignjustify | outdent indent | numlist bullist checklist | forecolor "
173154
"backcolor casechange permanentpen formatpainter removeformat | pagebreak | charmap emoticons | "
174155
"fullscreen preview save print | insertfile image media pageembed template link anchor codesample | "
175156
"a11ycheck ltr rtl | showcomments addcomment code",
176157
"custom_undo_redo_levels": 10,
177-
"language": "es_ES", # To force a specific language instead of the Django current language.
158+
"language": "es", # To force a specific language instead of the Django current language.
159+
"browser_spellcheck": True,
178160
}
179-
TINYMCE_SPELLCHECKER = True
180161
TINYMCE_COMPRESSOR = True
181162
TINYMCE_EXTRA_MEDIA = {
182163
'css': {

docs/usage.rst

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ The tinymce application adds one TinyMCE configuration option that can be set
4646
using ``mce_attrs`` (it is not useful as a default configuration):
4747

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

5555
Templates
5656
^^^^^^^^^
@@ -119,11 +119,9 @@ Example::
119119
tinyMCE.init({
120120
mode: "textareas",
121121
theme: "silver",
122-
plugins: "spellchecker,directionality,paste,searchreplace",
122+
plugins: "directionality,searchreplace",
123123
language: "{{ language }}",
124124
directionality: "{{ directionality }}",
125-
spellchecker_languages : "{{ spellchecker_languages }}",
126-
spellchecker_rpc_url : "{{ spellchecker_rpc_url }}"
127125
});
128126

129127
This example also shows the variables you can use in the template. The language

tests/settings.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
"theme": "silver",
7979
"height": 500,
8080
"menubar": False,
81-
"plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
82-
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
81+
"plugins": "advlist,autolink,lists,link,image,charmap,preview,anchor,"
82+
"searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,"
8383
"code,help,wordcount",
8484
"toolbar": "undo redo | formatselect | "
8585
"bold italic backcolor | alignleft aligncenter "

tests/test_compressor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ def test_compressor(self):
5555
"js": "true",
5656
"compress": "true",
5757
"languages": "en",
58-
"plugins": "example",
59-
"themes": "advanced",
58+
"plugins": "codesample",
59+
"themes": "silver",
6060
},
6161
)
6262
response = gzip_compressor(request)

tests/test_views.py

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import os
2-
from unittest.mock import Mock, patch
3-
from urllib.parse import urlencode
2+
from unittest.mock import patch
43

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

1817

1918
class TestViews(TestCase):
20-
@patch("tinymce.views.enchant")
21-
def test_spell_check_words(self, enchant_mock):
22-
checker_mock = Mock()
23-
checker_mock.check.return_value = True
24-
enchant_mock.Dict.return_value = checker_mock
25-
26-
body = urlencode({"method": "spellcheck", "text": "tesat", "lang": "en"})
27-
response = self.client.post(
28-
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
29-
)
30-
31-
output = {"words": {}}
32-
33-
self.assertEqual(200, response.status_code)
34-
self.assertEqual("application/json", response["Content-Type"])
35-
self.assertEqual(output, response.json())
36-
37-
@patch("tinymce.views.enchant")
38-
def test_spell_check_suggest(self, enchant_mock):
39-
result = ["sample"]
40-
checker_mock = Mock()
41-
checker_mock.check.return_value = False
42-
checker_mock.suggest.return_value = result
43-
enchant_mock.Dict.return_value = checker_mock
44-
45-
body = urlencode({"method": "spellcheck", "text": "smaple", "lang": "en"})
46-
response = self.client.post(
47-
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
48-
)
49-
50-
output = {"words": {"smaple": ["sample"]}}
51-
52-
self.assertEqual(200, response.status_code)
53-
self.assertEqual("application/json", response["Content-Type"])
54-
self.assertEqual(output, response.json())
55-
56-
@patch("tinymce.views.enchant")
57-
def test_spell_check_empty(self, enchant_mock):
58-
checker_mock = Mock()
59-
checker_mock.check.return_value = True
60-
enchant_mock.Dict.return_value = checker_mock
61-
62-
body = urlencode({"method": "spellcheck", "text": "", "lang": "en"})
63-
response = self.client.post(
64-
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
65-
)
66-
67-
output = {"words": {}}
68-
69-
self.assertEqual(200, response.status_code)
70-
self.assertEqual("application/json", response["Content-Type"])
71-
self.assertEqual(output, response.json())
72-
73-
@patch("tinymce.views.enchant")
74-
def test_spell_check_unknown_method(self, enchant_mock):
75-
body = urlencode({"method": "test", "text": "test", "lang": "en"})
76-
with patch("sys.stderr", devnull):
77-
response = self.client.post(
78-
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
79-
)
80-
81-
output = {"error": "Got an unexpected method 'test'"}
82-
83-
self.assertEqual(200, response.status_code)
84-
self.assertEqual("application/json", response["Content-Type"])
85-
self.assertEqual(output, response.json())
86-
87-
@patch("tinymce.views.enchant")
88-
def test_spell_check_unknown_lang(self, enchant_mock):
89-
enchant_mock.dict_exists.return_value = False
90-
91-
body = urlencode({"method": "spellcheck", "text": "test", "lang": "en"})
92-
with patch("sys.stderr", devnull):
93-
response = self.client.post(
94-
"/tinymce/spellchecker/", body, content_type="application/x-www-form-urlencoded"
95-
)
96-
97-
output = {"error": "Dictionary not found for language 'en', check pyenchant."}
98-
99-
self.assertEqual(200, response.status_code)
100-
self.assertEqual("application/json", response["Content-Type"])
101-
self.assertEqual(output, response.json())
102-
10319
def test_flatpages_link_list(self):
10420
FlatPage.objects.create(
10521
url="/test/url",

tests/test_widgets.py

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ class TestWidgets(SimpleTestCase):
2626
def test_default_config(self):
2727
config = get_language_config("en")
2828
config_ok = {
29-
"spellchecker_languages": "+English=en",
3029
"directionality": "ltr",
31-
"spellchecker_rpc_url": "/tinymce/spellchecker/",
3230
}
3331
self.assertEqual(config, config_ok)
3432

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

4239
@override_settings(LANGUAGES_BIDI=["en"])
4340
def test_default_config_rtl(self):
4441
config = get_language_config("en")
45-
config_ok = {
46-
"spellchecker_languages": "+English=en",
47-
"directionality": "rtl",
48-
"spellchecker_rpc_url": "/tinymce/spellchecker/",
49-
}
50-
self.assertEqual(config, config_ok)
42+
self.assertEqual(config["directionality"], "rtl")
5143

5244
def test_config_from_language_code(self):
5345
langs = [
@@ -85,26 +77,17 @@ def test_language_override_from_config(self):
8577
"""language in DEFAULT_CONFIG has priority over current Django language."""
8678
widget = TinyMCE()
8779
orig_config = tinymce.settings.DEFAULT_CONFIG
88-
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es_ES"}):
80+
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es"}):
8981
config = widget.get_mce_config(attrs={"id": "id"})
90-
self.assertEqual(config["language"], "es_ES")
82+
self.assertEqual(config["language"], "es")
9183

9284
def test_mce_attrs_language_priority(self):
9385
widget = TinyMCE(mce_attrs={"language": "ru"})
9486
orig_config = tinymce.settings.DEFAULT_CONFIG
95-
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es_ES"}):
87+
with patch.dict(tinymce.settings.DEFAULT_CONFIG, {**orig_config, "language": "es"}):
9688
config = widget.get_mce_config(attrs={"id": "id"})
9789
self.assertEqual(config["language"], "ru")
9890

99-
def test_content_language(self):
100-
config = get_language_config("ru-ru")
101-
config_ok = {
102-
"spellchecker_languages": "English=en",
103-
"directionality": "ltr",
104-
"spellchecker_rpc_url": "/tinymce/spellchecker/",
105-
}
106-
self.assertEqual(config, config_ok)
107-
10891
def test_tinymce_widget(self):
10992
widget = TinyMCE()
11093
html = widget.render("foobar", "lorem ipsum", attrs={"id": "id_foobar"})

tinymce/compressor.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ def split_commas(str):
5050
def gzip_compressor(request):
5151
plugins = split_commas(request.GET.get("plugins", ""))
5252
languages = split_commas(request.GET.get("languages", ""))
53+
if "en" in languages:
54+
languages.remove("en")
5355
themes = split_commas(request.GET.get("themes", ""))
5456
files = split_commas(request.GET.get("files", ""))
5557
source = request.GET.get("src", "") == "true"

0 commit comments

Comments
 (0)