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

Feat/improve max characters #282

Merged
Merged
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
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ CHANGELOG
-----------------------

- Fix of the widget `SelectMultipleWithPop` which did not add the newly created element in the related list (#1299)
- Add `MAX_CHARACTERS_BY_FIELD` to control the max length of a rich text field.
- Deprecate the `MAX_CHARACTERS` parameter

8.6.2 (2024-01-05)
-----------------------
Expand All @@ -14,6 +16,7 @@ CHANGELOG
- Support sub languages (see https://github.com/GeotrekCE/Geotrek-admin/issues/3801)



8.6.1 (2023-09-18)
-----------------------

Expand Down
9 changes: 6 additions & 3 deletions docs/customization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,12 @@ Or change just one parameter (the opacity for example) :
Edition
'''''''

For rich text fields, it is possible to a max number of caracters (spaces includes).
A help message will be added, and color of TinyMCE status bar will be colored in pink.
For rich text fields, it is possible to indicate a max number of characters on a specified field (spaces includes).
A help message will be added, and color of TinyMCE status bar and border will be colored in red.

.. code-block :: python

MAPENTITY_CONFIG['MAX_CHARACTERS'] = 1500
MAPENTITY_CONFIG['MAX_CHARACTERS_BY_FIELD'] = {
"tourism_touristicevent": [{'field': 'description_teaser_fr', 'value': 50}, {'field': 'accessibility_fr', 'value': 25}],
"trekking_trek": [{'field': 'description_teaser_fr', 'value': 150}],
}
23 changes: 20 additions & 3 deletions mapentity/forms.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import copy

from warnings import warn

from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Div, Button, HTML, Submit
Expand Down Expand Up @@ -106,15 +108,28 @@ def __init__(self, *args, **kwargs):
self.helper.form_tag = True

# If MAX_CHARACTERS is setted, set help text for rich text fields
textfield_help_text = ''
global_help_text = ''
max_characters = settings.MAPENTITY_CONFIG.get('MAX_CHARACTERS', None)
if max_characters:
textfield_help_text = _('%(max)s characters maximum recommended') % {'max': max_characters}

warn(
"Parameters MAX_CHARACTERS is deprecated, please use MAX_CHARACTERS_BY_FIELD instead",
DeprecationWarning,
stacklevel=2
)
global_help_text = _('%(max)s characters maximum recommended') % {'max': max_characters}

max_characters_by_field_config = settings.MAPENTITY_CONFIG.get('MAX_CHARACTERS_BY_FIELD', {}) or {}
# Default widgets
for fieldname, formfield in self.fields.items():
textfield_help_text = ''
# Custom code because formfield_callback does not work with inherited forms
if formfield:
# set max character limit :
if self._meta.model._meta.db_table in max_characters_by_field_config:
for conf in max_characters_by_field_config[self._meta.model._meta.db_table]:
if fieldname == conf["field"]:
textfield_help_text = _('%(max)s characters maximum recommended') % {'max': conf["value"]}

# Assign map widget to all geometry fields
try:
formmodel = self._meta.model
Expand All @@ -134,6 +149,8 @@ def __init__(self, *args, **kwargs):
# Bypass widgets that inherit textareas, such as geometry fields
if formfield.widget.__class__ == forms.widgets.Textarea:
formfield.widget = TinyMCE()
if max_characters:
textfield_help_text = global_help_text
if formfield.help_text:
formfield.help_text += f", {textfield_help_text}"
else:
Expand Down
1 change: 1 addition & 0 deletions mapentity/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
'MAP_STYLES': _DEFAULT_MAP_STYLES,
'REGEX_PATH_ATTACHMENTS': r'\.\d+x\d+_q\d+(_crop)?\.(jpg|png|jpeg)$',
'MAX_CHARACTERS': None,
'MAX_CHARACTERS_BY_FIELD': {},
}, **getattr(settings, 'MAPENTITY_CONFIG', {}))

# default MAP_STYLES should not be replaced but updated by MAPENTITY_CONFIG
Expand Down
25 changes: 24 additions & 1 deletion mapentity/static/mapentity/mapentity.helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ function tr(s) {


function tinyMceInit(editor) {
// Overflow on characters count
var context = $('body').data();
editor.on('WordCountUpdate', function(event) {
console.log(window.SETTINGS);
// DEPRECATED paramters maxCharacters -> to remove
if (("container" in event.target) && (window.SETTINGS.maxCharacters > 0)) {
var characters = event.wordCount.characters;
if (characters > window.SETTINGS.maxCharacters) {
Expand All @@ -117,5 +119,26 @@ function tinyMceInit(editor) {
event.target.container.classList.remove('cec-overflow');
}
}
if (("container" in event.target) && (window.SETTINGS.maxCharactersByField)) {
var fullTableName = context.appname+"_"+context.modelname
if (fullTableName in window.SETTINGS.maxCharactersByField) {
var currenInputName = event.target.container.previousSibling.name;
window.SETTINGS.maxCharactersByField[fullTableName].forEach(config => {
if(config.field == currenInputName) {
var statusBar = $(event.target.container).find(".tox-statusbar__wordcount");
$(event.target.container).find(".injectedCount").remove()
$("<p class='injectedCount'>"+event.wordCount.characters+"/"+config.value+" characters</p>").insertBefore(statusBar)
if(event.wordCount.characters > config.value) {

event.target.container.classList.add('cec-overflow');
event.target.container.classList.add('is-invalid');
} else {
event.target.container.classList.remove('cec-overflow');
event.target.container.classList.remove('is-invalid');
}
}
})
}
}
});
}
5 changes: 5 additions & 0 deletions mapentity/static/mapentity/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,11 @@ label.requiredField .asteriskField {
.cec-overflow.tox .tox-statusbar {
background-color: pink;
}
.tox.is-invalid {
border-color: #dc3545!important;

}



/*
Expand Down
2 changes: 2 additions & 0 deletions mapentity/views/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ class ModelName(mapentity_models.MapEntityMixin, models.Model):
# Languages
dictsettings['languages'] = dict(available=dict(app_settings['TRANSLATED_LANGUAGES']),
default=app_settings['LANGUAGE_CODE'])
# MAX_CHARACTERS paramters is deprecated : to remove
dictsettings['maxCharacters'] = app_settings['MAX_CHARACTERS']
dictsettings['maxCharactersByField'] = app_settings['MAX_CHARACTERS_BY_FIELD']
return dictsettings


Expand Down
32 changes: 22 additions & 10 deletions test_app/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,31 @@ def test_translated_fields_layout(self):


class MapEntityRichTextFormTest(TestCase):
old_setting = app_settings.copy()
old_setting["MAX_CHARACTERS"] = 10
new_setting = app_settings.copy()
new_setting['MAX_CHARACTERS_BY_FIELD'] = {
"test_app_dummymodel": [{'field': 'short_description', 'value': 5}]
}

def setUp(self):
app_settings['MAX_CHARACTERS'] = 1200

@override_settings(MAPENTITY_CONFIG=app_settings)
def test_max_characters(self):
"""Test if help text is set with MAX_CHARACTERS setting"""
@override_settings(MAPENTITY_CONFIG=new_setting)
def test_max_characters_by_field(self):
"""Test if help text is set with MAX_CHARACTERS_BY_FIELD setting"""
sample_object = DummyModel.objects.create()

form = DummyForm(instance=sample_object)
self.assertIn('1200 characters maximum recommended', form.fields['description'].help_text)
self.assertIn('Short description, 1200 characters maximum recommended',
self.assertIn('', form.fields['description'].help_text)
self.assertIn('Short description, 5 characters maximum recommended',
form.fields['short_description'].help_text)

def tearDown(self):
app_settings['MAX_CHARACTERS'] = 1200
@override_settings(MAPENTITY_CONFIG=old_setting)
def test_max_characters_global(self):
"""Test if help text is set with MAX_CHARACTERS setting -> deprecated paramter"""
sample_object = DummyModel.objects.create()

form = DummyForm(instance=sample_object)
for field_name in ["description", "short_description"]:
self.assertIn(
'10 characters maximum recommended',
form.fields[field_name].help_text
)