Widgets can be used for a wide variety of applications relating to organization, productivity, fitness, diet, finances, and learning. As you build more widgets and get to understand how to use them effectively, you will naturally discover more and more potential use cases. Our team has built personal Widgets for the following use cases:
- Workout logging
- Studying Chinese characters
- TODO List management
- Project management
- Expense tracking
- Junk Food / Alcohol logging
- Chore Reminders
- Private Question/Answer database
- Link Management
All of the data for a Widget is stored in a SQLite file on the server. When the Widget loads, the data in the file is transformed into JavaScript objects and sent to the browser, along with the HTML and other assets (images, etc) that make up the page.
The JavaScript code running on the browser can then perform whatever computations are desired to format and display the data to the user. The Widget typically provides the user a variety of ways to manipulate the data and create new data (for example, in a training log, the user can log new workouts). These data updates are sent back to the server for long-term storage. The Widget framework provides a simple API for querying and updating the JS objects that correspond to SQLite records.
FAST, except for the initial page load, which might take half a second.
The lifecycle of a user interaction with a Widget consists of two steps: the initial page load, and subsequent updates, queries, or data input that is performed by the user. In the initial load phase, the server converts all of the data in the underlying SQLite file into JavaScript objects and sends it to the client. Thus, this phase can take a short but perceptible amount of time, depending on the amount of data in the DB file. However, after the initial page load, all updates and operations should be nearly instantaneous, because all of the data is present in the browser's memory, and the server updates are performed asynchronously.
For example, suppose you are using a TODO List Widget and you add a new task. This requires the page to be redisplayed to include the new task. The redisplay can be performed instantaneously, without waiting for a server response, because the browser already has all the data it needs to redraw the page. The actual update to the SQLite DB won't happen for perhaps half a second after the user makes a change, but this latency is invisible to the user.
YES. As of October, 2023, there is an open-core version of WebWidgets that you can install on your own machine(s). The backend Java code is now included in the GitHub repo. There is an installation script that guides you through the installation. Here is a YouTube video that walks through the installation process.
The open-core version runs the basic Widget functionality. The full-featured WWIO system is enhanced with email-sending capability, blob storage so you can upload photos or audio, and the ability to export Widget data to Google Sheets.
The WebWidgets site uses industry-standard methods for encrypting messages between the browser and the service, and for user authentication.
However, the SQLite files stored on the server, and backed up in AWS cloud storage, are not encrypted. In the event of an illegal data breach initiated by cyber-criminals, this data may be compromised.
For users who require a higher level of security, we suggest using a local password to encrypt the sensitive data before sending it to the server. This technique ensures that confidential data will be protected even if the WWIO server is attacked.
YES, absolutely.
The service we provide makes it extremely easy to download the SQLite files that contain the Widget data. Not only do you have the data, but because you are the developer of the Widget, it will be easy for you to understand, access, and modify the data. You will know the exact schema of the DB, and you will know what each field of the DB means in terms of the Widget's functionality.
Widget data is stored in SQLite database files.
The use of SQLite is one of the core design factors of the Widget system. SQLite makes it so that every Widget user can design their own data structures. Furthermore, users can easily upload and download their data files, ensuring that members truly own their data.
YES, You can use any frontend framework that does not require any special backend support. This includes React.
Unfortunately we cannot allow people to run backend framework code on our servers. The Widget platform is designed to create a clean separation between the backend code and the frontend. Users can do whatever they want on the front end - the code is running on the user's browser - but all Widgets connect to the same, simple backend.
In the course of development of the WebWidgets platform, Dan (the developer) experimented with using React to build several widgets. This was successful, but Dan eventually found that React was too heavy-weight for his purposes. Dan moved to using the coding style that is illustrated in the WebWidgets Gallery.
To answer this question, it's useful to ask a related question, which is "What makes mainstream WebApps so difficult to build?" Mainstream WebApps have to satisfy a lot of requirements:
-- They must display correctly for every browser (Chrome/Firefox/Edge), including older versions. But each browser version has a slightly different set of functionality and quirks, especially when it comes to JavaScript. This makes it extremely difficult to implement client-side functionality.
-- They must be built to be scalable, and handle extremely high loads. Even if the load isn't very high on a daily basis, every entrepreneur dreams that her business will suddenly go viral and start gaining users rapidly. For this reason, developers must spend great efforts designing the application backend.
-- They need to look very professional and "slick" for the sake of branding. That means the designers must spend a lot of time thinking about the app's color scheme and making sure every icon looks perfect.
As you can see, Widget developers don't need to worry about any of these issues. Since WWIO apps are designed for individuals or small groups, you can make sure that everyone using your app has a relatively modern browser. You don't need to worry about scaling up to millions of users. And you can make your app as slick or as basic as you want, depending on your taste in web design.
YES. Widgets are WebApps that run in the browser, and all modern smartphones and tablets have browsers, so you can access the Widgets that way.
The main challenge with WWIO apps on mobile devices is getting the information to display cleanly. CSS Frameworks like Bootstrap can help with this.
The WWIO platform is agnostic about how the data is displayed to the user. It is completely up to the developer to decide the tradeoff between ease of development and the aesthetics of how the data looks on a mobile device.
YES, by all means! All of the Widgets in the Gallery can be used or remixed for any purpose. We invite you to either copy my Widgets entirely, or make small changes to them to suite your use case.
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.
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 the page 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.
WISP stands for WIdget Server Page.
It is a simple format used for WebWidgets.
It is almost exactly the same as normal HTML,
except it can have wisp
tags in the head
section,
as shown in this example:
<html> <head> <title>Link Manager</title>>
<wisp />
<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. The data from the SQLite database can now be accessed in JavaScript using the Widget API.
There are a variety of ways to configure and customize the wisp
tag by adding various attributes.
For example, this tag loads only a single table from the underlying DB:
<wisp tables="my_table"/>
For more information about how to configure the wisp
tag,
see the Wisp File Format technical docs.
NO, Widget coding is done completely in client side JavaScript.
Prior to developing the .wisp
file format, WWIO used JSP as the file format
for Widgets. However, only an extremely pared-down subset of JSP tags and Java code was allowed.
Some of the Gallery code examples may still use this old format.
For clients of our service business, we sometimes use JSP as a way to add small pieces of server-side functionality WWIO apps. Unfortunately we cannot allow general users to do this, for security reasons.
The two basic methods are W.lookupItem
and W.getItemList
.
These methods are included in the JavaScript code that is pulled in by the wisp
tag.
// 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 = W.lookupItem("my_widget_table", editid); editme.setShortName("CoolRecord41"); editme.syncItem();
Note that this operation is extremely fast because it does not reload the page and the update happens asynchronously. This is an important contrast to many web applications which require a full round-trip cycle between the browser and server for every data update.
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 newitem = W.buildItem("link_main", newrec); newitem.syncItem(); redisplay();
This code will create a new record for a SQLite table with this definition:
CREATE TABLE link_main (id int, cat_id int, short_desc varchar(150), link_url varchar(250), primary key(id));
Note that the id
column is optional and will be provided by the framework if you leave it out,
and doing so is the recommended approach.
There are many approaches to creating dynamic web pages.
The technique we recommend is very simple: 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 = W.getItemList("my_widget_table"); const mystr = "<h3>The number of records is " + mylist.length + "</h3>"; document.getElementById("record_info").innerHTML = mystr;
This is the technique used by most of the code in the Gallery section.
There is a utility method called populateSpanData
, that places HTML text into a given set of element IDs:
const edititem = W.lookupItem("link_main", STUDY_ITEM_ID); populateSpanData({ "item_id" : edititem.getId(), "short_desc" : edititem.getShortDesc(), "link_url" : edititem.getLinkUrl(), });
For security reasons, we cannot allow users to run code on our servers. However, our team can implement small back-end integrations for customers of the WebWidgets.io hosting platform. Some examples of integrations we've built for customers include:
- - Running a Python script that uses the Google OR Tools package to solve a scheduling problem
- - Connecting to an external datasource periodically to check for data updates
- - Providing a project-specific login workflow
Please Contact Us to request a quote.
Users of the Open Core version can, of course, implement itegrations on their own by writing the code themselves. If you are interested in this option, please reach out for advice or consulting services.
The main rules for the Widget SQLite file are:
- 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).
Here is an example:
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));
Note that, unlike other DBs,
SQLite does not enforce the varchar length limits,
you can put a string of any length in the short_desc
field.
These numbers are provided only as a hint about how long the inputs are expected to be.
The WWIO platform uses a JS code generation technique to create JavaScript objects that have getter/setter methods, that are named using a simple naming convention. For example, consider the following table from the Link Manager widget:
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 we make a strong recommendation to avoid heavy-weight JS tooling and use a simple redisplay loop. Here is how it works:
- There is a redisplay
JS method that repopulates all of the info on the page
- The redisplay
method queries the state of the Widget data,
using methods like W.getItemList
, to compose HTML strings.
This HTML is then inserted into div
or span
tags.
- This method is called on page load, using the onload
attribute of the body
tag
- 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 has all the basic necessary features of WWIO. It is missing some of the more advanced features such as email integration, blob storage management, and Google Sheet export (though you can implement those features yourself by defining some plugins).
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, and we are committed to supporting all standard OSes. If you run into problems running WWIO on other platforms, please reach out to us.
Okay, okay, we get it, the Demos are not exactly beautiful. The WWIO developer (Dan Burfoot) built most of those tools for his personal use, and he did not feel the need to make them look pretty. Like Han Solo says of the Millenium Falcon, "She may not look like much, but she's got it where it counts."
The WWIO platform is a backend tool for connecting front-end code (HTML, CSS, JavaScript, etc) to SQLite databases. As such, it is completely agnostic about how the front-end looks. You can make your WWIO apps as beautiful or as basic as you want, depending on your taste and how much time you are willing to invest in UI polishing.
The WWIO platform is a low-code system that makes it easy to build a wide variety of useful web applications. However, it is important to understand the limitations of the platform.
Limited Concurrent Writes : WWIO applications cannot easily support a large number of concurrent writes. If your application needs to have dozens of distinct users make updates to the database, that may cause a problem.
Simplified Permissioning Model : Permissioning - the problem of deciding what users are allowed to take what action - is one of the most painful and complex aspects of modern computer systems (take a moment to peruse the AWS Access Management Docs if you don't believe us.) WWIO provides a simplified approach to this issue, which may be too simple for some organizations.
Data Size : the basic approach of WWIO is to ship the entire contents of the SQLite database to the browser and let the front-end code decide what to display. Therefore, if you have an enormous database, the application may be very slow to load, or cause problems for your users by hogging too much memory. Note, however, that modern computers have multiple gigabytes of RAM, and most users have broadband connections that can deliver 100's of megabytes of data per second.
To a significant extent, clever engineering can be used to circumvent many of these limitations. WWIO is completely sufficient for a large number of use cases, but if you are shooting to achieve the scale of Facebook or GMail, WWIO is probably not the best solution for you.