Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Sessions intra-entreprises sur demande : contact[at]mokatech.net.
Inscrivez-vous vite !

Désactiver les liens hypertextes avec JavaScript

Lorsque, dans une page Web, l'utilisateur déclenche une action qui modifie toute la page, il est de bon ton de s'assurer qu'il ne déclenche pas une autre action avant que la page suivante ne soit chargée.

Tous les éléments qui permettent à l'utilisateur d'agir sur la page doivent donc être désactivés. Parmi ceux-ci, il y a les champs de formulaires (champs texte, boutons-poussoir, boutons radio, cases à cocher, ...), et les liens hypertextes.

Si désactiver les champs de formulaires est assez facile en JavaScript (tous possèdent un attribut disabled, qu'il suffit de mettre à true), désactiver les liens est une autre paire de manches ! Il y a bien un attribut disabled sur les ancres, mais c'est une spécificité, non standard, d'Internet Explorer. Et en plus cet attribut ne modifie que l'affichage : avec IE, un hyperlien dans l'état "disabled" est toujours actif !

Ce constat mène assez rapidement à la question suivante : comment faire ? Et d'ailleurs, est-ce faisable ?

La réponse est simple : c'est faisable, mais il va falloir écrire une fonction JavaScript ad hoc.

Cette fonction va, non seulement griser le texte du lien, en gérant les différences entre navigateurs (et profiter, sur IE, du bel effet d'ombrage que l'on obtient par un disabled=true), mais aussi se charger de désactiver le lien lui-même, pour que le clic ou le double-clic n'ait plus aucun effet sur celui-ci.

Pour ce faire, il va falloir éliminer l'attribut href de l'ancre, car c'est la présence de cet attribut qui fait de l'ancre un lien hypertexte. Mais il va falloir aussi penser à éliminer le code de l'événement onclick, si celui-ci est défini !

Enfin, il va falloir sauvegarder toutes les valeurs que l'on modifie, pour pouvoir les restaurer au cas où l'on souhaiterait, plus tard, réactiver l'ancre.

La fonction ci-dessous fait tout cela :

  1. function disableHyperLink(obj, disable) {
  2. var href, onclick, color;
  3.  
  4. if (disable) {
  5. // Protect against multiple deactivations
  6. var href_bak = element.getAttribute("href_bak");
  7. if (href_bak && href_bak != null) {
  8. return;
  9. }
  10.  
  11. // Deactivate the hyperlink and onclick event and
  12. // save them for future reactivation
  13. onclick = obj.getAttribute("onclick");
  14. href = (obj.nodeName.toLowerCase() == 'a') ? obj.getAttribute("href") : null;
  15.  
  16. if (onclick && onclick != null) {
  17. obj.setAttribute("onclick_bak", onclick);
  18. obj.setAttribute("onclick", function() { return false; });
  19. }
  20.  
  21. if (href && href != null) {
  22. obj.setAttribute("href_bak", href);
  23. obj.removeAttribute("href"); //(1)
  24.  
  25. // Gray the link text
  26. if (navigator.appName == "Microsoft Internet Explorer") {
  27. obj.disabled = true; // Non standard
  28. } else {
  29. color = obj.style.color;
  30. if (color == "") {
  31. color = "(null)";
  32. }
  33. obj.setAttribute("color_bak", color);
  34. obj.style.color = "gray";
  35. }
  36. }
  37. } else {
  38. // Reactivate the hyperlink and onclick event using
  39. // saved link address and onclick event
  40. onclick = obj.getAttribute("onclick_bak");
  41. href = obj.getAttribute("href_bak");
  42.  
  43. if (onclick && onclick != null) {
  44. obj.setAttribute("onclick", onclick);
  45. }
  46. obj.removeAttribute("onclick_bak");
  47.  
  48. if (href && href != null) {
  49. obj.setAttribute("href", href);
  50.  
  51. // Ungray the link text
  52. if (navigator.appName == "Microsoft Internet Explorer") {
  53. obj.disabled = false; // Non standard
  54. } else {
  55. color = obj.getAttribute("color_bak");
  56. if (color && color != null) {
  57. obj.style.color = ((color == "(null)") ? "" : color);
  58. }
  59. obj.removeAttribute("color_bak");
  60. }
  61. }
  62. obj.removeAttribute("href_bak");
  63. }
  64. }

Comme on peut voir, cette fonction n'est pas triviale !

Son code mérite quelques explications :

  • Cette fonction attend un élément de l'arbre DOM de la page (le lien hypertexte à modifier) et un booléen qui est à true pour désactiver le lien ou à false pour le réactiver. Elle fonctionne avec des éléments autres que des hyperliens (comme les images par exemple) sur lesquels on aurait défini un attribut onclick ; mais dans ce cas, il ne faut plus s'occuper de l'attribut href (attention, avec Internet Explorer, les images ont un attribut implicite href qui a la même valeur que l'attribut src !).
  • Cette fonction travaille en 2 phases : désactiver/réactiver le caractère hypertexte du lien, en supprimant les attributs href et onclick ; puis griser/dégriser le texte du lien, en modifiant la couleur dans le style CSS de l'ancre.
  • Cette fonction sauvegarde les 3 valeurs modifiées ou supprimées dans des attributs href_bak et onclick_bak et color_bak (que l'on peut voir avec Firebug pour Firefox, par exemple). Elle utilise ces 3 attributs de sauvegarde pour pouvoir restaurer les attributs href et onclick et style.color au moment de réactiver le lien.

Puisque c'est la présence d'un attribut href qui fait qu'une ancre (balise <a />) devient un lien hypertexte, notre fonction supprime l'attribut href lorsqu'elle désactive le lien. C'est très efficace, mais certains trouveront peut-être dommage que l'ex-lien ne puisse plus être différencié du tout du texte brut.

Dans ce cas, on peut remplacer la ligne obj.removeAttribute("href"); par celle-ci : obj.setAttribute("href", "#"); (dans le code ci-dessus, cette ligne est marquée par un //(1) pour pouvoir la retrouver plus facilement). Le lien reste alors hypertexte une fois qu'il a été désactivé, et le curseur de la souris change toujours en passant au dessus de lui, même si cliquer sur le lien reste toujours sans effet.

Une dernière petite question : comment appliquer facilement ce code à toutes les ancres d'une page ?

Facile, me direz-vous ! L'API DOM de JavaScript offre tout ce qu'il faut :

  1. var disable = true;
  2. var allAnchors = document.getElementsByTagName("a");
  3. for (var i = 0; i < allAnchors.length; i++) {
  4. disableHyperLink(allAnchors[i], disable);
  5. }

Commentaires

1. Le mardi 10 février 2009, 18:26 par AA

Durant mon expérience professionnelle, j'ai rencontré cette problématique également.
Dans deux des applications web, nous avions une barre de boutons (images avec un lien hypertext), nous changions donc le contenu de cette barre bar pour enlever les boutons. Néanmoins ça ne désactivait pas les actions javascripts des autres champs, mais à l'époque Ajax n'était pas trop présent.
Dans un autre projet, lorsqu'une action modifiait la page, nous affichions un calque semi-transparent au dessus de tous les éléments (division avec un très grand z-index et un alpha) ce qui empêchait l'accès aux éléments de la page. Mais cela ne fonctionnait pas avec les listes déroulantes sous IE qui ont sont toujours affichées devant les calques.

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.