Thursday, July 28, 2011

Scala by-name parameter

I was reading the section "Call-by-Name" in the book "Begining Scala" by David Pollak,
trying to get my head around by-name parameters. He gave an example,

def nano() = {
    println("Getting nano")
    System.nanoTime
}

def delayed(t: => Long) = { // => indicates a by-name parameter
    println("In delayed method")
    println("Param: "+t)
    t
}

println(delayed(nano()))

Coming from Java and used to call-by-reference, I was expecting the output to be

Getting nano
In delayed method
Param: 4513758999378
4513758999378     // same value as Param

but the output was

In delayed method
Getting nano
Param: 4475258994017
Getting nano
4475259694720     // different value from Param

Re-reading that section a couple of times still doesn't ring a bell (the book is really good though).
Googling "scala by-name parameters" returns long examples and explanations
on the subject, and more confusion for an absolute Scala beginner like me.

Referring to the Scala Language Specification, section 4.6.1 By-Name Parameters finally defreezes my brain.

... argument is not evaluated at the point of function application, but instead is evaluated at each use within the function.

Ok. Got it. Back to the example,

def delayed(t: => Long) = {
    println("In delayed method")
    println("Param: "+t) // t or nano() used, so "Getting nano" printed,
                         // then print "Param: " and the return of nano(), e.g. System.nanoTime
    t                    // t or nano() used again, thus print "Getting nano" and the System.nanoTime
                         // would have now elapsed
}

Wednesday, July 27, 2011

Google +1 callback and Wicket

Google plusone tag's callback parameter let's you call a JavaScript function when the plusone button is clicked. As an example,

<g:plusone size="tall" callback="callWicket"></g:plusone>
 
<script type="text/javascript">
        function callWicket(data) {
            // Do something here
        }
    </script>
 

What if you want to pass Wicket data (for this example, we'll get the JSON object) when the plusone button is clicked? There's an explanation of calling Wicket from JavaScript. We can either use the wicketAjaxGet or wicketAjaxPost functions provided by the contributed wicket-ajax.js when you add an Ajax behaviour to Wicket components, e.g. adding an AbstractDefaultAjaxBehavior.

We have to build the JavaScript as shown,

function callWicket() {
        var wcall = wicketAjaxGet('$url$' + '$args$', function() { }, function() { });
    }
 

to be generated by the wicket component :-

<script type="text/javascript" wicket:id="pluscallback"></script>
 
'$url$' is obtained from behave.getCallbackUrl() and $args will be constructed from plusone JSON object. Thus,
final AbstractDefaultAjaxBehavior behave = new AbstractDefaultAjaxBehavior() {

        protected void respond(final AjaxRequestTarget target) {
            // Do what you want with the data
        }
    };
    add(behave);

    CharSequence url = behave.getCallbackUrl();
    CharSequence args = "&href='+data.href+'&state='+data.state";
    StringBuffer sb = new StringBuffer();
    sb.append("function callWicket(data, id) { \n");
    sb.append("     var wcall = wicketAjaxGet('");
    sb.append(url); // the $url$
    sb.append(args); // the $args$
    sb.append(", function() { }, function() { });");
    sb.append("    }");
    Label pluscallback = new Label("pluscallback", sb.toString());   // the script tag
    add(pluscallback);
 
Getting the parameters from the JavaScript
RequestCycle.get().getRequest().getParameter("href");
    RequestCycle.get().getRequest().getParameter("state");
 

You can download the Wicket quickstart here.

Wednesday, July 20, 2011

Google +1 and Wicket Ajax Components

I wanted to incorporate the google +1 buttons for submitted links on a social bookmarking website I was building, which uses Wicket. Adding +1 buttons was easy.

The html tag:

<g:plusone wicket:id="plusone"></g:plusone>

Adding a dynamic href attribute to the tag was made simple using the AttributeModifier class:

Label plusone = new Label("plusone");
plusone.add(new AttributeModifier("href", true, new Model(submittedLink.getUrl())));
.

The rendered html tag, as sent to the browser will be:

<g:plusone wicket:id="plusone" href="http://www.exampleurl.com"></g:plusone>

with it's final form as a <div> tag with lot's of content.

However, the +1 buttons does not show after Wicket's Ajax calls, for example when clicking on a AjaxFallbackLink to refresh the section containing the button. I am guessing that the <g:plusone> tag is rendered to the final button form only initially when the page is first requested/loaded.

You can however fire up the JavaScript to manually render the tag using gapi.plusone.go(). Thus, overriding the Wicket Ajax component's onAjaxEvent will do the trick.

@Override
protected void onAjaxEvent(AjaxRequestTarget target) {
   target.appendJavascript("gapi.plusone.go()");
   super.onAjaxEvent(target);
}