Your First Widget

Setting up a widget file is easy, but there are few gotchas that can perplex beginners.

The first step is to create a new widget in the Widget Admin console. Click on the New Widget button and enter a name for your widget. Widget names should be short and snake-case (lowercase, with underscores). This will create the resources for your widget on the server. In this example, I will create a widget called "money_stuff".

Now create a folder for your new widget in the code directory on your local machine.

        // Go to my widget code directory, create a new folder
        admins-mbp:Desktop burfoot$ cd /opt/userdata/lifecode/widgets/dburfoot/
        admins-mbp:dburfoot burfoot$ mkdir money_stuff

Just for the sake of example, I will upload a file called "hello_world.txt" to the server. This won't do anything special, but it confirms that everything is setup correctly.

        admins-mbp:dburfoot burfoot$ cd money_stuff/
        admins-mbp:money_stuff burfoot$ echo "Hello, world" >> hello_world.txt
        admins-mbp:money_stuff burfoot$ ls
        hello_world.txt
Now I upload the widget to the server. If the configuration is working properly, you should see something like this. The system tells you the old stuff it is deleting, as well as the new files it uploads. Notice that you cannot upload specific files, you just upload the widget directory as a batch.
        admins-mbp:script burfoot$ CodeUploader.py widgetname=money_stuff
        Wrote upload file to path /opt/rawdata/servlet/dburfoot__money_stuff.widgetzip
        Deleted old file /opt/userdata/widgetserve/dburfoot/money_stuff/widget.jsp
        Extracted file /opt/userdata/widgetserve/dburfoot/money_stuff/hello_world.txt, size is 13

The file is now available on the WWIO server. Important: Notice that you do not have to log in to access this file! It is public for everyone to see. The WebWidgets framework only authenticates requests that attempt to access Widget data (ie, the info in the SQLite files).

        admins-mbp:money_stuff burfoot$ curl https://webwidgets.io/u/dburfoot/money_stuff/hello_world.txt
        Hello, world

Now we create a skeleton SQLite DB and send it to the server. Go to your Widget data directory and run sqlite3. Notice the name of the sqlite3 DB I created. To name the file correctly, upper-case the widget name, and add the extension "_DB.sqlite". After that, I create a simple table with 3 fields, including an "id" primary key.

        admins-mbp:~ burfoot$ cd /opt/userdata/db4widget/dburfoot
        admins-mbp:dburfoot burfoot$ sqlite3 MONEY_STUFF_DB.sqlite
        SQLite version 3.28.0 2019-04-15 14:49:49
        Enter ".help" for usage hints.
        sqlite> create table big_money (id int, amount int, desc varchar(20), primary key(id));
        sqlite> .schema
        CREATE TABLE big_money (id int, amount int, desc varchar(20), primary key(id));

Now I upload the file with the DataPush.py script. The server tells you a bit about how it is handling the upload, in particular, it tells you how it has auto-generated a JS file from the SQLite definition.

        admins-mbp:script burfoot$ DataPush.py widgetname=money_stuff
        Wrote upload file to path /opt/rawdata/servlet/dburfoot__money_stuff.sqlite
        Saving DB file for widget dburfoot::money_stuff
        Deleted old DB file /opt/userdata/db4widget/dburfoot/MONEY_STUFF_DB.sqlite
        Copied upload file to location /opt/userdata/db4widget/dburfoot/MONEY_STUFF_DB.sqlite, size is 12288
        Created directory /opt/userdata/widgetserve/dburfoot/autogenjs/money_stuff
        Wrote autogen code to path /opt/userdata/widgetserve/dburfoot/autogenjs/money_stuff/BigMoney__001.js

If you're interested, you can look at the JS autogen file. The file is pretty large, I'm just showing the first 20 lines:

admins-mbp:money_stuff burfoot$ curl https://webwidgets.io/u/dburfoot/autogenjs/money_stuff/BigMoney__001.js | head -n 20
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  3966  100  3966    0     0  80938      0 --:--:-- --:--:-- --:--:-- 80938
// Auto-Generated JavaScript code for big_money
// Definition of main collection name

BigMoneyTable = 
{

    // Table properties
    widgetOwner : "dburfoot",
    widgetName : "money_stuff",
    tableName : "big_money",
    _dataMap : new Object(),


    register : function(tableitem)
    {
        // Item inherits same DB as collection
        tableitem._dbName = this._dbName;

        // Assign the K/Value pair.
        this._dataMap[tableitem.getPkeyStr()] = tableitem;
        ....

Don't worry: you don't actually need to understand all of that code! It is just backend plumbing for the system.

Now I'm going to create a bare-bones widget.jsp file. You can use this page as a skeleton for developing your widgets.

<html>
<head>
<title>Money Stuff</title>

<wisp/>

<script>
function redisplay()
{
    const itemlist = W.getItemList("big_money");
    populateSpanData({"num_records" : itemlist.length });
}
</script>

</head>

<body onLoad="javascript:redisplay()">

<center>

<h3>Money Stuff</h3>

Number of records: <span id="num_records"></span>

</center>
</body>
</html>

As you can see, there's only one difference between this file and a normal, pure HTML/JS file (ie, a file you could look at with your browser's Open File command). The difference is the DataServer tag that comes right after the <title> tag. This tag instructs the WebWidgets framework to pull in the data associated with the page. The framework authenticates the user using the request object (this is a Java HttpServletRequest). It also uses the request object to determine the widget name from the URL, and pulls in all of the code and data associated with the widget. The basicInclude command pulls in the entire widget database; it is possible to be more selective about what data is requested, and also to pull in data from other widgets.

Older widget code used two additional tags called AuthInclude and AssetInclude. AuthInclude was placed at the top of every .jsp file, and instructed the system to authenticate the user before serving data. This tag is still used, but you don't need to explicitly include it: the framework adds it to every .jsp file when it is uploaded. The AssetInclude tag was used to pull in the JS library code needed by the system; this is now done by the DataServer tag.

If all goes well, you should see a page that looks like this:

It's showing 0 records because we don't have any data in the SQLite DB. Let's go back to the DB and enter some data:

        admins-mbp:dburfoot burfoot$ sqlite3 MONEY_STUFF_DB.sqlite 
        SQLite version 3.28.0 2019-04-15 14:49:49
        Enter ".help" for usage hints.
        sqlite> .schema
        CREATE TABLE big_money (id int, amount int, desc varchar(20), primary key(id));
        sqlite> insert into big_money values (5, 15, 'cheeseburger');

And use the uploader script to send the data to the server:

        admins-mbp:script burfoot$ DataPush.py username=dburfoot widgetname=money_stuff
        Wrote upload file to path /opt/rawdata/servlet/dburfoot__money_stuff.sqlite
        Saving DB file for widget dburfoot::money_stuff
        Deleted old DB file /opt/userdata/db4widget/dburfoot/MONEY_STUFF_DB.sqlite
        Copied upload file to location /opt/userdata/db4widget/dburfoot/MONEY_STUFF_DB.sqlite, size is 12288
        New version of AutoGen code identical to previous for DB big_money

Now we reload the page in the browser and we see our new record:

You can also see the record content by going into the browser JavaScript console and calling W.getItemList(..):

Okay! Your widget is setup correctly. From here, you can add more tables to the SQLite database, or start to build out the user interface for your widget. For more ways to manipulate the data, check out the JavaScript API.