Our Blog

Let us find tech solutions together

Feb 01

After following some of the debates raging about Apple’s new iPad and the future of Adobe’s Flash, the discussion usually turned to the coming future of HTML5.

Seeing as we love Apache Wicket at Mystic, I thought I’d tinker around to see how hard it would be to start adding some support for the new HTML5 tags. There are quite a few examples out there that show off canvas, geolocation, storage, and of course video and audio.

First thing I set about doing, was to define the video tag. It takes an optional src attribute among others, or multiple source tags for offering up different video streams for the browser to choose from. Firefox uses Ogg Vorbis, and Safari uses H.264, so of course, the browser vendors still don’t agree. Here’s some code to use what I’d want to see from a video component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
        final List<mediaSource> mm = new ArrayList<mediaSource>();
        mm.add(new MediaSource("/dizzy.mp4", "video/mp4"));
        mm.add(new MediaSource("/dizzy.ogv", "video/ogg"));

        IModel<list<mediaSource>> mediaSourceList = new AbstractReadOnlyModel<list<mediaSource>>() {
            public List<mediaSource> getObject() {
                return mm;
            }
        };

        add(new Html5Video("dizzy", mediaSourceList) {

            @Override
            protected boolean isControls() {
                return true;
            }

            @Override
            protected boolean isAutoPlay() {
                return true;
            }
        });

We’ve defined a custom Object for use with our new Html5Video component, and it will hold the appropriate attributes we would need to output either a src attribute or a source tag. You can also see from this example that we’ve got a few booleans we’re overriding by default, and more available in the actual implementation. Let’s take a look at the Html5Video component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Html5Video extends Html5Media {

    public Html5Video(String id, IModel<list<mediaSource>> model) {
        super(id, model);
    }

    protected int getWidth() { return 0; }

    protected int getHeight() { return 0; }

    @Override
    protected void onComponentTag(final ComponentTag tag) {
        if(getWidth()>0) {
            tag.put("width", getWidth());
        }

        if(getHeight()>0) {
            tag.put("height", getHeight());
        }

        super.onComponentTag(tag);
    }

    protected String getTagName() {
        return "video";
    }
}

So you can see we’ve abstracted this out even further into an Html5Media object which we’ll look at shortly. For now, we have width and height which are specific to just the video tag. And we’re also overriding onComponentTag to throw those attributes into the video tag if they aren’t zero. We also steal from some ideas in wicket core, and implement a method in Html5Media to checkComponentTag based on the results of a method that can be overridden getTagName.

Let’s take a look at Html5Media which is where we’ll find most of the meat:

1
2
3
4
5
6
7
8
9
public class Html5Media extends WebMarkupContainer {

    private IModel<list<mediaSource>> sources;

    public Html5Media(String id, final IModel<list<mediaSource>> model) {
        super(id, model);
        this.sources = wrap(model);
        add(new Html5UtilsBehavior());
    }

First thing we see, is we’re extending WebMarkupContainer, basically because our component can have body text (useful for fallback support). Next you’ll see that we’re adding a behavior Html5UtilsBehavior. The basic purpose is to header contribute a useful javascript file when working with browsers that don’t yet support HTML5 (Internet Explorer I’m looking at you!). Some more code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    @Override
    protected void onComponentTag(final ComponentTag tag) {
        String tagName = getTagName();
        if (tagName != null) {
            checkComponentTag(tag, tagName);
        }

        List<mediaSource> sources = getSources();

        if (sources != null && sources.size() == 1) {
            MediaSource source = sources.get(0);
            tag.put("src", source.getSrc());
        }

        if (isAutoBuffer()) {
            tag.put("autobuffer", true);
        }

        if (isAutoPlay()) {
            tag.put("autoplay", true);
        }

        if (isLoop()) {
            tag.put("loop", true);
        }

        if (isControls()) {
            tag.put("controls", true);
        }

        // Default handling for component tag
        super.onComponentTag(tag);
    }

    protected String getTagName() {
        return null;
    }

Here we check the component tag to ensure it is the acceptable name. Then if we only have a single source, we add this to the video tag instead of separate elements in the body. The next bunch of statements pull from methods and add boolean attributes to the tag if they are true. And we provide an implementation of getTagName that returns null as a sensible default.

onComponentTagBody is where we optionally will define source tags and the optional attributes that go along with it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    @Override
    protected void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) {

        List<mediaSource> sources = getSources();

        if (sources != null && sources.size() > 1) {
            final AppendingStringBuffer buffer = new AppendingStringBuffer();
            for (int index = 0; index < sources.size(); index++) {
                final MediaSource source = sources.get(index);
                buffer.append("
<source ");
                buffer.append("src='");
                buffer.append(source.getSrc());
                buffer.append("'");
                if (source.getType() != null) {
                    buffer.append(" type='");
                    buffer.append(source.getType());
                    buffer.append("'");
                }
                if (source.getMedia() != null) {
                    buffer.append(" media='");
                    buffer.append(source.getMedia());
                    buffer.append("'");
                }

                buffer.append(" />");
            }

            buffer.append("
");

            getResponse().write(buffer.toString());

        }
        super.onComponentTagBody(markupStream, openTag);
    }

Here we’re ensuring things aren’t empty, and then if we have more than one source element (often the case for compatibility between Firefox and Safari), we’ll output each source tag.

We’ve also gone through the trouble of adding an implementation of Html5Audio which consisted of overriding the getTagName method and returning audio. Pretty simple stuff.

When we put our example into place, we get a video with controls like so:

So what’s next? If you download the project available and linked below, it also contains an example of using the audio component. The Html5UtilsBehavior gives us the ability to CSS style the new HTML5 tags even with Internet Explorer, so our code can be more semantic instead of littering it with div’s for lack of an alternative. There are a ton more interactions and behaviors that can be added to support video and audio, support for canvas, postMessage, storage, Web Database. Web Workers, geolocation, Content Editable, etc. I have no reason to think any of these would be impossible to integrate into a sensible component with Wicket.

If you’d like to download the example and run it locally, or take a look at the components written, I’ve started a project over at Google Code called wicket-html5. Contact me if you’d like to contribute and start hacking away at some of these components.

To infinity, and beyond!

Read more
Jan 30

After a recent week long training Mystic gave a week ago, one item that came up was the examples as posted on the official Wicket website are a version behind. Available here: http://www.wicketstuff.org/wicket13/.

In response to throwing up the latest javadoc at a simple to remember URL on this website, the examples seem to be the next logical step to make available. So point your browser here:

http://wicketbyexample.com/examples

This is running the latest 1.4.6 release of Apache Wicket. Enjoy.

Read more
Jan 29

There are definitely times, that I wish I had easy access to the javadoc for something in the Wicket internals, without opening the IDE, or keeping my own local versions available.

I usually resort to a quick Google search and unfortunately 9 / 10 I get a non-recent javadoc version.

Today I’ve gone through and downloaded all the core library javadocs for Wicket and as of version 1.4.6 they are all available from the following link:

wicketbyexample.com/api

Click through to the library you’d like and get immediate access. It follows a simple structure /api/<module name>/<version>/

That’s it. Hope some of you find it useful.

Read more