Colin's profileColin Brown MSN MVPPhotosBlogListsMore ![]() | Help |
|
|
May 22 Windows Live Web Toolbar Mashup – MessyTwitTechnorati Tags: Windows Live, Windows Live Web Toolkit, Windows Live UI Controls, Mashup, jQuery, Personal Messages, Twitter A lot of people nowadays have Twitter accounts, a Facebook account etc. and if you’re reading this then I’m also assuming you have a Windows Live account and some interest in Windows Live Services. Each of these have their own “Personal Message” where you can tell people what you are currently doing and there-in lies the problem. You have to visit each of these places to update them individually. Why not have a central place where you can update them all? The good news is that you can. There are various ways of doing this, whether through a website or a Silverlight application. Basically anything that can use web services. With Microsoft’s recent introduction of the Windows Live Web Toolbar, I thought I’d do just that and show you how easy it is. I will be building upon my previous articles regarding the new Windows Live controls so please go check them out if you haven’t already as I’ve discussed a lot of the code present in this mashup in previous articles. So first up, lets take a look at our actual web page :- Here you can see that I’ve sectioned off the page. At the top of the page we will display the users Windows Live login picture along with their personal message that is tied to that account. Just below that will be the list of their contacts. This is an easy way to display the personal messages of their Windows Live contacts. The next section will be their Twitter account showing their own personal messages that they have sent to Twitter and at the bottom you will see the Windows Live Web Toolbar that we will use to sign people into their Windows Live accounts and hook in with the other Windows Live Web Controls that we display on the page. <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:msgr="http://messenger.live.com/2009/ui-tags"> <head runat="server"> <title>MessyTwit</title> <link type="text/css" rel="Stylesheet" href="MessyTwit.css" /> <script type="text/javascript" src="http://www.wlmessenger.net/api/3.0/loader.js"></script> <script type="text/javascript" src="JScript/JQuery.js"></script> <script type="text/javascript" src="JScript/Messenger.js"></script> <script type="text/javascript" src="JScript/Twit.js"></script> <script type="text/javascript"> Microsoft.Live.Core.Loader.load(['Messenger.UI', 'Messenger.UI.Styles.Core'], null); </script> </head> <body> <msgr:app privacy-url="Privacy.html" channel-url="Channel.htm" application-verifier-token="<%= appVerifier %>" token-url="RefreshMessengerToken.aspx" onauthenticated="onAuthenticated"></msgr:app> <form id="form1" runat="server"> <div id="msgrDisplayPic"> </div> <hr /> <div> <msgr:contact-list word-wheel-enabled="false"></msgr:contact-list> </div> <hr /> <%-- <div id="ctrls"> <msgr:personal-message cid='$user' id='persmsg' editable='true'></msgr:personal-message>
</div>
--%> <div id="msgs"> <div id="TwitCreds" class="msgHidden"> <span>Twitter Username </span> <input type="text" id="acct" /><br /> <span>Twitter Password </span> <input type="password" id="pwd" /><br /> <span id="TwitLogin">Login to Twitter</span> </div> </div> <hr /> <div id="persMsg" class="msgHidden"> <input type="text" id="msg" value="Enter a personal message" size="80" /> <span id="msgsend">Send</span> </div> <div> <msgr:bar sign-in-enabled="true"></msgr:bar> </div> </form> </body> </html> Above is the default.aspx page. As you can see, it’s not very complicated at all. Most of this was covered in my previous articles so I’ll just give a quick rundown here. At the top we include various Javascript files which we’ll cover later and we tell the page to load the messenger controls when the xhtml page has loaded. Next we have the messenger application section in which we supply various required variables such as where our privacy and channel pages are and we also set an event for when the user has authenticated (logged in to) their Windows Live Account. After that there is a placeholder for where we will put the users display picture and Windows Live personal message. Following the horizontal rule (I’ve only put that in the display physically break the page into sections) we have the Windows Live Contact List control. It’s as simple as that one line of markup to display a very nice list of the users contacts. The next section on the page is where we will gather the users’ Twitter credentials so that we can interact with their Twitter account. Towards the bottom we have a simple input box that the user will type their personal message in to and finally we display the Windows Live Web Toolbar at the bottom of the page. For completeness here is the code behind for the default.aspx page :- using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using WindowsLive;
using System.Diagnostics;
public partial class _Default : System.Web.UI.Page {
WindowsLiveLogin wll = new WindowsLiveLogin(true); public string appVerifier {
get
{
return wll.GetAppVerifier();
} } } I’ve covered this before so won’t go into it here. The corresponding style sheet associated with this page is very basic. Here is MessyTwit.css :- input#msg
{
border-width: 0px; } .msgHidden
{
display: none; } .msgShow
{
display: block; } We hide the border around the personal message input box and we define two classes to hide or show various elements of our page. There are two main Javascript files that cover all of the functionality on the page. The Messenger.js file I’ve basically covered before :- var userToken = null; var msgrUser = null; function onAuthenticated(e)
{
msgrUser = e.get_user(); msgrUser.add_signInCompleted(SignInCompleted); } function onUserConsentCompleted(e)
{
userToken = e.get_consentToken(); } function SignInCompleted(sender, e)
{
if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success)
{
if (typeof (InvokeOnUserSignIn) === 'function') {
InvokeOnUserSignIn(); } } else
{
OnUserSignedOut(); } var userAddress = msgrUser.get_address().get_address();
var usercid = msgrUser.get_identity().get_cid();
var signinframe = document.getElementById("msgrDisplayPic"); var tag = Microsoft.Live.Messenger.UI.Tags.TagsFactory.createTag('display-picture', { 'cid': usercid, 'presence-enabled': 'true', 'size': 'Large', 'logo-enabled': 'true' });
$("#msgrDisplayPic").append(tag);
var tag2 = Microsoft.Live.Messenger.UI.Tags.TagsFactory.createTag('personal-message', { 'cid': '$user', 'editable': 'false', 'id':'Persmsg2'}); $("#msgrDisplayPic").append(tag2);
$("div#TwitCreds").removeClass("msgHidden"); $("div#TwitCreds").addClass("msgShow"); } function OnUserSignedOut()
{
//add code for sign-out.
} As a quick overview we have the onAuthenticated event handler that we tied up in the messenger application block on the default.aspx page. As mentioned this gets fired when the user logs in to their Windows Live account. Once they login we capture that event and extract the user object then setup another event to capture when sign-in has been completed. The API fires off multiple events at differing stages of login. Another one of those events is when the user gives consent to send information back to our web site. In this event handler we simply capture the consent token that is sent. Once the user has completed sign-in we make sure that sign-in was successful (i.e. the correct username and password were supplied). Next we create the users display picture and also their personal message. These are two different Windows Live controls. The documentation for the Personal Message control says that it must have the CID of the user in order to display their personal message. This makes sense. However if you pass in the CID as we do for the display picture, the Personal Message control does not work. You HAVE to pass the $user string that is a reserved variable created by the Windows Live API. Next we simply use some jQuery to insert these controls onto our page. We also now use some jQuery to show the Twitter credentials portion of our web page which is hidden until after the user signs in to their Windows Live account. After the user has signed into their Windows Live account, this is what you will see. On this screenshot, my personal message is not displayed as I don’t have a personal message currently tied to this account however the control is present as you’ll see later. The second of the two main Javascript files, twit.js, contains the jQuery functions for manipulating the page. This is all new so I’ll break it down a bit :- $(document).ready ( function()
{
$('span#msgsend').click
( function()
{
var acct = $("input#acct").val(); var pwd = $("input#pwd").val(); var msg = $("input#msg").val(); So in the ready section we attach an event handler to the “send” text next to the personal message input. I just used text here but it could just have easily been a button.
When the text gets clicked we first get the username and password for the users Twitter account and we also get the personal message they want to send.
$.post("/MessyTwit/TwitterService.asmx/SendTweet",
{ 'account': acct, 'pass': pwd, 'msg': msg },
function(_xml)
{
$('div#msgs').text(''); $xml = $(_xml); $xml.find("status").each
( function()
{
$('div#msgs').append("<div><img src='" + $(this).find("profile_image_url").text() + "'/>" + "<span> " + $(this).find('text').text() + "</span></div>"); } ); } , 'xml');
To finish off this AJAX call we define an anonymous function that gets called once the call returns to our script. Here we first blank out any Twitter messages that may already be displayed on the screen. Then we take the XML that is returned by the AJAX call and parse it. We loop through the XML parsing each individual message. For each message we take the display picture of the user and also the text of the message and display it in the placeholder we marked out in our default.aspx page. The final part to this is just saying that the AJAX call will use XML rather than JSON or some other format. if (msgrUser)
{
msgrUser.get_presence().set_personalMessage(msg); } So we have posted the users personal message to their Twitter account, next we need to do the same for their Windows Live account. In the code above, this is exactly what we do. We first check to see that the user object isn’t null and if it’s not then we simply call the set_personalMessage method to update their Windows Live personal message. $('input#msg').val(''); } ); Finally for this event handler we do some cleanup. Here I’m blanking out the personal message input box ready for their next message.
$('input#msg').focus
( function()
{
$(this).val(''); } ); $('input#msg').blur
( function()
{
if (this.value == '') {
this.value = 'Enter your personal Message'; } } ); Here is the personal message input box before the user has clicked on it :- and after they have clicked on it :- The next two event handlers we define are tied to the personal message input box. All that this does is blank the input box when the user focuses on it (clicks or tabs into it). If the user clicks or tabs away from it and the input box is blank then we insert the message “Enter your personal Message” into it so the user knows where to type. $('span#TwitLogin').click
( function()
{
$('div#persMsg').removeClass('msgHidden'); $('div#persMsg').addClass('msgShow'); $('div#TwitCreds').removeClass('msgShow'); $('div#TwitCreds').addClass('msgHidden'); var acct = $("input#acct").val(); $.post("/MessyTwit/TwitterService.asmx/GetTweet",
{ 'account': acct },
function(_xml)
{
$xml = $(_xml); $xml.find("status").each
( function()
{
$('div#msgs').append("<div><img src='" + $(this).find("profile_image_url").text() + "'/>" + "<span> " + $(this).find('text').text() + "</span></div>"); } ); } , 'xml');
} ); } ); The final event handler is tied to the text I’ve displayed on the page for logging in to their Twitter account. Again, I’ve just used some text but it could just as well be a button control. When the user clicks on the login text we hide the twitter login credentials area and display the personal message input box. Next we get the users username and again make an AJAX call. This time only to retrieve the users’ own Twitter messages. Finally we use the same anonymous function as we had above to parse through the returned XML and extract the display picture and message from each message returned and display them onscreen. As soon as the user enters their Twitter credentials you should see the following :- Now you can take this code and expand on it so that when the user clicks on the login text you actually do a check against their Twitter credentials and display an error message if they are not correct. Twitter has lots of web service calls that you can use to make this code more robust. See the Twitter API for more details. This really only leaves one piece left, our web service :- using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.Net;
/// <summary> /// Summary description for TwitterService /// </summary> [WebService(Namespace = "blah")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class TwitterService : System.Web.Services.WebService { public TwitterService () {
//Uncomment the following line if using designed components
//InitializeComponent();
} [WebMethod]
public XmlDocument GetTweet(string account) {
string url = "http://www.twitter.com/statuses/user_timeline/" + account + ".xml?count=5"; HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url); Request.Method = "GET";
WebResponse Response = Request.GetResponse();
StreamReader Reader = new StreamReader(Response.GetResponseStream()); string Result = Reader.ReadToEnd();
Reader.Close(); XmlDocument doc = new XmlDocument(); doc.LoadXml(Result); return doc;
} [WebMethod]
public XmlDocument SendTweet(string account, string pass, string msg) {
string url = "http://www.twitter.com/statuses/update.json"; NetworkCredential creds = new NetworkCredential(account, pass); string EncodedText = "status=" + HttpUtility.UrlEncode(msg); HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(url); Request.Method = "POST";
Request.Credentials = creds; Request.ContentType = "application/x-www-form-urlencoded";
Request.ContentLength = EncodedText.Length; Request.UserAgent = "MessyTwit";
Request.Timeout = 10000; System.Net.ServicePointManager.Expect100Continue = false; Stream reqStream = Request.GetRequestStream();
StreamWriter Writer = new StreamWriter(reqStream); Writer.Write(EncodedText); Writer.Close(); WebResponse Response = Request.GetResponse();
StreamReader Reader = new StreamReader(Response.GetResponseStream()); string Results = Reader.ReadToEnd();
Reader.Close(); Response.Close(); reqStream.Close(); XmlDocument doc = GetTweet(account);
return doc;
} } This is a standard .Net web service except that we need to un-comment the line that reads :- [System.Web.Script.Services.ScriptService]
This is so that our Javascript can actually make calls to it. The first method that we have simply calls the Twitter web service and gets the top 5 messages the user has posted and returns that as XML back to our AJAX call. The second method is the one that actually posts the message to Twitter. After we have posted our message to using the Twitter API we make the call to the first method to retrieve the new updated top 5 messages. The main line to take note of in this method is :- System.Net.ServicePointManager.Expect100Continue = false; Without this line any posts to Twitter will fail with a 417 return code. This only applies to posts, not to gets. And there you have it. One web page that updates both a users’ Windows Live personal message and also their Twitter account as can be seen in the screenshot below. The Windows Live Personal-Message control now contains my latest message at the top of the page and also my latest Twitter entry has the same message :- This should give you an idea of the kind of mashups that you can do using the new Windows Live Messenger UI controls. I’ve expanded this example to include Facebook although I didn’t put the code here but it’s fairly easy to do and the above code will give you all the basics you need. You can expand it to include any other site that does some kind of personal message you wish. One final point should be noted. The Windows Live Web Toolbar includes it’s own area in which a user can type their personal message. When the personal message gets posted you can capture the event using the following :- // attach event for future changes
This also applies to the Personal Message UI control if you allow it to be edited. This way you can handle whether the user types their personal message into the Web Toolbar or using a control that you’ve specifically placed on the page. May 13 Windows Live UI ControlsTechnorati Tags: Windows Live, Windows Live Messenger UI, UI Controls, How to, display picture control Following on from my previous tutorial on how to integrate the Windows Live Web Bar into your site, we’ll build upon this and show you some of the other UI controls that you can use in your site. One thing that a lot of people might want to do is display the signed-on users’ display picture somewhere on the site other than in the web-bar. As with most everything Microsoft does in the web space there are a couple of ways of doing this. Lets start by doing it the easy way. Take the default.aspx page from the last tutorial and add a new <div> element under the <form> tag :- <form id="form1" runat="server"> <div id="msgrDisplayPic"></div> Into the div tag we will add the display picture UI control. This control has a few different options you can specify but only one is actually required, the cid of the user who’s image you wish to display. How do you get the cid of the signed-in user? Again there are a couple of ways of doing this but we’ll take the easy route again. For use with their tags on the aspx page, Microsoft has thoughtfully provided a variable that automatically gets populated with the users’ cid, $user. So the base tag that we need to enter into our div looks like this :- <msgr:display-picture cid='$user'></msgr:display-picture> When you run the page you’ll notice the default “blank” user image as nobody has signed in yet :- When a user signs in then this image will change to the users’ display picture as seen above. There are a couple of options that you can add to the control. You can adjust it’s size by supplying it with a size attribute. Size can take three pre-defined values, Small, Medium and Large. By default the control is set to Medium size. You can also tell it whether to enable or disable presence information (the “glow” around the border of the image). By default this is set to true so presence information is displayed. Finally you can also state whether a logo is displayed in the bottom right of the image or not by setting the logo-enabled attribute. The default is set to false. When set to true, a small logo is displayed :- So here is our final display-picture tag :- <msgr:display-picture cid='$user' presence-enabled='true' size='Large' logo-enabled='true'></msgr:display-picture> Microsoft also allow you to override their default style sheets for this control giving you a range of options :-
And that’s it, you can now add the users’ display picture to anywhere on your site with one tag. If you want more fine grained control over the process or you wish to do all this programmatically Microsoft also allows you to do this. First remove the <msgr:display-picture> tag from the default.aspx, but keep the <div> tag in place. Next create a Javascript file and add a reference to it at the top of the default.aspx :- <script type="text/javascript" src="JScript/Messenger.js"></script> In this Javascript file we will programmatically insert the users’ display picture control onto the site. I’ve added a couple of extra event handlers to this file that you don’t necessarily need but are very handy to have as well. First off we want to declare a couple of global variables, one to hold the users’ token that gets generated when they give their consent to sign-in to your site, and the second is to hold the actual user object :- var userToken = null; var msgrUser = null; Our first event handler gets fired once the user gives his permission to sign into your site :- function onUserConsentCompleted(e)
{
userToken = e.get_consentToken(); } All that we’re doing here is getting the consent token that gets generated and storing it in our global variable for use later. The next event handler gets fired once the user has authenticated (i.e. the windows live credentials are correct) :- function onAuthenticated(e)
{
msgrUser = e.get_user(); msgrUser.add_signInCompleted(SignInCompleted); } Here we capture the actual user object (the most important object you use when dealing programmatically with Windows Live Web Messenger) and store it in our global variable. Then we add an event handler for when the sign-in process has completed. function SignInCompleted(sender, e)
{
if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success)
{
if (typeof (InvokeOnUserSignIn) === 'function') {
InvokeOnUserSignIn(); } } else
{
OnUserSignedOut(); } var usercid = msgrUser.get_identity().get_cid();
var signinframe = document.getElementById("msgrDisplayPic"); var tag = Microsoft.Live.Messenger.UI.Tags.TagsFactory.createTag('display-picture', { 'cid': usercid, 'presence-enabled': 'true', 'size': 'Large', 'logo-enabled': 'true' });
signinframe.appendChild(tag); } The SignInCompleted handler first of all checks to see if authorization was correct (did the user really sign in or did they perhaps have a typo and sign-in wasn’t completed successfully). If sign-in was not correct then we make sure our page reflects that by calling our sign-out routine which should house any clean-up code. If the user has successfully signed in then we grab their cid. Remember, this is the one required field for the display-picture control (and most other controls as well). Next we get a reference to our <div> element where we want to place the display-picture control. All Windows Live Messenger UI Controls are instantiated through the TagFactory object. Here we simply call the method createTag and pass into it two values. The first is the type of control that we wish to create, in this case the display-picture control. The second value is a set of key:value pairs containing any attributes that we wish to supply. In the example code above we are simply re-creating the <msgr:display-picture> tag we created earlier on the page itself. The only difference here is that we are passing in the cid manually. Finally we simply add this control into the <div> tag we got a reference for earlier. The final entry in our Javascript file is the event handler for when the user signs out :- function OnUserSignedOut()
{
//add code for sign-out.
} And that’s it, you will end up with exactly the same screen as we did earlier, only this time you have gained knowledge in how to do it programmatically. The basics on what we have covered here applies to all the other Web Messnger UI controls. For example, if we wanted to add the contact-list control to our page we simply add the appropriate tag within our page or do it programmatically :- <msgr:contact-list word-wheel-enabled="false"></msgr:contact-list> And this results in the following :- There are a lot of UI controls to explore. You can find more information about what’s available, their methods and parameters etc. over on msdn :- http://msdn.microsoft.com/en-us/library/microsoft.live.messenger.ui.tags.aspx April 28 Windows Live Web Toolbar – How to integrate into your siteA few months ago at Mix 09, the Windows Live Team launched a number of exciting new additions under the Windows Live Web Toolkit. One of which was the Windows Live Web Toolbar. This toolbar allows you include presence information into your site as well as other social experiences. Unfortunately due to the limitations of Windows Live Spaces I cannot post the article on here. I’ve posted the article on Liveside.Net, so please hop over and see the article in full there. April 21 UI Controls for Web MessengerMicrosoft have now made your job even easier if you are developing your own Messenger application on your website. Not only have they produced an excellent API that I have written about before but they have now released a whole bunch of controls. If you head over to http://msdn.microsoft.com/en-us/library/dd570052.aspx you will find all the new controls listed by section. Examples of some of these controls are :- The Messenger Contact Picker control
The Messenger Display Name control
The Messenger Profile control
and of course the new Messenger Web Bar. There are lots more controls to be had. Go check them out and look here in the coming weeks on tutorials on how to use them in your own sites. March 20 Using Linq to amend a Word documentI got handed an interesting little problem as an emergency project yesterday. The basis of it was that I had to dynamically insert content into a word document (user name, email address, phone number, physical address etc.). This had to be done from a web site so I couldn’t just add some code to word and distribute the word document. So the basis of my solution was to get hold of the word document that needed to be amended and insert bookmarks where ever the data had to be inserted. Then split out the word document into it’s constituent parts (a docx file is really just a zip document). When you unzip a word document (by renaming the extension from docx to zip then unzipping with something like winzip) you end up with the following documents and folders :- What we’re really interested in however is what’s in the word folder :- In this folder you’ll find document.xml which is the file that actually contains all the text etc. for the word document. So what we want to do is create a little program that parses the document.xml file for all of our bookmarks, insert the appropriate content and save the new file out. It’s not as hard as what it seems. Here’s where Linq comes in very handy. Just copy the unzipped word document files into a folder under the website root :-
Here’s the code from my quick test program :- using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Xml;
using System.Xml.Linq;
/// <summary> /// Summary description for WordDocx /// </summary> public class WordDocx {
public WordDocx()
{
} public void AmmendDocx(string username) {
IEnumerable<XElement> bookmarks; //List<XElement> bookmarks = new List<XElement>();
XDocument doc = XDocument.Load("E:\\WordDocSite\\Docx\\word\\document.xml"); XNamespace namesp = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; bookmarks = doc.Descendants(namesp + "bookmarkStart");
int count = bookmarks.Count();
foreach (XElement el in bookmarks) {
string attr = el.Attribute(namesp + "name").Value; if (attr.ToLower() == "username") {
el.AddAfterSelf(new XElement(namesp + "r", new XElement(namesp + "t", "value"))); } } doc.Save("E:\\WordDocSite\\Docx\\word\\document2.xml");
} }
This isn’t the final code that I wrote, just a quick proof of concept for manipulating the content of the word document.
In the final code you simply do a select…case statement against the “w:name” attribute and have routines for adding the appropriate content. Once all of this is done you simply need to zip up all the files within the Docx folder. For this I used the NSoftware IP*Works Zip library (which is excellent and very easy to use. NSoftware has a whole range of tools to help you with things like this. I would recommend that you go check out what they have to offer). Once it’s zipped up, rename the extension back to docx and do a simple response.redirect to point to the file so that the end user can download it. December 03 Creating a Web Messenger control from Scratch – Part 11Technorati Tags: Web Messenger Control, Web Messenger, Windows Live, Windows Live Messenger, Programming, API In this the final installment of this series of tutorials for the moment we will be completing the Web Messenger control by adding the ability for users to actually hold conversations. We will also add some clean-up code, and generally tidy up some things that were left. So first off lets re-visit our signInCompleted routine. As you remember, when a user signs in, two events will get fired. The first being authentication completed then once the user has authenticated correctly, sign in completed will get called. We have already wired this event handler up but there are a couple of additions to make to it. Firstly we need to add a delegate for whenever a conversation property takes place. This happens for example if you’ve signed in and another user starts a conversation with you :- //Add delegate for when conversation changesmsgruser.get_conversations().add_propertyChanged(Delegate.create(null, conversation_collectionChanged));If you remember way back to the beginning of this series, the user class has a property :- This property retries the Conversation Collection for the user. The Conversation collection class has a number of events that you can tie into :-
The one we’re interested in is the PropertyChanged event. In the code snippet above, we simply get the Conversation Collection for the signed in user, then hook into the PropertyChanged event and point it to a function conversation_collectionChanged. The other change we’re making to the signInCompleted event handler is to create a TimeOut to call a function a little later. We are doing this due to the way that we initially create and display Contacts :- //Now we need to set a single timout so that we have time for the users//contacts to be enumerated through and the ContactsList array to be//created. Then we can assign the contact presence changed delegate//We'll set the timeout to 10 seconds.contactPresenceTimeout = setTimeout(ContactPresenceDelegate, 10000); The function that we call simply iterates through the our array of contact objects and sets an event handler up to call a function whenever a contact’s online presence changes :- function ContactPresenceDelegate(){if (ContactsList != null) { //Only clear the timeout if the contacts list has been built.clearTimeout(contactPresenceTimeout); var contactcount = ContactsList.getLength();for (var counter = 0; counter < contactcount; counter++) { var address = ContactsList[counter].get_Address(); //This will fire whenever a contacts online presence changes. address.get_presence().add_propertyChanged(Delegate.create(null, presence_PropertyChanged));} //We also want to close the groups hereToggleContacts(); } } First off we clear the Timeout so that it doesn’t fire again and at the end of the routine we simply collapse the Contacts list displayed on screen so that it look a bit tidier. /* Called by the Messenger Library when presence status changes occur (i.e. contacts sign in or out). */function presence_PropertyChanged(sender, e){displayContacts(); } The presence_PropertyChanged function that we hook into simply calls the displayContacts routines which will refresh all the contacts and their statuses.
function conversation_collectionChanged(sender, e){displayConversations(); } The conversation_collectionChanged routine simply calls displayConversations() function as shown above. function displayConversations(){ ConversationArray = new Array();var sb = new StringBuilder('<p><b>Active Conversations: (click a conversation to resume):</b></p>'); var item = 0; var enum1 = msgruser.get_conversations().getEnumerator(); while (enum1.moveNext()) { var conv = enum1.get_current(); ConversationArray.push(conv + ":" + item); if (conv.get_closed()) continue;sb.append(conversationLink(conv, item)); sb.append("<hr />");item++; } $get('divConversations').innerHTML = sb.toString();} The displayConversations simply adds a link to our open conversations box, one for each conversation that is currently ongoing as you can see below :- function conversationLink(conv, item){ var roster = conv.get_roster(); var enum1 = roster.getEnumerator();var names = new Array(); while (enum1.moveNext()) { var dispName = enum1.get_current().get_presence().get_displayName(); var dispEmail = enum1.get_current().get_address();if (dispName !== '') {names.push(dispName); } else {names.push(dispEmail); } } var sb = new StringBuilder(); sb.append('<a href=\"javascript:switchConv(' + item + ')\">'); if (conv == Conversations) sb.append('<b>'); sb.append(names.join(', ')); if (conv == Conversations) sb.append('</b>'); sb.append('</a>'); sb.append(' ');sb.append('<a href=\"javascript:closeConversation(' + item + ')\">'); sb.append('close</a>'); return sb.toString();} The displayConversations in turn calls the conversationLink function above to actually create the link. All we are doing here is creating a link so that the user can switch to that conversation and also creating a close link that will end that particular conversation. /* Close the current conversation. */function closeConversation(id){ var conv = msgruser.get_conversations().get_item(id);convArray.splice(id, 1); conv.close(); if (conv == Conversations) { removeChildrenFromNode('txtConv');} displayConversations(); if (msgruser.get_conversations().get_count() == 0)document.getElementById('btnSend').disabled = true; } The closeConversation function takes in the ID of the conversation to close (which is created whenever a conversation starts). We get the actual conversation through the Item(id) method of the Conversation Collection then close that item. If the conversation we are closing is the currently displayed conversation then we clear the conversation from the display area and disable the button to send a conversation item. We’re nearly there, only another few routines to go through. Whenever a user clicks on a Contact, the createConv function is called :- function createConv(index){ var newConv = msgruser.get_conversations().create(ContactsList[index].get_Address()); var convId = msgruser.get_conversations().get_count();switchConv(newConv.convId); } This routine simply creates a conversation object based on the users current address and an id. The id is simply the number of conversations that are currently open, plus 1. Since the Conversation Collection is zero based, when you get a count of current open conversations, it will always be the index + 1. function switchConv(id){ var conversation = msgruser.get_conversations().get_item(id); if (conversation) { if (Conversations) {Conversations.remove_messageReceived(ConversationSink); } ConversationSink = Delegate.create(null, receiveMessage);Conversations = conversation; Conversations.add_messageReceived(ConversationSink); removeChildrenFromNode('txtConv'); /* Display all messages from the conversation history. */ var hist = conversation.get_history(); var histEnum = hist.getEnumerator(); while (histEnum.moveNext()) {displayMsg(histEnum.get_current()); } document.getElementById('btnSend').disabled = false; } displayConversations(); document.getElementById('txtMessage').focus();} We then call the switchConv function passing in the conversation id as described above. This routine gets the Conversation object from the Conversation Collection, creates a delegate for if a message is received on that particular conversation object and displays all the messages that have been sent and received on this particular conversation thread. We also enable the Send button to allow the user to send a message on this Conversation thread. /* Called by the Messenger Library when a new message is received. */function receiveMessage(sender, e){ var message = e.get_message();displayMessage(message); document.getElementById('msgLastRecv').innerText = 'Last message at: ' + Conversations.get_history().get_lastReceived().toString(); } When we receive a message we simply display it. /* Send a message in the current conversation. */function sendMessage(){var txtMessage = $get('txtMessage'); var messageText = txtMessage.value;var message = new Microsoft.Live.Messenger.TextMessage(messageText, null); if (msgruser) { Conversations.sendMessage(message, null);} displayMessage(message); txtMessage.value = '';txtMessage.focus(); } Whenever the user clicks on the “Send” button to send a line of text in the conversation, the above routine gets called. This simply grabs the line of the text from the input textbox on the page, adds this line of text to the current conversation object and sends the line of text to the recipient. Then we clear the line of the text from the input box ready for the next message to be sent. That’s all there is to sending and receiving text messages to a users’ contacts. The reason for the brief description above is that I’ve actually covered this in more depth in a previous article that I have written which you can find on this site. The last thing we want to do is complete our signOutCompleted handler :- function signOutCompleted(sender, e){ //Fill in laterif (signincontroldisplayed == false) {ToggleSignIn() } Conversations = null; ContactsList = null; userInfo = null; //Blank the user interface. removeChildrenFromNode("divConversations"); removeChildrenFromNode("divContacts"); removeChildrenFromNode("searchResults");$get('divConversations').innerHTML = ""; $get('txtConv').innerHTML = ""; $get('btnSend').disabled = true; } Here we are just tidying things up. We show the sign-in Control and remove all conversations, user contact lists etc. from memory and also from the screen display. There you have it. A fully functional web messenger control. I will be entire code for the above control soon and will post where I have uploaded it to. There are numerous improvements we can make to this control, e.g. each conversation actually takes place in a popup window rather than having to switch conversation in a single control etc. and these are things that I will continue to do with this control but the main reason for not going into all that here is that it’s mainly cosmetic changes and I want to start getting into Live FX programming. I will be revisiting this code in the future however. If you’ve followed each article in this series then you should have the complete code already. The only thing that you will need to change is the following :- var privacyUrl = 'http://localhost:44444/WLWebMessenger/WebMessenger/Privacy.htm'; var channelUrl = 'http://localhost:44444/WLWebMessenger/WebMessenger/Channel.htm'; December 02 Creating a Web Messenger control from Scratch – Part 10Technorati Tags: Windows Live, Web Messenger, Windows Live Messenger, Programming, SDK, How To, Web Messenger Control So far in this series we have covered quite a bit of ground including customizing the sign-in control, groups, contacts, new features of the 2.5 API including user images etc. For this part we will do a simple search function. If you can remember, one of our original goals was to mimic the Messenger Client as closely as possible with the limitations that a browser based User Control will have. If you take a look at the messenger client you will see a search bar :- This search bar is used to both search the web and also as a quick search through your contacts list. We won’t bother with the internet search at the moment but will implement the quick contacts based search. We already have the basis for everything we need. It’s just a matter of adding some more code and another function to our existing MessengerContacts.js class. First off let’s add the code to our base file ascx to enable searching. Right under the “setPeronalMessage” section we will add the following :- <tr> <td> <div id="searchContacts"> <span><b>Search for Contact: </b></span> <input id="search" type="text" /> <input onclick="btnSearchClick();" id="btnSearch" type="image" src="WebMessenger/Images/SearchContact.gif" value="Search" /> </div> <div id="searchResults"> </div> </td> </tr> When you click on the search button we kick off simply invoke a simple Javascript function :- function btnSearchClick(){ removeChildrenFromNode("searchResults");var searchfor = $get("search").value; if (ContactsList != null) { var ContactsLength = ContactsList.getLength();for (var counter = 0; counter < ContactsLength; counter++) { var name = ContactsList[counter].get_ContactName();var regexp = new RegExp(searchfor); var res = regexp.exec(name);if (res != null) {ContactsList[counter].DisplaySearchContact(); } } } else { alert("You currently do not have any contacts to search”);} } First off we clear out the current search area using the removeChildrenFromNode function we already had, passing in the id of the search results DIV. Next we get the value that the user entered in the search text box. We already have a list of Contacts stored as an array in the variable ContactsList when we created all the contacts. So here we simply iterate through that array of contacts, get the Contact Name from each object and perform a simple regular expression search on the contact name to see if the characters that the user typed in the search box match. If they do then we call the DisplayContactSearch method of the corresponding MessengerContacts class to display the contact in the search results area. If no match then we continue through the loop. The only other thing we need is the new DisplayContactSearch method in our MessengerContacts class :- DisplaySearchContact: function(){if ($get("SearchContact" + this.ContactName) == null) { //Get base group DOM elementvar link = document.createElement("a"); link.href = "javascript:createConv('" + this.Index + "');"; link.className = "ContactLink";link.id = "SearchContactImgLink" + this.ContactName; var textlink = document.createElement("a"); textlink.href = "javascript:createConv('" + this.Index + "');"; textlink.className = "ContactLink";textlink.id = "SearchContactTextLink" + this.ContactName; var outerdiv = document.createElement("div"); outerdiv.id = "SearchContact" + this.ContactName; //Status and picture holdervar PicOutline = document.createElement("div"); PicOutline.id = "SearchContactStatus" + this.ContactName; PicOutline.className = "ContactImgOutline";var ContactPicHolder = document.createElement("div"); ContactPicHolder.id = "SearchContactImgHolder" + this.ContactName; ContactPicHolder.className = "ContactImgHolder"; //Create a span to place the name of the contactvar ContactNameHolder = document.createElement("div"); ContactNameHolder.id = "SearchContactNameHolder" + this.ContactName; ContactNameHolder.className = "ContactNameHolder";var name = document.createElement("span"); name.className = "ContactName";name.id = "SearchContactName" + this.ContactName; //create a horizontal rule to seperate contactvar hr = document.createElement("hr"); //Build the heirarchyContactPicHolder.appendChild(link); PicOutline.appendChild(ContactPicHolder); textlink.appendChild(name); ContactNameHolder.appendChild(PicOutline); ContactNameHolder.appendChild(textlink); outerdiv.appendChild(ContactNameHolder); outerdiv.appendChild(hr); this.DisplayContactImage(link) this.ChangeContactStatus(PicOutline); this.DisplayContactName(name); //get the groupDivvar grp = $get("searchResults"); //add the contact to the search resultsgrp.appendChild(outerdiv); } }, Now all of the above code should look very familiar to you as it’s basically just the DisplayContact method we talked about and implemented in the last part of this tutorial series. The only difference between the two are that all of the IDs have changed to include the word “Search” so that they are different from the normal Contacts list. e.g. :- link.id = "ContactImgLink" + this.ContactName; Now becomes :- link.id = "SearchContactImgLink" + this.ContactName; The only other difference is at the end of the code where we get the add the contact to. Instead of :- //get the groupDivvar grp = $get("group" + this.GroupName); We have changed this to :- //get the groupDivvar grp = $get("searchResults"); And we end up with the following :- There you have it. A quick Contact Search function just like in the Messenger Client. November 21 Creating a Web Messenger control from Scratch – Part 9After a little break due to a very heavy work schedule, we’re back with Part 9 of this mini-series explaining how to create a Web Messenger control that you can just drop into your web sites. It’s hard to believe that we’re currently on Part 9 of this series of tutorials. In the last part we discussed Groups within Web Messenger. Users can create their own groups and place contacts within these groups, e.g. Co-Workers, Friends, Family etc. Now that we’ve got groups, it’s now time to place the actual contacts within the appropriate group. What we will end up is something similar to the above. We will grab each contacts picture or assign a default one if the user does not have a custom image. Display their name and email address and create links so that you can start a conversation with them. I’ve split groups and contacts into two separate classes. As you may recall we call the groups function from within our signInCompleted event handler :- function signInCompleted(sender, e) { if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success) { msgruser.get_presence().add_propertyChanged(Delegate.create(null, user_Presence_PropertyChanged));var selectStatus = $get('selectStatus'); selectStatus.selectedIndex = 6; getMessengerLinks(); //Get the users IMAddressPresencedisplayUserInfo(); //Now that the user has signed in, get their contactsdisplayContactGroups(); } } Previously this function was displayContacts, I’ve now renamed it displayContactGroups just to separate it from Contacts. The function remains the same except for one addition. We now call the function to display contacts at the end. function displayContactGroups(){ var enumgroups = msgruser.get_groups().getEnumerator(); while (enumgroups.moveNext()) { var currentGroup = enumgroups.get_current(); var name = currentGroup.get_name();var group = new Messenger.Group(name, currentGroup); group.DisplayGroup(); //Show the users some progresscontactTimeout = setTimeout(displayContacts, 500); } } We do this by setting a Javascript timeout. The main reason for doing this is that it shows users some progress. It will display the groups onscreen whilst it comes back to create the contacts rather than processing everything at once and making the user wait until everything has completed. function displayContacts(){ //clear any timeouts.clearTimeout(contactTimeout); var enumgroups = msgruser.get_groups().getEnumerator();index = 0; while (enumgroups.moveNext()) { var currentGroup = enumgroups.get_current(); var name = currentGroup.get_name(); var enumContacts = currentGroup.get_contacts().getEnumerator(); while (enumContacts.moveNext()) { var currentContact = enumContacts.get_current(); //Need to pass in the contact and the group namevar contact = new Messenger.Contacts(currentContact, name, index); contact.DisplayContact(); index++; } } } The displayContacts function first clears any timeouts that may have been created (e.g. when calling from the displayContactGroups function). Next it gets a reference to each of the groups that the user has. Once we have that we iterate through each group and get the contacts for each of the groups. The Web Messenger Group class exposes two properties as shown above. We have already used the Name property in our own Group class.
The other property gets a collection of all the Contacts for that particular Group. We use both of these properties for our Contacts class. We need the Name property so that we can tell which contact belongs to which group and we obviously need the list of Contacts. As you can see from the code above, we iterate through the Contacts collection the same way that we iterate through the Groups collection. For each Contact in the Contacts collection we instantiate a new MessengerContact class. Then we call the Display method of this class to display the contact and repeat until all the contacts for that particular group have been processed, then we go onto the next group and repeat until all contacts have been displayed.
Our MessengerContact class defines a few key properties :- Type.registerNamespace("Messenger");Messenger.Contacts = function(contact, groupName, index){ this.Contact = contact; this.GroupName = groupName; this.Index = index; var _contactName = contact.get_displayName();if (_contactName.indexOf("@") > -1) {this.ContactName = _contactName.substr(0, _contactName.indexOf("@")); } else { this.ContactName = _contactName;} } We pass in the contact object itself, the name of the group that this contact belongs to and also an index (which will be used for conversations. This is simply an incremental number). Note that the groupName that is passed in we could have gotten from the Groups property that is exposed in the Contact object however if a contact is placed in multiple groups (which is allowed) then we want a separate instance of the contact for each group, hence why we pass in this value. The last chunk of code assigns the name of the Contact. We will use this later. Some Contacts do not have display names and instead their email address is substituted for their display name. If this is the case then we want their display name to be the first part of their email address (the bit before the “@”). Next we define our actual class prototype and start off with some simple getters and setters :- Messenger.Contacts.prototype = { get_ContactName: function() {return this.ContactName; }, set_ContactName: function(value) {if (value.indexOf("@") > -1) {this.ContactName = value.substr(0, value.indexOf("@")); } else { this.ContactName = value;} }, get_Index: function() {return this.Index; }, set_Index: function(value) { this.Index = value;}, get_GroupName: function() {return this.GroupName; }, set_GroupName: function(value) { this.GroupName = value;}, get_Contact: function() {return this.Contact; }, set_Contact: function(value) { this.Contact = value;}, Next we define our DisplayContact method, which gets called immediately after the class is instantiated :- DisplayContact: function(){if ($get("Contact" + this.ContactName) == null) { //Get base group DOM elementvar link = document.createElement("a"); link.href = "javascript:createConv('" + this.Index + "');"; link.className = "ContactLink";link.id = "ContactImgLink" + this.ContactName; var textlink = document.createElement("a"); textlink.href = "javascript:createConv('" + this.Index + "');"; textlink.className = "ContactLink";textlink.id = "ContactTextLink" + this.ContactName; var outerdiv = document.createElement("div"); outerdiv.id = "Contact" + this.ContactName; //Status and picture holdervar PicOutline = document.createElement("div"); PicOutline.id = "ContactStatus" + this.ContactName; PicOutline.className = "ContactImgOutline";var ContactPicHolder = document.createElement("div"); ContactPicHolder.id = "ContactImgHolder" + this.ContactName; ContactPicHolder.className = "ContactImgHolder"; //Create a span to place the name of the contactvar ContactNameHolder = document.createElement("div"); ContactNameHolder.id = "ContactNameHolder" + this.ContactName; ContactNameHolder.className = "ContactNameHolder";var name = document.createElement("span"); name.className = "ContactName";name.id = "ContactName" + this.ContactName; //create a horizontal rule to seperate contactvar hr = document.createElement("hr"); //Build the heirarchyContactPicHolder.appendChild(link); PicOutline.appendChild(ContactPicHolder); textlink.appendChild(name); ContactNameHolder.appendChild(PicOutline); ContactNameHolder.appendChild(textlink); outerdiv.appendChild(ContactNameHolder); outerdiv.appendChild(hr); this.DisplayContactImage(link) this.ChangeContactStatus(PicOutline); this.DisplayContactName(name); //get the groupDivvar grp = $get("group" + this.GroupName); //add the contact to the groupgrp.appendChild(outerdiv); } }, This may look complicated but in reality it’s not. Most of the code above simply defines a hierarchy of html elements for placement of the various elements of our contact. In particular we have the contact picture, the contact display name and email address and to be like the new Wave 3 client Messenger product we’re also introducing a presence halo. Both the Contact image and their name/email address will be hyperlinks so that we can start a conversation when the user clicks on that particular contact.
DisplayContactImage: function(ContactPicHolder){ this.RemoveChildrenFromNode(ContactPicHolder.id);var img = new Image(); img.onerror = function() { img.src = "WebMessenger/Images/MsgrNoImage.gif";} img.src = this.Contact.get_presence().get_displayPictureUrl(); //Now we need to scale the image down to 40 pixels width //and the appropriate height var scale = Math.round(img.width / 40); img.style.width = "40"; if (scale > 0) {img.style.height = Math.round(img.height / scale) } img.id = "ContactPic" + this.ContactName; img.className = "ContactImage";ContactPicHolder.appendChild(img); }, The DisplayContact method makes a call into DisplayContactImage. This routine simply gets the Contacts picture from the Presence object, which we’ve talked about before when we were display the Users own picture and presence. We also apply some very rough scaling to the image and then put it in place. ChangeContactStatus: function(StatusDiv){var stat = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, this.Contact.get_presence().get_status()) switch (stat) {case "online": StatusDiv.style.backgroundColor = "#00cc00"; break;case "offline": StatusDiv.style.backgroundColor = "#cc0000"; break; default: StatusDiv.style.backgroundColor = "#E3AC4F"; break;} }, The ChangeContactStatus method simply changes the color of the halo around our Contacts image to indicate whether they are busy (orange), offline (red) or online (green). The Contacts presence can be gathered from the Presence object and is actually an enum. Again we have covered this previously when we were talking about the actual user Object that we created. DisplayContactName: function(NameDiv){ this.RemoveChildrenFromNode(NameDiv); //Now we need to check if the name is actually a name //or an email address.var displayName = this.ContactName; if (this.ContactName.indexOf("@") == -1) { displayName += " ("; displayName += this.Contact.get_currentAddress().get_address(); displayName += ")";} NameDiv.innerHTML = displayName; }, The DisplayContactName function simply displays the contacts name and concatenates their email address onto the end of it. Therefore you end up with something like “Colin – abc@ba.com”. RemoveChildrenFromNode: function(id) { var node = document.getElementById(id);if (node == undefined || node == null) { return;} var len = node.childNodes.length; while (node.hasChildNodes()) {node.removeChild(node.firstChild); } }, dispose: function() { }} Messenger.Contacts.registerClass("Messenger.Contacts", null, Sys.IDisposable); if (typeof (Sys) !== "undefined") {Sys.Application.notifyScriptLoaded(); } The rest of the class is straightforward and code that we’ve used in other classes. The RemoveChildrenFromNode simply removes any inner content from a particular html element. The standard Dispose functionality and lastly we actually register the class with the Asp.Net Ajax ClientScript object which will be found in the hosting page or it’s master page. In our WebMessenger.ascx.cs code behind file for our Server Control page we need to register our Javascript object so that we can access it :- if (!sm.Scripts.Contains(new ScriptReference("WebMessenger/Script/MessengerContacts.js"))) {sm.Scripts.Add(new ScriptReference("WebMessenger/Script/MessengerContacts.js")); } As with other classes that we’ve defined, I’ve also included a stylesheet object so that end users can modify how things look and the layout without having to delve into any code. Therefore again in our code behind we need to register the CSS style sheet we have for the MessengerContacts class :- HtmlLink ContactSylteSheet = new HtmlLink(); ContactSylteSheet.Attributes.Add("href", "WebMessenger/Contact.css"); ContactSylteSheet.Attributes.Add("rel", "stylesheet"); ContactSylteSheet.Attributes.Add("type", "text/css"); header.Controls.Add(ContactSylteSheet); And here is the appropriate StyleSheet :- .ContactImage {border: 0px; text-decoration: none; border-width: 0px; } .ContactName{text-decoration: none; font-size: 0.9em; padding: 2px; text-align: center; } .ContactLink {border: 0px; border-width: 0px; text-decoration: none; } .ContactNameHolder{position: relative; text-decoration: none; } .ContactImgOutline{width: 44px; padding: 2px; } .ContactImgHolder{width: 40px; } October 22 Creating a Web Messenger control from Scratch – Part 8So far in this series we have learned about the Sign-In control, how to use it and the new features allowing you customize and hide it. We have also learned about the User class, how to implement that and also some of it’s new features such as the ability to display the user’s sign-in picture. The next step in our journey through the Web Messenger API and our Custom Control is contacts. After all there is little point in having a messenger control if you have nobody to talk to. In Windows Live Messenger, there is the ability to group your contacts. You can place each contact into a group so that referencing a contact becomes quicker and Messenger is easier to manage. So before we delve into Contacts themselves, we need to implement groups. A users personal list of groups obviously don’t become available until after they have signed in, therefore we will create a new function that retrieves and displays the list of the user’s groups. As you may have guessed, because there can be multiple groups, there are two classes that we are interested in. The Group Collection class which holds a collection of Group objects. The group collection class :-
There are a few interesting methods here that we can use but for now all that we’re interested in is the GetEnumerator method as we will use this to loop through the group collection. function displayContacts(){ var enumgroups = msgruser.get_groups().getEnumerator();// var groupindex = 0;// index = 0; while (enumgroups.moveNext()) { var currentGroup = enumgroups.get_current(); var name = currentGroup.get_name();var group = new Messenger.Group(name); group.DisplayGroup(); // groupindex++;} } Above is our displayContacts function that we will be expanding on over the next couple of tutorials. For now it is fairly simple and straightforward. The first thing we do is to call the GetEnumerator method of the groups collection returned from the User class. Next we simply loop through this collection and instantiate a new custom Messenger.Group object, one for every group in the list. As a constructor for this object you pass in the group name which is a property of the Group class (not the group collection class) :-
The group class that I’ve created is just a standard Asp.Net Ajax class that will also get expanded upon later, but nicely encapsulates what we need to do for a group (over the past week I’ve been cleaning up some of the code we have already talked about and moving it to classes however there is no real need to do so). Type.registerNamespace("Messenger");Messenger.Group = function(GroupName){ this.GroupName = GroupName;this.ShowGroup = false; } Here we create the Group class and put it in the Messenger namespace that we’ve been using so far. As you can see, the constructor for this class expects a Group Name as input. We also define a variable to hold whether the group is expanded or collapsed (which we’ll use in a minute). Messenger.Group.prototype = { get_GroupName: function() {return this.GroupName; }, set_GroupName: function(value) { this.GroupName = value;}, get_ShowGroup: function() {return this.ShowGroup; }, Above we are defining the methods, properties, events etc. that our class will hold. We create a read/write property for the GroupName variable and also a read only property for the ShowGroup variable. DisplayGroup: function(){if ($get("Group" + this.GroupName) == null) { //Get base group DOM elementvar contacts = $get("divContacts"); var outerdiv = document.createElement("div"); //create a link for the contactvar link = document.createElement("a"); //Add an event handler for when this gets clicked$addHandler(link, "click", this.ToggleGroup); link.className = "GroupLink";var img = new Image(); img.src = "WebMessenger/Images/minus_icon.gif";img.id = "GroupExpand" + this.GroupName; img.className = "GroupImage"; //Create a span to place the name of the groupvar name = document.createElement("span"); name.innerHTML = " " + this.GroupName; name.className = "GroupText"; //create a horizontal rule to seperate groupsvar hr = document.createElement("hr"); //Finally create another Div that all the contacts will list undervar innerdiv = document.createElement("div"); innerdiv.id = "Group" + this.GroupName; //Build the heirarchylink.appendChild(img); outerdiv.appendChild(link); outerdiv.appendChild(name); outerdiv.appendChild(hr); outerdiv.appendChild(innerdiv); contacts.appendChild(outerdiv); } }, Our DisplayGroup method first checks to see whether this group is already displayed in our control, if it’s not then we need to display it. There are a number of ways that we could do this, one way that I’ve used in the past is simply to code the html into a string and use the innerHTML property of an element to display the html. This time however I’ve opted to actually create the elements through the DOM and assign classes to them so that it’s very easy to change things positioning, colors etc. through the stylesheet alone. It’s also a slightly cleaner approach. So here we are just creating a couple of DIV elements to hold our group and ultimately our list of contacts in, a graphic so that you can expand or hide that particular groups entries, and display the name of the group itself. The handler calls an internal routine that expands or contracts the list of contacts based upon whether it is currently expanded or collapsed. A toggle function. Then we simply add these elements to the divContacts element that is part of base ascx page.
ToggleGroup: function(eventElement){ var elmid = eventElement.target.id; var groupimg = $get(elmid); //get the group name so as to hide the innerdiv which //contains all the actual contacts var groupname = elmid.substr(11);var innerdiv = $get("Group" + groupname); if (this.ShowGroup == true) { groupimg.src = "WebMessenger/Images/minus_icon.gif"; innerdiv.style.display = "none";this.ShowGroup = false; } else { groupimg.src = "WebMessenger/Images/plus_icon.gif"; innerdiv.style.display = "block";this.ShowGroup = true; } }, The ToggleGroup handler as mentioned uses the ShowGroup variable that we defined to determine whether this contact group is currently expanded or collapsed and expands the group if it is currently collapsed, or collapses it if it is currently expanded. We also change the image to reflect this behavior. RemoveChildrenFromNode: function(id) { var node = document.getElementById(id);if (node == undefined || node == null) { return;} var len = node.childNodes.length; while (node.hasChildNodes()) {node.removeChild(node.firstChild); } }, dispose: function() { }} Messenger.Group.registerClass("Messenger.Group", null, Sys.IDisposable); if (typeof (Sys) !== "undefined") {Sys.Application.notifyScriptLoaded(); } The RemoveChildrenFromNode function I’ve covered previously. It’s the exact same and simply clears out an element of all it’s children. The rest is fairly standard Asp.Net Ajax code for registering the class. So where do we call all of this from? As mentioned, the Group Collection and Group classes for a user are available after a user sign in. We already have a handler in our code that gets called upon from the Sign In Control when sign in completes so we simply place a call to our displayContacts function in there :- function signInCompleted(sender, e) { if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success) { msgruser.get_presence().add_propertyChanged(Delegate.create(null, user_Presence_PropertyChanged));var selectStatus = $get('selectStatus'); selectStatus.selectedIndex = 6; getMessengerLinks(); //Get the users IMAddressPresencedisplayUserInfo(); //Now that the user has signed in, get their contactsdisplayContacts(); } } Finally, since we have a new class (and a new stylesheet) we need to register these with the hosting page. So in our code behind for the ascx page, we add these as we did previously with our other classes and style sheets, in the Page_Load event :- protected void Page_Load(object sender, EventArgs e) {HtmlHead header = (HtmlHead)this.Page.Header; HtmlLink stylesheet = new HtmlLink(); stylesheet.Attributes.Add("href", "WebMessenger/Default.css"); stylesheet.Attributes.Add("rel", "stylesheet"); stylesheet.Attributes.Add("type", "text/css"); header.Controls.Add(stylesheet); HtmlLink UserInfoSylteSheet = new HtmlLink(); UserInfoSylteSheet.Attributes.Add("href", "WebMessenger/UserInfo.css"); UserInfoSylteSheet.Attributes.Add("rel", "stylesheet"); UserInfoSylteSheet.Attributes.Add("type", "text/css"); header.Controls.Add(UserInfoSylteSheet); HtmlLink GroupSylteSheet = new HtmlLink(); GroupSylteSheet.Attributes.Add("href", "WebMessenger/Group.css"); GroupSylteSheet.Attributes.Add("rel", "stylesheet"); GroupSylteSheet.Attributes.Add("type", "text/css"); header.Controls.Add(GroupSylteSheet); //Add our script classes to scriptmanagerScriptManager sm = ScriptManager.GetCurrent(Page); if (!sm.Scripts.Contains(new ScriptReference("WebMessenger/Script/MessengerUI.js"))) {sm.Scripts.Add(new ScriptReference("WebMessenger/Script/MessengerUI.js")); } if (!sm.Scripts.Contains(new ScriptReference("WebMessenger/Script/MessengerUserInfo.js"))) {sm.Scripts.Add(new ScriptReference("WebMessenger/Script/MessengerUserInfo.js")); } if (!sm.Scripts.Contains(new ScriptReference("WebMessenger/Script/MessengerGroups.js"))) {sm.Scripts.Add(new ScriptReference("WebMessenger/Script/MessengerGroups.js")); } sm.LoadScriptsBeforeUI = true; //Add the messenger library to our pageif (!Page.ClientScript.IsClientScriptIncludeRegistered("messengerlib")) {Page.ClientScript.RegisterClientScriptInclude("messengerlib", "http://settings.messenger.live.com/api/2.5/messenger.js"); } //For the moment add our messenger functions as a standard Javascript fileif (!Page.ClientScript.IsClientScriptIncludeRegistered("messengerfns")) {Page.ClientScript.RegisterClientScriptInclude("messengerfns", "WebMessenger/Script/MessengerFns.js"); } //Add some startup scriptif (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), "Load")) {string str = "var msgrui; function pageLoad(sender, args)"; str += "{msgrui = new Messenger.UI(); startMessenger(msgrui.get_SignInBackColor(), msgrui.get_SignInLinkColor());}";ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "Load", str, true); } } After running the code what we end up with is a list of groups at the bottom of our control :- In the next part of this series we will continue with the functionality of groups and adding contacts to our Custom Control Technorati Tags: Web Messenger, Windows Live, Windows Live Web Messenger, Programming, Custom Control October 07 Creating a Web Messenger control from Scratch – Part 7Technorati Tags: Windows Live, Messenger, Windows Live Messenger, API, Messenger API, Programming, How to CorrectionsBefore moving onto the next part of the Web Messenger User Control, I was running through the code I have developed so far and happened upon a couple of bugs, so this part of the Web Messenger User Control tutorial will be a short one fixing the bugs in the code we have so far. On fixing these bugs the User Control works as expected and you end up with something akin to the following :- Both of the bugs appear in the displayUserInfo() function, and following onto that there have been changes made to the getSignInCode() function as well. The first bug is to do with displaying the user’s stored picture. In my original code, I retrieved the Image by using the get_displayPictureUrl() property of the Presence class. Then I checked for a valid file extension using the following code :- var userPicLast3 = userPicture.substr(userPicture.length - 3); var pic = new Image(); if (userPicLast3 !== "jpg" && userPicLast3 !== "gif" && userPicLast3 !== "png") { pic.src = "WebMessenger/Images/MsgrNoImage.gif"; } else { pic.src = userPicture; pic.onerror = function() { pic.src = "WebMessenger/Images/MsgrNoImage.gif"; } } This code is incorrect as the DisplayPictureUrl() property will never return a file extension, therefore when running the code you would always end up with the default image and never get the user’s actual display image. This code should be removed and replaced with :- var userPicture = msgruser.get_presence().get_displayPictureUrl();var img = new Image(); img.onerror = function(){ img.src = "WebMessenger/Images/MsgrNoImage.gif";} img.src = userPicture; //Now we need to scale the image down to 40 pixels width//and the appropriate heightvar scale = Math.round(img.width / 40);img.style.width = "40";img.style.height = Math.round(img.height / scale) Here we again use the DisplayPictureUrl() property however we assign this directly to a new Image() object which will render correctly. Just in case it doesn’t we put an onerror condition in to point to our default image. Reasons for it not rendering correctly can be things like the user hasn’t actually assigned themselves an image and therefore the property call returns null, the user has a specialized animated for messenger (like I do for one of my accounts) etc. Since we now have an actual image object and are not just creating an <img> html tag, we need to change certain things in our getSignInCode() function. We no longer pass in the img.src attribute as we did before and instead just assign a placeholder in which we will put the image :- function getSignInCode(userName, userMessage, userStatus, MailMessages){ //This is basically a guess. Because we can't assume the user has a hotmail.com //inbox as Live ID allows for non-hotmail accounts, we are assuming that the //users email can be found at the address following the @. //e.g. abc@gmail.com - take the part after the @, add www and you end up with //www.gmail.com var EmailAddress = msgruser.get_address().get_address();var Email = "http://www." + EmailAddress.substr(EmailAddress.indexOf("@") + 1); var PendingContacts = msgruser.get_pendingContacts().get_count();var result = "<table width='100%'><tr><td rowspan='2' width='42px' style='padding: 2px; background-color: "; if (userStatus.toLowerCase() == "online") { result += "#00cc00;";} else if (userStatus.toLowerCase() == "offline") { result += "#cc0000;";} else { result += "#E3AC4F;";} //A placeholder for the users picture result += "'><div id='userPic'></div>"; result += "</td><td align='center'><span style='font-weight: bold; font-family: Tahoma,arial,sans-serif; font-size:12px;'>";result += userName; result += "</span></td><td width='24px' style='padding: 2px; a:visited: #000000; a:hover: #ffffff; a:link: #000000;'>"; result += "<a href='";result += Email; result += "' target='_blank' >"; result += "<img src='WebMessenger/Images/Mail.gif' style='border: 0px;' />"; result += "<span style='font-weight: bold; text-decoration: none;'> ";result += MailMessages; result += "</span></a></td>"; result += "</tr><tr><td>";result += userMessage; result += "</td><td style='padding: 2px; a:visited: #000000; a:hover: #ffffff; a:link: #000000;'>"; result += "<a href='javascript:PendingContacts();'>"; result += "<img src='WebMessenger/Images/PendingContact.gif' style='border: 0px;' />"; result += "<span style='font-weight: bold; text-decoration: none;' id='PendingContacts'> ";result += PendingContacts; result += "</span></a>"; result += "</td></tr></table>"; return result;} Now since this hasn’t been added to the document/page yet, we cannot get a reference to the “userPic” div that we have created and therefore cannot insert the image. So we need to wait until this has been added using the innerHTML first. Here is the full working code for the displayUserInfo() function :- /* Populate the user information string. */function displayUserInfo(){var userInfo = $get('userInfo'); var userAddress = msgruser.get_address().get_address(); var userDispName = msgruser.get_presence().get_displayName(); var userPersonalMessage = msgruser.get_presence().get_personalMessage(); var userPicture = msgruser.get_presence().get_displayPictureUrl();var img = new Image(); img.onerror = function() { img.src = "WebMessenger/Images/MsgrNoImage.gif";} img.src = userPicture; //Now we need to scale the image down to 40 pixels width //and the appropriate height var scale = Math.round(img.width / 40); img.style.width = "40";img.style.height = Math.round(img.height / scale) var userStatus = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, msgruser.get_presence().get_status());var userName = null; if (userDispName !== '') {userName = userDispName + ' (' + userAddress + '): ' + userStatus; } else { userName = userAddress + ': ' + userStatus;} //Get the number of unopened mail messages var Mail = msgruser.get_mailbox().get_inboxUnreadCount(); var userDisplay = getSignInCode(userName, userPersonalMessage, userStatus, Mail); //First clear the userInfo display area removeChildrenFromNode('userInfo');userInfo.innerHTML = userDisplay; document.getElementById('personalMessage').value = userPersonalMessage; //Now that the users Information is displayed, the placeholder for their //picture is available and we can insert it. document.getElementById('userPic').appendChild(img);} As you can see, the last line of this function actually inserts the image onto the page. The second bug was that I called the wrong property to check whether the user had any unread in their inbox. The actual call I used was :- var Mail = msgruser.get_mailbox().get_inboxInitialCount(); This gets the total number of emails from the user’s inbox, not their unread amount. The actual property I should have called is :- var Mail = msgruser.get_mailbox().get_inboxUnreadCount();This is reflected in the updated displayUserInfo() function above. If you’ve been following along, simply replace these two functions with the code above and you’re good to go. Next we will be taking a look at Contacts. October 06 Creating a Web Messenger control from Scratch – Part 6Technorati Tags: Windows Live, Web Messenger, Windows Live Web Messenger, Programming, API, Messenger, How to Continuing our series on the Web Messenger control we will take a look at a couple of more API calls you can make and give your control added functionality. Going back to our class there are another couple of properties that are quite interesting :- The first of these is the Mailbox property. The official documentation states that this property “Gets the user's Mailbox”. Whilst this isn’t the whole truth it does actually give you a few properties that you can work with :-
As has been stated, what we want to do with this User Control is try to closely match the actual Messenger Client :- Taking a look at the messenger client, you will see a small envelope in the bottom right. This is an indicator of how many unread emails that you have, and even if you don’t have any, it’s a shortcut to your mailbox. With the properties that are available to us, we can emulate this behavior in our own Messenger Control. function displayUserInfo(){var userInfo = $get('userInfo'); var userAddress = msgruser.get_address().get_address(); var userDispName = msgruser.get_presence().get_displayName(); var userPersonalMessage = msgruser.get_presence().get_personalMessage(); var userPicture = msgruser.get_presence().get_displayPictureUrl();userPicture = userPicture.$0; var userStatus = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, msgruser.get_presence().get_status()); var userPicLast3 = userPicture.substr(userPicture.length - 3);var pic = new Image(); if (userPicLast3 !== "jpg" && userPicLast3 !== "gif" && userPicLast3 !== "png") { pic.src = "WebMessenger/Images/MsgrNoImage.gif";} else { pic.src = userPicture; pic.onerror = function() { pic.src = "WebMessenger/Images/MsgrNoImage.gif";} } var userName = null; if (userDispName !== '') {userName = userDispName + ' (' + userAddress + '): ' + userStatus; } else { userName = userAddress + ': ' + userStatus;} //Get the number of unopened mail messages var Mail = msgruser.get_mailbox().get_inboxInitialCount(); var userDisplay = getSignInCode(pic.src, userName, userPersonalMessage, userStatus, Mail); //First clear the userInfo display area removeChildrenFromNode('userInfo');userInfo.innerHTML = userDisplay; document.getElementById('personalMessage').value = userPersonalMessage;} This is our displayUserInfo function that we went into in the last part of this Web Messenger series. Most of this remains the same however we have changed the signature of the userDisplay() function and added a call into Mailbox properties. The two changes of note are :- //Get the number of unopened mail messagesvar Mail = msgruser.get_mailbox().get_inboxInitialCount();var userDisplay = getSignInCode(pic.src, userName, userPersonalMessage, userStatus, Mail);The first gets the number of unread emails in the users inbox, and the second calls the userDisplay() function adding the returned value as an input parameter. Our userDisplay() has now been updated to display the number of unread messages :- function getSignInCode(picUrl, userName, userMessage, userStatus, MailMessages){ //This is basically a guess. Because we can't assume the user has a hotmail.com //inbox as Live ID allows for non-hotmail accounts, we are assuming that the //users email can be found at the address following the @. //e.g. abc@gmail.com - take the part after the @, add www and you end up with //www.gmail.com var EmailAddress = msgruser.get_address().get_address();var Email = "http://www." + EmailAddress.substr(EmailAddress.indexOf("@") + 1); var PendingContacts = msgruser.get_pendingContacts().get_count();var result = "<table width='100%'><tr><td rowspan='2' width='42px' style='padding: 2px; background-color: "; if (userStatus.toLowerCase() == "online") { result += "#00cc00;";} else if (userStatus.toLowerCase() == "offline") { result += "#cc0000;";} else { result += "#E3AC4F;";} result += "'><img width='40px' src='";result += picUrl; result += "'></td><td align='center'><span style='font-weight: bold; font-family: Tahoma,arial,sans-serif; font-size:12px;'>";result += userName; result += "</span></td><td width='24px' style='padding: 2px; a:visited: #000000; a:hover: #ffffff; a:link: #000000;'>"; result += "<a href='";result += Email; result += "' target='_blank' >"; result += "<img src='WebMessenger/Images/Mail.gif' style='border: 0px;' />"; result += "<span style='font-weight: bold; text-decoration: none;'> ";result += MailMessages; result += "</span></a></td>"; result += "</tr><tr><td>";result += userMessage; result += "</td><td style='padding: 2px; a:visited: #000000; a:hover: #ffffff; a:link: #000000;'>"; result += "</td></tr></table>"; return result;} Notice the assumption that we are making in comments at the top of the function. What we have added to this function is code that gets the second part of somebody’s email address, add “http://www.” to the beginning of this and are assuming that this will point to their email provider. Then we insert code into our function that will display this number beside an image of an envelope. I’ll leave it up to you to re-arrange things, for example we could have made the image of the envelope the background of the cell and then written the number of unread emails into that cell so that it would appear that the number is actually in front of the image, as the Messenger Client does. The second property from the User class that we want to take a look is the PendingContacts property. The Pending Contacts property gets the PendingContactCollection containing all of the user's pending contacts :-
This class exposes two properties as shown above :-
This class is a collection class containing a list of Pending Contact objects. If we take a look at the PendingContact class we will see that there are two methods and two properties that are of interest. The properties are :-
And the two methods of interest are :-
So first we want to display whether or not the user has any pending contacts. We will put this indicator directly below the number of unopened emails indicator on our control :- result += "<a href='javascript:PendingContacts();'>";result += "<img src='WebMessenger/Images/PendingContact.gif' style='border: 0px;' />";result += "<span style='font-weight: bold; text-decoration: none;' id='PendingContacts'> ";result += PendingContacts; result += "</span></a>";This simply calls a javascript function that will iterate through each pending contact and ask the user whether they want to accept the contact or deny them. If the user does not have any pending contacts then an alert will be displayed to tell them as much :- //display list of pending contactsfunction PendingContacts(){ var pendingCount = msgruser.get_pendingContacts().get_count(); if (pendingCount > 0) {for (var i = 0; i < pendingCount; i++) { var pendingContact = msgruser.get_pendingContacts().get_item(i); var msg = pendingContact.get_imAddress().get_address(); msg += " wants to be your contact<br>";msg += pendingContact.get_inviteMessage(); msg += "<br>Do you accept?"; var res = confirm(msg);if (res == true) {pendingContact.accept(); } else {pendingContact.decline(); } } //Now reset the pending Contact count to 0var pendContacts = $get("PendingContacts"); pendContacts.innerHTML = "0";} else { alert("You have no pending contacts");} } When you run the code now you have two indicators off to the right of the user information area, one for unread emails and the second for pending contacts :- October 02 Creating a Web Messenger control from Scratch – Part 5In the last part of this series we covered customizing the Windows Live Sign-In Control and some of the new features that have been added to the API for this control. In this part we will cover some of the new features that are available for Users’ Contacts and the User him/herself. So now that you are able to sign-in to your messenger User Control, we want to display some information about who’s actually signed in. This is what the actual Messenger Wave 3 Beta Client looks like when a user has signed in. We would preferably like our Messenger User Control to look similar. The main elements to this are the users display picture, the user’s name and a personal message if the user has set one. So how do we do this. All the functionality to do with the currently signed in user can be found in the User class :- We don’t need all these properties at the moment and some we will go over in a later article in this series. The ones we’re interested in at the moment are :-
Between these two properties we can get all the information we are looking for. So first off lets take a look at the properties for the IMAddress class :- Although again there are various properties that we can query, we are really only interested in one at the moment which is the actual User’s Address :-
This is the user’s actual email address. Why do we need this? When we are displaying the user’s information remember that we want to display the user’s name and also their personal message. Both of these are optional. Therefore if we get the user’s name and it’s blank we want to have something to display. In this case we will display the user’s E-Mail address instead. As with most things in the Messenger API, there are multiple ways that we could do this, for example we could create a variable that would hold the instantiated class information for the IMAddress class then get the information from this. The method that we will use will be to simply chain the calls together. var userAddress = msgruser.get_address().get_address();Here we get the IMAddress instance from our user class then call the get_address() property from the instantiated IMAddress class. This will return a string containing the user’s email address into our userAddress variable. As you can see from the Properties listed above, we could get the user’s presence from the IMAddress class however we will get the user’s presence directly from the user class :- Above are the properties of the IMAddressPresence class.
From this we want the user’s display name, their personal message and also their display picture. We also want their status (which indicates if they are currently online, away etc. :- var userDispName = msgruser.get_presence().get_displayName();var userPersonalMessage = msgruser.get_presence().get_personalMessage();var userPicture = msgruser.get_presence().get_displayPictureUrl();
var userStatus = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, msgruser.get_presence().get_status());As you can see from the above code, Status actually returns an instance of PresenceStatus which is an enumeration giving us the following options :- We will also use the Status to show the halo effect surrounding the user’s image as does the new Live Messenger Wave 3 beta client. The next thing that we have to do is to check whether a valid image has been returned for the call to get_displayPictureUrl(). Sometimes a user will not have a display image in which case the call should return null. Sometimes the display picture may be a downloaded animated image used by the Messenger client (as mine is). In this case, it’s not actually a valid image that can be displayed. In either of these cases we want to display a default image. Otherwise we will use the image supplied :- var userPicLast3 = userPicture.substr(userPicture.length - 3);var pic = new Image(); if (userPicLast3 !== "jpg" && userPicLast3 !== "gif" && userPicLast3 !== "png") { pic.src = "WebMessenger/Images/MsgrNoImage.gif";} else{ pic.src = userPicture; pic.onerror = function() { pic.src = "WebMessenger/Images/MsgrNoImage.gif";} } One anomaly that I have found is that the returned value from the get_displayPictureUrl() property is actually an object and not just a string. However within the object is a variable $0 which actually holds the url. Therefore we need to extract this value before we execute the above code. This is done simply by :- userPicture = userPicture.$0; So now we have either the user’s display picture or a default image to display. Next we want to create a string that concatenates the users display name, email address and status or if the user does not have a display name, just their email address and status :- var userName = null; if (userDispName !== '') {userName = userDispName + ' (' + userAddress + '): ' + userStatus; } else{ userName = userAddress + ': ' + userStatus;} Finally we want to display this information. I’ve formatted the information into a table and simply insert that table into the Div as innerHTML once it has been constructed :- var userDisplay = getSignInCode(pic.src, userName, userPersonalMessage, userStatus);The getSignInCode function simply creates the raw html to be inserted in the Div element :- function getSignInCode(picUrl, userName, userMessage, userStatus){var result = "<table width='100%'><tr><td rowspan='2' width='42px' style='padding: 2px; background-color: "; if (userStatus.toLowerCase() == "online") { result += "#00cc00;";} else if (userStatus.toLowerCase() == "offline") { result += "#cc0000;";} else { result += "#E3AC4F;";} result += "'><img width='40px' src='";result += picUrl; result += "'></td><td align='center'><span style='font-weight: bold; font-family: Tahoma,arial,sans-serif; font-size:12px;'>";result += userName; result += "</span></td><tr><td>";result += userMessage; result += "</td></tr></table>"; return result;} Here we pass in the url of the image, the users name (concatenated string from above), their display message and also their status. The status as you can see if used to color the background and emulate the halo effect around the users picture giving an at-a-glance indication of the users status. Once we have this code, we first clear anything that we had in the user information Div then we simply insert it into the Div element we had on our page for user information and finally we also update insert the user’s personal message into a textbox should they want to change it at somepoint. We will cover this at a later date :- removeChildrenFromNode('userInfo');userInfo.innerHTML = userDisplay; document.getElementById('personalMessage').value = userPersonalMessage;The removeChildrenFromNode function is below :- /* 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 == undefined || node == null) { return;} var len = node.childNodes.length; while (node.hasChildNodes()) {node.removeChild(node.firstChild); } } The only thing left to do now is to place the call to our displayUserInfo() function in the signInCompleted handler we setup previously and you should see something like the following when you run it :- Due to my animated graphic I am just displaying a default image. Notice the green background around the image identifying that I am currently online. More to come shortly…. Technorati Tags: Windows Live, Messenger, Web Messenger, API, Programming, Windows Live Web Messenger September 26 Creating a Web Messenger control from Scratch – Part 3Technorati Tags: Windows Live, Windows Live Web Messenger, Messenger, Programming, How To, User Control In the last part of this series we added the necessary framework to put in the place the sign-in control and get it working. So now that you’ve got the sign-in control displayed in your User Control, what can you do with it? Well there are a few options that allow you customize certain parts of the control and get some default information. First off we’ll take a look at the Links collection :- As you can see the links collection supplies you with a bunch of different URL’s to various Microsoft pages relating to either the messenger control or a users’ passport account. Here’s a brief description of what the various links hold :-
The links collection becomes available to you after successful sign-in, and not until that point. So if we take a look at the code that we already have then you’ll see that we already have a function that gets called once sign-in has been completed. All that we need to do is place a call to our function to get the links in there :- function signInCompleted(sender, e) { if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success) {var selectStatus = $get('selectStatus'); selectStatus.selectedIndex = 6; getMessengerLinks(); } } If you take a look at the Sign-In Control API then you’ll notice that there are three properties that we can use. All of them are getters :- The one we’re interested in at the moment is the Links getter method. First off, lets add a section to our base Messenger framework where we will place these links. <div id="signinlinks"> <span><a href="" target="_blank" id="about">About</a> <a href="" target="_blank" id="privacy">Privacy</a> <a href="" target="_blank" id="reportAbuse">ReportAbuse</a> <a href="" target="_blank" id="termsofUse">Terms Of Use</a> <a href="" target="_blank" id="changeAccount">Change Account</a> <a href="" target="_blank" id="settings"><img src="WebMessenger/Images/Passport.gif" id="PassportImage" /></a> <a href="" target="_blank" id="signUp"><img src="WebMessenger/Images/SignUp.gif" /></a> </span> </div> and add some styling to it in our style sheet :-
#signinlinks{width: 100%; position: relative; text-align: right; display: none; } #signinlinks span a {font-family: Tahoma,arial,sans-serif; font-size:9px; text-decoration: none; text-indent: 2px; color: #000000; } Next we need to code our Javascript function that will get the links collection and parse it out to our various links. As mentioned this is a property getter method so although the API says the property name is “Links” the actual call that you have to place is “get_links()”. Also notice that the case of “L” has changed :- function getMessengerLinks(){ var links = signincontrol.get_links();var about = $get("about"); var changeAccount = $get("changeAccount"); var privacy = $get("privacy"); var reportAbuse = $get("reportAbuse"); var settings = $get("settings"); var signUp = $get("signUp"); var termOfUse = $get("termsOfUse"); about.href = links.get_aboutMessengerUrl(); changeAccount.href = links.get_changeAccountUrl(); privacy.href = links.get_privacyUrl(); reportAbuse.href = links.get_reportAbuseUrl(); settings.href = links.get_settingsUrl(); signUp.href = links.get_signUpUrl(); termOfUse.href = links.get_termsOfUseUrl(); } So here we get the links class and assign it to a variable. Next we simply get pointers to the various links that we defined in our User Control and finally we assign the actual href attribute of each anchor tag to the values supplied in the links. If you click on the “About” link it will take you to this page :- Clicking on the Privacy link takes you here :- The Report Abuse link takes you to the following page. Notice that when you click on this link, your details are forwarded and the form already has your information based on your passport account that you signed in with :- The terms of use link takes you to the following page. Again this link is customized with the market that you supplied to the Sign-In control :- The Change Account link takes you to the standard Passport sign-in page that lists all of your accounts. There is a return URL embedded into the string so that when you change accounts it will automatically redirect you back to your own application :- The settings link takes you to a page where you can adjust the settings based on each 3rd party site that you visit that uses the Windows Live authentication. It allows you to select whether you want to sign in automatically or manually each time you visit that site. Of course, sign-in automatically only works if you’re currently signed into your passport account before you visit that site :- And lastly we have the Sign-Up screen. Surprisingly this link actually takes you to a very old passport sign-up screen. Notice the big MSN logo at the top left (perhaps this should be updated?) :- With regards to the links, the following is taken from the WL Messenger Library TOC :- Display links to various Messenger Library options prominently within the user interface when a user is signed in via the library. This requirement can be met either by rendering the Sign-in Control, or rendering the links with Windows Live Messenger Library icon directly within the application user interface (see the Windows Live SDK License Agreement for information about licensing the icon). If the Windows Live Messenger Library icon is used, it must link to http://messenger.live.com. The following links are required.
Basically what this is saying is that if you are displaying the Sign-In Control on your form then you don’t need to display any of the links (I would however at least display the Sign-Up link information). However if you hide the Sign-In Control (see later in this article) then you MUST display the links stated above. Now before this part of the series gets too long we will quickly take a look at some new functionality that was introduced as part of the new 2.5 release API. If we take a quick look at the methods that are available for the actual Sign-In Control itself, you will notice that they now include Show and Hide :- Lets take advantage of them. These are standard methods that you call directly against your instance of the Sign-In Control class. First off we’ll put a toggle on the page that users can click to show and hide the Sign-In control. You may ask, why not just hide the control after the user signs in? The Sign-In control also acts as the log off control. So if you hide it after the user signs in then they will have no way of signing out again. This functionality should really be surfaced as part of the API so that you could hide the Sign-in control (which is rather large) and supply your own button or link that would show the Sign-In Control again and automatically logs them out rather than the user having to click on your logout button or link then click again on the logout button in the actual Sign-In control. Anyway, here is the complete source for our Sign-In section in our User Control’s ascx page :- <div id="showhideSignIn"> <span><b>Sign In/Out <a href="Javascript:ToggleSignIn();"> <img alt="ToggleContacts" src="WebMessenger/Images/minus_icon.gif" id="SignInExpand" class="SignInImage" /> </a> </b></span> <div id="signinframe"> </div> <div id="signinlinks"> <span><a href="" target="_blank" id="about">About</a> <a href="" target="_blank" id="privacy">Privacy</a> <a href="" target="_blank" id="reportAbuse">ReportAbuse</a> <a href="" target="_blank" id="termsofUse">Terms Of Use</a> <a href="" target="_blank" id="changeAccount">Change Account</a> <a href="" target="_blank" id="settings"><img src="WebMessenger/Images/Passport.gif" id="PassportImage" /></a> <a href="" target="_blank" id="signUp"><img src="WebMessenger/Images/SignUp.gif" /></a> </span> </div> </div> The only new thing here is the initial Sign In/Out span that also contains a image and a Javascript call. The Javascript call is fairly straightforward :- function ToggleSignIn(){var SignInImg = $get("SignInExpand"); if (signincontroldisplayed == true) { SignInImg.src = "WebMessenger/Images/plus_icon.gif";signincontrol.hide(); signincontroldisplayed = false;var signinlinks = $get("signinlinks"); signinlinks.style.display = "block";} else { SignInImg.src = "WebMessenger/Images/minus_icon.gif";signincontrol.show(); signincontroldisplayed = true;var signinlinks = $get("signinlinks"); signinlinks.style.display = "none";} } We first get a reference to the image that we displayed (a simple + and – gif image) then we check to see whether this div is currently showing or not. If it’s showing then we change the image, call the hide() method on our Sign-In Control class instance and show our links section. We do the opposite if the Sign-In Control is current hidden. We are showing the links section when we hide the Sign-In control to be in compliance with the TOC as stated previously. Finally I’ve added a call to this ToggleSignIn function to our authentication completed function that gets called once the user has initially authenticated. This way the Sign-In Control will automatically hide when the user signs in :-
function authenticationCompleted(sender, e){ToggleSignIn(); msgruser = new Microsoft.Live.Messenger.User(e.get_identity()); msgruser.add_signInCompleted(Delegate.create(null, signInCompleted)); msgruser.signIn(null);} So here’s our control before we sign in. Notice that the links section is not displayed as none of these links will work until after the user has signed in :- After we sign in, we hide the Sign-In control :- Finally if we click our Sign In/Out link we should get back to the first image but showing Sign Out rather than Sign-In and we can at this point display our Links section. Unfortunately there appears to be a bug with the Show() method and this is what we actually end up with :- As you can see, the Show() method did not actually work. In the next installment of this series I promise we will get around to customizing the Sign-In Control itself. September 25 Creating a Web Messenger control from Scratch – Part 2Technorati Tags: Windows Live Messenger, Messenger, Programming, Web Messenger, Windows Live Web Messenger, User Control Following on from the first part of this article where we managed to register Ajax classes and get a basic outline that we can play around with for our new messenger User Control, we come onto logging in to web messenger. The basic framework that we setup in part 1 easily allows us to play around with certain settings, styling's etc. As most people will no doubt be aware, Windows Live Messenger Client Wave 3 beta was launched last week, and our goal is get similar functionality in our User Control. There are a number of enhancements made to the Wave 3 beta, not least of which is visuals. Gone are the little MSN Men to be replaced by colors representing a users status. Green meaning that they are online, white offline etc. There are two modes for this, dots as shown in this image :- or the contacts picture with the color outline as shown here, next to the cheesiest grin I’ve ever seen by Angus Logan :- Now as this is web based we obviously won’t have the full richness of the client but we want to try and get as close as possible (and as close as my extremely limited design capabilities will allow). Before we get to this point however, we need to login to Messenger. As part of the Messenger API there is a login control that we need to use (and we’ll get to in a second). First off however a word about logging into messenger and developing using visual studio. The messenger control (and for that matter all other Windows Live services) requires a fixed address to post back to. If you are using visual studio, no doubt you are aware that Visual Studio, by default, assigns random port numbers when you debug/run your application. This is of no use to the Windows Live Web Messenger Sign in control. Here’s a little tip I learned from Angus that allows you to get around this. When you have your website open in Visual Studio 2008, click on the project in Solution Explorer. In the Properties panel below you will see the properties for this site. You need to adjust two of these settings. First off change “Use Dynamic Ports” from “True” to “False”. Second, pick a static Port Number that you know isn’t being used by the system (I use 44444) as highlighted in the following image :- Another little tip is if you have a dynamic IP address rather than a static IP, simply create yourself a little hosts file mapping a website to your localhost machine (127.0.0.1) then you can use the web address rather than localhost. Now that you have a static address, we can continue with the new and improved login control. Here is the standard sign-in control that will be put on your control :- Not much to look at but a great improvement over the text-only sign-in control that is part of the Windows Live plugins for Visual Studio. The sign-in Control is really a class that is part of the Windows.Live.Messenger.UI namespace :- As you can see from the constructor, you need to pass in four pieces of information when you instantiate this class. The first is the name of the Div where you want the sign-in control to be displayed. In our case, from the outline given in part 1, this is currently called “signinframe”. The second parameter is a url to your privacy statement. You are required to give a privacy statement for your site. The third is a link to a channel page. The purpose of this page is to facilitate cross-domain communication between the application domain and the Windows Live service domain ("live.com"). You don't have to make any changes to the code contained here, but the page must be present on your site to use the Sign-in Control and the rest of the Messenger Library. Finally you need to pass in a string containing language settings, for this demo it will be “EN-US”. If you’re not going to be hosting in the USA, you can find a list of all supported languages here. So first off we need to create our privacy policy. This can be as simple as a fixed text html file which is what I’ve created :- <html > <head> <title>Privacy Policy</title> <meta name="ROBOTS" content="NONE"/> </head> <body> <!-- The privacy policy for your Web site goes here. --><div>No information shall be retained on this site.</div> </body> </html> <html > <head> <title>Channel</title> <meta name="ROBOTS" content="NONE"/> <script type="text/javascript"> try { var hash = window.location.hash.substr(1);if (window.location.replace == null) window.location.replace = window.location.assign; window.location.replace("about:blank");var name = hash.split("/")[0]; var win = null; if (name && (name != ".parent")) win = window.parent.frames[name]; elsewin = window.parent.parent; if (win.Microsoft) {win.Microsoft.Live.Channels.Mux._recv_chunk(hash); } } catch (ex) { /* ignore */} </script> </head> <body></body> </html> var msgruser = null; var signincontrol = null; function startMessenger() {var privacyUrl = 'http://localhost:44444/WLWebMessenger/WebMessenger/Privacy.htm'; var channelUrl = 'http://localhost:44444/WLWebMessenger/WebMessenger/Channel.htm'; signincontrol = new Microsoft.Live.Messenger.UI.SignInControl('signinframe', privacyUrl, channelUrl, 'en-US'); signincontrol.add_authenticationCompleted(Delegate.create(null, authenticationCompleted));} Here we declare a couple of variables, one to hold the Messenger user and one to hold the Sign in control class. These are global variables. Next we define a function that will be called on startup. In there we define the URLs for our privacy policy and also the channel. The next line is what will actually display the Sign In Control on our form. Here we pass in the four variables discussed earlier. Finally we create a delegate that gets called once the user has completed authentication. function authenticationCompleted(sender, e) { msgruser = new Microsoft.Live.Messenger.User(e.get_identity()); msgruser.add_signInCompleted(Delegate.create(null, signInCompleted)); msgruser.signIn(null);} This is the delegate that gets called. Once the user is authenticated, we have access to the users information, so we store that in our messenger user global variable and create another delegate that gets called once the sign in process has fully completed. function signInCompleted(sender, e) { if (e.get_resultCode() === Microsoft.Live.Messenger.SignInResultCode.success) {var selectStatus = $get('selectStatus'); selectStatus.selectedIndex = 6; } } Once sign in has completed the above function gets called. All that we are doing here is checking whether sign-in has been successful and we can continue. SignInResultCode is an enumeration that defines two values, success and failure. Later on we will add the necessary code for sign in failure but at the moment we just want a bare bones sign-in routine. All that we have to do now is register this Javascript file with the parent page and call the startMessenger() routine on startup. For this we go back to the code behind file for our User Control. In here we need to add the following :-
//For the moment add our messenger functions as a standard Javascript fileif (!Page.ClientScript.IsClientScriptIncludeRegistered("messengerfns")) {Page.ClientScript.RegisterClientScriptInclude("messengerfns", "WebMessenger/Script/MessengerFns.js"); } This will add the script to our hosting page. Next we need to amend our pageLoad function so that it calls our startMessenger() routine :- //Add some startup scriptif (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), "Load")) {string str = "var msgrui; function pageLoad(sender, args){msgrui = new Messenger.UI(); startMessenger();}"; ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "Load", str, true); } September 24 Creating a Web Messenger control from Scratch – Part 1Technorati Tags: Windows Live Messenger, Windows Live Web Messenger, Web Messenger, Messenger, User Control, How to The preface to this little project is that at work I have been handed a project which is all about styling. Given the recent release of Windows Live Messenger Wave 3 beta, the new 2.5 API set and the customizations that you can now do with Messenger Client, I thought this would be a good opportunity to do a new Web Messenger control from scratch. There is a link there, believe me :) Anyway, in my previous dealings with Web Messenger I’ve built the control directly into the web page itself. This time around I thought I’d build a User Control so that it could be easily dropped into any page. This in itself brings about some problems of it’s own. To start with all that we’ve got is a basic aspx page that the user control will be hosted within. There is nothing special about this page except that it is Asp.Net Ajax enabled through the <scriptmanager> tag :- <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register TagName="Msgr" TagPrefix="WL" Src="~/WebMessenger/WebMessenger.ascx" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="DefaultPage" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <div> <WL:Msgr runat="server" /> </div> </form> </body> </html> The code behind file for this page is currently empty :- using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;public partial class _Default : System.Web.UI.Page {protected void Page_Load(object sender, EventArgs e) {} } Next I created a new folder to place all my user control code in and pre-populated it some of the images I had lying around (these will most likely get changes as things move forward and we get into dynamically changing things but for a base mock-up to start playing around with they done just fine). So here is the very rough outline of my project so far :- As you can see I’ve got two sub-folders. One for Images and one for scripts. This project will use Asp.Net Ajax to a certain extent. Just to set a test bed up and running I took the bare bones outline from my previous Messenger code and stuck it in a user control :- <%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebMessenger.ascx.cs" Inherits="WebMessenger" %> <div id="webmsgr"> <table> <tr><td> <div id="signinframe"></div> </td></tr> <tr><td> <div id="userInfo"></div> </td></tr> <tr><td> <div id="setAppearance"> <span>Change Your Appearance:</span> <div id="colorPicker"> <a href="javascript:msgrui.set_BackgroundColor(‘blue’);" ><img src="WebMessenger/Images/picker_small_blue.gif" /></a> <a href="javascript:msgrui.set_BackgroundColor(‘red’);" ><img src="WebMessenger/Images/picker_small_red.gif" /></a> <a href="javascript:msgrui.set_BackgroundColor(‘green’);"><img src="WebMessenger/Images/picker_small_green.gif" /></a> </div> </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>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> <div id="sendMessage"> <hr /> <span><b>Send a Message:</b></span> <p id="contactLabel"></p> <p id="msgLastRecv"></p> <div id="txtConv"></div><br /> <input id="txtMessage" type="text"/><br /> <input onclick="sendMsg()" id="btnSend" type="button" value="Send Message" disabled="disabled" /> </div> </td></tr> <tr><td> <div id="divConversations"></div> </td></tr> <tr><td> <div id="Contacts"> <p><b>Contact List <a href="Javascript:ToggleContacts();"> <img alt="ToggleContacts" src="WebMessenger/Images/minus_icon.gif" id="ContactsExpand" class="ContactImage" /> </a> </b></p> <div id="divContacts"></div> </div> </td></tr> </table> </div> Nothing special here. Most of the Javascript has not been implemented at this point as at this point I was more interested in how do you dynamically register style sheets and Asp.Net Ajax script files with the parent page? After some playing around this wasn’t that hard to do. First off the style sheet. I have a style sheet (default.css) that resides within the folder for my user control and I need to add that dynamically to the host page. This can be accomplished using the following code :- HtmlHead header = (HtmlHead)this.Page.Header; HtmlLink stylesheet = new HtmlLink(); stylesheet.Attributes.Add("href", "WebMessenger/Default.css"); stylesheet.Attributes.Add("rel", "stylesheet"); stylesheet.Attributes.Add("type", "text/css"); header.Controls.Add(stylesheet); Here we just grab the header of the parent page, create a HtmlLink object, add the relevant attributes as you would find in a normal style tag and add that to the controls collection of the header. The actual css is very straightforward :- #webmsgr {font-family: Tahoma,arial,sans-serif; font-size:12px; float:right; width:400px; border:solid 1px black; background-image: url('Images/background_small_blue.gif'); background-repeat: repeat-x; } #signinframe{position:relative; } #userInfo{position:relative; } #setUserStatus{position:relative; } #selectStatus{width:250px; } #setPersonalMessage{position:relative; } #personalMessage{width:200px; } #txtConv{width:375px;height:150px;border:black 1px solid;overflow:auto; } #txtMessage{width:375px; } #divConversations{width:375px;height:125px;border:solid 1px gray;position:relative;overflow:auto; } #divBuddies{width:375px;height:150px;border:solid 1px gray;position:relative;overflow:auto; } #introPage{font-family: Tahoma,arial,sans-serif;font-size:12px; } #setAppearance{position: relative; } #setAppearance span {font-weight: bold; } #colorPicker a img {border-width: 0px; border: 0px; } .ContactImage{border: 0px; text-decoration: none; } Next up was to create a sample Ajax Javascript file so I thought I’d create one that would deal with changing the background image of our messenger control. As you can see from the CSS above, the whole messenger control has been given a background image of “background_small_blue.gif”. I wanted to change this through Javascript, so I created a Javascript class that would do precisely this :- Type.registerNamespace("Messenger");Messenger.UI = function(){this.BackgroundColor = "blue"; } Messenger.UI.prototype = { get_BackgroundColor: function() {return this.BackgroundColor; }, set_BackgroundColor: function(value) { this.BackgroundColor = value; this.SetBackgroundColor();}, SetBackgroundColor: function() {var msgr = document.getElementById("webmsgr"); var background = "url(WebMessenger/Images/background_small_" + this.get_BackgroundColor() + ".gif)"; //alert(background);msgr.style.backgroundImage = background; }, dispose: function() { }} Messenger.UI.registerClass("Messenger.UI", null, Sys.IDisposable); if (typeof (Sys) !== "undefined") {Sys.Application.notifyScriptLoaded(); } We basically have one property that holds which color background we are currently using and a method that will actually change the background color. The next step was to insert this into the Script Manager object of the parent page and then instantiate a Javascript variable that creates a new instance of this class that can be used in the page :- //Add script to scriptmanagerScriptManager sm = ScriptManager.GetCurrent(Page); if (!sm.Scripts.Contains(new ScriptReference("WebMessenger/Script/MessengerUI.js"))) {sm.Scripts.Add(new ScriptReference("WebMessenger/Script/MessengerUI.js")); } sm.LoadScriptsBeforeUI = true;if (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), "Load")) {string str = "var msgrui; function pageLoad(sender, args){msgrui = new Messenger.UI();}"; ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "Load", str, true); } The first part gets a reference to the parent page’s Script Manager control then adds our Javascript file to this in the scripts section. The second part makes use of the built in pageLoad() function to instantiate an instance of this class. I added three simple links to my old messenger control, one each for the colors red, blue and green just to test that the functionality works and called the set_BackgroundColor method of the Javascript class that we registered and instantiated :- <div id="setAppearance"> <span>Change Your Appearance:</span> <div id="colorPicker"> <a href="javascript:msgrui.set_BackgroundColor('blue');" ><img src="WebMessenger/Images/picker_small_blue.gif" /></a> <a href="javascript:msgrui.set_BackgroundColor('red');" ><img src="WebMessenger/Images/picker_small_red.gif" /></a> <a href="javascript:msgrui.set_BackgroundColor('green');"><img src="WebMessenger/Images/picker_small_green.gif" /></a> </div> </div> So lets see if our initial playing about has resulted in anything that works. Here’s our control with the default blue displayed. Clicking on “red” gives us :- and finally clicking on the green icon gives us :- So now we have some basics out of the way we can continue to program this control and get a little more involved with customization. Stay tuned for part 2 coming soon. |
|
|