speed up your gwt coding with gquery

35
Speed up your GWT coding with gQuery Manuel Carrasco Moñino GWT.create 2015 Run these slides 1/35

Upload: manuel-carrasco-monino

Post on 17-Jul-2015

411 views

Category:

Presentations & Public Speaking


1 download

TRANSCRIPT

Speed up your GWT coding with gQueryManuel Carrasco Moñino

GWT.create 2015

► Run these slides

1/35

About me...

Open Source advocateVaadin R&DGWT MaintainerApache James PMCJenkins Committer

 @dodotis+ManuelCarrascoMoñino

2/35

What is gQuery?Write less. Do more!

An entire GWT rewrite of the famous jQuery javascript library.Use the jQuery API in GWT applications without including the jQuery,while leveraging the optimizations and type safety provided by GWT.

3/35

It looks like jQuery

The API and syntax of GQuery is almost identical to jQuery.Existing jQuery code can be easily adapted into GQuery and used inyour GWT applications.

jQuery gQuery

$(".article:not(.hidden) > .header") .width($("#mainHeader").innerWidth()) .click(function () {

$(this) .siblings(".content") .load("/article/" + $(this).parent().id(), null, function () {

$(this).fadeIn(250);

});

});

import static com.google.gwt.query.client.GQuery.*;

$(".article:not(.hidden) > .header") .width($("#mainHeader").innerWidth()) .click(new Function() { public void f() { $(this) .siblings(".content") .load("/article/" + $(this).parent().id(), null, new Function() { public void f() { $(this).fadeIn(250); } }); } });

4/35

But it's much more

It integrates gently with GWTshares and enhances its event mechanismknows about widgets hierarchy

GWT OptimizersProvides a simpler deferred binding mechanism

Provide many utilities for GWT.Plenty of useful methods

5/35

Current gQuery status

Very active development3000 downloads per monthIn the top 5 of the most popular GWT librariesStable versions since 2010Official sponsored & supported by ArcBees

6/35

gQuery Fundamentals

7/35

Easy DOM manipulation

GQuery eases traversal and manipulation of the DOM.Use $() to wrap, find and create elements or widgets

Chaining methods: select & modify several elements in just one lineof code.friendly css style properties syntax.

Use $$() to set style properties or for animationsIt also supports type safe CSS

$(".slides > section").css("background-color", "green") .animate($$("top: +80%")) .animate($$("top: 0, background-color: transparent")).size();$("<p>Hello</p>").appendTo(".current");

8/35

Full GWT Widget integration

Whatever you do with elements, you can do with widgetsQuery, Enhance, Manipulate, Modify

Promote elements to widgets inserting them in gwt hierarchyImprove widgets events

Adding events not implemented by the widget

Button b = new Button("Click me");b.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { console.log("Clicked on Button"); }});// Promote any DOM element to a GWT panelPanel p = $("section.current .jCode-div").as(Widgets).panel().widget();// Use it as any other widget in GWT hierarchyp.add(b);// Enhance Widget DOM$("<a href='javascript:'>Click me</a>").prependTo($(b)).on("click", new Function() { public boolean f(Event e) { console.log("Clicked on Link"); return false; }});

9/35

Event Handling

Handle and fire any native event.Create your own events.Support for event name spaces.Delegate events.Pass data to listeners using events

Tip: Replacement to EventBus

console.log("Click on code text to see the font color.");$("#console").on("foo", new Function() { public boolean f(Event e, Object... args) { console.log(args[0]); return true; }});

$(".current .jCode").on("tap", "span", new Function() { public boolean f(Event e) { $("#console").trigger("foo", $(e).css("color")); return false; }

});

10/35

Promises

GQuery implements the promises API existing in jQuery.when, then, and, or, progress, done, fail, always

Use it as an alternative to nested callback based code.Declarative syntax.

Can be used in the JVM

//Launch things at the same time with whenGQuery.when($(".ball.yellow").animate($$("bottom:0"), 1000), $(".ball.red").animate($$("bottom:0"), 2000)).done(new Function() { public void f() { $(".ball").fadeOut(); }});

11/35

Ajax

GQuery provides an easy API for Ajax.Syntax sugarPromisesProgressWorks in JVM

$("#response").load("gwtcreate2015.html #hello > div");

12/35

Data Binding

GQuery ships an easy data binding system to and from JSON or XMLLight weight implementation: each object wraps a JS objectJVM compatible.

public interface Person extends JsonBuilder { Person setName(String s); String getName(); Person setAge(int i); int getAge(); List<Person> getChildren(); Person getPartner(); Person setPartner(Person p);}

Person me = GQ.create(Person.class).setAge(10).setName("Manolo");console.log(me);

13/35

Utilities

GQuery ships a set of GWT utilities which makes your live easier

Avoiding writing GWT JSNIexport, import

Simplifying GWT Deferred bindingbrowser.isIe, browser.isWebkit ... flags

Browser syntax loggingconsole.log, console.err ...

Import external JS in JSNIBlocksJsniBundle

14/35

All Right, but how can gQuery help in my GWT project ?

Writing less code !For certain actions you can save 60-90% of code

Making your code more expressiveChaining is more declarative.Promises try to solve nested and complex asynchronous blocks.

Using pure DOM elements instead of creating widgets for everything.The tendency is to avoid WidgetsWeb-components are hereReusing existing code (js, html)

15/35

When can I use gQuery in my GWT project?

1.- Doesn't matter the final GWT architecture of your projectPlain GWT, MVP, GWTPGXT, MGWT, Vaadin

2.- As usual separate Views from your Business logic.In your Views: gQuery will help you to enhance & manipulate the DOMIn your Logic: you can use Ajax, Promises, and Json binding and test in theJVM

16/35

I want to write less and do more...Show me the code

17/35

Don't extend GWT widgets to change it's behavior.

Modify the widget when it attaches or detaches.Modify its DOMAdd effectsAdd eventsTip: when GWT attaches/detaches you must set events again

Easy to use in UiBinder classes

Widget widget = new Label("Hello");widget.addAttachHandler(new Handler() { public void onAttachOrDetach(AttachEvent event) { $(event.getSource()) .append("<span> GWT</span><span> Create</span>") .animate($$("y: +200px, x: +50px, color: yellow "), 3000) .on("click", "span", new Function() { public void f() { console.log($(this).text()); } }); }});RootPanel.get().add(widget);

18/35

Decouple your widgets

Find any widget of a specific java class.By default it looks for widgets attached to the RootPanelEnclose your search using especific selectors like '.gwt-Label' or specificcontexts.

Then you can use those widgets as usual in your GWT application

// You get a list with all MyBreadCrumb matching the selectorList<MyBreadCrumb> list = $(".gwt-Label").widgets(MyBreadCrumb.class);MyBreadCrumb crumbs = list.get(0);

crumbs.addCrumb("Rocks");

19/35

GWT Ajax never was simpler.

Just one line of code vs dozen of lines using RequestBuilderReusable responses via PromisesAdvanced features

Upload/Download progress, FormData, CORSUsable in the JVM

// Configurable via Properties syntaxAjax.get("/my-rest-service/items", $$("customer: whatever"));Ajax.post("/my-rest-service/save", $$("id: foo, description: bar"));Ajax.loadScript("/my-cdn-host/3party.js");Ajax.importHtml("/bower_components/3party-web-component.html");// Or via the Settings interfaceAjax.ajax(Ajax.createSettings() .setUrl("/my-3party-site/service") .setWithCredentials(true) .setData(GQ.create().set("parameter1", "value"))) .fail(new Function() { public void f() { console.log("The call should fail because url's are invalid"); }

});

20/35

Make your async code more declarative and simpler

Avoid nesting callbacksChain promises methods to add callbacksReuse resolved promises to avoid requesting twice the same service

resolved status is maintained for everPipe your callbacks

// We can reuse the login promise any timePromise loginDone = Ajax.post("/my-login-service", $$("credentials: whatever"));

GQuery.when(loginDone) .then(Ajax.post("/my-rest-service", $$().set("param", "value"))) .done(new Function() { public Object f(Object... args) { return super.f(args); }}).fail(new Function() { public void f() { console.log("Login Error"); }});

21/35

JSNI sucks, how does gQuery help?

Export java functions to JS objectsThis will be covered by JsInteropBut sometimes you will be interested on simply export one method

Execute external functionsAutomatically boxes and un-boxes parameters and return values

Wrap any JS object with JsonBuildersIt supports functions

Load external libraries via JsniBundle

JsUtils.export(window, "foo", new Function() { public Object f(Object... args) { return args[0]; }});

String response = JsUtils.jsni(window, "foo", "Bye Bye JSNI");console.log(response);

22/35

Simplifying deferred binding

gQuery Browser flags are set in compilation time.They return true or false, making the compiler get rid of other borwserscode

Not necessity of create classes nor deal with module files

if (browser.webkit) { console.log("WebKit");} else if (browser.ie6) { // This code will never be in chrome permutation Window.alert("IE6 does not have console");} else { // This code will never be in chrome permutation console.log("Not webkit nor IE. Maybe mozilla? " + browser.mozilla);}

23/35

Extending gQuery

24/35

How to extend gQuery?

Plugins add new methods to GQuery objectsIt's easy to call new methods via the as(Plugin) methodPlugins also could modify certain behaviors of gQuery:

support for new selectorssynthetic eventsnew css properties ...

public static class Css3Animations extends GQuery { // We just need a constructor, and a reference to the new registered plugin protected Css3Animations(GQuery gq) { super(gq); } public static final Class<Css3Animations> Css3Animations = GQuery .registerPlugin(Css3Animations.class, new Plugin<Css3Animations>() { public Css3Animations init(GQuery gq) { return new Css3Animations(gq); } }); // We can add new methods or override existing ones public Css3Animations css3Animate(Properties properties) { super.animate(properties); return this; }}

$(".ball").as(Css3Animations.Css3Animations).animate($$("rotateX: 180deg, rotateY: 180deg"

25/35

How to port a jQuery plugin to gQuery

Gesture Plugin DifferencesTake original JS codeCreate JsBuider interfaces so as syntax is similar to JSSet appropriate java types to JS variables

Gesture Plugin Source GighubGesture Plugin Demo

$(".current .jCode").as(Gesture.Gesture).on("taptwo", new Function() { public void f() { console.log("Double Tap"); }});

26/35

What is the future of gQuery

Type safe functions and promisesFull support for java 8 lambdasMobile friendlyIntegration with JsInterop

GQuery g = $(".ball");g.each(new IsElementFunction() { public void run(Element elm) { $(elm).animate("scale: 1.2"); }});g.on("tapone", new IsEventFunction() { public Boolean call(Event evt) { return $(evt).animate($$("rotateX: 90deg")).animate($$("rotateX: 0deg")).FALSE; }});// Predefined return types in the gQuery chaing.on("taptwo", (e) -> $(e).animate($$("x: +=50")).TRUE);//Get the result of multiple callbacks$.when(() -> "aaa", () -> "bbb", Ajax.get("/lambdas.html")) .done((Object[] s) -> console.log(s[0], s[1], s[3])) .fail((s) -> console.log("Fail"));

27/35

Show me more cool code ...

28/35

Example: Material Design Hierarchical Timing.boxes.each(new Function() { int scale = boxes.isVisible() ? 0 : 1; public void f(Element e) { GQuery g = $(this); int delay = (int) (g.offset().left + g.offset().top); g.animate("duration: 200, delay: " + delay + ", scale: " + scale); }});

29/35

Example: Material Design Ripple Effect.//Create the ripple element to be animatedfinal GQuery ripple = $("<div>").as(Transitions.Transitions).css( $$("position: absolute, width: 40px, height: 40px, background: white, border-radius: 50%"//Add ripple effects to certain elements when they are tapped$(".jCode, .button, h1").on("tap.ripple", new Function() { public boolean f(Event e) { GQuery target = $(this).css($$("overflow: hidden")).append(ripple); int x = e.getClientX() - 20 - target.offset().left; int y = e.getClientY() - 20 - target.offset().top; int f = Math.max(target.width(), target.height()) / 40 * 3; ripple.css($$("opacity:0.8, scale:0.5")).css("left", x + "px").css("top", y + "px"); ripple.animate($$("opacity: 0, scale:" + f), new Function() { public void f() { ripple.detach(); } }); return false; }});

30/35

Example: Wrapping Web Components with gQuery

Use bower to install components in the public folderbower install Polymer/paper-slider

Use Ajax utility methods to load polyfills and import templatesWeb Components can be created and manipulated as any otherelement.We can change its properties or bind events.

Ajax.loadScript("bower_components/webcomponentsjs/webcomponents.js");Ajax.importHtml("bower_components/paper-slider/paper-slider.html");

GQuery slider = $("<paper-slider />").appendTo($("#sliders-container"));

slider.prop("value", 67);slider.on("change", (e) -> { console.log($(e).prop("value")); return true;});

$("#sliders-container").append("<paper-slider value=183 max=255 editable>");

31/35

Example: Binding Attributes of Web Components.

JsonBuilder can wrap any JavaScript elementLight Weight wrapperType safeChain setters

public interface PaperSlider extends JsonBuilder { // get/set prefixes are optional int getValue(); // Chaining setters is optional PaperSlider setValue(int value); PaperSlider min(int value); PaperSlider max(int value); PaperSlider step(int value); PaperSlider snaps(boolean value); PaperSlider pin(boolean value);}//Wait until the polyfill and the web component has been loadedGQuery.when(Ajax.loadScript("bower_components/webcomponentsjs/webcomponents.js"), Ajax.importHtml("bower_components/paper-slider/paper-slider.html")).done(new Function() { public void f() { // Create and append the element as usual in gQuery GQuery g = $("<paper-slider>").appendTo($("#slider-container")); // Wrap the native element in a POJO PaperSlider slider = GQ.create(PaperSlider.class).load(g); // Use it as a java object slider.setValue(300).max(400).step(50).snaps(true).pin(true); }});

32/35

Example: Uploading files with progress bar.final GQuery progress = $("<div>").css($$("height: 12px, width: 0%, background: #75bff4, position: absolute, bottom:0px"final GQuery fileUpload = $("<input type='file' accept='image/*'>").appendTo(document).hidefileUpload.on("change", new Function() { public boolean f(Event e) { final JsArray<JavaScriptObject> files = $(e).prop("files"); JavaScriptObject formData = JsUtils.jsni("eval", "new FormData()"); for (int i = 0, l = files.length(); i < l; i++) { JsUtils.jsni(formData, "append", "file-" + i, files.get(i)); } Ajax.ajax(Ajax.createSettings() .setUrl(uploadUrl).setData(formData).setWithCredentials(true)) .progress(new Function() { public void f() { progress.animate("width:" + arguments(2) + "%", 1000); } }).always(new Function() { public void f() { progress.remove(); } }).done(new Function() { public void f() { uploadImg.attr("src", uploadUrl + "&show=file-0-0"); } }); return true; }}).trigger("click");

33/35

Real Examples

www.GwtProject.orgwww.Arcbees.comGwtQuery Slideswww.Talkwheel.com

34/35

Questions and AnswersRate this talk: http://gwtcreate.com/agenda

when(() -> "Talk") .then((o) -> "Questions") .and((o) -> "Answers") .done((o) -> console.log("Thanks"));

35/35