Comme je disais hier j’ai ajouté un bouton géré par le plugin hljs pour permettre de copier le code contenu dans la zone syntaxiquement colorisée — ou colorié, je sais pas trop quel adjectif utiliser.
Ça se présente sous la forme d’un cadre, affiché en bas à droite, en blanc sur fond violet, comme sur l’exemple ci-dessous :
function findSequence(goal) {
function find(start, history) {
if (start == goal)
return history;
else if (start > goal)
return null;
else
return find(start + 5, "(" + history + " + 5)") ||
find(start * 3, "(" + history + " * 3)");
}
return find(1, "1");
}
Ce bouton est entièrement produit avec quelques lignes de CSS :
.hljs::after {
content: 'copy';
position: absolute;
right: 0;
bottom: 0;
font-size: smaller;
padding: 0.1em 0.6em 0.1em 0.6em;
color: #fff;
background-color: blueviolet;
}
Ensuite c’est du côté de javascript que tout le boulot est fait, en détectant le click sur la zone complète (il n’est pas possible de détecter l’événement click sur le :after
d’un élément) et ensuite on détermine, en fonction de la position de la souris au moment du clic si ça a été fait dans la zone couverte par le bouton :
elt.addEventListener('click', (e) => {
// First we get the pseudo-elements style
const target = e.currentTarget || e.target;
const after = getComputedStyle(target, ':after');
if (!after) {
return;
}
// Then we parse out the dimensions
const atop = Number(after.getPropertyValue('top').slice(0, -2));
const aheight = Number(after.getPropertyValue('height').slice(0, -2));
const aleft = Number(after.getPropertyValue('left').slice(0, -2));
const awidth = Number(after.getPropertyValue('width').slice(0, -2));
// And get the mouse position
const ex = e.layerX;
const ey = e.layerY;
// Finally we do a bounds check (Is the mouse inside of the after element)
if (!(ex > aleft && ex < aleft + awidth && ey > atop && ey < atop + aheight)) {
return;
}
// Ici on commence à gérer la copie dans le presse-papier …
Ça fonctionne très bien sauf que :
- Il n’y a aucun feedback visuel au moment de la copie qui indique que l’opération a été déclenchée et correctement finie.
- Ce n’est pas un bouton réel, au sens HTLM du terme, ce qui veut dire que d’un point de vue accessibilité, j’ai tout faux ! Pas de prise de focus, etc…
- Si javascript est désactivé (quelle que soit la raison), le pseudo-bouton est présent mais ne sert à rien.
Il faudrait donc que je bascule sur la création d’un bouton réel (<button class="hljs-copy-button">copier</button>
) ; ça je sais faire sauf que je me heurte à un petit problème temporel : si je crée le bouton (avec la gestion de l’événement idoine) au chargement de la page, celui-ci est supprimé quand le code est remplacé par son équivalent syntaxiquement coloré par la bibliothèque highlight.js.
Il faudrait dont que j’attende, en quelque sorte, que la bibliothèque ait fini son job, y compris quand ça passe par des web workers (qui est la configuration par défaut et qui permet un traitement simultané de toutes les zones de code de la page), et là je sèche un peu.
J’ai pensé à ajouter une tempo de deux secondes avant de créer les boutons, sauf que c’est très aléatoire et pas du tout élégant comme solution !
Forcément, après avoir écrit ce billet hier je me suis replongé dans le code et ai découvert que finalement j’avais tout ce qu’il faut sous la main pour parvenir à mes fins !
Dans les carnets de contre que j’ai pu lire, durant ma formation de scribe, le furvent a toujours occupé une place à part. Il reste la figure active et imprévisible de la mort. Chaque horde en a rencontré - parfois jusqu’à sept ou huit, et chaque scribe a tenté, dans la mesure de son savoir et de ses moyens, d’en extraire des leçons qui puissent sauver les hordes futures. Ces leçons sont étranges, folles parfois, plus souvent profondes et saines. Elles sont toutes émouvantes par ce fil, par ce don qu’elles tendent, du bout des doigts, vers l’avenir. Comme si, même détruire, même disloquée, une horde gardait encore au fond d’elle-même, enkysté dans sa foi, l’espoir qu’une seule d’entre elles, plus tard et plus loin, peut-être des siècles et des siècles en amont dans le futur, atteindra enfin, grâce aux exploits cumulés des autres, l’Extrême-Amont - et qu’ainsi elles seront justifiées, toutes quoi qu’elles fissent, et pour toujours.
Alain , La Horde du Contrevent
Comme quoi, poser des mots sur papier, même électronique, aide à réfléchir posément au problème !
1 De Biou -
Tu as déjà trouvé une solution, donc ce commentaire est probablement inapproprié, j’en suis désolé par avance. Si tu veux gérer des événements dynamiquement sur des éléments qui peuvent être rajoutés ou supprimés dans le DOM, tu peux utiliser la délégation d’événements en JavaScript (le pattern qui utilise le bubbling des événements) comme par exemple ici : https://dmitripavlutin.com/javascript-event-delegation/
2 De Franck -
Oh mais oui, j’aurais pu y penser, merci Biou !