{"id":762,"date":"2010-12-23T08:31:38","date_gmt":"2010-12-23T16:31:38","guid":{"rendered":"http:\/\/www.zackgrossbart.com\/hackito\/?p=762"},"modified":"2011-03-10T03:38:48","modified_gmt":"2011-03-10T11:38:48","slug":"gwt-slider","status":"publish","type":"post","link":"http:\/\/www.zackgrossbart.com\/hackito\/gwt-slider\/","title":{"rendered":"Creating a GWT Wrapper for the JQuery UI Slider"},"content":{"rendered":"<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 \/>\n<style type=\"text\/css\"> body {font-size: 10px;} <\/style>\n<p>\nToday my wonderful and amazing colleague <a href=\"#bess\">Bess Siegal<\/a> dropped by to talk with me about wrapping JQuery controls in GWT. \u00a0You 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>.\n<\/p>\n<p>\nJavaScript 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>. \u00a0And GWT can&#8217;t. \u00a0Well&#8230; not easily. \u00a0\n<\/p>\n<p>\nThere&#8217;s a world of JQuery plugins you can use easily and safely in your GWT project. \u00a0All it takes is a little planning and a little practice. \u00a0\n<\/p>\n<p>\nThis 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.\n<\/p>\n<div id=\"demo\">\n\u00a0\u00a0 \u00a0<\/p>\n<h2>Default Slider<\/h2>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<div id=\"sliderContainer\"><\/div>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<h2>Range Slider<\/h2>\n<p>\u00a0\u00a0 \u00a0 \u00a0 \u00a0<\/p>\n<div id=\"rangeContainer\"><\/div>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<h2>Snap to increments<\/h2>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<div id=\"stepContainer\"><\/div>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<h2>Slider with multiple anchors<\/h2>\n<p>\u00a0\u00a0 \u00a0<\/p>\n<div id=\"multiContainer\"><\/div>\n<\/div>\n<h2>Importing JQuery libraries<\/h2>\n<p>\nWe&#8217;ll start by adding a few libraries. \u00a0Download 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. \u00a0Then reference them in your HTML file like this:\n<\/p>\n<pre>\r\n&lt;link media=\"all\" type=\"text\/css\" href=\"jquery-ui.css\" rel=\"stylesheet\"&gt;\u00a0\r\n&lt;script src=\"jquery-1.4.4.min.js\" type=\"text\/javascript\" charset=\"utf-8\"&gt;&lt;\/script&gt;\u00a0\r\n&lt;script src=\"jquery-ui.min.js\" type=\"text\/javascript\" charset=\"utf-8\"&gt;&lt;\/script&gt;\u00a0\r\n<\/pre>\n<p>\nYou can also have Google host them for you like this:\n<\/p>\n<pre>\r\n&lt;link media=\"all\" type=\"text\/css\"\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0href=\"http:\/\/ajax.googleapis.com\/ajax\/libs\/jqueryui\/1.8.6\/themes\/base\/jquery-ui.css\" rel=\"stylesheet\"&gt;\u00a0\r\n&lt;script src=\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/1.4.4\/jquery.min.js\"\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0type=\"text\/javascript\" charset=\"utf-8\"&gt;&lt;\/script&gt;\u00a0\r\n&lt;script src=\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jqueryui\/1.8.6\/jquery-ui.min.js\"\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0type=\"text\/javascript\" charset=\"utf-8\"&gt;&lt;\/script&gt;\u00a0\r\n<\/pre>\n<h2>Let&#8217;s add some code<\/h2>\n<div class=\"sourcebox\">\nGet the <br \/><a href=\"\/extras\/sliderexample\/SliderExample.zip\">source code<\/a>\n<\/div>\n<p>\nNow that you&#8217;ve imported the JQuery libraries, let&#8217;s start using them. \u00a0The <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>. \u00a0\n<\/p>\n<p>\nPicking the correct base class is an important part of creating a fully featured GWT control. \u00a0Our slider is just a <code>DIV<\/code>. \u00a0If 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.\n<\/p>\n<pre>\r\npublic class Slider extends Widget\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_comment\">\/**\r\n\u00a0\u00a0 \u00a0 * Create a slider with the specified ID. \u00a0The ID is required\r\n\u00a0\u00a0 \u00a0 * because the slider needs a specific ID to connect to.\r\n\u00a0\u00a0 \u00a0 * @param id - id of the element to create\r\n\u00a0\u00a0 \u00a0 * @param options - JSONObject of any possible option, can be null\u00a0\r\n\u00a0\u00a0 \u00a0 * \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0for defaults\r\n\u00a0\u00a0 \u00a0 *\/<\/span>\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">public<\/span> Slider(String id, JSONObject options)\r\n\u00a0\u00a0 \u00a0{ \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">super<\/span>();\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0Element divEle = DOM.createDiv();\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0setElement(divEle);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0divEle.setId(id); <span class=\"footnote\"><a name=\"slider_code1\" href=\"#slider_note1\">1<\/a><\/span>\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0m_defaultOptions = options;\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0if (m_defaultOptions == <span class=\"code_keyword\">null<\/span>) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0m_defaultOptions = getOptions(0, 100, new int[]{0});<span class=\"footnote\"><a name=\"slider_code2\" href=\"#slider_note2\">2<\/a><\/span>\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0} \u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0}\r\n<\/pre>\n<p>\nA <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>.\n<\/p>\n<p>\nExtending widget works well for the Slider, but it isn&#8217;t always the best choice. \u00a0When 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. \u00a0Choosing the right base class let&#8217;s your JQuery wrapper act like a first class GWT widget.\n<\/p>\n<h2>Getting your slider&#8217;s options<\/h2>\n<p>\n<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 \/>\nof options. \u00a0\n<\/p>\n<pre> \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_comment\">\/**\r\n\u00a0\u00a0 \u00a0 * A convenient way to create an options JSONObject. \u00a0Use SliderOption\u00a0\r\n\u00a0\u00a0 \u00a0 * for keys.\r\n\u00a0\u00a0 \u00a0 *\r\n\u00a0\u00a0 \u00a0 * @param min - default minimum of the slider\r\n\u00a0\u00a0 \u00a0 * @param max - default maximum of the slider\r\n\u00a0\u00a0 \u00a0 * @param defaultValues - default points of each anchor\r\n\u00a0\u00a0 \u00a0 * @return a JSONObject of Slider options\r\n\u00a0\u00a0 \u00a0 *\/<\/span>\r\n\u00a0\u00a0 \u00a0<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)\u00a0\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0JSONObject options = <span class=\"code_keyword\">new<\/span> JSONObject();\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.put(SliderOption.MIN.toString(), <span class=\"code_keyword\">new<\/span> JSONNumber(min));\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.put(SliderOption.MAX.toString(), <span class=\"code_keyword\">new<\/span> JSONNumber(max));\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0JSONArray vals = intArrayToJSONArray(defaultValues);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.put(SliderOption.VALUES.toString(), vals);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">return<\/span> options;\r\n\u00a0\u00a0 \u00a0}\r\n\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">static<\/span> JSONArray intArrayToJSONArray(<span class=\"code_keyword\">int<\/span>[] values)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0JSONArray vals = <span class=\"code_keyword\">new<\/span> JSONArray();\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (<span class=\"code_keyword\">int<\/span> i = 0, len = values.length; i &lt; len; i++) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0vals.set(i, <span class=\"code_keyword\">new<\/span> JSONNumber(values[i]));\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">return<\/span> vals;\r\n\u00a0\u00a0 \u00a0}\r\n<\/pre>\n<h2>More options<\/h2>\n<p>\nThere are also other constructors for the most common parameter options set during initialization.\u00a0\n<\/p>\n<pre><span class=\"code_comment\">\/**\r\n\u00a0* Create a slider with the specified ID. \u00a0The ID is required\r\n\u00a0* because the slider needs a specific ID to connect to.\r\n\u00a0* @param id - id of the element\r\n\u00a0* @param min - default minimum of the slider\r\n\u00a0* @param max - default maximum of the slider\r\n\u00a0* @param defaultValue - default point of a single anchor\r\n\u00a0*\/<\/span>\r\n<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)\r\n{\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">this<\/span>(id, min, max, <span class=\"code_keyword\">new<\/span> <span class=\"code_keyword\">int<\/span>[]{defaultValue});\r\n}\r\n\u00a0\u00a0 \u00a0\r\n<span class=\"code_comment\">\/**\r\n\u00a0* Create a slider with the specified ID. \u00a0The ID is required\r\n\u00a0* because the slider needs a specific ID to connect to.\r\n\u00a0* @param id - id of the element\r\n\u00a0* @param min - default minimum of the slider\r\n\u00a0* @param max - default maximum of the slider\r\n\u00a0* @param defaultValues - default points of each anchor\r\n\u00a0*\/<\/span>\r\n<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)\r\n{ \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">this<\/span>(id, getOptions(min, max, defaultValues));\r\n}\r\n<\/pre>\n<p>\nThe <code>SliderOption<\/code> enumeration helps with additional slider options. \u00a0The Javadoc comments for each option is copied directly from <a href=\"http:\/\/docs.jquery.com\/UI\/Slider#options\">JQuery UI Slider documentation<\/a>.\n<\/p>\n<h2>Initialization<\/h2>\n<p>\nConstructing your GWT object is only the first step. \u00a0You 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>. \u00a0The 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.\n<\/p>\n<p>\nWe need this method because GWT causes a timing problem. \u00a0With a regular JQuery page you would just call the binding when your page loads. \u00a0GWT uses a delayed loading mechanism which loads the correct GWT code for your browser and language. \u00a0The <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.\n<\/p>\n<pre>\r\n\u00a0\u00a0 \u00a0@Override\r\n\u00a0\u00a0 \u00a0<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>\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0if (m_defaultOptions == null) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0m_defaultOptions = <span class=\"code_keyword\">new<\/span> JSONObject();\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0createSliderJS(this, getElement().getId(), m_defaultOptions.getJavaScriptObject());\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">super<\/span>.onLoad();\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<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) \/*-{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.start = function(event, ui) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0x.@com.example.slider.client.widget.slider.Slider::fireOnStartEvent(Lcom\/google\/gwt\/user\/client\/Event;Lcom\/google\/gwt\/core\/client\/JsArrayInteger;)(event, ui.values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0};\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.slide = function(event, ui) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0return x.@com.example.slider.client.widget.slider.Slider::fireOnSlideEvent(Lcom\/google\/gwt\/user\/client\/Event;Lcom\/google\/gwt\/core\/client\/JsArrayInteger;)(event, ui.values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0};\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.change = function(event, ui) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0var has = event.originalEvent ? true : false;\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0x.@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); \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0};\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0options.stop = function(event, ui) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0x.@com.example.slider.client.widget.slider.Slider::fireOnStopEvent(Lcom\/google\/gwt\/user\/client\/Event;Lcom\/google\/gwt\/core\/client\/JsArrayInteger;)(event, ui.values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0};<span class=\"footnote\"><a name=\"slider_code5\" href=\"#slider_note5\">5<\/a><\/span>\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0$wnd.$(\"#\" + id).slider(options);<span class=\"footnote\"><a name=\"slider_code4\" href=\"#slider_note4\">4<\/a><\/span>\r\n\u00a0\u00a0 \u00a0}-*\/;\r\n\u00a0\u00a0 \u00a0\r\n<\/pre>\n<p>\nIn 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>. \u00a0The 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>. \u00a0Thus we have our cornerstone for event handling.\n<\/p>\n<h2>Event handling<\/h2>\n<p>\nWhen we&#8217;re done with our <code>Slider<\/code> it will look just like a standard GWT widget from the outside. \u00a0That way we can switch implementations and never worry about our choice of JavaScript library leaking out to other code in our project. \u00a0We&#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>.\n<\/p>\n<pre>\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">void<\/span> fireOnStartEvent(Event evt, JsArrayInteger values)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">int<\/span>[] vals = jsArrayIntegerToIntArray(values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0SliderEvent e = new SliderEvent(evt, <span class=\"code_keyword\">this<\/span>, vals);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (SliderListener l : m_listeners) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0l.onStart(e);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">boolean<\/span> fireOnSlideEvent(Event evt, JsArrayInteger values)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">int<\/span>[] vals = jsArrayIntegerToIntArray(values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0SliderEvent e = <span class=\"code_keyword\">new<\/span> SliderEvent(evt, <span class=\"code_keyword\">this<\/span>, vals);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (SliderListener l : m_listeners) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0l.onStart(e);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">boolean<\/span> ret = true;\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (SliderListener l : m_listeners) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">if<\/span> (!l.onSlide(e)) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_comment\">\/\/if any of the listeners returns false, return false,\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\/\/but let them all do their thing<\/span>\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0ret = <span class=\"code_keyword\">false<\/span>;\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">return<\/span> ret;<span class=\"footnote\"><a name=\"slider_code6\" href=\"#slider_note6\">6<\/a><\/span>\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">void<\/span> fireOnChangeEvent(Event evt, JsArrayInteger values,\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <span class=\"code_keyword\">boolean<\/span> hasOriginalEvent)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">int<\/span>[] vals = jsArrayIntegerToIntArray(values); \u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0SliderEvent e = new SliderEvent(evt, <span class=\"code_keyword\">this<\/span>, vals, hasOriginalEvent);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (SliderListener l : m_listeners) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0l.onChange(e);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">void<\/span> fireOnStopEvent(Event evt, JsArrayInteger values)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">int<\/span>[] vals = jsArrayIntegerToIntArray(values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0SliderEvent e = new SliderEvent(evt, <span class=\"code_keyword\">this<\/span>, vals);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">for<\/span> (SliderListener l : m_listeners) {\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0l.onStop(e);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0}\r\n\r\n<\/pre>\n<p>\nEach 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>. \u00a0\n<\/p>\n<h2>Changing options after initialization<\/h2>\n<p>\nYou may change a slider&#8217;s options after initialization. \u00a0There are <code>get\/setIntOption<\/code>, <code>get\/setBooleanOption<\/code> and <code>get\/setStringOption<\/code> methods to maintain type-safety. \u00a0Each of these methods calls a corresponding JSNI method to get or set the option. \u00a0Getting and setting the slider&#8217;s values is a little different, so they have their own methods.<\/p>\n<pre>\r\n\u00a0\u00a0 \u00a0<span class=\"code_comment\">\/**\r\n\u00a0\u00a0 \u00a0 * Convenience method for only 1 anchor\r\n\u00a0\u00a0 \u00a0 * @return Returns the value.\r\n\u00a0\u00a0 \u00a0 *\/<\/span>\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">public<\/span> <span class=\"code_keyword\">int<\/span> getValue()\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">return<\/span> getValueAtIndex(0);\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_comment\">\/**\r\n\u00a0\u00a0 \u00a0 * Sets the value of each anchor\r\n\u00a0\u00a0 \u00a0 * @param values - int array of values\r\n\u00a0\u00a0 \u00a0 *\/<\/span>\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">public<\/span> <span class=\"code_keyword\">void<\/span> setValues(<span class=\"code_keyword\">int<\/span>[] values)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0JSONArray vals = intArrayToJSONArray(values);\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0setValuesJS(getElement().getId(), vals.getJavaScriptObject());\r\n\u00a0\u00a0 \u00a0}\u00a0\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_comment\">\/**\r\n\u00a0\u00a0 \u00a0 * Gets the value of a anchor at the specified index\r\n\u00a0\u00a0 \u00a0 *\u00a0\r\n\u00a0\u00a0 \u00a0 * @param index \u00a0the index to retrieve the value for\r\n\u00a0\u00a0 \u00a0 *\u00a0\r\n\u00a0\u00a0 \u00a0 * @return the value\r\n\u00a0\u00a0 \u00a0 *\/<\/span>\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">public<\/span> <span class=\"code_keyword\">int<\/span> getValueAtIndex(<span class=\"code_keyword\">int<\/span> index)\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">return<\/span> getValueJS(getElement().getId(), index);\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">native<\/span> <span class=\"code_keyword\">void<\/span> setValuesJS(String id, JavaScriptObject values) \/*-{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0$wnd.$(\"#\" + id).slider(\"option\", \"values\", values);\r\n\u00a0\u00a0 \u00a0}-*\/;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<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) \/*-{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0return $wnd.$(\"#\" + id).slider(\"values\", index);\r\n\u00a0\u00a0 \u00a0}-*\/;\r\n<\/pre>\n<h2>Extending the Slider<\/h2>\n<p>\nBecause 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. \u00a0You could extend the slider for any of the specific options required by your application.\n<\/p>\n<h2>Cleanup<\/h2>\n<p>\nThe 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.\n<\/p>\n<pre>\r\n\u00a0\u00a0 \u00a0@Override\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">protected<\/span> <span class=\"code_keyword\">void<\/span> onUnload()\r\n\u00a0\u00a0 \u00a0{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0destroySliderJS(this, getElement().getId());\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0<span class=\"code_keyword\">super<\/span>.onUnload(); \u00a0 \u00a0 \u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0}\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0<span class=\"code_keyword\">private<\/span> <span class=\"code_keyword\">native<\/span> <span class=\"code_keyword\">void<\/span> destroySliderJS(Slider x, String id) \/*-{\r\n\u00a0\u00a0 \u00a0 \u00a0 \u00a0$wnd.$(\"#\" + id).slider(\"destroy\");\r\n\u00a0\u00a0 \u00a0}-*\/;\r\n<\/pre>\n<h2>The Takeaway<\/h2>\n<p>\nFor our web application projects at Novell, we like to use GWT for maintainability. \u00a0For all GWT&#8217;s benefits, we understand that it&#8217;s standard widgets are limited, especially when compared to its corresponding JQuery widget. \u00a0Fortunately, 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. \u00a0You may also feel free to use the slider code in your application. \u00a0Either way, please let us know if you do.\n<\/p>\n<p>\nThe 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.\n<\/p>\n<p style=\"margin-top: 5em\"><a name=\"bess\">Bess Siegal<\/a> is a software engineer at Novell. \u00a0She enjoys her <a href=\"\/blog\">one-minute commute<\/a> so she can spend more time with her husband and 3 daughters. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>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.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,20],"tags":[],"_links":{"self":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/762"}],"collection":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/comments?post=762"}],"version-history":[{"count":106,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/762\/revisions"}],"predecessor-version":[{"id":1005,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/posts\/762\/revisions\/1005"}],"wp:attachment":[{"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/media?parent=762"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/categories?post=762"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.zackgrossbart.com\/hackito\/wp-json\/wp\/v2\/tags?post=762"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}