Thursday, March 24, 2011

IMNRC in UpdatePanel - Postback Issue Resolved

Issue Premise
When using IMNRC within an Ajax based UpdatePanel, the Communicator/Lync presence appears fine upon initial load. Once a post back occurs, the presence indicators render as offline images and the communication menu is not available. This is the exact issue discussed in the Microsoft forums here.

Scenario
I created a tabbed version of the Smart Part web part. This tabbed version renders various configurable tabs, and just like the Smart Part, loads the selected aspx user control. I use an UpdatePanel to load the controls and perform partial post backs when a different tab is selected.

One of the controls I created for use within this tabbed web part is a list of users based on certain filters or criteria. I generate the users using the presence image calling the IMNRC javascript function within the onload parameter. As described in the Issue Premise, upon initial rendering, the indicators function normally. When I click on a different tab and then come back to the list of users, all of the images go "offline" and there is no more drop-down menu available.

Root Cause
The root cause lies within the IMNRC function during a postback. The objects are not set properly for conditions to render the proper code. The orginal poster of the problem found that commenting out a condition in the IMNRC function allowed the presence to persist upon postbacks. I was able to reproduce his solution and it did work but I noticed that even though the indicators showed the users' status, I no longer had the communicator menu after a postback. So the loss of functionality as well as the editing of system javascript would not work for me.

Solution
My solution involved four steps:

1) Copying and tweaking the IMNRC function to handle postbacks
2) Renaming the IMNRC function to something else (e.g. CustomIMNRC)
3) Including the new function in my control markup or including in a referenced custom .js file
4) Modifying the onload parameter of the img tag to use the new function name.

The tweaking of the IMNRC function involves creating a new variable named postback and setting that to true:

var objSpan = obj;
var id = obj.id;
var fFirst = false;
var postback = true;


Next change the fFirst variable to postback in one of the lower if conditions:

if (postback && EnsureIMNControl() && IMNControlObj.PresenceEnabled) {
var state = 1, img;
state = IMNControlObj.GetStatus(name, id);

....
Finally add || postback to the last if (fFirst) condition: {this block of code allows the communicator menu to appear over the image when moused over}

if (fFirst || postback) {
var objRet = IMNGetOOUILocation(obj);
objSpan = objRet.objSpan;

...
The full function is show below: (use it in as script in your markup or include in a reference .js file)

function CustomIMNRC(name, elem) {
        if (name == null || name == '')
            return;
        if (browseris.ie5up && browseris.win32) {
            var obj = (elem) ? elem : window.event.srcElement;
            var objSpan = obj;
            var id = obj.id;
            var fFirst = false;
            var postback = true;
            if (!IMNDictionaryObj) {
                IMNDictionaryObj = new Object();
                IMNNameDictionaryObj = new Object();
                IMNSortableObj = new Object();
                IMNShowOfflineObj = new Object();
                if (!IMNOrigScrollFunc) {
                    IMNOrigScrollFunc = window.onscroll;
                    window.onscroll = IMNScroll;
                }
            }
            if (IMNDictionaryObj) {
                if (!IMNNameDictionaryObj[id]) {
                    IMNNameDictionaryObj[id] = name;
                    fFirst = true;
                }
                if (typeof (IMNDictionaryObj[id]) == "undefined") {
                    IMNDictionaryObj[id] = 1;
                }
                if (!IMNSortableObj[id] &&
    (typeof (obj.Sortable) != "undefined")) {
                    IMNSortableObj[id] = obj.Sortable;
                    if (!bIMNOnloadAttached) {
                        if (EnsureIMNControl() && IMNControlObj.PresenceEnabled)
                            window.attachEvent("onload", IMNSortTable);
                        bIMNOnloadAttached = true;
                    }
                }
                if (!IMNShowOfflineObj[id] &&
    (typeof (obj.ShowOfflinePawn) != "undefined")) {
                    IMNShowOfflineObj[id] = obj.ShowOfflinePawn;
                }
                if (postback && EnsureIMNControl() && IMNControlObj.PresenceEnabled) {
                    var state = 1, img;
                    state = IMNControlObj.GetStatus(name, id);
                    if (IMNIsOnlineState(state) || IMNSortableObj[id] ||
     IMNShowOfflineObj[id]) {
                        img = IMNGetStatusImage(state, IMNSortableObj[id] ||
           IMNShowOfflineObj[id]);
                        IMNUpdateImage(id, img);
                        IMNDictionaryObj[id] = state;
                    }
                }
            }
            if (fFirst || postback) {
                var objRet = IMNGetOOUILocation(obj);
                objSpan = objRet.objSpan;
                if (objSpan) {
                    objSpan.onmouseover = IMNShowOOUIMouse;
                    objSpan.onfocusin = IMNShowOOUIKyb;
                    objSpan.onmouseout = IMNHideOOUI;
                    objSpan.onfocusout = IMNHideOOUI;
                }
            }
        }
    }


If you found this useful, please help support my SharePoint and .NET user group (Philly SNUG) by clicking on the logo below.