Étiquette : Web

Vincent Lecomte
[JS] Retour sur le rendu d’une page avec PDF.js

[JS] Retour sur le rendu d’une page avec PDF.js

Il y a déjà un moment nous abordions le fait de pouvoir afficher une page de PDF sous forme d’image grâce à la librairie PDF.js. Les différentes mises à jour de celle-ci ont conduit à ce que certains appels soient désormais dépréciés, bien que toujours fonctionnels.

Voici le nouveau code que nous pouvons utiliser :

pdfjsLib.getDocument(
{
	data : ao_pdfData
})
.promise.then(function(dPdf)
{
	dPdf.getPage(ai_num).then(function(page)
	{
		var canvas = document.createElement('canvas');
		canvas.id = as_id + '-page-' + ai_num;
		canvas.className = 'f-canvas';

		var vContext = canvas.getContext('2d');
		var vViewport = page.getViewport({
			scale: af_scale2,
			rotation: 0
		});
		
		canvas.height = vViewport.height;
		canvas.width = vViewport.width;

		var renderContext = {
			canvasContext: vContext,
			viewport: vViewport
		};
		
		page.cleanupAfterRender = true;
		
		var renderTask = page.render(
			renderContext
		);
		
		renderTask.promise.then(function()
		{
			if (canvas.msToBlob) 
			{
				$('#' + img_id).attr("src", 
					canvas.toDataURL(
						"image/jpeg", 0.85
					)
				);
			}
			else
			{
				canvas.toBlob(function(blob) 
				{
					let img = new Image();
					img.onload = function() { 
						URL.revokeObjectURL(img.src); 
					}; 
					img.src = URL.createObjectURL(blob);
					$('#' + img_id).attr("src", 
						img.src
					);
				}, "image/jpg", 0.85);
			}
		})
	});
});

Quelques détails concernant ce code :

  • On charge toujours le document en passant en paramètre les données qui auront été décodées à l’aide de la méthode atob(). On aura passé le contenu du PDF sous forme de chaine de caractères en Base64.
  • Petite différence : on appelle la méthode then() sur un objet “promise”. Même modification pour la tâche de rendu (variable “renderTask”).
  • La variable “viewport” est toujours initialisée avec getViewport() mais on passe un objet contenant les paramètres.
    • scale : l’échelle permettant de définir le zoom (ex: 1,5)
    • rotation : indique la rotation du document (0 = position initiale)
  • On définit toujours la hauteur et la largeur du canevas avec les valeurs du viewport.
  • On ajoute une petite option qui permet d’indiquer que la page doit être libérée et nettoyée après son rendu.
  • Petite nouveauté : l’utilisation de la méthode toBlob() dans les navigateurs qui supportent cela. Notez que si la méthode “msToBlob” existe alors on va plutôt appeler toDataUrl() pour la compatibilité avec IE.
    • On peut également déterminer le type de l’image.
    • On peut aussi indiquer la compression (ex : 0.85, 1 étant la qualité la plus élevée).

Grâce à ces modifications vous n’obtiendrez plus de message dans la console indiquant du code deprecated.

N’hésitez pas à partager votre expérience ou à suggérer des améliorations pour ce code !

[JS] Prism, une alternative à SyntaxHighlighter

[JS] Prism, une alternative à SyntaxHighlighter

En guise d’alternative au très bon SyntaxHighlighter développé par Alex Gorbatchev (voir le site ici) mais qui n’est malheureusement plus mis à jour, on peut utiliser Prism.js.

Il offre la coloration syntaxique pour afficher du code de manière à ce qu’il soit lisible par les utilisateurs. Il se veut intuitif et extensible car il est possible d’ajouter assez facilement des langages à ceux déjà pris en charge. On peut même basculer entre différents thèmes. La librairie est utilisée par de nombreux sites tels que React ou même Drupal.

Pour l’utiliser sur Blogger comme c’est mon cas, il faut importer les scripts et styles de base. Et pour cela il faut modifier le thème du blog. Depuis le tableau de bord de votre blog choisissez Thème puis cliquez sur Modifier le code HTML.

Juste avant l’élément fermant head du thème, il faut inclure les feuilles de style.

<link href='https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism.css' rel='stylesheet'/>
<link href='https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.css' rel='stylesheet'/>

De même qu’il faut inclure le script et l’autoloader avant la fermeture de l’élément body. On y ajoute aussi les différents plugins que l’on veut utiliser. Les éléments obligatoires sont prism-core et prism-autoloader.

<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-core.min.js'/>
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/autoloader/prism-autoloader.min.js'/>
<script src='https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.min.js'/>

Ensuite on peut commencer à utiliser les blocs de code. Il faut utiliser les balises pre et code. La seconde prendra une classe qui sera le langage du code que l’on veut formater. La liste complète est disponible sur le site officiel. La classe peut être language-* ou lang-*, l’astérisque étant remplacée par le bon code pioché dans la liste.

<pre>
<code class="lang-html">
<!-- Code qu'on veut formater -->
</code>
</pre>

Il faut faire attention car il faut échapper les caractères du code à formater, sinon il sera évidemment interprété (très important donc si on veut afficher du HTML au lecteur).

Pour éviter de le faire à la main utilisez plutôt l’outil en ligne Quick Escape Tool.Petit truc supplémentaire avant de nous quitter : afin d’utiliser le plugin line-numbers (destiné à afficher les numéros de ligne) que nous avons importé dans le second exemple ci-dessus, il vous suffira d’ajouter la classe “line-numbers” à l’élément ouvrant pre. N’hésitez pas à consulter le site officiel : vous y découvrirez de nombreux plugins ainsi que des tutoriels.

Bon développement !

Prismjs.com

[Java] Gestion des erreurs à l’aide d’une servlet

[Java] Gestion des erreurs à l’aide d’une servlet

Dans votre application web, il est possible de réaliser une gestion d’exceptions – notamment pour intercepter ServletException – en passant par une servlet. Par défaut, les erreurs telles que le code HTTP 500 sont gérées par le serveur et renvoient vers une page par défaut. L’idée est donc de changer ce comportement en renvoyant par exemple une information en JSON ou en redirigeant vers une JSP.

On va donc créer une classe qui hérite de HttpServlet. Celle-ci devra implémenter des fonctions pour gérer les différentes méthodes HTTP (exemple : PUT, GET, POST…).

public class MaServletHttp extends HttpServlet 
{
    public void doGet(HttpServletRequest request, 
        HttpServletResponse response) throws IOException 
    {
        // On gère l'erreur...
    }
}

Comme on peut le constater on a donc créé une fonction qui sera exécutée lorsque la méthode GET est utilisée. Typiquement lorsqu’on appelle une URL et qu’on spécifie un ensemble de paramètres dans celle-ci. Il faudra donc ajouter les autres fonctions comme doPost() – généralement appelée lors d’un envoi de formulaire – ou doPut().On remarque aussi l’annotation @WebServlet qui permet de définir tout un ensemble d’informations utiles, notamment l’ “URL pattern”. On peut soit spécifier cette valeur directement comme dans l’exemple ci-dessus, soit en spécifiant les attributs de la manière suivante.

@WebServlet(
        name = "maBelleServlet",
        description = "Gestion d'exceptions",
        urlPatterns = "/maServletHttp"
)
public class MaServletHttp extends HttpServlet 
{
    // Code de la servlet...
}

Certains attributs de la servlet ne sont utiles que pour les outils utilisés lors du développement (par exemple, description ou encore smallIcon). Ces attributs sont décrits dans la documentation de JavaEE 7.Il faut ensuite modifier le fichier web.xml pour spécifier dans quels cas la servlet doit être appelée pour gérer les exceptions ou les différents code d’erreur. Dans l’exemple ci-dessous on va faire en sorte que la servlet soit appelée en cas d’erreur HTTP 500.

<web-app ... >
    <error-page> 
        <error-code>500</error-code> 
        <location>/maServletHttp</location> 
    </error-page>
</web-app>

On a donc ajouté un élément “error-page” dans le fichier descriptif de l’application. Pour cet élément on a spécifié le code d’erreur grâce à l’élément “error-code” et l’emplacement de la servlet (qui correspond au URL pattern défini précédemment dans l’annotation de la classe Java) représenté par l’élément “location“.

A la place de l’élément “error-code” on peut aussi spécifier “exception-type” et indiquer les erreurs que la servlet devra intercepter. On y spécifie alors le canonical name de la classe d’exception visée (ex : java.lang.NullPointerException).

Une fois le fichier de configuration XML modifié, on peut s’attaquer au code de la servlet. Aussi bien lorsqu’on redirige vers une JSP qu’une servlet, des attributs contenant des informations à propos de l’erreur qui se produit, sont définis au niveau de la requête et peuvent donc être rapatriés dans le code.

@WebServlet("/maServletHttp")
public class MaServletHttp extends HttpServlet 
{
    public void doGet(HttpServletRequest request, 
        HttpServletResponse response) throws IOException 
    {
        Integer li_st = (Integer) request.getAttribute(
                "javax.servlet.error.status_code"
        );

        Throwable lo_e = (Throwable) request.getAttribute(
                "javax.servlet.error.exception"
        );

        String ls_svlt = (String) request.getAttribute(
                "javax.servlet.error.servlet_name"
        );
        
        // Envoi de la réponse après.
        // Voir ci-dessous.
    }
}

Voici le tableau des attributs disponibles (source : tutorialspoint).

L’attribut qui contient le nom de la servlet est intéressant car il s’agit de la source, là où l’erreur s’est produite. Cela signifie qu’en fonction du nom on peut imaginer un traitement différent en retour.L’exemple ci-dessous renvoie simplement du JSON au client après une erreur dans un Web Service.

@WebServlet("/maServletHttp")
public class MaServletHttp extends HttpServlet 
{
    public void doGet(HttpServletRequest request, 
        HttpServletResponse response) throws IOException 
    {
        // Récupération des attributs avant.
        // Voir ci-dessus.
        if (ls_svlt.equals("webserviceServlet"))
        {
            response.setContentType("application/json");
            response.getWriter().print(
                "{ key1: 'val1', key2: 'val2' }"
            );

            response.getWriter().flush();
        }
    }
}

On peut également modifier le code de retour (par exemple, si le code était 500, on peut le redéfinir au niveau de l’objet HttpServletResponse).

Sources

Baeldung
CodeJava.net
LogicBig
Oracle
Tutorialspoint

[JS] Afficher un PDF en image avec pdf.js

[JS] Afficher un PDF en image avec pdf.js

Il existe plusieurs méthodes en Java pour transformer un PDF (ou une partie seulement) en image côté serveur, afin de renvoyer le résultat au client, pour qu’il ne lui reste plus qu’à l’afficher. La première qui vient à l’esprit est Apache PDFBox. D’autres comme IcePDF ou JPedal font bien le job aussi, mais sont souvent payantes. De plus, le traitement peut évidemment vite devenir lourd pour le serveur si de nombreuses requêtes sont effectuées par plusieurs utilisateurs.

On peut imaginer laisser le client faire le boulot, en utilisant la librairie pdf.js, qui est sous licence Apache. Elle permet de visualiser des documents PDF dans une page web mais aussi de les transformer en image ce qui nous intéresse ici.

L’idée de l’exemple qui suit est de transformer une page donnée en image. Après ajout du script principal dans l’élément head, on va créer une fonction qui recevra plusieurs paramètres tels que les données du fichier PDF (sous forme de chaine encodée en Base64), le numéro de page à transformer, un ID pour la création du canvas, une valeur pour l’échelle du rendu, et l’identifiant de l’élément img qui recevra le résultat.

PDFJS.getDocument({data : atob(ao_pdfData)})
    .then(function(ao_pdf) 
{
 ao_pdf.getPage(ai_num).then(function(ao_page) 
 {
  var lo_canvas = document.createElement('canvas');
  lo_canvas.id = as_idd + '-page-' + ai_num;
  lo_canvas.className = 'f-canvas';

  var lo_context = lo_canvas.getContext('2d');
  var lo_viewport = ao_page.getViewport(af_scale2);
  lo_canvas.height = lo_viewport.height;
  lo_canvas.width = lo_viewport.width;
  
  var lo_renderContext = {
   canvasContext: lo_context,
   viewport: lo_viewport
  };

  ao_page.render(lo_renderContext).then(function()
  {
   $('#' + as_imageId)
     .attr("src", lo_canvas.toDataURL());
  });
 });
});

La fonction PDFJS.getDocument() reçoit en paramètre les données, décodées par la fonction JavaScript atob().

Une fois le document chargé, on va demander à récupérer la page dont le numéro est passé en paramètre. Une fois que cela est fait on exécute une fonction pour traiter les données de cette fameuse page. On crée un élément canvas temporaire, qu’on pourra stocker – ou pas – dans la page. On récupère aussi le contexte de dessin de ce canvas.

On récupère le viewport en indiquant l’échelle (ex : 1.5f). On définit ensuite la hauteur et la largeur du canvas avec les valeurs du viewport.

On crée ensuite un objet qui contiendra le contexte de dessin et le viewport. Ceux-ci seront passés à la fonction render() qui est une fonction de l’objet page. Lorsque le rendu est terminé, on peut récupérer la source de l’image depuis le canvas, grâce à la fonction toDataURL() de ce dernier.

[JS] JQuery – Mémo #2 – Requête AJAX

[JS] JQuery – Mémo #2 – Requête AJAX

JQuery vous permet d’effectuer facilement des requêtes AJAX. Par exemple:

$.ajax({
 type : "POST",
 url : "URL_A_APPELER",
 data : {
  param1: val_param1,
  param2: val_param2,
  // ...
 }
})
.done(function(data)
{
})
.fail(function(jqXHR, responseHtml, url)
{
});

Dans l’exemple on spécifie le type de requête, l’URL appelée, et les données envoyées. La fonction done() est exécutée lorsque la réponse est positive. L’objet “data” est alors un objet qui peut contenir du HTML notamment. La fonction fail() est exécutée quand la réponse du serveur est une erreur ou quand l’appel a échoué.

Dans JQuery 3, il ne faut plus utiliser les méthodes callback suivantes : error(), success() et complete().

La documentation officielle décrit les paramètres supplémentaires et l’utilisation des méthodes callback. Par exemple, on peut passer un objet dans “data” à la place des différents paramètres. Au niveau des options, on peut notamment spécifier async: false, pour forcer l’attente de la réponse. Les possibilités sont nombreuses.

[JS] Des infobulles avec Tooltipster 4

[JS] Des infobulles avec Tooltipster 4

Tooltipster est un script permettant d’afficher des infobulles modernes, bien plus “user-friendly” que ce que proposent les navigateurs. Il nécessite JQuery pour fonctionner (attention que sous IE9 avec JQuery version 1.8, cela ne fonctionnera tout simplement pas!)

Pour le télécharger, rendez-vous sur le site officiel (ici : http://iamceege.github.io/tooltipster/) et cliquez sur le bouton “Download“. Le sous-répertoire “dist” contient deux dossiers essentiels :

  • js : contient le script (format normal et format minified)
  • css : contient les feuilles de style (format normal et format minified) ainsi que les thèmes par défaut.

Il faudra ensuite l’inclure à la page :

<link rel="stylesheet" type="text/css" href="/tooltipster/css/tooltipster.bundle.css" /> 
<script type="text/javascript" src="/tooltipster/js/tooltipster.bundle.js"></script> 
<script type="text/javascript" src="https://code.jquery.com/jquery-x.xx.x.min.js"></script>

Après chargement du script, dans notre page nous allons placer des attributs “title” sur les éléments pour lesquels on veut avoir une infobulle. On va aussi leur assigner une classe, “tooltip“, mais on peut choisir un autre nom.

<img id="imgTest" src="test.jpg" class="tooltip" title="Le texte du tooltip" />

Lors du chargement de la page on doit initialiser les bulles.

<script>
     $(document).ready(function() {
          $('.tooltip').tooltipster();
     });
</script>

Par défaut la fonction tooltipster() ne reçoit aucun paramètre. Elle utilisera donc les options par défaut définies dans le fichier .js du script.

On peut notamment définir :

  • contentAsHTML : par défaut à false. Il est conseillé de stocker un objet JQuery dans le contenu. Sinon on peut passer la valeur à true et passer du texte au format HTML en appelant la méthode tooltipster().
  • delay : en millisecondes, délai après ouverture. On peut spécifier un
    tableau (par ex : [100, 2000]) ce qui correspondra alors au temps avant
    ouverture et au délai avant fermeture automatique).
  • position : attention aussi à la position ; seules 4 sont supportées (top, left, right et bottom). Dans les anciennes versions il existait plusieurs combinaisons mais cela a été supprimé.
  • theme : on peut définir un ou plusieurs thèmes à charger. Il faudra penser à charger les CSS quand cela s’applique.

Exemple de feuille de style dans le dossier “csspluginssideTipthemes” :

On peut aussi appeler la méthode tooltipster() en lui passant des options. Utile quand l’élément pour lequel on veut spécifier du texte, n’en a pas à la base.

$(SELECTOR).tooltipster({ 
	content: 'texte à placer', 
	maxWidth: 200 
});

Parmi les options que l’on peut spécifier il y a également divers événements, ce qui permet par exemple d’afficher un contenu récupéré grâce à une requête AJAX.

$(SELECTOR).tooltipster({ 
	delay: [200, 2000], 
	content: 'Chargement...', 
	functionBefore: function(instance, helper) 
	{ 
		if ($(helper.origin).data('ajax') !== 'loaded') 
		{
			$.ajax({ 
				type: 'POST', 
				url: 'action.php?param=', 
				success: function(data) 
				{
					instance.content(data); 
					$(helper.origin).data('ajax', 'loaded'); 
				}
			}); 
		} 
	} 
});

Ce qu’on a fait :

  • Appel de la fonction tooltipster().
  • On passe les différents arguments ; tout d’abord le délai (delay).
  • Ensuite on spécifie le contenu par défaut à afficher pendant l’appel AJAX (content).
  • Enfin on ajoute “functionBefore” : elle reçoit deux paramètres (instance et helper).
    • helper.origin : élément HTML sur lequel on définit le tooltip.
    • instance : objet Tooltipster qui appelle la fonction de callback.
    • La condition permet de savoir si l’élément a déjà été chargé ou pas (car on définit une donnée nommée “ajax” avec la valeur “loaded” une fois l’appel effectué).

Si un tooltip est déjà chargé, on peut effectuer diverses manipulations comme changer son contenu ou même le désactiver. On appelle la fonction tooltipster() avec comme premier argument, un nom de méthode (voir documentation). Les arguments suivants dépendent de la méthode appelée.

Exemple :

$(SELECTOR).tooltipster('content', 'nouveau contenu');

A noter que toute la documentation est disponible à l’adresse mentionnée au début de cet article.

[JS] Personnaliser la liste de styles dans tinyMCE

[JS] Personnaliser la liste de styles dans tinyMCE

Dans l’éditeur tinyMCE, lorsqu’on choisit de dérouler le menu de sélection du format, on dispose d’éléments par défaut comme les en-têtes (h1 à h6), l’alignement ou bien même la mise en forme classique comme le “gras”, “souligné” ou “italique”.

Ce menu peut être personnalisé de différentes manières. La méthode la plus simple reste de redéfinir les styles dans la méthode d’initialisation de l’éditeur. Dans notre cas cela écrasera les valeurs par défaut pour n’afficher que ce qu’on désire.

tinymce.init(
{
 // ...

 toolbar : [ "bold italic underline | styleselect" ]
 style_formats: [
  {title: 'Blocks', items: [
     {title: 'Paragraph', block: 'p'}
  ]},  
  {title: 'Headers', items: [
     {title: 'Header 1', block: 'h1'},
     {title: 'Header 2', block: 'h2'},
     {title: 'Header 3', block: 'h3'},
     {title: 'Header 4', block: 'h4'},
     {title: 'Header 5', block: 'h5'},
     {title: 'Header 6', block: 'h6'}
  ]},     
 ],
 
 // ...
});

Le fait de modifier le contenu de “style_formats” affecte la liste déroulante qui s’affiche quand on ajoute l’option “styleselect” dans la barre d’outils (cfr. paramètre “toolbar“). Vous constaterez également qu’il est possible de créer plusieurs niveaux (ce qui permet visuellement d’obtenir des sous-menus).

Le paramètre “title” est évidemment essentiel. On y met le texte qui sera affiché à l’utilisateur. Il sera automatiquement traduit en fonction de la langue choisie dans la configuration. Les fichiers de langue sont stockés dans un sous-dossier du répertoire de tinyMCE.

Les autres paramètres qu’on peut définir sont :

  • inline : indique le nom de balise inline qui sera utilisé comme conteneur.
  • block : indique le type de balise block qui sera utilisé comme conteneur.
  • selector : indique à quel élément cela peut s’appliquer.
  • classes : indique les classes à associer au résultat.
  • styles : pour générer du CSS pour l’élément

Des exemples sont disponibles dans la documentation officielle.

A lire aussi : content formatting

[Web] Partage de fichiers avec Send

[Web] Partage de fichiers avec Send

Mozilla s’essaie au partage de fichiers, avec Send. Cette plateforme vous permet d’envoyer des fichiers à vos contacts, de manière sécurisée. Chaque lien généré expirera après 24h ou un téléchargement et le fichier ne laissera aucune trace physique sur les serveurs.

L’utilisation du service ne nécessite l’installation d’aucun module. Pour s’assurer que l’envoi aboutit il est recommandé de partager des fichiers pesant de moins d’1 Go.

Pour essayer c’est par ici.

[JS] Recharger un TA tinyMCE après appel AJAX

[JS] Recharger un TA tinyMCE après appel AJAX

Pas plus tard qu’aujourd’hui j’ai été confronté à un petit problème de rafraichissement de mes champs textarea pour lesquels j’utilise l’éditeur tinyMCE 4, un éditeur WYSIWYG permettant de saisir du texte et de le transformer en code HTML.

En effet, après un appel AJAX qui ajoutait des éléments textarea dans mon code, je rappelais la fonction tinymce.init(). Sauf qu’il n’y avait alors que les nouveaux champs qui étaient chargés…

Pour que cela fonctionne, j’ai simplement ajouté ceci, à la fin d’un appel AJAX ayant abouti à la création des nouveaux champs :

function f_initMce() 
{ 
	// C'est cette ligne qui a été ajoutée :-) 
	tinymce.EditorManager.editors = []; 
	
	// Et là on initialise. 
	tinymce.init( {
		// General options. 
		selector : "textarea.myMceClass", 
		theme : "modern",
		plugins : "mucharactercount wordcount paste", ... 
	}); 
}

Et voilà : tous les éléments textarea sont alors transformés même après l’appel qui effectue l’ajout de nouveaux champs dans ma page.

Edit du 18/10/2017 : attention car cela peut poser quelques problèmes à d’autres niveaux, il vaut mieux supprimer proprement chacun des éditeurs avec la méthode remove. En cas d’exception englober dans un try/catch.

Exemple :

$('textarea').each(function() 
{ 
	var ed = tinymce.get($(this).attr('id'));
	if (ed != undefined) 
	{
		try 
		{ 
			tinymce.remove(ed); 
		} 
		catch(e) 
		{ 
			delete tinymce.EditorManager.editors[ 
				$(this).attr('id')
			]; 
		} 
	} 
});

N’hésitez pas à réagir si cela ne vous parait pas correct ou si vous avez d’autres effets de bord que je n’aurais pas détecté.

[JS] JQuery – Mémo #1 – Sélecteurs

[JS] JQuery – Mémo #1 – Sélecteurs

Coché et sélectionné

On utilisera le sélecteur “:checked“. Exemple :

if($('#monChampId').is(':checked')) 
{ 
  ... 
}

A noter qu’on pourra utiliser “:selected” pour des listes déroulantes, dans la méthode find par exemple, ou directement comme sélecteur.

$("#maComboId option:selected").text();

Récupération du parent (méthode)

$('#formTest').parent()

Récupère le parent du niveau direct inférieur. On peut aussi spécifier un filtre en tant que paramètre de la fonction, pour s’assurer de la nature du parent choisi.

Sélection par classe

var champ = $('.classe1');

Sélection par ID

var champ = $('#idChamp');

Sélection de champs sur l’attribut name

$('element[name="VALUE"]')

On peut notamment utiliser :

  • ^= : commence par.
  • $= : termine par.
  • *= : contient.

La recherche peut être effectuée sur d’autres attributs (ex : id, type).

Traitement appliqué à X éléments

Utiliser la fonction find sur le parent (par exemple, un formulaire).

$('#formTest').find(
	'input[type=text].classe1, select.classe2'
)
.each(function() 
{ 
	// Traitement des champs 
	// (utiliser $(this) pour le champ parcouru). 
});

On peut envisager d’utiliser des sélecteurs qui contrôlent l’état.

$('#formTest').find(
	'select.classe2:visible:disabled, 
	input[type=radio]:not(:disabled)'
)
.each(function() { ... });

Ou même recherche sur un enfant…

$('#formTest').find(
	'div.classe1 > input[type=text]'
)
.each(function() { ... });

En savoir plus…

Les sélecteurs