MKWS logo

Introduction

This manual is for people who want to build the widget set from source, develop the widget set's core code, or (more likely) create their own widgets as extensions to the main set.

Those who want to use existing widgets should read The MKWS manual: embedded metasearching with the MasterKey Widget Set instead.

Required development tools

If you are building the widget set, you will need the following Debian packages (or their equivalents on your operating system):

$ sudo apt-get install curl git make unzip apache2 pandoc bzip2

You also need Node.js, but unfortunately the node-js package is not available for Debian wheezy. You can either get it from wheezy-backports or download the source from http://nodejs.org/download/ and build it yourself. You need both Node itself and its package manager Yarn: make install puts them into /usr/local/bin.

Concepts

Code structure

The code of the widget set is in four main layers, described here from the bottom up:

  1. The core code, which manages the set of widget teams, default options, authentication onto the Service Proxy, and the creation of widgets from HTML elements. This code is in mkws-core.js

  2. The team code, which manages teams of widgets. This is responsible for the collections of widgets that make up teams, event queues, and handling search-and-retrieval events. This code is in mkws-team.js

  3. The generic widget code, which handles the creation of widget objects, parsing configuration attributes from their HTML elements, and firing off automatic searches.

  4. The code for individual widgets, which is specific to those widgets. It often involves subscribing to events and responding to them by setting the HTML of the widget element, but need not do so. The code for many of the most important widgets is in mkws-widget-main.js, but certain other widgets are defined in other files beginning with the prefix mkws-widget-.

In addition to this code, there are several source files containing support code:

The final component of the source code is the set of Handlebars templates, in the templates directory, which are used to emit the HTML of the various widgets' contents. These are compiled into the file mkws-templates.js.

Event passing

The primary method of communication between components of the widget set -- specifically, between teams and their widgets -- is event passing. Widgets subscribe to named events; when something relevant happens (such as the reception of a message from metasearch middleware), the event is published, along with the relevant data. All widgets that subscribed to the event are then notified, and can take appropriate action.

Different kinds of events have different data associated with them. This data is passed when the event is published, and so is made available to the subscribing code.

The possible events, and their associated data, are described below.

Defining new types of widget

Development with MKWS consists primarily of defining new types of widgets. This is done using exactly the same API as the widgets that come as part of the set: they have no privileged access.

You create a new widget type by calling the mkws.registerWidgetType function, passing in the widget name and a function. The name is used to recognise HTML elements as being widgets of this type -- for example, if you register a foo widget, elements like <div class="mkws-foo"> will become widgets of this type.

The function promotes a bare widget object (which is created by the core widget code and passed in as this) into a widget of the appropriate type. MKWS doesn't use classes or explicit prototypes: it just makes objects that have the necessary behaviours. There are no behaviours that Widgets are obliged to provide: you can make a doesn't-do-anything-at-all widget if you like:

mkws.registerWidgetType('sluggard', function() {});

More commonly, widgets will subscribe to one or more events, so that they're notified when something interesting happens. For example, the log widget asks to be notified when a log event happens, and appends the logged message to its node, as follows:

mkws.registerWidgetType('log', function() {
  var that = this;

  this.team.queue("log").subscribe(function(teamName, timestamp, message) {
    $(that.node).append(teamName + ": " + timestamp + message + "<br/>");
  });
});

This simple widget illustrates several important points:

Widget specialisation (inheritance)

Many widgets are simple specialisations of existing widgets. For example, the images widget is the same as the records widget except that it defaults to using the images template for displaying its result list. It's defined as follows:

mkws.registerWidgetType('images', function() {
  mkws.promotionFunction('records').call(this);
  if (!this.config.template) this.config.template = 'images';
});

Remember that when a promotion function is called, it's passed a base widget object that's not specialised for any particular task. To make a specialised widget, you first promote that base widget into the type that you want to specialise from -- in this case, Records -- using the promotion function that's been registered for that type.

Once this has been done, the specialisations can be introduced. In this case, it's a very simple matter of changing the template configuration setting to 'images' unless it's already been given an explicit value. (That would occur if the HTML used an element like <div class="mkws-images" template="my-images"> to use a customised template.)

Reference Guide

Widget properties and methods

The following properties and methods exist in the bare widget object that is passed into registerWidgetType's callback function, and can be used by the derived widget.

In addition to these properties and methods of the bare widget object, some kinds of specific widget add other properties of their own. For example, the builder widget uses a callback property as the function that it uses to publish the widget definition that it constructs. This defaults to the builtin function alert, but can be overridden by derived widgets such as console-builder.

Team methods

Since the team object is supposed to be opaque to widgets, all access is via the following API methods rather than direct access to properties.

These are all simple accessor functions that provide the ability to read properties of the team. submitted is initially false, then becomes true when the first search is submitted (manually or automatically).

Some of these methods are arguably too low-level and should not be exposed; others should probably be widget-level methods. The present infelicities should be fixed in future releases, but backwards compatibility with the present API will be maintained for at least one complete major-release cycle.

Events

The following events are generated by the widget-set code:


Copyright (C) 2013-2016 Index Data ApS. http://indexdata.com