November 10, 2009

Simple Website Instant Messenger – Client-side Functionality

This is part two of the Simple Website Instant Messenger (SWIM for short, I love it when acronyms just work themselves out) and will cover adding some client-side functionality to our system. For part 1, click here.

Client-side functionality essentially translates itself to “using JavaScript to do some funcy (eh? get it? Funcy? Functional?) things”. It will allow us to add a level of interaction that users are familiar with and that they come to expect from applications. We want them to have the ability to minimize or maximize the windows, as well as close them. We also want to do all of this without page refreshes. Since actions like this are on a per-session basis, we don’t need to have any server-side code to handle it. We can let the browsers do all the work for us.

For this section we’ll be making some heavy use of jQuery and some rather complex DOM manipulation. I’ve also opted to use the long-hand version of everything instead of shorthand. This is so that you guys will be able to read the code and such. I’ve opted to use the production version of jQuery, but if you’re just getting started, you may as well download the development version. The bonus of this is that if you’re just learning you can easily pop in to the jQuery code and see how things are done. As well, if you are using an advanced IDE (such as Dreamweaver) you’ll get full code hinting. You can do this by heading to this website and downloading the appropriate version. I also recommend that you bookmark the documentation for jQuery (http://docs.jquery.com) as you’ll end up using it a lot.

Setup jQuery in whatever folder you’ve stored the HTML/CSS file from the previous tutorial (setup is actually just copy/paste). You’ll then need to link the script in your HTML by adding the following line of code to your HTML file in the head section of the code

<script src="jquery.min.js" type="text/javascript"></script>

Note the src attribute contains the name of the jquery file that I am using. You may have to edit it so that the name of the file matches the name of the file you downloaded.

Directly below that you can add this line as well

<script src="im.js" type="text/javascript"></script>

That line of code will link to our not-yet-created javascript file which will hold all the client-side functionality for our IM script. Once that’s done you can pop open your editor and get started with the actual jQuery code. However, before we continue with the tutorial note that this is NOT a jQuery primer. This tutorial is expecting you to have some knowledge of jQuery and javascript syntax. If you do not, please read this jQuery primer tutorial first before continuing.

The first thing we are going to do is ensure that our “information” window has a toggle-state. Instead of using jQuery’s built in toggle() method, I’ve decided to go with a simple boolean check.

$(document).ready(function){
var windowOpen = false;
$('.info').click(function(){
			if(windowOpen){
				$('.more').fadeOut('fast');
				$(this).children('span').children('img').attr('src','/icon/bullet_arrow_up.png');
				windowOpen = false;
			}
			else{
				$('.more').fadeIn('fast');
				$(this).children('span').children('img').attr('src','/icon/bullet_arrow_down.png');
				windowOpen = true;
			}
	});
});

Basically, this will apply the “onclick” event to our main window launching button. When clicked it will check if the window is already open and depending on the value of windowOpen, it will close/open it accordingly.

This next section of code will handle opening the chat windows. Since we want to make sure that only windows that AREN’T opened can be opened (redundant? yes, but completely necessary). This will ensure that if a window is already open, it won’t open it again.

	$('.contacts span').live('click',function(){
		var id = $(this).attr('id'); 
		var name = $(this).attr('name'); 
		var found = false; 
		for(i in openWindows){
			if(openWindows[i] == id+name){
				found = true;
			}
		}
 
		if(!found){
			$('.im-bar').prepend('<span class="task" id="'+id+'"><div class="convo"><img src="/icon/cancel.png" id="close-win" alt="Cancel"><span class="system">You have entered a conversation with '+name+'</span><textarea name="message" id="message"></textarea></div><div class="win" name="'+name+'">'+name+'</div>');
			$('#'+id).children('.convo').css('display','inline');
			openWindows[openWindows.length] = id+name;
			$('#'+id).children('.win').css('padding-top','50px');
			convoOpen = true;
			var offset = (openWindows.length*50)+(openWindows.length*15);
			$('#'+id).children('.convo').css('right',offset+'px');
			$('#'+id).children().children('textarea').focus();
		}
 
		$('.more').fadeOut('fast');
		$('.info').children('span').children('img').attr('src','/icon/bullet_arrow_up.png');
		windowOpen = false;
	});

The code itself remains fairly straightforward albeit long. First it does some variable assignment and then checks the openWindows array to see if it can find this particular window. If it can’t, it simply continues with the code. First it creates the new window and places it at the front of the open-window list. Then it just adds it to the openWindows array and does a bit more manipulation to create a text-box and align it properly with the current tab. It also opens the window and focuses on the text area. Finally it fades out the main information window and resets the image and boolean var.

Something to note here: Since we want openWindows and convoOpen to be accessible to ALL our functions, we can place it next to the “openWindow” declaration at the top of the script. It would look like this:

var openWindows = new Array(); 
var convoOpen = false;

This next bit will just pop open the window if you click on the tab, and minimize it again if you click again.

$('.task .win').live('click',function(){
		if(convoOpen){
			$(this).prev().css('display','none'); 
			$(this).css('padding-top','5px'); 
			convoOpen = false;
		}
		else{
			$(this).prev('.convo').css('display','block'); 
			$(this).css('padding-top','50px');
			convoOpen = true;
		}		   
	});

We’re nearing the end of our code. This block of code will handle the “Close” button on a conversation window. If it is clicked, the window is removed from the tab bar and the openWindows array and the remaining positions are re-calculated.

	$('.task .convo #close-win').live('click',function(){
		var id = $(this).parent().parent().attr('id');
		var name = $(this).parent().next().attr('name');
		for(i in openWindows){
			if(openWindows[i] == id+name){
				openWindows.splice(i,1);
				break;
			}
		}
		$(this).parent().parent().remove(); 
		convoOpen = false;
		var i = openWindows.length;
		$('.im-bar').children().children('.convo').each(function(){
			var offset = (i*50)+(i*15);
			$(this).css('right',(offset)+'px');
			i--;
		});	
	});

This last block of code will take any text in our textarea and submit it to the server when you press enter. The AJAX portion of this tutorial will be following, so in the mean-time everything else is showed here. The message is sent to the server, and then it is also automatically placed into the conversation window. We also strip out all tags from the code to ensure that nothing breaks our layout or is able to get through.

$('.task .convo #message').live('keyup',function(e){
		if(e.which == 13){
			data = $(this).val();
			data = data.replace(/<\/?[^>]+>/gi, '');
			// Send message
			$(this).val('');
			$(this).prev().addClass('text');
			if($(this).prev().hasClass('system')){
				$(this).prev().removeClass('system');
				$(this).prev().text('');
			}
			if(data != '' && data != '\n'){
				$(this).prev().append('<p><b>'+yourName+':</b> '+data+'</p>');
				$(this).prev().attr({ scrollTop: $(this).prev().attr("scrollHeight") });
			}
		}
	});

That is the basics of our Client-Side functionality to our Simple Website Instant Messenger system. The next installment will cover adding the AJAX function and modifying this last section sightly to reflect it.

November 6, 2009

Microsoft WebsiteSpark

While I initially decided that Fridays would be posts from my favourite blogs, this was something that I realized not a lot of people are aware of. If you’re looking to get into ASP.NET I recommend you check out this great offering from Microsoft. There are a few stipulations, but definitely worth it if you’re interested in building up your knowledge base.

http://www.microsoft.com/web/websitespark/

wbs

November 2, 2009

Google Wave

If you’ve been keeping up with latest Google news, you’ll know that Google Wave is the latest and greatest thing. Or so they claim. After spending a few days playing around with Wave I’ve come to a rather disappointing conclusion. Unless you’re a developer, Wave will be useless.

First off, let me highlight what Google Wave provides

  • Real time collaboration, and I mean real time – people can see as you type letter by letter.
  • A new way to organize your email
  • A convergence of both traditional email and instant messaging

As a developer and a computer geek I’m incredibly excited by this. Not only is it something new and fancy, but it could potentially replace existing email and IM systems and provide a platform for developers to integrate these features into their own websites. That’s amazing right?!

Wrong.

Google Wave undermines certain benefits that traditional email comes with. I never thought about the implications of real-time email until I was trying to write an email to a client and I realized that at numerous times I just stopped and re-read what I was writing, and even went back and changed certain sections of it. I realized that if my client could see what I was typing as I was typing it, they might get a little impatient and call me just to find out what I was talking about quickly. However, my writing took place over several days. And that is the benefit of email. You have the ability to refine your response over any number of days before sending it, and once you sent it you can sit back and relax knowing that your client received an email with exactly the tone that you were trying to imply.

Google wave even claims it will be a good way to IM with multiple people, but that isn’t the case. As with emails, instant messaging provides you with a certain set of tools that Google Wave can not provide. Things like statuses (which are implemented somewhat vaguely in Wave), emoticons, and even the ability to write out your message and spell check it before sending it are built into IM clients. By providing people direct access to your thought process as you compose your messages, Google strips away a necessary barrier that these clients require to be successful. A friend once asked me how I cope with being so connected. I read hundreds of feeds a day, respond to numerous emails, keep up with contacts over my Blackberry and even make use of Friendfeed and Twitter when necessary. For an average user that alone is too much. I can’t imagine how I would be able to cope with all of it if I could watch people writing their content in real time.

As a collaboration tool however, Google Wave will serve its purpose. In a corporate setting, working with numerous people on documents is something that occurs fairly frequently, and the ability to open a single copy and edit it (with revisions saved) is a huge bonus. In that respect, I think Google definitely hit the nail on the head.

But what they provide to developers is much bigger than what they provide to users. The ability to access these real-time components and integrate them into their own web applications is something that developers everywhere are waiting to be able to do. Imagine utilizing Google Wave to write your own web-based editor, ala Bespin, but with collaboration and versioning built right in to it. Imagine being able to instantly set up a collaboration between other bloggers to work on a common post.

To developers Google Wave represents the future of the web. It represents the future of JavaScript as it finally becomes welcomed by developers. It forces browsers to push their JS engines to perform faster while lowering their system resources at the same time. To regular users? Google Wave is useless.

wave

If you are interested in Google Wave, I have about 10 invites left. Please leave a comment with your name and the email address you would like me to send it to. The first 10 comments left will get invites.