11521 sujets

JavaScript, DOM et API Web HTML5

Bonjour,

Dans mon passage de jQuery à javascript vanilla je rencontre plusieurs difficultés pour progresser. Bien que j'arrive à faire des trucs un peu complexes, comme cet accordéon, je trouve que ma manipulation du DOM reste aléatoire, avec beaucoup de tamponnements. Quelqu'un sur le forum (Ostara) m'avait beaucoup impressionné en réécrivant/refactorisant mon code de manière jusque-boutiste, mais c'était tellement extrême pour moi qu'aujourd'hui encore j'ai du mal à en tirer parti.

Je voudrais donc partir d'un exemple plus simple, un cas d'école pour moi, un exercice pour lequel j'ai trouvé une solution, mais que je cherche à améliorer.

Donc j'ai ceci :
<div class="add-dropcap">
  <p>Lorem ipsum dolor sit amet, consetetur <ins>sadipscing elitr</ins> ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
</div>


Et je dois ajouter un un span wrappant le premier caractère pour pouvoir le styler comme une lettrine :
<div class="add-dropcap">
  <p><span>L</span class="dropcap">orem ipsum dolor sit amet, consetetur <ins>sadipscing elitr</ins> ut labore et dolore magn"eea aliquyam erat, sed diam voluptua.</p>
</div>


Je suis arrivé à ce résultat en produisant ceci :
// @note Les propriétés applicables au sélecteur ::first-letter varient d'un navigateur à l'autre ; la solution retenue est un wrapper en javascript 'span.dropcap' sur la première lettre.

const addDropCap = (() => {
  const paragraphs = document.querySelectorAll('.add-dropcap p:first-child')
  for (const paragraph of paragraphs) {
    let string = paragraph.innerHTML.substring(1)
    let dropcap = paragraph.textContent.substring(0, 1)
    dropcap = `<span class="dropcap">${dropcap}</span>`
    const content = `<p>${dropcap}${string}</p>`
    paragraph.insertAdjacentHTML('beforeBegin', content)
    paragraph.remove()
  }
})()

Le CodePen

1. Premier problème : j'utilise des boucles for() dans mes codes, elles fonctionnent très bien mais j'aimerais pouvoir m'en départir pour alléger l'ensemble, comment procéder ? Comment notamment utiliser .map() dans ce cas de figure ?

2. Je trouve mon code lourd, en effet je crée un nouveau paragraphe, supprime l'ancien... auriez-vous une solution pour faire le tout en une seule passe ?

Toute suggestion d'amélioration sera la bienvenue.
Modifié par Olivier C (25 Nov 2020 - 17:54)
Modérateur
Bonjour,

Par exemple ça ? Ou bien c'est encore trop long ? Smiley biggrin

document.querySelectorAll('.add-dropcap p:first-child').forEach(e =>
    e.innerHTML=e.innerHTML.replace(/^(.)/,"<span class='dropcap'>$1</span>"));


Amicalement,
Meilleure solution
Et bien je vois que j'ai bien fais de poser la question ! J'ai de quoi méditer. Merci à toi.
A titre de comparaison, pour compléter l'info sur ce topic (et pour aider les gens comme moi qui ont du mal à se dépatouiller de jQuery) voici le code d'origine en jQuery avec replace() justement (là je donne le bâton pour me faire battre) :
jQuery.fn.dropcap = function() {
	$( '[class*="adddropcap"] p:first-child' ).each( function() {
		var string = $( this ),
			newString = string.html().replace( /(<([^>]+)>|[A-Z0-9«»"]|&amp;)/, '<span class="dropcap">$1</span>' ); // Ajout d'un span + class sur les caractères sélectionnés, filtrage des balises html
		string.html( newString );
	} );
};

jQuery( '.dropcap' ).dropcap();


On vois tout de suite mieux la similitude entre ce code et celui proposé par parsimonhi
Modérateur
Salut Olivier,
Si ce n’est que pour une lettrine, pour ne pas simplement utiliser :first-letter de css ? Smiley smile
Bonsoir Yordi,

Ce n'est pas vraiment le sujet car je me sers ici de ce script comme d'un cas d'école pour m’entraîner. Mais ceci étant dit la question est intéressante, j'en avais laissé un mot dans le Pen : "Les propriétés applicables au pseudo-élément ::first-letter varient d'un navigateur à l'autre...". MDN en parle dans son descriptif de ::first-letter au chapitre "Propriétés utilisables".

Pour mon code en full CSS, sur Chrome pas de problème, c'est sur Firefox que cela se voit. J'avais tout de même laissé un fall back si pas de JS :
.dropcap,
.no-js .add-dropcap > p:first-child::first-letter {
  float: left;
  margin-right: 0.2em;
  padding: 0.2em;
  line-height: 1;
  font-size: 3em;
  font-weight: bold;
  font-family: _fontList2;
  color: _color2;
  background-color: rgba(255,255,255,0.05);
}

Modifié par Olivier C (26 Nov 2020 - 09:09)
Modérateur
Ok, sorry j'avais lu ton message, regarder visuellement ce que ça donnait dans codepen mais pas lu le code.
Du coup je comprend l'idée "du cas d'école".
Par contre, tu obtiens quoi avec Firefox ? J'ai quelque de vraiment similaire chez moi…
Similaire sans le js ? oui mais à quelque chose près seulement : on observe un décalage de la hauteur du span et de la position je crois. Je n'ai pas creusé le sujet et préférais me concentrer sur un truc qui fonctionne de manière sûre.

Si tu veux en savoir plus sur le sujet il y a quelques articles qui trainent sur le net, par exemple cet article sur CSS-Tricks.