Top Banner
The Joy of writing JavaScript Applications How Qooxdoo puts the fun back into programming for the web Tobias Oetiker OETIKER+PARTNER AG 22nd Large Installation System Administration Conference
65

LISA QooxdooTutorial Slides

Jan 18, 2015

Download

Technology

Tobias Oetiker

A Slideset for a half day qooxdoo tutorial.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: LISA QooxdooTutorial Slides

The Joy of writing JavaScript ApplicationsHow Qooxdoo puts the fun back into programming for the

web

Tobias Oetiker

OETIKER+PARTNER AG

22nd Large Installation System Administration Conference

Page 2: LISA QooxdooTutorial Slides

The Browser: my application platform

I Applications in the Browser: Netscapes original Plan.I Performance: SquirelFish, V8, Tracemonkey engines.I JavaScript graduated with Web 2.0I Widget libraries for breakfast, lunch and dinner.I A separte hack for every browser.

Page 3: LISA QooxdooTutorial Slides

Qooxdoo: application in the browser

I Web 2.0 is all about the look and feel.I Web pages with eye candy.I Applications running in the browser.I Back to client/server computing.I Qooxdoo is a complete environment.

Page 4: LISA QooxdooTutorial Slides

Qooxdoo features

I Turns JS into a grown up OO language.I No HTML or CSS knowledge required.I Cross Browser: >= FF 1.5, Safari 3, Chrome, IE6, Opera8.I Multilingual.I Full API Documentation.I Users works ’inside the box’.I LGPL, EPLI Fun.

Page 5: LISA QooxdooTutorial Slides

Jump right in

I Install Python. http://www.python.org/download/I Unpack Qooxdoo. http://qooxdoo.org/download/I Get Js2-mode for emacs

http://code.google.com/p/js2-mode/I Do this NOW!

Page 6: LISA QooxdooTutorial Slides

Jump right in

I Install Python. http://www.python.org/download/I Unpack Qooxdoo. http://qooxdoo.org/download/I Get Js2-mode for emacs

http://code.google.com/p/js2-mode/I Do this NOW!

Page 7: LISA QooxdooTutorial Slides

Generating the first application

I Point your path to qooxdoo-0.8-sdk/tools/binI Change directory to your development space.I Run create-application.py –name helloI CD into the hello directory.I Run generate.py sourceI Point your browser to hello/source/index.html

Page 8: LISA QooxdooTutorial Slides

Generating the first application

I Point your path to qooxdoo-0.8-sdk/tools/binI Change directory to your development space.I Run create-application.py –name helloI CD into the hello directory.I Run generate.py sourceI Point your browser to hello/source/index.html

Page 9: LISA QooxdooTutorial Slides

generated files

hello/generate.pyhello/config.jsonhello/source/resource/hello/test.pnghello/source/translation/readme.txthello/source/class/hello/test/DemoTest.jshello/source/class/hello/Application.jshello/source/index.htmlhello/Manifest.jsonhello/readme.txt

Page 10: LISA QooxdooTutorial Slides

source code: hello/source/class/hello/Application.js I

1 /* Tell qooxdoo that we need the resources in hello /*2 #asset(hello /*)3 */4 qx.Class. define ("hello. Application ",5 {6 extend : qx. application .Standalone ,7 members :8 {9 main : function ()

10 {11 // Call super class12 this.base( arguments );13 // Enable logging in debug variant14 if (qx.core. Variant .isSet("qx.debug", "on"))15 { // native logging capabilities16 qx.log. appender . Native ;17 // additional cross - browser console .18 // Press F7 to toggle visibility19 qx.log. appender . Console ;20 }

Page 11: LISA QooxdooTutorial Slides

source code: hello/source/class/hello/Application.js II

21 // Create a button22 var button1 = new qx.ui.form. Button (23 "First Button ", "hello/test.png");24 // Document is the application root25 var doc = this. getRoot ();26 // Add button to document at fixed coordinates27 doc.add(button1 , {left: 100, top: 50});28 // Add an event listener29 button1 . addListener (" execute ", function (e) {30 alert("Hello World!");31 });32 }33 }34 });

The original Qooxdoo hello world application,modified to fit the slide.

Page 12: LISA QooxdooTutorial Slides

Qooxdoo and JavaScript

I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.

Page 13: LISA QooxdooTutorial Slides

Qooxdoo and JavaScript

I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.

Page 14: LISA QooxdooTutorial Slides

Qooxdoo and JavaScript

I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.

Page 15: LISA QooxdooTutorial Slides

A function pointer example

1 var add_alert = function (a,b){2 alert(’The Result is: ’+(a+b));3 }4 add_alert (1 ,2);

Page 16: LISA QooxdooTutorial Slides

Scoping for the naïve

You know scoping from other languages1 var j = 100;2 var z = 22;3 for (var z = 1;z <10;z++){4 var j = z;5 }6 alert(’And the Winner is j:’+j+’ z:’+z);

Or so you thought

Page 17: LISA QooxdooTutorial Slides

Scoping for the naïve

You know scoping from other languages1 var j = 100;2 var z = 22;3 for (var z = 1;z <10;z++){4 var j = z;5 }6 alert(’And the Winner is j:’+j+’ z:’+z);

Or so you thought

Page 18: LISA QooxdooTutorial Slides

Scoping for the disillusioned

JavaScript scoping works only within function blocks.1 var j = 100;2 var z = 22;3 for (var z = 1;z <10;z++){( function (){4 var j = z;5 })()}6 alert(’And the Winner is j:’+j+’ z:’+z);

Note that z is outside the function block!

Page 19: LISA QooxdooTutorial Slides

Scoping for the disillusioned

JavaScript scoping works only within function blocks.1 var j = 100;2 var z = 22;3 for (var z = 1;z <10;z++){( function (){4 var j = z;5 })()}6 alert(’And the Winner is j:’+j+’ z:’+z);

Note that z is outside the function block!

Page 20: LISA QooxdooTutorial Slides

A simple closures example

1 var set;2 var get;3 var j=2;4 ( function (){ // the magic javascript scope trick5 var j;6 set = function (x){j=x};7 get = function (){ alert(’Hidden j is ’+j)};8 })(); // end of scope9 set (33);

10 get ();11 alert(’Outside j is still ’+j);

Everything as expected.

Page 21: LISA QooxdooTutorial Slides

A simple closures example

1 var set;2 var get;3 var j=2;4 ( function (){ // the magic javascript scope trick5 var j;6 set = function (x){j=x};7 get = function (){ alert(’Hidden j is ’+j)};8 })(); // end of scope9 set (33);

10 get ();11 alert(’Outside j is still ’+j);

Everything as expected.

Page 22: LISA QooxdooTutorial Slides

A simple closures example

1 var set;2 var get;3 var j=2;4 ( function (){ // the magic javascript scope trick5 var j;6 set = function (x){j=x};7 get = function (){ alert(’Hidden j is ’+j)};8 })(); // end of scope9 set (33);

10 get ();11 alert(’Outside j is still ’+j);

Everything as expected.

Page 23: LISA QooxdooTutorial Slides

A broken function factory

1 var j = [];2 for (var z = 1;z <10;z++){3 var g = z;4 j[g] = function (a){5 alert(’The value for j[’ + a + ’] is ’+g);6 };7 }8 j [2](2);

JavaScript! Has! No! Scope! For! Loop! Blocks!

Page 24: LISA QooxdooTutorial Slides

A broken function factory

1 var j = [];2 for (var z = 1;z <10;z++){3 var g = z;4 j[g] = function (a){5 alert(’The value for j[’ + a + ’] is ’+g);6 };7 }8 j [2](2);

JavaScript! Has! No! Scope! For! Loop! Blocks!

Page 25: LISA QooxdooTutorial Slides

A broken function factory

1 var j = [];2 for (var z = 1;z <10;z++){3 var g = z;4 j[g] = function (a){5 alert(’The value for j[’ + a + ’] is ’+g);6 };7 }8 j [2](2);

JavaScript! Has! No! Scope! For! Loop! Blocks!

Page 26: LISA QooxdooTutorial Slides

A working function factory

1 var j = [];2 for (var z = 1;z <10;z++){( function (){ // for a block3 var g = z;4 j[g] = function (a){5 alert(’The value for j[’ + a + ’] is ’+g);6 };7 })()} // end of block8 j [2](2);

Again the anonymous function trick comes to the rescue.

Page 27: LISA QooxdooTutorial Slides

A working function factory

1 var j = [];2 for (var z = 1;z <10;z++){( function (){ // for a block3 var g = z;4 j[g] = function (a){5 alert(’The value for j[’ + a + ’] is ’+g);6 };7 })()} // end of block8 j [2](2);

Again the anonymous function trick comes to the rescue.

Page 28: LISA QooxdooTutorial Slides

fun with this

1 var hello = {2 world: ’You ’,3 show: function (){4 alert(’Hello ’+this.world+’ this: ’+this ); }5 };6 hello.show (); // method call7 var plain = hello.show; // function pointer8 var world = ’Me’; // change this.world9 plain (); // method call

this refers tothe hello object.

this refers to the browsersbase Window object.

Page 29: LISA QooxdooTutorial Slides

fun with this

1 var hello = {2 world: ’You ’,3 show: function (){4 alert(’Hello ’+this.world+’ this: ’+this ); }5 };6 hello.show (); // method call7 var plain = hello.show; // function pointer8 var world = ’Me’; // change this.world9 plain (); // method call

this refers tothe hello object.

this refers to the browsersbase Window object.

Page 30: LISA QooxdooTutorial Slides

Class definition

In its most basic form, a Qooxdoo class is very simple.1 qx.Class. define (’my.first.Class ’);

In reality you would use something like this1 qx.Class. define ("my.cool.Class", {2 // declare constructor , members , ...3 });

A regular class can then be instantiated1 var myClass = new my.cool.Class;

Page 31: LISA QooxdooTutorial Slides

Class inheritance

The map contains the meat of the class.1 qx.Class. define ("my.cool.Class",2 {3 extend : my.great.SuperClass ,4 construct : function () { ... },5 destruct : function () { ... }6 });

Embrace and extend.

Page 32: LISA QooxdooTutorial Slides

Static members

Static member names are in the statics key.They use UPPERCASE names by convention.

1 qx.Class. define ("my.cool.Class", {2 statics : {3 FOO : VALUE ,4 BAR : function () { ... }5 }6 });

Static members are accessed with their full name:1 my.cool.Class.FOO = 3.141;2 my.cool.Class.BAR ();

Page 33: LISA QooxdooTutorial Slides

Static members

Static member names are in the statics key.They use UPPERCASE names by convention.

1 qx.Class. define ("my.cool.Class", {2 statics : {3 FOO : VALUE ,4 BAR : function () { ... }5 }6 });

Static members are accessed with their full name:1 my.cool.Class.FOO = 3.141;2 my.cool.Class.BAR ();

Page 34: LISA QooxdooTutorial Slides

Instance Members

Instance members reside in the members map.1 qx.Class. define ("my.cool.Class", {2 members : {3 foo : VALUE ,4 bar : function () { ... }5 }6 });

Use new to create an instance.1 var myClass1 = new my.cool.Class;2 myClass1 .foo = 3.141;3 myClass1 .bar ();

Page 35: LISA QooxdooTutorial Slides

Instance Members

Instance members reside in the members map.1 qx.Class. define ("my.cool.Class", {2 members : {3 foo : VALUE ,4 bar : function () { ... }5 }6 });

Use new to create an instance.1 var myClass1 = new my.cool.Class ;2 myClass1 .foo = 3.141;3 myClass1 .bar ();

Page 36: LISA QooxdooTutorial Slides

Calling the Superclass

1 qx.Class. define ("my.cool.Class",2 {3 extend : my.great.SuperClass ,4 construct : function (x) {5 this.base(arguments , x); // superclass constructor6 }7 members : {8 foo : function (x) {9 this.base(arguments , x);

10 }11 }12 });

The this.base construct works for both constructor andmember functions.

Page 37: LISA QooxdooTutorial Slides

Generic access to static members

1 qx.Class. define ("my.cool.Class",2 {3 extend : qx.core.Object ,4 construct : function (x){ this.base(arguments ,x)},5 statics : {6 PI : 3.1417 }8 members : {9 circumference : function ( radius ) {

10 return 2 * this.self( arguments ).PI * radius ;11 }12 }13 });

this.self only works for subclasses of qx.core.Object

Page 38: LISA QooxdooTutorial Slides

mixins

1 qx.Mixin. define (’my.cool. MMixin ’,{2 // code and variables like in a class3 });

Like classes, but without inheritance.By convention Mixin names start with ’M’.

1 qx.Class. define (’my.cool.Class ’, {2 include : [my.cool.MMixin , my.other.cool. MMixin ]3 ...4 });

Include mixins when creating new classes.1 qx.Class. include (qx.ui.core.Widget , qx. MWidgetFeatures );

Or even inject them into an existing class.

Page 39: LISA QooxdooTutorial Slides

class access control

There is the following naming convention for class members.1 publicMember2 _protectedMember3 __privateMember

In the Qooxdoo build process it is optionally possible torandomize the names of private members to protect access.

Page 40: LISA QooxdooTutorial Slides

static, abstract and singleton classes

1 qx.Class. define (’my. static .Class ’, {2 type : ’static ’3 statics : { ... };4 });

Neither members nor constructors are allowed in static classes.1 qx.Class. define (’my. abstract .Class ’, {2 type : ’abstract ’3 });

Abstract classes must be sub-classed for use.1 qx.Class. define (’my. singleton .Class ’, {2 type : ’singleton ’3 });4 var instance = my. singleton .Class. getIntance ()

There is only one instance which gets created on the first call.

Page 41: LISA QooxdooTutorial Slides

Browser specific code

Normally Qooxdoo takes care of all browser differences, but ifyou must intervene . . .

1 members : {2 foo: qx.core. Variant . select (3 ’qx.bom. client . Engine .NAME ’, {4 ’mshtml |opera ’: function () {5 // Internet Explorer or Opera6 },7 ’default ’: function () {8 // All other browsers9 }

10 }11 )12 }

Page 42: LISA QooxdooTutorial Slides

The demo Browser

1 $ cd $QX/ frontend / application / demobrowser /2 $ ./ generate .py build3 $ gnome -open build/index.html

Or surf to http://demo.qooxdoo.org/current/demobrowser

Page 43: LISA QooxdooTutorial Slides

The API Documentation

1 $ cd $QX/ frontend / framework2 $ ./ generate .py api3 $ gnome -open api/index.html

Or surf to http://demo.qooxdoo.org/current/apiviewer

Page 44: LISA QooxdooTutorial Slides

The Qooxdoo generator

Python is the sole dependencyI generator.py is the toolI it gets called by generate.py

The generator has many functionsI source - prep development codeI build - prep code for deploymentI api - build api docI lint - check your code for beautyI pretty - fix the code layoutI . . .

Page 45: LISA QooxdooTutorial Slides

Running your Qooxdoo program in source

Use source code during development1 $ cd hello2 $ ./ generate .py source3 $ gnome -open source /index.html

As long as you do not use any new classes, press reload in thebrowser to see changes.

Page 46: LISA QooxdooTutorial Slides

Deploying your Qooxdoo program

1 $ cd hello2 $ ./ generate .py build3 $ cp -rp build ~/ public_html /hello

I only two js filesI code gets optimized and compressedI no external dependencies

Page 47: LISA QooxdooTutorial Slides

Button, TextField and some Action1 // Create a textfield2 var tf1 = new qx.ui.form. TextField (’Demo Text ’);3 // Add button to root4 root.add(tf1 , { column : 0, row: 0});5 // Create a button6 var bt1 = new qx.ui.form. Button (7 ’Open Alert ’, ’lisa08 /test.png ’);8 // Add button to root9 root.add(bt1 , { column : 1, row: 0});

10 // Add an event listener11 bt1. addListener (’execute ’, function (e) {12 // closure !!13 this.info(’TextField : ’+tf1. getValue ());14 alert(’TextField : ’ + tf1. getValue ());15 });

Try F7 to see inline console!

Page 48: LISA QooxdooTutorial Slides

The Layout Manager

I Qooxdoo Widgets can contain other widgets.I Layout manager positions child widgets.I qx.ui.container.Composite basicI qx.ui.container.Scroll draws scroll barsI qx.ui.window.Window directs children to an inner

composite pane.I Layout manager set at construction timeI Modified with setLayout method.

Page 49: LISA QooxdooTutorial Slides

Container and Layout1 // a container with horizontal layouyt manager2 var hbox = new qx.ui. layout .HBox ();3 hbox. setSpacing (4); // set property45 // assign layout6 var ctr1 = new qx.ui. container . Composite (hbox );7 ctr1. setWidth (600); ctr1. setHeight (40);8 // layout properties : position9 root.add(ctr1 ,{ column : 0, row: 1, colSpan : 2});

1011 var tf2 = new qx.ui.form. TextField (’Some More Text ’);12 var bt2 = new qx.ui.form. ToggleButton (’AllowGrowY ’);13 bt2. addListener (’changeChecked ’, function (e) {14 // modify widget property15 tf2. setAllowGrowY (e. getData ());16 this.info(’New Value for AllowGrowY : ’+e. getData ());17 });18 ctr1.add(tf2 ); ctr1.add(bt2 );

Page 50: LISA QooxdooTutorial Slides

Grid Layout

I qx.ui.layout.GridI fully dynamicI ideal for dialogsI one widget per cellI row and column spansI minimal and maximal column and row sizesI fixed row and column sizes

Page 51: LISA QooxdooTutorial Slides

About the Qooxdoo Layout Widgets

I A container widget needs a layout manager to place itschildren.

I The layout manager object has properties.I Every widget has basic properties like: alignment,

growability, shrinkability, stretchability, margins, padding,width and height.

I Each widget can have layout-specific properties.I Layout properties get checked as the widget is added to a

layout.

Lets play with the layout demos!

Page 52: LISA QooxdooTutorial Slides

Localized Applications1 var lmgr = qx. locale . Manager . getInstance ();2 var bt3 = new qx.ui.form. ToggleButton (3 this.tr(’Translate !’)4 );5 root.add(bt3 , { column : 1, row: 3});6 bt3. addListener (’changeChecked ’, function (e) {7 var lang = e. getData () ? ’de’ : ’en’;8 lmgr. setLocale ( lang );9 this.info(’Language set to: ’+lang );

10 });

I add locale to config.jsonI ./generate.py translationI translate de.poI ./generate.py source

Page 53: LISA QooxdooTutorial Slides

calling code on the server

I JSON RPC for transportI various language bindingsI often minimal server codeI async with callbacksI qx.io.Rpc

Page 54: LISA QooxdooTutorial Slides

An RPC Example: Client

1 var rpc = new qx.io. remote .Rpc(’jsonrpc .cgi ’,’myclass ’);2 var bt4 = new qx.ui.form. Button (this.tr(’Call RPC ’));3 root.add(bt4 , { column : 1, row: 4});4 var that = this; // we want this ’this ’!5 var callback = function (result , ex , id) {6 that. RpcRunning = null; // free the reference7 if (ex == null) {8 alert(’The RPC call returned : ’+ result );9 that.info(’RPC call returned : ’+ result );

10 } else {11 alert(’Async(’ + id + ’) exception : ’ + ex);12 that.error (’Async(’ + id + ’) exception : ’ + ex);13 }14 };15 bt4. addListener (’execute ’, function (e) {16 that. RpcRunning = rpc. callAsync (17 callback ,’mymethod ’,’Hello ’);18 });

The example only works on a cgi enabled webserver.

Page 55: LISA QooxdooTutorial Slides

An RPC Example: Server CGI

source/jsonrpc.cgi:

1 #!/ usr/bin/perl -w2 use strict ;3 use lib qw(perl );45 use CGI;6 # use CGI :: Fast;7 use CGI :: Session ;8 use Qooxdoo :: JSONRPC ;9

10 # $Qooxdoo :: JSONRPC :: debug =1;11 my $cgi = new CGI;12 # while (my $cgi = new CGI :: Fast ){13 my $session = new CGI :: Session ;14 Qooxdoo :: JSONRPC :: handle_request ($cgi , $session );15 # }

For best performance use CGI::Fast and configureCGI::Session to keep the session data in a database.

Page 56: LISA QooxdooTutorial Slides

An RPC Example: the myclass service

source/perl/Qooxdoo/Services/myclass.pm:

1 package Qooxdoo :: Services :: myclass ;2 use strict ;34 # for now let everyone access the methods5 sub GetAccessibility { ’public ’ };67 sub method_mymethod {8 my $error = shift;9 my $arg = shift;

10 return ’The argument was: ’.$arg;11 }1213 1;

The myclass module gets loaded dynamically.

Page 57: LISA QooxdooTutorial Slides

An RPC Example: Getting it to work

I Install language bindings from Qooxdoo website.I ln -s /var/www/lisa08 buildI ./generate.py buildI cp -rp source/jsonrpc.cgi source/perl buildI Open the application in the browser.I Make sure the cgis are actually executedI Watch the Apache error log while testing.

Page 58: LISA QooxdooTutorial Slides

Organizing the code into multiple classes

I Object orientation “by the book”.I One file per class.I Java’s file name based approach.I Supported by the generator.I Ideal for code re-use.I Use Inline Docs!I ./generate.py api

Page 59: LISA QooxdooTutorial Slides

The textclick class I

1 /**2 * textclick combines a textfield and a button .3 */4 qx.Class. define (" lisa08 .ui. textclick ",5 {6 extend : qx.ui. container .Composite ,7 /**8 * @param button_text { String } button text.9 */

10 construct : function ( button_text ) {11 this.base( arguments ,12 new qx.ui. layout .HBox (). set ({ spacing : 4})13 );14 this.__tf = new qx.ui.form. TextField ();15 this.__bt = new qx.ui.form. Button ( button_text );16 this.add(this.__tf );17 this.add(this.__bt );18 },1920

Page 60: LISA QooxdooTutorial Slides

The textclick class II

21 members :22 {23 /**24 * Get a handle to the Button widget .25 */26 getButton : function () { return this.__bt },27 /**28 * Get a handle to the TextField widget .29 */30 getTextField : function () { return this.__tf },31 __bt: null ,32 __tf: null33 }34 });

Page 61: LISA QooxdooTutorial Slides

Using the textclick class

1 var mywi =new lisa08 .ui. textclick (2 this.tr(’Copy Text from Example 1’));34 mywi. getButton (). addListener (’execute ’, function (e) {5 mywi. getTextField (). setValue (tf1. getValue ());6 this.info(’Set textfield to ’+tf1. getValue ());7 });89 root.add(mywi ,{ column : 0, row: 5, colSpan : 2});

Page 62: LISA QooxdooTutorial Slides

The Message Bus

I Communication in “large” applications.I Singleton message bus class.I Careful with references: memory leaks!

1 var mywi2 =new lisa08 .ui. textclick (2 this.tr(’Send Hello to Textfield ’));3 var bus = qx.event. message .Bus. getInstance ();4 mywi2. getButton (). addListener (’execute ’, function (e) {5 bus. dispatch (’mybus .1’,’Hello World ’);6 this.info(’Sent Hello World on this bus ’);7 },this ); // context provided for console8 bus. subscribe (’mybus .1’,function (m){9 mywi2. getTextField (). setValue (m. getData ());

10 this.info(’Got ’+m. getData ()+ ’ from the bus ’);11 },this );1213 root.add(mywi2 ,{ column : 0, row: 6, colSpan : 2});

Page 63: LISA QooxdooTutorial Slides

Code walk through of the SmokeTrace application.

Page 64: LISA QooxdooTutorial Slides

?

Page 65: LISA QooxdooTutorial Slides

Tobi Oetiker <[email protected]>