TeamWox SDK: Building User Interface

Introduction

From the previous TeamWox SDK: How to Add Page into TeamWox Module article you've learned how to add pages into module, and got acquainted with the simplest way to output data.

In this article we will consider how to build user interface in TeamWox groupware using JS controls. We will also consider templates - how to use them to specify format and procedure of data output, and to set page layout.

User interface is built using TeamWox library written on JavaScript programming language.

 

TeamWox JavaScript-components Library for Building User Interface

User interface is created using standard controls available in TeamWox JavaScript library. Note, that before using any controls, you need to organize data output via template file in the source code of your page (the example code from the previous article):

//+------------------------------------------------------------------+
//| Process request                                                  |
//+------------------------------------------------------------------+
TWRESULT CPageReference::Process(const Context *context,IServer *server,const wchar_t *path)
  {
//--- Checks
   if(context==NULL || path==NULL) ReturnError(RES_E_INVALID_ARGS);
   if(context->request==NULL)      ReturnError(RES_E_INVALID_CONTEXT);
//--- get server
   if(server==NULL)                ReturnError(RES_E_FAIL);
//---
   m_server=server;
//--- display page
   return(server->PageProcess(context, L"templates\\number3.tpl", this, TW_PAGEPROCESS_NOCACHE));
  }

Since module pages are displayed in a web browser, their templates must conform to the HTML standard, i.e. they must contain the basic tags: <html></html>, <head></head> and <body></body>.

To be able to use JavaScript components from TeamWox library, you have to add library initialization code into page template TPL file:

<script type="text/javascript">
   top.TeamWox.Start(window);
</script>

Thus, we initialize the TeamWox base object. All other objects are inherited from it and obtain all its properties and methods. This script should be included in every page template.

 

Adding a Control

All controls are created using one method - TeamWox.Control(), that looks as follows:

TeamWox.Control("controlType","controlProperty", ...)

где:

  • controlType - Type of added control (for example, it can be page header, text, table, data input form, etc.).

  • controlProperty - property of control. There can be any number of properties, it all depends on particular type of control.

All instances of controls are arranged on the page in order of their creation. Each control has the following methods:

.Append("onclick", function() { alert("Hello World!") }) - Adds an event handler.
.Remove("onclick") - Removes an event handler.
.Style( {width: "80px", "padding-top": "4px" } ) - Sets style.
.Title("<lngj:TRANSLATION/>") - Tool-tip for control.
.Class("header-decor", false) - Adds or removes CSS class.
.Attr("page-id", 12) - Sets an arbitrary attribute for control.
.Document() - Returns DOM document, to which control is applied.
.Window() - Returns browser window, to which control is applied.

Let's consider the process of developing user interface using sample page PageNumberTwo from the Hello World module.

Fig. 1. The 'PageNumberTwo' Page

This page consists of three basic controls: page header, text block and table with data. Let's consider how each of these elements is created in details. To do this, in any text editor open page template - the number2.tpl file.

 

Page header is a standard element of TeamWox user interface. It includes the basic commands, the search string, and the filtering and help buttons. Page header must be on every page.

Fig. 2. Page Header

Page header is created using the PageHeader control:

TeamWox.Control("PageHeader","#41633C")
       .Command("<lngj:MENU_HELLOWORLD_LIST>","/helloworld/index","<lngj:MENU_HELLOWORLD_LIST>")
       .Search(65536)
       .Help("/helloworld/index");

The PageHeader control has only one property - the hexadecimal color code, from which starts the vertical gradient fill (from bottom to top, with shading of specified color).

The Command method creates a command (i.e. link), that leads to the module home page. The first parameter - is the link text, the second - its address, and the third - the tooltip text, that appears when you hover the mouse cursor on the command. Links text is presented as language tokens.

The Search method adds a search string. The module ID is passed as parameter into this method.

The Help method adds a link button that opens help topic. A link to help topic is passed as parameter of this method.

 

Text - Block of Text

Sometimes you may need to display part of a page, that is styled using HTML tags (e.g., table description).

Fig. 3. Block of Text

In such cases, blocks of text are inserted using the Text control:

TeamWox.Control("Text","<strong><lngj:HELLOWORLD_INFO/></strong>","html")
       .Style({"font-size":"24px", "padding-top":"12px"});

The first parameter is the text itself. If you use HTML tags, you need to specify the second parameter - html. Note that in this control we've invoked the .Style() method that specifies text size and its indent.

Note: Do not use this control to create blocks of text with complex formatting (with different colors and fonts).

 

ViewTable - Table with Data

Tables are created using the ViewTable control:

TeamWox.Control("ViewTable",ids,headers,data);

The first parameter - ids - are columns IDs, the second - headers - text of columns headings, the third - data - data array that is inserted into table. In our example, the table contains the names and governing dates of first five U.S. presidents:

Fig. 4. Table

Let's consider the implementation of this table in the template:

//+----------------------------------------------+
//| Table with public information                |
//+----------------------------------------------+

//--- Table configuration
var table_cfg =
{
   //--- Table headers
   id:     ['number','name'],
   header: [
               {id:'number', content:'<lng:HELLOWORLD_POSITION/>', style:'width:20px'},
               {id:'name',   content:'<lng:HELLOWORLD_NAME/>'}
           ]
};
//--- Function that writes data from manager into table (array)
function RecordToTable(data)
{
   var records = [];
   for(var i in data)
      //--- Write data into the records array
      records.push([
         {id:'number', content:data[i].id},
         {id:'name',   content:TeamWox.StrSafe(data[i].name)}
                  ]);
   //---
   return records;
}
//--- Create table and fill it with data
TeamWox.Control("ViewTable",table_cfg.id,table_cfg.header, RecordToTable(<tw:info_list/>))
//--- The info_list token passes data from module's manager into RecordToTable function,
//    that returns array to display in table

First the table_cfg object is created, that determines table configuration - number of columns, their IDs, header names, their widths. Then we create the RecordToTable() function, that prepares data as an array to be displayed in the table.

Finally, the ViewTable control is created: it creates a table using the table_cfg configuration and populates it with data, that are passed into RecordToTable() as a parameter. Note that the function parameter in this example - is the <tw:info_list/> token.

 

Templates - Tool for Data Output on Pages

Data output via page templates is done using TeamWox tokens. Tokens are created in the source code of module pages.

By their look in a template file, tokens resemble the HTML tags (opened and closed), but don't confuse them. Token TeamWox begins with opening angle bracket (<), followed by prefix (tw, tws or lngj - see details next), then after colon (:) comes the value of token, then (optionally) follow the attributes of token in the form свойство="значение". After that the token ends with closing angle bracket (>) or with slash and closing angle bracket (/>). In the first case (>), the token is considered as opened (containing child tokens), in the second case (/>) - it is closed (without child tokens).

Template file is parsed consistently from top to bottom. When a token is encountered, controlling is switched to the class page. When token processing is complete, it returns either true (in this case its child tokens and text tag are processed) or false (token parsing is completed).

 

Data Output from Module Manager into Page

Let's consider the implementation of the <tw:info_list/> token, which is used to populate our table with data. The <tw:info_list/> token is created in the source code of the PageNumberTwo.cpp page. Open it and go to the Process token section:

//+------------------------------------------------------------------+
//| Process token                                                    |
//+------------------------------------------------------------------+
bool CPageNumberTwo::Tag(const Context *context,const TagInfo *tag)
  {
//--- checks
   if(context==NULL || tag==NULL || m_server==NULL)  return(false);
   if(context->request==NULL || context->user==NULL) return(false);
//---
   wchar_t tmp[64]={0};
//---
   if(TagCompare(L"info_list",tag))
     {
      CJSON json(context->response);
      json << CJSON::ARRAY;
      for(int i=0;i<m_info_count;i++)
        {
         json << CJSON::OBJECT;
         //---
         json << L"id"   << m_info[i].id;
         json << L"name" << m_info[i].name;
         //---
         json << CJSON::CLOSE;
        }
      //---
      json << CJSON::CLOSE;
      //---
      return(false);
     }

As the data from server is being output in JSON (JavaScript Object Notation) format, suitable for automatic processing, we need to generate the response as a simple two-dimensional array of key/value pairs. For convenient and secure data output in JSON format you should use the CJSON class, included in TeamWox SDK.

All tokens on the page are processed using the Tag() method, in which using the TagCompare() function each token is checked against the name being processed.

In our case - this token is named as info_list. With its help, we will send data from server to page. In this token the json object is created, which represents the response text in JSON format.

Then we create the array (CJSON::ARRAY - in JSON response the opening bracket [ is created). Every object in the array contains two key/value pairs. The first pair will contain the number(id), and the second will contain the text (name). For each object, first opens the curly brace { (CJSON::OBJECT), followed by the comma , (if you have the next array element), after which the curly brace is closed } (CJSON::CLOSE). Once the array is filled, it also closes with the bracket ] (CJSON::CLOSE).

Data for this array is taken from the Manager (see Manager's source code for more details: Managers\HelloWorldManager.cpp). Thus, the info_list token sends the following response:

[
 {"id":1,"name":"George Washington (April 30, 1789 - March 4, 1797)"},
 {"id":2,"name":"John Adams (March 4, 1797 - March 4, 1801)"},
 {"id":3,"name":"Thomas Jefferson (March 4, 1801 - March 4, 1809)"},
 {"id":4,"name":"James Madison (March 4, 1809 - March 4, 1817)"},
 {"id":5,"name":"James Monroe (March 4, 1817 - March 4, 1825)"}
]

This is a simple, human friendly data format, which is also easily and naturally processed by the ViewTable object.

 

Conclusion

In this article we've considered only three controls from TeamWox library. Here are few more:

  • PageNumerator - Page numbers that can be switched.
  • Form - Input form.
  • Input.text - Input simple text.
  • Input.rte - Input formatted text.
  • Input.combobox - Drop-down list.
  • Input.comboedit - Drop-down list with ability to manually enter values.
  • Input.date - Date.
  • Calendar - Calendar.

2010.10.05