Merge pull request #8990 from tchak/fix-limit-textarea-size
ETQ administrateur, je veux pouvoir limiter le nombre de caractères dans les champs "texte long"
This commit is contained in:
commit
f563fb3269
14 changed files with 136 additions and 26 deletions
|
@ -42,6 +42,11 @@ $dossier-actions-bar-border-width: 1px;
|
|||
}
|
||||
}
|
||||
|
||||
.characters-count {
|
||||
position: relative;
|
||||
top: -1rem;
|
||||
}
|
||||
|
||||
.warning {
|
||||
margin-bottom: 20px;
|
||||
background-color: #f9b91666;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
en:
|
||||
remaining_characters: You have %{remaining_words} characters remaining.
|
||||
excess_characters: You have %{excess_words} characters too many.
|
|
@ -0,0 +1,3 @@
|
|||
fr:
|
||||
remaining_characters: Il vous reste %{remaining_words} caractères.
|
||||
excess_characters: Vous avez dépassé la taille conseillée de %{excess_words} caractères.
|
|
@ -4,3 +4,11 @@
|
|||
rows: 6,
|
||||
required: @champ.required?,
|
||||
value: html_to_string(@champ.value)
|
||||
|
||||
- if @champ.character_limit_info?
|
||||
%span.fr-icon-information-fill.fr-text-default--info.characters-count
|
||||
= t('.remaining_characters', remaining_words: @champ.remaining_characters)
|
||||
|
||||
- if @champ.character_limit_warning?
|
||||
%span.fr-icon-close-circle-fill.fr-text-default--error.characters-count
|
||||
= t('.excess_characters', excess_words: @champ.excess_characters)
|
||||
|
|
|
@ -36,6 +36,8 @@ fr:
|
|||
add_condition: Une condition a été ajoutée sur le champ « %{label} ». La nouvelle condition est « %{to} ».
|
||||
remove_condition: La condition du champ « %{label} » a été supprimée.
|
||||
update_condition: La condition du champ « %{label} » a été modifiée. La nouvelle condition est « %{to} ».
|
||||
update_character_limit: La limite de caractères du champ texte « %{label} » a été modifiée. La nouvelle limite est « %{to} ».
|
||||
remove_character_limit: La limite de caractères du champ texte « %{label} » a été supprimée.
|
||||
private:
|
||||
add: L’annotation privée « %{label} » a été ajoutée.
|
||||
remove: L’annotation privée « %{label} » a été supprimée.
|
||||
|
|
|
@ -130,7 +130,14 @@
|
|||
= t(".#{prefix}.update_condition", label: change.label, to: change.to)
|
||||
- if !total_dossiers.zero? && !change.can_rebase?
|
||||
.fr-alert.fr-alert--warning.fr-mt-1v
|
||||
%p= t('.breaking_change', count: total_dossiers)
|
||||
%p= t('.breakigng_change', count: total_dossiers)
|
||||
- when :character_limit
|
||||
- if change.to.blank?
|
||||
- list.with_item do
|
||||
= t(".#{prefix}.remove_character_limit", label: change.label, to: change.to)
|
||||
- else
|
||||
- list.with_item do
|
||||
= t(".#{prefix}.update_character_limit", label: change.label, to: change.to)
|
||||
|
||||
- if @public_move_changes.present?
|
||||
- list.with_item do
|
||||
|
|
|
@ -121,4 +121,14 @@ class TypesDeChampEditor::ChampComponent < ApplicationComponent
|
|||
def conditional_enabled?
|
||||
!type_de_champ.private?
|
||||
end
|
||||
|
||||
def options_for_character_limit
|
||||
[
|
||||
[t('.character_limit.unlimited'), nil],
|
||||
[t('.character_limit.limit', limit: 400), 400],
|
||||
[t('.character_limit.limit', limit: 1000), 1000],
|
||||
[t('.character_limit.limit', limit: 5000), 5000],
|
||||
[t('.character_limit.limit', limit: 10000), 10000]
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,3 +10,6 @@ fr:
|
|||
natura_2000: Natura 2000
|
||||
zones_humides: Zones humides d’importance internationale
|
||||
znieff: ZNIEFF
|
||||
character_limit:
|
||||
unlimited: Pas de limite de charactères
|
||||
limit: Limité à %{limit} caractères
|
||||
|
|
|
@ -101,8 +101,11 @@
|
|||
= form.label :collapsible_explanation_text, for: dom_id(type_de_champ, :collapsible_explanation_text) do
|
||||
= "Texte à afficher quand l'utiliser a choisi de l'afficher"
|
||||
= form.text_area :collapsible_explanation_text, class: "small-margin small", id: dom_id(type_de_champ, :collapsible_explanation_text)
|
||||
|
||||
|
||||
- if type_de_champ.textarea?
|
||||
.cell
|
||||
= form.label :character_limit, for: dom_id(type_de_champ, :character_limit) do
|
||||
Spécifier un nombre maximal de caractères (non restrictif) :
|
||||
= form.select :character_limit, options_for_character_limit, id: dom_id(type_de_champ, :character_limit)
|
||||
|
||||
- if type_de_champ.block?
|
||||
.flex.justify-start.section.ml-1
|
||||
|
|
|
@ -119,28 +119,29 @@ module Administrateurs
|
|||
|
||||
def type_de_champ_update_params
|
||||
params.required(:type_de_champ).permit(:type_champ,
|
||||
:libelle,
|
||||
:description,
|
||||
:mandatory,
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:collapsible_explanation_enabled,
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level,
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
:unesco,
|
||||
:arretes_protection,
|
||||
:conservatoire_littoral,
|
||||
:reserves_chasse_faune_sauvage,
|
||||
:reserves_biologiques,
|
||||
:reserves_naturelles,
|
||||
:natura_2000,
|
||||
:zones_humides,
|
||||
:znieff
|
||||
])
|
||||
:libelle,
|
||||
:description,
|
||||
:mandatory,
|
||||
:drop_down_list_value,
|
||||
:drop_down_other,
|
||||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:collapsible_explanation_enabled,
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level,
|
||||
:character_limit,
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
:unesco,
|
||||
:arretes_protection,
|
||||
:conservatoire_littoral,
|
||||
:reserves_chasse_faune_sauvage,
|
||||
:reserves_biologiques,
|
||||
:reserves_naturelles,
|
||||
:natura_2000,
|
||||
:zones_humides,
|
||||
:znieff
|
||||
])
|
||||
end
|
||||
|
||||
def draft
|
||||
|
|
|
@ -75,6 +75,8 @@ class Champ < ApplicationRecord
|
|||
:mandatory?,
|
||||
:prefillable?,
|
||||
:refresh_after_update?,
|
||||
:character_limit?,
|
||||
:character_limit,
|
||||
to: :type_de_champ
|
||||
|
||||
delegate :to_typed_id, :to_typed_id_for_query, to: :type_de_champ, prefix: true
|
||||
|
|
|
@ -24,4 +24,44 @@ class Champs::TextareaChamp < Champs::TextChamp
|
|||
def for_export
|
||||
value.present? ? ActionView::Base.full_sanitizer.sanitize(value) : nil
|
||||
end
|
||||
|
||||
def remaining_characters
|
||||
character_limit_base - character_count if character_count >= character_limit_threshold_75
|
||||
end
|
||||
|
||||
def excess_characters
|
||||
character_count - character_limit_base if character_count > character_limit_base
|
||||
end
|
||||
|
||||
def character_limit_info?
|
||||
analyze_character_count == :info
|
||||
end
|
||||
|
||||
def character_limit_warning?
|
||||
analyze_character_count == :warning
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def character_count
|
||||
return value&.bytesize
|
||||
end
|
||||
|
||||
def character_limit_base
|
||||
character_limit&.to_i
|
||||
end
|
||||
|
||||
def character_limit_threshold_75
|
||||
character_limit_base * 0.75
|
||||
end
|
||||
|
||||
def analyze_character_count
|
||||
if character_limit? && character_count.present?
|
||||
if character_count >= character_limit_base
|
||||
return :warning
|
||||
elsif character_count >= character_limit_threshold_75
|
||||
return :info
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -377,6 +377,13 @@ class ProcedureRevision < ApplicationRecord
|
|||
from_type_de_champ.piece_justificative_template_filename,
|
||||
to_type_de_champ.piece_justificative_template_filename)
|
||||
end
|
||||
elsif to_type_de_champ.textarea?
|
||||
if from_type_de_champ.character_limit != to_type_de_champ.character_limit
|
||||
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
|
||||
:character_limit,
|
||||
from_type_de_champ.character_limit,
|
||||
to_type_de_champ.character_limit)
|
||||
end
|
||||
end
|
||||
changes
|
||||
end
|
||||
|
|
|
@ -19,6 +19,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
FILE_MAX_SIZE = 200.megabytes
|
||||
FEATURE_FLAGS = {}
|
||||
MINIMUM_TEXTAREA_CHARACTER_LIMIT_LENGTH = 400
|
||||
|
||||
STRUCTURE = :structure
|
||||
ETAT_CIVIL = :etat_civil
|
||||
|
@ -118,6 +119,7 @@ class TypeDeChamp < ApplicationRecord
|
|||
:drop_down_secondary_libelle,
|
||||
:drop_down_secondary_description,
|
||||
:drop_down_other,
|
||||
:character_limit,
|
||||
:collapsible_explanation_enabled,
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level
|
||||
|
@ -177,6 +179,11 @@ class TypeDeChamp < ApplicationRecord
|
|||
|
||||
validates :libelle, presence: true, allow_blank: false, allow_nil: false
|
||||
validates :type_champ, presence: true, allow_blank: false, allow_nil: false
|
||||
validates :character_limit, numericality: {
|
||||
greater_than_or_equal_to: MINIMUM_TEXTAREA_CHARACTER_LIMIT_LENGTH,
|
||||
only_integer: true,
|
||||
allow_blank: true
|
||||
}
|
||||
|
||||
before_validation :check_mandatory
|
||||
before_validation :normalize_libelle
|
||||
|
@ -235,6 +242,10 @@ class TypeDeChamp < ApplicationRecord
|
|||
drop_down_other == "1" || drop_down_other == true
|
||||
end
|
||||
|
||||
def character_limit?
|
||||
character_limit.present?
|
||||
end
|
||||
|
||||
def collapsible_explanation_enabled?
|
||||
collapsible_explanation_enabled == "1"
|
||||
end
|
||||
|
@ -340,6 +351,10 @@ class TypeDeChamp < ApplicationRecord
|
|||
type_champ == TypeDeChamp.type_champs.fetch(:number)
|
||||
end
|
||||
|
||||
def textarea?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:textarea)
|
||||
end
|
||||
|
||||
def titre_identite?
|
||||
type_champ == TypeDeChamp.type_champs.fetch(:titre_identite)
|
||||
end
|
||||
|
@ -539,7 +554,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
type_champs.fetch(:multiple_drop_down_list),
|
||||
type_champs.fetch(:dossier_link),
|
||||
type_champs.fetch(:linked_drop_down_list),
|
||||
type_champs.fetch(:drop_down_list)
|
||||
type_champs.fetch(:drop_down_list),
|
||||
type_champs.fetch(:textarea)
|
||||
true
|
||||
else
|
||||
false
|
||||
|
|
Loading…
Reference in a new issue