jQuery in XPages #1 – Highcharts

I am delighted to present the first in my series of articles highlighting some extremely cool jQuery plugins and how to integrate them within XPages. During the course of the articles I will always demonstrate at least at some level, basic integration with XPages. In many cases I will not be able to cover all the examples of everything possible with each plugin, but I hope to give at least a good teaser to the possibilities and  show the myriad of possibilities.

I have to also say a HUGE thank you to David Leedy (www.notesin9.com) who is hosting my demonstration for this and the rest of this series when I get to them.

So without further ad0 – welcome to jQuery in XPages #1 🙂

Highcharts

For full disclosure, Highcharts is not free for commercial use.
“Do you want to use Highcharts for a personal or non-profit project? Then you can use Highchcarts for free under the Creative Commons Attribution-NonCommercial 3.0 License.”.

But part of the reason I chose it as the #1 is because it really rocks well with an XPage environment. It has direct business applicability, unlike many other jQuery plugins which are pretty, but hardly “corporate”. The format and structure of the chart instantiation also jibes well with XPages and I was able to create a custom control which can be applied to any formatted viewPanel or dataTable.

The Demo

Here is the demonstration site

and here is the demo dataabase

Link download the demo database

In the example below you can see a simple form with a viewPanel. Adding a new value to the form refreshes the page and displays the value entered. The exact same functionality would be seen if I had a basic data table looking at the same view of data.

The Example

Initial XPages form
Initial XPages form

Submitting the form gives us our new value

XPage with new Apples value added
XPage with new Apples value added

The XPage is laid out very simply and our View control is called viewPanel1

View Panel on the XPage
View Panel on the XPage

We add the drawHighchart Custom Control to the XPage

Adding the drawHighchart custom control to the page
Adding the drawHighchart custom control to the page

And let’s refresh our webpage – et voila – a chart

A simple Highchart added to our XPage
A simple Highchart added to our XPage

Changing the chart type is as simple as selecting a new theme and/or a new chart type

Changing the Highchart style
Changing the Highchart style

For more information on how this works check out the next article

jQuery in XPages #1 – Highcharts – how does it work?

Nin9 TypeAhead Demo

Today marks the release of my first video for Notes in 9. It has been my absolute pleasure to work with David Leedy on this project and I really hope that people find it useful. This blog entry is intended for my side-notes and also to provide a spot for any questions/comments.

Here’s a link to the video 🙂

Side Notes

This came about after my blog article on Adding a “working” visual indicator to the XPages TypeAhead. David approached me because he thought it would make a great Nin9 video. The original article was written from code on an 8.5.2 server and when I went to make the video on my 8.5.3 server I found that the HTML code generated for the type ahead was different any my code was “broken”.

As i said at the start of the original article, this is not bullet proof because you are always at the risk of this happening because we are manipulating the HTML created by the server. When IBM release 8.5.3 they upgraded dojo to 1.6 from 1.4 and the way the dijit comboxbox works had changed from one version of dojo to another, so IBM had to adapt.

The code in the example will work for 8.5.3 and 8.5.2 however because of the beauty of using the dojo.query. The 8.5.2 version is less complex and a couple of the lines in the addVisual() function are irrelevant. Because we are working with the dojo.query selector, and it find nothing to action on in the 8.5.2 HTML code, it does nothing – and most importantly fails over gracefully!!

Hope you enjoy the video 🙂

Marky

jQuery in XPages #1 – Highcharts – How does it work?

This how does it work article is a follow on from the original jQuery in XPages #1 – Highcharts and goes into depth as to how the functionality was created and how you can modify it yourself.

Be fore-warned this is quite dry and not for the faint of heart, but hopefully will provide a good insight and understanding.

How does this work?

This Highchart demonstration is made up of the following design elements

  • XPage
    • xFruit (the container XPage)
  • Custom Controls (where all the hard work is done)
  • Theme
    • Highchart (extends oneuiv2)
  • View
    • Fruit (data source for the viewPanel)
  • Form
    • Fruit (data container)
  • JavaScript Library
    • jsformFruit

To avoid making this article long(er than it already is) I am going to focus just on the drawHighchart custom control and the Highchart theme. The sample database is available for download and you can pick it to pieces at your leisure.

Highcharts Theme

The theme works by:

  • Extending the oneuiv2 theme (as a demonstration that it does not conflict)
  • Imports the jQuery library we need (jquery-1.7.1.min.js)
  • Imports the highchart.js library. Because this is a pure JavaScript library there are no associated image files (amazing really)

<theme extends="oneuiv2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="platform:/plugin/com.ibm.designer.domino.stylekits/schema/stylekit.xsd" >
	<resource>
		<content-type>text/css</content-type>
		<href>theme/style.css</href>
	</resource>
	<resource>
		<content-type>application/x-javascript</content-type>
		<href>jquery-1.7.1.min.js</href>
 	</resource>
	<resource>
		<content-type>application/x-javascript</content-type>
		<href>Highcharts/js/highcharts.js</href>
 	</resource>

</theme>

drawHighchart custom Control

This custom control is intended to be self contained for the sake of this demonstration and can be dropped onto any XPage in your application. The example has a dropdown for theme and graph type choices. These parameters are fed into the Highchart.js file based on the selected field values, but in your application where you only want a specific chart type they could be hard-coded. Later in the article you will see where the parameters are fed into the highchart.js library and how you can configure them yourself.

The code for the custom control breaks down like this:

  • Both the chart theme and chart type fields have a full refresh set on the “onchange” event. This reloads the page and data when a change is made. Again for the sake of a demonstration this is ok, but in your real-world application you would only provide one chart type and remove these drop downs.
    • NOTE: because the code is instantiated in the $(document).ready(function()  that means a partial refresh will NOT work
Full update onchange event
Full update onchange event
  • The onClientLoad event of the custom control contains all the JavaScript which makes this work

    onClientLoad event of the custom control
    onClientLoad event of the custom control
  • The JavaScript is shown below and performs two basic tasks
    • It determines the selected theme and calls a function in the jsFormFruit library which sets the theme
      • e.g. callGray()
    • It instantiates the Highchart and passes the chart type as a value derived from the XPage
    • htmlTableGraph(“#{id:viewPanel1}”, “#{javascript: getComponent(‘chartType’).getValue()}”)
      • “#{id:viewPanel1}” is the idTag for the viewPanel <—change this if your view panel is called something different
      •  “#{javascript: getComponent(‘chartType’).getValue()}” is the value chosen for chart type

$(document).ready(function() {

var sTheme=x$('#{id:theme1}').val() //get the value from the theme dropdown on the webpage
switch(sTheme)
    {
    case 'gray':
        callGray()
        break;
    case 'darkBlue':
        callDarkBlue()
        break;
    case 'grid':
        callGrid()
        break;
    default:
        ""
    }

htmlTableGraph("#{id:viewPanel1}", "#{javascript: getComponent('chartType').getValue()}")

})

jsFormFruit JavascriptLibrary

The callGray(), callDarkBlue and callGrid() functions are all very similar and while it might look like a lot, it is actually very readable and you can see how the color scheme is created. NOTE : this is all JavaScript and can therefore be changed to suit your own needs – no images!! This is a snippet and the whole code is available in the database in the script library


function callGray(){
	Highcharts.theme = {
			   colors: ["#DDDF0D", "#7798BF", "#55BF3B", "#DF5353", "#aaeeee", "#ff0066", "#eeaaee",
			      "#55BF3B", "#DF5353", "#7798BF", "#aaeeee"],
			   chart: {
			      backgroundColor: {
			         linearGradient: [0, 0, 0, 400],
			         stops: [
			            [0, 'rgb(96, 96, 96)'],
			            [1, 'rgb(16, 16, 16)']
			         ]
			      },
			      borderWidth: 0,
			      borderRadius: 15,
			      plotBackgroundColor: null,
			      plotShadow: false,
			      plotBorderWidth: 0
			   },
			   title: {
			      style: {
			         color: '#FFF',
			         font: '16px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
			      }
			   },
			   subtitle: {
			      style: {
			         color: '#DDD',
			         font: '12px Lucida Grande, Lucida Sans Unicode, Verdana, Arial, Helvetica, sans-serif'
			      }
			   },
			   xAxis: {
			      gridLineWidth: 0,
			      lineColor: '#999',
			      tickColor: '#999',
			      labels: {
			         style: {

			         etc etc etc.............
			         systematically going through each element and setting the style
			};

			// Apply the theme
			var highchartsOptions = Highcharts.setOptions(Highcharts.theme);
}

The htmlTableGraph() function

The htmlTableGraph is my modified version of the example given at the Highcharts website. I had to modify it because the viewPanel table created by XPages is not the same as the simple example given. Here’s the breakdown……


function htmlTableGraph(idTag, sType){

	/**
	 * Visualize an HTML table using Highcharts. The top (horizontal) header
	 * is used for series names, and the left (vertical) header is used
	 * for category names. This function is based on jQuery.
	 * @param {Object} table The reference to the HTML table to visualize
	 * @param {Object} options Highcharts options
	 */
	Highcharts.visualize = function(table, options) {
		// the categories
		options.xAxis.categories = [];
		$('tbody tr td:first-child', table).each( function(i) {
			options.xAxis.categories.push(this.lastChild.innerHTML);
		});

		// the data series
		options.series = [];
		$('tr', table).each( function(i) {
			var tr = this;
			$('th, td', tr).each( function(j) {
				if (j > 0) { // skip first column
					if (i == 0) { // get the name and init the series
						options.series[j - 1] = {
							name: this.lastChild.innerHTML,
							data: []
						};
					} else { // add values
						options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
					}
				}
			});
		});

		var chart = new Highcharts.Chart(options);
	}
            //idTag is the viewPanel1 id passed into the function
	var table = document.getElementById(idTag),
	options = {
		chart: {
			renderTo: 'container',
			type: sType
		},
		title: {
			text: 'Data extracted from a HTML table in the page'
		},
		xAxis: {
		},
		yAxis: {
			title: {
				text: 'Units'
			}
		},
		tooltip: {
			formatter: function() {
				return '<b>'+ this.series.name +'</b><br/>'+
					this.y +' '+ this.x.toLowerCase();
			}
		}
	};
	Highcharts.visualize(table, options);

}

The HTML created by the XPages server

The HTML generated by the XPage to display the viewPanel  looks like this where every table row TR has three table cells – inside each TD cell there is a span and inside that a value

<tbody>
<tr>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn1:_internalViewText">
        Bananas
    </span>
</td>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn2:_internalViewText">
        1.0
    </span>
</td>
<td>
    <span id="view:_id1:_id2:_id23:viewPanel1:0:viewColumn3:_internalViewText">2</span>
</td>
</tr>

How we parse the generated HTML in jQuery

The first thing I want to discuss is this part of the function

		options.xAxis.categories = [];
		$('tbody tr td:first-child', table).each( function(i) {
			options.xAxis.categories.push(this.lastChild.innerHTML);
		});

Breaking it down section by section

options.xAxis.categories = []; //sets up the array into which we will add the xAxis (the fruit)

We will work right to left to read what is going on

$('tbody tr td:first-child', table)
  • within the table (viewPanel1) element select everything which matches
    • the first td (td:first-child)
    • inside the tr
    • inside the tdbody
.each( function(i) {
  • because we can chain jQuery functions together we are cycling through each of the selected elements and for each element we are going to execute the function
options.xAxis.categories.push(this.lastChild.innerHTML);
  • this (the element we are acting on)
    • .lastChild (the last DOM element within the TD) – this bypasses the span within the TD
    • .innerHTML – the HTML within the element
  • options.xAxis.categories.push (add (push) the value into the options object on the xAxis.categories value)

Simply put this 4 lines of code cycles through the table, extracts the fruit values and adds them to an array for display on the xAxis (Apples, Oranges etc)

Parsing the table values

options.series = [];
$('tr', table).each( function(i) {
	var tr = this;
	$('th, td', tr).each( function(j) {
		if (j > 0) { // skip first column
			if (i == 0) { // get the name and init the series
				options.series[j - 1] = {
					name: this.lastChild.innerHTML,
						data: []
				};
			} else { // add values
				options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
			}
		}
	});
});
options.series = [];
  • Creates the array for drawing the chart values
$('tr', table).each( function(i) {
});
  •  For each TR within the table (viewPanel) provided cycle through each row
  •  i is the counter here as to which row we are on going down the table
	var tr = this;
	$('th, td', tr).each( function(j) {
	});
  •  for every th or td in each tr
  •  j is the counter here as we are going across the row
	if (j > 0) { // skip first column
		if (i == 0) { // get the name and init the series
			options.series[j - 1] = {
				name: this.lastChild.innerHTML,
					data: []
			};
		} else { // add values
			options.series[j - 1].data.push(parseFloat(this.lastChild.innerHTML));
		}
	}
  •  We ignore the first column (xAxis)
  •  if j > 0 (skiping the first column which is the xAxis (apples) values)
  •  if i = 0 (we are on the first row (the top one) and therefore we have the name Jane and John
  • add this (tr).lastChild.innerHTML (the HTML within the span) to the NAME value within the options.series array (NO DATA)
  • else (we are not on the top row) add the innerHTML value (converted to a number with parseFloat) to the options.series array

This section creates a string which looks like this – that is then parsed by the highchart.js

options = {series: [{
			name: Adam,
			data: {1, 2, 2, 6 }
		},
		{
			name: Jane,
			data: 2, 0, 4, 9 }
		]
	}

And finally, once we have created all the data arrays – display the highchart

	Highcharts.visualize(table, options);

Checking XPages Radio buttons have been selected with jQuery

So I found out the other day that an XPages Radio Button Group idTag is not resolved using the server side #{id:RadioButtonGroup}

Cert Next Year Needed Radio Button Group
Cert Next Year Needed Radio Button Group

Creates the following HTML on the webpage (in this example my RadioButtonGroup is called CertNextYearNeeded)

<label class="xspRadioButton" for="view:_id1:_id2:_id18:radio1">
<input id="view:_id1:_id2:_id18:radio1" type="radio" name="view:_id1:_id2:_id18:CertNextYearNeeded" value="No" />No</label
<label class="xspRadioButton" for="view:_id1:_id2:_id18:radio2">
<input id="view:_id1:_id2:_id18:radio2" type="radio" name="view:_id1:_id2:_id18:CertNextYearNeeded" value="Yes"/>Yes</label>

however using the # notation in my SSJS I got the following….(Using x$)


x$("#{id:CertNextYearNeeded}", ":checked").val()!="Yes"

came through into the webpage source code as


x$(":checked").val()!="Yes"

so therefore we need to select by name (which I don’t like as it could be ambiguous, but have no choice) you have to select the radio button group by name (don’t use x$). In this case we are testing to see if “Yes” has been selected – No or no selection at all will fail.

if ($("[name$=CertNextYearNeeded]:checked").val() != 'Yes') {
    msg="Select the option\n";
}
  • [name$=CertNextYearNeeded] <— Selects all elements with a name like *CertNextYearNeeded
  • :checked <—- get the checked
  • element .val() <— get the value

x$ reference examples

As I come across more and more variant for selectors I am going to list them here once I figure out how they can be constructed

function x$(idTag, param, jd){ //Updated 28 Feb 2012
idTag=idTag.replace(/:/gi, "\\:")+(param ? param : "");
return( jd=="d" ? "#"+idTag : $("#"+idTag));
}

Basic Selecting a field by id

 jQuery  x$(“#{id:divisionNo1}”).
 dojo  dojo.query(x$(“#{id:divisionNo1}”, “”, “d”)).

Note the “”, “d” needed to let the function know this is a dojo call and therefore only return a string and not the jQuery object

Selecting multiple fields by id

 jQuery  x$(“#{id:divisionNo1}, “+”##{id:companyName1}”).
 dojo  dojo.query(x$(“#{id:divisionNo1}, “+”##{id:companyName1}”, “”, “d”)).

Note there are two ## in the query because x$ only appends a # onto the first element returned

Selecting a field by id and then by style

 jQuery  x$(“#{id:divisionNo1}, ” .xspEditBoxClass”).
 dojo  dojo.query(x$(“#{id:divisionNo1}, “+”##{id:companyName1}”, ” .xspEditBoxClass”, “d”)).

Note the space ( ) in front of the classname

Selecting a field by attribute with wildcard (no x$)

 jQuery $(“[name$=RadioButtonGroup]:checked”).val()
 dojo

This is how you would determine if a Radio Button Group has been checked

if ($("[name$=RadioButtonGroup]:checked").val() != 'Yes'){
msg="Select the option\n";
}

Got my laptop back – Productivity tool time…

So I got my freshly imaged laptop back after having contracted a virus/trojan last weekend…..and I am in the unenviable process of re-installing everything I use. So i figured I would document them, as much for myself as anything else…..so here we go

Lotus Notes

Designer 8.5.3 (standard is only 8.5.2 client)

  • Change homepage to workspace (old school)

OpenNTF extension library

OpenNTF jQuery extension

OSGI console plugin for client

Teamstudio configurator

General Productivity Tools

Google Chrome (Which synced all my installed plugins, bookmarks and skin – SO happy)

  • Google Calendar
  • Goo.gl URL shortener
  • Google reader
  • WordPress
  • TweetDeck
  • IE Tab (if i MUST use IE it may as well have a nice wrapper)

Dropbox (Store all my personal stuff)

Logitech Gaming Keyboard drivers (keyboard freak)

7-Zip (Better than windows Zip as it will handle files >2G)

Notepad++ (notepad on steriods)

Snagit 11 (Screen capture)

StrokeIt (mouse gestured)

PDFCreator (PDF printer)

Web Development Tools

FireFox (DUH)

  • Firebug (If I have to explain this, you really need to go look)
  • HTTPFox (HTTP Traffic sniffer)

Things to install later (when I need them)

Skype (chat)

Wireshark (Packet sniffer)

I will update later if anything else occurs to me but that seems to do it for now

All installed and up and running again within 60 minutes

Run Domino server *then* Skype

I turned on my locally running Domino server this morning and got the following

03/07/2012 07:16:09 AM HTTP Server: Using Web Configuration View
03/07/2012 07:16:10 AM HTTP Server: Error – Unable to Bind port 443, port may be in use or user needs net_privaddr privilege
03/07/2012 07:16:11 AM HTTP Server: Shutdown

My initial reaction was extreme concern because I didn’t know what was running on port 443 and that I had a virus/trojan

Turns out that it was Skype – well there you go. I turned off Skype and the http task loaded just fine

Once the server was loaded and http was running, I then started Skype and there was no problem !

When should you use jQuery in your XPage?

For full disclosure, I used jQuery with Domino long before v8.5 at a time when the dojo documentation sucked big ones and it was nearly impossible to figure anything out. Today though that is much improved and the dojotoolkit website and the work done by sitepen have done a lot to catch up.

I am more familiar with jQuery syntax and the core library capabilities and I think I will always prefer to use jQuery than dojo given a choice and even playing field. In traditional Domino it is a level playing field as neither library is loaded by default. But that all changed with XPages and I am forcing myself to have to learn dojo because it just doesn’t make sense to use jQuery “just cos dojo sucks”.

jQuery does not conflict with dojo and can be used very successfully in tandem with each other. But there are some things to consider before you do.

jQuery selectors are IMHO easier to read and more intuitive to understand. jQuery uses a combination XPath/CSS query selection process and dojo uses a CSS3 selector paradigm

So why shouldn’t I use jQuery?

If you are going to add jQuery there has to be a good reason/purpose other than “‘cos I like jQuery and dojo sucks”. If you add a jQuery library you are:

  • adding additional overhead to the database
  • adding potential maintenance issues down the road
  • adding to the download size of every XPage which already has the dojo overhead by default.
    • (Yes you can turn dojo off but why would you? If you not going to use the XPage functionality don’t use an XPage design element……)

So if you are just doing a basic selector to get a page element or a basic animation, there is really nothing dojo can’t do any worse than jQuery. If you want to see a simple comparison between dojo selectors and jQuery selectors check this out

Dojo & jQuery side by side. Part 1: DOM Basics

Dojo & jQuery side by side. Part 2: Animation

So when should I use jQuery?

When you can’t do something you need to in dojo, or just just does not make sense to re-invent the wheel. jQuery is now more popular than Flash in terms of web usage for the most popular sites. dojo isn’t even on the map when it comes to web usage tracking. In terms of community size and usage jQuery dwarfs dojo everything else and because of that there is a lot of libraries to chose from.

In an XPages environment, the real benefit is not so much using jQuery itself, but in taking advantage of the thousands of plugins available which other people have written. There are plugins for everything from:

  • Menus
  • Calendars
  • Embedded video players
  • Photo galleries
  • Page Design libraries
  • Effect libraries
  • MVC Framework design libraries

I think I am going to start a series of weekly jQuery plugin examples (in XPages) to show what can be achieved very easily with the minimum of code. Let’s see how far it takes me before I run out of the over 4000 jQuery plugins and jQuery mobile