Wisp File Format

The WISP (WIdget Server Page) is a simple file format that is used to develop Widgets. This format is just a normal HTML web page that is augmented with a small number of wisp tags. When the server sees a file with the .wisp extension, it uses the data-injection logic to insert the data from the underlying SQLite DB into the page. There are a variety of configuration options, but for many use cases, you will need only a single wisp tag.

<html>
<head>

<!-- other HEAD material --> 

<!-- Wisp tags should be directly enclosed within head tag -->
<wisp/>

</head>

<body>

<!-- normal page contents -->

This simple tag will import all of the DB tables corresponding to the Widget (the Widget name is discovered by looking at the request URL). It will also import all required JavaScript code to be able to use the Widget data. So by using this single tag in a .wisp file, the main API methods such as W.getItemList(...) and W.lookupItem(...) will now work. You can see more information about these methods on the Main Widget API page.

There are a variety of options you might want to use when including Widget data. One important tool allows you to specific which tables you want to load. The first option allows you to load data from another Widget. By default, the server finds the Widget name from the HTTP request URL. But sometimes you want to "cross-load" data, which means to load data for Widget A in a page corresponding to Widget B. To do this, you can use the widgetname attribute:

<wisp widgetname="other"/>
This command will load all the DB tables in the "other" Widget. Similarly, you might want to specify which tables you want. By default, the server will send all tables contained in the Widget DB. If some of the tables are large, that can result in a slower page load. To specify which tables you want to load, use the tables attribute. The value for this attribute is a comma-separated list of table names that you want to load, for example:

<wisp widgetname="other" tables="alc_log,money_log"/>

This command will load the alc_log and money_log tables from the other Widget.

Advanced Usage

There are a couple of more advanced attributes you can use in conjunction with the wisp tags.

Permission Checking and Redirection

The WWIO server will only serve data to users with permission to view that data. The owner of a Widget has the option to assign read and write permissions to other accounts, this can be done in the Permission Control page of the Admin Console.

Every Widget page is has a specific, primary Widget DB associated with it, and the WWIO server uses the request URL to determine this association. If a user attempts to access a Widget page, but does not have read permission for the primary Widget, then the user is bounced to a log-in screen that informs them that they do not have the right permissions. However, wisp pages can also load data from secondary DBs using the widgetname tag mentioned above. If a user can access the primary widget but not a secondary widget, they will get an error message at page load time. Thus, when using the cross-loading technique, Widget developers should take care that users have the right permissions for the secondary DBs.

Deprecated JSP Format

As of November 2023, the Wisp file format is the preferred way to develop Widget pages. Prior to this conversion, Widget pages were written using a strict subset of the Java Server Page format. This approach used a JSP tag that referred to a Java class:

<%= DataServer.include(request) %>

<%= DataServer.include(request, "widgetname=sms_box&tables=outbox") %>

This old style of writing Widgets is still present in some places in the documentation. The attribute names in the second argument of the DataServer.include command correspond exactly to the Wisp tag attributes mentioned above. This style is no longer allowed on the hosted WWIO platform for security reasons, but users who are running their own instance of WWIO may wish to use the old JSP for various purposes.

Understanding the Data Injection

If you are interested about what the data-insertion logic is doing, you can take a look at the resulting page source using the View Source option in the browser.

<!-- Widget Core Asset Include -->
<link rel="stylesheet" href="/u/shared/css/BasicWidget.css?modtime=1696701856211" />
<script src="/u/shared/jslib/TimeUtil.js?modtime=1702059034060"></script>
<script src="/u/shared/jslib/LegacyApi.js?modtime=1702059034060"></script>
<script src="/u/shared/jslib/WidgetUtil.js?modtime=1702059034060"></script>
<script src="/u/shared/jslib/OptSelector.js?modtime=1702059034060"></script>
<script src="/u/shared/jslib/WidgetMainApi.js?modtime=1702059034060"></script>
<!-- End Core Asset Include -->


<!-- Custom JS code for user -->
<link rel="icon" type="image/x-icon" href="/u/testuser/MyFavIcon.png?modtime=1701993523963"></link>
<!-- End custom JS code for user -->

<script src="/u/testuser/autogenjs/links/LinkCateg__003.js"></script>
<script>



function __arr2DictLinkCateg(arr) {
	const d = {};
	d['id'] = arr[0];
	d['short_code'] = decodeURIComponent(arr[1]);
	d['full_desc'] = decodeURIComponent(arr[2]);
	d['is_active'] = arr[3];
	return d;
}
[
	[ 2, "Bills", "...", 1]  , 
	[ 3, "News", "...", 1]  , 
	[ 4, "Shopping", "...", 1] 
].forEach(function(myrec) { 
	LinkCategTable.register(W.buildItem("link_categ", __arr2DictLinkCateg(myrec)));
});

// LiteTableInfo__LOAD_SUCCESS
</script>
<script src="/u/testuser/autogenjs/links/LinkMain__003.js"></script>
<script>

There are a couple of sections here. First, the server sends script commands to instruct the browser to load various helper JS files. These are the main utility classes that are required for the browser to interact with the server. Then there are some user-generated files that are auto-included. These files have modtime attributes included in the URL, which causes the browser to reload them, if new versions are sent to the server. After this, there is the actual data objects - basically the contents of the DB tables, expressed in JavaScript. Finally there is the table-specific JS code that is created by the server by inspecting the SQLite table definitions.