Managing Presence

In this second segment of the Windows Live Messenger Library tutorial, you will modify the code from the previous example (Hosting the Sign-in Control) to display user information, such as current status, and the Messenger contact list. The sample also features a drop-down list for changing the signed in user's status. If the sign-in was successful the user's name and status are displayed, along with a contact list that includes each contact's status.

This sample demonstrates how to track changes to the user's presence by subscribing to the User.PropertyChanged event, and tracking changes to each contact's presence by subscribing to the Contact.PropertyChanged event for each contact respectively. The Windows Live Messenger Library raises these events each time a property changes. Because the application subscribes to these events, the respective event handlers are triggered whenever a property changes for the user or one of the user's contacts.

Note   In this section of the tutorial, you modify the file Default.htm. The other files (Channel.htm, Privacy.htm, and Default.css) do not change.

Overview

This sample carries over the Sign-in Control functionality of the previous sample (Hosting the Sign-in Control) and adds the following new functionality:

  • Obtaining properties from the User object and each Contact object associated with the User object.
  • Subscribing to the User.PropertyChanged event to track the status for the signed in user, and the Contact.PropertyChanged event to track the status for each user on the contact list.
  • Creating a drop-down list so that the signed in user can change status (Microsoft.Live.Messenger.PresenceStatus).

The following Windows Live Messenger Library classes and members are used:

  • Microsoft.Live.Messenger.UI.SignInControl
  • Microsoft.Live.Messenger.User
  • Microsoft.Live.Messenger.PresenceStatus

Modifying the Project Files

You will make the following changes:

Default.htm  - Add a <select> element to list the various PresenceStatus options and add code to display information about the currently signed in user and a contact list to show the status of each contact.

Default.htm

In this step, you will update Default.htm with some UI elements so that the user can change his or her status.

To Create Default.htm

  1. Using the IDE or text editor of your choice, open the version of Default.htm created in the previous step (Hosting the Sign-in Control) for editing.

  2. Replace the signInCompleted function with the following code. This updates the signInCompleted function to create delegates for event handlers that track changes in the user's presence (user_Presence_PropertyChanged). It also contains a function call to displayUserInfo(), which will be added in the next step along with the event handlers.

    function signInCompleted(sender, e)
    {
        if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success)
        {               
            _user.get_presence().add_propertyChanged(user_Presence_PropertyChanged);
            displayUserInfo();
    
            // Set event handlers to online and offline contacts collections.
            _user.get_onlineContacts().add_collectionChanged(onlineContacts_CollectionChanged);
            _user.get_offlineContacts().add_collectionChanged(offlineContacts_CollectionChanged);
        }
    }        
    
  3. Paste the following code immediately after signInCompleted. The first function is the event handler for tracking changes in the user's presence. The next function gets various properties from the User object and displays them.

    /* Called by the Windows Live Messenger Library when status changes of the user occur. */
    function user_Presence_PropertyChanged(sender, e)
    {
        displayUserInfo();
        if (_user.get_presence().get_status() === Microsoft.Live.Messenger.PresenceStatus.offline)
        {
            alert("Your presence has been set to offline.");
        }
    }
    
    /* Populate the user information string. */
    function displayUserInfo()
    {
        var userInfo = document.getElementById('userInfo');
        var userAddress = _user.get_address().get_address();
        var userDisplayName = _user.get_presence().get_displayName();
        var userPersonalMessage = _user.get_presence().get_personalMessage();
        var userStatus = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, _user.get_presence().get_status());
        var statusLine = document.createElement('p');
        removeChildrenFromNode('userInfo');
        if (userDisplayName)
        {
            statusLine.appendChild(Microsoft.Live.Messenger.MessengerUtility.emoticonEncode(userDisplayName));
            statusLine.appendChild(document.createTextNode(" (" + userAddress + "): " + userStatus));
        }
        else
        {
            statusLine.appendChild(document.createTextNode(userAddress + ": " + userStatus));
        }
        userInfo.appendChild(statusLine);
        document.getElementById('personalMessage').value = userPersonalMessage;
    }
    
  4. Paste the following code immediately after displayUserInfo. This code handles user changes to the selectStatus drop-down list.

    /* Called when the user changes the status drop-down list. */
    function selectStatusChanged() 
    {
        var selectStatus = document.getElementById('selectStatus');
        var presenceStatus = [ Microsoft.Live.Messenger.PresenceStatus.appearOffline,
    Microsoft.Live.Messenger.PresenceStatus.away,
    Microsoft.Live.Messenger.PresenceStatus.beRightBack,
    Microsoft.Live.Messenger.PresenceStatus.busy,
    Microsoft.Live.Messenger.PresenceStatus.idle,
    Microsoft.Live.Messenger.PresenceStatus.inACall,
    Microsoft.Live.Messenger.PresenceStatus.online,
    Microsoft.Live.Messenger.PresenceStatus.outToLunch ];
        if (_user.get_presence().get_status() !== Microsoft.Live.Messenger.PresenceStatus.offline)
        {
            _user.get_presence().set_status(presenceStatus[selectStatus.selectedIndex]);
        }
    }
    
  5. Paste the following code immediately after signInCompleted. These functions work together to display each contact, and apply an event handler that is triggered if the contact's status changes.

    /* Contact handlers */
    
    /* Refresh the online contact list for the current user. */
    function onlineContacts_CollectionChanged()
    {
        removeChildrenFromNode("divOnlineContacts");
        var onlineContactList = document.getElementById("divOnlineContacts");
    
        for (var i = 0; i < _user.get_onlineContacts().get_count(); i++)
        {
          var contactItem = createContactItem(_user.get_onlineContacts().get_item(i));
          onlineContactList.appendChild(contactItem);
        }
    }
    /* Refresh the offline contact list for the current user. */
    function offlineContacts_CollectionChanged()
    {
        removeChildrenFromNode("divOfflineContacts");
        var offlineContactList = document.getElementById("divOfflineContacts");
    
        for (var i = 0; i < _user.get_offlineContacts().get_count(); i++)
        {
          var contactItem = createContactItem(_user.get_offlineContacts().get_item(i));          
          offlineContactList.appendChild(contactItem);
        }
    } 
    
    function createContactItem(contact) 
    {
        /* Create the contact DOM elements. */
        var contactItem = document.createElement("div");
        contactItem.setAttribute("className", "ContactItem");
        var displayName = document.createElement("span");
        var status = document.createElement("span");
        var personalMessage = document.createElement("span");
        contactItem.appendChild(displayName);
        contactItem.appendChild(status);
        contactItem.appendChild(personalMessage);
       
        /* Display contact presence. */
        displayContent(contact.get_displayName(), displayName);
        displayStatus(contact.get_presence().get_status(), status);
    
        /* Add the contact presence update event handler. */
        addOnContactPresenceUpdated(
            contact,
            displayName,
            status,
            personalMessage);
         
        return contactItem; 
    } 
    
    function addOnContactPresenceUpdated(
        contact,
        displayNameElement,
        statusElement,
        personalMessageElement)
    {
        contact.add_propertyChanged(
            function(sender, e)
            {
                switch (e.get_propertyName())
                {
                    case "DisplayName":
                        displayContent(contact.get_displayName(),  displayNameElement);
                        break;
                }
            });
    
        contact.get_presence().add_propertyChanged(
            function(sender, e)
            {
                var presence = contact.get_presence();
    
                switch (e.get_propertyName())
                {
                    case "Status":
                        displayStatus(presence.get_status(), statusElement);
                        break;
                    case "PersonalMessage":
                        displayContent(presence.get_personalMessage(), personalMessageElement);
                        break;
                }
            });
    }
    
    function displayStatus(status, element)
    {
        switch (status)
        {
        case Microsoft.Live.Messenger.PresenceStatus.offline: 
            element.innerText = " (Offline) ";
            break;
        case Microsoft.Live.Messenger.PresenceStatus.away: 
            element.innerText = " (Away) ";
            break;
        case Microsoft.Live.Messenger.PresenceStatus.busy:
            element.innerText = " (Busy) ";
            break;
        default: 
            element.innerText = " (Online) "; 
            break;  
        }
    }
    
    function displayContent(content, element) 
    {
        replaceChild(element, Microsoft.Live.Messenger.MessengerUtility.emoticonEncode(content));
    }
    
    /* End contact handlers */
    
  6. Paste the following code after selectStatusChanged. This function updates the user's personal status message when btnSetPersonalMessage is clicked.

    /* Update the user's personal status message. */
    function setPersonalMessage() 
    {
        var personalMessage = document.getElementById('personalMessage');
        var messageText = personalMessage.value;
        messageText = messageText.replace(/</g, "").replace(/>/g, "");
        if (_user)
        {
            _user.get_presence().set_personalMessage(messageText);
        }
    }
    
  7. Paste the following code immediately before the closing script element. The removeChildrenFromNode function is a helper class that clears the child nodes from a DOM element.

    /* Clear all children from the specified node 
       (i.e. clear messages from the conversation window). */
    function removeChildrenFromNode(id)
    {
        var node = document.getElementById(id);
        if (!node)
        {
            return;
        }
    
        while (node.hasChildNodes())
        {
            node.removeChild(node.firstChild);
        }
    }
    
  8. Replace the HTML body with the following:

    <body onload="scriptMain()">
        <div id="msgr">
            <table>
                <tr>
                    <td style="height:150px">
                        <div id="signinframe">
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div id="userInfo">
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div id="setUserStatus">
                            <span><b>Change Your Status:</b></span>
                            <select id="selectStatus" onchange="selectStatusChanged()">
                                <option>Appear Offline</option>
                                <option>Away</option>
                                <option>Be Right Back</option>
                                <option>Busy</option>
                                <option>Idle</option>
                                <option>In a Call</option>
                                <option selected>Online</option>
                                <option>Out to Lunch</option>
                            </select>
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <div id="setPersonalMessage">
                            <span><b>Personal Message: </b></span>
                            <input id="personalMessage" type="text" />
                            <input onclick="setPersonalMessage()" id="btnSetPersonalMessage" type="button" value="Set" />
                        </div>
                    </td>
                </tr>
                <tr>
                    <td>
                        <b>Online:</b><br />
                        <div id="divOnlineContacts">
                        </div>
                        <br />
                        <b>Offline:</b><br />
                        <div id="divOfflineContacts">
                        </div>
                    </td>
                </tr>
            </table>
    
    
        </div>
    </body>
    

To Run the Sample

  1. Upload the project files to your Web server.

  2. Log in to Messenger client with the Windows Live ID account that you have designated as the receiver.

  3. Navigate to Default.htm on your Web site.

  4. In the sample application, log in with the Windows Live ID account that you have designated as the sender. If the sender is not a member of the receiver's contact list, the client will prompt you to add the sender to the list. Once the sender is added to the list you will be able to see interaction between the client and the Web application.

  5. When you change the status in the Web application it will be reflected in the client, and vice-versa.

Default.htm (completed)

The following code example shows the completed version of Default.htm.

<html xmlns="https://www.w3.org/1999/xhtml" >
<head>
<title>Windows Live Messenger Library</title>
<link rel="stylesheet" href="Default.css" type="text/css" />   
<script src="https://www.wlmessenger.net/api/2.5/messenger.js" type="text/javascript" 
    language="javascript"></script>
<script type="text/javascript" language="javascript">
function scriptMain() 
{
    var hostUrl = window.location.href;
    var index = hostUrl.lastIndexOf("/");
    hostUrl = hostUrl.substring(0, index);

    var privUrl = hostUrl + "/Privacy.htm";
    var chanUrl = hostUrl + "/Channel.htm";
    _signin = new Microsoft.Live.Messenger.UI.SignInControl('signinframe', privUrl, chanUrl, 'en-US');
    _signin.add_authenticationCompleted(authenticationCompleted);
}

function authenticationCompleted(sender, e) 
{
    _user = new Microsoft.Live.Messenger.User(e.get_identity());
    _user.add_signInCompleted(signInCompleted);
    _user.signIn(null);
}

function signInCompleted(sender, e)
{
    if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success)
    {               
        _user.get_presence().add_propertyChanged(user_Presence_PropertyChanged);
        displayUserInfo();
                
        // Set event handlers to online and offline contacts collections.
        _user.get_onlineContacts().add_collectionChanged(onlineContacts_CollectionChanged);
        _user.get_offlineContacts().add_collectionChanged(offlineContacts_CollectionChanged);
    }
}        

/* Contact handlers */
function onlineContacts_CollectionChanged()
{
    removeChildrenFromNode("divOnlineContacts");
    var onlineContactList = document.getElementById("divOnlineContacts");
            
    for (var i = 0; i < _user.get_onlineContacts().get_count(); i++)
    {
        var contactItem = createContactItem(_user.get_onlineContacts().get_item(i));
        onlineContactList.appendChild(contactItem);
    }
}
        
/* Refresh the offline contact list for the current user. */
function offlineContacts_CollectionChanged()
{
    removeChildrenFromNode("divOfflineContacts");
    var offlineContactList = document.getElementById("divOfflineContacts");
            
    for (var i = 0; i < _user.get_offlineContacts().get_count(); i++)
    {
        var contactItem = createContactItem(_user.get_offlineContacts().get_item(i));                
        offlineContactList.appendChild(contactItem);
    }
}        
        
function createContactItem(contact)
{
    /* Create the contact DOM elements. */
    var contactItem = document.createElement("div");
    contactItem.setAttribute("className", "ContactItem");
    var displayName = document.createElement("span");
    var status = document.createElement("span");
    var personalMessage = document.createElement("span");
    contactItem.appendChild(displayName);
    contactItem.appendChild(status);
    contactItem.appendChild(personalMessage);
        
    /* Display contact presence. */
    displayContent(contact.get_displayName(), displayName);
    displayStatus(contact.get_presence().get_status(), status);

    /* Add the contact presence update event handler. */
    addOnContactPresenceUpdated(
        contact,
        displayName,
        status,
        personalMessage);
                
    return contactItem;        
}     
        
function addOnContactPresenceUpdated(
    contact,
    displayNameElement,
    statusElement,
    personalMessageElement)
{
    contact.add_propertyChanged(
        function(sender, e)
        {
            switch (e.get_propertyName())
            {
                case "DisplayName":
                    displayContent(contact.get_displayName(),  displayNameElement);
                    break;
            }
        });
                
    contact.get_presence().add_propertyChanged(
        function(sender, e)
        {
            var presence = contact.get_presence();
                    
            switch (e.get_propertyName())
            {
                case "Status":
                    displayStatus(presence.get_status(), statusElement);
                    break;
                case "PersonalMessage":
                    displayContent(presence.get_personalMessage(), personalMessageElement);
                    break;
            }
        });
}

function displayStatus(status, element)
{
    switch (status)
    {
        case Microsoft.Live.Messenger.PresenceStatus.offline: 
            element.innerText = " (Offline) ";
            break;
        case Microsoft.Live.Messenger.PresenceStatus.away: 
            element.innerText = " (Away) ";
            break;
        case Microsoft.Live.Messenger.PresenceStatus.busy:
            element.innerText = " (Busy) ";
            break;
        default: 
            element.innerText = " (Online) "; 
            break;  
    }
}

function displayContent(content, element)
{
    replaceChild(element, Microsoft.Live.Messenger.MessengerUtility.emoticonEncode(content));
}
    
/* End contact handlers */       

/* Called by the Windows Live Messenger Library when status changes of the user occur. */
function user_Presence_PropertyChanged(sender, e)
{
    displayUserInfo();
    
    if (sender.get_status() == Microsoft.Live.Messenger.PresenceStatus.offline)
    {
        alert("Your presence has been set to offline.");
    }
}
        
/* Populate the user information string. */
function displayUserInfo()
{
    var userInfo = document.getElementById("userInfo");
    var userAddress = _user.get_address().get_address();
    var userDisplayName = _user.get_presence().get_displayName();
    var userPersonalMessage = _user.get_presence().get_personalMessage();
    var userStatus = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, _user.get_presence().get_status());
    var statusLine = document.createElement("p");
    removeChildrenFromNode("userInfo");
            
    if (userDisplayName)
    {
        statusLine.appendChild(Microsoft.Live.Messenger.MessengerUtility.emoticonEncode(userDisplayName));
        statusLine.appendChild(document.createTextNode(" (" + userAddress + "): " + userStatus));
    }
    else
    {
        statusLine.appendChild(document.createTextNode(userAddress + ": " + userStatus));
    }
    userInfo.appendChild(statusLine);
    document.getElementById("personalMessage").value = userPersonalMessage;
}        
        
/* Called when the user changes the status dropdown. */
function selectStatusChanged()
{
    var selectStatus = document.getElementById("selectStatus");
    var presenceStatus = [ Microsoft.Live.Messenger.PresenceStatus.appearOffline, Microsoft.Live.Messenger.PresenceStatus.away, Microsoft.Live.Messenger.PresenceStatus.beRightBack, Microsoft.Live.Messenger.PresenceStatus.busy, Microsoft.Live.Messenger.PresenceStatus.idle, Microsoft.Live.Messenger.PresenceStatus.inACall, Microsoft.Live.Messenger.PresenceStatus.online, Microsoft.Live.Messenger.PresenceStatus.outToLunch ];
    if (_user.get_presence().get_status() != Microsoft.Live.Messenger.PresenceStatus.offline)
    {
        _user.get_presence().set_status(presenceStatus[selectStatus.selectedIndex]);
    }
}
        
/* Update the user's personal message. */
function setPersonalMessage()
{
    var personalMessage = document.getElementById('personalMessage');
    var messageText = personalMessage.value;
    messageText = messageText.replace(/</g, "").replace(/>/g, "");
    if (_user)
    {
        _user.get_presence().set_personalMessage(messageText);
    }
}
              
function replaceChild(element, newChild)
{
    if (typeof(element) == "string")
    {
        element = document.getElementById(element);
    }
    
    while (element.hasChildNodes())
    {
        element.removeChild(element.firstChild);
    }
    
    element.appendChild(newChild);
}

/* Clear all children from the specified node 
   (e.g. clear messages from the conversation window). */
function removeChildrenFromNode(id)
{
    var node = document.getElementById(id);
    if (!node)
    {
        return;
    }
            
    while (node.hasChildNodes())
    {
        node.removeChild(node.firstChild);
    }
}

_user = null;
_signin = null;
</script>
</head>
<body onload="scriptMain()">
    <div id="msgr">
        <table>
            <tr>
                <td style="height:150px">
                    <div id="signinframe">
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <div id="userInfo">
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <div id="setUserStatus">
                        <span><b>Change Your Status:</b></span>
                        <select id="selectStatus" onchange="selectStatusChanged()">
                            <option>Appear Offline</option>
                            <option>Away</option>
                            <option>Be Right Back</option>
                            <option>Busy</option>
                            <option>Idle</option>
                            <option>In a Call</option>
                            <option selected>Online</option>
                            <option>Out to Lunch</option>
                        </select>
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <div id="setPersonalMessage">
                        <span><b>Personal Message: </b></span>
                        <input id="personalMessage" type="text" />
                        <input onclick="setPersonalMessage()" id="btnSetPersonalMessage" type="button" value="Set" />
                    </div>
                </td>
            </tr>
            <tr>
                <td>
                    <b>Online:</b><br />
                    <div id="divOnlineContacts">
                    </div>
                    <br />
                    <b>Offline:</b><br />
                    <div id="divOfflineContacts">
                    </div>
                </td>
            </tr>
        </table>


    </div>
</body>
</html>

See Also

Concepts

Hosting the Sign-in Control
Exchanging Messages

Other Resources

Windows Live Messenger Library Tutorial