Monday, December 18, 2006

The brains behind jQuery

Originally a one-man show, jQuery has evolved far enough to be managed by a team of developers (work on the jQuery code), evangelists (promoting the product - e.g. to developers using Cold Fusion, Drupal, Ruby on Rails etc), web developers (working on the jQuery website backend) and designers (jQuery website, frontend). For more information and a list of the members - jQuery: Blog: » Meet The People Behind jQuery.

Thursday, December 14, 2006

Get remote page contents (ASPX C#)

A simple function for getting the contents of another page in your code behind

private string GetHTML(string url)
{
 WebRequest request = WebRequest.Create(url);
 // use logged in user credentials
 request.Credentials = CredentialCache.DefaultCredentials;
 try
 {
  // get the response
  HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  // set the content length
  int contentLength = (int)response.ContentLength;
  // get the stream
  Stream responseStream = response.GetResponseStream();
  // Pipes the stream to a higher level stream reader with the required encoding format. 
  StreamReader readStream = new StreamReader(responseStream, Response.ContentEncoding);
  // create a char array
  char[] data = new char[contentLength];
  // load from the stream into the char array
  readStream.Read(data, 0, contentLength);
  // return the data as a string
  return new String(data);
 }
 catch(Exception ex)
 {
  return string.Empty;
 }
 return string.Empty;
}

Wednesday, December 13, 2006

New Version (1.0.4) of jQuery is out

As detailed in the post jQuery: Blog: » jQuery 1.0.4 there are quite a few bug fixes as well as some enhancements to its AJAX functionality. While the new additions are useful, the fact it is a point/minor release (i.e. from 1.0.3 to 1.0.4 rather than to 1.1) can be of an issue as generally minor releases are for bug fixes only not API changes. Although, to be fair, it looks like nothing was removed from the API and if you tried to use the new features on a page using the old version, they simply would not work. Like in previous releases, a lot of the fixes have been provided by Jörn Zaefferer.

Tuesday, December 12, 2006

A simple solution to Firebug not picking up styles

When you upgrade Firefox from 1.5 to 2 and are a user of the Firebug 1.0 beta, you may notice that when you inspect an element you can't see the styles - i.e. you get an error message - 'Unable to show styles. You must install DOM Inspector.'. This can happen even if you have the DOM Inspector installed. You may also notice that you cannot see the styles in that either. So the problem seems to be that the DOM Inspector is not upgraded to the latest version when you upgrade (or some old files are not removed).

To get it working, simply close all instances of Firefox, navigate to the components directory in the Firefox application folder (i.e C:\Program Files\Mozilla Firefox\components and delete all files beginning with the word inspector. Once you have done this, reinstall Firefox to the same folder. When you start Firefox again, you should now be able to edit and disable styles within Firebug.

What I have noticed, is that after reinstalling, the files that were deleted are not in the components folder, which suggests that the DOM Inspector actually uses a feature built into Firefox (i.e. it just provides a GUI interface) and it may be the case that Firebug can actually work without installing the DOM Inspector. Infact I have disabled it and Firebug still works.

Tuesday, December 05, 2006

Select dropdown options using jQuery

Finally an update to my Select box manipulation collection of plugins for jQuery. You can select options that match a given string or regular expression. The original code for this particular plugin was created by Mathias Bank, with a modification by me to use a regular expression as a parameter as well as a string. He wrote it over a month ago, but I have only just got round to implementing it.

Monday, December 04, 2006

Firebug Lite

While Firebug only works on Firefox, there is an option for other browsers (IE, Opera, Safari) called Firebug Lite. While not as powerful as the full Firebug, it is still a good way to debug for other browsers. You just include it on your page as you would any external JavaScript file and then press F12 on the page to show the console.

Firebug 1.0 Beta 1

Firebug 1.0 is available as a beta version. Initially it was going to be a commercial extension, but it looks like it will be open source. Hopefully it will be maintained (and not just by one or two people), although I am not sure how it can be improved (aside from working on IE as well). Very good for debugging (JavaScript and CSS) as you can set breakpoints, view a box-model representation of any selected element, disable CSS (down to specific properties (i.e. font-size)) and more.

Get Firebug and make a donation to show your appreciation for Joe Hewitt's hard work.

Friday, December 01, 2006

Mono Migration Analyzer (MoMA)

Mono Migration Analyzer (MoMA) is an application (requiring .NET 2.0 or Mono 1.2) that you can use to analyse your assemblies (.exe, .dll) to see if there are any incompatibilities with Mono. While it can't analyse web pages (.aspx, .ascx, .ashx etc), it can be used on any assemblies compiled for use within your website that are stored in the bin folder under your site root. Once done, you can submit a report (that only contains methods you call that are not implemented) which will help the Mono team prioritise their work (as it reflects real world applications).

Microsoft eases IE6 development

Microsoft has released a Virtual PC Image containing Windows XP SP2 and IE6. It is free (so you don't need to buy another license for Windows). Finally there is an official way to test websites in both IE6 and IE7 without extra cost to you. For more details - IEBlog : IE6 and IE7 Running on a Single Machine. Expires on April 1, 2007 so hopefully they will release a new image, or a way to run IE6 without Virtual PC by then.

Monday, November 27, 2006

Using WebHandlers with jQuery (ASP.NET 2)

A WebHandler is a useful way for updating data without needed to resort to an ASP.NET page (with its additional overhead). You can decide what content type to send (so can send data as text/html, text/plain or even image/jpeg - all can be handled with the same file) and don't have to worry about view state, but you cannot use the WYSIWYG utilities you may normally use so they are more suited to those comfortable with coding by hand. Combine this with jQuery and you have an easy way to update records (or do any kind of processing on the server) without using postbacks (and it can result in a more efficient application).

The ASP.NET page

<%@ Page Language="C#" %>

<!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">
<head runat="server">
 <title>Test Page</title>

 <script src="jquery-latest.pack.js" type="text/javascript"></script>

 <script type="text/javascript">
 $(
  function()
  {
   $("input[@name$=AddRecord][@type=submit]").click(addRecord);
  }
 )
 function addRecord()
 {
  var data = $("#addcontact input[@type=text], #addcontact textarea").serialize();
  var tmp = data.split("&");
  var tmp2 = [];
  var fielddata;
  for(var f in tmp)
  {
   // $'s are used to make unique names (eg ctl00$FirstName, ctl00$MyPanel$FirstName), so it is split
   fielddata = tmp[f].split("$");
   // deliminator in .NET 1.1 is ':' so tmp[f].split(":") should hopefully work
   // get the item in the array (which is the field name and data)
   tmp2[tmp2.length] = fielddata[fielddata.length - 1];
  }
  // set new data
  data = tmp2.join("&");
  $.ajax(
   {
    type: "POST",
    url: "addrecord.ashx",
    data: data,
    success: function(msg)
    {
     alert(msg);
    }
   }
  );
  return false;
 }
 </script>

</head>
<body>
 <form runat="server">
  <div id="addcontact">
   <p>
    First Name:
    <asp:TextBox ID="FirstName" runat="server"></asp:TextBox></p>
   <p>
    Last Name:
    <asp:TextBox ID="LastName" runat="server"></asp:TextBox></p>
   <p>
    Address:<br />
    <asp:TextBox ID="Address" runat="server" TextMode="MultiLine"></asp:TextBox>
   </p>
   <asp:Button ID="AddRecord" runat="server" Text="Add" />
  </div>
 </form>
</body>
</html>

The WebHandler

Simply create a blank text file with the extension ashx, e.g. addrecord.ashx in the same folder as you ASP.NET page (although it is named addrecord, it could be used to modify existing records, get an associated photo etc.

<%@ WebHandler Language="C#" Class="AddRecord" %>

using System;
using System.Collections.Specialized;
using System.Web;

public class AddRecord : IHttpHandler
{

 public void ProcessRequest(HttpContext ctx)
 {
  ctx.Response.ContentType = "text/plain";
  if (ctx.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
  {
   // get all form items
   NameValueCollection formItems = ctx.Request.Form;
   // loop through fields in the form
   foreach (string field in formItems)
   {
    ctx.Response.Write(field + " : " + formItems[field] + "\n");
   }
  }
  else
  {
   ctx.Response.Write("Access denied");
  }
 }

 public bool IsReusable
 {
  get
  {
   return false;
  }
 }

}

Tuesday, November 21, 2006

Link: Really Simple Live Comment Preview

You can use jQuery to show a live preview of comments before you post them (so you can see how they will display when you submit) and it is very simple to do. You can find more details on the Learning jQuery site: Really Simple Live Comment Preview. You can see how it works by filling in the comments form at the bottom of the aforementioned post. It could be improved if the live preview was styled like it would be if you posted the message (with your name and date before the comment), rather than just showing the comment and possibly malicious tags (script, object) not interpreted.

Friday, November 17, 2006

Link: Open Source C# Projects

While I think PHP (and other open source languages) developers have more of a positive attitude to open source (perhaps because of a different mindset in general compared to .NET developers and the cost of Visual Studio) there is some software available under some kind of open source license and a lot of it can be found via: http://csharp-source.net/

Thursday, November 09, 2006

Text Clip Generator for jQuery

As a user of jQuery (jquery.com) and Programmer's Notepad 2 (www.pnotepad.org) I find that the text clips feature of PN2 can help productivity (and also be used as a quick reference of the methods available), so I have created a command line tool (written in .NET 1.1) that can generate these clips.

Source code (BSD style license) and a binary are available for download from jQuery - Text Clip Generator

Hopefully this will be of use to someone.

Tuesday, November 07, 2006

Link: Opera Developer Community

Opera Developer Community - a community orientated site for web developers working with the Opera Web Browser. Includes several official JavaScript libraries created by Opera Software, including a Calendar, Feed Reader, Web Page Scraper and Tooltip library.

Thursday, October 26, 2006

jQuery Tip: Highlight row on hover

This snippet applies a class when you hover over a table row and removes it when you move the mouse out. Useful when you have a table with many rows and want to improve readability.

Define your stylesheet in head:

<style type="text/css">
<!--
 #mytable {
  border-collapse: collapse;
  width: 300px;
 }
 #mytable th,
 #mytable td
 {
  border: 1px solid #000;
  padding: 3px;
 }
 #mytable tr.highlight {
  background-color: #eee;
 }
//-->
</style>

JavaScript (also in head)

<script type="text/javascript">
<!--
$(
 function()
 {
  $("#mytable tr").hover(
   function()
   {
    $(this).addClass("highlight");
   },
   function()
   {
    $(this).removeClass("highlight");
   }
  )
 }
)
//-->
</script>

Your table (with id mytable) in body

<table id="mytable">
 <tr>
  <th>Foo</th>
  <td>Lorem</td>
  <td>Ipsum</td>
 </tr>
 <tr>
  <th>Bar</th>
  <td>Dolor</td>
  <td>Sit</td>
 </tr>
 <tr>
  <th>Baz</th>
  <td>Amet</td>
  <td>Consectetuer</td>
 </tr>
</table>

Now whenever you move your mouse over a row in the table, the background colour is changed to gray (#eee is a shade of gray).

Friday, October 20, 2006

Link: JavaScript Management with ASP.NET

JavaScript Management with ASP.NET outlines how you can make managing JavaScript easier in ASP.NET. It uses an XML file to store the JavaScript code (so only one file needs to be edited) and a HTTP Handler / Utility class to request and obtain the JavaScript code. The downside to this approach is that it is less portable than simply having separate files - you would need to write code for extracting the JavaScript from the XML file if you use another server side language like PHP.

Preloading Images the jQuery way

jQuery is capable of creating elements without using the DOM (i.e. document.createElement). You can take advantage of this to preload images, and it involves less code that most other solutions - if you ignore the fact that jQuery has overhead and assume you are using jQuery for tasks other than preloading.

jQuery.preloadImages = function()
{
    for(var i = 0; i<arguments.length; i++)
    {
        jQuery("<img>").attr("src", arguments[i]);
    }
}

You can then preload images before the page has fully loaded. Useful for when you implement rollover images (as there will not be the usual delay you normally get after mousing over a rollover image).

$.preloadImages("foo.jpg", "bar.gif", "baz.png");
$(
    function()
    {
        alert("document ready");
    }
)

Thursday, October 19, 2006

jQuery Tip: Open links in new windows with valid (X)HTML Strict DocType

Update: forgot the return false (without it, the page would open in a new window and replace the current page).

In (X)HTML Strict, anchor tags linking to other pages are not allowed to have the target attribute. Because of this, links can not be opened in a new window if the page validates. However, with jQuery and the addition of a class to anchors that open in new windows: <a href="http://jquery.com" class="external">jQuery</a> you can do this in just one line of code: $("a.external").click(function(){window.open(this.href);return false;});. If you add any more links dynamically (i.e. through AJAX), you would have to run this again, but preferably not anonymously (i.e. inline function).

function openWindow()
{
    window.open(this.href);
    return false;
}
// shorthand for $(document).ready(function(){...})
$(
    function()
    {
        $("a.external").click(openWindow);
    }
)

Friday, October 06, 2006

Fixing quotes with jQuery

It is easy to solve the problem with quotes in Internet Explorer (the problem being that they are not contained in quotation marks) by using jQuery.

All it takes is one line of code:

$("q").prepend("&#8220;").append("&#8221;");

However, that means there are two quotes for browsers that do support the tag. A browser sniff is all that is needed (generally it is a bad idea to do that, but some circumstances require it).

if($.browser.msie)
{
 $("q").prepend("&#8220;").append("&#8221;");
}

Demo page

Thursday, October 05, 2006

Google Code Search

Google now allows you to search for source code via Google Code Search that is freely available under several open source licenses (e.g. (L)GPL, BSD, MIT, Apache etc).

Wednesday, October 04, 2006

jQuery Text Clips for PN2 (updated)

An update of my text clips for Programmers Notepad 2 (jQuery version 1.0.1). Download.

Friday, September 22, 2006

jQuery Plugin: newsticker

A news ticker plugin using jQuery. Create a list of news items:

<ul id="news">
  <li>News Item 1</li>
  <li>News Item 2</li>
  <li>News Item 3</li>
  <li>News Item 4</li>
  <li>News Item 5</li>
</ul>

Then apply the plugin: $("#news").newsticker() to display each one in turn.

Wednesday, September 13, 2006

Checkbox manipulation using jQuery

I have done a set of plugins for working with multiple checkboxes on a page (check, uncheck and toggle) - checkbox manipulation.

Sunday, September 03, 2006

Link: Learning jQuery

Learning jQuery is a new blog all about teaching the basics as well as tutorials, demos and perhaps advanced subjects in the future. There are only a few posts at the moment (because it is so new), but I expect it to be become more valuable (for beginners and intermediate/advanced jQuery developers alike).

Saturday, August 26, 2006

jQuery 1.0

jQuery, the JavaScript library by John Resig is now at version 1.0 and replaces the last stable release (dated May 12). For more information and to download, read about it on the jQuery Blog: jQuery 1.0. Many new feature - including AJAX form submission and more methods for navigating the DOM.

The main jQuery site is in the process of being updated, so at the time of this posting, the download links on the home page are for the older stable version.

Tuesday, August 22, 2006

Windows Live Writer

Windows Live Writer is a tool for writing posts to your blog. It is targeted at Windows Live Spaces, but also works with other blogging services (like Blogger). It is a WYSIWYG editor (which generates better markup than Word or older versions of Frontpage), but you can also edit the HTML directly.

Rather that knowing the link to the API used for publishing, you simple provide your blog address and username/password and it discovers what service you are using (although this will take a longer time that just providing the publishing API URL). It publishes a post on your blog to detect styles that are being used (so you may need to delete the post it makes).

Overall, quite a good tool that is easy to use.

Monday, August 21, 2006

Link: Web Devout

Web Devout is a useful site with comprehensive tables listing the state of standards support in various web browsers (Internet Explorer, Firefox, Opera, Safari and Konqueror). It includes the levels of HTML, CSS, DOM and ECMAScript (aka JavaScript) support for all these browsers. It also has other useful information, articles and tools.

Tuesday, August 15, 2006

osalt.com - Open Source Alternatives

osalt.com is a site that lists Open Source alternatives to commercial applications. It is broken down into the following categories:

  • business
  • communications
  • databases
  • development
  • graphic applications
  • internet & networking
  • multimedia & audio
  • security & privacy
  • system utilities
  • web development

While most commercial products have an free alternative, there are sometimes features that the commercial product offers the the free one doesn't. For instance, you can generate PDF's with PDFCreator, but if you want to edit them (or add form fields), Adobe Acrobat is the only real option.

Sometimes the Open Source counterpart can be more unstable and lack technical support (there will be exceptions to that though - generally when the release version is greater than 1.0). With each release though, stability normally gets better.

Tuesday, August 08, 2006

Dynamically create radio buttons with DOM (even in IE)

Currently, the way to create radio buttons dynamically in Internet Explorer is to use document.createElement("<input type='checkbox'>"). However, that is not very cross browser friendly. There is an easier way, that involves using jQuery and the correct DOM methods:

First of all, the HTML:

<form action="mypage.php">
<div id="radios"></div">
</form>

Now add the radio buttons to the radios element.

$(window).load(
 function()
 {
  $("#radios").each(
   function()
   {
    var radio = document.createElement("input");
    radio.name = "myradio";
    radio.type = "radio";
    radio.value = "radio1";
    this.appendChild(radio);
    for(i = 2; i < 10; i++)
    {
     radio = radio.cloneNode(true);
     radio.value = "radio" + i;
     this.appendChild(radio);
    }
    fixRadios(this.id);
   }
  )
 }
);

function fixRadios(parent)
{
 // uncheck existing radio buttons
 $("#" + parent + " input[@type=radio]").click(
  function()
  {
   
   $("[@name=" + this.name + "]").each(
    function()
    {
     this.checked = false;
    }
   )
   this.checked = true;
  }
 )
}

To see it in action: Dynamically create radio buttons with DOM

Monday, August 07, 2006

autocomplete plugin (for jQuery), by Dylan Verheul

A handy plugin for adding auto complete capabilities to your web pages - autocomplete. Start typing in a bird name to see it in action.

Monday, July 31, 2006

Find out how many days are in a given month (JavaScript)

Often an array is used to figure out how many days there are in a month (and extra work is used to figure out how many days are in February (depending on the leap year)). This method uses the inbuilt Date object, so should be user locale friendly (assuming 12 months in a year). For instance, to find out how many days are in February 2008, you would do: daysInMonth(2008, 2)

function daysInMonth(year, month)
{
 // month is zero based, so take away 1
 month = --month;
 // first day of the following month
 var nextDay;
 // if last month of year, then use first day of following year
 if(month == 11)
 {
  nextDay = new Date(++year, 0);
 }
 // otherwise use next day of current year
 else
 {
  nextDay = new Date(year, ++month);
 }
 // take away a millisecond to get required date
 var requiredDate = new Date(nextDay - 1);
 // return the day
 return requiredDate.getDate();
}

Friday, July 28, 2006

Source Code Hosting from Google

Google now offers hosting for your source code: Google Code - Project Hosting. It seems to use subversion for version control and you can use your Google username (the password is generated for you) to check out code. Labels are used instead of set categories - it would be better if they were used to complement categories instead. It has very few licenses to choose from (which in some ways is good as there are so many open source licenses to choose from) - it lists only the most popular ones.

There are a few downsides though:

  • Code has to be downloaded via SVN (browser or client application), no zip/exe/tar.gz releases
  • Latest updates not shown on homepage (due to lack of releases feature - listing SVN updates would not be very helpful as they page will be constantly changing)
  • No popularity / activity rating (listing most active and popular projects on home page)
  • No Atom (Google don't use RSS) feeds (which is a bit of a surprise)
  • No ability to request features
  • Search page doesn't indicate how it is sorted or offer any status next to results
  • No category view (as tags are used instead)
  • No development status (beta, alpha, stable etc) feature - you use labels instead

If you mostly work with source code and only need the absolute essentials (issue tracking and a place to store your code), this may be fine. But if your needs are greater, CodePlex or SourceForge are better.

I wouldn't expect it to have as many features as SourceForge, but it should at least be at a similar level as CodePlex.

Thursday, July 27, 2006

CodePlex

Microsoft has a community site for code called CodePlex. Like SourceForge, you can create your own projects and download code from existing ones. The good think is that it does not require Microsoft Passport to register / sign in (unlike GotDotNet). However, it is not categorised - i.e. broken down by type (database, desktop, finance, games etc), programming language (C#, VB.NET) or interface (WinForms, WebForms).

Despite that, it is a lot easier to navigate than SourceForge and contains several useful projects (IronPython, Jad Engine - C# + MDX 3D Game Engine, "Atlas" Control Toolkit and more). It also allow GPL'd projects (which I don't think GotDotNet does) - Jad is under the LGPL.

A bit of AJAX would help improve the site (as you need JavaScript just to sign in, so visitors will likely have it enabled). For instance, when you go to a project's page you see a series of tabs, which you then click on the go to another page. If instead of that it loaded the content into the current page, it would be more responsive.

Tuesday, July 25, 2006

Link: What is "Modern Software Development"?

From Coding Horror: What is "Modern Software Development"?. Old checklists (2000 and 1997), but still relevant today.


Tags:

Thursday, July 20, 2006

Link: HTML Color Code Combination Chooser

The HTML Color Code Combination Chooser is a very useful web based utility for picking a colour pallet with colours that compliment each other.


Tags:

Tuesday, July 18, 2006

jQuery Plugin: sortOptions

jQuery Plugin: sortOptions is a plugin that sorts the options in select dropdowns - either ascending (the default), or descending.

jQuery Plugin: removeOption

The jQuery plugin addOption now has a complementary plugin for doing the opposite: removeOption. Both available via jQuery Plugins: addOption/removeOption.

Monday, July 17, 2006

jQuery Plugin: addOption

New plugin: addOption allows you to add items to a select dropdown list via jQuery.

Tuesday, July 11, 2006

jQuery Text Clips for PN2

I have done some jQuery text clips for use in Programmer's Notepad 2. Available, along with the others I have done at: Text Clips for Programmer's Notepad 2

Friday, July 07, 2006

Link: Working with Files and Directories using ASP.NET

Working with Files and Directories using ASP.NET. Handy reference (with snippets in C#) for when you want to do things (creating, renaming, deleting, moving, enumeration, getting properties (e.g. last modified) etc) with files and directories in ASP.NET


Tags: , ,

Friday, June 30, 2006

Create CSS Class (JavaScript)

This function (createCSSClass) creates a new class with the given style. However, it does not work in version of Opera prior to 9, due to lack of support for document.styleSheets. For example, if you want all text in a pre element bold, you would do createCSSClass("pre", "font-weight: bold"). Note, that if you already have the rule defined, it will replace it, unless it is not a stylesheet with media type 'screen' (or media not set) or it is not the first linked/embedded screen stylesheet.

So for example, if you had the following:

<link rel="stylesheet" href="print.css" media="print" />
<link rel="stylesheet" href="screen.css" />
<style type="text/css">pre { border: 1px solid #000}</style>

When you do createCSSClass("pre", "font-weight: bold"), it will replace the rule in screen.css (or add it if it does not exist). Any styles defined in print.css and the following <style> will not be replaced.

The function itself:

function createCSSClass(selector, style)
{
 // using information found at: http://www.quirksmode.org/dom/w3c_css.html
 // doesn't work in older versions of Opera (< 9) due to lack of styleSheets support
 if(!document.styleSheets) return;
 if(document.getElementsByTagName("head").length == 0) return;
 var stylesheet;
 var mediaType;
 if(document.styleSheets.length > 0)
 {
  for(i = 0; i<document.styleSheets.length; i++)
  {
   if(document.styleSheets[i].disabled) continue;
   var media = document.styleSheets[i].media;
   mediaType = typeof media;
   // IE
   if(mediaType == "string")
   {
    if(media == "" || media.indexOf("screen") != -1)
    {
     styleSheet = document.styleSheets[i];
    }
   }
   else if(mediaType == "object")
   {
    if(media.mediaText == "" || media.mediaText.indexOf("screen") != -1)
    {
     styleSheet = document.styleSheets[i];
    }
   }
   // stylesheet found, so break out of loop
   if(typeof styleSheet != "undefined") break;
  }
 }
 // if no style sheet is found
 if(typeof styleSheet == "undefined")
 {
  // create a new style sheet
  var styleSheetElement = document.createElement("style");
  styleSheetElement.type = "text/css";
  // add to <head>
  document.getElementsByTagName("head")[0].appendChild(styleSheetElement);
  // select it
  for(i = 0; i<document.styleSheets.length; i++)
  {
   if(document.styleSheets[i].disabled) continue;
   styleSheet = document.styleSheets[i];
  }
  // get media type
  var media = styleSheet.media;
  mediaType = typeof media;
 }
 // IE
 if(mediaType == "string")
 {
  for(i = 0;i<styleSheet.rules.length;i++)
  {
   // if there is an existing rule set up, replace it
   if(styleSheet.rules[i].selectorText.toLowerCase() == selector.toLowerCase())
   {
    styleSheet.rules[i].style.cssText = style;
    return;
   }
  }
  // or add a new rule
  styleSheet.addRule(selector,style);
 }
 else if(mediaType == "object")
 {
  for(i = 0;i<styleSheet.cssRules.length;i++)
  {
   // if there is an existing rule set up, replace it
   if(styleSheet.cssRules[i].selectorText.toLowerCase() == selector.toLowerCase())
   {
    styleSheet.cssRules[i].style.cssText = style;
    return;
   }
  }
  // or insert new rule
  styleSheet.insertRule(selector + "{" + style + "}", styleSheet.cssRules.length);
 }
}

Monday, June 26, 2006

Date Manipulation - GoToWeek and WeekOfYear (C#)

GoToWeek goes to the specific week in a year (e.g. GoToWeek(2006, 10) would go return the start day of week 10 in 2006 - 27th February). WeekOfYear returns the given dates Week Number (e.g. GoToWeek(DateTime.Now) would return 27). Uses the current threads culture, so will work with whatever culture you have set the current thread to (e.g. System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-GB");).

private DateTime GoToWeek(int year, int week)
{
 // use the current culture
 System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
 // get first day of week from culture
 DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
 
 // new empty Date (so starts 01/01/0001)
 DateTime d = new DateTime();
 
 // year starts at 1, so take away 1 from desired year to prevent going to the next one
 d = d.AddYears(year - 1);
 
 // get day January 1st falls on
 int startDay = (int)d.DayOfWeek;
 
 // get the difference between the first day of the week, and the day January 1st starts on
 int difference = (int)fdow - startDay;
 // if it is positive (i.e. after first day of week), take away 7
 if(difference > 0)
 {
  difference = difference - 7;
 }
 
 // already on week 1, so add desired number of weeks - 1 * days in week
 if(week > 1)
 {
  d = d.AddDays((week - 1) * 7 + difference);
 }
 
 return d;
}

private int WeekOfYear(DateTime date)
{
 // use the current culture
 System.Globalization.CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
 // use current culture's calendar
 System.Globalization.Calendar cal = ci.Calendar;
 // get the calendar week rule (i.e. what determines the first week in the year)
 System.Globalization.CalendarWeekRule cwr = ci.DateTimeFormat.CalendarWeekRule;
 // get the first day of week for the current culture
 DayOfWeek fdow = ci.DateTimeFormat.FirstDayOfWeek;
 // return the week
 return cal.GetWeekOfYear(date, cwr, fdow);
}

Tags: , , , ,

Friday, June 23, 2006

jQuery Sample: Collapsible List

jQuery Sample: Collapsible List is a sample of how to do a collapsible list using jQuery.


Tags: ,

jQuery Plugin: numeric (update)

I have updated jQuery Plugin: numeric with a few bug fixes.

Thursday, June 22, 2006

StartOfWeek - get start of the week for supplied date (C#)

This function returns the date the week started from the supplied date. You can also supply which day is the start of the week through the overload. i.e. today is the 22nd June. StartOfWeek(DateTime.Now) would return 19th June. If the start day was Sunday, StartOfWeek(DateTime.Now, DayOfWeek.Sunday) would return 18th June.

public static DateTime StartOfWeek(DateTime date)
{
 return StartOfWeek(date, DayOfWeek.Monday);
}
 
public static DateTime StartOfWeek(DateTime date, DayOfWeek weekStart)
{
 // get the difference in days between the start of the week and the supplied dates day of week
 int difference = (int)weekStart - (int)date.DayOfWeek;
 // if it is positive (i.e. in future), take away 7
 if(difference > 0)
 {
  difference = difference - 7;
 }
 // return the new date
 return date.AddDays(difference);
}

Tags: , ,

Tuesday, June 20, 2006

jQuery Plugin: numeric

jQuery Plugin: numeric is a plugin for jQuery that allows only valid numbers in a text box input. There are a few limitations that I have not found the solution for though (listed on the page).

Monday, June 12, 2006

jQIR - jQuery Image Replacement

A plugin built on jQuery that replaces text with images (for prettier headings for example). Demo and code: jQIR - jQuery Image Replacement

jQuery Plugin: outlineTextInputs

A plugin built on jQuery that adds an outline when a text field gains focus. Demo and code: jQuery Plugin: outlineTextInputs


Tags: ,

Friday, June 02, 2006

Dean Edwards - Levels of JavaScript Knowledge

You may have read Levels of CSS knowledge and Levels of HTML knowledge which rank users based on what they know about the technology in question. Higher ranks are not always better (unless they are one of the top two) - knowledge may be lacking in areas of importance (like standards, semantics and accessibility).

Dean Edwards has done a version for JavaScript: Levels of JavaScript Knowledge. Filed under humour, so not to be taken too seriously.


Tags: ,

Tuesday, May 30, 2006

Webride - web page discussion

Webride.org allows you to have discussions on any pages you visit on the World Wide Web. Requires JavaScript and cookies enabled to signup and login (so not fully accessible). Doesn't have a rating system though (for users or pages). Uses CAPTCHA in the signup process (so hopefully spam should not be a major problem).

jQuery is used for some of its scripting backend. Provides an API so you can integrate some aspects of it on your own site (i.e. you could include comments people have made with Webride on your own pages, rather than visitors loading the Webride site).


Tags: , ,

Friday, May 19, 2006

Free Icons

There is also a list that is updated @ MaxPower - Free! Icons for your website or application

There probably are more sites with free icons, which I will try to add if I find them. Tutorial on creating your own icons with GIMP: GIMP - Creating Icons.


Tags: , ,

Wednesday, May 17, 2006

FixListControl - select correct item on PostBack for CheckBoxList/DropDownList/ListBox/RadioButtonList (ASP.NET)

When you add a DropDownList (or any other web controls that inherit from ListControl) to a page and bind it on page load, the first value ends up being selected (or to be more accurate, no value gets selected, so by default the first item is shown) on PostBack (rather than the one you selected). One solution to this is to check if a PostBack has occured and only set up the DropDownList on initial page load.

private void Page_Load(object sender, EventArgs e)
{
 if(!IsPostBack)
 {
  SetupMyDropDown();
 }
}

This helps in most cases, but not if you do a DataBind for the whole page.

private void Page_Load(object sender, EventArgs e)
{
 if(!IsPostBack)
 {
  SetupMyDropDown();
 }
 BindData();
}

This could cause a "Object reference not set to an instance of an object" error, because your DropDownList is bound to an object that needs to be set up on each page load (it is not persisted in view state). One solution would be to bind everything but the DropDownList, but that would not be viable if you needed to bind the whole page (e.g. in your HTML you had <title><%# PageTitle %></title>.

Another solution would be to change the selected value before the page renders. The following method does this (and only if the user is posting back).

private void InitializeComponent()
{
 this.Load += new EventHandler(this.Page_Load);
 this.MyDropDown.PreRender += new EventHandler(this.FixListControl);
}
private void FixListControl(object sender, EventArgs e)
{
 if(IsPostBack)
 {
  ListControl l = (ListControl)sender;
  l.SelectedValue = Request.Form[l.ClientID];
 }
}

Very little code is needed and you can use it for anything that inherits from ListControl, so the following should work as well (I have only tested it with DropDownList):

this.MyCheckBoxList.PreRender += new EventHandler(this.FixListControl);
this.MyDropDown.PreRender += new EventHandler(this.FixListControl);
this.MyListBox.PreRender += new EventHandler(this.FixListControl);
this.MyRadioButtonList.PreRender += new EventHandler(this.FixListControl);

Tags: , , , , , , ,

Friday, May 12, 2006

Lots of free software for almost any purpose

You can do just about anything with free software (freeware or open source). eConsultant has a big list: I want a Freeware Utility to ... 450+ common problems solved (does not include open source in the list). There is a seperate list for open source: Open Source Freeware : 400+ free applications and utilities


Tags: , ,

Friday, May 05, 2006

Direct Manipulation Using JavaScript and CSS

ToolMan DHTML Library is a useful JavaScript library that allow you to: drag and drop, sort (lists and toolbars) and edit in place (edit content by double clicking on it in the page).


Tags: ,

A Multipart Series on ASP.NET 2.0's Membership, Roles, and Profile

From 4GuysFromRolla.com. 4 parts so far. And a feed of the series.

  • Part 1 - membership basics, a look at the SqlMembershipProvider class.
  • Part 2 - creating roles and assigning to users.
  • Part 3 - adding membership related schemas to a SQL database using aspnet_regsql.exe.
  • Part 4 - show messages to users who cannot login (i.e. why they can't), keep log of login failures.

Tags: ,

Wednesday, April 26, 2006

Form layout styling with CSS

You can style forms using CSS and definition lists instead of tables. This has only been tested in IE6 and Firefox. As a basis I define the form in HTML as follows:

<fieldset class="form">
 <legend>Add Contact</legend>
 <dl>
  <dt>Forename: </dt>
  <dd><input type="text" name="forename" id="forename" /></dd>
  <dt>Surname: </dt>
  <dd><input type="text" name="surname" id="surname" /></dd>
  <dt>Email: </dt>
  <dd><input type="text" name="email" id="email" /></dd>
  <dt></dt>
  <dd><input type="submit" value="Add" /></dd>
 </dl>
</fieldset>

And the CSS:

fieldset.form {
 width: 95%;
 border: 1px dotted #ccc;
 padding: 12px;
}

fieldset.form legend {
 font-weight: bold;
 background: #fff;
}

fieldset.form dl {
 float: left;
 clear: both;
}

fieldset.form dl dt {
 clear: left;
 float: left;
 width: 110px;
 margin: .5em 0;
 text-align: right;
}

fieldset.form dl dd {
 margin: .5em 0;
 float: left;
 padding: 0 0 0 4px;
}

* html fieldset.form dl dd {
 float: none;
 margin: .5em 0 0 0;
}

fieldset.form dl dt is the definition for the label accompanying an input control. It has a fixed width and is right-aligned. fieldset.form dl dd is the input control next to the label. The * html fieldset.form dl dd is used to fix a few bugs in IE - without it, the input controls are not next to the labels, and the seperation between items is greater than it should be.

Sample:

Add Contact
Forename:
Surname:
Email:

Tags: ,

Friday, April 07, 2006

Portable GIMP + Extras (Help and Animation Package)

It is possible to run The GIMP (an open source alternative to Photoshop) off an external USB drive. There are instruction on how to do it from Cemetech | View topic - Making The GIMP Portable and a Zip file (XGimp_2.2.10_all_lang.zip) from WinPenPack's Grafica section (Italian site, found via tech poetic » Blog Archive » portable GIMP by winpenpack.com). The problem with these solutions is that they do not include the extras, and (in the case of the WinPenPack site) depend on a third party to update them when new versions of the software come out. Here is another way to do it manually, and should apply to future updates.

First of all download The GIMP for Windows, GTK + Runtime Environment, GIMP Help 2 and GIMP Animation Package from http://gimp-win.sourceforge.net/stable.html. You will require approximately 90MB free disk space on your external drive, 100MB if you want to be on the safe side. After you have downloaded the files and confirmed that you have enough space, install in order:

  1. GTK + Runtime Environment
  2. The GIMP for Windows (uncheck the box prompting you to launch the GIMP after setup)
  3. GIMP Help 2
  4. GIMP Animation Package

If you have any other plugins etc that you use, install them before continuing. After these have all been installed, you need to copy the GTK runtime:

  1. Go to C:\Program Files\Common Files
  2. Copy GTK folder
  3. Go to external drive (e.g. E:)
  4. Paste GTK folder
  5. Go to E:\GTK\2.0
  6. Delete unins000.dat, unins000.exe and uninst.isl

Now copy over The GIMP:

  1. Go to C:\Program Files
  2. Copy GIMP-2.0
  3. Go to external drive (e.g. E:)
  4. Paste GIMP-2.0 folder
  5. Go to E:\GIMP-2.0
  6. Delete unins000.dat, unins000.exe and uninst.ini

Now uninstall The GIMP and GTK + (unless you use GTK + for other applications).

In the root of your external drive (e.g. E:\), create a text file named gimp.cmd containing the following:

@echo off
SET HOME=
SET GIMP2_DIRECTORY=\GIMP-2.0\pref
SET PATH=\GTK\2.0\bin\;%PATH%
cd \GIMP-2.0\bin
echo Starting GIMP...
start gimp-2.2.exe

If you want your settings to be different on each computer, remove the line SET GIMP2_DIRECTORY=\GIMP-2.0\pref

To use the built-in help browser (which is what I prefer to use) rather than the systems default web browser, launch The GIMP (from the gimp.cmd file) and choose Preferences from the File menu. Click Help System and set Help Browser to GIMP help browser.


Tags: ,

Thursday, March 30, 2006

Displaying the Sizes of Your SQL Server's Database's Tables

Displaying the Sizes of Your SQL Server's Database's Tables. Uses ASP.NET to show you how much space you are using for each table in your SQL Server database. Returns table name, number of rows, reserved space, space used by table data, space used by table indexes and unused space.


Tags: , ,

Tuesday, March 28, 2006

Helpful Links on JavaScript Closures

Helpful Links on JavaScript Closures. Some useful links on closures (what they are, how to write them etc). They are very useful, but can cause memory leaks (especially in Internet Explorer) and are not always appropriate.


Tags: ,

Wednesday, March 15, 2006

Round-up of 30 AJAX Tutorials

Round-up of 30 AJAX Tutorials is a very useful list of tutorials for those just starting with Ajax, or lacking knowledge in some areas. Areas it covers:

  • Client-Server Communication
  • Drag and Drop
  • Web Forms
  • File Uploader (Java)
  • Framework and Toolkit
  • Getting Started
  • Image Gallery (JavaScript, XML)
  • Keyword Suggest
  • Live Search
  • Rounded Corner
  • Sorting
  • Tabbed Pages

Tags: , ,

Tuesday, March 14, 2006

Ajax Toybox

Ajax Toybox gives you simple examples of using client-side JavaScript (XmlHttpRequest) to get remote content (served by PHP). Includes a dynamic City/State lookup and an RSS News Ticker (using Magpie RSS and PHP to get remote feeds).


Tags: , , , ,

Monday, March 06, 2006

JavaScript Framework Comparison - Popup Windows

I have a simple function for opening new windows. I want all anchors with the class external (or contained in a parent with this class name) to open links in a new window using this function. So I look at the various frameworks for doing it. In this case, I am comparing jQuery with Prototype (more may follow soon in an edit to this post).

function popup()
{
 window.open(this.href);
 return false;
}

This function is the same, regardless of framework used (so as to emulate a real world scenario).

HTML code:

<p>In a div</p>
<div class="external">
 <a href="http://www.google.com">Google</a> |
 <a href="http://search.yahoo.com">Yahoo</a> |
 <a href="http://search.msn.com">MSN</a> |
 <a href="http://www.ask.com">Ask</a>
</div>
<p>In a list</p>
<ul class="external">
 <li><a href="http://www.google.com">Google</a></li>
 <li><a href="http://search.yahoo.com">Yahoo</a></li>
 <li><a href="http://search.msn.com">MSN</a></li>
 <li><a href="http://www.ask.com">Ask</a></li>
</ul>
<p>Standalone</p>
<a href="http://www.google.com" class="external">Google</a>
<a href="http://search.yahoo.com" class="external">Yahoo</a>
<a href="http://search.msn.com" class="external">MSN</a>
<a href="http://www.ask.com" class="external">Ask</a>

jQuery

$(window).bind("load",function()
{
 $(".external a,a.external").bind("click",popup);
});

Works as expected in Internet Explorer 6 (Windows 2000), Opera 8.5 and Firefox 1.5.

Prototype

Event.observe(window, 'load', setPopup);
function setPopup()
{
 var nodes = $A(document.getElementsByClassName("external"));
 nodes.each(function(node)
 {
  if(node.nodeName == 'A')
  {
   Event.observe(node, 'click', popup);
  }
  else
  {
   var subnodes = $A(node.getElementsByTagName("a"));
   subnodes.each(function(node)
   {
    Event.observe(node, 'click', popup);
   });
  }
 });
}

It could just be me not knowing enough about Prototype, but that seems like far more code than necessary. It doesn't get any better though. Firefox and Opera opens the new window with the right page as expected, but return false is ignored. Internet Explorer opens a new windows and does not seem to ignore return false, but this.href ends up being undefined

Summary

In this case, jQuery wins out. Far less code is needed (both the framework and the page code) and it works in all tested browsers. So it shows that depending on the circumstances, it is not always best to go with the framework with the most features.


Tags: ,

Saturday, March 04, 2006

JavaScript Frameworks

There are many frameworks to make working with web pages (via JavaScript) easier. All of them work cross browser, do events (window load, element click etc) and basic manipulation (get element, modify css, hide/show/move), but some do more than others. Syntax often differs between them.

Choosing one to work with depends on what you want to do, and how much code you are willing to write yourself (sometimes it is more satisfying to figure out a solution to a problem yourself, rather than to rely on someone else's code). Like with any code, the more it does, the bigger the download for the client. So it may be best to go with the most minimal solution (no extra features you won't use).

Here is a basic overview of what is available (that I know of)

Prototype

http://prototype.conio.net/

There is a useful reference for this at Prototype Dissected. As you can see from it, Prototype has quite a lot of features.

Very widely used and quite a reasonably big file (approx 46kb). There are several other projects based on it.

  • Ruby On Rails - open source web development framework, based on the Ruby language.
  • script.aculo.us - a library (approx 100kb) for adding visual effects (animation, fade), drag and drop and more to your web pages.
  • Rico - an Ajax library (approx 90kb) built on Prototype. Behaviour - this uses CSS style selectors to attach events to elements in your page.
  • moo.fx - a lightweight (3kb / 6kb with extra effects) alternative to script.aculo.us. Also, as an option, you can use a cutdown version of Prototype (3kb)

jQuery

http://jquery.com/

A relative newcomer onto the scene. Very lightweight and easy to use. < 15kb compressed. Basic features include: DOM traversing and modification, iteration, events, style and effects. Plugins are easy to write and there is currently an Ajax one available. Example code (adds a line break after all labels, and adds a border around the associated element):

var break = document.createElement("br");
$(window).bind("load",function()
{
 $("label").after(break).each(htmlFor);
});
function htmlFor()
{
 $(this.htmlFor).css("border","1px solid #000");
}

Dojo

http://dojotoolkit.org/

Animation, Widgets, Events, Ajax and more. It includes a rich text editor widget, which just requires some extra html markup. However, to make best use of it, extra attributes need to be added, meaning that it will not validate. It can be applied to div's, but then there would be an issue if the client has JavaScript disabled, so it is better if textarea's are used instead. Other widgets include a DatePicker, TimePicker, Menu, ContextMenu and ToolBar. It has a package system which means you don't have to include extra markup (it is dynamically loaded). Better suited when you know the client has enough bandwidth (i.e. not on dial up). There are several build available:

  • AJAX
  • I/O (XmlHttp)
  • Event + I/O
  • Widgets
  • The "Kitchen Sink" (all packages)

There is a good Dojo tutorial available: Dojo Done Quick, which covers coverting your own code to use the Dojo events and widget systems.

Yahoo! User Interface Library

http://developer.yahoo.net/yui/

One of the most well known companies that are doing a free toolkit for working with JavaScript. Already outlined its features before: Yahoo! User Interface Library and Design Pattern Library

Atlas

http://weblogs.asp.net/scottgu/archive/2005/06/28/416185.aspx

Microsoft is working on Atlas, mainly targetted at ASP.NET developers, but hopefully will work with any server side solution. No download link that I can find, so at the moment, the Yahoo one is the most 'mainstream' (company known for other things) solution.

Conclusion

These should be seen as enhancements to your web page. You should still have a fallback to server side processing. Otherwise your site is not accessible. Get the basics done first, then work on the client to improve the experience and reduce hits to you web server.


Tags: , ,

Friday, March 03, 2006

Yahoo! Developer Network - PHP Developer Center

Yahoo! Developer Network - PHP Developer Center - found via Quick Link: Yahoo's PHP Developer Center. A good resource for PHP developers, including snippets and useful links. Code is for interacting with Yahoo's Web services, but could be used as a learning tool for various common tasks (parsing XML, caching etc).

Tags: , ,

Wednesday, February 22, 2006

GreatNews Feed Reader

GreatNews is a free feed (RSS/Atom) reader that can work off portable drives and supports syncing with Bloglines.com, full page reading (newspaper style, Sage (Firefox feed reader) style, and others), labeling and news watches.


Tags: , , ,

Tuesday, February 21, 2006

iTextSharp: Generate a PDF file containing a table (ASP.NET/C#)

Contining on from iTextSharp: Generating a Basic PDF file (ASP.NET/C#), here is a demo of how to generate a PDF document with a table in it.

TablePDF.ashx

<%@ WebHandler Language="C#" Class="MyNamespace.TablePDF" %>
using System;
using System.IO;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace MyNamespace
{
 public class TablePDF: IHttpHandler 
 {
  
  public bool IsReusable
  {
   get
   {
    return true;
   }
  }
  
  /// <summary>
  /// Font used for table headers
  /// </summary>
  private Font TableHeaderFont
  {
   get
   {
    return new Font(Font.HELVETICA, Font.DEFAULTSIZE, Font.BOLD);
   }
  }
  
  public void ProcessRequest(HttpContext ctx)
  {
   // make sure it is sent as a PDF
   ctx.Response.ContentType="application/pdf";
   // make sure it is downloaded rather than viewed in the browser window
   ctx.Response.AddHeader("Content-disposition", "attachment; filename=TablePDF.pdf");
   
   // create a MemoryStream (as there may not be write access to any folder on the server)
   using(MemoryStream m = new MemoryStream())
   {
    // create the PDF document
    Document document = new Document(PageSize.A4);
    PdfWriter.GetInstance(document, m);
    
    // open document to add content
    document.Open();
    
    // add table with 3 columns
    Table myTable = new Table(3);
    myTable.AutoFillEmptyCells = true;
    // add padding to table cells
    myTable.Cellpadding = 3.5f;
    // make sure table fits the width of the page
    myTable.WidthPercentage = 100.0f;
    
    // remove borders
    //myTable.DefaultCellBorder = Rectangle.NO_BORDER;
    //myTable.Border = Rectangle.NO_BORDER;
    
    // create cell
    Cell myCell = new Cell();
    
    // add header cell
    myCell.Header = true;
    myCell.Add(new Chunk("Header 1",TableHeaderFont));
    // row 1 column 1
    myTable.AddCell(myCell, 0, 0);
    
    // new header
    myCell = new Cell();
    myCell.Header = true;
    myCell.Add(new Chunk("Header 2",TableHeaderFont));
    // row 1 column 2
    myTable.AddCell(myCell, 0, 1);
 
    // another new header
    myCell = new Cell();
    myCell.Header = true;
    myCell.Add(new Chunk("Header 3",TableHeaderFont));
    // row 1 column 3
    myTable.AddCell(myCell, 0, 2);
 
    // add some data (6 rows worth)
    for (int i=1; i<=6; i++)
    {
     // on the third iteration, span several columns
     if(i == 3)
     {
      myCell = new Cell();
      myCell.Colspan = 3;
      myCell.HorizontalAlignment = Element.ALIGN_CENTER;
      myCell.Add(new Chunk("R" + (i + 1) + "C1 - " + "R" + (i + 1) + "C3"));
      myTable.AddCell(myCell, i, 0);
     }
     else
     {
      myCell = new Cell();
      myCell.Add(new Chunk("R" + (i + 1) + "C1"));
      myTable.AddCell(myCell, i, 0);
      
      myCell = new Cell();
      myCell.Add(new Chunk("R" + (i + 1) + "C2"));
      myTable.AddCell(myCell, i, 1);
      
      myCell = new Cell();
      myCell.Add(new Chunk("R" + (i + 1) + "C3"));
      myTable.AddCell(myCell, i, 2);
     }
    }
    // add table
    document.Add(myTable);
    
    // close the document
    document.Close();
    
    // stream the PDF to the user
    ctx.Response.OutputStream.Write(m.GetBuffer(), 0, m.GetBuffer().Length);
   }
   ctx.Response.End();
  }
 }
}

Tags: , , , , ,

Tuesday, February 14, 2006

Yahoo! User Interface Library and Design Pattern Library

Yahoo! User Interface Library is a JavaScript library (under the open source BSD license) that can be used to make a site more interactive. It is comprised of 'Core Utilities' and 'UI Controls'.

Core Utilities

  • Animation
  • Connection Manager (XMLHttpRequest / AJAX)
  • DOM (manipulating the elements (style, coordinates) in a loaded web page)
  • Drag and Drop
  • Event (adding them to existing elements on a page)

UI Controls

  • Calendar
  • Slider
  • TreeView

Yahoo! Design Pattern Library is a set of solutions to common problems (breadcrumbs, autocomplete, drag/drop, pagination etc). There is no code, but it does demonstrate the solutions Yahoo uses for its sites.

They also have a blog about it: Yahoo! User Interface Blog.


Tags: , , , ,

Monday, February 13, 2006

Add .NET Framework Folder to PATH via batch file (update)

Add .NET Framework Folder to PATH via batch file has been updated. This is a batch file that adds the .NET framework directory (i.e. where the command line compilers csc, vbc etc are in) to the PATH system variable. It does not add the path if it is already set, so it is of most use to those that have not done it manually (the SDK doesn't add the directory on install).


Tags: ,

Thursday, February 09, 2006

How to generate an iCalendar file (ASP.NET/C#)

It is fairly simple to generate an iCalendar file (for calendar clients like Microsoft Outlook or Mozilla Sunbird) as it is just a plain text file with the extension 'ics'. A WebHandler is the best method of doing this.

Update (10 Feb 2006): Now works in Sunbird. When prompted to open / save the file, choose to download. Then in Sunbird, go to File > Import and browse for the saved file.

iCalendar.ashx

<%@ WebHandler Language="C#" Class="MyNamespace.iCalendar" %>
using System;
using System.Web;
namespace MyNamespace
{
 public class iCalendar: IHttpHandler 
 {
  
  public bool IsReusable
  {
   get
   {
    return true;
   }
  }

  string DateFormat
  {
    get
    {
      return "yyyyMMddTHHmmssZ"; // 20060215T092000Z
    }
  }
  
  
  public void ProcessRequest(HttpContext ctx)
  {
   DateTime startDate = DateTime.Now.AddDays(5);
   DateTime endDate = startDate.AddMinutes(35);
   string organizer = "foo@bar.com";
   string location = "My House";
   string summary = "My Event";
   string description = "Please come to\\nMy House";
   
   ctx.Response.ContentType="text/calendar";
   ctx.Response.AddHeader("Content-disposition", "attachment; filename=appointment.ics");
   
   ctx.Response.Write("BEGIN:VCALENDAR");
   ctx.Response.Write("\nVERSION:2.0");
   ctx.Response.Write("\nMETHOD:PUBLISH");
   ctx.Response.Write("\nBEGIN:VEVENT");
   ctx.Response.Write("\nORGANIZER:MAILTO:" + organizer);
   ctx.Response.Write("\nDTSTART:" + startDate.ToUniversalTime().ToString(DateFormat));
   ctx.Response.Write("\nDTEND:" + endDate.ToUniversalTime().ToString(DateFormat));
   ctx.Response.Write("\nLOCATION:" + location);
   ctx.Response.Write("\nUID:" + DateTime.Now.ToUniversalTime().ToString(DateFormat) + "@mysite.com");
   ctx.Response.Write("\nDTSTAMP:" + DateTime.Now.ToUniversalTime().ToString(DateFormat));
   ctx.Response.Write("\nSUMMARY:" + summary);
   ctx.Response.Write("\nDESCRIPTION:" + description);
   ctx.Response.Write("\nPRIORITY:5");
   ctx.Response.Write("\nCLASS:PUBLIC");
   ctx.Response.Write("\nEND:VEVENT");
   ctx.Response.Write("\nEND:VCALENDAR");
   ctx.Response.End();
  }
 }
}

Wednesday, February 08, 2006

iTextSharp: Generating a Basic PDF file (ASP.NET/C#)

iTextSharp is free library for .NET that allows you to create PDF documents. It can be used to dynamically create PDF's which can be streamed to the user. As there is no HTML being sent to the user, a WebHandler (ashx file) is a more appropriate way to generate your PDF than an aspx page. Download itextsharp-3.0.10-dll.zip (latest version as of 08 Feb 2006) and save the dll in the archive to your websites bin directory.

Here is a basic sample of creating a PDF (more complex samples may follow in future posts).

BasicPDF.ashx

<%@ WebHandler Language="C#" Class="MyNamespace.BasicPDF" %>
using System;
using System.IO;
using System.Web;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace MyNamespace
{
 public class BasicPDF: IHttpHandler 
 {
  
  public bool IsReusable
  {
   get
   {
    return true;
   }
  }
  
  /// <summary>
  /// Font used for any hyperlinks added to the PDF
  /// </summary>
  private Font LinkFont
  {
   get
   {
    return new Font(Font.HELVETICA, Font.DEFAULTSIZE, Font.UNDERLINE, Color.BLUE);
   }
  }
  
  public void ProcessRequest(HttpContext ctx)
  {
   // make sure it is sent as a PDF
   ctx.Response.ContentType="application/pdf";
   // make sure it is downloaded rather than viewed in the browser window
   ctx.Response.AddHeader("Content-disposition", "attachment; filename=BasicPDF.pdf");
   
   // create a MemoryStream (as there may not be write access to any folder on the server)
   using(MemoryStream m = new MemoryStream())
   {
    // create the PDF document
    Document document = new Document(PageSize.A4);
    PdfWriter.GetInstance(document, m);
    
    // set meta data
    document.AddTitle("Test PDF");
    document.AddSubject("This is a PDF generated by a WebHandler in ASP.NET");
    document.AddKeywords("test document,foo,bar,baz");
    document.AddAuthor("John Doe");
    document.AddCreator("My Web Application");
    
    // open document to add content
    document.Open();
    
    // create a paragraph 
    Paragraph p = new Paragraph();
    
    // create a phrase object (which will contain the text to go in the paragraph)
    Phrase content = new Phrase();
    
    // start adding content to the phrase
    content.Add(new Chunk("Download iTextSharp from: "));
    
    Anchor link = new Anchor("itextsharp.sourceforge.net",LinkFont);
    link.Reference = "http://itextsharp.sourceforge.net";
    
    // add link to phrase
    content.Add(link);
    
    // add the phrase to the paragraph
    p.Add(content);
    
    // add the paragraph to the document
    document.Add(p);
    
    // add another paragraph
    document.Add(new Paragraph("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. "
     + "Praesent ante dui, adipiscing ac, pretium in, cursus non, dui. "
     + "Vivamus risus tellus, semper non, posuere eget, elementum eu, nulla. "
     + "Nulla scelerisque arcu et odio."));
    
    // close the document
    document.Close();
    
    // stream the PDF to the user
    ctx.Response.OutputStream.Write(m.GetBuffer(), 0, m.GetBuffer().Length);
   }
   ctx.Response.End();
  }
 }
}

Tags: , , , , ,

Monday, February 06, 2006

Alternatives to innerHTML

Alternatives to innerHTML (slayeroffice article) gives many examples of working with the DOM and modifying a document without resorting to innerHTML. The problem with innerHTML is that it could cause issues with strict XHTML documents (served with the correct mime type, application/xhtml+xml) and also can result in illegible code (may be hard to decipher another developers code).


Tags: , ,

Thursday, February 02, 2006

Clean Word Html Update

Clean Word Html has been updated with a few bug fixes.


Tags:

Sunday, January 22, 2006

Free Computer Textbooks

Textbook Revolution is a site that keeps track of free books in electronic form and has a section for computer / technology ones.

Electronic books, while they can be useful, are not a substitute for the real thing (which are easier to read and can be read anywhere).


Tags: ,

Friday, January 20, 2006

FireBug (Firefox Extension for Web Developers)

What do you get if you cross the DOM Inspector with the JavaScript console and a JavaScript interpreter? A very useful extension for debugging/analysing web pages in Firefox called FireBug. Features include (more details on each feature can be found on the site):

  • Log DOM Elements With Your Mouse
  • Log Objects From The Command Line
  • Log Objects From Your Web Page Scripts
  • XMLHttpRequest Spy
  • Contextual Error Display
  • Error Status Bar Indicator
  • Error Filtering

With the addition of CSS errors to the JavaScript console (which can't be filtered out), this is a very welcome extension with its error filtering.


Tags: , ,

Sunday, January 15, 2006

Clean Word Html (command line tool)

This command line tool is based on the code from Cleaning Word's Nasty HTML, and has been backported to .NET 1.1. To compile, download Snippet Compiler (the version for .NET 1.1). Then do File > New > Default.cs and clear the contents. Paste in the following code, then click Build > Build Current To File and call it CleanWordHtml. Open the Command Prompt at the location it was saved to and type CleanWordHtml for help.

Edit (18-Jan-06): remove u tags. Not all empty tags were removed. Does not remove empty table cells (as they may be used for column/row layout). Quoted class attributes are removed.

Edit (2-Feb-06): As a side effect of removing u tags, ul tags where also removed. So they are no longer removed. When reading in text from a file, line breaks were not read in, but now they are. You can now drag files onto the application (rather than resorting to the command line).

CleanWordHtml.cs

using System;
using System.Reflection;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

[assembly: AssemblyTitle("CleanWordHtml")]
[assembly: AssemblyDescription("Cleans up HTML generated by Microsoft Word")]
[assembly: AssemblyVersion("1.0.1.*")]

public class CleanUp
{
 static bool Mso = false;
 static bool IgnoreSpans = false;
 static bool IgnoreDivs = false;
 
 static void Main(string[] args)
 {
  string help = "Cleans up HTML generated by Microsoft Word" + Environment.NewLine + Environment.NewLine
   + "Usage:" + Environment.NewLine
   + "------" + Environment.NewLine
   + "CleanWordHtml \"path to file\"" + Environment.NewLine
   + "CleanWordHtml -path \"path to file\"" + Environment.NewLine + Environment.NewLine
   + "  Other options:" + Environment.NewLine
   + "   -mso (remove only classes generated by word)" + Environment.NewLine
   + "   -ignorespans (don't remove span tags)" + Environment.NewLine
   + "   -ignoredivs (don't remove div tags)";
  
  string filepath = string.Empty;
  if ((args.Length == 0 || IsNullOrEmpty(args[0]))) 
  {
   Console.WriteLine(help);
   return;
  }
  
  if(args.Length == 1)
  {
   filepath = args[0];
  }
  else
  {
   for(int i=0; i<args.Length; i++)
   {
    if(args[i].ToLower() == "-path")
    {
     filepath = args[i+1];
    }
    if(args[i].ToLower() == "-mso")
    {
     Mso = true;
    }
    if(args[i].ToLower() == "-ignorespans")
    {
     IgnoreSpans = true;
    }
    if(args[i].ToLower() == "-ignoredivs")
    {
     IgnoreDivs = true;
    }
   }
  }
  if(IsNullOrEmpty(filepath))
  {
   Console.WriteLine(help);
   return;
  }
  if (Path.GetFileName(filepath) == filepath)
  {
   filepath = Path.Combine(Environment.CurrentDirectory, filepath);
  }
  if (!File.Exists(filepath))
  {
   Console.WriteLine("File '" + filepath + "' doesn't exist.");
   return;
  }
  string html = ReadAllText(filepath);
  Console.WriteLine("Input html is " + html.Length + " chars");
  html = CleanWordHtml(html);
  html = FixEntities(html);
  filepath = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath) + ".modified" + Path.GetExtension(filepath));
  WriteAllText(filepath, html);
  Console.WriteLine("Cleaned html is " + html.Length + " chars. Saved to " + filepath);
 }
 
 static string CleanWordHtml(string html)
 {
  StringCollection sc = new StringCollection();
  if(!IgnoreSpans)
  {
   sc.Add(@"<(/?span|!\[)[^>]*?>");
  }
  if(!IgnoreDivs)
  {
   sc.Add(@"<(/?div|!\[)[^>]*?>");
  }
  if(!Mso)
  {
   // Get rid of classes
   sc.Add(@"\s?class=[""']?\w+[""']?");
  }
  else
  {
   // Get rid of office classes
   sc.Add(@"\s?class=[""']?Mso\w+[""']?");
  }
  // get rid of unnecessary tag spans (comments and title)
  sc.Add(@"<!--(\w|\W)+?-->");
  sc.Add(@"<title>(\w|\W)+?</title>");
  // get rid of inline style
  sc.Add(@"\s?style=[""']?\w+[""']?");
  // Get rid of unnecessary tags
  sc.Add(@"<(meta|link|/?o:|/?style|/?font|/?st\d|/?head|/?html|body|/?body|!\[)[^>]*?>");
  // Get rid of empty tags (except table cells)
  sc.Add(@"(<[^/][^(th|d)>]*>){1}(&nbsp;)*(</[^>]+>){1}");
  // remove bizarre v: element attached to <img> tag
  sc.Add(@"\s+v:\w+=""[^""]+""");
  // remove extra lines
  sc.Add(@"(" + Environment.NewLine + "){2,}");
  // remove extra spaces
  sc.Add(@"( ){2,}");
  foreach (string s in sc)
  {
   html = Regex.Replace(html, s, "", RegexOptions.IgnoreCase);
  }
  // quote unquoted attributes
  //html = Regex.Replace(html, @"(\w+=)(\w+)(?=[ >])", @"$1""$2""", RegexOptions.IgnoreCase);
  return html;
 }
 
 static string FixEntities(string html)
 {
  NameValueCollection nvc = new NameValueCollection();
  nvc.Add("“", "&ldquo;");
  nvc.Add("”", "&rdquo;");
  nvc.Add("—", "&mdash;");
  foreach (string key in nvc.Keys)
  {
   html = html.Replace(key, nvc[key]);
  }
  return html;
 }
 
 static bool IsNullOrEmpty(string value)
 {
  if (value != null)
  {
   return (value.Length == 0);
  }
  return true;
 }

 static string ReadAllText(string path)
 {
  StringBuilder sb = new StringBuilder();
  using (StreamReader sr = new StreamReader(path)) 
  {
   String line;
   // Read and display lines from the file until the end of 
   // the file is reached.
   while ((line = sr.ReadLine()) != null) 
   {
    sb.Append(line + Environment.NewLine);
   }
  }
  return sb.ToString();
 }
 
 static void WriteAllText(string path, string contents)
 {
  WriteAllText(path, contents, new UTF8Encoding(false, true));
 }
 
 static void WriteAllText(string path, string contents, Encoding encoding)
 {
  using (StreamWriter sw = new StreamWriter(path, false, encoding))
  {
   sw.Write(contents);
  }
 }
}

Friday, January 13, 2006

Free PDF Generators

Adobe Acrobat isn't the only tool able to create PDF documents, there are others, some of them free. Two good ones are:

  • PDFCreator (many features, can be intimidating to less tech-savvy users). Download.
  • PrimoPDF (less features than PDFCreator, but easier to use)

Tags: ,

Programmer's Notepad Forums

The developer of Programmer's Notepad has setup some forums where you can discuss the program, ask for help etc. Uses bbPress, a very light-weight forum software by some of the developers of WordPress (which powers pnotepad.org).


Tags: , ,

Wednesday, January 04, 2006

HyperLinks and UserControls (ASP.NET)

If you have a file (/myapp/page.aspx) which references a user control (/myapp/controls/control.ascx) that contains a HyperLink, you find that the link generated is relative to the control, not the page. For example if the following code was in the control:

<asp:HyperLink Text="Foo" NavigateUrl="bar.aspx" runat="server" />

The following output would be generated:

<a href="controls/bar.aspx">Foo</a>

This may not the desired outcome. You can set the link relative to the server root (by using /myapp/bar.aspx), site root (by using ~/bar.aspx), or even the control itself (../bar.aspx) but if you want to make it relative to the calling page more work is involved. For doing this you can use the Uri class and Request.Url:

<asp:HyperLink id="lnkFoo" Text="Foo" NavigateUrl='<%#(new Uri(Request.Url,"bar.aspx")).AbsolutePath%>' runat="server" />

If the link is in a Repeater (or something else that is bound to data) you do not need the id attribute. However if it is not, you have to add the following to the page load event of the control:

FindControl("lnkFoo").DataBind();

You then end up with a link that works:

<a id="myrepeater_lnkFoo" href="/myapp/bar.aspx">Foo</a>

Tags: ,

Tuesday, January 03, 2006

anchorWrap (JavaScript)

Wraps a node with an anchor (i.e. HyperLink, JavaScript prompt).

// 'node' can be an existing node, or a string (id of node)
// 'anchor' can be a URL string, or a precreated anchor
// 'target' is the target frame to go to, and is optional
function anchorWrap(node,anchor,target)
{
 if(!document.createElement) return;
 var newanchor,parent,sibling;
 if(typeof(node) == "string")
 {
  node = document.getElementById(node);
 }
 if(!node || !node.parentNode) return;
 if(typeof(anchor) == "string")
 {
  newanchor = document.createElement("a");
  newanchor.href = anchor;
 }
 else
 {
  newanchor = anchor;
 }
 if(!newanchor) return;
 // if href is not set (which may be the case when it performs a javascript action), set it to #, so the link is seen
 if(!newanchor.href) newanchor.href = "#";
 // if target is defined, set it
 if(typeof(target) == "string")
 {
  newanchor.target = target;
 }
 // get the sibling and the parent node (so we can insert in the right place)
 sibling = node.nextSibling;
 parent = node.parentNode;
 // add the node to the new anchor
 newanchor.appendChild(node);
 // insert new anchor before sibling, or at the end if there is no sibling
 if(sibling)
 {
  parent.insertBefore(newanchor,sibling);
 }
 else
 {
  parent.appendChild(newanchor);
 }
}

Example uses:

// element with id 'foo', open http://webdevel.blogspot.com in new window
anchorWrap("foo", "http://webdevel.blogspot.com", "_blank");
// element with id 'bar', open http://webdevel.blogspot.com in same window
anchorWrap("bar", "http://webdevel.blogspot.com");
// get element 'baz', style it so it is bold
var baz = document.getElementById("baz");
baz.style.fontWeight = "bold";
// create JavaScript anchor
var jsanchor = document.createElement("a");
jsanchor.onclick = function()
{
 alert("Hello World");
 return false;
}
// wrap 'baz' element with the created JavaScript anchor
anchorWrap(baz, jsanchor);

Tags: ,