Régler les problèmes de ponctuation à la ligne

Dans cet article

J'adore écrire !

C'est par la création d'un site de vulgarisation scientifique que je suis arrivé à Drupal il y a plus de 10 ans, et aujourd'hui une partie de mon maigre temps libre est consacré à l'écriture, y compris en étant co-développeur d'un jeu RP par navigateur.

Bref, j'aime écrire !

Et dans l'écriture, une chose me chagrine : l'espace devant la ponctuation.

Prenez une phrase avec un "deux points" : voilà un espace devant la ponctuation ! Et devant ce point d'exclamation également ! Maintenant redimensionnez votre écran, et bim... fatalement, à un moment où un autre, vous allez vous retrouver avec une phrase dont la ponctuation est seule à la ligne. Comme ça 
!

Et ça m'énerve !!

Alors comment régler le problème ? D'autant que j'imagine que le français n'est pas la seule langue concernée.

Ajout d'un espace insécable

En théorie, c'est simple, il suffit de faire en sorte que l'espace devant cette ponctuation soit insécable. C'est à dire qu'il soit considéré par votre navigateur comme une lettre à part entière du mot, et à ce titre, ne puisse-t-être coupé. D'un point de vue code source, l'espace insécable se note   par opposition au simple espace " ".

<p>L'espace en fin de phrase est <em>insécable</em>&nbsp;!<p>
Le saviez-vous ?
Les lettres nbsp de cette entité html signifient:
Non-Breaking SPace.

Mises en œuvres possibles

Pour taper un tel espace au clavier, j'ai plusieurs possibilités :

  • Editer manuellement le code source de mon article, en allant dans la partie source de CKEditor. Autant dire que devant la lourdeur de la solution, c'est hors de question.
  • Utiliser un module type CKEditor Non-breaking space Plugin (&nbsp;) qui me permettrait de taper cet espace possible avec le raccourci Ctrl + Space. Là aussi, c'est assez laborieux et certainement un pli à prendre pour ne pas l'oublier devant chaque caractère de ponctuation.
  • Automatiser le tout !

Automatisation par un filtre

Vous l'aurez deviné, je suis développeur et donc fainéant par nature ! Impossible pour moi qu'une solution manuelle me convienne, voici donc ma solution à ce problème : un filtre pour les formats de texte.

Comme tout plugin dans Drupal, il se déclare par annotation et sera donc automatiquement reconnu par le manager des filtres de formats de texte et disponible dans la UI du site pour usage. La déclaration doctrine est un @Filter dont les configurations possibles sont lisibles dans la description de l'interface Drupal\filter\Plugin\FilterInterface.php.

Pour ma part, je le définis ainsi : 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Handles &nbsp; spaces before/after punctuations.
 *
 * @Filter(
 *   id = "nbsp_filter",
 *   title = @Translation("NBSP Filter"),
 *   description = @Translation("Handles &nbps; (non-breaking spaces in contents), depending on configuration"),
 *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
 *   settings = {
 *     "clean_all" = TRUE,
 *     "insert_before" = "?!;:",
 *     "insert_after" = "¿¡"
 *   },
 * )
 */

Ce filtre est déclaré irréversible car il va proposer de remplacer les &nbsp; par des espaces normaux au sein du texte. Cette opération ne peut être défaite, car nous perdons l'information de quel espace était insécable ou non avant opération. En ce sens, nous ne pourrons pas revenir en arrière une fois fait.

Ce filtre présente trois configurations distinctes dont les valeurs par défaut permettront de :

  • remplacer tous les &nbsp; au sein de l'article par des espaces normaux. CKEditor a en effet tendance à en ajouter à des endroits inutiles au fur et à mesure de l'évolution du texte inséré dans l'éditeur.
  • remplacer les espaces simples DEVANT quelques éléments de ponctuations donnés par défaut
  • remplacer les espaces simples APRES quelques éléments de ponctuations donnés par défaut

Nous allons ensuite étendre FilterBase ce qui nous donnera accès à divers méthode que nous pourrons surcharger.

La première que nous utiliserons : settingsForm permet de créer un formulaire de configuration. Il sera disponible en bas de la page d'édition d'un format de texte et permettra de modifier les configurations par défaut.

Configuration pour NBSP Filter
Configuration du filtre activé au sein du format de texte.

La seconde méthode utilisée est la méthode process qui va processer le texte donné en sortie et le renvoyer sous forme de FilterProcessResult une fois transformé de manière adéquate. Cette méthode se découpe en trois parties pour les trois transformations que nous avons évoquées au-dessus.

 

Je vous livre le code source entier de la classe à titre d'information :

Cliquez pour ouvrir/fermer ce bloc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
 
namespace Drupal\nbsp_filter\Plugin\Filter;
 
use Drupal\Core\Form\FormStateInterface;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
 
/**
 * Handles &nbsp; spaces before/after punctuations.
 *
 * @Filter(
 *   id = "nbsp_filter",
 *   title = @Translation("NBSP Filter"),
 *   description = @Translation("Handles &nbps; (non-breaking spaces in contents), depending on configuration"),
 *   type = Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
 *   settings = {
 *     "clean_all" = TRUE,
 *     "insert_before" = "?!;:",
 *     "insert_after" = "¿¡"
 *   },
 * )
 */
class NbspFilter extends FilterBase {
 
  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state) {
    $default = $this->defaultConfiguration();
    $form['clean_all'] = [
      '#type' => 'checkbox',
      '#title' => $this->t("Transform all &amp;nbps; (non-breaking spaces) with standard spaces"),
      '#default_value' => $this->settings['clean_all'],
      '#description' => $this->t("Remove non-breaking spaces in content and replace with standard spaces (excepted the ones configured below)"),
    ];
    $form['insert_before'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Insert &amp;nbps; (non-breaking space) before'),
      '#default_value' => $this->settings['insert_before'],
      '#description' => $this->t('List of characters to insert a non-breaking space before.'),
    ];
    $form['insert_after'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Insert &amp;nbps; (non-breaking space) after'),
      '#default_value' => $this->settings['insert_after'],
      '#description' => $this->t('List of characters to insert a non-breaking space after.'),
    ];
    return $form;
  }
 
  /**
   * {@inheritdoc}
   */
  public function process($text, $langcode) {
 
    // Replace all &nbsp; with standard spaces.
    if ($this->settings['clean_all']) {
      $text = str_replace('/([^>])&nbsp;/ui', '$1 ', $text);
    }
 
    // Replace spaces before configured characters with &nbsp;.
    $before_chars = $this->settings['insert_before'];
    if (!empty($before_chars)) {
      $pattern = "/ ([$before_chars])/i";
      $text = preg_replace($pattern, '&nbsp;$1', $text);
    }
 
    // Replace spaces after configured characters with &nbsp;.
    $after_chars = $this->settings['insert_after'];
    if (!empty($before_chars)) {
      $pattern = "/([$after_chars]) /i";
      $text = preg_replace($pattern, '$1&nbsp;', $text);
    }
 
    return new FilterProcessResult($text);
  }
}

 

Inutile de vous embêter à créer un module pour utiliser ce filtre chez vous ! Je l'ai fait pour vous, et l'ensemble est contribué directement en open-source sur drupal.org sous le nom de NBSP Filter. En cas de problème ou d'idée d'amélioration, je vous retrouve directement dans l'issue-queue :)

Ajouter un commentaire

Votre nom sera affiché publiquement avec votre commentaire.
Votre email restera privé et n'est utilisé que pour vous notifier de l'approbation de ce commentaire.
Sur internet, vous pouvez être qui vous voulez. Soyez quelqu'un de bien :)