Make Ajax changes "bookmarkables" in Wicket


Have you ever noticed that when your application uses a lot of Ajax features to replace Panels, the user looses the ability to use the back/forward buttons of his browser, or even to bookmark the page?

If there was a lot of Ajax browsing (panel replacements), when the user clicks on the back or the refresh button the browser will take him to the last visited page, or even to his home page.

My goal here was to provide a set of functions allowing the developper to change the token in the URL, but also to add a behavior listening to the token changes.

1. If you call

TokenManager.changeToken("newtoken", target);

the new URL will be http://localhost:8080/home#newtoken

1. If you add a DefaultTokenValueChangeAjaxBehavior (requires IE8+) or a JqueryTokenValueChangeAjaxBehavior (requires jquery.js)

add(new DefaultTokenValueChangeAjaxBehavior() {
	@Override
	public void onTokenChanged(AjaxRequestTarget target, String token) {
		target.appendJavaScript("alert('ontokenchanged:" + token + "');");
	}
});

you will be notified each time the token changes; for example if the uses presses the back button, or if the TokenManager.changeToken method is called.

You can have a look at the project here : https://github.com/vmontane/wicket-ajax-bookmarks.

There is also a demo project with a simple

How to start the demo in a few command lines : - get the project on github

git clone git://github.com/vmontane/wicket-ajax-bookmarks.git wicket-ajax-bookmarks

- build wicket-ajax-bookmarks

cd wicket-ajax-bookmarks/wicket-ajax-bookmarks
mvn install

- build wicket-ajax-bookmarks-example

cd ../wicket-ajax-bookmarks-example
mvn install

- run the application with the jetty maven plugin

mvn jetty:run

That's all ! Now you can browse to http://localhost:8080 and start playing with the demo.
Here's what the demo does: An Ajax DropDownChoice allows you to change a panel. I added a DefaultTokenValueChangeAjaxBehavior to the page and overrode the onTokenChanged method, which is called each time the token changes in the browser (ie. when the user clicks the next/previous button, or when he switches panel). When the onTokenMethod is called, a JavaScript 'alert(token);' is called so you can see what has been caught on the server, and the current panel is changed.


Note that this projetct uses some elements of Wicket 1.5 and has not been tested with Wicket 1.6-beta. If you wish to contribute or ask for new requests don't hesitate to contact me.

Wicket Component Debug


Lors d’un audit, d’une revue de code, ou simplement lors de la maintenance d’un projet Wicket, il est parfois difficile d'obtenir une vision claire des composants qui constituent une page.

Afin de résoudre ce problème, je vous propose un outil permettant de visualiser, directement dans votre navigateur, les différents composants présents sur votre page. Les composants sont représentés sous la forme d’un arbre permettant de comprendre leur hiérarchie.

Lire la suite...

Behavior qui affiche une info-bulle sur un bouton 'disabled'


Quoi de plus normal que d'afficher par une info-bulle la raison pour laquelle un bouton (ou autre : case à cocher, ...) n'est pas cliquable ?

<input type="button" name="valider" disabled="disabled" value="Valider"></input>

Problématique


Et bien force est de constater le comportement n'est pas celui-attendu sous Firefox ! Ce dernier n'affiche pas l'info-bulle !

Vous pouvez le vérifier ci-dessous ou ici

Solution


En pensant d'abord aux utilisateurs, j'ai cherché une solution de contournement, et il s'avère qu'afficher par dessus le bouton une div transparente avec l'info-bulle corrige notre problème.

Voici le résultat :

<div class="zindex-tips-container">
<div class="zindex-tips-label" title="Vous n'avez pas les droits d'effectuer cette action"></div>
    <input type="button" name="valider" disabled="disabled" value="Valider"></input>
</div>

Et le css associé :

.zindex-tips-container {
    height: 100%;
    position: relative;
    width: 100%;
}
.zindex-tips-label {
    background: transparent;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    top: 0;
    z-index: 10;
}

Voici le résultat (lien) :

Il faut tout de même faire attention, car la superposition de la div bloque tous les événements, comme le clic avec la souris sur un bouton actif.

Maintenant faisons cela en Wicket :)

Implémentation dans Wicket


La mise en place est assez simple, il faut créer un behavior qui va ajouter le code html correspondant, et je vais donc directement vous donner le code correspondant :

public class ZindexTooltipBehavior extends AbstractBehavior {
 
	private StringResourceModel tooltip;
 
	public ZindexTooltipBehavior(StringResourceModel tooltip) {
		this.tooltip = tooltip;
	}
 
	@Override
	public void beforeRender(Component component) {
		super.beforeRender(component);
		Response response = component.getResponse();
		response.println("<div class=\"zindex-tips-container\">");
		response.println("<div class=\"zindex-tips-label\" title=\""+tooltip.getString()+"\"></div>");
 
	}
	@Override
	public void onRendered(Component component) {
		Response response = component.getResponse();
		super.onRendered(component);
		response.println("</div>");
	}
 
	public void setTooltip(StringResourceModel tooltip) {
		this.tooltip = tooltip;
	}
 
}

On remarque ici comment ajouter du contenu HTML avec les méthodes beforeRender et onRendered.

Ensuite, il faut ajouter le CSS correspondant dans la feuille de style de votre application ou directement dans le behavior grâce au code add(CSSPackageResource.getHeaderContribution(this.getClass(),"zindexTooltip.css")); .

Et voici un exemple d'utilisation sur une checkbox :

add(new Check<MonModel>("checkbox", model){
			@Override
			protected void onInitialize() {
				super.onInitialize();
				//On ajoute un zindex tooltip si la case est désactivée
				add(new ZindexTooltipBehavior(new StringResourceModel("button.action.forbidden.role")){
					@Override
					public boolean isEnabled(Component component) {
						return !isCheckboxEnabled();
					}
				});
			}
			@Override
			public boolean isEnabled() {
				return isCheckboxEnabled();
			}
 
			protected boolean isCheckboxEnabled() {
				return false; //Condition à implémenter
			}
		});

Voilà, c'est une astuce toute simple, mais qui montre la puissance d'utilisation des behaviors Wicket.

C'est nos utilisateurs qui vont être contents !

Gestion des listes avec les Repeaters suite


Ce billet fait suite au précédent billet sur les Repeaters. Vous en voulez plus ? Un composant facile à utiliser ? Des colonnes triables ? Tout ça en ajax ? Et bien Wicket le fait.

Lire la suite...

Upload de fichier avec Wicket


Dans ce billet nous allons voir comment gérer un formulaire d'Upload avec Wicket. Pour l'exemple nous allons ajouter une fonctionnalité d'upload d'image au formulaire de contact de l'application ZenContact.

Lire la suite...

Gérer facilement les fenêtres modales avec Wicket


Le framework web Wicket fournit un composant ModalWindow permettant de gérer des fenêtres modales.
Dans cet article, nous verrons comment le mettre en oeuvre, au travers de cas d'utilisation de plus en plus complexes.

Lire la suite...

Wicket JSR-303 Validators


La validation de données est un travail nécessaire et critique mais bien souvent rébarbatif, du fait notamment de la duplication des règles (bases de données, server-side, client-side). L'arrivée de la JSR-303 Bean Validation, emmenée par Emmanuel Bernard, apporte une standardisation bienvenue à cette problématique incontournable de toute application de gestion. Nous vous proposons donc une solution pour Wicket en intégrant cette JSR !

L'intégration est livrée sur GoogleCode dans le projet wicket-jsr303-validators. Des tests unitaires couvrant un bon nombre de cas sont fournis, mais si vous constatez que certains de vos use-cases spécifiques ne sont pas supportés, n'hésitez pas à nous en faire part sur le bugtracker, le but étant de contribuer ce code s'il prouve son utilité.

Lire la suite...

GoogleWavePanel : surfez sur les Waves avec Wicket !


Nous avons le plaisir de vous présenter GoogleWavePanel, un composant Wicket vous permettant d'intégrer des Google Waves au sein de vos applications.
Il s'appuie sur un récent tutorial clarifiant l'utilisation de l'API Embedded Wave fournie par Google.

Lire la suite...