SlideShare une entreprise Scribd logo
1  sur  24
Télécharger pour lire hors ligne
The Joy of writing JavaScript Applications
   How Qooxdoo puts the fun back into programming for the web



                       Tobias Oetiker

22nd Large Installation System Administration Conference
1    Introduction

The Browser: my application platform

    • Applications in the Browser: Netscapes original Plan.

    • Performance: SquirelFish, V8, Tracemonkey engines.

    • JavaScript graduated with Web 2.0

    • Widget libraries for breakfast, lunch and dinner.

    • A separte hack for every browser.


It is said that people at Netscape back in the nineties had the vision of escaping
the Microsoft dominance by enhancing their browser so that it could become a
platform of its own for running client side applications. It is also said that MS was
not thrilled by this thought.
Netscape is no more but the vision has become a reality. The Web 2.0 hype
sparked a slew of highly interactive web applications that used JavaScript snipets
on the browser to enhance the user experience.



Qooxdoo: application in the browser

    • Web 2.0 is all about the look and feel.

    • Web pages with eye candy.

    • Applications running in the browser.

    • Back to client/server computing.

    • Qooxdoo is a complete environment.
Qooxdoo features

   • Turns JS into a grown up OO language.

   • No HTML or CSS knowledge required.

   • Cross Browser: >= FF 1.5, Safari 3, Chrome, IE6, Opera8.

   • Multilingual.

   • Full API Documentation.

   • Users works ’inside the box’.

   • LGPL, EPL

   • Fun.


Qooxdoo is way more than yet another JavaScript widget collection. Apart from
a cool collection of widgets, it introduces fully object oriented programming to
the JavaScript world. Similar to the way OO got introduced in the Perl world, the
Qooxdoo folks designed a framework that provides all of the OO bits that were
left out of JavaScript’s initial design.




                                       2
2    Hello World

Jump right in

    • Install Python. http://www.python.org/download/
    • Unpack Qooxdoo. http://qooxdoo.org/download/
    • Get Js2-mode for emacs http://code.google.com/p/js2-mode/
    • Do this NOW!


Some claim Qooxdoo has a steep learning curve since it does just publish some
JavaScript files you can link into your web page. While there are ways todo this all
the same, I think it is actually a good thing since Qooxdoo’s main objective is to
provide an environment for writing standalone, browser based applications. With
such a scope in mind, the developer should treat herself to a decent programming
environment.


Generating the first application

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




Qooxdoo comes with many sensible defaults. One could argue, that a lot of Qoox-
doo’s appeal comes from the many defaults. Normally when I start to write a pro-
gram from scratch I am faced with way too many decisions at once. I often spend
considerable time mulling about seemingly trivial decisions instead of just start-
ing to program. Qooxdoo takes a lot of this “freedom” away by setting a standard
on how to write your application. Many of these defaults can be changed, but I
found that they are actually quite a good aproximation to my optimal program-
ming environment, so there is no immediate need to change them.


                                        3
generated files

     hello/generate.py
     hello/config.json
     hello/source/resource/hello/test.png
     hello/source/translation/readme.txt
     hello/source/class/hello/test/DemoTest.js
     hello/source/class/hello/Application.js
     hello/source/index.html
     hello/Manifest.json
     hello/readme.txt




     source code: hello/source/class/hello/Application.js
1    /* Tell qooxdoo that we need the resources in hello/*
2    #asset(hello/*)
3    */
4    qx.Class.define(quot;hello.Applicationquot;,
5    {
6       extend : qx.application.Standalone,
7       members :
8       {
 9        main : function()
10        {
11          // Call super class
12          this.base(arguments);
13          // Enable logging in debug variant
14          if (qx.core.Variant.isSet(quot;qx.debugquot;, quot;onquot;))
15          { // native logging capabilities
16            qx.log.appender.Native;
17            // additional cross-browser console.
18            // Press F7 to toggle visibility
19            qx.log.appender.Console;
20          }
21          // Create a button
22          var button1 = new qx.ui.form.Button(
23                             quot;First Buttonquot;, quot;hello/test.pngquot;);
24          // Document is the application root
25          var doc = this.getRoot();
26          // Add button to document at fixed coordinates
27          doc.add(button1, {left: 100, top: 50});
28          // Add an event listener
29          button1.addListener(quot;executequot;, function(e) {
30            alert(quot;Hello World!quot;);
31          });
32        }
33      }
34   });

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


                                            4
3    The finer Points of JavaScript

    Qooxdoo and JavaScript

        • It’s just like Perl and OO

        • It’s all about anonymous functions

        • 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);


    Calling function creates a function object which I can use exactly like a normal
    function.



    Scoping for the naïve
    You know scoping from other languages
1 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




                                              5
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!


    While many languages provide scope for every block, this is not the case for
    JavaScript. Here the only scoping block is the function block. So if we need
    scope inside a looping block for example, we just add an anonymous function and
    execute it in place. I am not sure how efficient this is, so do not use it in tight
    loops.



    A simple closures example
1  var set;
2  var get;
3  var j=2;
4  (function(){ // the magic javascript scope trick
5     var j;
6     set = function(x){j=x};
 7    get = function(){alert(’Hidden j is ’+j)};
 8 })(); // end of scope
 9 set(33);
10 get();
11 alert(’Outside j is still ’+j);




                                Everything as expected.



                                            6
With closures, several functions can share a common variable defined outside the
    function. Lisp/Scheme has been the first language to implement this concept. To-
    day many object oriented languages can do closures: There are subtle differences
    though, as I had to discover the hard way, working with JavaScript coming from
    a Perl/C background.



    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 block
3    var g = z;
4    j[g] = function(a){
5        alert(’The value for j[’ + a + ’] is ’+g);
6    };
7 })()} // end of block
8 j[2](2);




               Again the anonymous function trick comes to the rescue.

                                           7
When programming with Qooxdoo its almost entirely about anonymous functions
    and closures. It took me almost a year to finally figure out about JavaScript scop-
    ing, before it was just the odd problem which I could not really fix and spent
    hours working finding a work-a-round, cursing mysterious JavaScript bugs in the
    process.



    fun with this
1 var hello = {
2          world: ’You’,
3          show: function(){
4     alert(’Hello ’+this.world+’ this: ’+this); }
5 };
6 hello.show();            // method call
7 var plain = hello.show; // function pointer
8 var world = ’Me’;        // change this.world
9 plain();                 // method call




    this refers to                               this refers to the browsers
    the hello object.                            base Window object.

    Be careful when using this in an anonymous function since it always points to
    the current parent. Call-back functions are especially ’vulnerable’ to this problem.




                                             8
4    The Qooxdoo OO Features

    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 this
1 qx.Class.define(quot;my.cool.Classquot;, {
2   // declare constructor, members, ...
3 });


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




    Class inheritance
    The map contains the meat of the class.
1   qx.Class.define(quot;my.cool.Classquot;,
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(quot;my.cool.Classquot;, {
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();




                                               9
Instance Members
     Instance members reside in the members map.
1    qx.Class.define(quot;my.cool.Classquot;, {
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(quot;my.cool.Classquot;,
2    {
3      extend : my.great.SuperClass,
4      construct : function(x) {
5        this.base(arguments, x); // superclass constructor
6      }
7      members : {
8        foo : function(x) {
 9         this.base(arguments, x);
10       }
11     }
12   });

     The this.base construct works for both constructor and member functions.

     The arguments object/map used in this example is a native JavaScript feature.
     Inside a function call it contains all the information about how the function was
     called: a list of the arguments passed to the function as well as pointers to the
     function itself.




                                            10
Generic access to static members
1    qx.Class.define(quot;my.cool.Classquot;,
2    {
3      extend : qx.core.Object,
4      construct : function(x){this.base(arguments,x)},
5      statics : {
6        PI : 3.141
7      }
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 class
3    });

     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.

     A mixin may contain anything a normal class can contain, but it does not get
     instantiated or inherited from directly. Is included into new and existing classes to
     provide additional features through its methods and properties.


     class access control
     There is the following naming convention for class members.
1    publicMember
2    _protectedMember
3    __privateMember

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



                                              11
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 if you must intervene
     ...
1    members: {
2      foo: qx.core.Variant.select(
3        ’qx.bom.client.Engine.NAME’, {
4          ’mshtml|opera’: function() {
 5            // Internet Explorer or Opera
 6         },
 7         ’default’: function() {
 8            // All other browsers
 9         }
10       }
11     )
12   }




                                              12
5    Working with Qooxdoo

    The demo Browser




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

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

    For me the demobrowser is the quickest way of seeing how to write Qooxdoo.
    Select a widget on the tree at the left and activate the JS Code toggle. Now you
    can see both the running program as well as the JavaScript code. The rest is mostly
    cut and paste.




                                            13
The API Documentation




1   $ cd $QX/frontend/framework
2   $ ./generate.py api
3   $ gnome-open api/index.html

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

    The Qooxdoo API documentation is generated directly from embedded javadoc
    in the Qooxdoo JS source files. You can apply the same process to your own
    Qooxdoo application to get a api viewer for your own code.


    The Qooxdoo generator
    Python is the sole dependency

       • generator.py is the tool
       • it gets called by generate.py

    The generator has many functions

       • source - prep development code
       • build - prep code for deployment
       • api - build api doc
       • lint - check your code for beauty
       • pretty - fix the code layout
       • ...



                                             14
Running your Qooxdoo program in source
    Use source code during development
1 $ cd hello
2 $ ./generate.py source
3 $ gnome-open source/index.html


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

    To run a Qooxdoo application, the code for each class you used must be loaded.
    This can easily be 30 or more files. When calling the generator with the option
    source it will create an JavaScript file in source/script/hello.js which
    takes care of loading these class files. While developing you may want to try the
    lint option as well, to catch some frequent mistakes.



    Deploying your Qooxdoo program
1 $ cd hello
2 $ ./generate.py build
3 $ cp -rp build ~/public_html/hello



       • only two js files

       • code gets optimized and compressed

       • no external dependencies


    The Qooxdoo generator builds a fully custom js file containing all the Qooxdoo
    classes required to run your application. It also compresses and optimizes the
    code in this step. You will notice that the first source and build run will take quite
    some time. This is because Qooxdoo creates cache files of all classes involved. If
    you run the build for a second time things will run much quicker.




                                             15
6    Programming with Qooxdoo

     Button, TextField and some Action
1    // Create a textfield
2    var tf1 = new qx.ui.form.TextField(’Demo Text’);
3    // Add button to root
4    root.add(tf1, {column: 0, row: 0});
5    // Create a button
6    var bt1 = new qx.ui.form.Button(
 7         ’Open Alert’, ’lisa08/test.png’);
 8   // Add button to root
 9   root.add(bt1, {column: 1, row: 0});
10   // Add an event listener
11   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!

     In this first example there is already a closure. The variable tf1 is used inside
     the event handler. The function is passed as a reference and takes the access to the
     TextField object with it.



     The Layout Manager

         • Qooxdoo Widgets can contain other widgets.

         • Layout manager positions child widgets.

         • qx.ui.container.Composite basic

         • qx.ui.container.Scroll draws scroll bars

         • qx.ui.window.Window directs children to an inner composite pane.

         • Layout manager set at construction time

         • Modified with setLayout method.




                                             16
Container and Layout
 1   // a container with horizontal layouyt manager
 2   var hbox = new qx.ui.layout.HBox();
 3   hbox.setSpacing(4); // set property
 4
 5   // assign layout
 6   var ctr1 = new qx.ui.container.Composite(hbox);
 7   ctr1.setWidth(600); ctr1.setHeight(40);
 8   // layout properties: position
 9   root.add(ctr1,{column: 0, row: 1, colSpan: 2});
10
11   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 property
15       tf2.setAllowGrowY(e.getData());
16          this.info(’New Value for AllowGrowY: ’+e.getData());
17   });
18   ctr1.add(tf2);ctr1.add(bt2);




     The container widget together with an associated layout object can arrange wid-
     gets on screen giving the user high level control over the operation. Here the tog-
     gle button lets us choose if the text field should grow vertically to fill the available
     space or not.




                                              17
Grid Layout




   • qx.ui.layout.Grid

   • fully dynamic

   • ideal for dialogs

   • one widget per cell

   • row and column spans

   • minimal and maximal column and row sizes

   • fixed row and column sizes


The grid widget has all the flexibility of a html table plus a great deal more. It is
the ideal basis for laying out dialog boxes or complex screen setups.



About the Qooxdoo Layout Widgets

   • A container widget needs a layout manager to place its children.

   • The layout manager object has properties.

   • Every widget has basic properties like: alignment, growability, shrinkabil-
     ity, stretchability, margins, padding, width and height.

   • Each widget can have layout-specific properties.

   • Layout properties get checked as the widget is added to a layout.

Lets play with the layout demos!

For me the best way to understand how layouts work was to first try them out in
the demo browser and then use them in a little program of my own.


                                        18
Localized Applications
1    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   });


        • add locale to config.json

        • ./generate.py translation

        • translate de.po

        • ./generate.py source




     Qooxdoo locale files are normal .po files. You can use any of the existing kde/g-
     nome tools for updating your translations. Qooxdoo will automatically pick the
     language that best matches the locale settings in your browser.



     calling code on the server

        • JSON RPC for transport

        • various language bindings

        • often minimal server code

        • async with callbacks

        • qx.io.Rpc




                                           19
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 reference
7        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 -w
2    use strict;
3    use lib qw(perl);
4
5    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 configure CGI::Session to keep
     the session data in a database.




                                          20
An RPC Example: the myclass service
     source/perl/Qooxdoo/Services/myclass.pm:
1    package Qooxdoo::Services::myclass;
2    use strict;
3
4    # for now let everyone access the methods
5    sub GetAccessibility { ’public’ };
6
7  sub method_mymethod {
8      my $error = shift;
 9     my $arg = shift;
10     return ’The argument was: ’.$arg;
11 }
12
13   1;

     The myclass module gets loaded dynamically.



     An RPC Example: Getting it to work

          • Install language bindings from Qooxdoo website.

          • ln -s /var/www/lisa08 build

          • ./generate.py build

          • cp -rp source/jsonrpc.cgi source/perl build

          • Open the application in the browser.

          • Make sure the cgis are actually executed

          • Watch the Apache error log while testing.


     Debugging client/server AJAX applications can be pretty daunting. I find that I
     have the best success when I keep my eyes on the Apache error log and add debug-
     ging output liberally. For the Perl bindings, setting $Qooxdoo::JSONRPC::debug
     to 1 gives also valuable debugging output from the Qooxdoo Perl modules point
     of view.




                                             21
Organizing the code into multiple classes

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




     The textclick class
1    /**
2      * textclick combines a textfield and a button.
3      */
4    qx.Class.define(quot;lisa08.ui.textclickquot;,
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      },
19
20
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: null
33     }
34   });


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


     By splitting your application into different classes, your code becomes simpler to
     understand and to test, you can even re-use it in other projects.
     The generator tool will merge your own classes with the relevant Qooxdoo Classes
     into optimized, monolithic JavaScript files, ready for deployment.



     The Message Bus

        • Communication in “large” applications.

        • Singleton message bus class.

        • 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 console
 8   bus.subscribe(’mybus.1’,function(m){
 9       mywi2.getTextField().setValue(m.getData());
10       this.info(’Got ’+m.getData()+’ from the bus’);
11   },this);
12
13   root.add(mywi2,{column: 0, row: 6, colSpan: 2});


     While a message bus can provide a nice way to get inner-application communica-
     tion organized, you may soon end up in a maze of different messages being sent
     back and forth to no end. A better way to organize an applications logic may be
     provided by the qx.util.fsm class which lets you describe the logic in form
     of an finite state machine which then takes care of how your gui works. There is
     a nice example in the Qooxdoo api viewer.


     Tobias Oetiker <tobi@oetiker.ch>

                                            23

Contenu connexe

Tendances

Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Tomek Kaczanowski
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionSchalk Cronjé
 
NetBeans Support for EcmaScript 6
NetBeans Support for EcmaScript 6NetBeans Support for EcmaScript 6
NetBeans Support for EcmaScript 6Kostas Saidis
 
淺談 Groovy 與 AWS 雲端應用開發整合
淺談 Groovy 與 AWS 雲端應用開發整合淺談 Groovy 與 AWS 雲端應用開發整合
淺談 Groovy 與 AWS 雲端應用開發整合Kyle Lin
 
Apache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystemApache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystemKostas Saidis
 
Openshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhceOpenshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhceDarnette A
 
Extracting Plugins And Gems From Rails Apps
Extracting Plugins And Gems From Rails AppsExtracting Plugins And Gems From Rails Apps
Extracting Plugins And Gems From Rails AppsJosh Nichols
 
The Gradle in Ratpack: Dissected
The Gradle in Ratpack: DissectedThe Gradle in Ratpack: Dissected
The Gradle in Ratpack: DissectedDavid Carr
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developersTricode (part of Dept)
 
Managing dependencies with gradle
Managing dependencies with gradleManaging dependencies with gradle
Managing dependencies with gradleLiviu Tudor
 

Tendances (20)

Gradle in 45min
Gradle in 45minGradle in 45min
Gradle in 45min
 
Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010Gradle talk, Javarsovia 2010
Gradle talk, Javarsovia 2010
 
Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
JS Class 2016
JS Class 2016JS Class 2016
JS Class 2016
 
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers VersionCool Jvm Tools to Help you Test - Aylesbury Testers Version
Cool Jvm Tools to Help you Test - Aylesbury Testers Version
 
JS class slides (2016)
JS class slides (2016)JS class slides (2016)
JS class slides (2016)
 
nullcon 2010 - Intelligent debugging and in memory fuzzing
nullcon 2010 - Intelligent debugging and in memory fuzzingnullcon 2010 - Intelligent debugging and in memory fuzzing
nullcon 2010 - Intelligent debugging and in memory fuzzing
 
Ugo Cei Presentation
Ugo Cei PresentationUgo Cei Presentation
Ugo Cei Presentation
 
NetBeans Support for EcmaScript 6
NetBeans Support for EcmaScript 6NetBeans Support for EcmaScript 6
NetBeans Support for EcmaScript 6
 
淺談 Groovy 與 AWS 雲端應用開發整合
淺談 Groovy 與 AWS 雲端應用開發整合淺談 Groovy 與 AWS 雲端應用開發整合
淺談 Groovy 與 AWS 雲端應用開發整合
 
Apache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystemApache Groovy: the language and the ecosystem
Apache Groovy: the language and the ecosystem
 
Openshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhceOpenshift cheat rhce_r3v1 rhce
Openshift cheat rhce_r3v1 rhce
 
C++ for the Web
C++ for the WebC++ for the Web
C++ for the Web
 
Js tacktalk team dev js testing performance
Js tacktalk team dev js testing performanceJs tacktalk team dev js testing performance
Js tacktalk team dev js testing performance
 
Rest, sockets em golang
Rest, sockets em golangRest, sockets em golang
Rest, sockets em golang
 
Extracting Plugins And Gems From Rails Apps
Extracting Plugins And Gems From Rails AppsExtracting Plugins And Gems From Rails Apps
Extracting Plugins And Gems From Rails Apps
 
The Gradle in Ratpack: Dissected
The Gradle in Ratpack: DissectedThe Gradle in Ratpack: Dissected
The Gradle in Ratpack: Dissected
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developers
 
Hands on the Gradle
Hands on the GradleHands on the Gradle
Hands on the Gradle
 
Managing dependencies with gradle
Managing dependencies with gradleManaging dependencies with gradle
Managing dependencies with gradle
 

En vedette

Engage -- eGovernment strategies for success
Engage -- eGovernment strategies for successEngage -- eGovernment strategies for success
Engage -- eGovernment strategies for successNIC Inc | EGOV
 
Anonos U.S. Patent Number 9,087,215
Anonos U.S. Patent Number 9,087,215Anonos U.S. Patent Number 9,087,215
Anonos U.S. Patent Number 9,087,215Ted Myerson
 
Configuring Greenstone's OAI server
Configuring Greenstone's OAI serverConfiguring Greenstone's OAI server
Configuring Greenstone's OAI serverDiego Spano
 
State of virtualisation -- 2012
State of virtualisation -- 2012State of virtualisation -- 2012
State of virtualisation -- 2012Jonathan Sinclair
 
FUSE and beyond: bridging filesystems paper by Emmanuel Dreyfus
FUSE and beyond: bridging filesystems paper by Emmanuel DreyfusFUSE and beyond: bridging filesystems paper by Emmanuel Dreyfus
FUSE and beyond: bridging filesystems paper by Emmanuel Dreyfuseurobsdcon
 
Upgrade OBIEE to 11.1.1.7.1
Upgrade OBIEE to 11.1.1.7.1Upgrade OBIEE to 11.1.1.7.1
Upgrade OBIEE to 11.1.1.7.1Osama Mustafa
 
DBA Basics guide
DBA Basics guideDBA Basics guide
DBA Basics guideazoznasser1
 
Owasp top 10_-_2013
Owasp top 10_-_2013Owasp top 10_-_2013
Owasp top 10_-_2013Edho Armando
 
Especial Linux Magazine Software Público
Especial Linux Magazine Software PúblicoEspecial Linux Magazine Software Público
Especial Linux Magazine Software PúblicoGovBR
 
Internet ve e posta yönetimi
Internet ve e posta yönetimiInternet ve e posta yönetimi
Internet ve e posta yönetimiErol Dizdar
 
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...IIBA_Latvia_Chapter
 
SharePoint Search - SPSNYC 2014
SharePoint Search - SPSNYC 2014SharePoint Search - SPSNYC 2014
SharePoint Search - SPSNYC 2014Avtex
 
Curso richfaces 3.3.3 II
Curso richfaces 3.3.3 IICurso richfaces 3.3.3 II
Curso richfaces 3.3.3 IIeclaudioaugusto
 
Static Detection of Application Backdoors
Static Detection of Application BackdoorsStatic Detection of Application Backdoors
Static Detection of Application BackdoorsTyler Shields
 

En vedette (20)

Engage -- eGovernment strategies for success
Engage -- eGovernment strategies for successEngage -- eGovernment strategies for success
Engage -- eGovernment strategies for success
 
Anonos U.S. Patent Number 9,087,215
Anonos U.S. Patent Number 9,087,215Anonos U.S. Patent Number 9,087,215
Anonos U.S. Patent Number 9,087,215
 
Configuring Greenstone's OAI server
Configuring Greenstone's OAI serverConfiguring Greenstone's OAI server
Configuring Greenstone's OAI server
 
Planet talent
Planet talentPlanet talent
Planet talent
 
AngularJS and SPA
AngularJS and SPAAngularJS and SPA
AngularJS and SPA
 
State of virtualisation -- 2012
State of virtualisation -- 2012State of virtualisation -- 2012
State of virtualisation -- 2012
 
FUSE and beyond: bridging filesystems paper by Emmanuel Dreyfus
FUSE and beyond: bridging filesystems paper by Emmanuel DreyfusFUSE and beyond: bridging filesystems paper by Emmanuel Dreyfus
FUSE and beyond: bridging filesystems paper by Emmanuel Dreyfus
 
Upgrade OBIEE to 11.1.1.7.1
Upgrade OBIEE to 11.1.1.7.1Upgrade OBIEE to 11.1.1.7.1
Upgrade OBIEE to 11.1.1.7.1
 
DBA Basics guide
DBA Basics guideDBA Basics guide
DBA Basics guide
 
Owasp top 10_-_2013
Owasp top 10_-_2013Owasp top 10_-_2013
Owasp top 10_-_2013
 
Manual web2.0 professores
Manual web2.0 professoresManual web2.0 professores
Manual web2.0 professores
 
Especial Linux Magazine Software Público
Especial Linux Magazine Software PúblicoEspecial Linux Magazine Software Público
Especial Linux Magazine Software Público
 
Internet ve e posta yönetimi
Internet ve e posta yönetimiInternet ve e posta yönetimi
Internet ve e posta yönetimi
 
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...
'A View-Based Approach to Quality of Service Modelling in Service-Oriented En...
 
SharePoint Search - SPSNYC 2014
SharePoint Search - SPSNYC 2014SharePoint Search - SPSNYC 2014
SharePoint Search - SPSNYC 2014
 
Visual facilitation for agile BAs
Visual facilitation for agile BAsVisual facilitation for agile BAs
Visual facilitation for agile BAs
 
A internet sob ataque!
A internet sob ataque!A internet sob ataque!
A internet sob ataque!
 
Curso richfaces 3.3.3 II
Curso richfaces 3.3.3 IICurso richfaces 3.3.3 II
Curso richfaces 3.3.3 II
 
Static Detection of Application Backdoors
Static Detection of Application BackdoorsStatic Detection of Application Backdoors
Static Detection of Application Backdoors
 
FinistJUG - Apache TomEE
FinistJUG - Apache TomEEFinistJUG - Apache TomEE
FinistJUG - Apache TomEE
 

Similaire à LISA Qooxdoo Tutorial Handouts

LISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesLISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesTobias Oetiker
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyDavid Padbury
 
How to make Ajax Libraries work for you
How to make Ajax Libraries work for youHow to make Ajax Libraries work for you
How to make Ajax Libraries work for youSimon Willison
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGuillaume Laforge
 
WebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open webWebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open webpjcozzi
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing UpDavid Padbury
 
The curious Life of JavaScript - Talk at SI-SE 2015
The curious Life of JavaScript - Talk at SI-SE 2015The curious Life of JavaScript - Talk at SI-SE 2015
The curious Life of JavaScript - Talk at SI-SE 2015jbandi
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James NelsonGWTcon
 
Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?Patrick Chanezon
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails IntroductionEric Weimer
 
Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Libraryjeresig
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptHazelcast
 
JavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureJavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureSimon Willison
 
Scripting Oracle Develop 2007
Scripting Oracle Develop 2007Scripting Oracle Develop 2007
Scripting Oracle Develop 2007Tugdual Grall
 
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume LaforgeGroovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume LaforgeGuillaume Laforge
 

Similaire à LISA Qooxdoo Tutorial Handouts (20)

LISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesLISA QooxdooTutorial Slides
LISA QooxdooTutorial Slides
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
Javascript Best Practices
Javascript Best PracticesJavascript Best Practices
Javascript Best Practices
 
How to make Ajax Libraries work for you
How to make Ajax Libraries work for youHow to make Ajax Libraries work for you
How to make Ajax Libraries work for you
 
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume LaforgeGroovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
Groovy and Grails in Action - Devoxx 2008 - University - Guillaume Laforge
 
WebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open webWebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open web
 
JavaScript Growing Up
JavaScript Growing UpJavaScript Growing Up
JavaScript Growing Up
 
Os Wilhelm
Os WilhelmOs Wilhelm
Os Wilhelm
 
dojo.Patterns
dojo.Patternsdojo.Patterns
dojo.Patterns
 
The curious Life of JavaScript - Talk at SI-SE 2015
The curious Life of JavaScript - Talk at SI-SE 2015The curious Life of JavaScript - Talk at SI-SE 2015
The curious Life of JavaScript - Talk at SI-SE 2015
 
"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson"Xapi-lang For declarative code generation" By James Nelson
"Xapi-lang For declarative code generation" By James Nelson
 
Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?Google's HTML5 Work: what's next?
Google's HTML5 Work: what's next?
 
Groovy And Grails Introduction
Groovy And Grails IntroductionGroovy And Grails Introduction
Groovy And Grails Introduction
 
Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Library
 
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScriptThe Power of the JVM: Applied Polyglot Projects with Java and JavaScript
The Power of the JVM: Applied Polyglot Projects with Java and JavaScript
 
JavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureJavaScript Libraries: The Big Picture
JavaScript Libraries: The Big Picture
 
Scripting Oracle Develop 2007
Scripting Oracle Develop 2007Scripting Oracle Develop 2007
Scripting Oracle Develop 2007
 
Trimming The Cruft
Trimming The CruftTrimming The Cruft
Trimming The Cruft
 
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume LaforgeGroovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
Groovy in the Enterprise - Case Studies - TSSJS Prague 2008 - Guillaume Laforge
 
How to build the Web
How to build the WebHow to build the Web
How to build the Web
 

Dernier

HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 

Dernier (20)

HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 

LISA Qooxdoo Tutorial Handouts

  • 1. The Joy of writing JavaScript Applications How Qooxdoo puts the fun back into programming for the web Tobias Oetiker 22nd Large Installation System Administration Conference
  • 2. 1 Introduction The Browser: my application platform • Applications in the Browser: Netscapes original Plan. • Performance: SquirelFish, V8, Tracemonkey engines. • JavaScript graduated with Web 2.0 • Widget libraries for breakfast, lunch and dinner. • A separte hack for every browser. It is said that people at Netscape back in the nineties had the vision of escaping the Microsoft dominance by enhancing their browser so that it could become a platform of its own for running client side applications. It is also said that MS was not thrilled by this thought. Netscape is no more but the vision has become a reality. The Web 2.0 hype sparked a slew of highly interactive web applications that used JavaScript snipets on the browser to enhance the user experience. Qooxdoo: application in the browser • Web 2.0 is all about the look and feel. • Web pages with eye candy. • Applications running in the browser. • Back to client/server computing. • Qooxdoo is a complete environment.
  • 3. Qooxdoo features • Turns JS into a grown up OO language. • No HTML or CSS knowledge required. • Cross Browser: >= FF 1.5, Safari 3, Chrome, IE6, Opera8. • Multilingual. • Full API Documentation. • Users works ’inside the box’. • LGPL, EPL • Fun. Qooxdoo is way more than yet another JavaScript widget collection. Apart from a cool collection of widgets, it introduces fully object oriented programming to the JavaScript world. Similar to the way OO got introduced in the Perl world, the Qooxdoo folks designed a framework that provides all of the OO bits that were left out of JavaScript’s initial design. 2
  • 4. 2 Hello World Jump right in • Install Python. http://www.python.org/download/ • Unpack Qooxdoo. http://qooxdoo.org/download/ • Get Js2-mode for emacs http://code.google.com/p/js2-mode/ • Do this NOW! Some claim Qooxdoo has a steep learning curve since it does just publish some JavaScript files you can link into your web page. While there are ways todo this all the same, I think it is actually a good thing since Qooxdoo’s main objective is to provide an environment for writing standalone, browser based applications. With such a scope in mind, the developer should treat herself to a decent programming environment. Generating the first application • Point your path to qooxdoo-0.8-sdk/tools/bin • Change directory to your development space. • Run create-application.py -name hello • CD into the hello directory. • Run generate.py source • Point your browser to hello/source/index.html Qooxdoo comes with many sensible defaults. One could argue, that a lot of Qoox- doo’s appeal comes from the many defaults. Normally when I start to write a pro- gram from scratch I am faced with way too many decisions at once. I often spend considerable time mulling about seemingly trivial decisions instead of just start- ing to program. Qooxdoo takes a lot of this “freedom” away by setting a standard on how to write your application. Many of these defaults can be changed, but I found that they are actually quite a good aproximation to my optimal program- ming environment, so there is no immediate need to change them. 3
  • 5. generated files hello/generate.py hello/config.json hello/source/resource/hello/test.png hello/source/translation/readme.txt hello/source/class/hello/test/DemoTest.js hello/source/class/hello/Application.js hello/source/index.html hello/Manifest.json hello/readme.txt source code: hello/source/class/hello/Application.js 1 /* Tell qooxdoo that we need the resources in hello/* 2 #asset(hello/*) 3 */ 4 qx.Class.define(quot;hello.Applicationquot;, 5 { 6 extend : qx.application.Standalone, 7 members : 8 { 9 main : function() 10 { 11 // Call super class 12 this.base(arguments); 13 // Enable logging in debug variant 14 if (qx.core.Variant.isSet(quot;qx.debugquot;, quot;onquot;)) 15 { // native logging capabilities 16 qx.log.appender.Native; 17 // additional cross-browser console. 18 // Press F7 to toggle visibility 19 qx.log.appender.Console; 20 } 21 // Create a button 22 var button1 = new qx.ui.form.Button( 23 quot;First Buttonquot;, quot;hello/test.pngquot;); 24 // Document is the application root 25 var doc = this.getRoot(); 26 // Add button to document at fixed coordinates 27 doc.add(button1, {left: 100, top: 50}); 28 // Add an event listener 29 button1.addListener(quot;executequot;, function(e) { 30 alert(quot;Hello World!quot;); 31 }); 32 } 33 } 34 }); The original Qooxdoo hello world application, modified to fit the slide. 4
  • 6. 3 The finer Points of JavaScript Qooxdoo and JavaScript • It’s just like Perl and OO • It’s all about anonymous functions • 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); Calling function creates a function object which I can use exactly like a normal function. Scoping for the naïve You know scoping from other languages 1 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 5
  • 7. 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! While many languages provide scope for every block, this is not the case for JavaScript. Here the only scoping block is the function block. So if we need scope inside a looping block for example, we just add an anonymous function and execute it in place. I am not sure how efficient this is, so do not use it in tight loops. A simple closures example 1 var set; 2 var get; 3 var j=2; 4 (function(){ // the magic javascript scope trick 5 var j; 6 set = function(x){j=x}; 7 get = function(){alert(’Hidden j is ’+j)}; 8 })(); // end of scope 9 set(33); 10 get(); 11 alert(’Outside j is still ’+j); Everything as expected. 6
  • 8. With closures, several functions can share a common variable defined outside the function. Lisp/Scheme has been the first language to implement this concept. To- day many object oriented languages can do closures: There are subtle differences though, as I had to discover the hard way, working with JavaScript coming from a Perl/C background. 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 block 3 var g = z; 4 j[g] = function(a){ 5 alert(’The value for j[’ + a + ’] is ’+g); 6 }; 7 })()} // end of block 8 j[2](2); Again the anonymous function trick comes to the rescue. 7
  • 9. When programming with Qooxdoo its almost entirely about anonymous functions and closures. It took me almost a year to finally figure out about JavaScript scop- ing, before it was just the odd problem which I could not really fix and spent hours working finding a work-a-round, cursing mysterious JavaScript bugs in the process. fun with this 1 var hello = { 2 world: ’You’, 3 show: function(){ 4 alert(’Hello ’+this.world+’ this: ’+this); } 5 }; 6 hello.show(); // method call 7 var plain = hello.show; // function pointer 8 var world = ’Me’; // change this.world 9 plain(); // method call this refers to this refers to the browsers the hello object. base Window object. Be careful when using this in an anonymous function since it always points to the current parent. Call-back functions are especially ’vulnerable’ to this problem. 8
  • 10. 4 The Qooxdoo OO Features 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 this 1 qx.Class.define(quot;my.cool.Classquot;, { 2 // declare constructor, members, ... 3 }); A regular class can then be instantiated 1 var myClass = new my.cool.Class; Class inheritance The map contains the meat of the class. 1 qx.Class.define(quot;my.cool.Classquot;, 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(quot;my.cool.Classquot;, { 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(); 9
  • 11. Instance Members Instance members reside in the members map. 1 qx.Class.define(quot;my.cool.Classquot;, { 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(quot;my.cool.Classquot;, 2 { 3 extend : my.great.SuperClass, 4 construct : function(x) { 5 this.base(arguments, x); // superclass constructor 6 } 7 members : { 8 foo : function(x) { 9 this.base(arguments, x); 10 } 11 } 12 }); The this.base construct works for both constructor and member functions. The arguments object/map used in this example is a native JavaScript feature. Inside a function call it contains all the information about how the function was called: a list of the arguments passed to the function as well as pointers to the function itself. 10
  • 12. Generic access to static members 1 qx.Class.define(quot;my.cool.Classquot;, 2 { 3 extend : qx.core.Object, 4 construct : function(x){this.base(arguments,x)}, 5 statics : { 6 PI : 3.141 7 } 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 class 3 }); 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. A mixin may contain anything a normal class can contain, but it does not get instantiated or inherited from directly. Is included into new and existing classes to provide additional features through its methods and properties. class access control There is the following naming convention for class members. 1 publicMember 2 _protectedMember 3 __privateMember In the Qooxdoo build process it is optionally possible to randomize the names of private members to protect access. 11
  • 13. 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 if you must intervene ... 1 members: { 2 foo: qx.core.Variant.select( 3 ’qx.bom.client.Engine.NAME’, { 4 ’mshtml|opera’: function() { 5 // Internet Explorer or Opera 6 }, 7 ’default’: function() { 8 // All other browsers 9 } 10 } 11 ) 12 } 12
  • 14. 5 Working with Qooxdoo The demo Browser 1 $ cd $QX/frontend/application/demobrowser/ 2 $ ./generate.py build 3 $ gnome-open build/index.html Or surf to http://demo.qooxdoo.org/current/demobrowser For me the demobrowser is the quickest way of seeing how to write Qooxdoo. Select a widget on the tree at the left and activate the JS Code toggle. Now you can see both the running program as well as the JavaScript code. The rest is mostly cut and paste. 13
  • 15. The API Documentation 1 $ cd $QX/frontend/framework 2 $ ./generate.py api 3 $ gnome-open api/index.html Or surf to http://demo.qooxdoo.org/current/apiviewer The Qooxdoo API documentation is generated directly from embedded javadoc in the Qooxdoo JS source files. You can apply the same process to your own Qooxdoo application to get a api viewer for your own code. The Qooxdoo generator Python is the sole dependency • generator.py is the tool • it gets called by generate.py The generator has many functions • source - prep development code • build - prep code for deployment • api - build api doc • lint - check your code for beauty • pretty - fix the code layout • ... 14
  • 16. Running your Qooxdoo program in source Use source code during development 1 $ cd hello 2 $ ./generate.py source 3 $ gnome-open source/index.html As long as you do not use any new classes, press reload in the browser to see changes. To run a Qooxdoo application, the code for each class you used must be loaded. This can easily be 30 or more files. When calling the generator with the option source it will create an JavaScript file in source/script/hello.js which takes care of loading these class files. While developing you may want to try the lint option as well, to catch some frequent mistakes. Deploying your Qooxdoo program 1 $ cd hello 2 $ ./generate.py build 3 $ cp -rp build ~/public_html/hello • only two js files • code gets optimized and compressed • no external dependencies The Qooxdoo generator builds a fully custom js file containing all the Qooxdoo classes required to run your application. It also compresses and optimizes the code in this step. You will notice that the first source and build run will take quite some time. This is because Qooxdoo creates cache files of all classes involved. If you run the build for a second time things will run much quicker. 15
  • 17. 6 Programming with Qooxdoo Button, TextField and some Action 1 // Create a textfield 2 var tf1 = new qx.ui.form.TextField(’Demo Text’); 3 // Add button to root 4 root.add(tf1, {column: 0, row: 0}); 5 // Create a button 6 var bt1 = new qx.ui.form.Button( 7 ’Open Alert’, ’lisa08/test.png’); 8 // Add button to root 9 root.add(bt1, {column: 1, row: 0}); 10 // Add an event listener 11 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! In this first example there is already a closure. The variable tf1 is used inside the event handler. The function is passed as a reference and takes the access to the TextField object with it. The Layout Manager • Qooxdoo Widgets can contain other widgets. • Layout manager positions child widgets. • qx.ui.container.Composite basic • qx.ui.container.Scroll draws scroll bars • qx.ui.window.Window directs children to an inner composite pane. • Layout manager set at construction time • Modified with setLayout method. 16
  • 18. Container and Layout 1 // a container with horizontal layouyt manager 2 var hbox = new qx.ui.layout.HBox(); 3 hbox.setSpacing(4); // set property 4 5 // assign layout 6 var ctr1 = new qx.ui.container.Composite(hbox); 7 ctr1.setWidth(600); ctr1.setHeight(40); 8 // layout properties: position 9 root.add(ctr1,{column: 0, row: 1, colSpan: 2}); 10 11 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 property 15 tf2.setAllowGrowY(e.getData()); 16 this.info(’New Value for AllowGrowY: ’+e.getData()); 17 }); 18 ctr1.add(tf2);ctr1.add(bt2); The container widget together with an associated layout object can arrange wid- gets on screen giving the user high level control over the operation. Here the tog- gle button lets us choose if the text field should grow vertically to fill the available space or not. 17
  • 19. Grid Layout • qx.ui.layout.Grid • fully dynamic • ideal for dialogs • one widget per cell • row and column spans • minimal and maximal column and row sizes • fixed row and column sizes The grid widget has all the flexibility of a html table plus a great deal more. It is the ideal basis for laying out dialog boxes or complex screen setups. About the Qooxdoo Layout Widgets • A container widget needs a layout manager to place its children. • The layout manager object has properties. • Every widget has basic properties like: alignment, growability, shrinkabil- ity, stretchability, margins, padding, width and height. • Each widget can have layout-specific properties. • Layout properties get checked as the widget is added to a layout. Lets play with the layout demos! For me the best way to understand how layouts work was to first try them out in the demo browser and then use them in a little program of my own. 18
  • 20. Localized Applications 1 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 }); • add locale to config.json • ./generate.py translation • translate de.po • ./generate.py source Qooxdoo locale files are normal .po files. You can use any of the existing kde/g- nome tools for updating your translations. Qooxdoo will automatically pick the language that best matches the locale settings in your browser. calling code on the server • JSON RPC for transport • various language bindings • often minimal server code • async with callbacks • qx.io.Rpc 19
  • 21. 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 reference 7 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 -w 2 use strict; 3 use lib qw(perl); 4 5 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 configure CGI::Session to keep the session data in a database. 20
  • 22. An RPC Example: the myclass service source/perl/Qooxdoo/Services/myclass.pm: 1 package Qooxdoo::Services::myclass; 2 use strict; 3 4 # for now let everyone access the methods 5 sub GetAccessibility { ’public’ }; 6 7 sub method_mymethod { 8 my $error = shift; 9 my $arg = shift; 10 return ’The argument was: ’.$arg; 11 } 12 13 1; The myclass module gets loaded dynamically. An RPC Example: Getting it to work • Install language bindings from Qooxdoo website. • ln -s /var/www/lisa08 build • ./generate.py build • cp -rp source/jsonrpc.cgi source/perl build • Open the application in the browser. • Make sure the cgis are actually executed • Watch the Apache error log while testing. Debugging client/server AJAX applications can be pretty daunting. I find that I have the best success when I keep my eyes on the Apache error log and add debug- ging output liberally. For the Perl bindings, setting $Qooxdoo::JSONRPC::debug to 1 gives also valuable debugging output from the Qooxdoo Perl modules point of view. 21
  • 23. Organizing the code into multiple classes • Object orientation “by the book”. • One file per class. • Java’s file name based approach. • Supported by the generator. • Ideal for code re-use. • Use Inline Docs! • ./generate.py api The textclick class 1 /** 2 * textclick combines a textfield and a button. 3 */ 4 qx.Class.define(quot;lisa08.ui.textclickquot;, 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 }, 19 20 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: null 33 } 34 }); 22
  • 24. Using the textclick class 1 var mywi =new lisa08.ui.textclick( 2 this.tr(’Copy Text from Example 1’)); 3 4 mywi.getButton().addListener(’execute’, function(e) { 5 mywi.getTextField().setValue(tf1.getValue()); 6 this.info(’Set textfield to ’+tf1.getValue()); 7 }); 8 9 root.add(mywi,{column: 0, row: 5, colSpan: 2}); By splitting your application into different classes, your code becomes simpler to understand and to test, you can even re-use it in other projects. The generator tool will merge your own classes with the relevant Qooxdoo Classes into optimized, monolithic JavaScript files, ready for deployment. The Message Bus • Communication in “large” applications. • Singleton message bus class. • 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 console 8 bus.subscribe(’mybus.1’,function(m){ 9 mywi2.getTextField().setValue(m.getData()); 10 this.info(’Got ’+m.getData()+’ from the bus’); 11 },this); 12 13 root.add(mywi2,{column: 0, row: 6, colSpan: 2}); While a message bus can provide a nice way to get inner-application communica- tion organized, you may soon end up in a maze of different messages being sent back and forth to no end. A better way to organize an applications logic may be provided by the qx.util.fsm class which lets you describe the logic in form of an finite state machine which then takes care of how your gui works. There is a nice example in the Qooxdoo api viewer. Tobias Oetiker <tobi@oetiker.ch> 23