Développer un plugin, on s'occupe de l'administration, 1re partie

Aujourd’hui on va commencer à s’occuper de l’utilisation de la bibliothèque d’Access42 à l’administration de Dotclear, en commençant par l’aspect préférences utilisateurs. On verra dans un deuxième temps sa mise en œuvre effective et les quelques problèmes rencontrés.

Tout d’abord, voyons la mise en place du réglage du plugin pour l’utilisateur côté administration, accessible via le lien « Mes préférences » en haut du tableau de bord. Le principe, côté code, est assez similaire à celui qu’on avait mis en œuvre un premier temps pour l’activation du plugin dans les paramètres du blog[1] :

Il faut mettre en place :

  • Un traitement associé au behavior adminPreferencesForm pour afficher les éléments de formulaire spécifiques à notre plugin
  • Un traitement associé au behavior adminBeforeUserOptionsUpdate pour enregistrer les choix spécifiques à notre plugin lorsque le formulaire est validé (appui sur le bouton « Enregistrer »)

C’est ce qu’on peut découvrir dans le code du fichier _admin.php que j’ai complété pour cela :

…
$core->addBehavior('adminBeforeUserOptionsUpdate', ['a11yconfigAdmin', 'adminBeforeUserOptionsUpdate']);
$core->addBehavior('adminPreferencesForm', ['a11yconfigAdmin', 'adminPreferencesForm']);
…
class a11yconfigAdmin
{
    public static function adminBeforeUserOptionsUpdate($cur, $userID)
    {
        global $core;

        // Get and store user's prefs for plugin options
        $core->auth->user_prefs->addWorkspace('a11yConfig');
        try {
            $core->auth->user_prefs->a11yConfig->put('active', !empty($_POST['a11yc_active']), 'boolean');

            $core->auth->user_prefs->a11yConfig->put('label', html::escapeHTML($_POST['a11yc_label']), 'string');
            $core->auth->user_prefs->a11yConfig->put('icon', abs((integer) $_POST['a11yc_icon']), 'integer');
            $core->auth->user_prefs->a11yConfig->put('position', abs((integer) $_POST['a11yc_position']), 'integer');

            $core->auth->user_prefs->a11yConfig->put('font', !empty($_POST['a11yc_font']), 'boolean');
            $core->auth->user_prefs->a11yConfig->put('linespacing', !empty($_POST['a11yc_linespacing']), 'boolean');
            $core->auth->user_prefs->a11yConfig->put('justification', !empty($_POST['a11yc_justification']), 'boolean');
            $core->auth->user_prefs->a11yConfig->put('contrast', !empty($_POST['a11yc_contrast']), 'boolean');
            $core->auth->user_prefs->a11yConfig->put('image', !empty($_POST['a11yc_image']), 'boolean');
        } catch (Exception $e) {
            $core->error->add($e->getMessage());
        }
    }

    public static function adminPreferencesForm($core)
    {
        $a11yc_positions = [
            0 => __('In admin header'),
            1 => __('In admin footer')
        ];

        $a11yc_icons = [
            0 => __('No'),
            1 => __('Wheelchair'),
            2 => __('Visual deficiency')
        ];

        // Get user's prefs for plugin options
        $core->auth->user_prefs->addWorkspace('a11yConfig');

        $a11yc_active = (boolean) $core->auth->user_prefs->a11yConfig->active;

        $a11yc_label    = $core->auth->user_prefs->a11yConfig->label;
        $a11yc_icon     = (integer) $core->auth->user_prefs->a11yConfig->icon;
        $a11yc_position = (integer) $core->auth->user_prefs->a11yConfig->position;

        $a11yc_font          = (boolean) $core->auth->user_prefs->a11yConfig->font;
        $a11yc_linespacing   = (boolean) $core->auth->user_prefs->a11yConfig->linespacing;
        $a11yc_justification = (boolean) $core->auth->user_prefs->a11yConfig->justification;
        $a11yc_contrast      = (boolean) $core->auth->user_prefs->a11yConfig->contrast;
        $a11yc_image         = (boolean) $core->auth->user_prefs->a11yConfig->image;

        echo
        '<div class="fieldset"><h5>' . __('a11yConfig') . '</h5>';

        echo
        '<p>' . form::checkbox('a11yc_active', 1, $a11yc_active) . ' ' .
        '<label for="a11yc_active" class="classic">' . __('Active a11yConfig') . '</label></p>';

        echo
        '<p><label for="a11yc_label" class="required" title="' . __('Required field') . '"><abbr title="' . __('Required field') . '">*</abbr> ' . __('Label:') . '</label> ' .
        form::field('a11yc_label', 30, 256, html::escapeHTML($a11yc_label), '', '', false, 'required placeholder="' . __('Accessibility parameters') . '"') .
            '</p>';

        // Options for button appearance
        echo '<h6>' . __('Icon:') . '</h6>';
        echo
        '<p class="form-note">' . __('The previous label will be used as alternative text if one of proposed icons is choosen.') . '</p>';
        $i = 0;
        foreach ($a11yc_icons as $k => $v) {
            echo '<p><label for="a11yc_icon_' . $i . '" class="classic">' .
            form::radio(['a11yc_icon', 'a11yc_icon_' . $i], $k, $a11yc_icon == $k) . ' ' . $v . '</label></p>';
            $i++;
        }

        // Options for automatic insertion
        echo '<h6>' . __('Position:') . '</h6>';
        $i = 0;
        foreach ($a11yc_positions as $k => $v) {
            echo '<p><label for="a11yc_position_' . $i . '" class="classic">' .
            form::radio(['a11yc_position', 'a11yc_position_' . $i], $k, $a11yc_position == $k) . ' ' . $v . '</label></p>';
            $i++;
        }

        echo '<h6>' . __('Options:') . '</h6>';
        echo
        '<p>' . form::checkbox('a11yc_font', 1, $a11yc_font) . ' ' .
        '<label for="a11yc_font" class="classic">' . __('Font adaptation') . '</label></p>' .
        '<p>' . form::checkbox('a11yc_linespacing', 1, $a11yc_linespacing) . ' ' .
        '<label for="a11yc_linespacing" class="classic">' . __('Line Spacing adaptation') . '</label></p>' .
        '<p>' . form::checkbox('a11yc_justification', 1, $a11yc_justification) . ' ' .
        '<label for="a11yc_justification" class="classic">' . __('Justification adaptation') . '</label></p>' .
        '<p>' . form::checkbox('a11yc_contrast', 1, $a11yc_contrast) . ' ' .
        '<label for="a11yc_contrast" class="classic">' . __('Contrast adaptation') . '</label></p>' .
        '<p>' . form::checkbox('a11yc_image', 1, $a11yc_image) . ' ' .
        '<label for="a11yc_image" class="classic">' . __('Image replacement') . '</label></p>';

        echo
            '</div>';
    }
}

Je ne vais pas détailler beaucoup plus cette partie vu que c’est assez similaire à ce qu’on a mis en place dans le fichier index.php qui gère les options pour la partie publique du blog.

À noter cependant :

  • Pas de choix pour l’insertion automatique ou pas ici, seuls les choix entête ou pied de page sont disponibles pour la position du bouton. La raison est qu’on a pas de moyen de s’insérer dans la construction du code HTML d’une page de l’administration et j’ai donc du m’occuper de ça via un script javascript qu’on verra dans le billet suivant au sujet de la mise en œuvre.
  • Vous aurez remarqué que j’utilise la notation $core->auth->user_prefs->a11yConfig… plutôt que $core->blog->settings->a11yConfig… utilisé pour les paramètres du blog ; puisqu’il s’agit ici de réglages spécifiques à l’utilisateur connecté. Là où côté blog on utilise la notion de namespace (ou espace de nom), on utilise maintenant la notion de workspace (ou espace de travail). Tout le reste de la mécanique entre ces deux notions étant de fonctionnement identique.

Côté visible dans les préférences utilisateur, voilà à quoi ça ressemble du côté de l’onglet « Mes options » :

a11yConfig : préférences utilisateur, janv. 2020

On n’oublie pas non plus la partie dédiée pendant l’installation, donc dans le fichier _install.php :

// Default user settings
    $core->auth->user_prefs->addWorkspace('a11yConfig');
    $core->auth->user_prefs->a11yConfig->put('active', false, 'boolean', 'Active', false, true);

    $core->auth->user_prefs->a11yConfig->put('label', 'Accessibility parameters', 'string', 'Label', false, true);
    $core->auth->user_prefs->a11yConfig->put('icon', 0, 'integer', 'Icon', false, true);
    $core->auth->user_prefs->a11yConfig->put('position', 0, 'integer', 'Position', false, true);

    $core->auth->user_prefs->a11yConfig->put('font', true, 'boolean', 'Font adaptation', false, true);
    $core->auth->user_prefs->a11yConfig->put('linespacing', true, 'boolean', 'Line spacing adaptation', false, true);
    $core->auth->user_prefs->a11yConfig->put('justification', true, 'boolean', 'justification adaptation', false, true);
    $core->auth->user_prefs->a11yConfig->put('contrast', true, 'boolean', 'contrast adaptation', false, true);
    $core->auth->user_prefs->a11yConfig->put('image', true, 'boolean', 'Image replacement', false, true);

On va arrêter là pour aujourd’hui avec quelques remarques qui me sont venus pendant le développement de cette partie. On verra l’application effective à l’administration dans le prochain billet.

Premièrement je me suis posé la question de savoir s’il fallait ou pas une activation effective du plugin côté administration ou s’il fallait l’activer d’emblée. J’avoue être encore partagé à ce sujet ; à vous de me dire ce que vous en pensez.

Deuxièmement, toujours dans le soucis de conserver une (quasi) symétrie entre l’aspect publique (blog) et l’aspect administration j’ai conservé les deux positionnements haut et bas — sachant qu’il n’y a pas de système de widget pour l’administration — ; après quelques tests, je trouve que la position basse, en pied de page, est à peu près inutile. Dites-moi aussi ce que vous en pensez.

Troisièmement j’ai opté pour un retour à la présentation texte du bouton quand l’utilisateur choisit de renforcer ou d’inverser le contraste, afin d’éviter une lecture difficile des icônes (chaise roulante ou déficience visuelle) ; j’ai d’ailleurs fait de même pour la partie publique, autant conserver un fonctionnement symétrique.

Quatrièmement la bibliothèque d’Access42 est assez brut(al)e — sans être péjoratif — du côté de la CSS appliquée quand on choisit un des deux modes de contraste dans le sens où les images de fond de certains éléments (boutons ou assimilés) sont laissées telles quelles.
J’ai d’ailleurs ouvert un ticket à ce sujet et j’attends un avis éclairé sur la question avant d’aller plus loin. Vous verrez dans le prochain billet ce que j’ai du mettre en place pour pallier, voire annuler, ce comportement.

Cinquièmement et ce sera la dernière remarque pour aujourd’hui, après avoir un peu joué, surtout sur les modes de contraste, c’est assez hardcore l’aspect de l’administration de Dotclear dans ces cas-là :-)

Note

[1] On avait ensuite abandonné cette partie au profit d’une page dédiée pour le plugin.

Ajouter un commentaire

Comments can be formatted using the Markdown syntax.

Ajouter un rétrolien

URL de rétrolien : https://open-time.net/trackback/14447

Haut de page