![]() |
|
Spaces home MSN and Windows LivePhotosProfileFriendsMore ![]() | ![]() |
|
MSN and Windows LiveTips, tricks and information regarding MSN and Windows Live. See also http://hackersoftmvp.spaces.live.com/
August 01 The Ultimate HTML Reference - Review
As I’m currently off work due to surgery I thought there’s no better time to read some of the books that I haven’t gotten around to read yet. As such here is the first of my reviews for this week. In previous years I was never very enchanted with Sitepoint titles however over the past year or so Sitepoint seem to have upped their game and have published a number of fairly good titles. This book being one of them. The ultimate HTML reference by Ian Lloyd is exactly what it says, a reference guide. Although I’ve read the book cover to cover it is meant more as a reference book than a straight read. The book covers every single HTML/XHTML tag and corresponding attribute known (including some that aren’t even in the official ratified HTML standard but are supported by certain browsers, mainly during the browser wars from a few years ago) from HTML version 1 right through to HTML 4.01 and also includes XHTML through version 1.1. Unfortunately you won’t find any HTML 5 or XHTML 2.0 tags or extensions in the book but that is mainly because these haven’t been ratified by the W3C yet. The book is very well laid out with each each attribute to a tag immediately following the tag and a quick reference stating exactly what tag the attribute is associated with (which is handy for a reference guide). Next to this is a quick reference stating whether or not the tag or attribute has been deprecated, whether it’s required, the version of HTML or XHTML that it was introduced and a quick browser support reference stating whether it’s fully supported by the browser, partially supported, not supported at all or whether the implementation is buggy for a particular browser. This is followed by a description of what the tag or attribute does, any values that it takes followed by a more complete browser compatibility list. The list covers the major browsers that are currently out from IE5.5 through IE7, Firefox 1.0 through 2.0, Safari 1.3 through 3.0 and Opera 9.2. This is followed by a brief description of any compatibility issues as listed finally followed by a list of other relevant tags or attributes. As with any book of this nature, basically it is out of date virtually as it’s printed. With Firefox 3.0 and Opera 9.5 just being released and Internet Explorer 8.0 just around the corner, however there are mentions of these scattered throughout the book e.g. the “X-UA-Compatible” attribute of the http-equiv that was introduced with IE8. Unfortunately since the book went to print Microsoft have changed their mind and this tag is no longer necessary to put IE8 into full compatibility mode as it will ship in that mode as default. There are also numerous references to web articles like RFC’s that the reader can use for further information should they be inclined. Also there are tips as to what CSS styling you should use instead if an attribute be deprecated. This leads me to one of my biggest complaints about this good. Reading through it you just get the feeling that as well as the HTML/XHTML reference, there should also be a CSS reference. It just seems so natural a fit to this type of book, however as the title suggests this book only covers HTML/XHTML. As such Ian Lloyd has done an insanely outstanding job of providing all the information you could ever want about any HTML element or attribute. This is definitely a book that will be sitting on my desk and one that I will dip into every now and again and one that you should have too. I just hope that there is a companion book in the works detailing CSS in the same manner. July 11 Cheap and Easy Online HelpdeskA lot of professional sites are now including a means of real time chat as part of their helpdesk sites. MSDN has their online concierge service, Dell has an online help, AT&T etc. So how do you do this type of thing within your own web site? In previous articles I've covered how to incorporate Windows Live Messenger into your own site. This article simply takes that process one step further by allowing you to host your own online Helpdesk chat system. The code in this article is actually very similar to the code in the previous articles I've posted and so I won't be going over all the functions again, instead I will point out the differences between this application and the previous one.
As you can see, the site structure is exactly the same. The Privacy.htm and Channel.htm required files are present. There are a few graphics files, a theme and everything else is contained in the Default.aspx file. The main body of the html code found in Default.aspx is the same as in my previous articles however we've removed a couple of features as these aren't strictly necessary for a helpdesk application :-
<body onload="scriptMain()"> <form id="form1" runat="server"> <div id="msgr"> <table> <tr><td> <div id="signinframe"></div> </td></tr> <tr><td> <div id="userInfo"></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>Helpdesk Contact <a href="Javascript:ToggleContacts();"> <img alt="ToggleContacts" src="minus_icon.gif" id="ContactsExpand" class="ContactImage" /> </a> </b></p> <div id="divContacts"></div> </div> </td></tr> </table> </div> </form> </body> As you will notice there no longer is a placeholder to change your online status and I've also removed the placeholder that allowed you to change your personal message. The rest however is the same. Once rendered it should look like this :- The basis of this program is that you go to a specific page on a site if you are having a problem and chat to someone from the site to help solve your problem. You want this to all be automatic and for your user to do as little as possible to enable this. With the upcoming launch of Windows Live Messenger 9, this actually becomes scalable to a point as Messenger 9 allows for multiple presences on the same Live ID. Therefore you could have multiple team members, all sign into the same Live ID and all handling chats at the same time. The user comes along to your site where you have your Live Web Messenger application and is prompted to sign-in. This is the same process and code as in the previous article so I won't regurgitate it here. Basically they are taken away from your site to the Windows Live login site, they enter their credentials and are then taken back to your site. The sign-in screen actually gets presented to them as a pop-up window so as not to completely take them away from your site. You application changes to reflect the fact that the user is signing in. At this point the application is awaiting the token back from the Windows Live Login site saying that the user is authenticated. Once signed in the user is able to chat to the help desk representative :- As you will notice from the above screen shot, we don't display all of the users contacts, we only display the help desk contact. Why do we even want to display this? Well it's helpful to see whether someone is actually signed on and manning the online help desk or not, as is reflected in the status displayed next to the contact (in the above example the person is not currently online). So what changes in the code do we need from my previous articles to get this to work? Basically it all happens in the displayContacts() routine :-
function displayContacts() {var sb = new StringBuilder(); var HelpDeskIndex = null; _addressList = new Array(_user.get_contacts().get_count());var groupList = new Array(_user.get_groups().get_count()); var enum2 = _user.get_groups().getEnumerator(); var enum1 = _user.get_contacts().getEnumerator(); var groupindex = 0;index = 0; while (enum2.moveNext()) { var c = enum2.get_current();var _contacts = new Array(c.get_contacts().get_count()); var enum3 = c.get_contacts().getEnumerator(); while (enum3.moveNext()) { var contact = enum3.get_current(); var address = contact.get_currentAddress(); var dispName = address.get_presence().get_displayName(); var currAddress = address.get_address(); var status = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, address.get_presence().get_status()); //Check to see if Helpdesk account is presentif(currAddress.toLowerCase() == "Your helpdesk address") { HelpDeskAdded = true;var statusimg = null; switch(status) {case "online": statusimg = "<img src='online.gif' class='ContactImage' alt='online' />"; break;case "offline": statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;case "appearOffline": statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;case "away": statusimg = "<img src='away.gif' class='ContactImage' alt='away' />"; break;case "beRightBack": statusimg = "<img src='away.gif' class='ContactImage' alt='beRightBack' />"; break;case "busy": statusimg = "<img src='busy.gif' class='ContactImage' alt='busy' />"; break;case "idle": statusimg = "<img src='away.gif' class='ContactImage' alt='idle' />"; break;case "inACall": statusimg = "<img src='busy.gif' class='ContactImage' alt='InACall' />"; break;case "outToLunch": statusimg = "<img src='away.gif' class='ContactImage' alt='OutToLunch' />"; break; default: statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;} var statusLine = ''; var strDelete = ''; _addressList[index] = address; if (dispName !== '') {statusLine = '<a href=\'javascript:createConv(' + index + ')\'>' + statusimg + dispName + '</a>'; } else {statusLine = '<a href=\'javascript:createConv(' + index + ')\'>' + statusimg + currAddress + '</a>'; } sb.append(statusLine); HelpDeskIndex = index; } index++; } groupindex++; index = 0; while (enum1.moveNext()) { var contact = enum1.get_current(); var address = contact.get_currentAddress(); var dispName = address.get_presence().get_displayName(); var currAddress = address.get_address(); var status = Enum.toString(Microsoft.Live.Messenger.PresenceStatus, address.get_presence().get_status());if(currAddress.toLowerCase() == "Your helpdesk address") { HelpDeskAdded = true; //Change status to an imagevar statusimg = null; switch(status) {case "online": statusimg = "<img src='online.gif' class='ContactImage' alt='online' />"; break;case "offline": statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;case "appearOffline": statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;case "away": statusimg = "<img src='away.gif' class='ContactImage' alt='away' />"; break;case "beRightBack": statusimg = "<img src='away.gif' class='ContactImage' alt='beRightBack' />"; break;case "busy": statusimg = "<img src='busy.gif' class='ContactImage' alt='busy' />"; break;case "idle": statusimg = "<img src='away.gif' class='ContactImage' alt='idle' />"; break;case "inACall": statusimg = "<img src='busy.gif' class='ContactImage' alt='InACall' />"; break;case "outToLunch": statusimg = "<img src='away.gif' class='ContactImage' alt='OutToLunch' />"; break; default: statusimg = "<img src='offline.gif' class='ContactImage' alt='offline' />"; break;} var statusLine = ''; var strDelete = ''; _addressList[index] = address; if (dispName !== '') {statusLine = '<a href=\'javascript:createConv(' + index + ')\'>' + statusimg + dispName + '</a>'; } else {statusLine = '<a href=\'javascript:createConv(' + index + ')\'>' + statusimg + currAddress + '</a>'; } sb.append(statusLine); HelpDeskIndex = index; } index++; } groupindex++; } document.getElementById('divContacts').innerHTML = sb.toString();if(HelpDeskAdded == true) {createConv(HelpDeskIndex); } else {alert(HelpDeskAdded); var helpDeskContact = "Your helpdesk address"; if(_user !== null) {alert(_user); _user.addContact(helpDeskContact, "Please accept in order to converse with the helpdesk", null); HelpDeskAdded = true;} } } Overall this routine is very similar to the displayContacts() routine explained thoroughly in my previous articles however there are a few changes and also a hack (workaround) to a problem I came across, which I'll get to in a minute. if(currAddress.toLowerCase() == "your helpdesk address") Simply replace "your helpdesk address" with your help desks live id. Make sure however that it is all in lower case as you'll see from the line of code that that's how the code does the comparison. If the contact is found then we get the contacts status and create a string to display their information in the contacts section at the bottom of the application. Now you'll notice from the code that this basic routine looks like it's present twice. This is actually the quick hack. The reason for this is the way Live Contacts can be stored. Most contacts are actually assigned to a group and you may have multiple groups with multiple contacts in each. However some contacts are actually stored outside of groups and are in effect free floating. This hack gets around that problem. The first routine searches through all the contacts that belong to groups, the second section (which is essentially the same code) searches through the contacts that aren't assigned to any group. if(HelpDeskAdded == true) {createConv(HelpDeskIndex); } else {var helpDeskContact = "Hackersoft@live.com"; if(_user !== null) {_user.addContact(helpDeskContact, "Please accept in order to converse with the helpdesk", null); HelpDeskAdded = true;} }
At the bottom we have the check to see whether the help desk contact has been added or not. If it's already present then we are ready to start a conversation, if not then we need to add the help desk contact to the users contact list. The HelpDeskAdded variable is a global variable defined later in the code. And that's basically it. One last point, I came across a bug in my previous articles. Before I had the :- index = 0;
placed within the loop, this actually caused problems when trying to chat with the correct contact. This has now been moved outside of the loop. For the complete source file see this post (due to limitations in Live Spaces) With this you now have a fully functional interactive help desk chat application that you can add to your site. June 18 Review - Advanced Asp.Net Ajax Server Controls for .Net Framework 3.5
Technorati Tags: Advanced Asp.Net Ajax Server Controls, Addison Wesley, Book Review, Ajax, Server Controls, Visual Studio 2008, Asp.Net May 21 How to use Teleriks' RadChart control within SharepointTechnorati Tags: Telerik, RadChart, Sharepoint 2007, MOSS 2007, Web Charts in Sharepoint, Telerik RadChart in Sharepoint I have been playing around with the Telerik controls over the past couple of months and decided to see if I could incorporate their RadChart control into Sharepoint. The basis was to create a custom web part that houses the RadChart control. That web part then points to a list and gets its data from the list and creates the chart. It's a fairly easy process but there are a couple of gotchas to watch out for. So let's get started. The first thing you need to do is to download the "Dev" zip file from Telerik so that you can do a manual deployment, rather than the normal automated MSI file. Once you have that, unzip it. There are two things you need to deploy from this. Open up Windows Explorer on your Sharepoint box and browse to your Sharepoint Site directory (usually found under c:\inetpub\wwwroot\wss\VirtualDirectories somewhere). Then open up the bin directory as this is where you will copy the Web Chart dll. Next you need to register the RadChart so that it's marked as safe in the web.config file. Open the web.config file for your Sharepoint site and add the following to the end of the SafeControls list :- <SafeControl Assembly="RadChart.Net2, Version=4.1.1.0, Culture=neutral, PublicKeyToken=d14f3dcc8e3e8763" Namespace="Telerik.WebControls" TypeName="*" Safe="True" /> This is the RadChart 2007 Q3 SP1 version. If you've got a different version of the RadChart then these values will be slightly different, namely the version number and the PublicKeyToken. Now Sharepoint can theoretically display charts, but without some custom coding it obviously won't be able to. Next open your copy of Visual Studio and create a class file (I actually used Visual Studio 2005 SP1 for this and download the Sharepoint Extensions for Visual Studio 2005 and used the Sharepoint Web Part project to build this with. Makes things slightly easier). Once you have your project open in Visual Studio, you need to include a reference to the RadChart dll (In solution explorer, right click and select Add Reference then browse to where the dll resides). Now to the code :- using System; using System.Runtime.InteropServices; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Serialization; using Telerik.WebControls; using Telerik.Charting; using System.Runtime.CompilerServices; using System.Reflection; using System.Security; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Collections.Generic; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; using Microsoft.SharePoint.WebPartPages; [assembly:AllowPartiallyTrustedCallers] This first part are the includes that you will need along with the AllowPartiallyTrustedCallers attribute which is required for Sharepoint. namespace WebChart { [Guid("2bee1192-339c-4f85-849d-2df6f24c24d4")] public class WebChartPart : System.Web.UI.WebControls.WebParts.WebPart { #region Private Properties private string m_Web = string.Empty; private string m_Site = string.Empty; private string m_List = string.Empty; private string m_ChartData = string.Empty; private string m_ChartText = "Title"; #endregion Next we define our class and namespace and also create some local variables. These variables will be used by public properties that will show up Sharepoint to allow users to set which list, columns etc. to get the data from. #region Editor Properties [WebBrowsable(true), Category("Chart Settings"), /* DefaultValue(m_Web), */ Personalizable(PersonalizationScope.Shared), DisplayName("MOSS Site"), WebDisplayName("MOSS Site"), WebDescription("The Top Level MOSS Site where the list resides.")] public string Web { get { return m_Web; } set { m_Web = value; } } [WebBrowsable(true), Category("Chart Settings"), /* DefaultValue(m_Site), */ Personalizable(PersonalizationScope.Shared), DisplayName("Sub Site"), WebDisplayName("Sub Site"), WebDescription("The actual MOSS Site where the list resides.")] public string MOSSSite { get { return m_Site; } set { m_Site = value; } } [WebBrowsable(true), Category("Chart Settings"), Personalizable(PersonalizationScope.Shared), DisplayName("Sub Site"), WebDisplayName("List Name"), WebDescription("The list where the chart data resides.")] public string MOSSList { get { return m_List; } set { m_List = value; } } [WebBrowsable(true), Category("Chart Settings"), /* DefaultValue(m_Site), */ Personalizable(PersonalizationScope.Shared), DisplayName("Sub Site"), WebDisplayName("Chart Data"), WebDescription("The numeric column within the list to get the data.")] public string ChartData { get { return m_ChartData; } set { m_ChartData = value; } } [WebBrowsable(true)] [Category("Chart Settings")] /* [DefaultValue(m_Site)] */ [Personalizable(PersonalizationScope.Shared)] [DisplayName("Sub Site")] [WebDisplayName("Chart Text")] [WebDescription("The text column within the list to get the chart text.")] public string ChartText { get { return m_ChartText; } set { m_ChartText = value; } } #endregion And here are the public properties. One for each of the private variables we declared earlier. These all follow the same procedure. First you decorate the property with attributes that tell Sharepoint which grouping to list them under in the Edit Properties pane, what you wish to call this property, how to store the values within Sharepoint etc. Then we just have a standard getter/setter pair pointing back to our private variables. Next we need to instantiate our RadChart control :- #region Controls Telerik.WebControls.RadChart chart = new RadChart(); #endregion We don't need to do anything with the class constructor. However we do need to override the CreateChildControls method. This is where we will be adding the RadChart to the web parts controls for display :- public WebChartPart() { } protected override void CreateChildControls() { base.CreateChildControls(); if (m_List != string.Empty) { GetSites(); //GetFolders(); chart.UseSession = false; chart.RadControlsDir = "~/_wpresources/RadControls"; chart.TempImagesFolder = "~/_wpresources/RadControls/Chart/TempImages"; BuildChart(); this.Controls.Add(chart); } } First we make sure any other controls and created, then check to see if the List public property actually has a value. If not then there obviously won't be any data for the chart so we simply don't display the chart. If it does have a value then we get all the data to build the chart and then display the control. There are a couple of things worthy of mention here :-
As noted above there is something else that you need to copy over from your RadControls zip file. Go to where you unzipped all the controls then go to the Net2\RadControls directory. Within there you will find a Chart folder. Copy this folder. Next to go c:\program files\common files\microsoft shared\web server extensions\wpresources and create a folder in there called RadControls. Paste the Chart directory you just copied into the RadControls folder. Back to Visual Studio and our next method :- private void GetSites() { if (m_Web == string.Empty) { SPWeb myweb = SPControl.GetContextWeb(this.Context); m_Web = myweb.Url; } } All that this method does is pre-populate the web site public property with the url of the current site where the web part is deployed. private void BuildChart() { ArrayList numbers = new ArrayList(); ArrayList text = new ArrayList(); SPWeb myweb = SPControl.GetContextWeb(this.Context); SPList list = myweb.Lists[m_List]; for (int i = 0; i < list.ItemCount; i++) { SPListItem item = list.Items[i]; numbers.Add(Convert.ToInt32(item[m_ChartData].ToString())); text.Add(item[m_ChartText].ToString()); } chart.ChartTitle.TextBlock.Text = list.Title; ChartSeries series = new ChartSeries(); series.Name = list.Title; series.Type = ChartSeriesType.Pie; for (int i = 0; i < numbers.Count; i++) { int j = Convert.ToInt32(numbers[i]); series.AddItem(j, Convert.ToString(text[i])); } chart.Series.Add(series); } } } Finally we have our BuildChart method. We first create two lists, one to hold the text to be displayed and one to hold the numerical data that will make up the chart. Next we fill these two arrays from the list pointed to by the values entered in the Edit Web Part Properties window that the user will enter. Compile your dll, put it in your Sharepoint sites bin folder and add it to the safecontrols. if you use the code below then your safecontrol entry should look similar to :- <SafeControl Assembly="WebChart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9f4da00116c38ec5" Namespace="WebChart" TypeName="*" Safe="True" /> Add your web part to the page, edit the web part properties to point to a valid site, list and data and there you have it. The sample list I used I only put two values in for testing and here are the results :- You now have a fully functional RadChart control that can be embedded in your Sharepoint sites. Here is the full code for the above :- using System; using System.Runtime.InteropServices; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Serialization; using Telerik.WebControls; using Telerik.Charting; using System.Runtime.CompilerServices; using System.Reflection; using System.Security; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.Collections.Generic; using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls; using Microsoft.SharePoint.WebPartPages; [assembly:AllowPartiallyTrustedCallers] namespace WebChart { [Guid("2bee1192-339c-4f85-849d-2df6f24c24d4")] public class WebChartPart : System.Web.UI.WebControls.WebParts.WebPart { #region Private Properties private string m_Web = string.Empty; private string m_Site = string.Empty; private string m_List = string.Empty; private string m_ChartData = string.Empty; | ||||||||||||||||||||||||||||||||||||