gquery a jquery clone for gwt, rivieradev 2011
DESCRIPTION
Talk given at the rivieradev conferences Oct-2011TRANSCRIPT
About me
● Apache James● HUPA
● GWT● Gquery & Gquery-plugins● GwtExporter● GwtUpload● Chronoscope
● Jenkins● Performance plugin● Emma plugin
● Linux● LXP a light and visual window manager based on icewm
Contents
● What is GWT
● What is Gquery
● Learning Gquery– GQuery, $(), Function
– Collections & grabbing Values
– Selectors
– Traversing the DOM
– Method Chaining
– CSS
– Events
– Effects
– Ajax
– Data binding
– Plugins
● Js Size
● jsQuery
What is GWT
Is a full SDK. Not a Js FrameworkNot a Js LibraryNot a new languageNot a Web Framework
Java to Javascript Compiler, Linker, Optimizer and Obfuscator One compiled 'js' per browser (like c++ one 'exec' per processor)
Advantages of using Java.● A high level language allows that the developer doesn't get
lost with low level details: DOM, Ajax, Cross-domain, Compression, Obfuscation, Dependencies, Browser differences, etc.
● Huge Java ecosystem: IDE, Re-factoring, Debug, Code assist, Maven.
● Metrics, TDD, CI, Reusing (libraries)
● Patterns, Builders …
● Type safe, syntax checking, reduce errors.
● Separate code maintenance from the effectiveness of the executable.
● Normally, the compiler would produce better js code than the code we could write by hand (less code, compressed, obfuscated, remove dead code, etc).
What does the Gwt SDK provide● Generators, Compiler, Linker, Optimizer, Obfuscater.
● Client side libraries: DOM, XML, JSON, RPC, RF, I18n, MVP, Widgets
● Server libraries: RPC, RF
● Eclipse plugin
● Multi-browser Dev mode
● Unit testing and Debug tools.
● Performance tools (speed tracer)
● Compiler Statistics
● Everything is open sourced (Apache v2.0)
Java Server Side
Java Client Side
Java Code (IDE)
GWT server libs RPC/RF
GWT development Debug/Hosted/Test
GWT Compiler JRE Emulation
Browser libsWidgets
Test Runner FF/IE/Ch-Plugin
JVM App-Server
J-Byte Code
3ª Party Server libs
BrowserAny Backend(php, ruby, ...)
JavaScript.Bundles (css, sprite).
3ª Party Client libs
Toolkit (SDK)
JSON/XML/HTML/TXT RPC/RF
JSON/XML/HTML/TXT
GWT Eclipse Plugin
GQuery
What is GQuery
● A library for GWT
● Provides jQuery API and syntax (small differences)
● Entirely re-written in java, not a wrapper, optimized for Gwt.
● Has many features not available in jQuery.
– Data binding generators
– Type-safe structures
– Compile selectors
● It is a useful complement for Gwt.
– CSS selectors
– Widget finders
– Light weight collections
– DOM and Widget enhancers.
● Can be used as an alternative to traditional Gwt developing (progressive enhancement)
● Performance in mind, Unit tested.
● Extensible via Plugins
Easy to getting started
● Use the gquery maven Archetype.mvn archetype:generate \ -DarchetypeGroupId=com.googlecode.gwtquery \ -DarchetypeArtifactId=gquery-archetype \ -DarchetypeVersion=1.1.2 \ -DgroupId=fr.rivieradev \ -DartifactId=hello \ -DprojectName=HelloWorld
● Maven Ready (see README.txt).mvn clean package mvn gwt:run
IDE Friendly● Eclipse, IntelliJ, Netbeans● Run, Debug, Test● Code Assist● Re-Factoring● Software Metrics
The GQuery Object
● Like in jQuery ...● Selectors return an object ...● Which represents a collection of Elements ...● And each has plenty of useful methods.● Most methods return the object itself so you can chain
them.● Other methods return a value of the first element
GQuery g = $("img.photo");g.attr("src", "/default.png");String color = g.css("color");
int size = $("img.photo").css("border", "none").size();
The Dollar '$()' Method
// Import GQuery utility methods statically // it should be ...client.$.* but the compiler complains import static com.google.gwt.query.client.GQuery.*;
// The '$' method always returns a GQuery object GQuery g; // Use '$' to create new DOM elements g = $("<div>hello</div>"); // Use '$' to select DOM elements g = $("div:hidden"); // Use '$' to wrap existing elements g = $(document); // Use '$' to wrap Gwt widgets Button button = new Button(); g = $(button);
// '$' can handle other arguments: // Function, Event, Element[], NodeList ...
● As in Javascript, the symbol '$' is legal for methods and classes.
● But The Gwt Compiler disallows it for class names, So we use GQuery.
Functions
● java hasn't got closures.
● We use 'Function' inner class to emulate javascript function
● Override the appropriate 'f()' to write your code
Collections and Grabbing Values
// Returns a GQuery object GQuery g = $("div.section");
// Returns a nodelist NodeList<Element> l = $("div.section").get(); // Returns the size of the collection int size = $("div.section").size(); // Modify all elements in the collection $("div.section").addClass("highlighted"); $("a.foo").html("<em>Hello</em>"); // Iterate and runs a function around each // element $("div.section").each(new Function(){ public void f() { $(this).css("background", "red"); } });
// Some methods return results from the first // matched element int height = $("div#intro").height(); String src = $("img.photo").attr("src"); String lastP = $("p:last").html();
// Returns a jQuery object var g = $('div.section');
// Returns a nodelist var l = $('div.section').get(); // Returns the size of the collection var size = $('div.section').size(); // Modify all elements in the collection $('div.section').addClass('highlighted'); $('a.foo').html('<em>Hello</em>'); // Iterate and runs a function around each // element $('div.section').each(function(){ $(this).css('background', 'red'); });
// Some methods return results from the first // matched element var height = $("div#intro").height(); var src = $("img.photo").attr('src'); var lastP = $("p:last").html();
GQuery Java. jQuery JavaScript.
- We have to define the appropriate return type.- and to use double instead of single quotes
Selectors
● Both GQuery and jQuery are built around selectors.
● Both support CSS standard selectors plus extra selectors (:text :password :hidden etc).
● jQuery uses the sizzle engine. A javascript engine which works with any browser and has optimizations per browser.
● GQuery has optimized engines written in java.
● The more appropriate engine is selected in compile time.
● GQuery uses a modified sizzle version for IE6/7
● GQuery adds compile-time optimizations when using compiled selectors.
Dynamic selectors $("#note"); $(".note"); $("body"); $("div p"); $("div + p"); $("div .example"); $("div > div"); $("div ~ p"); $("h1[id]:contains(Selectors)"); $("tr:first"); $("tr:last"); $("*:checked"); $("*:visible"); $("a[href][lang][class]"); $("div:not(.example)"); $("div[class]"); $("div[class*=e]"); $("div[class=example]"); $("div[class~=dialog]"); $("div[class^=exa]"); $("div[class$=mple]"); $("p:first-child"); $("p:last-child"); $("p:nth-child(n)"); $("p:nth-child(2n)"); $("p:nth-child(2n+1)"); $("p:nth-child(even)"); $("p:nth-child(odd)"); $("p:only-child"); [...]
● Use $(string) with dynamic selectors
● Add the context if the target elements have not been attached yet or to improve performance.
● It supports XML documents as well
String className = "note"; $("." + className);
// Specify the context to improve performance Element e = DOM.getElementById("whatever"); $(".note", e); // Use the context with unattached elements Widget w = new MyWidget(); $(".note", w);
Compiled Selectors
interface MySelectors extends Selectors { @Selector("*:checked") GQuery allChecked();
@Selector("*:checked") GQuery allChecked(Node context); }
public void onModuleLoad() { MySelectors selectors = GWT.create(MySelectors.class);
selectors.allChecked(); Element e = DOM.getElementById("whatever"); selectors.allChecked(e); }
● Use them with immutable selectors.
● And when selector performance is a goal in your application.
● Context is supported
Selectors Performance→ Click to open the benchmarking application
Selectors Performance
● GQuery in compiled mode produces the faster javascript code to select DOM elements.
● GQuery dynamic selectors are, in most cases, faster or equal than any other library.
Traversing the Dom
GQuery nextSibling = $("div.section").next(); GQuery prevSibling = $("div.section").prev(); GQuery prevAnchorSibling = $("div.section").prev("a"); GQuery firstParent = $("div.section").parent(); GQuery allParents = $("div.section").parents();
● Like jQuery, GQuery provides enhanced methods for traversing the DOM
● Additionally it provides useful method to locate Gwt Widgets. // We can traverse the DOM to locate widgets // Return the CellTree widget whose id is myTree CellTree tree = $("#myTree").widget(); // Now we can use the instance tree.addCloseHandler(...); // Return all gwt Labels in the dom List<Label> allLabels = $("div").widgets(Label.class);
Chaining Methods
$("div.section").show().addClass("comeBack");
● Most GQuery methods return another GQuery object often representing the same collection. This means that you can chain methods together.
● Crazy chaining. $("form#login") // hide all the labels inside the form with the "optional" class .find("label.optional").hide().end() // add a red border to any password fields in the form .find("input:password").css("border", "1px solid red").end() // add a submit handler to the form .submit(new Function(){ public boolean f(Event e) { return confirm("Are you sure you want to submit?"); } });
CSS // jQuery like syntax: property, value $("#myId") .css("color", "red"); // jQuery like syntax: javascript object $("#myId") .css($$("top: '50px', left: '25px', color: 'red'")); // Additionally GQuery supports css style-sheet syntax (copy and paste) $("#myId") .css($$("margin: 3px; padding: 3px; font-size: small;"));
// Many properties require a strict syntax:
// background: color url repeat attachment position $("#myId").css("background", "transparent url('back.jpg') no-repeat scroll center");
// border: width style color $("#myId").css("border", "medium dotted #cdcd");
- We use the '$$' method to generate javascript property structures
CSS Type-safe
// Set the border style of a button widget to 'dotted' value Button myButton = new Button(); $(myButton).css(CSS.BORDER_STYLE.with(BorderStyle.DOTTED));
// vertical-align can take a constant value $("#myId").css(CSS.VERTICAL_ALIGN.with(VerticalAlign.MIDDLE)); // or a length : here 120 px $("#myId").css(CSS.VERTICAL_ALIGN.with(Length.px(120)));
// it easy now to specify shorthand property, // we do not have to remember the order! $("#myId").css(CSS.BACKGROUND.with( RGBColor.TRANSPARENT, UriValue.url("back.jpg"), BackgroundRepeat.NO_REPEAT, BackgroundAttachment.SCROLL, BackgroundPosition.CENTER)); // specify margin, padding, text-decoration and font-size in one pass $("#myId").css(CSS.MARGIN.with(Length.px(3)), CSS.PADDING.with(Length.px(3), Length.px(5)), CSS.TEXT_DECORATION.with(TextDecoration.NONE), CSS.FONT_SIZE.with(FontSize.SMALL));
Events
● GQuery provides methods for assigning event in a cross-browser way.
● GQuery event system is compatible with Gwt.
● issues:– When Gwt detaches a widget, events added via
GQuery are lost.– If you use 'live' for future elements, consider
performance (be carefully with 'onmouse...' events)
Events examples // GQuery provides methods for assigning event // handlers to elements in a cross-browser way. $("a").click(new Function() { public boolean f(Event ev) { $(this).css("backgroundColor", "orange"); // return false to stop default action and event-bubbling return false; } }); // Fires the event click on all labels $(".gwt-Label").click();
// Remove event handlers $("a").unbind("click"); // Attach a handler to all elements matching the // selector, now and in the future $("a") .live("over", new Function(){ public void f() { $(this).css("color", "red"); } }) // Type-safe .live(Event.ONMOUSEOUT, new Function(){ public void f() { $(this).css("color", null); } });
Effects
● GQuery provides several techniques for adding animations to a web page.
● These include simple, standard animations that are frequently used:
● fadeIn, fadeOut, slideDown, slideUp …
● and the ability to craft sophisticated custom effects via the animate method using jquery animation syntax
● queue, delay, stop, css, attr, colors ...
$(".foo").fadeIn(2000);
$(".foo") .stop() .animate("left:'+=1000'", 2000, Easing.SWING) .delay(500) .animate("left:'-=1000'", 2000);
→ Go to zoom example
Ajax
● Gwt includes its own facilities for performing communications with the server:● RPC, Request Factory (Only Java)● Request Builder
● But GQuery complements it adding:● jQuery syntax.● Builders to handle JSON and XML.
Ajax methods
// Load a remote html fragment in a set of // dom elements $("#c").load("file.html #mid");
// More advanced methods GQuery.get("file.html", null, new Function(){ public void f() { alert("success " + getData()[0]); } }); GQuery.post("file.html",$$("name:'John',time:'2pm'"), new Function(){ public void f() { alert("success " + getData()[0]); }});
GQuery.getJSON("file.html",$$("name:'John',time:'2pm'"), new Function(){ public void f() { alert("success " + getData()[0]); }});
// Load a remote html fragment in a set of // dom elements $('#c').load('file.html #mid');
// Unsupported in GQuery $.getScript(url, callback); // More advanced methods $.get('file.php', null, function(data){ alert("success " + data); });
$.post('file.php', {name: 'John', time: '2pm'}, function(data){ alert("success" + data); });
$.getJSON('file.php', {name: 'John', time: '2pm'}, function(data){ alert("success" + data); });
GQuery Java. jQuery JavaScript.
- Gwt compiler disallows a class named '$', so we use 'GQuery'
Data binding
● Although Gquery
– provides the class 'Properties' to handle Json objects...
– and it is able to inspect Xml objects using css selector engine...
GQuery provides generators to produce builders and handle Xml and Json as 'java' objects.
● Data binding objects support getters, setters and attribute renaming via annotations
● The usage of data binding makes the code more readable, type-safe, checks null conditions, castings, etc.
Properties p = $$("key1: 'value1', key2: [1,2]"); String v1 = p.getStr("key1");
Element e = JsUtils.parseXML("<root><message>hello</message></root>"); String txt = $("root message", e).text();
Data binding example // GQuery generator will create the implementation interface Site extends JsonBuilder { long getId(); String getUrl(); String[] getTags(); // change the name to fix the misspelling @Name("referer") Site getReferrer(); String getTitle();
//NOTE: Setters not displayed to simplify }
GQuery.getJSON("test.json", null, new Function() { public void f() { // Create the Site instance Site s = GWT.create(Site.class); // Load the data got from the server s.load(getData()[0]); // We can use standard getters and setters, // making the code more readable and type-safe alert("OK " + s.getUrl() + " " + s.getTags()[0] + " " + s.getReferrer().getUrl()); } }); // Alternative: handle data using GQuery Properties class
Properties p = (Properties)getData()[0];alert ("OK " + p.getStr("url") + " " + p.getArray("tags").getString(0) + " " + ((Properties)p.getJavaScriptObject("referer")).getStr("url"));
[{ "id": 1234, "referer": {"id": 2, "url": "http://google.com"}, "url": "http://mochikit.com/interpreter/index.html", "title": "Interpreter", "tags": [ "mochikit","webdev","tool","tools", "javascript","interactive","interpreter","repl" ]}]
Plugins● GQuery is extensible through plugins, adding new features for different
purposes.
● Because of java constrains, we can not add new methods to the GQuery class so we have to use the method 'as' to use plugin methods.
● Core already includes: Events, Effects, Widgets and Ajax plugins
● GQuery has its own site to host plugins. Contributions welcomed!
→ Go to the plugins site
Plugins: Create and Usage
public static class MyPlugin extends GQuery { // Register the plugin in the GQuery plugin system public static final Class<MyPlugin> MyPlugin = Gquery.registerPlugin(MyPlugin.class, new Plugin<MyPlugin>() { public MyPlugin init(GQuery gq) { return new MyPlugin(gq); } });
// Initialization protected MyPlugin(GQuery gq) { super(gq); }
// Add a new methods to GQuery objects public GQuery newMethod() { // Write your code here return this; } }
$("h1").as(MyPlugin).newMethod();
Usage a Plugin.
Develop a Plugin.
// jQuery syntax $("h1").newMethod();
Progressive Enhancement
● Enhance pure Html pages: Crawlers friendly.
● Enhance Gwt Widgets: Without manipulating the class.
● Enhance Gwt Views: MVP pattern compatible.
$(".gwt-Button").prepend("<img src='help.png'>");
$("a").click(new Function() { public void f() { GWT.log("Clicked: " + $(this).text() + " " + $(this).attr("href")); } });
$("textarea").as(Enhance).richText();
JavaScript size
● Gquery takes advantage of the gwt compiler which produces optimized and striped code.
● Gquery core tends to use light-weight stuff to reduce the javascript size and improve the performance.
● A small GQuery application normally is smaller than the jQuery minimized library.
● The js size which GQuery adds to a Gwt application is 3 or more times smaller than the jquery library.
Comparing sizes● The ImageZoom Example needs a 17% less of javascript code (FF).
● When using deflate-gzip in webserver, gwt js code is pre-ordered so the compression factor is better.
jsQuery
● The latest work in GQuery is to produce a clone of jquery which could be used as a replacement of jQuery. We call this library jsQuery.
● The goal is not to compete against jquery, but ● To avoid including jquery in Gwt applications which need some native jQuery
methods like jquery plugins.
● As an investigative work which demonstrates that any js API can be developed in Gwt (jQuery is the js API most widely used).
● We use the gwt-exporter library which is able to expose Gwt classes and methods to javascript.
● Right now most GQuery object methods are exposed but we have to implement and export many static methods which are in jQuery like extend, each, map …
● The main goal is to encourage people to wrap jQuery plugins, just including them as jsni and creating java wrappers methods around it.
jsQuery issues
● Gwt-exporter introduces a high amount of extra code to deal with types and wrappers. If we consider compression, jsQuery is only 8KB greater
● Gwt-exporter spends time figuring out which methods to call and how to wrap parameters and return objects.
● Apart of the code in GQuery, we will need extra code to emulate all jQuery API.
jsQuery example<!-- <script src="http://code.jquery.com/jquery-latest.min.js" /> -->
<script src="http://code.google.com/p/gwtquery/source/browse/api/jsquery.nocache.js" />
<script type="text/javascript"> $(document).ready(function(){ $("ul.thumb li").hover(function() { $(this).css({'z-index' : '10'}); $(this).find('img').addClass("hover").stop() .animate({ marginTop: '-110px', marginLeft: '-110px', top: '50%', left: '50%', width: '174px', height: '174px', padding: '20px' }, 200); } , function() { $(this).css({'z-index' : '0'}); $(this).find('img').removeClass("hover").stop() .animate({ marginTop: '0', marginLeft: '0', top: '0', left: '0', width: '100px', height: '100px', padding: '5px' }, 400); }); });</script>
Links
http://gwtquery-plugins.googlecode.com/svn/trunk/enhance/demos/Enhance/EnhanceSample.html
http://gwtquery-plugins.googlecode.com/svn/trunk/droppable/demo/GFinderSample/GFinderSample.html
http://gwtquery-plugins.googlecode.com/svn/trunk/droppable/demo/GwtPortletSample/GwtPortletSample.html
http://gwtquery-plugins.googlecode.com/svn/trunk/ratings/demos/Ratings/RatingsSample.html
http://talkwheel.com
http://gwtquery-ui.googlecode.com/svn/demos/GwtQueryUi.html
Plugins
Application
GwtQueryhttp://code.google.com/p/gwtquery/
http://gwtquery.googlecode.com/svn/trunk/gwtquery-core/javadoc/com/google/gwt/query/client/GQuery.html
http://code.google.com/p/gwtquery/w/list
http://code.google.com/p/gwtquery-plugins/
Conclusions
● People knowing jquery can easily use GQuery because share the API.
● GQuery uses java :
– Type safe, discover errors early (compile time instead of runtime)
– Advanced IDE (code completion, refactoring)
– Most people knows java but only a few js.
● GQuery uses gwt:
– Do not worry about compression, obfuscation …
– TDD, Debug
– Many libraries available
● GQuery complements the Gwt world making easier code: write less, do more.
● GQuery helps to develop applications using the jquery paradigm based on Enhancement, instead of the Gwt one based on Widgets.
● GQuery is mature, just released version 1.1.0, and well documented.
● The GQuery plugin system is simple.
● Contributors are Welcome !!!
Announcement
GQuery 1.1.0 released today !
We wanted to match the new release announcement with the RivieraDev event.