UNDER CONSTRUCTION …

Purpose of this page Introduction to AWF

Architecture

Widgets

Widget Addons

Building your own widgets

File structure and locations

Tags

Widget options

Option specification

Option synchronization

Option editors

AWF messages

Synchronous messages

Asynchronous messages

Message reference

Widget lifecycle

Communicating data with AIMMS

Cubes and cubeviews

Retrieving and changing data

Data changes notifications

A simple table widget example

Purpose of this document

The information on this page is meant for developers who want to extend the WebUI interface as distributed by AIMMS with their own widgets or functionality. To be able to successfully write your own widget you will need

Introduction to AWF

Introduction

Architecture

In AWF, the AIMMS Widget Framework, a DOM tree element can be instantiated as an aimms-widget. The selected DOM tree element will then be decorated (in a process similar to dependency injection) by various components. These components interact with each other without directly referencing one another. Rather each component has a ‘contract’ with the bus: A set of messages that will send on the bus when certain other messages are sent.

AWF components can be divided into the following categories:

For simplicity’s sake, we will focus on these first two here.

Widgets

A Widget (sometimes also called ‘control’) displays an information arrangement changeable by the user (see http://en.wikipedia.org/wiki/GUI_widget). Typically this is something like a chart, a table, a dropdown, a button, etc.

Examples of a widget:

Widget Addons

A Widget Addon is a piece of extra functionality that can generically apply to more than one specific widget.

Examples of a widget-addon:

Building your own widgets

Addons

File structure and locations

Both widgets and widget addons are usually implemented as one or more jQuery (UI) plugins. The implementation is broken up into several parts (and files):

Tags

To maximize reuse, decoupling and cohesion. The complete functionality of an instantiated widget is not determined by a single responsible entity. Instead, DOM tree elements are decorated by separate pieces of functionality (Widgets and Widget-Addons), each strictly separated from another (decoupling), with a specific purpose/functionality (cohesion).

But when there is not a direct reference to other widget types or addons, there must be a mechanism to determine when to add the specific functionality to the DOM tree element on which an AWF widget is being instantiated. This is done through the exchange of “tags”. For instance, the generic pivot addon will contribute itself when the current widget type declares that it has a “pivotable contents property” tag.

TODO Overview of the most important tags.

Widget options

Widget options store the widget configuration. Any information that is needed to configure the widget should be regarded as a widget option. For example, the specification of the widget content, or the title of a widget. Typically, options and their types are declared in the widget factory. Options can also be added by an addon (in case it is the responsibility of the addon to handle the options). For example, the ‘title’ option is declared in the factory of the title-addon

    
function forApplicableElQs(elQ, type, onApplicable) {
	if(!elQ.awf.tags("simple widget")) {
		onApplicable.call();
	}
}

AWF.installListenerToMethodBridges(AWF, {
	onInitializeOptionTypes: function(elQ, type) {
		forApplicableElQs(elQ, type, function() {
			AWF.OptionTypeCollector.addOptionType(elQ, "title", "string");
		});
	}
});

During the widget initialization phase, the AWF asks the widgets for all options that are available. For this purpose, AWF sends an InitializOptionTypes message which should be handles by the onInitializeOptionTypes handler. The above code snippet adds the a ‘title’ option of type ‘string’ to all widgets that have been tagged as simple widget.

Option specification

Option Specification

Option synchronization
Option editors

Option Editors

AWF messages

In AWF there are two bus types

Typically, the widget factory installs a few listeners on the global AWF bus. On this bus widget instantiations are being negotiated and announced, giving factories a change to interact with the AWF widget instantiation process. Once a widget has been instantiated, it will have its own per-widget bus that can be used for the local messaging mentioned above.

When a certain message is posted on a bus (either the global AWF bus or some widget bus), all message handlers that are registered on that bus (for that specific message) are called. There are four types of message handler that allow you to perform actions on a specific moment during the handling of the message.

For example, if a message with name collectTypes is registered on the AWF bus, AWF will look for handlers with name beforeCollectTypes, onCollectTypes, afterCollectTypes and postCollectTypes.

Synchronous messages

Synchronous Messages

Asynchronous messages

Asynchronous Messages

Message reference

Global AWF messages:

Widget bus messages:

Widget lifecycle

Widget Lifecycle

Communicating data with AIMMS

Communicating Data with AIMMS

Cubes and cubeviews

Cubes and Cubeviews

Retrieving and changing data

Retrieving and Changing data

Data change notifications

Data Change Notifications

A simple table widget example

The factory.js file for the ‘simple-table’ widget looks as follows:

(function($) {

var OptionTypeTable = {
                         type : "datasource",
                         parts : [ {name : "rowHeader"}, {name : "colHeader"} ],
                         alternativeNameForValuesProperty: "grid",
                         preferredPartitionSizes : [ {parts: ["rowHeader","colHeader"]}, {parts: "aggregated"} ]
                      };

var widgetType = 'simple-table';

AWF.installListenerToMethodBridges(AWF, {

	onCollectTypes: function(collectedTypes, contextElQ) {
		if(!contextElQ || contextElQ.awf.tags("contents property") || contextElQ.awf.tags("placeable")) {
			collectedTypes.push(widgetType);
		}
	},

	onInitializeTags: function(elQ, type) {
		if(type === widgetType) {
			elQ.awf.tags(["complex widget", "contents property", "simple-table", "table-widget"], 'add');
		}
	},

	onInitializeOptionTypes: function(elQ, type) {
		if(type === widgetType) {
			AWF.OptionTypeCollector.addOptionType(elQ, "contents", OptionTypeTable);
		}
	},

	onDecorateElement: function(elQ, type) {
		if(type === widgetType) {
			elQ.aimms_simple_table();
		}
	},
});

})(jQuery);