Binding jQuery code to an XPages partialRefresh using DOM Mutation events

Introduction

In this article I will demonstrate how to bind to the event which triggers on the completion of an XPages partialRefresh. Using that binding we will then be able to action to contents of the newly added partialRefresh DOM elements.

Background

In multiple articles I have discussed the use of the onComplete event of a programmatically triggered partialRefresh to be able to re-apply a jQuery plugin’s bindings to an area of an XPage. This works very nicely and integrates with the Dojo events controlling the xhr request to the Domino server.

A problem arises when you do not have a programmatically controlled partialRefresh, say for example in a pager. XPages uses the same technology to execute a partial refresh on a viewPanel – but you and I do not have programmatic access to the onComplete event without hijacking it.

This was brought back to my attention when reading Brad Balassaitis’ excellent article on adding font awesome to his data view. In that case he does not have an event available to him through the XPages designer so he has to hijack the Dojo calls. A practical solution given the tools available.

In general though I have always found using the XPage events a non-elegant way of controlling the page and there has to be a better way – I think upon reflection this is a nice learning experience and “good to know” article but not practical in production.

DOM Mutation events

These events have been around for a while but are now “deprecated” in favor of the new MutationObserver() constructor which is unfortunately not implemented in Internet Explorer until IE11

  • DOMAttrModified
  • DOMAttributeNameChanged
  • DOMCharacterDataModified
  • DOMElementNameChanged
  • DOMNodeInserted
  • DOMNodeInsertedIntoDocument
  • DOMNodeRemoved
  • DOMNodeRemovedFromDocument
  • DOMSubtreeModified

As the mozilla article states – “The practical reasons to avoid the mutation events are performance issues…...” – watching the DOM for changes every time a change happen has very processor intensive – believe me in my experiments if you latch onto DOMSubTreeModified and you are using jQuery which is constantly changing the DOM – you can easily drag your browser to its knees.

So in this article I am going to demonstrate how to use the “old” method for IE<11 and the preferred new method. You can then decide for yourself on the right way to do things – Dojo hijacking, degrading DOM performance or if you are lucky enough to not have to support IE – the way of the future 🙂

An example of the general problem

If I have a simple view panel on a page and I use some jQuery to stripe the rows it looks pretty…..(yes there are other ways to stripe the rows this is just to demonstrate the point).

jq1

But as soon as I hit the pager – the striping is lost. The DOM elements are removed and the new elements do not have the striping applied

jq2

The partialRefresh

As I am sure most of you know the partialRefresh as genius as it is, works by POST-ing the field values on the form back to the server where the JSF licecycle processes these POST-ed values and then returns a new set of HTML to the browser. That new HTML is inserted as a direct replacement of the DOM element which was being refreshed. Looking at the response from the server you can see below that when paging through a viewPanel the viewPanel1_OUTER_TABLE is re-downloded from the server and replaces the existing Table element in the DOM.

jw3

So my striped table is deleted from the DOM and replaced – ergo no more striping.

DOM Node insertion

Using the DOM Mutation event DomNodeInserted it is actually relatively easy to re-stripe the table.

I first surrounded the viewPanel with a div wrapper “viewPanelWrapper”. This is what I will use to listen to changes for. Because the whole outer table is replaced I cannot listen to events on it – it is removed along with my binding.

The first piece of code will demonstrate the event listener

$('.viewPanelWrapper').on("DOMNodeInserted", function(){
    console.log('a node was inserted')
})

When I run the above code snippet through firebug you will see that nothing changes (1). But when I click Next the partialRefresh is triggered and “a node was inserted”
jq5

If we then take this a step further we can add in our striping code again

$('.viewPanelWrapper').on("DOMNodeInserted", function(){
    console.log('a node was inserted')
    $('.viewPanel TR:even').css({background: '#FFCCCC'})
})

And that’s pretty much it – pretty simple really.

jq6

So then extending this simple example you can see how a jQuery plugin could be reapplied to any page after a partialRefresh has been triggered – JUST BE AWARE THAT THERE IS A PRICE TO PAY IN PERFORMANCE. If you are going to do this then make sure that you pick the smallest area to check possible and that it does not change every second – your browsers and more importantly users will not thank you. On and applying a jQuery plugin almost certainly also modifies your DOM – be careful not to create an endless loop of pluging in your plugin.

So the “better way”

This article explains the reasoning behind the new MutationObserver and more importantly why it makes more sense than what I just showed you.

DOM MutationObserver – reacting to DOM changes without killing browser performance.

Check out the “So what are these good for” section at the end – obviously they were talking about XPages 😉

Using a slightly modified version of their example we get this

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  var list = document.querySelector('.viewPanelWrapper');

  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {

        console.log(mutation.type);
        $('.viewPanel TR:even').css({background: '#FFCCCC'})
    });
  });

  observer.observe(list, {
  	attributes: true,
  	childList: true,
  	characterData: true
   });

jq7

Which works the same but as the article explains – WAY more efficient and also gives you the control to not screw up your plugins.

Remember though the caveat is modern browsers and that it is IE11 only

Conclusion

Overall this has been a fascinating learning experience for me. I can’t recommend using the DOMNodeInserted event listener because it definitely caused me pain and anguish in browser performance. The MutationObserver is a very interesting concept but I am not convinced I would use it in an application until I better understand it.

Advertisements

jQuery in XPages #18 Galleria (Easy to use Picture Carousel)

In this article I will describe how to implement and use the Galleria jQuery plugin to create a powerful picture carousel within your XPages application

Demonstration

The XPages integration of Galleria is demonstrated here

Download

The demonstration database can be downloaded from the link above or from here

Galleria

Introduction

“Galleria is a JavaScript image gallery framework that simplifies the process of creating beautiful image galleries for the web and mobile devices.”

I came across this carousel while I was researching my talk for IBMConnect 2013 and I was amazed by the simplicity, how powerful it was and how in depth and easy to understand the help documentation was. This article may be short and sweet because the plugin is that easy to implement!

Take a look at the example page http://galleria.io/

How does it work?

Looking at the documentation page there is a myriad of information on how to make the carousel you really want. The Beginner’s Guide is one of the best I have seen for any plugin. It is a step by step instruction on how to create the carousel in your web page including how to add jQuery.

We have to change that slightly to make the carousel work in our XPage – but only a little….

Download the plugin files from here http://galleria.io/download/

We add the jQuery library and the Galleria library file(s) to the database by adding them to the Web-Contents folder accessible via the package explorer.  (Window–>Show Eclipse Views–>Package Explorer) and drag and drop the two libraries from your computer into the “js” folder. We also add the themes and css files to the WebContent folder in the galleria folder.

gal1

We add the libraries to our XPages like this in the source panel

<script src="js/galleria-1.2.8.min.js"></script>

Using the information on the Beginner’s guide we also add the style

<style>
	#galleria{ width: 700px; height: 400px; background: #000 }
</style>

as well as the code to load the carousel once the page is loaded

Galleria.loadTheme('galleria/themes/classic/galleria.classic.min.js');
Galleria.configure({
   transition: 'fade',
   lightbox: true,
   imageCrop: true
});
Galleria.run('#galleria');

Once this is added to the page we just need to add some images…..In the beginners guide it staes that we have to just add some images into the galleria DIV

<div id="galleria">
    <img src="photo1.jpg">
    <img src="photo2.jpg">
    <img src="photo3.jpg">
</div>

but in our case we going to pull the pictures from notes documents in a view. In the same way as we did for the prettyphoto lightbox example we are going to add a view as a data source and use a repeat control to add the images to the page itself.

The data source

<xp:this.data>
	<xp:dominoDocument var="imageDoc" formName="imageHolder"></xp:dominoDocument>
	<xp:dominoView var="imagesView" viewName="images"></xp:dominoView>
</xp:this.data>

and the repeat control placing the images inside the galleria DIV

<div id="galleria">
	<xp:repeat id="repeat1" rows="30" value="#{imagesView}" var="imageRepeat">
		<xp:image id="Image1">
			<xp:this.url><![CDATA[#{javascript:"#{imageRepeat.imagePath}"}]]></xp:this.url>
		</xp:image>
	</xp:repeat>
</div>

And that is the absolute basic carousel (not that much different from the prettyphoto lightbox really at this point”

So what’s the difference with this one then?

Well it looks different, that is often a deciding factor when trying to impress your customer – which do they prefer the look of?

There are significantly more options to this carousel than the prettyphoto lightbox and this carousel has been optimized for mobile which the prettyPhoto has not (as far as I can tell). Let’s take a look at some of them…

Galleria comes with the following options:

  • Theming (allowing the developer to use pre-build settings to change the colors surrounding the carousel and the speed of the show)
  • Fullscreen capability
  • Responsive mobile view with swipe actions
  • An extensive API

In real words what does this mean? It means that you have almost absolute control over everything which happens within the slideshow or within the picture popups. Look at the optional themes as well. There are different themes you can buy which would serve you well if you were trying to implement this in a commercial site or if you just wanted to pump up an internal site.

In my example I have added a number of options to the carousel which give it some features. You should look seriously into the API to see what is possible.

Galleria.loadTheme('galleria/themes/classic/galleria.classic.min.js');
	Galleria.configure({
		transition: 'fade',
		lightbox: true,
		showCounter: true,
		showInfo: true,
		showImageNav: true,
		imagePan: true,
		imageCrop: true
	});
Galleria.run('#galleria');

Demonstration

Check out the demo(s)

The XPages integration of Galleria is demonstrated here

jQuery in XPages #13 – Peity – Small charts in a big world

In this article I will demonstrate how you can easily include small charts inside your XPages. As the saying goes, sometimes a picture can speak louder than a thousand words and in this case it really can. Using Peity you can easily insert small, yet effective, charts into your XPages

Do  you know what percentage of  the blog posts on this site are XPages related?

 

Over 80% of them.

Demonstration

The XPages integration of Peity is demonstrated here

Download

The demonstration database can be downloaded from the link above or from here

Peity

Introduction

from the website

Peity

Peity is less than 5k in size and yet really imposes itself as a big visual improvement to any site. It is HTML5 based which as normal precludes any none-canvas supporting browser. But it does work in Chrome, Firefox, IE9+, Opera, Safari.  With it you can make pie, bar, line or even custom charts by simply adding your data to a <span> element and calling the plugin.

Check out the original Peity demo site for the full information on the plugin.

Peity is one of those jQuery plugins which does not itself use jQuery – but to make it available to the masses it has been wrapped as a jQuery plugin.

Examples

The basic format for creating a Pity image could not be simpler

	<span>1/5</span>

 

	$("span.pie").peity("pie")

How does it work?

The jQuery and Peity JavaScript libraries are added to the database through the WebContents folder. Change the Designer perspective to show the Package Explorer (Window–>Show Eclipse Views–>Package Explorer) and drag and drop the two libraries from your computer into the “js” folder. (You can see the demo database as an example)

The js libraries are added to our XPage Source as follows

	<script src="js/jquery-1.7.1.min.js" clientSide="true"></script>
	<script src="js/jquery.peity.js" clientSide="true"></script>

The examples given on the plugin homepage show that the following options are available:

  • Chart Type with options
    • pie
      •  colours,diameter and delimeter
    • line
      • colourstrokeColourstrokeWidthdelimetermaxmin,width and height.
    • bar
      • colourdelimetermaxminwidth and height
    • custom

Size and color attributes

as an alternate to setting the colour and size using the function call you can add attributes to the chart

	<span data-colour="red" data-diameter="40">1/7</span>

Adding it to your XPage

In the example on the demo site I reused the highCharts fruit custom control to give me some data on the page. I haev added a chart to the page in two ways:

  • Using a DbLookup()
  • Using some jQuery to add the charts after loading
Integrating Peity charts into your XPage

The line chart is created by adding a computed field to the form. using the readonly=”true” parameter a SPAN is created by the XPage which is exactly what we need for the Peity chart.

The source code to create the line chart looks like this:

	<xp:inputText styleClass="line" id="inputText1" readonly="true">
		<xp:this.defaultValue><![CDATA[#{javascript:@DbColumn(@DbName(), "vwFruit", 2)}]]></xp:this.defaultValue>
	</xp:inputText>
	<script>
		$("[id$=inputText1]").peity("line")
	</script>

The Pie Charts are inserted into the viewPanel by using the following process:

  • Select all the table cells  in the 2nd column of the table (except for the first row)
  • Cycle through the values and total the column
  • Cycle through the table cells again and replace the Table contents with
    • The existing text and a SPAN (class .pie) containing the value / the total
  • Create the Peity pie charts for all matching elements (.pie)

And that looks like this in the code:

	var total=0
	var sTemp=""
	//get the total
	$("TABLE[id$=viewPanel1] TR:gt(0) td:nth-child(2)").each(function(i){
		total += parseInt($(this).text())
	})
	//replace the cell with the new contents
	$("TABLE[id$=viewPanel1] TR:gt(0) td:nth-child(2)").each(function(i){
		sTemp = $(this).text()+':    <span data-colour="red" data-diameter="20" class="pie">'+ $(this).text()+"/"+total+"</span>"
		$(this).html(sTemp)
	})
	//create all the Peity pie charts based on the .pie selector
	$(".pie").peity("pie", {
		colours: function() {
		    	return ["#dddddd", this.getAttribute("data-colour")]
		  	},
		diameter: function() {
		    return this.getAttribute("data-diameter")
		}
	  })

jQuery in XPages #7 – Pines Notify

In this article I will demonstrate how to implement a cool notification technique using Pines Notify.  This small (7k min) js library provides a wealth of flexibility and a feature set second to none. It can use multiple different CSS libraries (bootstrap, jQueryUI and others) so integration into your site is quick and simple.

Introduction

Pines Notify is a notification popup capability which is easily integrated into a website. Like most jQuery plugins there is a methods to instantiate the capability and the ability to pass in multiple parameters.  There are certainly other popup style plugins but this is easy to grasp and the examples are very good.

We are going to look at how to make some complex function popups like these…

Examples of Pines Notify popups
Examples of Pines Notify popups

Demonstration

There are two demonstration pages this week

The first demonstration is a basic port of the Pines Notify buttons from the original example into an XPage.

The second demonstration shows how the Pines Notify could be used in a real application

Download 

Click on the link to download the complete jQuery in XPages demonstration database (including Pines Notify).

Pines Notify

Pines Notify provides a basic shell for popup creation and the capability for multiple custom configurations. A “popup” by default is created on the top right of the screen and disappears after a fixed period of time. The the position, CSS, length of time shown, transparency, contents, callbacks and other features can be controlled through the use of parameters. There are too many to mention in one article but they can all be seen at the example website.

Sample Notification
Sample Notification

Adding Pines Notify to an XPage

The Pines Notify download contains the .js files (readable and minified) and a basic css file. These are easily added to our database as files in the WebContent folder.

Adding Pines Notify js and css fields to our database
Adding Pines Notify js and css fields to our database

Once we have added the js and css files to the database they can be added to our XPage as a resource(s)

	<xp:this.resources>
		<xp:script src="js/jquery.pnotify.min.js" clientSide="true"></xp:script>
		<xp:styleSheet href="css/jquery.pnotify.default.css"></xp:styleSheet>
	</xp:this.resources>

jQuery UI and jQuery

Pines Notify uses the jQuery library and jQuery UI CSS for display. These are added to the XPage as additional resources

	<xp:this.resources>
		<xp:script src="js/jquery-1.7.1.min.js" clientSide="true"></xp:script>
		<xp:styleSheet href="css/jquery.custom-theme/images/jquery-ui-1.8.18.custom.css"></xp:styleSheet>
	</xp:this.resources>

Using Pines Notify

Pines Notify has a basic format for activating. Here is a sample button from the website:

<button class="btn source" onclick="$.pnotify({
 	pnotify_title: 'Regular Notice',
 	pnotify_text: 'Check me out! I\'m a notice.'
});">Regular Notice</button>

In this format the button does not work correctly when added to an XPage as it causes a page refresh when clicked. To turn this into an functioning button we must use an <xp:button> like this one

<xp:button value="xPages Lower Timer" id="button1" styleClass="btn source">
<xp:eventHandler event="onclick" submit="false">
	<xp:this.script>
		<![CDATA[$.pnotify({
			pnotify_title: 'Regular Notice',
		 	pnotify_text: 'Check me out! I\'m a notice.'
		});]]>
	</xp:this.script>
</xp:eventHandler>
</xp:button>

The Pines Notify examples website gives us the code we need to create each button

Taking the sample code from the Pines Notify examples page
Taking the sample code from the Pines Notify examples page

And to convert this to our XPages button we just need to copy and paste this code and insert it into the <![CDATA[ code section above. Using this we can quickly and easily convert the examples into functioning XPages buttons.

Pinning Notifications

By default all Notifications have the ability to “pin” them to the screen. Should they contain information the user wishes to retain, they can do so

Pinning your notification
Pinning your notification

Closing Notifications

By default all notifications can be closed before they fade out using the X in the notification

Stacking notifications

Pines Notify notifications always stack on top of each other, so you never have to worry about position or overlaying issues, they will organize themselves nicely.

Showing all notifications

By default there is a bar added to the screen which allows user to see the last and/or all previous notifications.

Showing all previous notificaitons
Showing all previous notificaitons

Working this into XPages functionality

Javascript alert boxes have been used since the start of the web but they require a user click and an unnecessary interaction from the user if the point of the notification is just that – to notify the user of something.

In our XPages applications we could potentially notify the user after:

  • Successful REST update from the server
  • partialRefresh completion
  • form submission
  • Pager completion
  • General application workflow progress
  • Validation failure

really the possibilities are endless and really up to you the developer.

Examples

My demonstration site examples page has illustrated a number of buttons taken directly from the website and I have also added some notifications to the other jQuery in XPages examples (linked in through the menu).

On my second Demonstration page There are 4 simple examples of real application uses for Pines Notify

Dojo Toaster Widget

On the XPages server without the need for jQuery you can use the dojo toaster widget to provide a notification capability. You should take a look at Chris Toohey’s well written article on Mastering the Dojo Toaster for XPages to get a comparison.

Thanks

To Alan Hurt for pointing me in the direction of this plugin 🙂