Un bouton de copie pour Highlight.js (Français (French))

Un bouton de copie pour Highlight.js

Comments

NOTE: Apart from English (and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.

Saturday, 28 September 2024

//

5 minute read

Présentation

Dans ce site, j'utilise Hightlight.js pour rendre le côté client des extraits de code. J'aime cela car il maintient mon code côté serveur propre et simple. Cependant, je voulais ajouter un bouton de copie à chaque extrait de code afin que les utilisateurs puissent facilement copier le code dans leur presse-papiers. C'est une tâche simple, mais j'ai pensé que je la documenterais ici pour tous ceux qui pourraient vouloir faire de même.

Oh et tout cela m'attend en ajoutant la fonctionnalité de bulletin d'information pour réellement apparaître sur le site. Dès que j'aurai l'énergie de le faire, j'ajouterai ça.

Le paramètre est que nous avons un bouton de copie comme ceci sur le site: Copier le bouton

REMARQUE: Tout crédit pour cet article va à Faraz Patankar qui est l'article que j'avais l'habitude de créer celui-ci. Je voulais simplement documenter les modifications que je lui ai apportées ici pour ma propre référence et pour partager avec d'autres.

Les options

Il y a un certain nombre de façons de le faire, par exemple il y a un plugin bouton copie pour Higlight.js mais j'ai décidé que je voulais plus de contrôle sur le bouton et le style. Alors je suis tombé sur cet article pour ajouter un bouton de copie.

Les problèmes

Alors que cet article est une grande approche, il a eu quelques questions qui ont empêché qu'il soit parfait pour moi:

  1. Il utilise une police que je n'utilise pas sur mon site (mais ensuite manuellement a aussi le SVG, pas sûr pourquoi).
  // Lucide copy icon
    copyButton.innerHTML = `<svg class="h-4 w-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-copy"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>`;

Alors que cela fonctionne, j'utilise déjà BoxIcons sur ce site qui a un l'icône de copie là-dedans déjà.

  1. Il utilise une bibliothèque de toasts que je n'ai pas sur ce site.
  // Notify user that the content has been copied
      toast.success("Copied to clipboard", {
        description: "The code block content has been copied to the clipboard.",
      });
  1. Il fait tomber le flux de y sur le bloc de code et met l'icône en bas que je ne voulais pas. Donc la mienne est en haut à droite.

Mes adaptations

La fonction principale

Ce plugin s'accroche à la after:highlightElement event et ajoute un bouton au bloc de code.

Donc d'abord j'ai copié le code de Faraz et ensuite j'ai fait les changements suivants:

  1. Au lieu de l'ajouter à la fin du bloc de code, je le prépends au début.
  2. Au lieu de SVG, j'ai utilisé la version BoxIcons en ajoutant simplement ces classes au bouton inséré et en réglant le textize pour text-xl.
  3. J'ai retiré la notification de toast et l'ai remplacée par un simple showToast fonction que j'ai sur mon site (voir plus loin)
  4. J'ai ajouté un aria-label et title au bouton pour l'accessibilité (et pour donner un bel effet de vol stationnaire).
hljs.addPlugin({
    "after:highlightElement": ({ el, text }) => {
        const wrapper = el.parentElement;
        if (wrapper == null) {
            return;
        }

        /**
         * Make the parent relative so we can absolutely
         * position the copy button
         */
        wrapper.classList.add("relative");
        const copyButton = document.createElement("button");
        copyButton.classList.add(
            "absolute",
            "top-2",
            "right-1",
            "p-2",
            "text-gray-500",
            "hover:text-gray-700",
            "bx",
            "bx-copy",
            "text-xl",
            "cursor-pointer"
        );
        copyButton.setAttribute("aria-label", "Copy code to clipboard");
        copyButton.setAttribute("title", "Copy code to clipboard");

        copyButton.onclick = () => {
            navigator.clipboard.writeText(text);

            // Notify user that the content has been copied
            showToast("The code block content has been copied to the clipboard.", 3000, "success");

        };
        // Append the copy button to the wrapper
        wrapper.prepend(copyButton);
    },
});

showToast Fonction

Cela repose sur un rasoir partiel que j'ai ajouté à mon projet. Cette partie utilise les Composante Toast DaisyUI pour montrer un message à l'utilisateur. J'aime cette approche car elle maintient le Javascript propre et simple et me permet de styler le message toast de la même manière que le reste du site.

<div id="toast" class="toast toast-bottom fixed z-50 hidden overflow-y-hidden">
    <div id="toast-message" class="alert">
        <div>
            <span id="toast-text">Notification message</span>
        </div>
    </div>
    <p class="hidden right-1 bx-copy  cursor-pointer alert-success alert-warning alert-error alert-info"></p>
</div>

Vous remarquerez que cela a aussi un étrange caché p tag en bas, c'est juste pour Tailwind d'analyser ces classes quand il construit le CSS du site.

La fonction Javascript est simple, il suffit de montrer le message toast pour un certain temps et puis le cache à nouveau.

window.showToast = function(message, duration = 3000, type = 'success') {
    const toast = document.getElementById('toast');
    const toastText = document.getElementById('toast-text');
    const toastMessage = document.getElementById('toast-message');

    // Set message and type
    toastText.innerText = message;
    toastMessage.className = `alert alert-${type}`; // Change alert type (success, warning, error)

    // Show the toast
    toast.classList.remove('hidden');

    // Hide the toast after specified duration
    setTimeout(() => {
        toast.classList.add('hidden');
    }, duration);
}

Nous pouvons ensuite appeler ceci en utilisant le showToast fonction dans le copyButton.onclick l'événement.

showToast("The code block content has been copied to the clipboard.", 3000, "success");

J'ai ajouté cette partie en haut de mon _Layout.cshtml fichier donc il est disponible sur chaque page.

<partial name="_Toast"  />``

Maintenant, lorsque nous montrons les messages de blog, les blocs de code ont: Copier le bouton

En conclusion

Donc c'est tout, un simple changement au code de Faraz pour que ça marche pour moi. J'espère que ça aidera quelqu'un d'autre.

logo

©2024 Scott Galloway