Documentation

This page provides high-level documentation. For more in-depth technical documentation and code examples, follow these links:

Widget development is designed to be fast. You can use the following development cycle:

  1. - Make changes to a local copy of the Widget file
  2. - Run a Python script to upload the new code to the server
  3. - Reload your browser to see the effect of the new code

The Python script reads a simple configuration file, that includes info like where your Widget code is stored on your local machine.

Since the code is on your own computer, you can use any kind of text editor you want to edit it. No special installation or software is required, other than the Python script.

To use WebWidgets, all you need is a browser.

To develop WebWidgets, you will need a few pieces of basic software: Python3, Sqlite3, and curl. If you are using a recent version of Mac OS, you probably already have these tools. If you are using Windows, you might have to install them - but don't worry, these tools are among the most widely-used and battle-tested pieces of software in the world.

The WebWidget framework was very intentionally designed to be as simple and lightweight as possible. The system does not require third party frameworks or libraries either in the browser (JavaScript) or on the developer's machine.

To check if you have the right versions of the development tools already installed, consult the docs for the WebWidgets Python Scripts.

For most Widgets, you need to include only one special tag in your .jsp file, the one with the DataServer command shown below:


<html>
<head>
<title>Link Manager</title>>
<%= DataServer.include(request) %>
<script> // Your JS code here ...

This command instructs the framework to load the data for the widget, transform it into JavaScript objects, and send it to the browser.

Please do not use any other JSP tags in your file, the framework will reject your upload if you try to do this.

The two basic methods are W.lookupItem and W.getItemList. These methods are included in the JavaScript code that is pulled in by the DataServer command.


// Lookup a record given the table name and an ID.
const myitem = W.lookupItem("my_widget_table", 45);
console.log("Item name is " + myitem.getName());
// Get a list of all the records in the table.
const allitems = W.getItemList("my_widget_table");
console.log("Number of items in table is: " + allitems.length);

For more details on how these methods work, see the Widget JavaScript API docs.

To edit a record, just call the syncItem method on the Widget item:

const editid = 33;
const editme = lookupItem("my_widget_table", editid);
editme.setShortName("CoolRecord41");
editme.syncItem();
Older versions of the Widget code used a different method:

// OLD:
syncSingleItem(editme);
// NEW:
editme.syncItem():

Creating a new Widget object is simple, you just create a JavaScript hash with a value corresponding to each column in the given DB table, and call W.buildItem(tblname, record). This method returns a new Widget JS object, but it only exists in the browser. To persist the record to the server, call .syncItem:



    const newrec = {
        "link_url" : "http://danburfoot.net",
        "short_desc" : "NotYetSet",
        "cat_id" : -1
    };
    
    const newlinkitem = W.buildItem("link_main", newrec);       
    newlinkitem.syncItem(); 
    redisplay();

Note that the id column is optional and will be provided by the framework if you leave it out.

There are many approaches to creating dynamic web pages. The technique I use is to compose HTML strings in JavaScript, and then place the result in span or div tags using the innerHTML attribute. This block of code will create a header line that shows the number of records in the table, formatted with h3.

const mylist = getItemList("my_widget_table");
const mystr = "<h3>The number of records is " + mylist.length + "</h3>";
document.getElementById("record_info").innerHTML = mystr;
The main rules for the Widget SQLite file are:

  1. 1. Every table must have an integer primary key field named id.
  2. 2. The column names should be snake-case (all lower case, with underscores to separate distinct words for readability).


sqlite> .schema
CREATE TABLE link_main (id int, cat_id int, short_desc varchar(150), link_url varchar(250), primary key(id));
CREATE TABLE link_categ (id int, short_code varchar(20), full_desc varchar(400), is_active smallint, primary key(id));
The Widget framework JS code generated takes a SQLite file as input, and creates JavaScript code based on it.

CREATE TABLE link_main (id int, cat_id int, short_desc varchar(150), link_url varchar(250), primary key(id));
The objects created from this table will have get/set methods with the following names:

getId() // No setId(..) exists, ID field is immutable.
getCatId() -- setCatId(..)
getShortDesc() -- setShortDesc(..)
getLinkUrl() -- setLinkUrl(..)
The following function implements the ability to edit the description of a link record.

function editLinkDesc(linkid)
{
    const linkitem = W.lookupItem("link_main", linkid);
    const newdesc = prompt("Please enter a new description for this link: ", linkitem.getShortDesc());
    
    if(newdesc)
    {
        linkitem.setShortDesc(newdesc);
        linkitem.syncItem();
        redisplay();    
    }
}

As a Widget developer, you are empowered to use any client-side JavaScript framework that you want. But in my work, I've found a very simple (re)-display loop to be completely adequate for all my needs. Here is how it works at a high level:

- There is a redisplay JS method that repopulates all of the info on the page
- This method is called on page load, using the onload attribute of the body tag
- The redisplay method queries the state of the Widget data, using methods like W.getItemList
- Whenever the user modifies any data, the JS code calls redisplay again, to reflect the changes

Veterans of the web development world will be quick to point out that this approach is inefficient, because calling a global redisplay after every small change in the data wastes a lot of effort on redrawing sections that haven't changed. This may be true in a technical sense, but in the vast majority of cases, the inefficiency is simply not relevant. The naïve redisplay call may consume 50 milliseconds instead of 5 milliseconds, but that difference is not perceptible to the user.

To see some examples of how this pattern works in actual code, check out the WebWidgets gallery on GitHub.

If you are interested in running Widgets on your own machines, you can install the open-core version of WebWidgets. This version is missing some of the more advanced features of the system, but you will be able to get a lot of work done with it. You will also be able to implement additional features on your own.

The open-core version requires Python 3.7 or higher, Java 11 or higher, and a JSP-compliant Java app server such as Resin, Tomcat, or Glassfish. Here is a full list of app servers; many of them are free or open-source. (Note that WWIO does not require the full suite of J2EE functionality, just servlet container and JSP features). Though we have only tested it on Linux, the software was written to be platform independent, so a brave engineer who is willing to read the source should be able to get it to work on Windows or Mac OS.