Wednesday, October 24, 2007

modifying wicket ajax javascript output

Today I had a bit of challenge with Wicket. Wicket does a lot of ajax work for you, and most of the time you don't really have to think about things like javascript or ajax at all. However, here is the use case where Wicket didn't have me covered.


The application shows a list - and each row has an href, that if mouseover, a modalwindow pops up(this is similar to movie details coming up in netflix). Unfortuneately, wicket does not provide a built in way to "wait" on the mouseover- and I needed to prevent an inadvertent mouseover from opening the window.


I sent an email to wicket users mail list. Matej suggested I write an "IAjaxDecorator" (within about 20 minutes of my sending the email BTW) This would allow my code to add javascript code to the javascript that wicket is already emitting. Wicket code for the mouseover looks like so:

var wcall=wicketAjaxGet('?wicket:interface=:17:panelForList:datatable:rows:1:cells:1:cell:showModal2::IBehaviorListener:0:', function() { }.bind(this), function() { }.bind(this));return !wcall;


And the typical javascript to timeout looks like so:


var t=setTimeout("javascript statement",milliseconds)

and the javascript to cancel the timeout looks like this:

clearTimeout(setTimeout_variable)


So, I needed a javascript function that would deal with running the wicket function, but include all the setTimeout command for javascript. So I created this javascript:


function ExecutorWithTimeout()
{
ExecutorWithTimeout.t;
}

ExecutorWithTimeout.prototype.execute = function(func, delay){
ExecutorWithTimeout.t = setTimeout(func, delay);
};
ExecutorWithTimeout.prototype.cancel = function(){
if (ExecutorWithTimeout.t!= null)
{
clearTimeout(ExecutorWithTimeout.t);
}
};



If you can improve my javascript, feel free to let me know. It is certainly not my main skillset! Anyway, the javascript class has a static member that tracks the status of the timeout. The onmouseover for the href calls the execute function, and my href onmouseout calls the cancel() function.

So, time to wire this into wicket.
Create a new class that extends AjaxEventBehavior, such that we can return a decorator for the wicket javascript.


public abstract class AjaxEventBehaviorForTimeout extends AjaxEventBehavior {

public AjaxEventBehaviorForTimeout(String event) {
super(event);
}

@Override
protected IAjaxCallDecorator getAjaxCallDecorator() {
return new IAjaxCallDecorator(){

public CharSequence decorateOnFailureScript(CharSequence script) {
return null;
}
public CharSequence decorateOnSuccessScript(CharSequence script) {
return null;
}
public CharSequence decorateScript(CharSequence script) {
return new AppendingStringBuffer("new ExecutorWithTimeout().execute(").append(" function() { ").append(
script).append("},2000);");

}


};


Finally, wire up the onmouseout to call the javascript cancel above, first creating a behavior to attach to the link component:



public class OnMouseoutSetTimeoutBehavior extends AbstractBehavior{

@Override
public void onComponentTag(Component component, ComponentTag tag) {

tag.getAttributes().put("onmouseout", "new ExecutorWithTimeout().cancel();");
}



Then adding this behavior to the link back on the actual Page class:

link.add(new OnMouseoutSetTimeoutBehavior());

Remember you'll need an include for the above javascript if you put it in a seperate file.

Wednesday, October 17, 2007

design vs agility

Just watched this.

Which decisions need to be made when re: architecture...

What is the cost to change later...

Some items that resonated with me - all quotes are not exact:

  1. XP- Simplest thing that works is not the easiest, or the stupidist
  2. Encapsulation /(using interfaces) to make decisions later. Create enough abstraction for things that are likely to be changed later ...
  3. Domain model up front is worthwhile (David Farley)
  4. Domain model already exists (it is at work everyday in the business), coders should faithfully try to replicate in code - Erik Doernenburg
  5. Domain model = "Software simulation of the business model"
  6. Key is to know when decisions need to be made..
  7. Fred george- "If you want to make improvements, invest in making better programmers"

Ignoring non-functional requirements can be hazardous. (examples from Ian)

Sunday, June 24, 2007

reasons to love wicket

I spent about 12 hours over the last few days working with wicket framework. Some background- I've used struts etc for too many years, tried flex, jsf, webwork, and tapestry. I think for most applications wicket is the right tool for the job. I am very impressed. I have built some ajaxy forms, used the tabset, and done layout reuse, tables with nested gui controls. Here's some coolness:
  1. Use any model you want. If you use DTO pattern, or direct binding to domain objects, wicket will bind the UI components to them. No need to convert a struts form into a dto, or a backing bean into a dto. In my case I'll be binding to a DTO since I think having the UI build/manipulate domain objects, beaks the idea of a service layer.
  2. Work with UI folks. Like tapestry, wicket imposes minimal needs on the template, such that UI designers can easily modify things.
  3. Related to #2, I have yet to need a scriptlet, or jstl. (Add that in the plus column for learning curve)
  4. real re-use. Using every other framework, reuse at the UI layer has been nearly impossible, or at least broken. In struts you could re-use forms, but ended up copying jsp crap around. In wicket, you can make subclasses of existing components (like a panel) that contain your bus specific version of it.
  5. Layout "including". In about 15 minutes I was able to chop up my page into a "body", "footer", etc.
  6. Do all the above with just a few artifcacts. Java classes, and an html template. No xml, no annotations.
  7. ajax support. I ajaxified a few form elements within minutes. No need to rip open a dwr.
  8. 2 jars. Yep, no jar hell here, just drop in the wicket jar, and maybe the wicketextensions jars... (you already have log4j in your project anyway...)
  9. No servlet api. Some might think this is a con, but in 2 days I have had no need for sessions, requests, and application contexts. I'm not lost trying to find where the code is that puts that model object into some scope. Yeehaw.
  10. Validation- very good provided validators, and it is easy to find them. Just look at the java code where the component is created!
  11. Excellent examples and docs. Wicket site is a little disorganized, but there are non-trivial examples for 95% of what you'll need... a good book in apres press... and some good stuff on the wiki
  12. Mailing list- seems monitored by some really smart folks who are committers
  13. back button, bookmarkable links. Looks like the wicket guys have you covered. Haven't tried breaking my app with back buttons yet, but looks good.

So what are you waiting for! Stop complaining about your web framework and use one you can actually love.... Sure there is some learning curve, but it is well worth the lean, elegant code you'll be maintaining, as opposed to the rats nest created by most of the others...