This tutorial provides you with some hands-on experience in running and customizing a Web application delivered by the Genero Web Client front-end.
The Genero Application Server installs with a demo application known as the Contact List (Card Manager) application. The default configuration provided in the GAS configuration file allows you to run this demo application without any additional configuration.
To run the demo application, start the GAS and then enter the following URL in a browser:
http://localhost:6394/wa/r/demo/Card
Note: For the purpose of this tutorial, it is assumed that you are connecting to the GAS directly. If your browser is on a different host than the GAS, you will have to replace "localhost" with the name or IP address of the GAS host. Likewise, if you have changed the port number from the installation default of 6394, you will have to modify the port number accordingly.
Things to observe:
<?xml version="1.0"?> <APPLICATION Parent="defaultgwc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.4js.com/ns/gas/2.10/cfextwa.xsd"> <EXECUTION> <PATH>$(res.path.demo.app)/card/src</PATH> <MODULE>card.42r</MODULE> </EXECUTION> </APPLICATION>
For the next part of this tutorial, a custom snippet file has been created to display image widgets for this application.
Enter the following URL in a browser:
http://localhost:6394/wa/r/demo/CardStep1
Thing to observe:
Examine the application configuration file for this step in the tutorial.
<?xml version="1.0"?> <APPLICATION Parent="defaultgwc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.4js.com/ns/gas/2.11/cfextwa.xsd"> <EXECUTION> <PATH>$(res.path.demo.app)/card/src</PATH> <MODULE>card.42r</MODULE> </EXECUTION> <OUTPUT> <MAP Id="DUA_AJAX"> <THEME> <SNIPPET Id="Image" Style="Picture">$(res.path.demo.app)/card/tpl/set1/Image.xhtml</SNIPPET> </THEME> </MAP> <MAP Id="DUA_AJAX_HTML"> <THEME> <SNIPPET Id="Image" Style="Picture">$(res.path.demo.app)/card/tpl/set1/Image.xhtml</SNIPPET> </THEME> </MAP> </OUTPUT> </APPLICATION>
A new snippet file has been created for the rendering of the Image widgets for this application.
To identify what is different, you can compare the Image.xhtml file provided with the default AJAX theme ($FGLASDIR/tpl/set1/Image.xhtml) with the snippet file specified by the SNIPPET element in the application configuration file. Using Genero Studio's Graphical Differential tool, we can quickly identify the differences between the two files, as shown in Figure 1-3 below:
<ALIAS Id="/card/img">$(res.path.demo.app)/card/src/photo</ALIAS>
Usually, application pictures are configured through the picture component. In this example, the common pictures are handled by the picture component, alias "/pic", and the application images are served through alias "/card/img". Another solution could be to copy all the common picture in the application image directory and set the component picture path to alias /card/img.
<PICTURE> <PATH>$(connector.uri)/card/img</PATH> </PICTURE>
In this case you do not need to customize your image snippet file.
For the next step in this tutorial, a header and footer have been added.
Enter the following URL in a browser:
http://localhost:6394/wa/r/demo/CardStep2
Things to observe:
Examine the application configuration file for this step in the tutorial.
<?xml version="1.0"?> <APPLICATION Parent="defaultgwc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.4js.com/ns/gas/2.10/cfextwa.xsd"> <EXECUTION> <PATH>$(res.path.demo.app)/card/src</PATH> <MODULE>card.42r</MODULE> </EXECUTION> <OUTPUT> <MAP Id="DUA_AJAX"> <THEME> <TEMPLATE Id="_default">$(res.path.demo.app)/card/tpl/set1/main.xhtml</TEMPLATE> <SNIPPET Id="Image" Style="Picture">$(res.path.demo.app)/card/tpl/set1/Image.xhtml</SNIPPET> </THEME> </MAP> </OUTPUT> </APPLICATION>
Using Genero Studio's Graphical Differential tool, we can quickly identify the differences between the two files, as shown in Figure 2-3 and 2-4 below:
To add a header to the application display, the following code is placed in the custom template file:
<div class="card-header" style="background-color:#e6e6e6"> <img src="..." gwc:attributes="src application/connectorURI + '/fjs/demo/card-logo.png'" alt="Genero logo"/> </div>
To add a footer to the application display, the following code is placed in the custom template file:
<div class="card-footer">For any issues or comments please contact <a href="mailto:support@4js.com">support@4js.com</a></div>
To add a custom CSS file, an entry is made under the existing CSS entry and within the HEAD tags (as shown in Figure 2-3):
<link rel="stylesheet" gwc:attributes="href application/connectorURI+'/fjs/demo/card.css'" type="text/css" title="Default Theme"/>
For this example, we have provided a CSS for you. Before moving to the next step, you can make changes to this CSS file and view the results in the displayed application..
For the next step in this tutorial, various things are added:
First, the FormField snippet has been modified such that all fields where the REQUIRED attribute is set to true (1) are marked on the UI with an asterisk.
Second, customized Edit snippets are created to render Edit widgets based on their assigned styles. If the field is representing an email address, that field is assigned the style of "Email", and a custom Edit snippet is called to render the field as a link that, when clicked, opens a new message to the clicked-on address. If the field is representing a Web address, that field is assigned the sytle of "OpenURL", and a custom Edit snippet is called to render that field: displaying an Open button that, when clicked, opens the specified URL.
Enter the following URL in a browser:
http://localhost:6394/wa/r/demo/CardStep3
Things to observe:
The Email field displays as a link that, when clicked, opens a new mail message using the default mail program.
The Web Site field displays as a link also, when clicked, the specified Web Site displays.
Examine the application configuration file for this step of the tutorial.
<?xml version="1.0"?> <APPLICATION Parent="defaultgwc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.4js.com/ns/gas/2.10/cfextwa.xsd"> <EXECUTION> <PATH>$(res.path.demo.app)/card/src</PATH> <MODULE>card.42r</MODULE> </EXECUTION> <OUTPUT> <MAP Id="DUA_AJAX"> <THEME> <TEMPLATE Id="_default">$(res.path.demo.app)/card/tpl/set1/main.xhtml</TEMPLATE> <SNIPPET Id="Image" Style="Picture">$(res.path.demo.app)/card/tpl/set1/Image.xhtml</SNIPPET> <SNIPPET Id="FormField">$(res.path.demo.app)/card/tpl/set1/FormField.xhtml</SNIPPET> <SNIPPET Id="Edit" Style="Email">$(res.path.demo.app)/card/tpl/set1/Edit_Email.xhtml</SNIPPET> <SNIPPET Id="Edit" Style="OpenURL">$(res.path.demo.app)/card/tpl/set1/Edit_OpenURL.xhtml</SNIPPET> </THEME> </MAP> </OUTPUT> </APPLICATION>
Changes to the FormField snippet provide the code that places an asterisk next to required fields, when you are in input mode:
<span style="color:red" gwc:condition="item/isModifiable && item/isRequired && item/hidden!=1" >*</span>
isRequired notation is used to determine whether the required attribute is set to true, and if so an asterisk is displayed.
For the two custom Edit snippets, open the relevant files and observe the following:
For the Edit snippet for the style Email, the following has been added:
<a gwc:attributes="href 'mailto:'+value" gwc:content="'mail'" />
For the Edit snippet for the style OpenURL, the following has been added:
<input type="button" value="Open" gwc:attributes="onclick 'OpenURL(\''+value+'\')'"/>
For the next part of this tutorial, a custom Table snippet uses the gwc:marks instruction to make a call to a JavaScript that renders the table based on the value selected in the Page size list box.
Enter the following URL in a browser:
http://localhost:6394/wa/r/demo/CardStep4
Things to observe:
Examine the application configuration file for this step in the tutorial. Note that a new entry has been added, specifying a custom snippet file for all Table widgets.
<?xml version="1.0"?> <APPLICATION Parent="defaultgwc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.4js.com/ns/gas/2.10/cfextwa.xsd"> <EXECUTION> <PATH>$(res.path.demo.app)/card/src</PATH> <MODULE>card.42r</MODULE> </EXECUTION> <OUTPUT> <MAP Id="DUA_AJAX"> <THEME> <TEMPLATE Id="_default">$(res.path.demo.app)/card/tpl/set1/main.xhtml</TEMPLATE> <SNIPPET Id="Image" Style="Picture">$(res.path.demo.app)/card/tpl/set1/ImageStep4.xhtml</SNIPPET> <SNIPPET Id="FormField">$(res.path.demo.app)/card/tpl/set1/FormField.xhtml</SNIPPET> <SNIPPET Id="Edit" Style="Email">$(res.path.demo.app)/card/tpl/set1/Edit_Email.xhtml</SNIPPET> <SNIPPET Id="Edit" Style="OpenURL">$(res.path.demo.app)/card/tpl/set1/Edit_OpenURL.xhtml</SNIPPET> <SNIPPET Id="Table">$(res.path.demo.app)/card/tpl/set1/Table.xhtml</SNIPPET> </THEME> </MAP> </OUTPUT> </APPLICATION>
By this point, you should easily identify that a custom snippet for the Table widget has been created and specified for this application.
Adding a select to change the number of lines displayed in a table
<select gwc:marks="changePageSize [CID]" gwc:attributes="id 'pgsz_'+id"> <option gwc:attributes="value makePageSizeIDID(id , 1)">1</option> <option gwc:attributes="value makePageSizeIDID(id , 5)">5</option> <option gwc:attributes="value makePageSizeIDID(id , 10)">10</option> <option gwc:attributes="value makePageSizeIDID(id , 15)">15</option> <option gwc:attributes="value makePageSizeIDID(id , 20)">20</option> <option gwc:attributes="value makePageSizeIDID(id , 30)">30</option> <option gwc:attributes="value makePageSizeIDID(id , 50)">50</option> <option gwc:attributes="value makePageSizeIDID(id , size)">all</option> </select>makePageSizeIDID is the template function that will send the action to change the pageSize of the table
changePageSize is the new function we add to the component Table
gwc.componentSet.Table.changePageSize = function( polarity, eid, cid, component, data ) { // set an event on the object to submit the action when the value is changed gwc.tk.SetEventEx(polarity, document.getElementById(eid), 'change', gwc.componentSet.Table.sentPageSize); }
changePageSize is the function we declared in the Table.xhtml snippet using the gwc:marks instruction.
gwc.tk.SetEventEx is a function of the toolkit to handle (add/remove) events it take 4 arguments.
polarity: boolean, to add or remove the handler
elt: item on with the handler is set/removed
ev: event name
handler: function attached to the event
Warning! As with all functions in the CSF toolkit, this function is subject to changes.gwc.componentSet.Table.sentPageSize = function(ev,elt){ gwc.capi.Action(elt.value); }gwc.componentSet.Table.sentPageSize is the handler associate to the 'onchange' event of the select item.
gwc.api.Action sent an action to the engine.
<SNIPPET Id="Table">$(res.path.demo.app)/card/tpl/set1/Table.xhtml</SNIPPET>
<script type="text/javascript" gwc:attributes="src application/connectorURI+'/demo/card.js'" defer="defer"> </script>
Send an action to the engine (see the custom Image.xhtml snippet)
Clicking on the picture of the contact will
send the "changeimg" action to the engine and open a window to upload a new image
for the contact.
Note, accepting the dialog without changing the image will set the image to
blank.
<a gwc:attributes="href 'javascript:gwc.capi.Action(gwc.core.state.ActionDidByName(\'changeimg\') )'">[...]</a>
Communicate with external web sites like googlemap, geonames
To use googlemap you need to to sign up for a key at http://code.google.com/apis/maps. You can use the current key if you are testing with localhost server.
Figure 4-2: The Check Location button is added to the form.
Google Map and geonames are used to fill the country name. Clicking on the button gives the focus to the country field and opens the Google map. Once the map opens, double click on a country name to populate the country field.
Excerpt from Edit_GoogleMap.xhtml snippet:
<input type="button" value="Choose" gwc:condition="isModifiable" gwc:attributes="onclick 'gwc.capi.Focus(\'' + cid + '\');' + 'OpenMap(\''+ application/connectorURI + '/fjs/demo/card-map.html\',\'wd_country\',\'' + value + '\')'" />The field should have the focus, if you want the value to be taken in account by the 4GL application. To set the focus on a field, use the JavaScript api function gwc.capi.Focus.
Excerpt from card.js
function SetCountry(id,value) { var elt = gwc.tk.IdToElement(id); elt.value = value; }
gwc.tk.IdToElement is a function of the
toolkit that get the html object given the id of this element. The field is then
filled with the value returned by geonames.
GoogleMap is used to locate and check the address. In the Edit_GoogleMap.xhtml snippet, get the value of the fields address, town and country.
<input type="button" value="Check location" gwc:condition="!isModifiable" gwc:define="address FormField['formonly.address']/item/value; town FormField['formonly.town']/item/value; country FormField['formonly.country']/item/value; " gwc:attributes="onclick 'ShowLocation(\''+ application/connectorURI + '/fjs/demo/card-map.html\',' + '\'' + escapeJS(translate(address, ['\'',','] ,' ')) + '\',' + '\'' + escapeJS(translate(town, ['\'',','] ,' ')) + '\',' + '\'' + escapeJS(translate(country, ['\'',','] ,' ')) + '\'' + ')'" />
In card.js, the JavaScript function ShowLocation submits the data to the map page. GoogleMap locates and displays the address on the map.
function ShowLocation(url,address,town,country) { var args = "id=&value=&address=" + address + "&town=" + town + "&country=" + country; var win = window.open(url + "?" + args ,"CardMap","toolbar=no,menubar=no,location=no,height=500,width=500"); }
Throughout this tutorial, you have customized your application's User Interface using CSS, snippets, template files, and JavaScript.
You should have noted that at no time did you have to change the application source code.