Documents pour LISA : LISA Science case Science Requirement Document
LISA QooxdooTutorial Slides
-
Upload
tobias-oetiker -
Category
Technology
-
view
2.265 -
download
0
description
Transcript of 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
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.
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.
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.
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!
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!
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
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
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
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 }
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.
Qooxdoo and JavaScript
I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.
Qooxdoo and JavaScript
I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.
Qooxdoo and JavaScript
I It’s just like Perl and OOI It’s all about anonymous functionsI and closures . . . and scoping.
A function pointer example
1 var add_alert = function (a,b){2 alert(’The Result is: ’+(a+b));3 }4 add_alert (1 ,2);
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
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
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!
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!
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.
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.
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.
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!
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!
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!
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.
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.
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.
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.
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;
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.
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 ();
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 ();
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 ();
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 ();
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.
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
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.
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.
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.
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 }
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
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
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 . . .
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.
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
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!
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.
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 );
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
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!
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
calling code on the server
I JSON RPC for transportI various language bindingsI often minimal server codeI async with callbacksI qx.io.Rpc
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.
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.
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.
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.
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
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
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 });
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});
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});
Code walk through of the SmokeTrace application.
?
Tobi Oetiker <[email protected]>