Docs
This page provides high-level documentation. For technical documentation, click here.
Widget development is designed to be fast. You can use the following development cycle:
- - Make changes to a local copy of the Widget file
- - Run a Python script to upload the new code to the server
- - 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.basicInclude(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.
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.
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;
- 1. Every table must have an integer primary key field named id.
- 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));
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 aredisplay
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.