Web App Development Overview

Part 4: Writing a Mobile Web App with Pascal


Contents

Introduction
Setting up
A simple app
The Fish Facts app
Future developments
Misc. notes


Introduction

Part 1 discusses creating a Web app that uses the qooxdoo JavaScript framework for the app's user interface. These notes discuss writing a qooxdoo app in Pascal, using the Free Pascal "transpiler" to convert the Pascal to JavaScript instead of writing the JavaScript directly.

The rest of the qooxdoo development process remains the same, with the only difference being how the required JavaScript is created.


Setting up

  1. Download the qooxdoo SDK. If you prefer to use the development version of qooxdoo, you can download a .zip from the qooxdoo GitHub repository.

    Unzip this file anywhere you want; no installation is needed.

  2. On Windows, make sure you have Python 2.7 installed. Mac and Linux systems will already have Python installed.

  3. Sass is used by qooxdoo to create CSS files. You may already have Ruby Sass installed; if not, get it from here.

    On Windows you may need to first install Ruby. The small Ruby installer without Devkit from here is sufficient.

    On Linux, you can install Sass directly with this: sudo apt-get install ruby-sass

  4. Download the Pas2JS compiler (transpiler) and RTL from here.

    Unzip this file anywhere you like; no installation is needed.

  5. Download the PnJ .zip from here. This includes Pascal interface units for the qooxdoo classes.

    Unzip this file anywhere you like; no installation is needed.


A simple app

Here are the steps for manually creating a simple mobile app that has a single page:

  1. Use the qooxdoo script to create the app directory and structure. In a terminal, change to where you want to create the directory and enter something like this (substitute the path to your qooxdoo directory):

    python ~/Tools/qooxdoo-5.0.2-sdk/tool/bin/create-application.py --name=simple --type=mobile

    This will create a qooxdoo mobile app and directory named simple. (The source for this app is also included in the PnJ .zip.)

    If you have the qxotica package installed in Lazarus, you can also use File | New to create the qooxdoo app.

  2. Delete the generated JavaScript files. Since you'll be generating JavaScript from Pascal, you don't need these files that qooxdoo created. In the app's source/class/simple directory, delete everything that's there. (If you created the app with Lazarus, you can retain the Lazarus project file simple.lpi.)

    If you have npm installed, the current version of qooxdoo (5.0.2) will also create Gruntfile.js, package.json, package-lock.json, and node_modules in the top level of the app's directory. You can delete these as well. If you're using the trunk version of qooxdoo, these files won't be created.

  3. Create Application.pas in source/class/simple with any text editor. Copy and paste this code:

    program Application;
    
    uses
      JS,
      qx.ui.mobile,
      MainPage;
    
    var
      manager   : TPage_Manager;
      aMainPage : TMainPage;
    begin
      manager := TPage_Manager.New(False);
    
      aMainPage := TMainPage.New;
    
      manager.addDetail(aMainPage);
    
      aMainPage.show(nil);
    end.
    

    This code is pretty simple: create a page manager and the main page, add the page to the manager, show the page.

  4. Create MainPage.pas in source/class/simple. Copy and paste this code:

    unit MainPage;
    
    interface
    
    {$modeswitch externalclass}
    
    uses
      JS,
      qx,
      qx.ui.mobile;
    
    type
      TMainPage = class external name 'simple.MainPage' (TPage_NavigationPage)
      end;
    
    
    implementation
    
    procedure Construct;
    begin
      TMainPage(JSThis).base(JSArguments, nil);  //call ancestor's constructor
      TMainPage(JSThis).setTitle('Simple App');
    end;
    
    
    procedure Initialize;
    begin
      TMainPage(JSThis).base(JSArguments, nil);  //call ancestor's method
    end;
    
    
    procedure Destruct;
    begin
    end;
    
    
    initialization
    
      TQx_Class.define('simple.MainPage',
        new(['extend', TPage_NavigationPage,
    
             'construct', @Construct,
    
             'events',
               new([]),
    
             'properties',
               new([]),
    
             'members',
               new(['_initialize', @Initialize]),  //override
    
             'destruct', @Destruct]));
    
    end.
    

    Because JavaScript is not an OOP language, qooxdoo introduces its own system for adding OOP to JavaScript, using a "closed form" of class declaration. You can read more about that here if you're interested. Instead of declaring the class's structure, the class is defined completely by calling define. In the example code, this is done in the unit's initialization section to ensure that the class is defined before it's used.

    Note how the class is also declared as an external class at the top of the unit. Since everything has to be declared in Pascal, this is needed so the class's inherited methods can be referenced in Application.pas.

    The define call illustrates two language features that are used routinely in JavaScript and qooxdoo. The first is the JavaScript object (or "map" in qooxdoo terminology). Anytime you need to pass a group of key-value pairs in JavaScript, you use an object ( {} ). You can create a JavaScript object in Pascal with the new function. In this example, a map of six keys is passed to define.

    The other recurring JavaScript language feature is anonymous functions, useful for on-the-fly function declarations. With qooxdoo, this allows the function's code to appear immediately after the key it's associated with. Since Pas2JS does not support anonymous functions, the example code uses named functions Construct, Initialize and Destruct.

    The Construct and Initialize procedures show how to work with another important JavaScript language feature: the this keyword that's part of all functions and which qooxdoo uses to implement polymorphism. JSThis is the Pas2JS equivalent, which is typecast to the type (TMainPage) of the object passed to the function so the object's methods can be called.

  5. Copy RunMobileApp.js from PnJ's packages/qooxdoo directory to the app's source/class/simple directory. Edit this file and change myapp to simple in two places. You can then forget about this little file. It's only needed to work around a chicken-and-egg problem when using the Pas2JS runtime with qooxdoo. See the comments in the file for more information.

  6. Compile the Pascal to generate Application.js. Create a script or batch file, then copy and paste and edit this as needed:

    #!/bin/sh
    set -e
    
    pas2jsdir=~/Tools/pas2js/bin
    qxunitsdir=~/Tools/pnj/packages/qooxdoo
    
    $pas2jsdir/pas2js -Jirtl.js -JiRunMobileApp.js -Jc -JoUseStrict- -Tbrowser -Fu$qxunitsdir Application.pas
    

  7. Generate the qooxdoo app. From the top level of the app directory, run the generate.py script:

    python generate.py source

    The first time you run generate.py, it creates a cache; this may take a couple minutes, but subsequent runs will only take seconds. When complete, load index.html (in the app's source directory) into your browser to run the app.

    Note that if you created the app in Lazarus with qxotica, you can also run generate.py by opening simple.lpi in Lazarus and choosing Run | Compile.

    To generate a final deployment version:

    python generate.py build

    This minimizes and obfuscates the app's JavaScript code and includes only the qooxdoo classes that the app uses. You can copy the contents of the app's build directory to your Web server. No other files are needed to deploy the app.

    To generate the app from the example files supplied with PnJ, edit the simple app's config.json file and change QOOXDOO_PATH so it points to where you unzipped the qooxdoo SDK.


The Fish Facts app

Part 1 gives the JavaScript code for a qooxdoo version of the venerable Delphi Fish Facts app. Here's the equivalent Pascal code. See the comments in the JavaScript code given in Part 1 for more information about what the code is doing.

Application.pas:

MainPage.pas:

DetailPage.pas:


Future developments

The previous notes describe what you can do today with Pas2JS and qooxdoo. Here are some thoughts on where development might become more automatic and streamlined in the future.

  1. Lazarus trunk (1.9) has some support for Pas2JS integration that you can play around with if you've built the IDE yourself from trunk. The qooxdoo Pascal interface units include a Lazarus package.

  2. Support for anonymous functions is a planned language feature for Pas2JS. Look at the number of places just in DetailPage.pas above where this would be useful.

  3. The next major version of qooxdoo (6.0) should include a command line compiler that will replace much of the current Python toolchain (generate.py, etc.). It includes its own copy of Sass too.

  4. The Pascal interface units for qooxdoo do not yet include all of the qooxdoo classes. For example, qooxdoo also has a complete set of user interface controls for developing desktop Web apps. The mobile UI controls generally work fine in desktop browsers, but they are designed for smaller, mobile browsers. If your mobile Web app doesn't look right in a desktop browser, try embedding it in an HTML embed tag, similar to what Part 1 does with the Fish Facts app (see the page's source).


Misc. notes

  1. A qooxdoo app that was generated by the "source" job includes a debugging console built-in, meaning you don't have to open the browser's console to see messages that you've output with console.log. Click and hold briefly on the app's title bar to open the debugging console.

  2. Note the naming of qooxdoo classes in the Pascal interface units. The Pascal convention of prefixing class names with "T" has been followed and the class names have been abbreviated from the actual qooxdoo class names to make them less verbose. So qx.core.Object becomes TCore_Object, qx.ui.mobile.basic.Label becomes TBasic_Label, and so on. With a small number of classes this results in a somewhat vague class name. For example, qx.event.type.Event becomes TType_Event. Note that you can also include the class's unit name when specifying the type, for example, qx.event.TType_Event.

    See the qooxdoo API viewer for documentation on all classes.


Copyright 2018 by Phil Hess.

macpgmr (at) icloud (dot) com

First posted April 26, 2018.

Code syntax highlighting done with highlight.js.