Select2 v4 needs AMD fixing in Domino R9 XPages

As we have seen in the past AMD (Asynchronous Module Definition) in Dojo causes issues with jQuery plugins and other JavaScript libraries, in that it prevents them from loading correctly.

The select2 version4 – new release contains AMD checking code

https://github.com/select2/select2/blob/master/dist/js/select2.js

As you can see from the start

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}

So we have two choices – edit the select2.js code which you download and add it to your database – change the code to look like this

(function (factory) {
  if (typeof define === 'function' && false) { // removed define.amd and returned false
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node/CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}

Or we have to ensure the database properties are set to do resource aggregation and use the following code to insert jQuery and select2 into the header

<xp:this.resources>

  <xp:headTag tagName="script">
   <xp:this.attributes>
    <xp:parameter name="type" value="text/javascript" />
    <xp:parameter name="src" value="js/jquery-1.9.1.min.js" />
   </xp:this.attributes>
  </xp:headTag>

  <xp:headTag tagName="script">
   <xp:this.attributes>
    <xp:parameter name="type" value="text/javascript" />
    <xp:parameter name="src" value="select2.js" />
   </xp:this.attributes>
  </xp:headTag>
 </xp:this.resources>

Check out Sven’s other blog post on the subject – http://hasselba.ch/blog/?p=1181

Advertisements

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.

jQuery Promises – Taking action .when() multiple ajax calls are complete

jQuery.when() – “Provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events”

https://api.jquery.com/jQuery.when/

Wouldn’t it be nice to be able to know when two ajax calls are both complete – and then process the data returned from both, at the same time ?

Callbacks

Off the top of my head I would normally achieve this using a callback – and I have done so in some of my ExtJS in XPages articles. The following code snippet creates a callback that once the $.ajax call the url is complete take the data and pass it to the createGrid function. In there I could make another ajax call and then when that is complete I could process both data sets.

function getGridData(url, callback){

	var dataURL = url
	$.ajax({
		  url: dataURL+"&rand="+aRandomNumber()+"&"
		}).done(function ( data ) {
			//one the data is loaded then pass it to the callback function
			//passed in as one of the function arguments
			if(callback){
				callback(data)
			}
		});
}

var url = location.href
url = (url.indexOf('5Col')>-1) ? '5Col' : ""

url = 'xRestService.xsp/byFirstNameFlat'+url+'?count=100000'
var theData
var theCallBack = function(theData){
		createGrid(theData)
		}
getGridData(url, theCallBack)

This kinda makes an synchronous linear usage of asynchronous calls – do this then do that

As inelegant as that it, it works. The problems really start when you have 3, 4 or more callbacks and you get a callback hell of what if something fails in the middle and you have to run back up the tree looking for a fail – not pretty.

Using jQuery.when()

Modern browsers support the Promises concept which natively allows us to do the same thing but we know what that means and not the browsers we code for today.

.when() gives us the ability to pass as many ajax calls as we like, and then create one line of code which processes all the answers together.

Example

Here is a simple REST service feed from an XPages URL (fakenames data)

http://copper.xomino.com/xomino/extjs.nsf/xRestService.xsp/byFirstNameFlat?count=5

[
  {
      "@entryid":"1-AE3FB4C32057B87C85257C22000A83DD",
      "@unid":"AE3FB4C32057B87C85257C22000A83DD",
      "@noteid":"F5CA",
      "@position":"1",
      "@siblings":1304,
      "@form":"fUserName",
      "noteid":"NT0000F5CA",
      "firstname":"Alfred",
      "lastname":"Hall",
      "address":"2139 Jail Drivedd",
      "city":"Tremont",
      "state":"FL",
      "zip":615680,
      .........
  }
]

Which is nice ‘n all, but if we then wanted to know what State FL was (remember this is an example)

At the same time as pulling in the person you could also pull a list of US states

http://copper.xomino.com/xomino/extjs.nsf/states.json

{
    "AL": "Alabama",
    "AK": "Alaska",
    "AS": "American Samoa",
    "AZ": "Arizona",
    "AR": "Arkansas",
    "CA": "California",
    "CO": "Colorado",
    "CT": "Connecticut",
    "DE": "Delaware",
    "DC": "District Of Columbia",
    "FM": "Federated States Of Micronesia",
    "FL": "Florida",
    "GA": "Georgia",
    ......

From that we can then do a cross reference and display something useful.

The $.when returns each element as an Array of data so we have to get the zeroth value of each object returned to access it’s key/pairs

$.when(
    $.ajax({
        url: "xRestService.xsp/byFirstNameFlat?count=5",
        dataType: "json"
    }),
    $.ajax({
        url: "states.json",
        dataType: "json"
    })
).done(function( people, states ) {
    for (var i=0; i < people[0].length; i++){
        var person = people[0][i]
        var temp = ""
        temp=temp+person.firstname+" "
        temp=temp+person.lastname+" lives in "
        temp=temp+states[0][person.state]
        console.log(temp)
    }

});

As you can see from the screenshots below – the ajax calls can be executed in either order and still the result stands because the .done() function is not run until both are complete

d2

d1

d3

 

 

Conclusion

This is a very interesting capability which has apparently been around for ages and I wish I had known about it earlier (added jQuery v1.5)

 

jQuery in XPages #20 – NProgress – YouTube-like slim progress bar

In this article I will describe how to implement and use the jQuery NProgress nano scrollbar plugin

Demonstration

The XPages integration of NProgress is demonstrated here

Download

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

NProgress

Introduction

Since Youtube.com added their nano scroll bar at the top of the page there have been a flurry of different jQuery plugins which mimic the nano progress bar at the top of the screen.

np1

The silly thing is that the progress bar itself does nothing useful.

  • It does not
    • Indicate any meaningful progress on the download of the AJAX or page
    • Give any indication of the likelyhood of page download completion
  • It does
    • Give the user a false sense of something happening on the page
    • Provide a nice User Experience for very little overhead and effort on the part of the developer

Using NProgress you can very quickly and easily add this capability to your website for only a very small overhead to the size of your application.

Adding NProgress to your XPages

  • Go to the NProgress site and download the file from the github site linked on the page
  • Drag and drop the contents of the zip file into your WebContents folder
  • Create a sample page with the following
 <link href='nprogress/support/style.css' rel='stylesheet' />
  <link href='nprogress/nprogress.css' rel='stylesheet' />

<xp:this.resources>
	<xp:headTag tagName="script">
		<xp:this.attributes>
			<xp:parameter name="type" value="text/javascript" />
			<xp:parameter name="src" value="js/jquery.js" />
		</xp:this.attributes>
	</xp:headTag>
</xp:this.resources>

<xp:this.resources>
	<xp:headTag tagName="script">
		<xp:this.attributes>
			<xp:parameter name="type" value="text/javascript" />
			<xp:parameter name="src" value="nprogress/nprogress.js" />
		</xp:this.attributes>
	</xp:headTag>
</xp:this.resources>

The reason we add this to our XPage in the manner above is because nprogress uses AMD as a possible loader (to integrate with require.js) and because of that Dojo 1.8 (on an R9 server) breaks it.

On my demo page I have loaded a viewPanel with 1300 documents in it – I cannot show you more because I do not want a large database on my host’s site but rest assured if you run this up to a 5000 row viewPanel the effect is better because the refresh is slower.

np2

On the demo I have included the main example from the NProgress site and you can see that there are a number of methods for starting and manipulating the progress bar. I use start because it very nicely randomly increments itself to give that illusion of progress.

On the XPage I have a button which refreshes the view Panel – and in the client script as the button is pushed I start the NProgress. In the onComplete of the refresh I end NProgress and really it is as simple as that

<xp:button value="Reload  viewPanel" id="button1" styleClass="clickMe btn btn-warning">
	<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="viewwrapper"
		onComplete="NProgress.done()">
		<xp:this.script><![CDATA[
			NProgress.start()
		]]></xp:this.script>
	</xp:eventHandler>
</xp:button>

I would suggest that if you are able to integrate with Tony McGuckin’s excellent XSnippet for intercepting dojo io events you could create an automated NProgress bar should you so chose.

Conclusion

As web developers we have used spinners in our application for quite a number of years – this is a new twist on that concept and seems to be getting very good reviews from users. Consider integrating it into your applications.

jQuery in XPages #19 – Shadow (Add eye catching drop shadows to your page elements)

In this article I will describe how to implement and use the jQuery shadow plugin to create great looking shadowed panels within your XPages application.

Demonstration

The XPages integration of shadow is demonstrated here

Download

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

Shadow

Introduction

“Adapted from Nicholas Gallagher’s CSS drop shadows without images demo

Adding “depth” to the visual aspect of your website is one of those things which can make them “pop” (pun intended). Using the shadow plugin, one line of code can be the difference between “meh” and “wow”.

Browser support?

Here’s the nice bit IE9, Firefox 3.5 Chrome, Safari – which means it works in XPiNC as well, and that’s sweet!

shad4

How does it work?

The main driver behind this plugin is really Nicholas Gallagher’s CSS drop shadows without images demo. The plug author just wrapped it as a jQuery plugin to make his and everyone else’s life easier.

Using the plugin could not be easier. Using the normal jQuery selector you identify the design element(s) you want to add a shadow to and then determine which type of shadow to add.

We add the plugin to the WebContent folder within our database and reference it in our source code

<script src="jquery-shadow/jquery.shadow.js"></script>
<link rel="stylesheet" href="jquery-shadow/jquery.shadow.css" />

And then add the code to call the plugin updating the elements with the vpDemo class

   $('.vpDemo').shadow('raised')

Examples
The first example you can see on the website is just a simple view panel. You click the but to. And you can see the effect.

shad1

The second example is an xe:widgetContainer widget from the extension library – this has a dojo stylesheet already applied but the shadow works nicely

shad2

The final example allows you appling it to the xp:panel.

shad3

Other styles

There are other styles  available other than ‘raised’ check out the website demo examples to see the others but be aware that they do not all work in all browsers.

Conclusion

As with most of the plugins in this series – for next to no effort, you get a big payoff in user interface enhancements. In this case even more so because this is all CSS3 and no images necessary.

Just a note

Many people ask me how long it really takes to create the demos and get the functionality into the database.

Well figured this out at 3pm this afternoon, finished work (at 5pm), cooked dinner for the kids, went to a school PTA meeting, put the kids to bed, started writing the blog and finished the demo by 11pm – so not long really 🙂

Caveat from the author

These are his words on the git hub repo – heed them, or not 🙂

“The purpose of this is to make it easier, as you don’t need to remember the specific css class names.

However, this is extremely bad practice… and should not be used for a production site, but feel free to use it for prototyping…”

Webcast: jQuery The World’s Most Popular JavaScript Library Comes to XPages – now on YouTube

It was an absolute pleasure to do my jQuery in XPages presentation for the 3rd time (publicly) earlier this week and it was as part of the TLCC and Teamstudio webcast series highlighting some of the people and presentations from the community.

There were 430 people registered for the webcast and at its peak there were over 300 people watching.

As with each presentation, podcast and screencast I have had the privilege of being a part of, I am humbled by knowing that I am able to help other developers and users in the community.

For those people who missed the presentation it was recorded and posted for posterity on youtube

Thank you to everyone who attended and let me know what you want to find out about in the future.

Marky

Webinar – jQuery: The World’s Most Popular JavaScript Library Comes to XPages – April 23rd

I am very pleased to announce that as part of the TLCC 2013 XPages Webinar Series with Teamstudio I have been invited to give a webinar presentation of my IBM Connect 2013 presentation on jQuery. In this webinar I will be going through the slides and showing some demonstrations of how to use jQuery in XPages. There will also be a question and answer session at the end of the presentation for all those who are interested.

 

Tuesday,April 23rd – 10:30 A.M. to noon, Eastern U.S. time

Whether you want to add some serious eye candy to your XPages Applications or just want to do more with less code, jQuery, the world’s most popular JavaScript framework can help you. Come to this webinar and find out how you can use some of the thousands of jQuery plugins, in harmony with Dojo, within your XPages applications to create a better experience not only for your users, but for you as a developer. In this webinar, we’ll look at how jQuery works, how to add it to your XPages, and how a complete JavaScript beginner can take advantage of its power. We’ll demonstrate many working examples —  and a sample database will be provided.

 

For more information please look at the TLCC website link below and sign up

http://www.tlcc.com/admin/tlccsite.nsf/pages/xpages-webinar?opendocument