This page last changed on Jan 21, 2009 by amitku.

Component Creation Guide

Organization

Components are currently located under trunk/tools in the SVN file system, and are categorized into folders based on what part of MONK they interact with (e.g. chunks, collections, worksets, analysis).

Components reside in their own folder, which, at a minimum, contains an HTML file and a JS file.

Component Requirements

HTML File

The Head

The head should link to all the files required by the component. The minimum requirements are: the monkcheck.js file (in trunk/resources/js) and the component's own JS file. The CSS and JS files from Ext JS should be included as well (if your component makes use of them).

The head is the place where the component gets initialized. This is typically accomplished with code snippet below:

<script type="text/javascript">
    var myComponent = new Monk.component.COMPONENT_NAMEComponent();
</script>

You will have weird problems if the component is not created in the <head>. Typical error messages point to <body> and complain about missing functions in the firebug.

Sample code snippet is below

<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <title>Summary Results</title>
	
    <!-- load EXTJS library -->
    <link rel="stylesheet" type="text/css" href="/lib/ext-2-0/resources/css/ext-all.css" />
    <link rel="stylesheet" type="text/css" href="/lib/ext-2-0/resources/css/xtheme-aero.css" />  
    <script type="text/javascript" src="/lib/ext-2-0/adapter/ext/ext-base.js"></script>
    <script type="text/javascript" src="/lib/ext-2-0/ext-all-debug.js"></script>
 
   <!-- monk workbench check -->
    <script type="text/javascript" src="/resources/js/monkcheck.js"></script> 

    <!-- load component definition -->
    <script type="text/javascript" src="/docs/getting-started/workbench/summary.js"></script>
    
       <script type="text/javascript">
        var summaryComponent = null;
        function initialize() {
            Ext.QuickTips.init();
            summaryComponent = new Monk.component.SummaryComponent();
            summaryComponent.init();
        }
        Ext.onReady(initialize, this, false);
    </script>  

    <link rel="stylesheet" type="text/css" href="/resources/css/monk.css" />
</head>
The Body

The body should include any visual and functional elements that aren't created dynamically.

JS File

All components should be created as classes under the Monk.component namespace. In addition, the component should extend the Workbench.component.Component class.

Use the following code as a guide for component creation. It is taken from the chunk viewer component. For your own component, replace COMPONENT_NAME with your component's name.

Monk.component.COMPONENT_NAMEComponent = function(args) {

    // custom properties can go here
    this.customProperty = null;

    // call the constructor for the superclass, i.e. Workbench.component.Component
    Monk.component.COMPONENT_NAMEComponent.superclass.constructor.call(this, args);
}

// overwrite Workbench.component.Component methods & properties and add custom methods
Workbench.extend(Monk.component.COMPONENT_NAMEComponent, Workbench.component.Component, {
    // this is required in order to associate the correct window with the component
    // since all components reside in IFRAMEs
    "window" : this.window,
    // the handle method of every component gets called when a Monk.event is sent to the Workbench.component.Manager.
    // here the component reacts only to those events it is interested in
    handle : function(monkEvent, data){
        if (monkEvent.instanceOf(Monk.event.chunk.ChunkSelected)) {

            // the user selected a chunk, so retrieve it
            Monk.data.chunk.retrieveChunkContents(data);
            Ext.get("content").mask("loading text chunk...");

        } else if (monkEvent.instanceOf(Monk.event.chunk.ChunkContentsRetrieved)) {

            // display the contents of a retrieved chunk
            document.getElementById("info").innerHTML="<i>"+data.text+"</i> ("+data.chunkType+")";
            document.getElementById("view").innerHTML = data.html;
            this.window.scrollTo(0,0);
            Ext.get("content").unmask();

        } 
    }
}

Registering your component with the workbench

In order for the workbench to recognize your component, you need to add it to the list of components (called "plugins" in the file) at trunk/apps/resources/js/monkFeatures.js.
The properties for the components in this list are as follows:

  • id: A unique ID for your component.
  • label: The name of your component. In the Workflow Application, this will be displayed as the window title for the component.
  • description: A description of the component's function. In the Workflow Application, this will be displayed as pop-up text in the Toolset Editor.
  • source: The path to your component's HTML file. It should begin with ../../tools/.
  • helptext: Basic help for your component. In the Workflow Application, this will be displayed as a pop-up, accessible from a help icon in the component window's toolbar.
  • group: The group that your component belongs to. Sample groups include: charts, collection browsers, and workset. In the Workflow Application, this is used to populate the component window's alternative components drop-down. This property can be left out.

Tool Icon

To set a custom icon for a tool, place a file called '/docs/getting-started/workbench/icon.gif' into the tools directory.

Component Methods

handle(event, data) override

The handle method of every component gets called when a Monk.event is sent to the Workbench.component.Manager. Using the event's instanceOf method, you can determine the type of event, and whether it applies to your component.
The second parameter is the data that accompanies the event; which can be anything, depending on the event.

An example:

handle : function(monkEvent, data){
    if (monkEvent.instanceOf(Monk.event.chunk.ChunkSelected)) {
        // the user selected a chunk, so retrieve it
        Monk.data.chunk.retrieveChunkContents(data);
        Ext.get("content").mask("loading text chunk...");
    }

notify(event, data)

The notify method is the counterpart of handle. Components use it to send out events to other components, via the Workbench.component.Manager.
For a list of possible events, see MONK Workbench Events. You can also add your own, by modifying the file at /trunk/resources/js/event.js.

An example:

this.notify(new Monk.event.chunk.ChunkRated(
    {
        // a description
        label: 'Chunk '+id+' was given a rating of '+rating

        // component does not need to be listed here, it is added automatically
    }),
    {
        // data associated with the event
        chunkId: id, rating: rating
    }
);

isValid() override

By default, this method returns true. If your component requires certain conditions to be met before the Workflow Application moves to the next step in the toolset, you can specify those here. If the component is not valid, this method should return a string containing the details of the error.

Component Properties

window

When extending Workbench.component.Component, make sure to include the following property:

"window" : this.window

This is required in order for the correct window to be associated with the component (as each component is contained within an IFRAME).

label

This property is no longer necessary, as it has been superseded by the label in monkFeature.js (see here).

description

This property is no longer necessary, as it has been superseded by the description in monkFeature.js (see here).

Interaction with the Workbench

The Collection

The Collection is the set of texts which are available for the workbench. They are accessible through the Monk.data.collection.getMetaDataHierarchy method. The Collection is an array and has the following structure:

[
    {
        id: 'ncf', // collection ID
        text: 'NCF', // collection label
        children: [  // all the works in the collection
            {
                id: 'ncf-22501', // work ID
                collectionId: 'ncf', // collection ID that this work belongs to
                text: 'A Christmas Carol', // title of the work
                fullLabel: 'Dickens, Charles (1812-1870): A Christmas Carol. In Prose.', // full title of the work
                numWorkPart: 8, // the number of workparts (children) this work contains,
                authors: [], // array containing author info
                authorsLabel: 'Dickens, Charles (1812-1870)' // label for author info
            },
            { } // etc.
        ]
    },
    { } // etc.
]

Note that the Collection in its entirety is huge, and so initially contains only the top-level works for each collection. To get the workparts of a work, you need to call Monk.data.chunk.getWorkInfo(collectionId, workId).

Server Calls

See CollectionManager Calls for a list of possible calls. However, you shouldn't need to make these calls directly, as they are encapsulated in the Monk.data namespace. You can find the calls at trunk/resources/js/data.js.

As these calls are all AJAX, the standard procedure is to make the call, then handle the event that gets sent out when the server response is received. Typically, the data accompanying the event will contain the server response.

When testing locally, make sure you have the proxy set properly as detailed in the MONK workbench quick start guide.

Data Manager

The Data Manager is used to store and process user data, primarily the workset and analysis results. It is located at trunk/resources/data-manager.js, and can be accessed from your component using the static class Monk.component.dataManager. The Data Manager is too large to get into with any kind of detail here. However, some important methods are getWorkset and setWorkset, and initializeProgressDialog (which is used in conjunction with workset saving to run an analysis).

An example:

Monk.data.workset.saveWorkset(Monk.component.dataManager.getWorkset());
// run analysis setup after workset is saved
Monk.component.dataManager.initializeProgressDialog(this.cachedData);

Messenger

The Messenger is used to send messages to the user. It is located at trunk/resources/js/messenger.js, and can be accessed from your component using the static class Monk.component.messenger. You can call the following methods to display various types of messages: show, progress, alert, wait, confirm, prompt, and growl. These methods all take a 'target' parameter, which determines whether the message should be displayed in your component, or in the workbench itself (except for growl which can only be displayed in the workbench).

As this class is essentially a wrapper for the Ext.Msg class, see the Ext docs for more info on each type of message.

An example:

Monk.component.messenger.growl('Monk Workbench','Workset Loaded: '+worksetName);

Toolsets

For information on how to put your component into a Toolset, see the Workflow Application.

Window Focus

The Workbench.component.Manager has an array which keeps track of the focus history of component windows. Those windows which have been focused on (i.e. clicked on) recently will be toward the beginning of the array.

In most cases you can ignore the focus history entirely. However, there may be certain instances where you'll want to interact with it. You can force your component to be added to the beginning of the focus history array by by calling Workbench.component.manager.handleFocus(this) from within your component code. Currently, this is only used in chunk viewer components, along with the related hasFocusPriority method, in order to determine if the component should handle an event. See the trunk/tools/chunk/chunk-viewer/chunk-viewer.js for details.

Important MONK Files

There are several files which you should be aware of when designing your component.

monkFeature.js

Located at trunk/apps/resources/js/monkFeatures.js, this is the base feature class for our Workbench. Most importantly, it contains the list of components (called "plugins" in the file) which will be available to the user. You need to add your component to this list.

data.js

Located at trunk/resources/js/data.js, this file is used for all data calls to the server (e.g. loading/saving worksets, getting chunks, etc.). All calls produce an event upon completion, so handle those in your component to work with the results.

This file also contains the Monk.data.collection.getMetaDataHierarchy method. Use this to get the list of available collections, and their works.

data-manager.js

Located at trunk/resources/js/data-manager.js, this class handles all the management of user data. Currently it keeps track of the user's workset and related settings. A global instance of this class is available as Monk.component.dataManager.

event.js

Located at trunk/resources/js/event.js, this file lists all the potential events that components can produce/consume. Any new events should be defined here.

workflowFeature.js

Located at trunk/apps/workflow/resources/js/workflowFeature.js, this file contains the definitions for the default toolsets (around line 140). The format is fairly straightforward and the 'layouts' parameters are optional.
A sample default toolset is below:

The label of the toolset is "Search And Browse", it has two steps -the first step has the searchAndbrowse tool alongside a result summary tool and the second step comprises of the result summary tool and advanced viewer. A gotcha to notice is that
the tool ids in the layout end with -window, for example resultSummary-window and advanced-viewer-window in the toolstep with id toolstep-002-search-and-browse.

{
                id: 'toolset-searchAndbrowse',
                label: 'Search And Browse',
                pathToIcon: '/docs/getting-started/workbench/resources/images/toolsets/Toolset-faces-search-by-example.gif',
                description: 'This toolset allows you to search and browse the collections and' +
                        ' create worksets',
                tools: [
                    {id: 'toolstep-001-search-and-browse',
                     label: 'Search And Browse',
                     components: ['searchAndbrowse', 'resultSummary'],
                     layouts: [
                        {id:'searchAndbrowse-window', x: 0, y: 0, width: 0.38, height: 0.9602},
                        {id:'resultSummary-window', x: 0.38, y: 0, width: 0.62, height: 0.9602},
                     ]},
                       {id: 'toolstep-002-search-and-browse',
                     label: 'Search And Browse',
                     components: ['resultSummary', 'advanced-viewer'],
                     layouts: [
                        {id:'resultSummary-window', x: 0, y: 0, width: 0.38, height: 0.9602},
                        {id:'advanced-viewer-window', x: 0.38, y: 0, width: 0.62, height: 0.9602},
                     ]}
                ]
            }

Documenting your Component

In order to facilitate future code modification and reuse, make sure to document the properties and methods of your component.

Instructions

We are using the jsdoc-toolkit for documentation. It uses a style similar to javadoc, and has the similar benefit of generating HTML documentation from the code.

Here is a simple example of a documented method:

/**
 * Returns the workset ID for this workset.
 * @returns {String} The workset ID
 */
getWorksetId : function() {
    return this.worksetId;
}

See the jsdoc-toolkit website for the list of possible tags and in order to download the files necessary to generate the HTML documentation.

The generator is a Java app, run from the command line. Here is some sample code (in Windows) for producing documentation:

java -jar jsrun.jar app\run.js -t=templates\jsdoc -d=D:\workspace\Monk\docs D:\Monk\lib\workbench.js D:\Monk\resources\js\core.js 

This is run from the jsdoc-toolkit folder. Use -d to set the output directory. Include a space separated list of files and/or directories to document. Detailed instructions can be found in the accompanying readme.

Gotchas

Workbench.extend

When using the Workbench.extend method, use the @lends tag directly under it in order to associate the extended methods with your component:

Workbench.extend(Monk.component.SeasrManagerComponent, Workbench.component.Component, {
   /** @lends Monk.component.SeasrManagerComponent.prototype */

   // your methods go here
Namespaces

Namespaces are documented like so:

/** 
 * @name Workbench.lang
 * @namespace The Workbench.lang module contains basic language objects,
 * especially extensions to existing Javascript objects.
 */
Workbench.namespace("Workbench.lang");

FAQ

What does a component need in order to be noticed?
Initializing a component will automatically register it with the Workbench.component.Manager.

What does a component need in order to be self-contained?
Each component resides within its own IFRAME, and is only referenced indirectly through the event system.

What does a component need in order to exist?
At a minimum it needs an HTML file and a JS file.

What does a component need in order to post events?
Each component inherits a notify method which it uses to send events to the Workbench.component.Manager.

What does a component need in order to listen for events?
The Workbench.component.Manager notifies all components of events. Each component inherits a handle method (which you need to overwrite). This method determines what events a component is interested in and how it reacts to them.

What form do events take?
Events are divided into three basic categories based on where they originate: UserEvent, WorkbenchEvent, ServerEvent (these are defined in trunk/lib/workbench.js). All the MONK specific events are listed in trunk/resources/js/event.js. Properties of an event vary based on the event, but each one should have at least a label which describes the event, and a reference to the component which was the source of the event. The notify method includes both an event, and data associated with the event.


events_22_01_2008.htm (text/html)
Document generated by Confluence on May 06, 2009 09:24