<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hackito Ergo Sum</title>
	<atom:link href="http://www.zackgrossbart.com/hackito/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zackgrossbart.com/hackito</link>
	<description></description>
	<lastBuildDate>Wed, 26 Feb 2014 14:57:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.3.8</generator>
	<item>
		<title>Hashbang, Dandelions, and a Web Drawing Throwdown</title>
		<link>http://www.zackgrossbart.com/hackito/smash/</link>
					<comments>http://www.zackgrossbart.com/hackito/smash/#respond</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Wed, 22 Feb 2012 15:03:22 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=1165</guid>

					<description><![CDATA[I&#8217;ve started writing articles for Smashing Magazine. Smashing is a much larger community with some amazing content. Check out my latest articles there: Web-Drawing Throwdown: Paper.js Vs. Processing.js Vs. Raphael How To Create Web Animations With Paper.js Searchable Dynamic Content With AJAX Crawling. Check them out.]]></description>
										<content:encoded><![CDATA[<p></p><p>I&#8217;ve started writing articles for <a href="http://www.smashingmagazine.com">Smashing Magazine</a>.  Smashing is a much larger community with some amazing content.  </p>
<p>Check out my latest articles there:</p>
<p><a href="http://coding.smashingmagazine.com/2012/02/22/web-drawing-throwdown-paper-processing-raphael/">Web-Drawing Throwdown: Paper.js Vs. Processing.js Vs. Raphael</a></p>
<p><a href="http://coding.smashingmagazine.com/2011/11/21/create-web-animations-with-paperjs/">How To Create Web Animations With Paper.js</a></p>
<p><a href="http://coding.smashingmagazine.com/2011/09/27/searchable-dynamic-content-with-ajax-crawling/">Searchable Dynamic Content With AJAX Crawling</a>.  </p>
<p>Check them out.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/smash/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Running Spiffy UI with Node.js</title>
		<link>http://www.zackgrossbart.com/hackito/spiffy-nodejs/</link>
					<comments>http://www.zackgrossbart.com/hackito/spiffy-nodejs/#comments</comments>
		
		<dc:creator><![CDATA[Bess Siegal]]></dc:creator>
		<pubDate>Thu, 16 Jun 2011 22:50:30 +0000</pubDate>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Spiffy UI]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=1038</guid>

					<description><![CDATA[Today Bess Siegal drops by so we can show how Spiffy UI works with Node.js. The best feature of REST is running it from anywhere and calling it from anywhere. Spiffy UI is a GWT framework you can run on any server. We&#8217;ve said that from the beginning, now we&#8217;re going to prove it. This [&#8230;]]]></description>
										<content:encoded><![CDATA[<p></p><p><a href="https://github.com/spiffyui/HelloSpiffyAuthNode"><img decoding="async" style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a></p>
<p>Today <a href="#bess">Bess Siegal</a> drops by so we can show how <a href="http://www.spiffyui.org/">Spiffy UI</a> works with <a href="http://nodejs.org/">Node.js</a>.</p>
<p>The best feature of REST is running it from anywhere and calling it from anywhere.  Spiffy UI is a GWT framework you can run on any server.  We&#8217;ve said that from the beginning, now we&#8217;re going to prove it.</p>
<p>This article turns the normal stack upside down and creates a rich GWT client that calls a JavaScript server written with <a href="http://nodejs.org/">Node.js</a>.  This simple server and rich client scales to the cloud and shows you a little about <a href="http://www.spiffyui.org/#!auth">Spiffy UI security</a>.</p>
<h2>Creating Hello Spiffy Auth Node</h2>
<p><a href="http://www.spiffyui.org/#!getStarted">Creating a new Spiffy UI project</a> for Java is easy.  The project creator gives you a simple build with a GWT client and a Java server.  They&#8217;re both Java, but the separation between the client and server make it easy to replace the server with a different technology like <a href="http://nodejs.org/">Node.js</a>.</p>
<p>Node.js runs JavaScript on your server; a little funny since we&#8217;re replacing the client-side JavaScript with GWT.  The key to this architecture is making a thicker client with a thinner server.  When servers get thinner they scale better and take fewer resources.</p>
<p>Spiffy UI already has <a href="https://github.com/spiffyui/HelloSpiffyAnt">Hello Spiffy Ant</a> and <a href="https://github.com/spiffyui/HelloSpiffyMaven">Hello Spiffy Maven</a>.  We&#8217;ll make this new project <a href="https://github.com/spiffyui/HelloSpiffyAuthNode">Hello Spiffy Auth Node</a>.</p>
<p>This project builds with Apache Ant.  That tool creates the GWT compiled code in a directory called <code>targetDir</code>.  Next we create our Node script, <code>HelloSpiffyAuthNode.js</code>.   Before we create our server, we call <code>init</code>.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 26</i></b>

init: <span class="code_keyword">function</span>() {
    <span class="code_keyword">var</span> targetDirFull = path.join(process.cwd(), targetDir);
    path.exists(targetDirFull, function(exists) { <span class="footnote"><a href="#note1" name="code1">1</a></span>
        <span class="code_keyword">if</span> (exists) {
            HelloSpiffyAuthNode.runServer();
        } <span class="code_keyword">else</span> {
            sys.puts(<span class="code_string">'===================================================\n'</span>);
            sys.puts(<span class="code_string">'You have to build the Spiffy UI client before \n'</span>);
            sys.puts(<span class="code_string">'running the server.  Run the ant in the current \n'</span>);
            sys.puts(<span class="code_string">'directory and then run the server again.\n'</span>);
            sys.puts(<span class="code_string">'===================================================\n'</span>);
        }
    });
},
</pre>
<p>We run <code>HelloSpiffyAuthNode.js</code> from the project&#8217;s root directory so that joining the current working directory, <code>process.cwd()</code>, with <code>targetDir</code> will be the full path to where our static files are.  Node.js needs a little extra code to serve our static files, and we want to make sure they&#8217;re there before we start the server<span class="footnote"><a href="#code1" name="note1">1</a></span>.</p>
<h3>Serving static files from Node.js</h3>
<p>The GWT compiler produces JavaScript embedded in some very long HTML files.  From a server-side point of view these files are completely static.  All the server needs to do is serve them.  There are Node frameworks, such as <a href="http://expressjs.com/">Express</a>, that can handle this for you, but we don&#8217;t need them for this simple example.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 51</i></b>

<span class="code_keyword">var</span> server = http.createServer(<span class="code_keyword">function</span>(request, response) {
    <span class="code_comment">/*
     * Handle based on the URI
     */</span>
     <span class="code_keyword">var</span> uri = url.parse(request.url).pathname;

    <span class="code_comment">/*
     * Try to find a static file that matches the
     * current working directory/target/www/file name
     *
     * (process.cwd() gets the current working directory)
     */</span>
     <span class="code_keyword">var</span> filename = path.join(process.cwd(), targetDir, uri);  <span class="footnote"><a href="#note2" name="code2">2</a></span>
     path.exists(filename, function(exists) {

         <span class="code_comment">/*
         * Serve up the static file that is in /target/www
         */</span>

         <span class="code_keyword">if</span> (filename.match(<span class="code_string">'/www/$'</span>) !== <span class="code_keyword">null</span>) {
             <span class="code_comment">// Then this is a request for the root and we'll return
             // the index.html file</span>
             filename += 'index.html'; <span class="footnote"><a href="#note4" name="code4">4</a></span>
         }

         fs.readFile(filename, <span class="code_string">'binary'</span>, function(err, file) {
            <span class="code_keyword">if</span> (err) {
                response.writeHeader(500, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'text/plain'</span>});
                response.end(err + <span class="code_string">'\n'</span>);
                <span class="code_keyword">return</span>;
            }

            response.writeHeader(200);
            response.write(file, 'binary');  <span class="footnote"><a href="#note3" name="code3">3</a></span>
            response.end();
        }); <span class="code_comment">//end fs.readFile callback</span>
</pre>
<p>Joining <code>process.cwd()</code>, <code>targetDir</code>, and the <code>uri</code>, creates the full path and name of the static file to serve.<span class="footnote"><a href="#code2" name="note2">2</a></span>  We then read the file and write it to the response.<span class="footnote"><a href="#code3" name="note3">3</a></span></p>
<p>We also handle the URI at the root and return the default home page <code>index.html</code><span class="footnote"><a href="#code4" name="note4">4</a></span>.  This simple function returns any of the static files, including those created by GWT.  Now we can implement our REST endpoints.</p>
<h3>A REST server in Node.js</h3>
<p>Our project implements one REST call at <code>/simple/&lt;name entered by user&gt;</code>.  Normally we would implement this as a separate function, but our example is so simple that we just put it inline.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 71</i></b>

<span class="code_keyword">if</span> (!exists) {
    <span class="code_keyword">if</span> (uri.indexOf(<span class="code_string">'/simple/'</span>) === 0) { <span class="footnote"><a href="#note5" name="code5">5</a></span>
        <span class="code_comment">/*
         * This is the REST call!
         */</span>
        <span class="code_keyword">var</span> user = uri.substring(8);
        <span class="code_keyword">var</span> userAgent = request.headers[<span class="code_string">'user-agent'</span>];
        <span class="code_keyword">var</span> payload = {user: user,
                       userAgent: userAgent,
                       serverInfo: <span class="code_string">'Node.js'</span>}; <span class="footnote"><a href="#note6" name="code6">6</a></span>
        response.writeHeader(200, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'application/json'</span>});
        response.end(JSON.stringify(payload));
        <span class="code_keyword">return</span>;
    }

</pre>
<p>If the static file was not found, we test whether the <code>uri</code> is a REST request<span class="footnote"><a href="#code5" name="note5">5</a></span>.  If it is, we return our simple JSON response. <span class="footnote"><a href="#code6" name="note6">6</a></span></p>
<h3>Handling localization</h3>
<p>Spiffy UI provides a couple of servlets for handling <a href="http://www.spiffyui.org/#!l10n">localization</a>.  We took the same basic algorithm for matching the list of the browser&#8217;s preferred locales with the list of supported locales for our application and put it into <code>HelloSpiffyAuthNode.js</code>.</p>
<p>This may sound complex, but the idea is fundamentally simple.  The browser specifies a list of preferred locales with every request to the server.  For example, the browser might say, <i>I prefer French, then I&#8217;ll take German, and if you don&#8217;t have either of those give me English</i>.  This makes it possible for websites to do their best to provide the correct content.  </p>
<p>Before we can even respond to the browser we have to figure out what languages we support.  We do this by reading all the internationalized libraries included by Spiffy UI to localize dates and times.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 167</i></b>

<span class="code_comment">/*
 * Load all the internationalized resources by reading the i18n directory
 */</span>
fs.readdir(path.join(process.cwd(), targetDir,  i18nDir), 
           function(err, files) {
    HelloSpiffyAuthNode.resources = files;<span class="footnote"><a href="#note7" name="code7">7</a></span>

    <span class="code_comment">/*
     * After resources are retrieved then the server can listen
     */</span>
    server.listen(port);

    sys.puts(<span class="code_string">'=========================================================\n'</span>);
    sys.puts(<span class="code_string">'Access Hello Spiffy Node at http://localhost:' + port + '\n'</span>);
    sys.puts(<span class="code_string">'=========================================================\n'</span>);

});
</pre>
<p>All the files found in the <code>i18nDir</code> are stored in the <code>HelloSpiffyAuthNode.resources</code> variable.<span class="footnote"><a href="#code7" name="note7">7</a></span>  Then we add another simple condition to handle a localized date request.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 121</i></b>

<span class="code_keyword">else</span> <span class="code_keyword">if</span> (uri === i18nDir + <span class="code_string">'date'</span> ||
         uri === i18nDir + <span class="code_string">'jquery.ui.datepicker.js'</span>) {
    <span class="code_comment">/*
     * This is an internationalized file request!
     */</span>
    <span class="code_keyword">var</span> resource  = HelloSpiffyAuthNode.getI18nDateResource(request, uri);
    filename = path.join(process.cwd(), targetDir, i18nDir, resource); <span class="footnote"><a href="#note8" name="code8">8</a></span>
    <span class="code_comment">/*
     * Do not return -- let it get the correct i18n date file below
     */</span>
}
</pre>
<p>The <code>getI18nDateResource</code> function returns the best fit for the given list of preferred locales in the request&#8217;s <code>accept-language</code> header as compared with the locales embedded in the file names stored in the <code>HelloSpiffyAuthNode.resources</code> variable.  The full path to the appropriate localized static date JavaScript file is produced at the end of this condition block<span class="footnote"><a href="#code8" name="note8">8</a></span>.</p>
<p>This simple example does not use any <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/i18n/client/Messages.html">Messages</a> class.  If you want to add one so you can localize strings, you just need to add additional logic in your Node script to load the localized properties files then implement script to mimic the behavior of Spiffy UI&#8217;s <a href="http://www.spiffyui.org/#!l10n">locale filter</a>.  <a href="https://github.com/spiffyui/HelloSpiffyL10N">Hello Spiffy Localization</a> is a good example of localizing a Spiffy UI project.</p>
<p>That&#8217;s everything we need to serve our <a href="https://github.com/spiffyui/HelloSpiffyAuthNode">Hello Spiffy Auth Node</a> project.  We haven&#8217;t changed our client and our whole server is about 150 lines of code.  We can run the project now and serve anonymous requests.  However, we&#8217;d also like to secure the REST endpoint.</p>
<h2>Adding security</h2>
<p>We want to add an authentication layer to secure our data.  Spiffy UI provides a <a href="http://www.spiffyui.org/#!auth">security scheme</a> for REST endpoints.  We&#8217;ll implement that scheme on our server and our client will work with just a few minor tweaks.</p>
<h3>Adding security to our client</h3>
<p>Spiffy UI handles client-side security as part of the <a href="http://www.spiffyui.org/#!rest">REST framework</a>.  We add a little to our UI to show the user when they&#8217;re logged in and support log out.</p>
<p>We add the welcome banner and logout link to our <a href="http://www.spiffyui.org/javadoc/org/spiffyui/client/MainHeader.html">MainHeader</a>.</p>
<pre>
<b><i>Index.java, starting at line 76</i></b>

Anchor logout = <span class="code_keyword">new</span> Anchor(<span class="code_string">"Logout"</span>, <span class="code_string">"#"</span>);
logout.getElement().setId(<span class="code_string">"header_logout"</span>);
header.setLogout(logout);
<span class="code_keyword">if</span> (!Index.userLoggedIn()) {
    logout.setVisible(<span class="code_keyword">false</span>);
    header.setWelcomeString(<span class="code_string">""</span>);
} <span class="code_keyword">else</span> {
    header.setWelcomeString(<span class="code_string">"You are logged in!"</span>);
}
logout.addClickHandler(<span class="code_keyword">new</span> ClickHandler() {
        <span class="code_keyword">public</span> <span class="code_keyword">void</span> onClick(ClickEvent event)
        {
            event.preventDefault();
            doLogout();
        }
    });
</pre>
<p>Also, a login listener is added so the welcome banner can show the user name when the user logs in.</p>
<pre>
<b><i>Index.java, starting at line 129</i></b>

RESTility.addLoginListener(<span class="code_keyword">new</span> RESTLoginCallBack() {

    @Override
    <span class="code_keyword">public</span> <span class="code_keyword">void</span> onLoginSuccess()
    {
        <span class="code_keyword">if</span> (RESTility.getUserToken() == <span class="code_keyword">null</span>) {
            <span class="code_keyword">return</span>;
        }
        header.setWelcomeString(<span class="code_string">"Welcome "</span> + RESTility.getUsername());
        JSUtil.bounce(<span class="code_string">"#"</span> + MainHeader.HEADER_ACTIONS_BLOCK, 5, 500, 30);
        JSUtil.show(<span class="code_string">"#header_logout"</span>, <span class="code_string">"fast"</span>);
    }

    @Override
    <span class="code_keyword">public</span> <span class="code_keyword">void</span> loginPrompt()
    {
        //do nothing
    }
});
</pre>
<p>The supporting <code>userLoggedIn</code> and <code>doLogout</code> methods simply call methods provided by Spiffy UI&#8217;s <a href="http://www.spiffyui.org/javadoc/org/spiffyui/client/rest/RESTility.html">RESTility</a>.</p>
<pre>
<b><i>Index.java, starting at line 220</i></b>

<span class="code_comment">/**
 * returns whether the  user is logged in or not
 * @return true if the user is logged in (browser cookie is there)
 */</span>
<span class="code_keyword">public</span> <span class="code_keyword">static</span> <span class="code_keyword">boolean</span> userLoggedIn()
{
    String userToken = RESTility.getUserToken();
    <span class="code_keyword">if</span> ((userToken == <span class="code_keyword">null</span>) || (userToken.length() <= 0)) {
        <span class="code_keyword">return</span> <span class="code_keyword">false</span>;
    }
    <span class="code_keyword">return</span> <span class="code_keyword">true</span>;
}

<span class="code_comment">/**
 * Logout of the application
 */</span>
<span class="code_keyword">public</span> <span class="code_keyword">static</span> <span class="code_keyword">void</span> doLogout()
{
    RESTility.getAuthProvider().logout(<span class="code_keyword">new</span> RESTObjectCallBack<String>() {
        <span class="code_keyword">public</span> <span class="code_keyword">void</span> success(String message)
        {
            Window.Location.reload();
        }

        <span class="code_keyword">public</span> <span class="code_keyword">void</span> error(String message)
        {
            Window.Location.reload();
        }

        <span class="code_keyword">public</span> <span class="code_keyword">void</span> error(RESTException e)
        {
            MessageUtil.showFatalError(e.getReason());
        }
    });
}
</pre>
<p>That&#8217;s all we need to make our client aware of authentication.  The next step is to add security to our server.</p>
<h3>Adding security to our server</h3>
<p>When the REST request is made, we must first check that the request is authorized by looking at the request&#8217;s <code>authorization</code> header.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 72</i></b>

<span class="code_keyword">if</span> (uri.indexOf(<span class="code_string">'/simple/'</span>) === 0) {
    <span class="code_keyword">if</span> (isAuth(request.headers[<span class="code_string">'authorization'</span>])) {<span class="footnote"><a href="#note11" name="code11">11</a></span>
        <span class="code_comment">/*
         * This is the REST call!
         */</span>
        <span class="code_keyword">var</span> user = uri.substring(8);
        <span class="code_keyword">var</span> userAgent = request.headers[<span class="code_string">'user-agent'</span>];
        <span class="code_keyword">var</span> payload = {user: user, 
                       userAgent: userAgent, 
                       serverInfo: <span class="code_string">'Node.js'</span>};
        response.writeHeader(200, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'application/json'</span>});
        response.end(JSON.stringify(payload));
        return;
    } <span class="code_keyword">else</span> {
        <span class="code_comment">/*
         * Return the unauthenticated fault and include the header 
         * for authentication
         */</span>
        response.writeHeader(401, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'application/json'</span>,
            <span class="code_string">'WWW-Authenticate'</span>: <span class="code_string">'X-OPAQUE uri="http://localhost:'</span> + port + 
            authUri + <span class="code_string">'", signOffUri=""'</span>}); <span class="footnote"><a href="#note9" name="code9">9</a></span>
        <span class="code_keyword">var</span> fault = {<span class="code_string">'Fault'</span>: {<span class="code_string">'Code'</span>: {<span class="code_string">'Value'</span>: <span class="code_string">'Sender'</span>, <span class="code_string">'Subcode'</span>: 
            {<span class="code_string">'Value'</span>: <span class="code_string">'NoAuthHeader'</span>}}, <span class="code_string">'Reason'</span>: {<span class="code_string">'Text'</span>:<span class="code_string">''</span>}}};
        response.end(JSON.stringify(fault));
        <span class="code_keyword">return</span>;
    }
}
</pre>
<p>If authenticated, the regular payload is returned, otherwise the fault payload is returned with the <code>WWW-Authenticate</code> header for the authentication server.<span class="footnote"><a href="#code9" name="note9">9</a></span>  In this example the authentication server is the same Node server at <code>authUri</code>.</p>
<p>In the UI, you&#8217;ll see this in action when you click the &#8220;Submit&#8221; button.  If you are not authenticated, you will be shown the login screen.  When you click &#8220;Login,&#8221; the Spiffy UI framework will automatically <code>POST</code> a request to the URL <code>/auth</code>.  It is up to the handler of <code>/auth</code> to continue to delegate authentication responsibilities to the URL specified by the <code>WWW-Authenticate</code> header.  In our example, we know that <code>/auth</code> is the same as the <code>authUri</code>, so we by-pass the delegation and just handle it directly.</p>
<p>Now we add code to our Node server to handle the posted authentication request.</p>
<pre>
<b><i>HelloSpiffyAuthNode.js, starting at line 99</i></b>

<span class="code_keyword">else</span> <span class="code_keyword">if</span> (uri === authUri) {
    <span class="code_keyword">if</span> (request.method === <span class="code_string">'POST'</span>) {
        <span class="code_comment">/*
         * Any username and password combination is fine for this
         * sample, return the token, which is just the timestamp.
         */</span>
        <span class="code_keyword">var</span> token = <span class="code_string">''</span> + new Date().getTime()
        <span class="code_keyword">var</span> json = {<span class="code_string">'Token'</span>: token};
        tokens.push(token);
        response.writeHeader(200, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'application/json'</span>});
        response.end(JSON.stringify(json)); <span class="footnote"><a href="#note10" name="code10">10</a></span>
        return;
    } <span class="code_keyword">else</span> <span class="code_keyword">if</span> (request.method === <span class="code_string">'DELETE'</span>) {
        <span class="code_keyword">var</span> authHeader = request.headers[<span class="code_string">'authorization'</span>];
        removeToken(authHeader);
        response.writeHeader(200, {<span class="code_string">'Content-Type'</span>: <span class="code_string">'application/json'</span>});
        
        <span class="code_keyword">var</span> json = {<span class="code_string">'Status'</span>: <span class="code_string">'OK'</span>};
        response.end(JSON.stringify(json)); <span class="footnote"><a href="#note12" name="code12">12</a></span>
        <span class="code_keyword">return</span>;
    }
}
</pre>
<p>If the request&#8217;s <code>method</code> is <code>POST</code>, we know that it is a request to authenticate.  In this example, we just accept any username and password combination, keep track of the new token, and return the token back to the browser.<span class="footnote"><a href="#code10" name="note10">10</a></span>  Spiffy UI will then automatically re-issue the original REST request with the authentication token in its <code>authorization</code> header, so our Node server will validate it<span class="footnote"><a href="#code11" name="note11">11</a></span> and return the expected <code>/simple</code> payload.  In the browser you will then see the username you entered in the welcome banner and the results of the <code>/simple</code> REST request will be shown.</p>
<p>Lastly, we need to handle when you click &#8220;Logout.&#8221;  Spiffy UI will send a <code>DELETE</code> request with the token in its <code>authorization</code> header, so our Node server removes the token from its list of authorized tokens and sends back an &#8220;OK&#8221; response<span class="footnote"><a href="#code12" name="note12">12</a></span>.</p>
<h3>Next steps &#8211; adding real security</h3>
<p>This example accepts any username and password as valid.  It works well for the example, but it isn&#8217;t very secure.  The next step is adding a real token and connecting with a real security provider.  This security scheme is an excellent fit for <a href="http://en.wikipedia.org/wiki/SAML">SAML</a> tokens.  </p>
<p>The stateless nature of the SAML security scheme scales well and works very well with the REST architecture of Spiffy UI&#8217;s <a href="http://www.spiffyui.org/#!auth">tokenized identity</a>.  SAML is well supported by many security providers, but it&#8217;s not the only option.  Spiffy UI supports any token type you want to use.</p>
<h2>The client for every server</h2>
<p>GWT is a great technology for rich web applications, but Java isn&#8217;t the right language for every server.  When you put Spiffy UI in the front and REST in the middle the backend is any server that works for you.  We&#8217;ve created Spiffy UI applications working against PHP, Erlang, and now Node.js.  Spiffy UI will work with .NET, Python, or any application server you like.</p>
<p style="margin-top: 5em"><a name="bess">Bess Siegal</a> is a software engineer at NetIQ and a founding contributor to <a href="http://www.spiffyui.org/">Spiffy UI</a>.  She enjoys her <a href="/blog">one-minute commute</a> so she can spend more time with her husband and 3 daughters. </p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/spiffy-nodejs/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>The Spiffy UI Framework is Open Source</title>
		<link>http://www.zackgrossbart.com/hackito/spiffyui-open-source/</link>
					<comments>http://www.zackgrossbart.com/hackito/spiffyui-open-source/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Thu, 19 May 2011 22:09:45 +0000</pubDate>
				<category><![CDATA[All]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Servlets]]></category>
		<category><![CDATA[Spiffy UI]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=1022</guid>

					<description><![CDATA[Nine months ago I posted a video about Our Spiffy UI showing the process we used for combining GWT, JQuery, and REST to make a new kind of GWT application. It was fast, it was beautiful, and you couldn&#8217;t use it. That last part has changed. The Spiffy UI framework is now open source. Spiffy [&#8230;]]]></description>
										<content:encoded><![CDATA[<p></p><p><a href="http://www.spiffyui.org"><img decoding="async" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/05/SpiffyLogo2.png" alt="" title="Spiffy UI framework" width="140" height="200" class="alignright size-full wp-image-1029" /></a></p>
<p>Nine months ago I posted a video about <a href="/hackito/spiffy/">Our Spiffy UI</a> showing the process we used for combining GWT, JQuery, and REST to make a new kind of GWT application.  It was fast, it was beautiful, and you couldn&#8217;t use it.  That last part has changed.  The <a href="http://ww.spiffyui.org">Spiffy UI framework</a> is now open source.</p>
<p>Spiffy UI combines the best part of GWT and JQuery, adds on a layer of REST and security, and provides a comprehensive CSS framework to create amazing GWT applications.  It is open source and 100% free.  </p>
<p>We&#8217;re currently developing version 0.7.5.  There&#8217;s also some amazing Spiffy UI articles on the way.  There&#8217;s a lot of work to do and we need your help.  We need you to try the samples, give us feedback, tell a friend, and build Spiffy applications.  Join the Spiffy UI community.</p>
<p>Check out the framework at <a href="http://www.spiffyui.org">www.spiffyui.org</a> and find out a better way to write GWT applications.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/spiffyui-open-source/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Creating a Mobile Touch Slide Panel with JQuery</title>
		<link>http://www.zackgrossbart.com/hackito/touchslider/</link>
					<comments>http://www.zackgrossbart.com/hackito/touchslider/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Fri, 28 Jan 2011 19:55:29 +0000</pubDate>
				<category><![CDATA[All]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mobile]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=940</guid>

					<description><![CDATA[This article shows you how to implement a sliding touch panel in JavaScript.  jQuery is the only dependency of the touch slider.  The rest is pure JavaScript and HTML.  It runs fast, feels natural, and works on every mobile device with touch support.]]></description>
										<content:encoded><![CDATA[<p></p><p><a href="https://github.com/zgrossbart/jstouchslide"><img decoding="async" style="position: absolute; top: 0; right: 0; border: 0;" src="https://d3nwyuy0nl342s.cloudfront.net/img/7afbc8b248c68eb468279e8c17986ad46549fb71/687474703a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub"></a></p>
<p><script type="text/javascript" src="/extras/touchslider/jquery-1.4.4.min.js"></script><script type="text/javascript" src="/extras/touchslider/touchslider.js"></script><link type="text/css" rel="stylesheet" href="/extras/touchslider/touchslider.css" />
<div id="slidecont">
<div id="slidebar">
<div class="cell" id="maintitle">
<h1>Horizontal Slide View</h1>
</p></div>
<div class="cell">
<p>
                        This is a JavaScript implementation of a mobile style <a href="http://developer.android.com/reference/android/widget/HorizontalScrollView.html">Horizontal Slide View</a>.
                    </p>
</p></div>
<div class="cell">
<p>
                        Use your finger to drag it left and right to all of the items in the view.
                    </p>
</p></div>
<div class="cell">
<p>
                        Since this is JavaScript it works on every mobile device with touch support
                    </p>
</p></div>
<div class="cell" id="iphone"> </div>
<div class="cell" id="ipad"> </div>
<div class="cell" id="maintitle">
<h1 style="margin-top: 50px;">and</h1>
</p></div>
<div class="cell" id="android"> </div>
<div class="cell">
<h1>it does a good job with pictures</h1>
</p></div>
<div class="cell" id="snail"> </div>
<div class="cell" id="habenaro"> </div>
<div class="cell" id="stones"> </div>
<div class="cell">
<p>
                        Each cell of the slider is HTML so you can put anything you want in it
                    </p>
</p></div>
<div class="cell" id="gmail"> </div>
<div class="cell" id="youtube"> </div>
<div class="cell" id="ebay"> </div>
<div class="cell">
<p>
                        The slider works just like the native application sliders
                    </p>
</p></div>
<div class="cell">
<p>
                        It snaps each cell into place and supports momentum
                    </p>
</p></div>
<div class="cell">
<p>
                        Try dragging fast and watch the items fly by
                    </p>
</p></div>
<div class="cell" id="cupcake"> </div>
<div class="cell" id="cans"> </div>
<div class="cell" id="tomato"> </div>
<div class="cell" id="rabbit"> </div>
<div class="cell" id="gerbera"> </div>
<div class="cell" id="zebra"> </div>
<div class="cell">
<h1>Want to know how it works?</h1>
</p></div>
<div class="cell">
<h1>keep reading</h1>
<h1>&darr;</h1>
</p></div>
</p></div>
</p></div>
<p>This bar is boring on a computer, but it comes alive on a mobile device.  Grab your iPad or Android device and take a look.</p>
<p>Drag your finger and the items move with you.  They follow your speed and keep your momentum.  Play with it a little.  I&#8217;ll wait.</p>
<div class="sourcebox">
Get the <br /><a href="https://github.com/zgrossbart/jstouchslide">source code</a>
</div>
<p>The sliding touch panel only shows up on mobile platforms.  With a mouse it feels clunky, but sliding with your finger just feels right.</p>
<p>This article shows you how to implement a sliding touch panel in JavaScript.  <a href="http://www.jquery.com">jQuery</a> is the only dependency of the touch slider.  The rest is pure JavaScript and HTML.  It runs fast, feels natural, and works on every mobile device with touch support.</p>
<h2>It all starts with a grid</h2>
<p>The sliding panel is a set of <code>div</code> tags: two containers and a <code>div</code> for each cell.  The first step is laying them all out in a simple grid.</p>
<pre>createSlidePanel: <span class="code_keyword">function</span>(<span class="code_comment">/*string*/</span> gridid, <span class="code_comment">/*int*/</span> cellWidth, 
                           <span class="code_comment">/*int*/</span> padding) {
    <span class="code_keyword">var</span> x = padding;
    
    $(gridid).each(<span class="code_keyword">function</span>() {
        $(<span class="code_keyword">this</span>).css({
            <span class="code_string">'position'</span>: <span class="code_string">'relative'</span>,
            <span class="code_string">'left'</span>: <span class="code_string">'0px'</span>
        });
        
        $(<span class="code_keyword">this</span>).parent().css(<span class="code_string">'overflow'</span>, <span class="code_string">'hidden'</span>);
        $(<span class="code_keyword">this</span>).children(<span class="code_string">'.cell'</span>).each(<span class="code_keyword">function</span>() {
            $(<span class="code_keyword">this</span>).css({
                width: cellWidth + <span class="code_string">'px'</span>,
                height: <span class="code_string">'90%'</span>,
                position: <span class="code_string">'absolute'</span>,
                left: x + <span class="code_string">'px'</span>,
                top: padding + <span class="code_string">'px'</span>
            });

            x += cellWidth + padding;
        });
</pre>
<p>Each cell has a fixed width and padding and we lay them out in a single row.  We set the <code>overflow</code> property on the container to <code>hidden</code> so we don&#8217;t get scroll bars on the grid.  </p>
<p>All layout is based in CSS.  The grid&#8217;s <code>div</code> tag has a <code>position</code> of <code>relative</code> so we can easily move it to the left and right.  As the grid moves we adjust the <code>left</code> attribute in the CSS to position the grid.  The panel container doesn&#8217;t show any <code>overflow</code> so only the cells in the middle are visible.</p>
<p><img decoding="async" fetchpriority="high" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/scroll_slide.png" alt="" title="Scroll slider" width="970" height="130" class="alignleft size-full wp-image-941" srcset="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/scroll_slide.png 970w, http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/scroll_slide-300x40.png 300w" sizes="(max-width: 970px) 100vw, 970px" /></p>
<p>CSS easily adjusts the positioning with a single property change and the browser renders it quickly.  This straightforward layout lets us quickly get to the fun part: touching it.</p>
<h2>Make it touchable</h2>
<p>There are three important events for touch support:</p>
<p><strong>ontouchstart</strong> is called when you first press your finger onto the screen.</p>
<p><strong>ontouchmove</strong> is called every time you move your finger on the screen.</p>
<p><strong>ontouchend</strong> is when you take your finger off.  </p>
<p>The default action for touching and moving in the browser is to scroll.  By overriding this behavior we&#8217;ll allow the user to scroll our panel without moving the entire window.  </p>
<p>This works well for our widget, but it can easily go bad.  Overriding the default behavior is often defying the user&#8217;s expectations.  If you aren&#8217;t clear about what&#8217;s happening it quickly becomes a bad user experience.</p>
<p>Event handling is a little tricky because we want to make sure the links and any other widgets within the cells still work.  We just want the moving events.</p>
<p>The most interesting binding is <code>ontouchend</code>.  This one will control if we follow the behavior of the widget that was clicked on or off the panel.  </p>
<pre>$(gridid).each(<span class="code_keyword">function</span>() {
    <span class="code_keyword">this</span>.ontouchend = <span class="code_keyword">function</span>(e) {
        e.preventDefault();
        e.stopPropagation();
        
        <span class="code_keyword">if</span> (touchslider.sliding) {
            touchslider.sliding = <span class="code_keyword">false</span>;
            touchslider.touchEnd($(<span class="code_keyword">this</span>), e);
            <span class="code_keyword">return</span> <span class="code_keyword">false</span>;
        } else {
            <span class="code_comment">/*
               We never slid so we can just return true
               and perform the default touch end
             */</span>
            <span class="code_keyword">return</span> <span class="code_keyword">true</span>;
        }
    };
    ...
</pre>
<p>The first line binds the event so we can respond to it.  Then we have to figure out if we should allow the default behavior or not.  This depends if we&#8217;re at the end of a slide or just a widget interaction.</p>
<p>We always prevent the default handling of the event.  The default is never what we want here.  Android will just scroll the screen, but iPads will hover a little magnifying class control that looks broken for our widget.  </p>
<h2>Touch the screen</h2>
<p>The start of the touch is about recording data.  </p>
<pre>touchStart: <span class="code_keyword">function</span>(<span class="code_comment">/*JQuery*</span> elem, <span class="code_comment">/*event*/</span> e) {
     jsslide.startX = e.targetTouches[0].clientX;
     jsslide.startLeft = jsslide.getLeft(elem);
     jsslide.touchStartTime = new Date().getTime();
     
},
</pre>
<p>We record the location and the time the touch happened.  The location is important since all touches are relative.  The time helps us keep track of momentum.</p>
<p>Mobile devices make these panels feel realistic by adding momentum.  It gives you the feeling that the panel has weight.  If you drag it fast then it keeps going beyond your stopping point.  This is the strange physics of mobile momentum.</p>
<p>In the real world force equals mass times acceleration.  We need to figure out that force so we know how much extra to let the panel move when you&#8217;re not pushing it.  Our fake acceleration is the distance you moved multiplied by the time you spent doing it.  The start and end time of the touch motion give us that information.  Our widget doesn&#8217;t have any real mass, so we fake it.  That part comes later.</p>
<h2>Move your finger</h2>
<p>Once the touch is started we need to worry about moving events.  The user could move their finger in any direction so we need to handle them both.</p>
<pre>touchMove: <span class="code_keyword">function</span>(<span class="code_comment">/*JQuery*/</span> elem, <span class="code_comment">/*event*/</span> e) {
     <span class="code_keyword">if</span> (!touchslider.sliding) {
         elem.parent().addClass(<span class="code_string">'sliding'</span>);
     }
     
     touchslider.sliding = <span class="code_keyword">true</span>;
     

     if (jsslide.startX > e.targetTouches[0].clientX) {
         <span class="code_comment">/*
          * Sliding to the left
          */</span>
         elem.css("left", "-" + (jsslide.startX - e.targetTouches[0].clientX - 
                                 jsslide.startLeft) + "px");
         jsslide.slidingLeft = <span class="code_keyword">true</span>;
     } else {
         <span class="code_comment">/*
          * Sliding to the right
          */</span>
         <span class="code_keyword">var</span> left = (e.targetTouches[0].clientX - jsslide.startX + 
                     jsslide.startLeft);
         elem.css(<span class="code_string">'left'</span>, left + <span class="code_string">'px'</span>);
         jsslide.slidingLeft = <span class="code_keyword">false</span>;
     }
}
</pre>
<p>All positions are negative since the panel starts with a <code>left</code> property of zero.  Then we figure out what direction it&#8217;s moving in based on the current location and the start of the touch.  We don&#8217;t need any jQuery animations here since the touch is moving fast enough to simulate movement.  Adding any extra effects would just slow things down.</p>
<h2>Stop touching the screen</h2>
<p>The end of the touch is where things get really interesting.  There are a number of different ways the touch could end and we have to handle each of them individually.  </p>
<h3>Using native transitions</h3>
<p>At first I created this using JQuery animations.  They worked well, but they were a little choppy. <a href="http://twitter.com/millermedeiros">Miller Medeiros</a> left an awesome comment about using <a href="http://webkit.org/blog/138/css-animation/">WebKit transitions</a> so I gave it a try.  They worked really well.  I restructued the code a little to work with WebKit transitions and it looks great.</p>
<p>We can handle all animations through a single <code>doSlide</code> function.  It sets the <code>left</code> property and specifies the transform. </p>
<pre>doSlide: <span class="code_keyword">function</span>(<span class="code_comment">/*jQuery*/</span> elem, <span class="code_comment">/*int*/</span> x, <span class="code_comment">/*string*/</span> duration) {
     elem.css({
         left: x + <span class="code_string">'px'</span>,
         <span class="code_string">'-webkit-transition-property'</span>: <span class="code_string">'left'</span>,
         <span class="code_string">'-webkit-transition-duration'</span>: duration
     });
}
</pre>
<p>The tranform property is left and we specify a duration for the transform to take.  We need to unset these properties once we start the touch again so we don&#8217;t wait a long time for every transition while the touch is moving.  </p>
<h3>Did they drag too far</h3>
<p>During the touch moving they could have dragged the bar before the beginning or after the end of the items.  We let them do it so the widget seems responsive, but then give them a gentle reminder by sliding the bar back to the right place.</p>
<pre>touchEnd: <span class="code_keyword">function</span>(<span class="code_comment">/*JQuery*/</span> elem, <span class="code_comment">/*event*/</span> e) {
     if (jsslide.getLeft(elem) > 0) {
         <span class="code_comment">/*
          * This means they dragged to the right past the first item
          */</span>
         touchslider.doSlide(elem, 0, '0.5s');
         elem.parent().removeClass(<span class="code_string">'sliding'</span>);
         jsslide.startX = <span class="code_keyword">null</span>;
     } 
</pre>
<p>If they drag to the right past the first item then our panel will be left floating with a large space on the left.  In that case we&#8217;ll slide it back into place.</p>
<p>Dragging left past the last item works in a similar way.  We animate the panel back into place so there isn&#8217;t any extra space on the right side.</p>
<h3>Slide momentum</h3>
<p>When the user slides in the middle we need to consider their slide momentum.  This tells us how much farther we should push the panel once the touch ends.  If they do a short slow drag then the panel shouldn&#8217;t move much extra.  If they do a long fast drag then we want a large extra slide.  The momentum allows the user to easily make big jumps in the slider without having to perform multiple slides.</p>
<p>Calculating the slide momentum is a little tricky.  We need to consider the distance of the slide and how long it took.  </p>
<pre>slideMomentum: <span class="code_keyword">function</span>(<span class="code_comment">/*jQuery*/</span> elem, <span class="code_comment">/*event*/</span> e) {
     <span class="code_keyword">var</span> slideAdjust = (new Date().getTime() - jsslide.touchStartTime) * 10;
     <span class="code_keyword">var</span> left = jsslide.getLeft(elem);
     
     <span class="code_keyword">var</span> changeX = 12000 * (Math.abs(touchslider.startLeft) - Math.abs(left));
         
     slideAdjust = Math.round(changeX / slideAdjust);
     
     <span class="code_keyword">var</span> newLeft = slideAdjust + left;
     
     <span class="code_comment">/*
      * We need to calculate the closest column so we can figure out
      * where to snap the grid to.
      */</span>
     <span class="code_keyword">var</span> t = newLeft % touchslider.colWidth;
     
     <span class="code_keyword">if</span> ((Math.abs(t)) > ((touchslider.colWidth / 2))) {
         <span class="code_comment">/*
          * Show the next cell
          */</span>
         newLeft -= (touchslider.colWidth - Math.abs(t));
     } <span class="code_keyword">else</span> {
         <span class="code_comment">/*
          * Stay on the current cell
          */</span>
         newLeft -= t;
     }
     
     <span class="code_comment">/*
      * Next we'll slide the panel...
      */</span>
</pre>
<p>To start we need to know how long the slide took.  We&#8217;ll get this number in milliseconds.  Then we need to know the current location of the panel.  </p>
<p>Next we need to know how far they slid: the difference between the absolute values of the position when the slide started and the position when it ends.  Then we multiply that by a magic number.</p>
<p>The number of milliseconds the user was actively sliding could be very large, easily over 10,000.  The amount they moved will be a pretty small number, typically under 1,000.  We have to adjust the time to make it feel like the panel has real weight.  There&#8217;s some solid math behind why I chose 12,000, but in the end it just makes it feel right.</p>
<p>We divide these two numbers and get the <code>slideAdjust</code> value.  Then we apply it to the position of the panel depending on the movement to the left or the right.  Now we just need to adjust the panel so they match our grid.</p>
<p>Once we&#8217;ve moved the panel, if we&#8217;re still in the bounds of the grid, then we want to snap the item to the left-hand side of the grid.  This is the process of sliding the grid to the left or the right so there is a whole cell showing on the left side.  </p>
<p>We calculated the width of each column when we did our first grid layout.  Now we figure out of the panel is closer to the start of the cell or the end of it and adjust accordingly.</p>
<h2>This is all ridiculous</h2>
<p>I&#8217;m giving you a little gold star for making it this far <img decoding="async" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/gold_star.gif" alt="" title="gold_star" />.  This article is packed full of math and low-level UI programming.  This widget does the kind of work you often find in <a href="http://en.wikipedia.org/wiki/Physics_engine">physics engines</a> just so it can show a simple menu.  That&#8217;s a telltale sign you&#8217;re too far out on the bleeding edge.</p>
<p>I could write a native app to do this.  IOS and Android both have horizonal slide view widgets.  They did the work for me.  It would be easier, but native apps lock you in.  There&#8217;s no way to write a native application for multiple mobile platforms, but you can make your web application look and feel like a native app.</p>
<p>The only solution for cross-platform mobile applications is HTML and JavaScript.  That won&#8217;t change for at least the next couple of years.  Some applications will always require native code, but most of them could be HTML and JavaScript.  The environment isn&#8217;t as nice, but the cross-platform support is amazing.</p>
<h2>Debugging JavaScript on mobile devices</h2>
<p>There are some really nice tools for mobile development.  XCode is at the top of my list.  HTML doesn&#8217;t give you anything close to that level of support, but you can get a nice console.</p>
<p>I define a new function named <code>output</code>:</p>
<pre>output: <span class="code_keyword">function</span>(<span class="code_comment">/*string*/</span> msg) {
    if (console) {
        console.info(msg);
    }
}</pre>
<p>It prints to the console when it&#8217;s available.  Safari on the iPad and iPhone have options to enable the console under the settings panel.  Android does it a little better.</p>
<p>If I plug my Android device into the USB port of my computer and launch the <a href="http://developer.android.com/sdk/index.html">Android SDK</a> Dalvik Debug Monitor I can see a log of everything happening on my Android.</p>
<p><img decoding="async" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/android_log.png" alt="" title="Android Web Log" width="606" height="417" class="aligncenter size-full wp-image-943" srcset="http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/android_log.png 606w, http://www.zackgrossbart.com/hackito/wp-content/uploads/2011/01/android_log-300x206.png 300w" sizes="(max-width: 606px) 100vw, 606px" /></p>
<p>Browser logs are tagged with the word <code>browser</code>.  That makes it pretty easy to find them.  This interface isn&#8217;t pretty, but it works well and I don&#8217;t have to switch windows.</p>
<p>This new mobile world is strange, but mobile web applications are a big part of it.  They look good, run fast, and aren&#8217;t that hard to work with.</p>
<h3>Image credits</h3>
<p>The images in this slider were provided by the Apple marketing department, the Android marketing department, <a href="http://www.istockphoto.com/">iStockPhoto</a>, <a href="http://commons.wikimedia.org/wiki/File:Habanero_closeup_edit2.jpg">Fir0002</a>, <a href="http://commons.wikimedia.org/wiki/File:Gerbera_white_background.jpg">Bff</a>, <a href="http://commons.wikimedia.org/wiki/File:Rabbit1.jpg">Gentaur</a>, and <a href="http://www.flickr.com/photos/doug88888/">doug8888</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/touchslider/feed/</wfw:commentRss>
			<slash:comments>199</slash:comments>
		
		
			</item>
		<item>
		<title>How To Fix Your Software&#8217;s Technical Debt, Program Faster, and Spend More of Your Time Writing Useful Code</title>
		<link>http://www.zackgrossbart.com/hackito/techdebt/</link>
					<comments>http://www.zackgrossbart.com/hackito/techdebt/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Fri, 07 Jan 2011 00:05:10 +0000</pubDate>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=871</guid>

					<description><![CDATA[New software projects need to get off the ground. If 1.0 isn&#8217;t a success forget about 2.0. You move fast, change direction often, and don&#8217;t worry too much about the details. If you&#8217;re lucky version 1 leads to 2 and 3 and 4. A few years pass and you&#8217;ve built up a customer base. People [&#8230;]]]></description>
										<content:encoded><![CDATA[<p></p><p>New software projects need to get off the ground.  If 1.0 isn&#8217;t a success forget about 2.0.  You move fast, change direction often, and don&#8217;t worry too much about the details.</p>
<p>If you&#8217;re lucky version 1 leads to 2 and 3 and 4.  A few years pass and you&#8217;ve built up a customer base.  People like the product, your job is secure, life is good.  And you have a big problem.</p>
<p>Everything you did to push 1.0 out the door is coming back to haunt you.  The code is full of spaghetti nobody wants to touch and development becomes a series of frustrated meetings where everyone asks, &#8220;how can that simple feature possibly take so long?&#8221;  You have so much legacy code you can&#8217;t make any big changes.  Your nimble product has turned into an aircraft carrier.</p>
<p>At first it&#8217;s hard to tell you&#8217;re in trouble.  Sure there are a few rough patches, but all software has warts.  You made it this far, you must be doing something right.</p>
<p>Then some of your old engineers leave the project.  New ones join.  If you&#8217;re lucky the new ones tell you you&#8217;re in a hole.  You can dig out, but it takes time, effort, and a lot of money.</p>
<p>I&#8217;ve seen this process enough times to know it&#8217;s avoidable.  It just takes planning for the future at a time when everyone around you wants to focus on today.  That&#8217;s why I use <a href="http://www.sonarsource.org/">Sonar</a> and <a href="http://checkstyle.sourceforge.net/">Checkstyle</a> on all my new Java projects.</p>
<div class="sourcebox">Get our<br />
<a href="/extras/sonar/Novell_IDM_java.xml">Sonar<br />settings</a></div>
<p>Sonar and Checkstyle are <a href="http://en.wikipedia.org/wiki/Static_code_analysis">static analysis</a> tools that look through your code for bugs and formatting issues.  They&#8217;ll tell you if you assigned a variable to itself or put your curly-braces on the wrong line.  Code checking tools make your development time shorter and get rid of annoying little bugs, but it&#8217;s always hard to sell them to your team.</p>
<p>These tools feel like they make you go slower.  Maybe you know it&#8217;s good for you, but nobody likes being told to eat their vegetables.</p>
<p>Style tools are also the source of religious wars between programmers.  Where should your curly-braces go?  What is the right way to name your methods?  How many lines before a class is too long?  There&#8217;s no right answer to these questions, but there are consistent answers.</p>
<div class="sourcebox">Get our<br />
<a href="/extras/sonar/checkstyle_checks.xml">Checkstyle<br />checks</a></div>
<p>I want to share with you the way we use these tools, the rules we think are important, and how we convince new teams to use them.</p>
<h2>Curly-braces</h2>
<p>The curly-brace debates have been going on since we started writing <a href="http://en.wikipedia.org/wiki/ALGOL_68">ALGOL</a> in 1968.  Probably before that.  So what looks better to you?</p>
<div class="twoCodeBlock">
<pre class="twoCodeBlockLeft"><span class="code_keyword">if</span> (foo)
{
    doStuff();
}</pre>
<pre class="twoCodeBlockRight"><span class="code_keyword">if</span> (foo) {
    doStuff();
}
</pre>
</div>
<p>One of them is more compact, the other one easier to line up.  Which is the right way?  There isn&#8217;t one.  We&#8217;ve debated this issue for over 40 years because there&#8217;s no compelling argument either way.</p>
<p>We force curly-braces on the same line, but I can&#8217;t tell you why.  I can say that keeping them consistent makes our code easier to read.  Try switching back and forth too often and you&#8217;ll get lost.</p>
<h2>No tabs</h2>
<p>Using tab characters is another religious debate.  Some people love tabs, others hate them.  We ban them.  We add hooks so you can&#8217;t check in files with tabs.</p>
<p>Tabs mostly cause us trouble because of our very mixed development environment.  Our developers work on Windows, Linux, and Mac because we ship products on all of those platforms.  Moving from one to the other means most developers use different editors.</p>
<p>Some editors make tabs eight spaces and some make them four.  Most editors can show you correct indentation if you have one or the other, but mix them up and even the best editors get confused.</p>
<p>We indent four spaces and ban tabs.  This is another area where the code consistency pays off.</p>
<h2>Member names</h2>
<p>We force all member names to start with <code>m_</code>.  Let me show you why with an example.  Can you spot the bug here:</p>
<pre><span class="code_keyword">public</span> <span class="code_keyword">class</span> User {
    <span class="code_keyword">private</span> String firstName;
    <span class="code_keyword">private</span> String lastName;
    <span class="code_keyword">private</span> String email;
    <span class="code_keyword">private</span> String telephone;

    <span class="code_keyword">public</span> User(String strfName, String strlName,
                String strEmail, String strTelephone) {
        <span class="code_keyword">this</span>.firstName = strfName;
        <span class="code_keyword">this</span>.lastName = strlName;
        <span class="code_keyword">this</span>.email = email;
        <span class="code_keyword">this</span>.telephone = strTelephone;
    }
}
</pre>
<p>This simple class has a very common bug.  Did you find it yet?  Take another minute.</p>
<p>The variable <code>email</code> will never be assigned.  Someone might depend on it being there and get a <code>NullPointerException</code>.  Worst of all it will become a run-time exception.</p>
<p>Run-time exceptions are scary.  They happen unpredictably and it&#8217;s easy to miss them in testing.  We always try to turn run-time exceptions into compile-time exceptions.  Those are easy to find and rarely cause problems for customers.  As long as you have an automated build the chances of shipping a with a compile error are minuscule.</p>
<h2>File length</h2>
<p>Almost everyone can agree that a 500 line source file is fine and 10,000 lines is too long, but there are a lot of opinions in between.  We limit our file lengths to 2,000 lines.  There isn&#8217;t a really good reason for that number.  It could have been 1,500 or 2,500.  The key is choosing a length and sticking to it.</p>
<p>You may have a really good reason for making your file giant, but most of the time it turns into a 5,000 line monster.  Too big to easily document and too complex to maintain.</p>
<h2>JavaDoc</h2>
<p>When I started programming I was against JavaDoc.  It seemed like a crutch.  I thought code should be readable without documentation.  I still believe that, but there are some things your code can never say.</p>
<p>The code will never tell another programmer what your intention was.  Is that missing block a bug, a feature you haven&#8217;t implemented, or there for a reason?  The programmer&#8217;s intention is very important.  The code is the implementation, but not the plan.</p>
<p>The biggest advantage of good comments is that they enable refactoring.  The comments make it much easier for another developer to change something if they know how it was meant to work in the first place.</p>
<p>We require that all <code>public</code>, <code>protected</code>, or package private methods have JavaDoc which includes every argument and every declared exception.  If you skip JavaDoc then you get a Checkstyle warning.</p>
<h2>No @author tags</h2>
<p>Speaking of JavaDoc, we ban <code>@author</code> tags in our code.  I never liked these tags, but it was <a href="http://www.red-bean.com/kfogel/">Karl Fogel</a> who first explained to me what I didn&#8217;t like.  Karl is a founding member of the Subversion project where they also ban <code>author</code> tags.  For him it comes down to the bus factor.</p>
<p>The bus factor is the answer to a simple question, &#8220;how many people would need to get hit by a bus before nobody understands this code?&#8221;  You want the number high and <code>@author</code> tags drive it lower.</p>
<p>The <code>@author</code> tag is a signpost telling everyone else to stay away.  It creates an ownership mentality of a single class.  Normally ownership mentality is great.  When every developer feels like they own the product it drives quality up and fuels the passion that leads to inspiration.</p>
<p>The problem comes when you feel like the exclusive owner.  Then your bus factor stays at one.  If you leave the project it goes to zero.  We encourage everyone to look at every part of the code base and banning <code>@author</code> tags helps us do it.</p>
<h2>Spacing</h2>
<p>This is one more issue with no right answer.  What feels better to you?</p>
<div class="twoCodeBlock">
<pre class="twoCodeBlockLeft">String s[]=getMyStrings();
<span class="code_keyword">for</span>(<span class="code_keyword">int</span> i=0;i&lt;s.length;i++)
{
    System.out.println(s[i]);
}
</pre>
<pre class="twoCodeBlockRight">String s[] = getMyStrings();
<span class="code_keyword">for</span> (<span class="code_keyword">int</span> i = 0; i &lt; s.length; i++)
{
    System.out.println(s[i]);
}
</pre>
</div>
<p>You might ask why put the space before the parenthesis and not after or why spaces around the plus sign but not the semi-colon.  There isn&#8217;t a right answer.  We chose this because it was the Sun Java coding standard, but the key is consistency.</p>
<h2>Cyclomatic complexity</h2>
<p>Spaghetti code is about more than just the code formatting.  Methods that are too complex to understand are too complex to debug.  </p>
<p>Complexity is easy to add.  One developer adds a slightly complex method and then another adds one more condition.  Then you need a special case for one more condition.  And one more.  Go through a couple of iterations and your code path is a maze of back alleys and dead ends.</p>
<p>Labyrinthine code is a sanctuary for bugs, but it&#8217;s something worse.  Complex code is immovable code.  Bringing new developers up to speed takes months and even the experienced ones can&#8217;t move the project very far.  </p>
<p>The most dangerous part is that complex code is easy to ignore.  You&#8217;ll fix it someday, but someday never comes.  This technical debt drags your project down.</p>
<p>Sonar analyzes <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> and moves the complex code argument from opinion to fact.  You choose how much complexity you can live with and warn programmers when their code complexity gets too high.  </p>
<p>We set our cyclomatic complexity maximum at seven.  That&#8217;s enough code paths for a few <code>if</code> statements with a couple of <code>while</code> loops thrown in.  Anything more and it should be a separate method.</p>
<h2>Bugs</h2>
<p>So far we&#8217;ve talked mostly about formatting issues.  They often lead to bugs, but they might not be bugs yet.  Now let&#8217;s look at a few of the real bugs Sonar finds in most projects.</p>
<h3>Empty if or else statements</h3>
<pre><span class="code_keyword">boolean</span> b = getMyBoolean();
<span class="code_keyword">if</span> (b) {
    <span class="code_keyword">return</span>;
} <span class="code_keyword">else</span> {
}
</pre>
<p>What did the programmer who wrote this mean?  Is it a copy and paste error or a real bug?  Did they just forget to add code to that else statement?  This leads to confusion, bad code, and technical debt.  We don&#8217;t allow it.</p>
<h3>Equals without hash code</h3>
<pre><span class="code_keyword">public</span> class User
{
    <span class="code_keyword">private</span> String m_name;

    <span class="code_keyword">public</span> User(String name)
    {
        m_name = name;
    }

    @Override
    <span class="code_keyword">public</span> <span class="code_keyword">boolean</span> equals(Object o)
    {
        <span class="code_keyword">return</span> m_name.equals(o);
    }
}
</pre>
<p>This one comes from the excellent <a href="http://java.sun.com/docs/books/effective/">Effective Java</a> by <a href="http://en.wikipedia.org/wiki/Joshua_Bloch">Joshua Block</a>.  The Java uses the <code>hashcode</code> and <code>equals</code> methods together in many of the collection classes.  Overriding one without the other is always a bad idea.</p>
<h3>Catching NullPointerException</h3>
<pre><span class="code_keyword">try</span> {
    myRiskyMethod();
} <span class="code_keyword">catch</span> (NullPointerException npe) {
    <span class="code_comment">// No need to do anything here</span>
}</pre>
<p>Ever seen code like this?  I know programmers that talk about code smell and this code smells like a wet dog fresh from the compost pile.</p>
<p>This code gives more questions than answers.  Why is this method risky?  What does it mean if it throws a <code>NullPointerException</code>?  Why couldn&#8217;t you handle it properly in the first place?</p>
<p>Leave this in your code and you&#8217;re a lazy programmer.</p>
<h3>Unused locale variables, private methods, and formal parameters</h3>
<p>If your method takes three arguments you better use them.  If you don&#8217;t then why did you write it that way.  What did you mean?  Did you just forget or is this a bug?</p>
<p>Sonar plus Checkstyle gives us hundreds of checks and we try to fix all of them.  I make Checkstyle warnings build errors to force programmers to fix all of them.  I do it because fixing the warnings is faster than not fixing them.</p>
<h2>Digging your way out</h2>
<p>Using Checkstyle and Sonar for a new project is relatively easy.  Choose the rules you want to enforce and make the build break if they aren&#8217;t followed.  Your project will stay at zero warnings forever.  </p>
<p>The hard part is existing projects.  The first time you run the tools they&#8217;ll give you thousands, probably tens of thousands, of warnings.  The sheer magnitude of them is overwhelming.  I&#8217;ve seen many projects run their first report and never look at Checkstyle or Sonar again.  These errors are worth fixing and don&#8217;t take as long as you&#8217;d think.  The way forward is a simple process of tools, segregation, and persistence.</p>
<h3>Use the tools</h3>
<p>There are many products and open source projects that will fix up formatting errors in Java code.  They can analyze your code and apply your style guidelines.  The best one I&#8217;ve found is <a href="http://eclipse.org/">Eclipse</a>.</p>
<div class="sourcebox">Get our<br />
<a href="/extras/sonar/EclipseCodeStyle.xml">Eclipse Code Style</a></div>
<p>Eclipse will format an entire project with a single click.  It takes a little while on large projects, but you can run it overnight.  The Eclipse code formatter will fix thousands of errors at once.  The problem becomes much more tractable with all the simple formatting issues out of the way.</p>
<h3>Segregate the code</h3>
<p>It&#8217;s much easier to stay at zero warnings than 100.  100 and 101 warnings look identical, but the different between zero and one is staggering.  Leave 100 warnings and pretty soon the number will creep up.  </p>
<p>Segregating your code is the easiest way to get to zero.  If you&#8217;re starting a new module check it separately from the rest.  Keep that part at zero and then work on some of the others.  Segregation makes modules easier to test and gives you more manageable goals.  Maybe you can fix one module per month.</p>
<h3>Persist</h3>
<p>You don&#8217;t have to fix every error in a day.  Slow and steady progress will improve your code quality over time.  Just keep at it.</p>
<p>We often assign a special portion of each development effort to fixing these errors.  Every developer devotes a little time to it and slowly works the number of warnings down.</p>
<h2>The true cost of technical debt</h2>
<p>You&#8217;ll never lose a sale because your curly-braces are on the wrong line or your files have tabs.  You will lose customers because of missing features, unstable software, and a bad reputation.  Spending your limited time adding features is a good thing.  That makes these warnings seem trivial, but fixing these warnings will save you time.</p>
<p>Every Sonar or Checkstyle warning is a small bit of technical debt.  They cause bugs, make your code more difficult to maintain, and turn your product into spaghetti code that nobody wants to work with.  One or two don&#8217;t matter, but pile up hundreds and you&#8217;re in trouble.</p>
<p>These warnings are the issues you shouldn&#8217;t waste time on.  They&#8217;re the <code>NullPointerException</code> you spend a day tracking down and the bad formatting that costs you an extra hour understanding the code.  Let the tools find these problems so you can focus on the important features of your product.</p>
<p>Good software comes from distance.  It&#8217;s only when you can step back and see the forest from the trees that you make the hard decisions and design the features your customers really need.  If you spend all of your time putting out fires you&#8217;ll never get to the fun and profit.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/techdebt/feed/</wfw:commentRss>
			<slash:comments>9</slash:comments>
		
		
			</item>
		<item>
		<title>Creating a GWT Wrapper for the JQuery UI Slider</title>
		<link>http://www.zackgrossbart.com/hackito/gwt-slider/</link>
					<comments>http://www.zackgrossbart.com/hackito/gwt-slider/#comments</comments>
		
		<dc:creator><![CDATA[Bess Siegal]]></dc:creator>
		<pubDate>Thu, 23 Dec 2010 16:31:38 +0000</pubDate>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=762</guid>

					<description><![CDATA[My wonderful and amazing colleague Bess Siegal dropped by to talk with me about wrapping JQuery controls in GWT.  This article walks you through creating a GWT wrapper for the JQuery UI Slider with more features, testing, and customizability than any slider available in GWT.]]></description>
										<content:encoded><![CDATA[<p></p><link media="all" type="text/css" href="/extras/sliderexample/jquery-ui.css" rel="stylesheet"> <link type="text/css" rel="stylesheet" href="/extras/sliderexample/SliderExample.css"> <script src="/extras/sliderexample/jquery-1.4.4.min.js" type="text/javascript" charset="utf-8"></script> <script src="/extras/sliderexample/jquery-ui.min.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript" language="javascript" src="/extras/sliderexample/sliderexample/sliderexample.nocache.js"></script> <iframe src="javascript:" id="__gwt_historyFrame" tabIndex="-1" style="position:absolute;width:0;height:0;border:0"></iframe><br />
<style type="text/css"> body {font-size: 10px;} </style>
<p>
Today my wonderful and amazing colleague <a href="#bess">Bess Siegal</a> dropped by to talk with me about wrapping JQuery controls in GWT.  You might remember Bess from her last article, <a href="/hackito/gwt-rest-auto/">Creating A Multi-Valued Auto-Complete Field Using GWT SuggestBox And REST</a>.
</p>
<p>
JavaScript can <a href="http://tutorialzine.com/2010/06/apple-like-retina-effect-jquery-css/">dynamically zoom photos</a>, develop <a href="http://jqtouch.com/">mobile applications</a>, and create <a href="http://www.spritely.net/">complex animations without flash</a>.  And GWT can&#8217;t.  Well&#8230; not easily.  
</p>
<p>
There&#8217;s a world of JQuery plugins you can use easily and safely in your GWT project.  All it takes is a little planning and a little practice.  
</p>
<p>
This article walks you through creating a GWT wrapper for the <a href="http://jqueryui.com/demos/slider/">JQuery UI Slider</a> which has more features, testing, and customizability than any slider available in GWT.
</p>
<div id="demo">
    </p>
<h2>Default Slider</h2>
<p>    </p>
<div id="sliderContainer"></div>
<p>    </p>
<h2>Range Slider</h2>
<p>        </p>
<div id="rangeContainer"></div>
<p>    </p>
<h2>Snap to increments</h2>
<p>    </p>
<div id="stepContainer"></div>
<p>    </p>
<h2>Slider with multiple anchors</h2>
<p>    </p>
<div id="multiContainer"></div>
</div>
<h2>Importing JQuery libraries</h2>
<p>
We&#8217;ll start by adding a few libraries.  Download the minified files for <a href="http://www.jquery.com">JQuery</a> and <a href="http://jqueryui.com/download">JQuery UI</a> and add them to your WAR.  Then reference them in your HTML file like this:
</p>
<pre>
&lt;link media="all" type="text/css" href="jquery-ui.css" rel="stylesheet"&gt; 
&lt;script src="jquery-1.4.4.min.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; 
&lt;script src="jquery-ui.min.js" type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; 
</pre>
<p>
You can also have Google host them for you like this:
</p>
<pre>
&lt;link media="all" type="text/css" 
        href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/base/jquery-ui.css" rel="stylesheet"&gt; 
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" 
        type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; 
&lt;script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/jquery-ui.min.js" 
        type="text/javascript" charset="utf-8"&gt;&lt;/script&gt; 
</pre>
<h2>Let&#8217;s add some code</h2>
<div class="sourcebox">
Get the <br /><a href="/extras/sliderexample/SliderExample.zip">source code</a>
</div>
<p>
Now that you&#8217;ve imported the JQuery libraries, let&#8217;s start using them.  The <a href="http://jqueryui.com/demos/slider/">JQuery UI Slider</a> attaches to a <code>DIV</code> element in your page so our GWT Slider wrapper extends <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/user/client/ui/Widget.html">Widget</a>.  
</p>
<p>
Picking the correct base class is an important part of creating a fully featured GWT control.  Our slider is just a <code>DIV</code>.  If your control uses a text field you could extend <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/user/client/ui/TextBox.html">TextBox</a> or any other GWT widget.
</p>
<pre>
public class Slider extends Widget
    
    <span class="code_comment">/**
     * Create a slider with the specified ID.  The ID is required
     * because the slider needs a specific ID to connect to.
     * @param id - id of the element to create
     * @param options - JSONObject of any possible option, can be null 
     *                  for defaults
     */</span>
    <span class="code_keyword">public</span> Slider(String id, JSONObject options)
    {           
        <span class="code_keyword">super</span>();
        Element divEle = DOM.createDiv();
        setElement(divEle);
        divEle.setId(id); <span class="footnote"><a name="slider_code1" href="#slider_note1">1</a></span>
        
        m_defaultOptions = options;
        if (m_defaultOptions == <span class="code_keyword">null</span>) {
            m_defaultOptions = getOptions(0, 100, new int[]{0});<span class="footnote"><a name="slider_code2" href="#slider_note2">2</a></span>
        }        
    }
</pre>
<p>
A <code>DIV</code> element is created and set as the element in the constructor <span class="footnote"><a name="slider_note1" href="#slider_code1">1</a></span>.
</p>
<p>
Extending widget works well for the Slider, but it isn&#8217;t always the best choice.  When we wrapped the <a href="http://jqueryui.com/demos/datepicker/">JQuery UI Date Picker</a> we used <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/user/client/ui/TextBox.html">TextBox</a> as our base class.  Choosing the right base class let&#8217;s your JQuery wrapper act like a first class GWT widget.
</p>
<h2>Getting your slider&#8217;s options</h2>
<p>
<code>getOptions</code><span class="footnote"><a name="slider_note2">2</a></span> is a static method to assist in creating the <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/json/client/JSONObject.html">JSONObject</a><br />
of options.  
</p>
<pre>    
    <span class="code_comment">/**
     * A convenient way to create an options JSONObject.  Use SliderOption 
     * for keys.
     *
     * @param min - default minimum of the slider
     * @param max - default maximum of the slider
     * @param defaultValues - default points of each anchor
     * @return a JSONObject of Slider options
     */</span>
    <span class="code_keyword">public</span> <span class="code_keyword">static</span> JSONObject getOptions(<span class="code_keyword">int</span> min, <span class="code_keyword">int</span> max, <span class="code_keyword">int</span>[] defaultValues) 
    {
        JSONObject options = <span class="code_keyword">new</span> JSONObject();
        options.put(SliderOption.MIN.toString(), <span class="code_keyword">new</span> JSONNumber(min));
        options.put(SliderOption.MAX.toString(), <span class="code_keyword">new</span> JSONNumber(max));
        JSONArray vals = intArrayToJSONArray(defaultValues);
        options.put(SliderOption.VALUES.toString(), vals);
        <span class="code_keyword">return</span> options;
    }

    <span class="code_keyword">private</span> <span class="code_keyword">static</span> JSONArray intArrayToJSONArray(<span class="code_keyword">int</span>[] values)
    {
        JSONArray vals = <span class="code_keyword">new</span> JSONArray(); 
        <span class="code_keyword">for</span> (<span class="code_keyword">int</span> i = 0, len = values.length; i &lt; len; i++) {
            vals.set(i, <span class="code_keyword">new</span> JSONNumber(values[i]));
        }
        <span class="code_keyword">return</span> vals;
    }
</pre>
<h2>More options</h2>
<p>
There are also other constructors for the most common parameter options set during initialization. 
</p>
<pre><span class="code_comment">/**
 * Create a slider with the specified ID.  The ID is required
 * because the slider needs a specific ID to connect to.
 * @param id - id of the element
 * @param min - default minimum of the slider
 * @param max - default maximum of the slider
 * @param defaultValue - default point of a single anchor
 */</span>
<span class="code_keyword">public</span> Slider(String id, <span class="code_keyword">int</span> min, <span class="code_keyword">int</span> max, <span class="code_keyword">int</span> defaultValue)
{
    <span class="code_keyword">this</span>(id, min, max, <span class="code_keyword">new</span> <span class="code_keyword">int</span>[]{defaultValue});
}
    
<span class="code_comment">/**
 * Create a slider with the specified ID.  The ID is required
 * because the slider needs a specific ID to connect to.
 * @param id - id of the element
 * @param min - default minimum of the slider
 * @param max - default maximum of the slider
 * @param defaultValues - default points of each anchor
 */</span>
<span class="code_keyword">public</span> Slider(String id, <span class="code_keyword">int</span> min, <span class="code_keyword">int</span> max, <span class="code_keyword">int</span>[] defaultValues)
{           
    <span class="code_keyword">this</span>(id, getOptions(min, max, defaultValues));
}
</pre>
<p>
The <code>SliderOption</code> enumeration helps with additional slider options.  The Javadoc comments for each option is copied directly from <a href="http://docs.jquery.com/UI/Slider#options">JQuery UI Slider documentation</a>.
</p>
<h2>Initialization</h2>
<p>
Constructing your GWT object is only the first step.  You also have to bind it to JQuery<span class="footnote"><a name="slider_note4" href="#slider_code4">4</a></span> with the <a href="http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html">JavaScript Native Interface</a>.  The best place to do this is the <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/user/client/ui/Widget.html#onLoad%28%29"><code>onLoad</code></a> method.
</p>
<p>
We need this method because GWT causes a timing problem.  With a regular JQuery page you would just call the binding when your page loads.  GWT uses a delayed loading mechanism which loads the correct GWT code for your browser and language.  The <code>onLoad</code><a name="slider_note3" href="#slider_code3">3</a></span> method gives us a good place to bind to JQuery after our GWT object has been loaded into the page.
</p>
<pre>
    @Override
    <span class="code_keyword">protected</span> <span class="code_keyword">void</span> onLoad()<span class="footnote"><a name="slider_code3" href="#slider_note3">3</a></span>
    {
        if (m_defaultOptions == null) {
            m_defaultOptions = <span class="code_keyword">new</span> JSONObject();
        }
        
        createSliderJS(this, getElement().getId(), m_defaultOptions.getJavaScriptObject());
        <span class="code_keyword">super</span>.onLoad();
    }
    
    <span class="code_keyword">private</span> <span class="code_keyword">native</span> <span class="code_keyword">void</span> createSliderJS(Slider x, String id, JavaScriptObject options) /*-{
        options.start = function(event, ui) {
            x.@com.example.slider.client.widget.slider.Slider::fireOnStartEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/core/client/JsArrayInteger;)(event, ui.values);
        };
        options.slide = function(event, ui) {
            return x.@com.example.slider.client.widget.slider.Slider::fireOnSlideEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/core/client/JsArrayInteger;)(event, ui.values);
        };
        options.change = function(event, ui) {
            var has = event.originalEvent ? true : false;
            x.@com.example.slider.client.widget.slider.Slider::fireOnChangeEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/core/client/JsArrayInteger;Z)(event, ui.values, has);                
        };
        options.stop = function(event, ui) {
            x.@com.example.slider.client.widget.slider.Slider::fireOnStopEvent(Lcom/google/gwt/user/client/Event;Lcom/google/gwt/core/client/JsArrayInteger;)(event, ui.values);
        };<span class="footnote"><a name="slider_code5" href="#slider_note5">5</a></span>
        
        $wnd.$("#" + id).slider(options);<span class="footnote"><a name="slider_code4" href="#slider_note4">4</a></span>
    }-*/;
    
</pre>
<p>
In addition to the options set in the constructor, the <code>createSliderJS</code> method also maps the slider&#8217;s events to corresponding <code>fireOnXEvent</code> Java methods using the GWT technique for <a href="http://code.google.com/webtoolkit/doc/latest/DevGuideCodingBasicsJSNI.html#passing-javascript">passing JavaScript values into Java code</a>.  The values we pass are the native event and the values selected by the slider. <span class="footnote"><a name="slider_note5" href="#slider_code5">5</a></span>.  Thus we have our cornerstone for event handling.
</p>
<h2>Event handling</h2>
<p>
When we&#8217;re done with our <code>Slider</code> it will look just like a standard GWT widget from the outside.  That way we can switch implementations and never worry about our choice of JavaScript library leaking out to other code in our project.  We&#8217;ll continue that strong encapsulation by creating a <code>SliderEvent</code> object and <code>SliderListener</code> interface to allow other code to get events from the <code>Slider</code>.
</p>
<pre>
    <span class="code_keyword">private</span> <span class="code_keyword">void</span> fireOnStartEvent(Event evt, JsArrayInteger values)
    {
        <span class="code_keyword">int</span>[] vals = jsArrayIntegerToIntArray(values);
        SliderEvent e = new SliderEvent(evt, <span class="code_keyword">this</span>, vals);
        
        <span class="code_keyword">for</span> (SliderListener l : m_listeners) {
            l.onStart(e);
        }
    }
    
    <span class="code_keyword">private</span> <span class="code_keyword">boolean</span> fireOnSlideEvent(Event evt, JsArrayInteger values)
    {
        <span class="code_keyword">int</span>[] vals = jsArrayIntegerToIntArray(values);
        SliderEvent e = <span class="code_keyword">new</span> SliderEvent(evt, <span class="code_keyword">this</span>, vals);
        
        <span class="code_keyword">for</span> (SliderListener l : m_listeners) {
            l.onStart(e);
        }
        
        <span class="code_keyword">boolean</span> ret = true;
        
        <span class="code_keyword">for</span> (SliderListener l : m_listeners) {
            <span class="code_keyword">if</span> (!l.onSlide(e)) {
                <span class="code_comment">//if any of the listeners returns false, return false,
                //but let them all do their thing</span>
                ret = <span class="code_keyword">false</span>;
            }
        }
        
        <span class="code_keyword">return</span> ret;<span class="footnote"><a name="slider_code6" href="#slider_note6">6</a></span>
    }
    
    <span class="code_keyword">private</span> <span class="code_keyword">void</span> fireOnChangeEvent(Event evt, JsArrayInteger values, 
                                   <span class="code_keyword">boolean</span> hasOriginalEvent)
    {
        <span class="code_keyword">int</span>[] vals = jsArrayIntegerToIntArray(values);        
        SliderEvent e = new SliderEvent(evt, <span class="code_keyword">this</span>, vals, hasOriginalEvent);
        
        <span class="code_keyword">for</span> (SliderListener l : m_listeners) {
            l.onChange(e);
        }
    }
    
    <span class="code_keyword">private</span> <span class="code_keyword">void</span> fireOnStopEvent(Event evt, JsArrayInteger values)
    {
        <span class="code_keyword">int</span>[] vals = jsArrayIntegerToIntArray(values);
        SliderEvent e = new SliderEvent(evt, <span class="code_keyword">this</span>, vals);
        
        <span class="code_keyword">for</span> (SliderListener l : m_listeners) {
            l.onStop(e);
        }
    }

</pre>
<p>
Each fire event method notifies all listeners and passes the native event and an <code>int[]</code> of values. The <code>onSlide</code> event allows for cancellation of the action by returning false<span class="footnote"><a name="slider_note6" href="#slider_code6">6</a></span>.  
</p>
<h2>Changing options after initialization</h2>
<p>
You may change a slider&#8217;s options after initialization.  There are <code>get/setIntOption</code>, <code>get/setBooleanOption</code> and <code>get/setStringOption</code> methods to maintain type-safety.  Each of these methods calls a corresponding JSNI method to get or set the option.  Getting and setting the slider&#8217;s values is a little different, so they have their own methods.</p>
<pre>
    <span class="code_comment">/**
     * Convenience method for only 1 anchor
     * @return Returns the value.
     */</span>
    <span class="code_keyword">public</span> <span class="code_keyword">int</span> getValue()
    {
        <span class="code_keyword">return</span> getValueAtIndex(0);
    }
    
    <span class="code_comment">/**
     * Sets the value of each anchor
     * @param values - int array of values
     */</span>
    <span class="code_keyword">public</span> <span class="code_keyword">void</span> setValues(<span class="code_keyword">int</span>[] values)
    {
        JSONArray vals = intArrayToJSONArray(values);
        setValuesJS(getElement().getId(), vals.getJavaScriptObject());
    } 
        
    <span class="code_comment">/**
     * Gets the value of a anchor at the specified index
     * 
     * @param index  the index to retrieve the value for
     * 
     * @return the value
     */</span>
    <span class="code_keyword">public</span> <span class="code_keyword">int</span> getValueAtIndex(<span class="code_keyword">int</span> index)
    {
        <span class="code_keyword">return</span> getValueJS(getElement().getId(), index);
    }
    
    
    <span class="code_keyword">private</span> <span class="code_keyword">native</span> <span class="code_keyword">void</span> setValuesJS(String id, JavaScriptObject values) /*-{
        $wnd.$("#" + id).slider("option", "values", values);
    }-*/;
    
    
    <span class="code_keyword">private</span> <span class="code_keyword">native</span> <span class="code_keyword">int</span> getValueJS(String id, <span class="code_keyword">int</span> index) /*-{
        return $wnd.$("#" + id).slider("values", index);
    }-*/;
</pre>
<h2>Extending the Slider</h2>
<p>
Because a slider that uses the range option is unique in that the values are limited to 2, a <code>RangeSlider</code> subclass was created to only allow get and set of 2 values.  You could extend the slider for any of the specific options required by your application.
</p>
<h2>Cleanup</h2>
<p>
The widget will cleanup after itself by calling destroy on the slider during <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/com/google/gwt/user/client/ui/Widget.html#onUnload%28%29">onUnload</a>, which is called immediately before a widget will be detached from the browser&#8217;s document.
</p>
<pre>
    @Override
    <span class="code_keyword">protected</span> <span class="code_keyword">void</span> onUnload()
    {
        destroySliderJS(this, getElement().getId());
        <span class="code_keyword">super</span>.onUnload();        
    }
    
    <span class="code_keyword">private</span> <span class="code_keyword">native</span> <span class="code_keyword">void</span> destroySliderJS(Slider x, String id) /*-{
        $wnd.$("#" + id).slider("destroy");
    }-*/;
</pre>
<h2>The Takeaway</h2>
<p>
For our web application projects at Novell, we like to use GWT for maintainability.  For all GWT&#8217;s benefits, we understand that it&#8217;s standard widgets are limited, especially when compared to its corresponding JQuery widget.  Fortunately, we&#8217;ve developed a repeatable method for wrapping JQuery UI controls, and we hope you can employ it with this slider as an example.  You may also feel free to use the slider code in your application.  Either way, please let us know if you do.
</p>
<p>
The code in this example is free and released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 license</a>. The other programs needed to run this example are also free, but some of them may use different licenses. Make sure to read and understand each license before using a tool.
</p>
<p style="margin-top: 5em"><a name="bess">Bess Siegal</a> is a software engineer at Novell.  She enjoys her <a href="/blog">one-minute commute</a> so she can spend more time with her husband and 3 daughters. </p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/gwt-slider/feed/</wfw:commentRss>
			<slash:comments>31</slash:comments>
		
		
			</item>
		<item>
		<title>4 More GWT Anti-patterns</title>
		<link>http://www.zackgrossbart.com/hackito/antiptrn-gwt2/</link>
					<comments>http://www.zackgrossbart.com/hackito/antiptrn-gwt2/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Tue, 21 Sep 2010 13:00:19 +0000</pubDate>
				<category><![CDATA[All]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=698</guid>

					<description><![CDATA[My view of GWT is changing. When I wrote 5 GWT Anti-Patterns I saw it as the framework controlling my entire application. Now it&#8217;s my glue. GWT is a wonderful foundation holding together the different parts of your application. It can grow and expand to new technologies and uses we haven&#8217;t thought of yet, but [&#8230;]]]></description>
										<content:encoded><![CDATA[<p></p><p>My view of GWT is changing.  When I wrote <a href="/hackito/antiptrn-gwt/">5 GWT Anti-Patterns</a> I saw it as the framework controlling my entire application.  Now it&#8217;s my glue.</p>
<p>GWT is a wonderful foundation holding together the different parts of your application.  It can grow and expand to new technologies and uses we haven&#8217;t thought of yet, but it can also hold us back.  You can get stuck in GWT and never find your way out.</p>
<p>Each of these four anti-patterns addresses different ways to write code you wish you hadn&#8217;t.  The solutions are all about opening doors instead of closing them.</p>
<h2>1. GWT RPC</h2>
<p>GWT RPC is the sexiest feature of the entire toolkit.  Making <a href="http://en.wikipedia.org/wiki/Ajax_(programming)">AJAX</a> simple lets you program for the web like it was a desktop.  Don&#8217;t worry about remote communications or networks, GWT RPC takes care of that for you.</p>
<h3>The problem</h3>
<p>GWT RPC generates the network calls for you and automatically marshals Java objects between the browser and the server, but that ease of use comes at a cost.</p>
<p><strong>It isn&#8217;t that easy</strong>.  GWT RPC requires you to manage two interfaces plus the client-side calling code and a servlet to make it all work.</p>
<p><strong>Error handling is hard</strong>.  Network programming is the art of error handling.  Networks are unpredictable and abstracting that away makes it much harder to respond well when something doesn&#8217;t go right.</p>
<p><strong>You can&#8217;t tell what&#8217;s going on</strong>.  Try debugging your GWT RPC through a network tool like <a href="http://www.wireshark.org/">Wireshark</a> or <a href="https://addons.mozilla.org/en-US/firefox/addon/6647/">HTTPFox</a>.  All the ease of debugging your Java by looking at the byte code.</p>
<p><strong>It&#8217;s slow</strong>.  GWT RPC adds a lot of overhead to the request, but that isn&#8217;t the worst part.  When you think of remote procedure calls as free you make a lot of them.   That&#8217;s the recipe for an application that loads in minutes instead of seconds.</p>
<h3>The solution</h3>
<p>Use REST.  I&#8217;ve written patterns for using <a href="/hackito/gwt-rest/">REST from GWT</a>.  There are also some good built-in features and third-party plugins to support it.  REST looks daunting at first, but it isn&#8217;t that bad.</p>
<p>REST is everything GWT RPC isn&#8217;t: fast, easy to debug, and simple.  It also does more.</p>
<p><strong>REST forces you to build an API</strong>.  GWT RPC makes everything look like the same program so you rarely create a solid API.  With REST you have to.  APIs make your code better even if nobody else ever calls them.</p>
<p><strong>REST supports automated testing</strong>.  Once you have a REST API you can test it without worrying about the client.  I&#8217;ve written test suites in Ruby just to make sure I had good coverage.</p>
<p><strong>REST decouples the client and server</strong>.  Imagine shipping a new version of your GWT client without changing your server.  You could fix bugs and not worry about destabilizing other parts of your code.  You could even write a GWT client for a server written in a different language like we did when we created a <a href="/hackito/gwt-rest-auto/">multi-value auto-complete field with GWT and REST</a>. That article has source code of a GWT application that calls to a Java servlet or PHP using REST.</p>
<h2>2. Securing your GWT application</h2>
<p>I sleep peacefully at night knowing my applications are secure.  So do my customers.  </p>
<p>GWT doesn&#8217;t solve the security problem for you so you might be tempted to put it all behind a firewall, password, or <a href="http://en.wikipedia.org/wiki/Java_Spring">Spring</a> framework and get perfect security.  Perfect security isn&#8217;t perfect.</p>
<h3>The problem</h3>
<p>It&#8217;s easy to put your entire GWT application behind a secure framework.  Require a login before you can even download the HTML.  You feel happy knowing the bad guys can&#8217;t see your JavaScript, HTML, or CSS, but securing everything makes your application less secure.</p>
<h3>The solution</h3>
<p>In the end GWT is just a web page.  People download, run it, and maybe view the source.  Let them.  Don&#8217;t secure any of the files that GWT generates and don&#8217;t put secure information in your source code.</p>
<p>Secure your data, not your code.  It doesn&#8217;t matter if you&#8217;re using GWT RPC, REST, or anything else, you&#8217;re just exposing URLs with data.  That&#8217;s the right place to put your security.</p>
<p>Create a single path, put all of your data behind it, and secure it with a servlet filter.  You can make this path something like <code>/data</code> so your URLs look like <code>/data/users</code> or <code>/data/roles</code>.  That simple path is easy to secure and easy to test.  </p>
<p>You can even go a step further and move the code serving secure data into a separate WAR file.  That avoids many accidental security problems.</p>
<p>Securing just your data makes your server easier to write and test.  It also helps your browser code.  Don&#8217;t make login a separate step in your application.  Add a single point in your client for login and make it part of your GWT application.</p>
<p><a name="onlyGWT"></a></p>
<h2>3. Using only GWT</h2>
<p>GWT is an insular environment.  It separates you from JavaScript and can cut you off from a world of innovations and well tested software.</p>
<h3>The problem</h3>
<p>There are many frameworks that wrap existing JavaScript code.  They work well, but they&#8217;re little more than a drop in the bucket.  GWT is a great project, but it can&#8217;t keep up with the rest of the Internet.</p>
<h3>The solution</h3>
<p>Wrap existing third-party Javascript with GWT. For example, GWT doesn&#8217;t have a progress bar control and JQuery UI has a <a href="http://jqueryui.com/demos/progressbar/">really nice one</a>.  Wrapping the JQuery UI progress bar is easy.  Here&#8217;s all the code you need:</p>
<table class="code_table" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td class="code-outline">
<pre><span class="code_keyword">import</span> com.google.gwt.user.client.ui.SimplePanel;

<span class="code_keyword">public</span> <span class="code_keyword">class</span> ProgressBar <span class="code_keyword">extends</span> SimplePanel
{
    <span class="code_keyword">private</span> <span class="code_keyword">int</span> m_value = 0;

    <span class="code_keyword">public</span> ProgressBar(<span class="code_keyword">String</span> id)
    {
        getElement().setId(id);
    }

    @Override
    <span class="code_keyword">public</span> <span class="code_keyword">void</span> onAttach()
    {
        super.onAttach();
        addProgressBarJS(getElement().getId(), m_value);
    }

    <span class="code_keyword">public</span> <span class="code_keyword">int</span> getValue()
    {
        return m_value;
    }

    <span class="code_keyword">public</span> <span class="code_keyword">void</span> setValue(<span class="code_keyword">int</span> value)
    {
        m_value = value;
        setValueJS(getElement().getId(), m_value);
    }

    <span class="code_keyword">private</span> <span class="code_keyword">static</span> <span class="code_keyword">native</span> <span class="code_keyword">void</span> setValueJS(<span class="code_keyword">String</span> id, <span class="code_keyword">int</span> barValue) <span class="code_comment">/*-{
        $wnd.$('#' + id).progressbar('destroy');
        $wnd.$('#' + id).progressbar({
            value: barValue
        });
    }-*/</span>;

    <span class="code_keyword">private</span> <span class="code_keyword">static</span> <span class="code_keyword">native</span> <span class="code_keyword">void</span> addProgressBarJS(<span class="code_keyword">String</span> id, <span class="code_keyword">int</span> barValue) <span class="code_comment">/*-{
        $wnd.$("#" + id).progressbar({
            value: barValue
        });
    }-*/</span>;
}</pre>
</td>
</tr>
</tbody>
</table>
<p>That&#8217;s it.  Add JQuery and JQuery UI to your GWT HTML page, include the JavaScript files in your WAR, and write 42 lines of code.  Now you have access to the JQuery progress bar in GWT and you&#8217;ve added strong typing to the control.  </p>
<p>Don&#8217;t like the JQuery progress bar? Wrap someone else&#8217;s.  You can always change your mind later, since none of the calling classes know you&#8217;re using it.  I&#8217;ve wrapped the progress bar, the date picker, and half a dozen third-party JavaScript controls.</p>
<h2>4. Using GWT for layout</h2>
<p>We all know the <a href="/hackito/antiptrn-gwt/#flextable">evils of FlexTable</a>, but we need to go further.  The layout technology of the web is CSS.</p>
<h3>The problem</h3>
<p>GWT provides <code><a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/FlexTable.html">FlexTable</a></code>,  <code><a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/DockLayoutPanel.html">DockLayoutPanel</a></code>, <code><a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/VerticalPanel.html">VerticalPanel</a></code>, and many others to do layout in HTML.  They put the layout in your code and make GWT feel a lot like Swing.  So why shouldn&#8217;t you use them?</p>
<p><strong>They&#8217;re ugly</strong>.  CSS isn&#8217;t just for aesthetes.  Look at any big professional website &#8211; Google, Amazon, Facebook &#8211; they all live and breathe CSS.  Without it you can&#8217;t really control or customize how your application looks.</p>
<p><strong>You have to recompile</strong>.  Needing to recompile for every pixel you change hurts your productivity.  It also means your customers can&#8217;t customize your application after you&#8217;re done with it.</p>
<p><strong>You can&#8217;t use <a href="http://getfirebug.com/">Firebug</a></strong>.  All user interfaces require tweaking and Firebug lets you do it live.  Stick with HTML layouts and you&#8217;re poking around in the dark hoping your changes are OK.</p>
<h3>The solution</h3>
<p>Put all of your layout in CSS.  This was one of our fundamental rules on <a href="/hackito/rpt-css/">my last project</a>.  Assign classes to your elements, write <a href="/hackito/tags-first-gwt/">tags first GWT</a>, and make a professional application.</p>
<h2>Conclusion</h2>
<p>Our understanding of <em>good</em> on the web is changing.  Just working isn&#8217;t enough anymore.  Good applications run fast, look professional, and are easy to use.  Most of these anti-patterns are advanced.  They represent subtle new ways of thinking about GWT.  Patterns at this level are a sign of maturing technology and our maturing understanding of it.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/antiptrn-gwt2/feed/</wfw:commentRss>
			<slash:comments>16</slash:comments>
		
		
			</item>
		<item>
		<title>Our Spiffy UI</title>
		<link>http://www.zackgrossbart.com/hackito/spiffy/</link>
					<comments>http://www.zackgrossbart.com/hackito/spiffy/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Mon, 09 Aug 2010 23:42:45 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[GWT]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=672</guid>

					<description><![CDATA[A presentation about the technologies, philosophies, and team organization behind my latest project at Novell.]]></description>
										<content:encoded><![CDATA[<p></p><p><b>Update</b>: The Spiffy UI Framework mentioned in this presentation is now open source.  Check it out at <a href="http://www.spiffyui.org">http://www.spiffyui.org</a>.</p>
<p>I&#8217;ve been working on a new project called The Novell Identity Manager Reporting Module.  It generates comprehensive reports about identity data in very large organizations.  It was also a chance to build a new web application from the ground up.</p>
<p>Official product names take a long time so within our group this project was known as Our Spiffy Reporting Tool.  It represents many new directions and innovations for web application UI.  It&#8217;s the application of some new philosophies.  We integrated <a href="/hackito/rpt-css/">fluid grids and vertical rhythm</a>, called all of our APIs using <a href="hackito/gwt-rest/">REST from GWT</a>, and created a new <a href="hackito/gwt-rest-auto/">auto-complete multi-valued suggest box</a>.  </p>
<p>This presentation also shows some of my personal transformation from desktop programming snob to a happy web application developer.</p>
<p>Here&#8217;s Our Spiffy UI:</p>
<p><object width="400" height="225"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=13950436&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=13950436&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="580" height="326"></embed></object></p>
<p>This presentation was given <a href="/hackito/present/">in the browser with JQuery</a>.  It&#8217;s all open source and you can <a href="/extras/spiffyui/">see the slides online</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/spiffy/feed/</wfw:commentRss>
			<slash:comments>10</slash:comments>
		
		
			</item>
		<item>
		<title>Collecting Statistics for The WordPress Editorial Calendar Plugin</title>
		<link>http://www.zackgrossbart.com/hackito/edcal_stats/</link>
					<comments>http://www.zackgrossbart.com/hackito/edcal_stats/#comments</comments>
		
		<dc:creator><![CDATA[Zack Grossbart]]></dc:creator>
		<pubDate>Sat, 07 Aug 2010 19:40:47 +0000</pubDate>
				<category><![CDATA[All]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Scripts]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=615</guid>

					<description><![CDATA[Writing a WordPress plugin is inspiration, perspiration, testing, guess work, and frustration.  You spend hours making your plugin just right, but you never know if it is just right.  This post shows you the details of the new process we added to collect remote data about the <a href="/hackito/edcal/">WordPress Editorial Calendar Plugin</a>.
]]></description>
										<content:encoded><![CDATA[<p></p><p><a href="https://github.com/zgrossbart/edcalpepper"><img decoding="async" style="position: absolute; top: 0; right: 0; border: 0;" src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a></p>
<p>Writing a WordPress plugin is inspiration, perspiration, testing, guess work, and frustration.  You spend hours making your plugin just right, but you never know if it is just right.  You hear from some of the happy users and none of the unhappy ones.  This guess work leads to assumptions we can&#8217;t back up.</p>
<p><a href="http://www.zackgrossbart.com/edcal/mint/"><img decoding="async" loading="lazy" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_stats.png" alt="" title="Editorial Calendar Statistics" width="256" height="339" class="alignright size-full wp-image-662" srcset="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_stats.png 256w, http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_stats-226x300.png 226w" sizes="(max-width: 256px) 100vw, 256px" /></a></p>
<p>The team from <a href="http://stresslimitdesign.com/">Stresslimit Design</a> and I have been working on the <a href="/hackito/edcal/">WordPress Editorial Calendar</a> for months, but we have no real idea how people use it.  How many weeks are people looking at in the calendar?  How big are there screens?  How many posts do they have per day?  We need the answers to design the plugin, but we&#8217;re just fumbling through the dark.</p>
<p>With version 0.9 of the calendar we&#8217;re trying to turn on the light.  </p>
<h2>Why we&#8217;re collecting data</h2>
<p>WordPress plugins go out into the wild and don&#8217;t phone home.  You get a simple <a href="http://wordpress.org/extend/plugins/editorial-calendar/stats/">plugin statistics page</a>, but never find out who&#8217;s using your plugin, how they&#8217;re using it, or even if they installed it after downloading.  As a privacy nut I like that, but it makes my life as a designer difficult.  </p>
<p><img decoding="async" loading="lazy" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_9w.png" alt="" title="9 Week Editorial Calendar" width="350" height="373" class="alignright size-full wp-image-637" srcset="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_9w.png 350w, http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/edcal_9w-281x300.png 281w" sizes="(max-width: 350px) 100vw, 350px" /></p>
<p>The editorial calendar is getting close to version 1.0 and we&#8217;re trying to refine our interface.  Make those little tweaks that take it from good to great.  We started with a simple question, how many weeks should we show on the calendar by default?  I rarely post more than once a day and my 24-inch monitor stretches on like the Montana prairie so I want as many weeks as possible.  I could even go up to eight or nine.  </p>
<p>Nine weeks is the perfect answer for me, but it isn&#8217;t the right answer.  Most users are stuck in Manhattan apartment sized screens and can&#8217;t see nine weeks with a magnifying glass.  Well&hellip; that&#8217;s what I think, but I don&#8217;t really know.  If I had real data on people&#8217;s window sizes I could make the right choice and make the calendar that much better.  </p>
<p>That&#8217;s why we&#8217;re tracking data with this plugin.  To make it work better.  That&#8217;s most of the reason.  We also want to know how many people are really using it.  </p>
<h2>Always make it opt-in</h2>
<p>WordPress plugins have a gigantic amount of power.  They can delete your data, steal your passwords, and hack your blog.  When you install a plugin you&#8217;re saying <i>I trust this plugin to not be evil</i>.  That&#8217;s a lot of trust and the Editorial Calendar has to earn it.  </p>
<p>We could collect data automatically, but that&#8217;s evil.  Instead we make all data collection opt-in.  Users can very clearly see everything we collect and have to click the button before we collect anything.  </p>
<p><img decoding="async" loading="lazy" src="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/feedback.png" alt="" title="Editorial calendar feedback screen" width="534" height="161" class="aligncenter size-full wp-image-627" srcset="http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/feedback.png 534w, http://www.zackgrossbart.com/hackito/wp-content/uploads/2010/08/feedback-300x90.png 300w" sizes="(max-width: 534px) 100vw, 534px" /></p>
<h2>How it works</h2>
<p>The data collection is based on <a href="http://www.haveamint.com/">Mint</a>.  I already used Mint to track statistics for <a href="http://www.zackgrossbart.com">my own site</a>.  Mint is a more configurable and better looking competitor to <a href="http://www.google.com/analytics/">Google Analytics</a>.  It also lets me hold onto my data instead of sending it to Google.  </p>
<p>Normally Mint is part of your website with a simple declaration like <code>&lt;script src="/mint/?js" type="text/javascript"&gt;&lt;/script&gt;</code>.  This causes the Mint JavaScript to get downloaded, collect information about the browser, and call back to the server without visitors ever knowing.  </p>
<div class="sourcebox">
Get the<br /><a href="https://github.com/zgrossbart/edcalpepper">Source Code</a>
</div>
<p>This type of website data collection is ubiquitous.  Every major site does it and the total volume of personal information they collect is a little scary.  My privacy rant is coming up in a little while.</p>
<p>Mint made collecting data from the Editorial Calendar pretty easy.  It just takes a few lines of JavaScript to get Mint onto the Calendar page:</p>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">jQuery.getScript(<span class="code_string">'http://www.zackgrossbart.com/edcal/mint/?js'</span>, function() {
    edcal.saveFeedbackPref();
});
</pre>
</td>
</tr>
</table>
<p>Now I can dynamically load the mint JavaScript files and save the preference of that when it&#8217;s done.  The dynamic loading is important because I don&#8217;t want to collect data every time and automatic data collection is way too scary.  Right now we prompt the user to let us collect data after they&#8217;ve loaded the calendar three times, and we never collect any data until we get permission.</p>
<h2>Peppers</h2>
<p>Mint collects data about how people came to your site like who they were referred by and what terms they searched for to get there.  It also collects information about the environment like what browser they&#8217;re running and if they have Flash.  I needed data more specific to the calendar like how many weeks are people seeing and how many posts do they have per day.  For that I needed to write a <a href="http://www.haveamint.com/peppermill/">Pepper</a>.</p>
<p>Peppers are the way you extend the capabilities of Mint.  I love puns.  They&#8217;re written in PHP and JavaScript and collect or display extra data.  There are Peppers to tell you how big someone&#8217;s browser window is or who has a secret crush on your website.  My Pepper collects data about the calendar.</p>
<p>This Pepper is open source and like the rest of the code on this blog it is released under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.  That means you can copy it, change it, or use it for free.</p>
<h3>Setting up our Pepper</h3>
<p>The Editorial Calendar Stats Pepper starts with a PHP file called class.php and a big comment.</p>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">&lt;?php
<span class="code_comment">/**************************************************
 Pepper
 
 Developer      : Zack Grossbart
 Plug-in Name   : Edcal Stats
 
 **************************************************/
</span>
 
$installPepper = <span class="code_string">"SI_EdcalStats"</span>;
    
class SI_EdcalStats extends Pepper
{
    var $version    = 1; <span class="code_comment">// Displays as 0.01</span>
    var $info       = array
    (
        <span class="code_string">'pepperName'</span>    =&gt; <span class="code_string">'Editorial Calendar Stats'</span>,
        <span class="code_string">'pepperUrl'</span>     =&gt; <span class="code_string">'http://www.zackgrossbart.com'</span>,
        <span class="code_string">'pepperDesc'</span>    =&gt; <span class="code_string">'Editorial Calendar Pepper'</span>,
        <span class="code_string">'developerName'</span> =&gt; <span class="code_string">'Zack Grossbart'</span>,
        <span class="code_string">'developerUrl'</span>  =&gt; <span class="code_string">'http://www.zackgrossbart.com'</span>
    );

</pre>
</td>
</tr>
</table>
<p>The <code>$info</code> array sets up our Pepper and gives us the basics; a title and description.  With this class we define the functionality and feel of the Pepper using a special set of variables.  We start by defining the panes we&#8217;ll show on the <a href="http://www.zackgrossbart.com/edcal/mint/">statistics page</a>.</p>
<h3>Defining our panes</h3>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">var $panes = array
(
    <span class="code_string">'Editorial Calendar Stats'</span> =&gt; array
    (
        <span class="code_string">'Stats'</span>
    )
);

</pre>
</td>
</tr>
</table>
<p>The Editorial Calendar Stats Pepper just has one pane where it shows the <i>Stats</i> for the calendar plugin.  This makes our <code>$panes</code> array very simple.  </p>
<h3>Collecting data</h3>
<p>The next step is to define the data we want to collect and where we&#8217;ll store it in the database.</p>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">var $manifest = array<span class="footnote"><a href="#edcalnote5">1</a></span>
(
    <span class="code_string">'visit'</span>    =&gt; array
    (
        <span class="code_string">'edcal_weeks'</span> =&gt; <span class="code_string">"SMALLINT(5) NOT NULL DEFAULT '-1'"</span>,
        <span class="code_string">'edcal_posts'</span> =&gt; <span class="code_string">"SMALLINT(5) NOT NULL DEFAULT '-1'"</span>,
        <span class="code_string">'edcal_author'</span> =&gt; <span class="code_string">"TINYINT"</span>
    )
);
    
function onRecord() 
{
    $edcalWeeks =  $this->Mint->escapeSQL($_GET[<span class="code_string">'edcal_weeks'</span>]);<span class="footnote"><a href="#edcalnote6">2</a></span>
    $edcalPosts =  $this->Mint->escapeSQL($_GET[<span class="code_string">'edcal_posts'</span>]);
    $edcalAuthor =  $this->Mint->escapeSQL($_GET[<span class="code_string">'edcal_author'</span>]);
    
    return array
    (
        <span class="code_string">'edcal_weeks'</span> =&gt; (float) $edcalWeeks,
        <span class="code_string">'edcal_posts'</span> =&gt; (float) $edcalPosts,
        <span class="code_string">'edcal_author'</span> =&gt; (boolean) $edcalAuthor
    );
}

</pre>
</td>
</tr>
</table>
<p>The <code>$manifest</code> array<span class="footnote"><a name="edcalnote5">1</a></span> defines the database columns we need.  Mint will create these database columns when this Pepper is installed.  We need columns for the number of visible weeks, the number of posts, and if they are showing authors.  </p>
<p>We populate these fields with the <code>onRecord</code> function.  The values come on the URL so we access the data using the PHP <code>$_GET</code> function<span class="footnote"><a name="edcalnote6">2</a></span>.  </p>
<h3>Querying the calendar with JavaScript</h3>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">function onJavaScript() 
{
    $js = <span class="code_string">"pepper/zackgrossbart/edcalstats/script.js"</span><span class="footnote"><a href="#edcalnote7">1</a></span>;
    if (file_exists($js))
    {
        include_once($js);
    }
}

</pre>
</td>
</tr>
</table>
<p>We access configuration values in the calendar using JavaScript.  We tell Mint about our JavaScript file with the <code>onJavaScript</code> function<span class="footnote"><a name="edcalnote7">1</a></span>.  This adds the <code>script.js</code> file to our Mint request.  </p>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">Mint.SI.EdcalStats = 
{
    onsave  : function() 
    {
        if (edcal) {
            
            <span class="code_comment">/*
             * Collect the number of weeks they are showing
             */</span>
            var val = '&edcal_weeks=' + edcal.weeksPref;<span class="footnote"><a href="#edcalnote1">1</a></span>
            
            
            <span class="code_comment">/*
             * If they are showing authors
             */</span>
            if (edcal.authorPref) {<span class="footnote"><a href="#edcalnote2">2</a></span>
                val += <span class="code_string">'&edcal_author=1'</span>;
            } else {
                val += <span class="code_string">'&edcal_author=0'</span>;
            }
            
            <span class="code_comment">/*
             * Get the average number of posts they have
             * per day
             */</span>
            var dayCounts = [];
            
            jQuery("#cal_cont .dayobj &gt; .postlist").each(function() {
                <span class="code_comment">/*
                 * Don't consider days with zero posts
                 */</span>
                if (jQuery(this).children().length &gt; 0) {
                    dayCounts.push(jQuery(this).children().length);<span class="footnote"><a href="#edcalnote3">3</a></span>
                }
            });
            
            var total = 0;
            for (var i = 0; i &lt; dayCounts.length; i++) {
                total += dayCounts[i];
            }
            
            if (dayCounts.length &gt; 0) {
                val += <span class="code_string">'&edcal_posts='</span> + Math.round(total / dayCounts.length);
            } else {
                val += <span class="code_string">'&edcal_posts=0'</span>;
            }
            
            return val;
                
        }
    }
};

</pre>
</td>
</tr>
</table>
<p>The Editorial Calendar is already running in our JavaScript memory space so calling it from <code>script.js</code> is ideal.  We can call the existing functions to collect the data we need.  The current number of weeks<span class="footnote"><a name="edcalnote1">1</a></span>, the authors preference<span class="footnote"><a name="edcalnote2">2</a></span>, and the average number of posts per day<span class="footnote"><a name="edcalnote3">3</a></span>.  JQuery makes it easy to iterate over the DOM.</p>
<h3>Showing the data</h3>
<p>Now that we&#8217;ve collected all of this data we need to show it on the <a href="http://www.zackgrossbart.com/edcal/mint/">Editorial Calendar Statistics</a> page.  For that we&#8217;ll implement the <code>onDisplay</code> function</p>
<table width="750px" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="code-outline">
<pre class="displaycode">function onDisplay($pane, $tab, $column = '', $sort = '')
{
$html = '';
    switch($pane) 
    {
        case <span class="code_string">'Editorial Calendar Stats'</span>:
        $html  = <span class="code_string">'&lt;table cellspacing="0" class="two-edcal-columns"&gt;'</span>;
        $html .= <span class="code_string">"\r\t&lt;tr&gt;\r"</span>;
        $html .= <span class="code_string">"\t\t&lt;td style=\"padding-right: 4px;\" class=\"left\"&gt;\r"</span>;
        $html .= $this-&gt;getHTML_EdcalWeeks();
        $html .= <span class="code_string">"\t\t&lt;/td&gt;"</span>;
        $html .= <span class="code_string">"\t\t&lt;td class=\"right\"&gt;\r"</span>;
        $html .= $this-&gt;getHTML_EdcalPosts();
        $html .= <span class="code_string">"&lt;br /&gt;"</span>;
        $html .= $this-&gt;getHTML_EdcalAuthor();
        $html .= <span class="code_string">"\t\t&lt;/td&gt;</span>";
        $html .= <span class="code_string">"\r\t&lt;/tr&gt;\r</span>";
        $html .= <span class="code_string">"&lt;/table&gt;\r</span>";
        break;
    }
    
    return $html;
}
</pre>
</td>
</tr>
</table>
<p>We show a little table for each piece of data we&#8217;ve collected and define the contents of that table in separate functions.  </p>
<h2>What about privacy?</h2>
<div class="sourcebox">
View the<br /><a href="http://www.zackgrossbart.com/edcal/mint">Stats Page</a>
</div>
<p>There is a constant tension between collecting data and preserving privacy.  I know we&#8217;re only using this data to improve the plugin, but would I trust a group of strangers to use the data?  Maybe.  </p>
<p>This article is a how to, but it&#8217;s also about transparency.  I want to make it clear what data we&#8217;re collecting and how we&#8217;re using it.  </p>
<p>We went out of our way to make sure the data collected by the calendar is innocuous and non-commercial.  We don&#8217;t sell the data.  Honestly, nobody would want to buy it.  </p>
<p>The whole point is to make the calendar better.  The more we understand how it&#8217;s being used the better we can make the design.  The calendar should be simple and easy to use, but simple isn&#8217;t so simple.  Making something that feels good means we have to know how people use it and what feels good to them.  These statistics help us do just that.</p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/edcal_stats/feed/</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>Creating a Multi-Valued Auto-Complete Field Using GWT SuggestBox and REST</title>
		<link>http://www.zackgrossbart.com/hackito/gwt-rest-auto/</link>
					<comments>http://www.zackgrossbart.com/hackito/gwt-rest-auto/#comments</comments>
		
		<dc:creator><![CDATA[Bess Siegal]]></dc:creator>
		<pubDate>Wed, 14 Jul 2010 20:32:14 +0000</pubDate>
				<category><![CDATA[GWT]]></category>
		<category><![CDATA[JavaScript]]></category>
		<guid isPermaLink="false">http://www.zackgrossbart.com/hackito/?p=419</guid>

					<description><![CDATA[This is a guest post written by Bess Siegal.  Bess and I work together and she recently created an auto-complete field that handles multiple values.  She stopped by to show us how it works, provide an open source example, and give you all the details you need to create a multi-value auto-complete field in <a href="http://code.google.com/webtoolkit/">GWT</a> using <a href="/hackito/gwt-rest/">REST</a>.]]></description>
										<content:encoded><![CDATA[<p></p><link type="text/css" rel="stylesheet" href="/extras/multisuggest/MultivalueSuggestBoxExample.css"> <script type="text/javascript" language="javascript" src="/extras/multisuggest/multivaluesuggestboxexample/multivaluesuggestboxexample.nocache.js"></script> <iframe src="javascript:" id="__gwt_historyFrame" tabIndex="-1" style="position:absolute;width:0;height:0;border:0"></iframe><br />
<style type="text/css"> body {font-size: 10px;} </style>
<p>
This is a guest post written by <a href="#bess">Bess Siegal</a>.  Bess and I work together and she recently created an auto-complete field that handles multiple values.  She stopped by to show us how it works, provide an open source example, and give you all the details you need to create a multi-value auto-complete field in <a href="http://code.google.com/webtoolkit/">GWT</a> using <a href="/hackito/gwt-rest/">REST</a>.
</p>
<h2>More Than Just Another Type-Ahead Script</h2>
<p>
Type ahead fields are ubiquitous.  Type <i>ja</i> into Google and it prompts you for Jamn 94.5, Java, and Jack Johnson.  These single value fields work well for search, but don&#8217;t scale to multiple values.  Our latest tool allows users to search for multiple users, roles, and other objects using an auto-complete field, and for that we needed something new.
</p>
<p>
This article shows you how to create a multi-valued auto-complete field using the GWT SuggestBox and REST.  Communicating between the client and server with REST gives this example a strong separation between the client and the server.  I proved it using a  server-side component written as a Java servlet, then swapping it out, thanks to <a href="/hackito/about-2/">Zack</a>, with a server-side component written in PHP.
</p>
<p>
This sample uses JavaScript, HTML, CSS, and nothing else.  It runs in all the major browsers and all the way back to Internet Explorer 6.  It&#8217;s also a good introduction to REST and how to use it from a browser.
</p>
<h2>Try It</h2>
<p>The multi-value auto-complete field can handle any type of data.  Here&#8217;s an example that searches for crayon colors.  </p>
<h4>Search for blue, mac, or *</h4>
<div id="multivalueFieldContainer"></div>
<div id="sendButtonContainer"></div>
<p><div id="valuesContainer"></div>
<div id="valueMapContainer"></div>
</p>
<h2>A Closer Look</h2>
<p>I began by investigating the GWT <a href="http://gwt.google.com/samples/KitchenSink/KitchenSink.html#Lists">SuggestBox</a>.  It&#8217;s not multi-valued, but it does automatically send a request and shows a suggestion list popup when you type into its text field. By default its suggestions come from a <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestBox.html"><code>MultiWordSuggestOracle</code></a>, which means all the suggestions reside on the client.
</p>
<p><a href="http://development.lombardi.com/?p=39">Using the GWT SuggestBox with RPC</a> by <a href="http://development.lombardi.com/?author=3">Alex Moffat</a> explains how to retrieve suggestions from a remote source using RPC by creating a custom <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestOracle.html"><code>SuggestOracle</code></a>.  It got me started on creating my own <code>SuggestOracle</code> using REST instead of using GWT&#8217;s RPC.  The <a href="http://jquery.bassistance.de/autocomplete/demo/">jQuery auto-complete plugin</a> by <a href="http://bassistance.de/about/">Jörn Zaefferer</a> inspired me to make it multi-valued.  </p>
<h3>Working Example</h3>
<div class="sourcebox">
Get the<br />
<a href="/extras/multisuggest/MultivalueSuggestBoxExample.zip">source code</a>
</div>
<p>I&#8217;ll walk you through the working code example and explain how it:</p>
<ul>
<li>retrieves suggestions using REST</li>
<li>allows for multiple selection</li>
<li>performs as an auto-completer even for multiple values that have been pasted in</li>
<li>allows for browsing through large data sets without having to use a div overflow scrollbar</li>
</ul>
<h4>REST Endpoint</h4>
<p>
The REST Endpoint can be any HTTP URL that supporst GET and takes the following parameters.</p>
<ul>
<li>q &#8211; the query</li>
<li>indexFrom &#8211; the 0-based starting index</li>
<li>indexTo &#8211; the last index, inclusive</li>
</ul>
<p>The endpoint returns <a href="http://www.json.org/">JSON</a> in the following format:</p>
<pre>
{ 
 "TotalSize" : 25,
 "Options" : [
              {"Value" : "#9ACEEB", "DisplayName" : "Cornflower"},
              {"Value" : "#CC6666", "DisplayName" : "Fuzzy Wuzzy"}
             ]
}
</pre>
<p>&#8220;TotalSize&#8221; is the total number of results yielded by the query and &#8220;Options&#8221; is the array of name-value pairs in the results from indexFrom and to indexTo.</p>
<p>This well-defined API allows for a server implementation in any language.  The <a href="http://www.zackgrossbart.com/extras/multisuggest/MultivalueSuggestBoxExample.html">source code</a> includes a Java servlet that serves this purpose and also the endpoint Zack wrote in <a href="http://php.net/index.php">PHP</a> that drives the <a href="http://www.zackgrossbart.com/extras/multisuggest/MultivalueSuggestBoxExample.html">live demo</a> in this article.
</p>
<h4>MultivalueSuggestBox</h4>
<p>
The <code>MultivalueSuggestBox</code> is a custom GWT widget that utilizes the GWT <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestBox.html"><code>SuggestBox</code></a>.  It extends <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/Composite.html"><code>Composite</code></a> with a <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/FlowPanel.html"><code>FlowPanel</code></a> as its main widget.  It encapsulates six inner classes that support server-side data retrieval.
</p>
<p>
Below is the constructor.  Its arguments are the REST endpoint URL and a boolean to specify multi-value.<span class="footnote"><a name="suggnote_note1" href="#suggnote_code1">1</a></span>  A <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/FlowPanel.html"><code>FlowPanel</code></a><span class="footnote"><a name="suggnote_note2" href="#suggnote_code2">2</a></span> is instantiated so that a <code>FormFeedback</code><span class="footnote"><a name="suggnote_note3" href="#suggnote_code3">3</a></span> control can be included next to the <code>SuggestBox</code>.  The <code>FormFeedback</code> is a custom GWT widget that shows an icon indicating the status of the control.  This lets the user know whether the control is loading and more importantly, helps to identify invalid values.
</p>
<p>
A <code>SuggestBox</code> is instantiated using the <code>RestSuggestOracle</code><span class="footnote"><a name="suggnote_note4" href="#suggnote_code4">4</a></span>.<br />
The <code>m_valueMap</code><span class="footnote"><a name="suggnote_note5" href="#suggnote_code5">5</a></span> is instantiated to hold all the valid values found, keyed by name. </p>
<pre>    
/**
 * Constructor.
 * @param the URL for the REST endpoint.  
 * @param isMultivalued - true for allowing multiple values
 */
public MultivalueSuggestBox(String restEndpointUrl, boolean isMultivalued)<span class="footnote"><a name="suggnote_code1" href="#suggnote_note1">1</a></span>
{
    m_restEndpointUrl = restEndpointUrl;
    m_isMultivalued = isMultivalued;

    FlowPanel panel = new FlowPanel();<span class="footnote"><a href="#suggnote_note2" name="suggnote_code2">2</a></span>
    TextBoxBase textfield;
    if (isMultivalued) {
        panel.addStyleName("textarearow");
        textfield = new TextArea();
    } else {
        panel.addStyleName("textfieldrow");
        textfield = new TextBox();
    }
        
    //Create our own SuggestOracle that queries REST endpoint
    SuggestOracle oracle = new RestSuggestOracle();<span class="footnote"><a href="#suggnote_note4" name="suggnote_code4">4</a></span>
    //intialize the SuggestBox
    m_field = new SuggestBox(oracle, textfield);
    if (isMultivalued) {
        //have to do this here b/c gwt suggest box wipes 
        //style name if added in previous if
        textfield.addStyleName("multivalue");            
    }
    m_field.addStyleName("wideTextField");
    m_field.addSelectionHandler(this);
        
    panel.add(m_field);
    m_feedback = new FormFeedback();<span class="footnote"><a href="#suggnote_note3" name="suggnote_code3">3</a></span>
    panel.add(m_feedback);        
        
    initWidget(panel);
      
    m_valueMap = new HashMap&lt;String, String&gt;();<span class="footnote"><a href="#suggnote_note5" name="suggnote_code5">5</a></span>
       
    resetPageIndices();        
}
</pre>
</p>
<h4>RestSuggestOracle</h4>
<p>
<code>RestSuggestOracle</code><span class="footnote"><a name="suggnote_note6" href="#suggnote_code6">6</a></span>, like all the other classes mentioned in the remainder of this article, is an inner class within <code>MultivalueSuggestBox</code>.  It extends <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestOracle.html"><code>SuggestOracle</code></a> implementing <code>requestSuggestions</code><span class="footnote"><a name="suggnote_note7" href="#suggnote_code7">7</a></span> and overriding <code>isDisplayStringHTML</code> to return true.  It creates a timer<span class="footnote"><a name="suggnote_note8" href="#suggnote_code8">8</a></span> that is reset whenever the user types<span class="footnote"><a name="suggnote_note9" href="#suggnote_code9">9</a></span> because we only want to query the server when the user has paused in their typing.  This will prevent overloading the server with unnecessary overlapping requests.  After the timer has elapsed, <code>getSuggestions</code><span class="footnote"><a name="suggnote_note10" href="#suggnote_code10">10</a></span> and conditionally <code>findExactMatches</code><span class="footnote"><a name="suggnote_note11" href="#suggnote_code11">11</a></span> are called. </p>
<pre>
/**
* A custom Suggest Oracle
*/
private class RestSuggestOracle<span class="footnote"><a name="suggnote_code6" href="#suggnote_note6">6</a></span> extends SuggestOracle
{
private SuggestOracle.Request m_request;
private SuggestOracle.Callback m_callback;
private Timer m_timer;

RestSuggestOracle()
{
    m_timer = new Timer()<span class="footnote"><a name="suggnote_code8" href="#suggnote_note8">8</a></span> {
        
        @Override
        public void run()
        {
            /*
             * The reason we check for empty string is found at
             * http://development.lombardi.com/?p=39 --
             * paraphrased, if you backspace quickly the contents of the field 
             * are emptied but a query for a single character is still executed.
             * Workaround for this is to check for an empty string field here.
             */
            
            if (!m_field.getText().trim().isEmpty()) {
                if (m_isMultivalued) {
                    //calling this here in case a user is trying to correct the 
                    //"kev" value of Allison Andrews, Kev, Josh Nolan or pasted 
                    //in multiple values
                    findExactMatches();<span class="footnote"><a name="suggnote_code11" href="#suggnote_note11">11</a></span>
                }                    
                getSuggestions();<span class="footnote"><a name="suggnote_code10" href="#suggnote_note10">10</a></span>
            }
        }
    };
}

@Override
public void requestSuggestions(SuggestOracle.Request request, 
			       SuggestOracle.Callback callback)<span class="footnote"><a name="suggnote_code7" href="#suggnote_note7">7</a></span>
{                
    //This is the method that gets called by the SuggestBox whenever typing in the text field            
    m_request = request;
    m_callback = callback;
    
    //reset the indexes (b/c NEXT and PREV call getSuggestions directly)
    resetPageIndices();
    
    //If the user keeps triggering this event (e.g., keeps typing), cancel and restart the timer
    m_timer.cancel();        
    m_timer.schedule(DELAY);<span class="footnote"><a name="suggnote_code9" href="#suggnote_note9">9</a></span>
}

</pre>
</p>
<h4>getSuggestions</h4>
<p>First we&#8217;ll look at <code>getSuggestions</code><span class="footnote"><a name="suggnote_note12" href="#suggnote_code12">12</a></span>.  This method performs the query for the contents of the suggestion list popup.  First, it determines the search term.  When not multi-valued, the search term is the contents of the suggest box text field.  If it is  multi-valued, the search term is the part of the string after the last <code>DISPLAY_SEPARATOR</code>, in this case a comma. It then sets the <code>FormFeedback</code> widget to a <code>LOADING</code> state, then calls <code>queryOptions</code>.   </p>
<pre>
private void getSuggestions()<span class="footnote"><a name="suggnote_code12" href="#suggnote_note12">12</a></span>
{
    String query = m_request.getQuery();
    
    //find the last thing entered up to the last separator
    //and use that as the query
    if (m_isMultivalued) {
        int sep = query.lastIndexOf(DISPLAY_SEPARATOR);
        if (sep &gt; 0) {
            query = query.substring(sep + DISPLAY_SEPARATOR.length());                
        }
    }
    query = query.trim();
    
    //do not query if it's just an empty String
    //also do not get suggestions you've already got an exact match for 
    //this string in the m_valueMap
    if (query.length() &gt; 0 &amp;&amp; m_valueMap.get(query) == null) {
        updateFormFeedback(FormFeedback.LOADING, null);               
                                    
        queryOptions( 
                query,
                m_indexFrom,
                m_indexTo,
            new RestSuggestCallback(m_request, m_callback, query));
    }
}
</pre>
<h4>queryOptions</h4>
<p>The <code>queryOptions</code><span class="footnote"><a name="suggnote_note13" href="#suggnote_code13">13</a></span> method sends a GET request to the URL of the REST endpoint passed to the constructor of <code>MultivalueSuggestBox</code><span class="footnote"><a href="#suggnote_code1">1</a></span>.  It uses the GWT <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/http/client/RequestBuilder.html"><code>RequestBuilder</code></a> object.  <code>queryOptions</code> converts the response from <a href="http://en.wikipedia.org/wiki/Json">JSON</a> to <a href="http://en.wikipedia.org/wiki/Type_safety">type safe</a> Java beans<span class="footnote"><a href="#suggnote_code14" name="suggnote_note14">14</a></span>.  The arguments are the query string, the indices of the result set desired, and an <code>OptionQueryCallback</code><span class="footnote"><a name="suggnote_note15" href="#suggnote_code15">15</a></span>.  </p>
<pre>
/**
 * Retrieve Options (name-value pairs) that are suggested from the REST endpoint
 * @param query - the String search term 
 * @param from - the 0-based begin index int
 * @param to - the end index inclusive int
 * @param callback - the OptionQueryCallback to handle the response
 */
private void queryOptions(final String query, final int from, final int to, 
                          final OptionQueryCallback callback)<span class="footnote"><a name="suggnote_code13" href="#suggnote_note13">13</a></span>
{
    RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, 
        URL.encode(m_restEndpointUrl + "?q=" + query + "&amp;indexFrom=" + 
        from + "&amp;indexTo=" + to));
        
    // Set our headers
    builder.setHeader("Accept", "application/json");
    builder.setHeader("Accept-Charset", "UTF-8");
                
    builder.setCallback(new RequestCallback() {
            
        @Override
        public void onResponseReceived(com.google.gwt.http.client.Request request, 
                                       Response response)
        {
            JSONValue val = JSONParser.parse(response.getText());
            JSONObject obj = val.isObject();
            int totSize = (int) obj.get(OptionResultSet.TOTAL_SIZE).isNumber().doubleValue();
            OptionResultSet options = new OptionResultSet(totSize);<span class="footnote"><a href="#suggnote_note14" name="suggnote_code14">14</a></span>
            JSONArray optionsArray = obj.get(OptionResultSet.OPTIONS).isArray();

            if (options.getTotalSize() &gt; 0 &amp;&amp; optionsArray != null) {
                    
                for (int i = 0; i &lt; optionsArray.size(); i++) {                        
                    JSONObject jsonOpt = optionsArray.get(i).isObject();
                    Option option = new Option();
                    option.setName(jsonOpt.get(OptionResultSet.DISPLAY_NAME).isString().stringValue());
                    option.setValue(jsonOpt.get(OptionResultSet.VALUE).isString().stringValue());
                    options.addOption(option);
                }
            }                    
            callback.success(options);
        }

        @Override
        public void onError(com.google.gwt.http.client.Request request, 
                            Throwable exception)
        {
            callback.error(exception);
        }
    });
        
    try {
        builder.send();
    } catch (RequestException e) {
        updateFormFeedback(FormFeedback.ERROR, "Error: " + e.getMessage());
    }
}
</pre>
</p>
<h4>OptionQueryCallback</h4>
<p>The <code>OptionQueryCallback</code> abstract class handles success and error conditions from the REST call.</p>
<pre>
/**
 * Handles success and error conditions from the REST call
 */
private abstract class OptionQueryCallback<span class="footnote"><a name="suggnote_code15" href="#suggnote_note15">15</a></span>
{
    abstract void success(OptionResultSet optResults);
    abstract void error(Throwable exception);
}
</pre>
</p>
<h4>RestSuggestCallback</h4>
<p><code>RestSuggestCallback</code><span class="footnote"><a name="suggnote_note16" href="#suggnote_code16">16</a></span> extends <code>OptionQueryCallback</code><span class="footnote"><a name="suggnote_note15" href="#suggnote_code15">15</a></span> and is the object passed to <code>queryOptions</code><span class="footnote"><a href="#suggnote_code13">13</a></span> from <code>getSuggestions</code><span class="footnote"><a href="#suggnote_code12">12</a></span>.  The <code>RestSuggestCallback</code> constructor takes the <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestOracle.Request.html"><code>SuggestOracle.Request</code></a>, <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestOracle.Callback.html"><code>SuggestOracle.Callback</code></a>, and the query as arguments.
</p>
<p>
Once the request succeeds <code>RestSuggestCallback</code> evaluates the response:
</p>
<ul>
<li>if the total size is less than one, it means there were no suggestions returned from the REST endpoint, so the <code>FormFeedback</code> shows an <!-- Zack: the form feedback icons are really small.  You could just embed them right in the text here instead of saying ERROR --><code>ERROR</code> status.<span class="footnote"><a name="suggnote_note17" href="#suggnote_code17">17</a></span>  The <code>OptionSuggestion</code> <code>ArrayList</code> remains empty.<span class="footnote"><a name="suggnote_note18" href="#suggnote_code18">18</a></span></li>
<li>if the total size is equal to one, then there was only one suggestion.  In this case we skip the popup and just show the value in the text field.  The name of the <code>Option</code> replaces the string after the last <code>DISPLAY_SEPARATOR</code>  <span class="footnote"><a name="suggnote_note19" href="#suggnote_code19">19</a></span>.   The  <code>FormFeedback</code> shows a <!-- Zack: you can use the icon here too --><code>VALID</code> status<span class="footnote"><a name="suggnote_note20" href="#suggnote_code20">20</a></span>.  The name and value are added to the value map.<span class="footnote"><a name="suggnote_note21" href="#suggnote_code21">21</a></span>.   The <code>OptionSuggestion</code> <code>ArrayList</code> remains empty.<span class="footnote"><a name="suggnote_note18" href="#suggnote_code18">18</a></span></li>
<li>if the total size is greater than 1, the The <code>OptionSuggestion</code> <code>ArrayList</code> is built up<span class="footnote"><a name="suggnote_note22" href="#suggnote_code22">22</a></span> and these suggestions are sent back to the <code>SuggestOracle.Callback</code><span class="footnote"><a name="suggnote_note23" href="#suggnote_code23">23</a></span>. We also conditionally add the next and previous options for scrolling in the results.<span class="footnote"><a name="suggnote_note24" href="#suggnote_code24">24</a></span>  The <code>FormFeedback</code> shows an <!-- Zack: and another icon --><code>ERROR</code> status until the user selects a valid option.<span class="footnote"><a name="suggnote_note25" href="#suggnote_code25">25</a></span>  </li>
</ul>
<pre>
/**
 * A custom callback that has the original SuggestOracle.Request 
 * and SuggestOracle.Callback
 */
private class RestSuggestCallback extends OptionQueryCallback<span class="footnote"><a name="suggnote_code16" href="#suggnote_note16">16</a></span>
{
    private SuggestOracle.Request m_request;
    private SuggestOracle.Callback m_callback;
    private String m_query; //this may be different from m_request.getQuery when multivalued it's only the substring after the last delimiter
        
    RestSuggestCallback(Request request, Callback callback, String query)
    {
        m_request = request;
        m_callback = callback;
        m_query = query;
    }

    public void success(OptionResultSet optResults)
    {
        SuggestOracle.Response resp = new SuggestOracle.Response();
        List&lt;OptionSuggestion&gt; suggs = new ArrayList&lt;OptionSuggestion&gt;();<span class="footnote"><a name="suggnote_code18" href="#suggnote_note18">18</a></span>
        int totSize = optResults.getTotalSize();
            
        if (totSize &lt; 1) {<span class="footnote"><a name="suggnote_code16" href="#suggnote_note16">16</a></span>
            //if there were no suggestions, then it's an invalid value
            updateFormFeedback(FormFeedback.ERROR, "Invalid: " + query);<span class="footnote"><a name="suggnote_code17" href="#suggnote_note17">17</a></span>
                
        } else if (totSize == 1) {
            //it's an exact match, so do not bother with showing suggestions, 
            Option o = optResults.getOptions()[0];
            String displ = o.getName();
                
            //remove the last bit up to separator
            m_field.setText(getFullReplaceText(displ, m_request.getQuery()));<span class="footnote"><a name="suggnote_code19" href="#suggnote_note19">19</a></span>
                
            //it's valid!
            updateFormFeedback(FormFeedback.VALID, null);<span class="footnote"><a name="suggnote_code20" href="#suggnote_note20">20</a></span>

            //set the value into the valueMap
            putValue(displ, o.getValue());<span class="footnote"><a name="suggnote_code21" href="#suggnote_note21">21</a></span>

        } else {
            //more than 1 so show the suggestions
                
            //if not at the first page, show PREVIOUS
            if (m_indexFrom &gt; 0) {
                OptionSuggestion prev = new OptionSuggestion(
                    OptionSuggestion.PREVIOUS_VALUE, m_request.getQuery());
                suggs.add(prev);
            }
                
            // show the suggestions
            for (Option o : optResults.getOptions()) {
                OptionSuggestion sugg = new OptionSuggestion(
	            o.getName(), o.getValue(), m_request.getQuery(), m_query);
                suggs.add(sugg);<span class="footnote"><a name="suggnote_code22" href="#suggnote_note22">22</a></span>
            }
                
            //if there are more pages, show NEXT
            if (m_indexTo &lt; totSize) {
                OptionSuggestion next = new OptionSuggestion(
                    OptionSuggestion.NEXT_VALUE, m_request.getQuery());
                suggs.add(next);<span class="footnote"><a name="suggnote_code24" href="#suggnote_note24">24</a></span>
            }
                
            //nothing has been picked yet, so let the feedback show an error (unsaveable)
            updateFormFeedback(FormFeedback.ERROR, "Invalid: " + m_query);<span class="footnote"><a name="suggnote_code25" href="#suggnote_note25">25</a></span>
        }

        //it's ok (and good) to pass an empty suggestion list back to the suggest box's callback method
        //the list is not shown at all if the list is empty.
        resp.setSuggestions(suggs);
        m_callback.onSuggestionsReady(m_request, resp);<span class="footnote"><a name="suggnote_code23" href="#suggnote_note23">23</a></span>
    }

    @Override
    public void error(Throwable exception)
    {
        updateFormFeedback(FormFeedback.ERROR, "Invalid: " + m_query);
    }    
}
</pre>
</p>
<h4>OptionSuggestion</h4>
<p><code>OptionSuggestion</code> objects are collected into a <code>List</code> and passed to <code>SuggestOracle.Callback.onSuggestionsReady</code><span class="footnote"><a href="#suggnote_code24">24</a></span>.  It extends <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/user/client/ui/SuggestOracle.Suggestion.html"><code>SuggestOracle.Suggestion</code></a> overriding <code>getDisplayString</code> and <code>getReplacementString</code> and adding <code>getValue</code> and <code>getName</code> methods for <code>Option</code> IDs and names.  You could add more properties depending on your needs.  In this example, the names are the crayon colors and the values are their corresponding hex codes.</p>
<p><code>OptionSuggestion</code> has two constructors.  One is for navigation<span class="footnote"><a name="suggnote_note26" href="#suggnote_code26">26</a></span> and the other is for an actual option<span class="footnote"><a name="suggnote_note27" href="#suggnote_code27">27</a></span>.
</p>
<p>
Since <code>RestSuggestOracle.isDisplayStringHTML</code> is true, HTML can be used for the display string.  In the body of the first constructor, the HTML returned is a div with a class that is included in the css.  It will show an appropriate image to indicate navigation.  In the body of the second constructor, HTML bold tags are used to highlight the query search term within each suggestion in the list popup.  The value returned by <code>getReplacementString</code><span class="footnote"><a name="suggnote_note28" href="#suggnote_code28">28</a></span> is determined by calling <code>getFullReplaceText</code> so that the text box does not lose any previously selected options in the multi-value case, and only the portion of the contents of the text field after the last <code>DISPLAY_SEPARATOR</code> is replaced.</p>
<pre>    
/**
 * Constructor for navigation options
 * @param nav - next or previous value
 * @param currentTextValue - the current contents of the text box
 */    
OptionSuggestion(String nav, String currentTextValue)<span class="footnote"><a name="suggnote_code26" href="#suggnote_note26">26</a></span>
{
    if (NEXT_VALUE.equals(nav)) {
        m_display = "&lt;div class=\"autocompleterNext\" title=\"Next\"&gt;&lt;/div&gt;";
    } else {
        m_display = "&lt;div class=\"autocompleterPrev\" title=\"Previous\"&gt;&lt;/div&gt;";
    }
    m_replace = currentTextValue;
    m_value = nav;
}
    
/**
 * Constructor for regular options
 * @param displ - the name of the option
 * @param val - the value of the option
 * @param replacePre - the current contents of the text box
 * @param query - the query
 */
OptionSuggestion(String displ, String val, String replacePre, String query)<span class="footnote"><a name="suggnote_code27" href="#suggnote_note27">27</a></span>
{
    m_name = displ;
    int begin = displ.toLowerCase().indexOf(query.toLowerCase());
    if (begin &gt;= 0) {
        int end = begin + query.length();
        String match = displ.substring(begin, end);
        m_display = displ.replaceFirst(match, "&lt;b&gt;" + match + "&lt;/b&gt;");
    } else {
        //may not necessarily be a part of the query, for example if "*" was typed.
        m_display = displ;
    }
    m_replace = getFullReplaceText(displ, replacePre);<span class="footnote"><a name="suggnote_code28" href="#suggnote_note28">28</a></span>
    m_value = val;
}    
</pre>
</p>
<h4>onSelection</h4>
<p><code>MultivalueSuggestBox</code> implements <a href="http://google-web-toolkit.googlecode.com/svn/javadoc/2.0/com/google/gwt/event/logical/shared/SelectionHandler.html"><code>SelectionHandler&lt;Suggestion&gt;</code></a>, so <code>onSelection</code><span class="footnote"><a name="suggnote_note29" href="#suggnote_code29">29</a></span> is called after the user chooses an option among the items shown in the <code>SuggestBox</code> list popup.  If an option is selected, the <code>FormFeedback</code> shows a <!-- Zack: another icon here --><code>VALID</code> status and the option&#8217;s name and value are put<span class="footnote"><a name="suggnote_note30" href="#suggnote_code30">30</a></span> into the value map.  If the selection is one of the navigation options, the indices are changed and <code>getSuggestions</code> is called again<span class="footnote"><a name="suggnote_note31" href="#suggnote_code31">31</a></span>.  Having the next/previous options allows for browsing of the result set within a reasonably sized popup that does not need scrollbars.</p>
<pre>
@Override
public void onSelection(SelectionEvent&lt;Suggestion&gt; event)<span class="footnote"><a name="suggnote_code29" href="#suggnote_note29">29</a></span>
{
    Suggestion suggestion = event.getSelectedItem();
    if (suggestion instanceof OptionSuggestion) {
        OptionSuggestion osugg = (OptionSuggestion) suggestion;
        //if NEXT or PREVIOUS were selected, requery but bypass the timer
        String value = osugg.getValue();
        if (OptionSuggestion.NEXT_VALUE.equals(value)) {
            m_indexFrom += PAGE_Size;
            m_indexTo += PAGE_Size;
            
            RestSuggestOracle oracle = (RestSuggestOracle) m_field.getSuggestOracle();
            oracle.getSuggestions();<span class="footnote"><a name="suggnote_code31" href="#suggnote_note31">31</a></span>
            
        } else if (OptionSuggestion.PREVIOUS_VALUE.equals(value)) {
            m_indexFrom -= PAGE_Size;
            m_indexTo -= PAGE_Size;
            
            RestSuggestOracle oracle = (RestSuggestOracle) m_field.getSuggestOracle();
            oracle.getSuggestions();
            
        } else {
            //made a valid selection
            updateFormFeedback(FormFeedback.VALID, null);
            
            //add the option's value to the value map            
            putValue(osugg.getName(), value);<span class="footnote"><a name="suggnote_code30" href="#suggnote_note30">30</a></span>
            
            //put the focus back into the textfield so user
            //can enter more
            m_field.setFocus(true);
        }
    }
}

</pre>
</p>
<h4>findExactMatches</h4>
<p>Now let&#8217;s go back and look at <code>findExactMatches</code><span class="footnote"><a name="suggnote_note32" href="#suggnote_code32">32</a></span>.  This is only called if multi-valued was specified, and is useful because the user might want to copy and paste an entire set of names or need to change a name that is in the middle of the text field.  <!--insert image here? -->  If there is more than one name in the text field, a query is executed for every name that does not already have a value in the value map.  It resets the member variables <code>m_findExactMatchesTotal</code>, <code>m_findExactMatchesFound</code>, and <code>m_findExactMatchesNot</code><span class="footnote"><a name="suggnote_note33" href="#suggnote_code33">33</a></span>, then for every non-valued term it calls <code>findExactMatch</code><span class="footnote"><a name="suggnote_note34" href="#suggnote_code34">34</a></span>.</p>
<pre>
/**
 * If there is more than one key in the text field,
 * check that every key has a value in the map.
 * For any that do not, try to find its exact match.
 */
private void findExactMatches()<span class="footnote"><a name="suggnote_code32" href="#suggnote_note32">32</a></span>
{
    String text = m_field.getText();
    String[] keys = text.split(DISPLAY_SEPARATOR.trim());
    int len = keys.length;       
    if (len &lt; 2) {
        //do not continue.  if there&#039;s 1, it is the last one, and getSuggestions can handle it
        return;
    }

    m_findExactMatchesTotal = 0;
    m_findExactMatchesFound = 0;
    m_findExactMatchesNot.clear();<span class="footnote"><a name="suggnote_code33" href="#suggnote_note33">33</a></span>
    for (int pos = 0; pos &lt; len; pos++) {
        String key = keys[pos].trim();

        if (!key.isEmpty()) {
            String v = m_valueMap.get(key);
            if (null == v) {
                m_findExactMatchesTotal++;
            }
        }
    }
    //then loop through again and try to find them
    /*
     * We may have invalid values due to a multi-value copy-n-paste,
     * or going back and messing with a middle or first key;
     * so for each invalid value, try to find an exact match.
     */
    for (int pos = 0; pos &lt; len; pos++) {
        String key = keys[pos].trim();
        if (!key.isEmpty()) {
            String v = m_valueMap.get(key);
            if (null == v) {
                findExactMatch(key, pos);<span class="footnote"><a name="suggnote_code34" href="#suggnote_note34">34</a></span>
            }
        }
    }        
}
</pre>
</p>
<h4>findExactMatch</h4>
<p><code>findExactMatch</code><span class="footnote"><a name="suggnote_note35" href="#suggnote_code35">35</a></span> updates the <code>FormFeedback</code> to show a <!-- Zack: another icon --><code>LOADING</code> status.  It then calls <code>queryOptions</code><span class="footnote"><a href="#suggnote_code13">13</a></span>, but this time the indices are hard-coded from zero to some relatively small amount so the exact match can attempt to be found within the top suggestions.
</p>
<p>
An anonymous <code>OptionQueryCallback</code><span class="footnote"><a name="suggnote_note36" href="#suggnote_code36">36</a></span> evaluates the response:
</p>
<ul>
<li>if the total size is equal to one, then the one option is the match, so the name and value will be placed in the value map and <code>m_findExactMatchesFound</code> is incremented.<span class="footnote"><a name="suggnote_note37" href="#suggnote_code37">37</a></span></li>
<li>if the total size is greater than one, it loops through the result set to find if there is an exact match within those top suggestions, and if so, the name and value will be placed in the value map and <code>m_findExactMatchesFound</code> is incremented.<span class="footnote"><a name="suggnote_note38" href="#suggnote_code38">38</a></span></li>
<li>if an exact match is not found, then the term is added to the <code>m_findExactMatchesNot</code> list.<span class="footnote"><a name="suggnote_note39" href="#suggnote_code39">39</a></span></li>
</ul>
<p>Once <code>m_findExactMatchesFound + m_findExactMatchesNot.size()</code> is equal to <code>m_findExactMatchesTotal</code>, the <code>FormFeedback</code> will be updated to either show <!-- Zack: another icon --><code>VALID</code> if all exact matches were found<span class="footnote"><a name="suggnote_note40" href="#suggnote_code40">40</a></span> or <!-- Zack: another icon --><code>ERROR</code> if any name could not be exactly matched.  All names that could not be matched will be shown within the tooltip (i.e., title) of the <code>FormFeedback</code>.<span class="footnote"><a name="suggnote_note41" href="#suggnote_code41">41</a></span></p>
<pre>
private void findExactMatch(final String displayValue, final int position)<span class="footnote"><a name="suggnote_code35" href="#suggnote_note35">35</a></span>
{
    updateFormFeedback(FormFeedback.LOADING, null);
    
    queryOptions( 
        displayValue,
            0,
            FIND_EXACT_MATCH_QUERY_LIMIT, 
        new OptionQueryCallback() {<span class="footnote"><a name="suggnote_code36" href="#suggnote_note36">36</a></span>
            
            @Override
            public void error(Throwable exception)
            {
                // an exact match couldn't be found, just increment not found
                m_findExactMatchesNot.add(displayValue);
                finalizeFindExactMatches();
            }

            @Override
            public void success(OptionResultSet optResults)
            {
                int totSize = optResults.getTotalSize();
                if (totSize == 1) {
                    //an exact match was found, so place it in the value map
                    Option option = optResults.getOptions()[0];                        
                    extactMatchFound(position, option);<span class="footnote"><a name="suggnote_code37" href="#suggnote_note37">37</a></span>
                } else {
                    //try to find the exact matches within the results
                    boolean found = false;
                    for (Option option : optResults.getOptions()) {
                        if (displayValue.equalsIgnoreCase(option.getName())) {
                            extactMatchFound(position, option);<span class="footnote"><a name="suggnote_code38" href="#suggnote_note38">38</a></span>
                            found = true;
                            break;
                        }                            
                    }
                    if (!found) {
                        m_findExactMatchesNot.add(displayValue);<span class="footnote"><a name="suggnote_code39" href="#suggnote_note39">39</a></span>
                    }
                }
                finalizeFindExactMatches();                    
            }

            private void extactMatchFound(final int position, Option option)
            {
                putValue(option.getName(), option.getValue());

                //and replace the text
                String text = m_field.getText();
                String[] keys = text.split(DISPLAY_SEPARATOR.trim());
                keys[position] = option.getName();
                String join = "";
                for (String n : keys) {
                    join += n.trim() + DISPLAY_SEPARATOR;
                }
                join = trimLastDelimiter(join, DISPLAY_SEPARATOR);
                m_field.setText(join);
                
                m_findExactMatchesFound++;
            }
            
            private void finalizeFindExactMatches()
            {
                if (m_findExactMatchesFound + m_findExactMatchesNot.size() == 
                        m_findExactMatchesTotal) {
                    //when the found + not = total, we're done
                    if (m_findExactMatchesNot.size() &gt; 0) {
                        String join = "";
                        for (String val : m_findExactMatchesNot) {
                            join += val.trim() + DISPLAY_SEPARATOR;
                        }
                        join = trimLastDelimiter(join, DISPLAY_SEPARATOR);                                
                        updateFormFeedback(FormFeedback.ERROR, "Invalid:" + join);<span class="footnote"><a name="suggnote_code41" href="#suggnote_note41">41</a></span>
                    } else {
                        updateFormFeedback(FormFeedback.VALID, null);<span class="footnote"><a name="suggnote_code40" href="#suggnote_note40">40</a></span>
                    }
                }
            }
        });
}
</pre>
</p>
<p>
You can call <code>getValue</code><span class="footnote"><a name="suggnote_note42" href="#suggnote_code42">42</a></span> when the values of the selected options are needed.  This implementation of getValue returns a concatenated string of all the values delimited by <code>VALUE_DELIM</code>, in this case a semi-colon.  If any of the names were found to be invalid, that is, never exactly matched or chosen, it is removed<span class="footnote"><a name="suggnote_note43" href="#suggnote_code43">43</a></span> and the <code>FormFeedback</code> will show an <code>ERROR</code> status with a tooltip containing the invalid name(s)<span class="footnote"><a name="suggnote_note44" href="#suggnote_code44">44</a></span>.  Depending on your needs, you might choose to return the value map or an array of names and values if order is important.</p>
<pre>
/**
 * Get the value(s) as a concatenated String
 * @return value(s) as a String
 */
public String getValue()<span class="footnote"><a name="suggnote_code42" href="#suggnote_note42">42</a></span>
{
    //String together all the values in the valueMap
    //based on the display values shown in the field
    String text = m_field.getText();
    
    String values = "";
    String invalids = "";
    String newKeys = "";
    if (m_isMultivalued) {
        String[] keys = text.split(DISPLAY_SEPARATOR);
        for (String key : keys) {
            key = key.trim();
            if (!key.isEmpty()) {
                String v = m_valueMap.get(key);
                if (null != v) {
                    values += v + VALUE_DELIM;
                    //rebuild newKeys removing invalids
                    newKeys += key + DISPLAY_SEPARATOR;<span class="footnote"><a name="suggnote_code43" href="#suggnote_note43">43</a></span>
                } else {
                    invalids += key + DISPLAY_SEPARATOR;
                }
            }
        }
        values = trimLastDelimiter(values, VALUE_DELIM);
        //set the new display values
        m_field.setText(newKeys);
    } else {
        values = m_valueMap.get(text);
    }
    
    //if there were any invalid show warning
    if (!invalids.isEmpty()) {
        //trim last separator
        invalids = trimLastDelimiter(invalids, DISPLAY_SEPARATOR);
        updateFormFeedback(FormFeedback.ERROR, "Invalids: " + invalids);<span class="footnote"><a name="suggnote_code44" href="#suggnote_note44">44</a></span>
    }
    return values;
}
</pre>
</p>
<h2>The Takeaway</h2>
<p>
This type-ahead control not only accepts multiple values but also auto-completes for a multi-valued copy and paste.  The user-friendly interface doesn&#8217;t impose a minimum number of characters before sending a request because it can limit the results shown while still allowing a complete browse of the dataset.
</p>
<p>
You could do all of that without REST, but we keep the client code completely encapsulated with a REST interface.  This sample could be extended with client-side caching to speed up performance.
</p>
<p>
The code in this example is free and released under the Apache 2.0 license.  The other programs needed to run this example are also free, but some of them may use different licenses. Make sure to read and understand each license before using a tool.
</p>
<p>
We encourage you to use this example in your own applications and we&#8217;d love to see the results.  Drop us a comment if you do.
</p>
<p style="margin-top: 5em"><a name="bess">Bess Siegal</a> is a software engineer at Novell.  She enjoys her <a href="/blog">one-minute commute</a> so she can spend more time with her husband and 3 daughters. </p>
]]></content:encoded>
					
					<wfw:commentRss>http://www.zackgrossbart.com/hackito/gwt-rest-auto/feed/</wfw:commentRss>
			<slash:comments>18</slash:comments>
		
		
			</item>
	</channel>
</rss>
