11526 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous
J'ai des dizaines de scripts écrits depuis 20 ans qui font appel à window.write()
Depuis maintenant 7 ou 8 ans il existe Document.currentScript qui devrait me permettre de remplacer ces window.write par une manipulation du DOM plus dans la ligne avec mes pratiques plus récentes et dont je n'avais pas noté l'existence.
Il m'arrive souvent d'avoir un code du genre

let node = fonction_de_generation(...):
window.write(node.outerHTML);

Je préférerais quelque chose comme :

let node = fonction_de_generation(...):
let script = document.currentScript;
script.parentNode.insertBefore(node, script.nextSibling);


Pouvez vous me donner votre avis sur une telle syntaxe?
Oui, ça me semble tout à fait valable. Il me semble que j'utilisais cette solution à un moment donné (mais j'ai testé tellement de trucs...).

En principe, pour l'injection d'un script, je ne prévois que deux points d'entrée dans la page web, tous les deux directement accessibles via l'API DOM de javascript, sans calculs (retrouver l'élément parent, etc.)...

Lorsque je veux inclure un script dans le head (en dernière position) :
document.head.appendChild(script)

Lorsque je veux inclure un script à la fin des contenus de body :
document.body.appendChild(script)


Et maintenant une petite fonction bien pratique :
/**
 * @param {string} url : une url de script
 * @param {string} hook : le placement du script, 'head' ou 'footer', footer par défaut.
 */
const getScript = (url, hook = 'footer') => new Promise((resolve, reject) => { // @see  https://stackoverflow.com/questions/16839698#61903296
 
  const script = document.createElement('script')
  script.src = url
  script.async = 1
  script.onerror = reject
  script.onload = script.onreadystatechange = function() {
    const loadState = this.readyState
    if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
    script.onload = script.onreadystatechange = null
    resolve()
  }
  if (hook == 'head') document.head.appendChild(script)
  else if (hook == 'footer') document.body.appendChild(script)
  else console.log('Error: the choice of the html tag for the hook is not correct.')
})

Ce qui me permet ensuite de faire par exemple :
// si un élément avec la classe "accordion" est trouvé dans la page, alors injection du script éponyme :
if (document.querySelector('[class*=accordion]')) getScript('/scripts/accordion.js')

Modifié par Olivier C (19 Aug 2022 - 22:37)
Très intéressant je vais tâcher d’en tirer parti.

Dans je site osirisnet.net j’utilise abondamment les scripts pour éviter au propriétaire d’écrire des choses complexes techniquement et de se concentrer sur le contenu, avec des directives de présentation. Il y a un appel en début de page qui génère le <header> mais pas seulement et un en fin de page qui génère le <footer> et fait une révision totale de la page.
En cours de page il dispose de scripts pour générer des <figure> mais également des "clusters d’images" c’est à dire des groupements d’images que je ne parviens pas à traiter correctement par CSS.

Tout cela fait appel aux fonctions de gestion du DOM et je suis constamment en recherche de solutions pour simplifier le fonctionnement de ce qui est devenu dès le début un ensemble assez conséquent de lignes de JavaScript.
Je dois aussi tenir compte des utilisateurs qui sont des gens qui gardent longtemps leurs PC ou Mac et qui souvent ne font pas les mises à jour des navigateurs. C’est pour cela que j’attends plusieurs années avant de mettre en œuvre certaines fonctions, notamment ce site n’est pas passé en ES6.
A mon tour si tu es encore là : tu peux me donner une application concrète pour Document.currentScript ? Autrement dit : comment peut-on tirer parti d'une détection du script courant (à quoi ça sert ) ?
Je suis effectivement loin de chez moi mais internet est partout… à condition d’avoir du réseau au fond de la campagne profonde Smiley cligne
Un exemple courant dans ce site:
J’ai une grande une bibliothèque de scripts qui est définie dans le <head> de chaque page.
L’un de ces scripts est

function diapo(imageName, presentation, text) {
/* code assez long qui génère un noeud figure */
    /* code actuel : */
    window.write(figure.outerHTML);
    /* nouveau code : */
    document.currentScript.parentNode.insertBefore(figcaption, document.currentScript.nextSibling);

Ça insère le noeud dans le DOM juste après l’endroit où le script est appelé au lieu de l’y écrire sous forme de window.write.
Bien sûr le nouveau code s’écrit comme un appel de fonction pour simplifier l’écriture.
En faisant cela je peux mettre des addEventListener sur les différents éléments de la <figure> au lieu d’accumuler les ajouts de onclick, onmouse, ontouch et autres.
Je peux même faire un objet figure dont le noeud n’est qu’une des propriétés et qui possède des méthodes pour traiter les événements, et autres choses auxquelles je n’ai pas encore pensé Smiley smile

Quand le propriétaire du site écrit dans son HTML basique
<script>diapo(,,,)</script>
tout se déroule comme nous avons convenu que ce devait être de façon plus simple et plus maintenable qu’actuellement.
Modifié par PapyJP (23 Aug 2022 - 07:22)
Modérateur
Bonjour,

1) Concernant document. currentScript, il faut faire attention au fait que sa valeur change au cours du temps. Il est donc prudent d'utiliser une variable intermédiaire pour stocker la valeur de l'élément contenant le script. Par exemple :
var myScript = document.currentScript;

On évite ainsi des effets de bord (en particulier, on peut avoir des problèmes si document.currentScript est directement utilisé dans le code d'une fonction de "callback" ou dans une fonction dont l'exécution est déclenchée suite à un "event") .

2) Concernant la syntaxe de la question initiale, ça me parait pas mal (je l'utilise d'ailleurs moi aussi donc bon, évidemment, je trouve ça pas mal Smiley lol ).

3) Concernant les usage de document.currentScript, comme le fait fort bien PapyJP, on peut s'en servir quand on souhaite insérer quelque chose dans la page à l'endroit où se trouve le script. Ça me semble être son utilisation principale. Ça se comporte un peu comme une sorte d'objet qui afficherait quelque chose dans la page à l'endroit où il se trouve.

4) Avant que document.currentScript n'existe, on pouvait s'en sortir en utilisant à la place :
myScript = document.scripts[document.scripts.length-1];


Amicalement,
Judicieuse remarque je n’y avait jamais pensé !
Ça m’aurait fait gagner des années…
Un exemple de problème qui l’enquiquinement: lors de l’appel à la fonction diapo je crée un objet qui disparaît dans l’opération d’écriture. Par la suite dans certains cas je suis obligée le recréer à partir de la balise. Savoir où se trouve le résultat du script dans la page, retrouver quel est son parentNode, tout cela devrait me permettre de simplifier le code.
Modifié par PapyJP (25 Aug 2022 - 14:03)