Tuesday, August 29, 2006

AJAX - Autocompletion

This article is an abstract of three articles in french section. If you read NSFTools blog, you've had a first solution to implement autocompletion with scriptaculous.

First Step : Installation of javascript libraries
Like Julian, I use javascript library Scriptaculous. Scriptaculous is based on another Javascript library, prototype.js. You can download all this libraries on scriptaculous web site. Unzip the file in your hard disk and add all the files in shared resources of your Lotus Notes Database. You can create a new database to add this javascript files too. This new database can be used by all your application who need this javascript libraries and it will be easier to update the javascript files. The advantage of files resources is to be accessible from Windows explorer with WebDAV. I'll write an article about this new Domino service.

Second Step : Creation of the form
We just need one editable field.

  • create new form
  • add editable text field
  • in the last tab of the property of the field add an id name. For example : autocomplete
  • add javascript code as HTML relay just after your field :
    <div id="autocomplete_choices" class="autocomplete"></div>
    <script language="javascript" charset="UTF-8" >
    new Ajax.Autocompleter("autocomplete", "autocomplete_choices",
    "search?openpage", {method:'get',paramName: 'autocomplete'});
    </script>
  • add in your HTML Head content the declaration of the javascript libraries prototype.js and scriptaculous and the stylesheet to display list :
    "<script src=\"prototype.js\" type=\"text/javascript\"></script>
    <script src=\"effects.js\" type=\"text/javascript\"></script>
    <script src=\"dragdrop.js\" type=\"text/javascript\"></script>
    <script src=\"controls.js\" type=\"text/javascript\"></script>
    <style>
    div.autocomplete {
    font-size:10px;
    font-family : tahoma, arial, helvetica, sans-serif;
    width: 350px;
    background: #fff;
    }
    div.autocomplete ul {
    border:1px solid #888;
    margin:0;
    padding:0;
    width:100%;
    list-style-type:none;
    }
    div.autocomplete ul li.selected {background-color: #ffb;}
    div.autocomplete ul li {
    margin:0;
    padding:3px;
    cursor:pointer;
    }
    </style>"
Be careful, perhaps you'll need to change the path of the javascript libraries.
The form is ready to use.

Third Step : Search view
In my example, the search view have only one sorted column. This column only display the values to show in autocompletion list.

Last Step : Search page
To search all the words who begin by the letters and send the response to Ajax, I use a Notes Page. It's possible to use form or agent too. The result must look like :
<ul>
<li>1st word</li>
...
</ul>
  • Create new page named "search"
  • Select "Type of content : HTML" in the second tab of the page properties
  • Add new computed field with formula :
    val := @DbLookup("":"nocache"; "";"dbautocomplete"; @UrlQueryString("autocomplete"); 1; [PartialMatch] );
    @If(@IsError(val); ""; "<ul>" + @Implode("<li>" + val + "</li>") + "</ul>");
It's finish ! You can test.

BONUS
You can add two interresting options to the declaration of the autocomplete class

1. Start search after the nth characters
If you don't want to start autocomplete search from the first letter, you can add a parameter to specify after how many letter you want to begin.
Add the parameter "minChars" like this :
new Ajax.Autocompleter("autocomplete", "autocomplete_choices",
"search?openpage", {method:'get',paramName: 'autocomplete', minChars: 2});
In this example the search will start after the second characters

2. Manage multivalues field
You can specify a separator values too. When the user will type this separator the autocompleter will start a new search with only the charaters typed after.
Add the parameter "tokens" like this :
new Ajax.Autocompleter("autocomplete", "autocomplete_choices",
"search?openpage", {method:'get',paramName: 'autocomplete', tokens: ','});

Sunday, August 27, 2006

TIPS - How to export web data to MS Excel

To export data to MS Excel, we can use CSV file format. This option is used by a lot of statiscal web site like Google Analytics.

Description of CSV File Format
CSV file format is a text file with values separated by comma or semicolon. Every rows are separated by carriage return. An example of CSV data :

Name; January;February; March
John; 12; 14;18
Tatiana;8;18; 15
Juan; 13; 12.5; 18

How to integrate CSV export in Lotus Domino
In this example I use a Notes View but we can use a Notes agent too.

Creation of view "statistics.csv"
To separate values, I create column between every column of values with formula ";". To separate each line I add a last column with formula : @char(13) + @char(10). I select option of my view "treat view content as HTML"

Creation of form "$$View Template for statistics.csv"
I integer the Notes View in a new form named "$$ViewTemplate ofr statistics.csv". I unselect "display column title" of the Embedded view option and I selcet to display it with HTML.

I want to open the view in MS Excel and not in Web Browser. To do that I just have to change MIME-Type of this form. The Mime-Type define to Web Browser how to display data and with which software. The MIME-Type for CSV file is : text/csv. I define this Mime-Type in the second tab of form options.


You can open this exemple in Excel.

Monday, August 21, 2006

GOOGLE API - Geolocalisation search from Lotus Notes client

It's possible to search geolocalisation of an postal address from Lotus Notes client too.


ALAX : Asynchronous LotusScript And XML

To search the geolocalisation of a postal address from Lotus Notes Client, I use XMLHTTP object like in AJAX solutions. This object can be used in lotuscript thru agent, event or action.

Search Form

The elements of my form are :

  • "street" : text field
  • "town" : text field
  • "country" : text filed
  • button "search"
  • "latitude" : text field
  • "longitude" : text field
The user will specify street, town and town, then will click on search button. The values of Lattitude and longititude fields will be automatically added.

Search button

I use the same web service than previous entry. The function must :
  • format search query from fields values
  • send request to web service
  • parse the result
  • added values to longitude and latitude fields
The LotusScript code :
Sub Click(Source As Button)
Dim wk As New NotesUIWorkspace
Dim uidoc As NotesUIDocument
Dim doc As NotesDocument
Dim street, town, country As Variant

Set uidoc = wk.CurrentDocument
Set doc = uidoc.Document

' longitude/latitude search request
' -----------------------------------------------------------
' the text must be encoded in URL format to replace special characters
' and spaces. localsearchmaps web service doesn't accept null value
' for street. If the user doesn't specify this information, we'll send
' "%20"

street = Evaluate({@URLEncode("UTF-8";"} + doc.street(0) + {")})
If street(0)="" Then street(0) = "%20"
town = Evaluate({@URLEncode("UTF-8";"} + doc.town(0) + {")})
country = Evaluate({@URLEncode("UTF-8";"} + doc.country(0) + {")})
request = "http://www.localsearchmaps.com/geo/?street=" + street(0) + _
"&city=" + town(0) + "&country=" + country(0) + "&cb=notes"

' Call and reception of the request
' -------------------------------------------------------------
' The XMLHTTP object only work if user have Internet Explorer

Set page = CreateObject("Microsoft.XMLHTTP")
Call page.open("GET", request, False)
Call page.send()

strReturn =page.responseText

If (Instr(strReturn,"notes")>0) Then
' Extraction of longitude and latitude
' ----------------------------------------------------
' The result of the request looks like :
' notes(latitude, longitude,'TOWN', 'CODE', 'COUNTRY');

search = Mid(strReturn, 7, Instr(strReturn, ",'") -7)
lattitude = Left(search, Instr(search, ",") -1)
longitude = Mid(search, Instr(search, ",") +2)

Call uidoc.FieldSetText("latitude", lattitude)
Call uidoc.FieldSetText("longitude", longitude)
Else
Messagebox "The postal address wasn't found", 48, "Geolocalisation"
End If

Set page = Nothing
End Sub

Sunday, August 20, 2006

GOOGLE API - Full-Text search in Google Maps API (2/3)

The previous entry presented how to find documents placed close to a postal address. I present now how to find the location of a document on the map. To find document in the database, I'll use Lotus Notes Full-Text Search.

AJAX : (Asynchronous JavaScript And XML)
I can't use standard Lotus Notes full-test search without using frames or iframes. The search form is "POSTed". Then the map will be reloaded after each requests. I'll use AJAX and little DHTML to perform my full-text search in asynchronous mode and integer the result without reload the web page. To learn more about AJAX you can read :

How to customize result search view

When users will click on a link in the result view, I want to center and center on Google Map at the position represented by the document. To do that, I reuse the Javascript function "mapZoom". To have more details on this function read the previous post. The hypertext link of the document will look like :
$lt;A HREF="" OnClick="mapZoom(longitude, latitude); return(false);">myLink</A>

To obtain this result :
  1. Create a new view "Search"
    • First column formula : "<A HREF="" OnClick="mapZoom(" + longitude + ", " + latitude + "); return(false);">" + title + "</A>"
    • Second column formula : description + "<br />"
    • Select view option : "treat view content as HTML"
  2. Create form to display search result : "$$SearchTemplateDefault"
    • Insert new field named "$$ViewBody"

The search form and result area

The user needs only one field to type his request and a search button. In html :
<FORM NAME="form_fts">
<LABEL>Texte : </LABEL> <INPUT NAME="req" SIZE=35 />
<BUTTON VALUE="Rechercher" NAME="Rechercher"
TYPE="button" onClick="searchNotes()">
Rechercher
</BUTTON>
</FORM>

<DIV id="affres" style="overflow:auto; padding:5px; height:100px;"></DIV>
Search and display result with AJAX

The AJAX function use Lotus Notes standard search url to call result web page and display it in the div with id "affres". The url to search query looks like :
"search?searchview&query=text from my query field".
function searchNotes(){
var xmlhttp=false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@end @*/

if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp=false;
}
}
if (!xmlhttp && window.createRequest) {
try {
xmlhttp = window.createRequest();
} catch (e) {
xmlhttp=false;
}
}

xmlhttp.open("GET", "search?searchview&query=" +
escape( document.form_fts.req.value),true);
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4) {
document.getElementById("affres").innerHTML = xmlhttp.responseText;
}
}
xmlhttp.send(null)
}
document.getElementById("idname").innerHTML display result as content of the div with id "idname".

GOOGLE API - How to search informations with Google Maps API (1/3)

There are no geographical localisation search function from postal address in Google Maps API. If we haven't latitude and longitude of the points, it will be difficult for users to search informations for every documents.

If I use Google Maps and Google Earth it's I want :

  • to find all documents in a region
  • to find where is the site referenced by the document

To find the position of a document the user need to zoom on the by clicking on this document in a list for example. With Google Earth there is no problem. The list of document appears in left pannel. We juste have to double click on the title of a document to be centered and zoomed on the site referenced by the document. Unfortunately you haven't this option with Google Maps.

How to find, center and zoom on Google Maps with a postal address
To find geolocalisation of a postal address I use web service localsearchmap. This web service return by default the Google Maps API syntax to center and zoom on this point. Unfortunately, it uses the version 1 of the API syntax who's not compatible with the actual version. The web service permiss to custumize the format of the response.

The basic syntaxe to call this service is :
http://www.localsearchmaps.com/geo/?street=mystreet&town=mytown
&country=mycountry
It's possible to add an argument to return the result with call to Javascript function : &cb=myJavascriptFonction

For example :
http://www.localsearchmaps.com/geo/
?street=rue+des+cosmonautes&town=palaiseau
&country=france&cb=mapZoom

return the result : mapZoom(46.624, 2.4622);

To use map object in Javascript function I must declare this object as global in the javascript code who display Google Maps map (previous entry).

The search form

The user needs to specify postal address in a form. We must add three fields and a button in the Google Maps page : street, town, coutry fields and search button.

<FORM NAME="form">
<LABEL>Street : </LABEL> <INPUT NAME="street" SIZE=50 /><BR />
<LABEL>Town : </LABEL> <INPUT NAME="town" SIZE=50 /><BR />
<LABEL>Country : </LABEL> <INPUT NAME="country" />
<BUTTON VALUE="Search
" NAME="Search" TYPE="button"
onclick="searchPoint()">
Search
</BUTTON>
</FORM>

mapZoom(lat,long) Javascript function
When we'll have found the geolocalisation of the point, we must center and zoom on the point. Then I declare a new Javascript function to do that :
function mapZoom(lat, long,town,state,country){
var point = new GLatLng( parseFloat(lat), parseFloat(long));
map.setCenter(point,14, G_HYBRID_MAP );
}
searchPoint() Javascript function
This function call web service with datas of the form in argument. The result will launch the previous function to zoom and center on the point.
function searchPoint() {
var queries = "?street=" + escape( document.form.street.value)+
"&city="+escape( document.form.town.value)+
"&country=" + escape( document.form.country.value);
var s = document.createElement( "script" );
s.src="http://www.localsearchmaps.com/geo/" + queries + "&cb=mapZoom";
s.type = "text/javascript";
document.getElementsByTagName( "head" )[0].appendChild(s);
}
This example (in french for the moment) shows you the result.

GOOGLE API - Lotus Notes & Google Maps

An API is available to customize Google Maps. You can add your own points on the earth like with Google Earth.

Steps to interface Lotus Notes and Google Maps :

  1. Signup for a Google Maps API key
  2. Create data source to define points to display (position and description)
  3. Create web page to display the Google Maps map and your points
Step 1 : Google Maps API key
The usage of API key is restricted to an URL to define. Only elements directly accessible from this "directory" can be displayed on the map. Be careful when you define the URL. Don't panic if you define a wrong URL. You'll can define a new API Key.
  • If you want to call map from a page or an agent you'll specify the URL of the database. for example http://www.acme.com/sample.nsf/
  • If you want to call map from a document you'll must add the view in your URL. You can use the special view "0" too. For example : http://www.acme.com/sample/0/
In my example, I'll use a page to declare the Google Maps. Then, I use the URL http://free.dominoserver.de/it/dominoweb.nsf/ to define my new Google Maps API key.

To obtain an API key, go to web page http://www.google.com/apis/maps/

Step 2 : Creation of the data source
I need the same informations than Google Earth. Then I use the same form.

The extraction of data thru XML file is managed by Javascript. I could use the same file format than Google Earth. I've defined another XML format in this example to simplify the javascript code.

XML View for Google Maps
The XML File must define at least latitude and longitude. In this example I've chosen the format :
<markers>
<marker lat="latitude" long="longitude" title="titre">
<description><![CDATA[description]]></description>
</marker>
</markers>
Then the column formula for the "Google Maps" view is :
"<marker
lat=\"" + latitude + "\"
long=\"" + longitude + "\"
title=\"" + titre + "\">
<description><![CDATA[" + description + "]]></description>
</marker>"
Select option "treat view content as HTML" in view properties.

I create a form to display view as XML flow.

  • New form named "$$ViewTemplate for <Name of my view>"
  • Select Option "Type of file : Other : text/xml" in form properties
  • Insert XML header code :
    <?xml version="1.0" encoding="ISO-8859-1" ?>
    <markers>
  • Insert the view with option display as HTML

  • Insert XML footer code :
    </markers>
Step 3 : Display the map and points from a page

I use a Lotus Notes "Page" to display map and points. You can use agent or document too.
The minimal code display map without points is :
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=MyGoogleMapsAPIKey"
type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[
function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(27.994401,13.164063),1, G_HYBRID_MAP );
}
}
//]]>
</script>
</head>

<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 500px; height: 300px"></div>
</body>

</html>
To download XML file and display points on the map I use "GDownloadUrl" Google javascript function.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script src="http://maps.google.com/maps?file=api&v=2&key=MaCleAPIGoogleMaps"
type="text/javascript"></script>

<script type="text/javascript">
//<![CDATA[
function load() {

if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(27.994401,13.164063),1, G_HYBRID_MAP );

GDownloadUrl("googlemaps.xml", function(data, responseCode) {
var xml = GXml.parse(data);
var markers = xml.documentElement.getElementsByTagName("marker");
for (var i = 0; i < markers.length; i++) {
var latitude = parseFloat(markers[i].getAttribute("lat"));
var longitude = parseFloat(markers[i].getAttribute("long"));
var title = markers[i].getAttribute("title");
var desc =
markers[i].getElementsByTagName("description")[0].firstChild.nodeValue;
var point = new GLatLng(latitude,longitude);
var marker = new GMarker(point);
map.addOverlay(marker);
}
});
}
}
//]]>
</script>
</head>

<body onload="load()" onunload="GUnload()">
<div id="map" style="width: 500px; height: 300px"></div>
</body>

</html>
I use two differents type of call in javascript to extract XML File datas.
  • var latitude = parseFloat(markers[i].getAttribute("lat"));
    To extract attribute of XML tag.
  • var desc = markers[i].getElementsByTagName("description")[0]
    .firstChild.nodeValue;
    To extract values declared between two XML tags.
For the moment I've just displayed the points. I can't display description when I click on a point.
To do that, I declare a new Javascript function :
function createMarker(point,title, desc ) {
var bulle = "<h3>" + title + "</h3><p>" + desc +"</p>";
var marker = new GMarker(point);
GEvent.addListener(marker, "click", function() {
map.setCenter(point,14, G_HYBRID_MAP );
marker.openInfoWindowHtml(bulle);
});
return marker;
}
To use this function, I replace var marker = new GMarker(point); by var marker = createMarker(point,title, desc);
You can look at an example (for the moment in french): http://free.dominoserver.de/it/dominoweb.nsf/googlemaps

To have more informations about Google Maps API you can read the API documentation

GOOGLE API - Lotus Notes & Google Earth

Display Lotus Notes Document on Google Earth is simpliest solution. To add points on maps you just have to prepare KML file.

Quick description of KML format
KML files are XML files who permiss to describe the points to display on earth. The definition of a point include position of the point (latitude and longitude) and a description.

<kml xmlns="http://earth.google.com/kml/2.0">
<Placemark>
<description>
<![CDATA[<a href="http://www.google.com/">Google Search!</a>]]>
</description>

<name>Google Headquarters</name>
<Lookat>
<longitude>-122.0839</longitude>
<latitude>37.4219</latitude>
<range>540.68</range>
<tilt>0</tilt>
<heading>3</heading>
</Lookat>
<Point>
<coordinates>-122.0839,37.4219,0</coordinates>
</Point>
</Placemark>
</kml>
  • Placemark : New point
  • description : description displayed when you click on a point in Google Earth.
  • name : name of the point
  • Lookat : geolocalisation
  • longitude : longitude of the point
  • latitude : latitude of the point
  • range : altitude
  • tilt : angle from North
  • heading : angle from skyline
  • coordinates : coordonnates of the point
If you want to define several points you must had the root tag <Document>. This tag accept tag "name" who permiss to describe the flow in Google Earth.

Other options can be used like customization of the icon. You'll find all informations on the help page of Google Earth : (http://www.keyhole.com/kml/docs/webhelp/index.htm)

How to integer Lotus Notes data in Google Earth with a simple view
There's a lot of solutions to interface Lotus Notes and Google Earth. I've choosen to generate KML file from Notes View.

Step 1 : The form
We need to have this informations :
  • a title
  • a description
  • longitude
  • latitude
The other elements will be define in the view.


Step 2 : The view
After create new view, select option "treat view content as HTML".
Column formula is (be carefull with Uppercase and Lowercase):

"<Placemark>
<description><![CDATA[" + description + "]]></description>
<name>" + titre + "</name>
<Lookat>
<longitude>" + longitude + "</longitude>
<latitude>" + latitude + "</latitude>
<range>540.68</range>
<tilt>0</tilt>
<heading>3</heading>
</Lookat>
<Point>
<coordinates>" + longitude + "," + latitude +"</coordinates>
</Point>
</Placemark>"


Step 3 : form to display view
To integer header and character setting of the KML file, I create a form to display the embedded view.

  • Create a forme named : $$ViewTemplate For
  • Select Option "Type of file : Other : Application/vnd.google-earth.kml+xml" in form properties
  • Insert KML header. I choose iso-8859-1 charset to support french characters. You can choose UTF-8 or other local charset.
  • <?xml version="1.0" encoding="iso-8859-1" ?>
    <kml xmlns="http://earth.google.com/kml/2.0">
    <Document>
    <name>Titre de mon flux Google Earth</name>
  • Insert embedded view
  • Insert KML footer
    </Document>
    </kml>
Etape 5 : Integer KML File in Google Earth
The MIME type was defined in Form properties. If you have installed Google Earth, you can open the view from a Web Browser. A dialog box will be open to ask you if you want to open the file in Google Earth. If you click on OK your file will be automaticly integer in Google Earth.

You can integer this file directly in Google Earth too. Open Google Earth and select Add\Network Link in menu. You'll just have to insert the URL of your view in location field.

Limitation with access control list
Be careful, you must defin Anaonymous with Reader access at least. I'll write an entries more later to resolve this problem.

Examples

GOOGLE API - Google Earth and Google Maps the new views for Lotus Domino

GoogleEarth and GoogleMaps now allow to display Lotus Notes documents, not in views, but on the earth.

The objectives of this first stage are to present :

  • how to display documents on Google Earth
  • how to display documents on Google Maps
  • the limitations of this tools with Lotus Notes
  • how to simplify the geolocalisation
Why would you want to display documents on a map ?
The geolocalisation of the documents should not be generalized with all types of documents. The first condition is to should associate geographical position to a document. The representation of the documents on a map can have two advantages :
  • To know the geographical position of a document
  • To know the documents who exist on a geographical position
This two informations are totaly differents. Google Earth and Google Maps can do the two things but it will be more or less simple to implement natively with.

Differences between Google Earth and Google Maps
Google Earth is a software then Google Maps is a service thru recent web browser (IE6 +, or Firefox).

Google Earth needs minimum configuration of the desktop and more particulary a recent graphic cards. You can dowload free version of Google Earth :
http://earth.google.com/download-earth.html

Google Earth

You ca access to Google Maps on URL http://maps.google.com. You can customized this maps with Google API. I use this API in the next entries. For more informations about GoogleMaps API, phlease consult the web site http://www.google.com/apis/maps/.

Interface Google Maps

Saturday, August 19, 2006

SITE - My Taylor is rich

This blog is the english translation of the French Blog Domino & Web 2.0.