Writing a plugin II


 * See also: Writing a plugin

This page explains an additional use of plugins. It is recommended to read Writing a plugin prior to reading this article, as instructions here may build on information explained in that tutorial.

In this tutorial you will learn how to write a plugin which registers itself as an attribute handler, i.e. which processes certain attributes of elements, and how to add GUI components directly to the stage. The plugin created by following these steps will display a small window with some information text when a user clicks on an element. The text will be changeable via an attribute of the element.

Additionally, a small button will be added to the overall plugin to demonstrate how to add common GUI elements which are always available (such as the NavigationBar).

Another concept explained in this tutorial is the use of the  and   functions available through the AbstractPlugin class.

Registering as an attribute handler
Create a blank plugin by copying the dummy plugin and renaming it. In the register function we will let the plugin register itself as an attribute handler for elements. In general, it is possible to register a plugin as an event handler for the following objects:
 * Chapters
 * PageSides
 * ElementProxies
 * Elements

The fine difference between ElementProxy and Element is that the attribute handling for an ElementProxy will only happen once, when the page containing the element the proxy represents is added to the book. The Element attribute handler on the other hand will be called whenever the element finishes loading, which can be multiple times during the lifetime of a book, if the containing page is unloaded, then loaded again, due to the user's navigation through book (i.e. if the page containing the element should be unloaded because it leaves the area of pages to be kept in memory, and at a later point needs to be loaded again).

To register the plugin as an attribute handler, use the  function. It takes three parameters:
 * type:Class, the type of element for which to register. The value given must be one of  or , i.e. the interfaces of the objects for which to register.
 * attribute:String, the name of the attribute for which to register as a handler.
 * priority:uint, with default value 10, a priority for when to call the handler. Handlers with a lower priority value get called first, i.e. a handler registered with priority 5 gets called before a handler registered with priority 10. The order of handlers with the same priority may vary.

Because we want to register for an element attribute, and we wish to act upon a click on the element, the call necessary in the register function looks like this:

The attribute we will be using is named "infotext". So to have a test element in our book, add the following to any page in a book (include the Overlays plugin to see it, you can still click on it if you don't):

ASUL definitions
See also: ASUL Document and Editing the GUI.

In the constructor of the plugin, change the super call so that ASUL definitions for the plugin will be loaded:

Then create the  file. In it we will define how our window and button will look. In general, define all GUI components you will use inside this file.

The important part are the ids and (non-ASUL) names. In this case:
 * id: infobox, the window we will display when an element that has the infotext attribute set is clicked.
 * id: btn_example, the example button permanently displayed.
 * name: infotext, the name of the textfield used to display the content of the infotext attribute of an element.

Creating the GUI components
GUI creation should take place in the initialize function of the plugin, so we will create the window and button here, and initially hide the window. The window will be stored in an instance variable of the plugin to make it visible it in the attribute handling function, as will a reference to the textfield, to change its value.

Implementing the attribute handler
For all of the attribute handling purposes, convenience functions which can be overridden are available in the AbstractPlugin class. They follow the naming pattern "handleXXXAttribute", where "XXX" is the type of element for which to handle the attribute. In our case it's "handleElementAttribute". This function is called whenever an element finishes loading and it's attributes should be processed by plugins.

Parameters of the handleElementAttribute function are
 * element:IElement, the element which finished loading.
 * attribute:String, the name of the attribute to be handled.
 * value:*, the value/content of the attribute.

Although this will only be called if the attribute is actually set (exists in the XML definition), we will still want to check if it has actually any value at all (is not an empty string). We will add a click listener to the element's interactiveObject which will update the text and show the window.

To store the text for each element for access in the event handler we will use the  function. This allows assigning values to any object at all. The mapping uses a Dictionary with weak keys, making it safe for use in regards of memory leakage.

= Final code =