Thursday, December 18, 2008

jQuery newsticker Demo Page

Some may have noticed, the demo page for the newsticker jQuery plugin has not been working in Internet Explorer 7. This is due to it being experimental code for allowing pausing, resuming and clearing of any active news ticker's on the page. It should now work in IE7 (and hopefully IE6 as well).

There are a few additions to the plugin that should be of benefit. Set up the news ticker as usual:

var $news = $("#news").newsticker();

After doing so, you may pause, resume and clear it in your own functions. For example, clicking on elements with id's pause, resume or clear will perform the relevant action:

$("#pause").click(
  function()
  {
    $.newsticker.pause($news);
    return false;
  }
);

$("#resume").click(
  function()
  {
    $.newsticker.resume($news);
    return false;
  }
);

$("#clear").click(
  function()
  {
    $.newsticker.clear($news);
    return false;
   }
);

The code available for download via jQuery SVN doesn't have this functionality, but should work fine in IE7.

jQuery Validation Plugin Tip: Highlight Field

The validation plugin for jQuery is a very useful plugin for validating forms before they are submitted. This tip shows you how you can highlight the field if there is an error with it.

var validator = $("#myform").validate({
 onblur: function(el)
 {
  if(validator.check(el))
   $(el).removeClass(validator.settings.errorClass);
  else
   $(el).addClass(validator.settings.errorClass);
 },
 onkeyup: function(el)
 {
  if(validator.check(el))
   $(el).removeClass(validator.settings.errorClass);
  else
   $(el).addClass(validator.settings.errorClass);
 }
});

This adds the errorClass (normally 'error') to the field being validated, which can then be styled via CSS:

input.error { border: 1px solid #c00; background: #fee }

Monday, December 15, 2008

jQuery appendToArray plugin

With jQuery, I found no real way of grouping elements together (other than using a class, and using filter), so I thought about adding jQuery objects to an array (or multiple arrays), which can then be iterated over with jQuery.each. I tried appendTo (on the off chance that it would work with plain arrays), but no such luck. So I created a simple plugin:

jQuery.fn.appendToArray = function()
{
 var a = arguments;
 for(var i = 0; i < arguments.length; i++) a[i][a[i].length] = this;
 return this;
}

Through using arguments, it can be appending to multiple arrays at the same time:

var ar1 = [];
var ar2 = [];
var $field1 = $("[name='field1']").appendToArray(ar1, ar2);
var $field2 = $("[name='field2']").appendToArray(ar1);
var $field3 = $("[name='field3']").appendToArray(ar1, ar2);
var $field4 = $("[name='field4']").appendToArray(ar2);
var $field5 = $("[name='field5']").appendToArray(ar2);

You can then loop through the arrays, with specific functions applied:

$.each(ar1, function()
 {
  console.log(this.attr("name") + " is in ar1");
 }
);

$.each(ar2, function()
 {
  console.log(this.attr("name") + " is in ar2");
 }
);

Code generation with jQuery

Update: changed post title (content still same)

Sometimes, when you are developing in javascript, you need to reference many form inputs on a page, which can be time consuming (typing each one out). With jQuery, you can reduce the time by using jQuery to write the code (which you then copy and paste). For example (simplified, as you probably would not have fields named field1, field2, field3 etc):

var $field1 = $("[name='field1']");
var $field2 = $("[name='field2']");
var $field3 = $("[name='field3']");
var $field4 = $("[name='field4']");
var $field5 = $("[name='field5']");
var $field6 = $("[name='field6']");
var $field7 = $("[name='field7']");
var $field8 = $("[name='field8']");
var $field9 = $("[name='field9']");

This simple script can be used to create the aforementioned code. Includes an ASP.NET fix (if you don't want names like $ctl00$Content1$Field1)

$(
 function()
 {
  var $inputs = $(":input");
  var $textarea = $("<textarea>").css({width: "100%", height: "200px"});
  $inputs.each(
   function()
   {
    // $textarea.append("var $" + this.name + " = $(\"[name='" + this.name + "']\");\n");
    // ASPNET fix to get the name as set server side
    $textarea.append("var $" + ASPNETFix(this.name) + " = $(\"[name$='" + ASPNETFix(this.name) + "']\");\n");
   }
  );
  $("body").append($textarea);
 }
)

function ASPNETFix(name)
{
 return name.split("$").pop();
}

Simply save this into a separate JavaScript file (tweaking as needed), include on your page, then copy the text generated in the textarea at the bottom of the page.

This could also save time in other languages, as you control the output (could be C#, VB.NET, PHP, Python etc).

HTML 5 Basic Template

Since HTML 5 is likely to be in common use at some time in the future (taking advantage of current/future web browsers standards rendering mode) and the W3C validation service now validates HTML 5.

<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
 <title>Site | Page 1</title>
</head>
<body>
 <div id="outer">
  <div id="top"></div>
  <div id="inner">
   <div id="header"><h1>Page 1</h1></div>
   <div id="navigation">
    <ul>
     <li class="current"><a href="#">Page 1</a></li>
     <li><a href="#">Page 2</a></li>
     <li><a href="#">Page 3</a></li>
    </ul>
   </div>
   <div id="content">
    <p>Lorem ipsum dolor sit amet...</p>
   </div>
   <div id="footer"><a href="#top">Top of page</a></div>
  </div>
  <div id="bottom"></div>
 </div>
</body>
</html>

Note: the Content-Type meta element has to be the first element under the head element to validate. In HTML elements can be optionally self closing (so <br /> and <br> are both valid.

Notice that there are 'top' and 'bottom' elements in the markup? They are used to allow the margin-top/bottom for the 'inner' <div> to work in Firefox. 'top' also functions as an anchor to get back to the top of the page.

Example of CSS that can be used with this template:

body {
 color: #000;
 background: #fff;
 margin: 0;
 padding: 10px
}

#outer {
 width: 960px;
 margin: 0 auto;
 background: #eee
}

#top {
 padding-bottom: 1px; margin-bottom: -1px /* force #inner margin-top to take effect in Firefox/WebKit */
}

#inner {
 margin: 3px; /* margin: 0 3px 3px 0; for drop shadow effect */
 border: 1px solid #009;
 background: #fff
}

#header { background: #eee }

#header h1 { margin: 0}


#navigation {
 background: #eef;
 width: 100%;
 overflow: hidden;
 border-width: 1px 0 1px 0;
 border-style: solid;
 border-color: #009
}

#navigation ul {
 margin: 0;
 padding: 0;
 list-style-type: none;
 float: right
}

#navigation ul li { float: left }

#navigation ul li a:link,
#navigation ul li a:visited {
 display: block;
 float: left;
 padding: 3px;
 zoom: 1 /* force hasLayout in IE */
}

#navigation ul li a:hover {
 background: #000;
 color: #fff
}

#navigation ul li a:active,
#navigation ul li.current a:link,
#navigation ul li.current a:visited,
#navigation ul li.current a:hover {
 background: #aaa;
 color: #ffe
}


#content { padding: 3px }

#footer {
 padding: 6px;
 border-top: 1px solid #009
}

#bottom {
 padding-top: 1px; margin-top: -1px /* force #inner margin-bottom to take effect in Firefox/WebKit */
}

Wednesday, December 03, 2008

DataBinding to an Enumeration / enum (C#, ASP.NET)

Enumeration types in C# can be used for many purposes. One such use is to reduce repetitive typing as they can be bound to server controls (e.g. Repeaters).

In code behind:

public enum WeekDays
{
 Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
}

In your page:

<asp:Repeater runat="server" DataSource='<%# Enum.GetValues(typeof(WeekDays)) %>'>
 <HeaderTemplate>
 <table>
 <thead>
  <tr>
   <th>Day</th>
   <th>Start Time</th>
   <th>End Time</th>
  </tr>
 </thead>
 <tbody>
 </HeaderTemplate>
 <ItemTemplate>
  <tr>
   <td><%# Container.DataItem %></td>
   <td><%# GetStartTime(Container.DataItem) %></td>
   <td><%# GetEndTime(Container.DataItem) %></td>
  </tr>
 </ItemTemplate>
 <FooterTemplate>
 </tbody>
 </table>
 </FooterTemplate>
</asp:Repeater>

GetStartTime and GetEndTime are just examples (so would just need writing in the code behind).

protected string GetStartTime(object day)
{
....
}
protected string GetEndTime(object day)
{
....
}

Friday, November 28, 2008

jQuery 1.2.6 Text Clips for Programmer's Notepad 2

jQuery 1.2.6 Text Clips for Programmer's Notepad 2 are available along with my other text clips. If they don't show when you start PN2, close it and delete installClipCache.xml that is stored within the %APPDATA%\Echo Software\PN2\ directory.

Programmer's Notepad 2 is an open source application that supports syntax highlighting of many file types, project support (using its own project file type), autocompletion, text clips (snippets), automatic indenting among other features. It loads quickly (startup is faster than IDE's like Visual Studio, Eclipse and Komodo have), so is a good lightweight IDE that is also portable (save it on your portable hard drive / memory stick and run on many different PC's).

Friday, November 14, 2008

GIMP Repeating Guidelines

Update (18 Nov): bug fix - guides go up to both edges, if width/height is a multiple of the separation distance. max was set to height (if vertical guide) when it should have been width and vice versa for vertical.

The GIMP photo/image manipulation program allows you to add guides as an aid to image editing. It is fairly simple to add them - Image > Guides > New Guide or click on one of the rulers and drag onto the canvas. However, this can be time consuming if you need to add multiple guides, equally spaced.

Script-Fu however, allows you to do this via scripting. First of all, create a scm file (e.g. guides-repeat.scm) in your script folder (on Windows this would be C:\Program Files\GIMP-2.0\share\gimp\2.0\scripts (all users) or %USERPROFILE%\.gimp-2.6\scripts, then paste in the following code (use a plain text editor like Notepad)

(define (script-fu-guide-repeat image
                             drawable
                             direction
                             separation)
  (let* (
        (width (car (gimp-image-width image)))
        (height (car (gimp-image-height image)))
  (position 0)
  )
 ; set maximum otherwise the guides will be added indefinitely
 (if (= direction 0)
   (set! max height)
   (set! max width)
 )
 ; while the position is less than the maximum
 (while (<= position max)

  (if (= direction 0)
   ;; check position is inside the image boundaries
   (if (<= position height) (gimp-image-add-hguide image position))
   (if (<= position width) (gimp-image-add-vguide image position))
  )
  
 ; increment position by defined separation 
 (set! position (+ position separation)))
 (gimp-displays-flush)
  )
)

(script-fu-register "script-fu-guide-repeat"
  _"R_epeating Guide"
  _"Add multiple guides separated by specified number of pixels"
  "Sam Collett"
  "Sam Collett"
  "2008-11-18"
  "*"
  SF-IMAGE      "Image"      0
  SF-DRAWABLE   "Drawable"   0
  SF-OPTION     _"Direction" '(_"Horizontal" _"Vertical")
  SF-ADJUSTMENT _"Separation"  (list 40 1 MAX-IMAGE-SIZE 1 10 0 1)
)

(script-fu-menu-register "script-fu-guide-repeat"
                         "<Image>/Image/Guides")

After saving the script, either restart GIMP or Filters > Script-Fu > Refresh Scripts (GIMP 2.6, earlier versions use Xtns instead of Filters). Repeating Guides should now appear under Image > Guides

Friday, November 07, 2008

Searching Indexing Service (ASP.NET C#)

Windows has an Indexing Service that can be used to index files on the server it is hosted on. Here is a simple way to query any catalogues (in this example, one called Data) you create and display the results in a repeater.

First of all, create a new page (in Visual Studio or Web Developer 2005), e.g. search.aspx. Create the search box and repeater within a form runat="server":

<form id="form1" runat="server">
<div>
 <asp:TextBox runat="server" ID="Search" />
 <asp:Button runat="server" Text="Search" OnClick="SearchDocuments" />
 <asp:Repeater ID="ResultsRepeater" runat="server">
  <HeaderTemplate>
   <table>
    <thead>
     <tr>
      <th>
       Filename
      </th>
      <th>
       Size
      </th>
      <th>
       Title
      </th>
      <th>
       Path
      </th>
      <th>
       Last Modified
      </th>
      <th>
       Rank
      </th>
     </tr>
    </thead>
    <tbody>
  </HeaderTemplate>
  <ItemTemplate>
   <tr>
    <td>
     <%# Eval("Filename") %>
    </td>
    <td>
     <%# Eval("size") %>
    </td>
    <td>
     <%# Eval("DocTitle") %>
    </td>
    <td>
     <%# Eval("path") %>
    </td>
    <td>
     <%# Eval("write") %>
    </td>
    <td>
     <%# Eval("rank") %>
    </td>
   </tr>
  </ItemTemplate>
  <FooterTemplate>
   </tbody> </table></FooterTemplate>
 </asp:Repeater>
</div>
</form>

Then in your code behind (search.aspx.cs) add:

protected void SearchDocuments(object sender, EventArgs e)
{
 String fileTypes = "\".doc\" OR \".rtf\"";
 String catalog = "Data";
 String q = Search.Text;
 q = q.Replace("'", "''");

 String query = "SELECT DocTitle,Filename,size,path,rank,write,vpath,url from SCOPE() WHERE FREETEXT('"+q+"') AND CONTAINS(Filename, '"+fileTypes+"') ORDER BY rank DESC, write DESC";

 OleDbConnection cn = new OleDbConnection("Provider=MSIDXS.1;Integrated Security .='';Data Source='Data'");

 OleDbDataAdapter cmd = new OleDbDataAdapter(query, cn);

 DataSet data = new DataSet();
 cmd.Fill(data);

 DataView results = new DataView(data.Tables[0]);

 ResultsRepeater.DataSource = results;
 ResultsRepeater.DataBind();

}

The results are sorted by rank (highest first), then date last modified (newest first). Only search Word documents (or more precisely, filenames containing .doc or .rtf) - but you can always add more types and refine the search further.

Wednesday, October 15, 2008

Link: jQuery + ASP.NET

JQuery | Encosia has several articles related to the use of jQuery with ASP.NET. Microsoft AJAX can add quite a lot of overhead and so the use of jQuery can help reduce that.

Monday, October 06, 2008

Select box manipulation with jQuery - update to removeOption, new selectedOptions

Check the Select Box Manipulation project page at the jQuery site for the latest download.

Thursday, September 25, 2008

Easy database querying with dOOdads (C#, .NET)

Been some time since I posted about MyGeneration and dOOdads. Still using it regularly, even though it is a few years old now. A few sites I do still use .NET 1.1, so it is still in use.

A brief (re)introduction - MyGeneration is a tool that can generate code for you, through the use of templates (you can create your own, and there is a template library). It comes bundled with the dOOdads data abstraction library, which allows you to update and query your database without knowing the intricacies of interacting with it (i.e. .NET classes to use, SQL to write etc). Both MyGeneration and dOOdads support multiple databases (SQL Server, MySQL, Oracle etc) and regeneration of code, changing the connection string is often all that is needed to move to another system.

It was freeware initially, but is now hosted on SourceForge and no longer actively maintained by the main developers.

A basic example of a query would be:

Employees e = new Employees();
e.Where.EmployeeID.Value = 1;
if(e.Query.Load())
{
    SurnameTextBox.Text = e.Surname;
}

You can even select multiple employees with different EmployeeID's:

Employees e = new Employees();
e.Where.EmployeeID.Value = "1,3,7";
e.Where.EmployeeID.Operator = WhereParameter.Operand.In;
if(e.Query.Load())
{
    ....
}

For columns of type 'bit' (e.g. true, false), where you want to treat NULL as false, you use a TearOff:

Employees e = new Employees();
e.Query.OpenParenthesis();
e.Where.DrivingLicense.Value = false;
WhereParameter driving = e.Where.TearOff.DrivingLicense;
driving.Operator = WhereParameter.Operand.IsNull;
// add conjunction and close parenthesis
driving.Conjuction = WhereParameter.Conj.Or;
e.Query.CloseParenthesis();
if(e.Query.Load())
{
    ....
}

Note: driving.Conjuction is correct, it is a typo in dOOdads.

jQuery UI draggables - helper CSS class

While working with jQuery UI draggables, I have noticed that there does not seem to be a class associated with the draggable helper, and so it is styled in the same way as the draggable you selected. As a result you have to resort to the start function option to add the class dynamically:

$(".dragme").draggable({helper: "clone",
 start: function(e, ui)
 {
  $(ui.helper).addClass("ui-draggable-helper");
 }
});

Then just create a style for ui-draggable-helper, e.g.

.ui-draggable-helper {
 border: 1px dotted #000;
 padding: 6px;
 background: #fff;
 font-size: 1.2em;
}

Friday, September 12, 2008

Place JavaScript code at bottom of page

Recently I've been placing scripts at the bottom of the page, instead if the top. However, I don't put all of them there - the key ones required by other scripts (e.g. libraries like jQuery) are still in the header. The pages can appear to load faster, and in some cases may save some (albeit not always that much) code, e.g.

....
<script src="js/jquery-1.2.6.min.js" type="text/javascript"></script>
<script type="text/javascript">
$( function()
{
 $("a.foo").click(doSomething);
};
function doSomething()
{
 return confirm("About to visit " + this.href + ", continue?");
}
</script>
</head>
<body>
...
</body>
</html>

Can instead be:

....
<script src="js/jquery-1.2.6.min.js" type="text/javascript"></script>
</head>
<body>
...
<script type="text/javascript">
$("a.foo").click(doSomething);
function doSomething()
{
 return confirm("About to visit " + this.href + ", continue?");
}
</script>
</body>
</html>

In some circumstances, the script may query the CSS of an element and so the script may run before the associated stylesheet has downloaded (at least, I have experienced this in Google Chrome).

This does assume that you have not attached javascript functions inline (e.g. a onclick="doSomething()" as these would fail if the user interacts with elements before the function is available.

If you use 'DOM ready' events, then there is less benefit of doing this (as it should run when the page is ready anyway). As with any optimisations, it is always worth experimenting to reduce the time it takes for a page to be used and interacted with by visitors.

Tuesday, August 26, 2008

jQuery Quick Tip: In general $(this).attr("attribute") = this.attribute

jQuery is a very useful JavaScript library for manipulating you web pages. However, I have seen it used to get attribute values when it doesn't have to be, normally to get element attributes. For example, opening all links with a class external and giving them a title (tooltip).

$("a.external").click( function()
  {
    window.open($(this).attr("href"));
    return false;
  }
).each( function()
  {
    $(this).attr("title", $(this).attr("title") + " External link: " + $(this).attr("href"));
  }
);

Would be the same as

$("a.external").click( function()
  {
    window.open(this.href);
    return false;
  }
).each( function()
  {
    this.title += " External link: " + this.href;
  }
);

There are some attributes that in JavaScript aren't the same as they are in html. The ones you may have issues with are listed below.

for          (htmlFor)
class        (className)
readonly     (readOnly)
maxlength    (maxLength)
cellspacing  (cellSpacing)

Doing this rather than using attr cuts down on code size and may improve performance.

Thursday, August 14, 2008

Querying a SQLite 3 database using PHP

Previously, I detailed a way of creating a database in A basic hit counter using PHP and SQLite 3 using PHP Data Objects and PHP 5. For most web sites, SQLite would be fine, but for very high volume (as in many hundreds of thousands of hits per day), there are better options - Appropriate Uses For SQLite (SQLite.org) has more details on when SQLite is a good option.

Here is an example of how to query the data and display it on a page (to see which pages are popular for example).

<?
$dbfolder = $_SERVER["DOCUMENT_ROOT"]."/data/";
$dbname = $_SERVER["HTTP_HOST"]."_log.sq3";

$logdb = new PDO("sqlite:".$dbfolder.$dbname);

$starttable = "<table>
<tr>
 <th>Page</th>
 <th>Counter</th>
</tr>";
$endtable = "</table>";
$tablecontents = "";
foreach ($logdb->query("SELECT * FROM hits ORDER BY counter DESC") as $row)
{
 $tablecontents .= "
 <tr>
  <td>{$row['page']}</td>
  <td>{$row['counter']}</td>
 </tr>";
}
echo $starttable.$tablecontents.$endtable;

// close connection
$logdb = null;
?>

Tuesday, August 12, 2008

A basic hit counter using PHP and SQLite 3

SQLite is a lightweight database engine that is bundled with PHP 5. Using PHP Data Objects (PDO) you can create and edit SQLite databases and tables. A SQLite databases is just a single file that is stored in a folder that has modify rights applied to it (otherwise you can't change it).

This sample shows how to create a database, add a table to it and insert and update a record in it. By using PDO, you can easily change it to use different database engines (like MySQL, IBM DB2 etc [others, like MSSQL and Oracle are in a experimental stage though, check the PDO site (linked above) for more information]).

You can copy this code into a separate file and include it within pages that you want a counter on <? include("counter.php"); ?>.

<?
// logging page hits
$dbfolder = $_SERVER["DOCUMENT_ROOT"]."/data/";
$dbname = $_SERVER["HTTP_HOST"]."_log.sq3";

// check if database file exists first
if(!file_exists($dbfolder.$dbname))
{
 $logdb = new PDO("sqlite:".$dbfolder.$dbname);
 $logdb->exec("CREATE TABLE hits(page VARCHAR(255) PRIMARY KEY, counter INTEGER)");
}
else
{
 $logdb = new PDO("sqlite:".$dbfolder.$dbname);
}

$page = $_SERVER["SCRIPT_URL"];

// check if page is already in the hits table
$statement = $logdb->query("SELECT counter FROM hits WHERE page='$page'");
$record = $statement->fetchAll();

// if a record is found
if(sizeof($record) != 0)
{
 $counter = $record[0]['counter']++;
 $logdb->exec("UPDATE hits SET counter=$counter WHERE page='$page'");
 echo "Counter: ".$counter;
}
else
{
 $logdb->exec("INSERT INTO hits(page, counter) VALUES ('$page', 1)");
 echo "Counter: 1";
}

// close connection
$logdb = null;
?>

In writing this code, LiteWebsite was a valuable resource, containing many SQLite examples.

Wednesday, July 23, 2008

JavaScript dates and timezone offsets

Working with dates can be problematic when handling dates returned by a remote server. They were returned in GMT format, but when displayed on a page, the time was either ahead or behind (depending on which timezone you are in). For example, if you have the date returned via JSON:

var dates = {"StartDate": new Date(1216944000000),"EndDate": new Date(1217030399000)}

So the date now has the timezone offset added:

dates.StartDate = Fri Jul 25 2008 01:00:00 GMT+0100 (GMT Standard Time)
dates.EndDate = Sat Jul 26 2008 00:59:59 GMT+0100 (GMT Standard Time)

So now, to take into account the timezone offset, getTimezoneOffset() can be used, along with setMinutes() and getMinutes()

dates.StartDate.setMinutes(dates.StartDate.getTimezoneOffset() + dates.StartDate.getMinutes());
dates.EndDate.setMinutes(dates.EndDate.getTimezoneOffset() + dates.EndDate.getMinutes());

For a useful JavaScript library for working with dates (it extends the native Date object), check out Datejs. 30kb download, under an MIT open source license.

There is also another library, a smaller download (so slightly less functionality) available with the jQuery datePicker plugin - http://code.google.com/p/jqueryjs/source/browse/trunk/plugins/datePicker/v2/demo/date.js, under a dual MIT / GPL license. For more localisations (as well as string and array manipulation), visit http://code.google.com/p/jqueryjs/source/browse/trunk/plugins/methods. Note: jQuery is not required for these libraries to work.

GPL Compatible Licenses

There is a useful diagram on the GNU site that lists what licences are compatible with the GNU GPL: A Quick Guide to GPLv3: New Compatible Licenses, plus a comprehensive list with more detailed compatibility information.

Tuesday, July 22, 2008

Link: HTML Agility Pack (.NET)

The HTML Agility Pack is an HTML parser for .NET, supporting XPATH and XSLT parsing. Basically the HTML equivalent of XmlDocument.

Example use (from site):

HtmlDocument doc = new HtmlDocument();
doc.Load("file.htm");
foreach(HtmlNode link in doc.DocumentElement.SelectNodes("//a[@href]")
{
    HtmlAttribute att = link["href"];
    att.Value = FixLink(att);
}
doc.Save("file.htm");

Tuesday, July 15, 2008

Portable GIMP and fonts

GIMP (GNU Image Manipulation Program), the open source alternative to Photoshop can be downloaded as a portable version. However, due to being portable, the choice of fonts you can use is limited by what is on the operating system and part of the basic GIMP package, so if you use the font tool and choose a font that is not on another system, you may have problems. Thankfully, fonts are easy to copy (you can copy them from the Fonts applet in the control panel by just dragging them to another folder).

To make your fonts available wherever you use GIMP Portable, you just copy them to E:\PortableApps\GIMPPortable\App\gimp\share\gimp\2.0\fonts (where E: is the drive letter of your portable drive). Then you can go on any Windows PC (even without Office or OpenOffice installed) and still use your own fonts (those which you are licensed for).

Monday, July 07, 2008

JSON and JsonML

JSON (JavaScript Object Notation) is a data interchange format for transferring data between disparate systems. Unlike XML (which is also designed for this), it is far simpler and can be processed more easily by client applications (no validation, or other advanced features of XML) and easier to implement (no special parser needed like XML) - JSON: The Fat-Free Alternative to XML. There are examples of JSON messages (and the XML equivalent) on the JSON Example page. You can validate JSON online using JSONLint.

While its name suggests that it is only for programmers using JavaScript, it is useful for other programming languages as well. The JSON site lists implementations and even hosts code for several languages, e.g. JavaScript, C and Java.

JsonML is a way of transporting XML data by representing it in the JSON syntax. As a result, it can be be used for transmitting XHTML markup (represented as JSON rather than XHTML) which can then be added directly to the document (via the DOM, instead of innerHTML). For jQuery developers, there is a plugin for working with JsonML: JSONML Array to DOM - jQuery.ml

Thursday, July 03, 2008

An overview of jQuery.browser

Update: jQuery.version should have been jQuery.browser.version. Added Firefox 3.0.1

If you are a user of jQuery, you may be aware of the basic browser sniffer that comes with it. However, it may seem to return the wrong version number for certain browsers (Firefox and Safari in particular). This is because it returns the version number of the rendering engine (i.e. the part of the web browser that determines how a page should look and function). To help simplify things, I have created a table of common user agents and what jQuery returns:

BrowserjQuery.browserjQuery.browser.version
Internet Explorer 6jQuery.browser.msie = true6.0
Internet Explorer 7jQuery.browser.msie = true7.0
Firefox 1.5 (first release)jQuery.browser.mozilla = true1.8 or 1.8.0
Firefox 1.5.0.9jQuery.browser.mozilla = true1.8.0.9
Firefox 2.0 (first release)jQuery.browser.mozilla = true1.8.1
Firefox 2.0.0.9jQuery.browser.mozilla = true1.8.1.9
Firefox 3.0jQuery.browser.mozilla = true1.9
Firefox 3.0.1jQuery.browser.mozilla = true1.9.0.1
Safari 2.0.2jQuery.browser.safari = true416.11 / 416.12
Safari 2.0.4jQuery.browser.safari = true418.x - 419
Safari 3.0.xjQuery.browser.safari = true522+, 522.x, 523.x
Safari 3.1.xjQuery.browser.safari = true525.x, 526+
Opera xjQuery.browser.opera = truex

I have listed Opera as 'Opera x' as the version number 'x' is always returned by jQuery.browser.version (so no extra work is required, unlike Firefox and Safari).

This table is based on information from UserAgentString.com. There is a Firefox 1.5.0.12, but I am unsure of the version number, plus there are Safari versions with a slightly different rendering engine version number (i.e. 2.0.2 is not always 416.11). Basically, with Safari, if the version number returned is less than 418, it is Safari 2 or lower and if it is around 525/526 it is Safari 3.1.

Tuesday, July 01, 2008

Link: FreeTechBooks.com

FreeTechBooks.com is a site that offers many computing and engineering related text books (topics include Computer Science, Mathematics, Programming etc) available to download for free./p>

Wednesday, June 25, 2008

Link: IconsPedia

IconsPedia is a site with many icons free for download. Check the license first to see if you can use it for the purpose you want it for (some have conditions - not for commercial use, and/or must attribute (give credit to) the author). You can also upload any icons that you have produced (as long as they are free).

Thursday, June 19, 2008

Link: A list of .NET Cheat Sheets

.NET Cheat Sheets includes ".NET Format String Quick Reference", "ASP.NET 2.0 Page Life Cycle & Common Events", "Visual Studio 2005 Built-in Code Snippets (C#)" as well as links to several more.

Tuesday, June 17, 2008

Tabs without JavaScript

It is possible to implement a tabbing system without needing to use JavaScript. All you need is CSS and standard (X)HTML. The downside is that you won't get styling on the active tab to indicate that it is active.

CSS:

div.tabcontainer {
 width: 500px;
 background: #eee;
 border: 1px solid #000000;
}
ul.tabnav {
 list-style-type: none;
 margin: 0;
 padding: 0;
 width: 100%;
 overflow: hidden;
}

ul.tabnav a {
 display: block;
 width: 100%;
}

ul.tabnav a:hover {
 background: #ccc;
}

ul.tabnav li {
 float: left;
 width: 125px;
 margin: 0;
 padding: 0;
 text-align: center;
}

div.tabcontents {
 height: 290px;
 background: #ccc;
 overflow: hidden;
 border-top: 1px solid #011;
 padding: 3px;
 
}

div.tabcontents div.content {
 float: left;
 width: 100%;
 height: 102%;
 overflow-y: auto;
}

div.tabcontents div.content h2 {
 margin-top: 3px;
}

HTML:

<div class="tabcontainer">
 <ul class="tabnav">
  <li><a href="#tab1">Tab 1</a></li>
  <li><a href="#tab2">Tab 2</a></li>
  <li><a href="#tab3">Tab 3</a></li>
  <li><a href="#tab4">Tab 4</a></li>
 </ul>
 <div class="tabcontents">
  <div class="content" id="tab1">
   <h2>Tab 1</h2>
  </div>
  <div class="content" id="tab2">
   <h2>Tab 2</h2>
  </div>
  <div class="content" id="tab3">
   <h2>Tab 3</h2>
  </div>
  <div class="content" id="tab4">
   <h2>Tab 4</h2>
  </div> 
 </div>
</div>

Demo page

Friday, June 13, 2008

Recursive Directory Listing (PHP)

In PHP, it is possible to get a list of files and folders and save them into an array: PHP: List files in a directory. Building on this, I have added recursion to the dirList function detailed in the aforementioned link:

/**
* Return a list of all files within a directory
*
* @param string $directory The directory to search
* @param bool $recursive Go through child directories as well
* @return array
*/
function dirList($directory, $recursive = true) 
{
 // create an array to hold directory list
 $results = array();

 // create a handler for the directory
 $handler = opendir($directory);

 // keep going until all files in directory have been read
 while (false !== ($file = readdir($handler)))
 {
  // if $file isn't this directory or its parent, 
  // add it to the results array
  if ($file != '.' && $file != '..')
  {
   // if the file is a directory
   // add contents of that directory
   if(is_dir($directory.DIRECTORY_SEPARATOR.$file) && $recursive === true)
   {
    $results[] = array($file => dirList($directory.DIRECTORY_SEPARATOR.$file));
   }
   else
   {
    $results[] = $file;
   }
  }
 }

 // tidy up: close the handler
 closedir($handler);

 // done!
 return $results;

}

Now you can build a list of files/folders generated with dirList:

/**
 * Return an unordered html list of all files within a directory
 *
 * @param string $directory The directory to search
 * @param array $fileTypes Which fileTypes to show. To list all files use htmlDirList("mydir", array("*"))
 * @param bool $recursive Search through child directories as well
 * @param string $listClassName The class name to apply to the <ul>
 * @param function $displayName A function to call on the file to determine how it is displayed (e.g. change _ to space)
 * @return array
 */
function htmlDirList($directory, $fileTypes = null, $recursive = true, $listClassName = null, $displayName = null)
{
 // defaults (if null)
 // restrict by fileTypes
 $fileTypes = (is_null($fileTypes) ? array("doc","rtf","pdf") : $fileTypes);
 // the class name to apply to the <ul>
 $listClassName = (is_null($listClassName) ? "documents" : $listClassName);
 // set a default function for displayName
 $displayName = (is_null($displayName) ? create_function('$fileName,$extension', 'return str_replace("_", " ", $fileName);') : $displayName);
 
 // get list of files / folders
 $list = dirList($directory, $recursive);
 
 // use an array for building up the string
 $results = array();
 // create the list
 $results[] = "<ul class=\"$listClassName\">\n";
 foreach ( $list as $value )
 {
  // is a folder
  if(is_array($value))
  {
   $results[] = "<li class=\"directory\">".$displayName(key($value),"")."\n".htmlDirList($directory.DIRECTORY_SEPARATOR.key($value), $fileTypes, $recursive, $listClassName, $displayName)."</li>\n";
  }
  else
  {
   // the extension is after the last "."
   $extension = strtolower(array_pop(explode(".", $value)));
   // the file name is before the last "."
   $fileName = array_shift(explode(".", $value));
   // continue to next item if not one of the desired file types
   if(!in_array("*", $fileTypes) && !in_array($extension, $fileTypes)) continue;
   // add the list item
   $results[] = "<li class=\"file $extension\"><a href=\"".str_replace("\\", "/", $directory)."/$value\">".$displayName($fileName, $extension)."</a></li>\n";
  }
 }
 $results[] = "\n</ul>";
 
 // return the results as a string
 return implode("", $results);
}

So now you can get create documents within a folder and have a page listing all those documents, all linked to. In your PHP page:

<?php echo htmlDirList("documents") ?>

The generated code is not formatted, but doing so would add further complexity and be of no benefit (apart from readability).

<ul class="documents">
<li class="file doc"><a href="files/File1.doc">File1</a></li>
<li class="file pdf"><a href="files/File_2.pdf">File 2</a></li>
<li class="file rtf"><a href="files/File_3.rtf">File 3</a></li>
<li class="directory">more
<ul class="documents">
<li class="file doc"><a href="files/File4.doc">File4</a></li>
<li class="file pdf"><a href="files/File_5.pdf">File 5</a></li>
<li class="file rtf"><a href="files/File_6.rtf">File 6</a></li>
</ul></li>
</ul>

There are also more options available, e.g. you may want an image listing:

<?php echo htmlDirList("images", array("jpg","gif","png"), true, "images") ?>

Simple JavaScript/CSS gzipping

I'm sure some may already do this, but compressing textual content can save bandwidth but also make it easier to maintain (by just including a php file instead of a CSS or JavaScript one). For example, create a file jquery.php in the same directory as JavaScript files:

<?php
ob_start("ob_gzhandler");
header("Content-Type: text/javascript");
include("jquery-1.2.6.min.js")
?>

Then include it instead of the normal JavaScript file:

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

It's simple to maintain and could be improved (for example, some kind of caching). CSS files can also be used:

<?php
ob_start("ob_gzhandler");
header("Content-Type: text/css");
include("styles.css")
?>

Friday, June 06, 2008

Delete all cached thumbnails (thumbs.db on Windows system)

Not web related, but possibly of interest.

thumbs.db is a file that caches the thumbnails of images stored within a folder. There are tools for deleting these files, but they are often through the use of an application to be downloaded or installed. There is an easy way to do this without resorting to that, just by using the command prompt.

del *thumbs.db /s /ah

This will delete all files (and folders) ending in thumbs.db (e.g. myappthumbs.db), so don't run this if you are unsure (or run it in a folder other than C:\). The /ah parameter searches hidden files and folders as well (so you may get access denied on C:\RECYCLER)

Disclaimer: Be very careful with this as a typo could prove disastrous. Do not run this if you are not completely sure and don't have a backup if a mistake is made.

Wednesday, May 28, 2008

Google now hosting JavaScript libraries (jQuery, Prototype et al)

Google now offers a service for hosting popular JavaScript libraries, so for any website this is used on the performance will be better (the user may have already downloaded the file on another site and it is cached) and it will reduce the bandwidth your server uses. So far it hosts jQuery, prototype, script.aculo.us, Mootools and Dojo. You can either load it via the Google AJAX API or the <script/> tag. The advantage of using the Google API is that it can be used for Google's services as well (like Maps, RSS/Atom Feeds and Search (Analytics is missing from the list though)).

Thursday, April 17, 2008

jQuery Quick Tip: Rollover images with jQuery

Update: Demo page created

There are several sites that show you how to create rollover images with jQuery (just search Google, Ask, A9, Yahoo etc) for "rollover image jquery"), but they do sometimes have more code than needed (like using $(this).attr("src") instead of this.src for determining the image source. Here is another method that does not use jQuery unnecessarily (which may be faster if there are lots of images).

Create two images, for the 'off' state (when mouse is not over it) and the 'on' state (on mouse over). Name them button_off.gif and button_on.jpg (the button bit can be anything, as can the extension (.gif) - the important bit is the _off and _on suffix.

HTML code:

<a id="mylink" href="/go/somewhere/"><img src="/images/button_off.gif" alt="" title="" border="0" width="100" height="30" /></a>

Then in your $(document).ready:

$("#mylink img").hover(
 function()
 {
  this.src = this.src.replace("_off","_on");
 },
 function()
 {
  this.src = this.src.replace("_on","_off");
 }
);

Due to its generic nature, it can be applied to multiple images, e.g. those with a class .rollover set $("img.rollover").hover...

Monday, April 14, 2008

pastebin sites

A pastebin is a site that allows you to share text with other, most commonly source code, but could be anything else as well (like prose or poetry - e.g. you are writing a novel or poem and want to share what you write). They are useful if you do not have a web site to post what you have written and want to share it to get any feedback (like spotting any bugs or spelling mistakes).

They allow you to post without registering or paying and the pastes normally expire after a set period (e.g after a month) so as to reclaim any lost disk space for the host. Source Code highlighting is often a feature of many as well. Some of them offer more than this, like comparison (e.g. diff's), password protection / encryption and notifications (to alert you of new pastes, or replies to pastes - normally through a chat system like IRC). The open nature of them could render them susceptible to spam though.

The following is a list of pastebin's I am aware of. All offer syntax highlighting.

  • pastebin.com - possibly the first site to do this, you can view recent pastes and search them
  • pastebin.ca - more features than pastebin.com: encryption, tags and description
  • nopaste.info - description, name, tab width
  • LodgeIt! - very simple interface, powered by jQuery, reply to pastes, view diff's, remote queries (XML-RPC). You can't see recent pastes or perform a search though (although this probably mitigates spam somewhat)
  • pastie - separate code into sections, mark as private, select a theme when viewing pastes
  • dpaste - associate a title and your name / email

Wednesday, February 27, 2008

jQuery Quick Tip: Select text on focus

Just a quick tip on how to select all text when focus is given to a textarea or input (only if the value has not changed) .

$("input, textarea").focus(
 function()
 {
  // only select if the text has not changed
  if(this.value == this.defaultValue)
  {
   this.select();
  }
 }
)

Thursday, January 31, 2008

ASP.NET: Binding alphabet to dropdown list

Update: Added VB code.

There may be some cases where you want a DropDownList to list all the letters in the alphabet (i.e. A - Z). Rather than add the letter individually (through using <asp:ListItem>) you can create an ArrayList and bind to that.

In your ASPX page:

<asp:DropDownList ID="Letters" DataSource='<%# Alphabet %>' runat="server" />

In your code behind. Create your Alphabet property:

private ArrayList _Alphabet;
protected ArrayList Alphabet
{
 get
 {
  if (_Alphabet == null)
  {
   _Alphabet = new ArrayList();
   for (int i = 65; i < 91; i++)
   {
    _Alphabet.Add(Convert.ToChar(i));
   }
  }
  return _Alphabet;
 }
}
Protected ReadOnly Property Alphabet() As ArrayList
 Get
  If _Alphabet Is Nothing Then
   _Alphabet = New ArrayList()
   For i As Integer = 65 To 91 - 1
    _Alphabet.Add(Convert.ToChar(i))
   Next
  End If
  Return _Alphabet
 End Get
End Property

Bind on Page_Load:

private void Page_Load(object sender, EventArgs e)
{
 if(!Page.IsPostBack)
 {
  DataBind();
 }
}
Public Sub Page_Load() Handles MyBase.Load
 If Not Page.IsPostBack Then
  DataBind()
 End If
End Sub

This will show A - Z (capitals) in the dropdown. For a - z (lower case), change 65 to 97 and 91 to 123 in Alphabet

Tuesday, January 08, 2008

Adding rounded corners to your web pages

There are several ways of adding rounded corners to your web page. There is a large list of methods found at Rounded Corners - css-discuss, but also a few other ways using JavaScript (some using jQuery):

  • The first (as far as I am aware) jQuery corner plugin (Dave Methvin)
  • An improved version (Mike Alsup) of the above plugin
  • curvyCorners - anti-aliased corners, supporting borders and background images
  • A modified version of curvyCorners made to work with jQuery.
  • The above plugin was rather big and couldn't be packed, so someone else made a futher modification that reduced its size and enabled it to be packed.
  • Cornerz - smooth, anti-aliased corners. Another jQuery plugin. Anti-aliased, but does not support backgrounds.
  • Rounded corners using <canvas>. <canvas> is a way of drawing/manipulating images via scripting (e.g. draw vector images, transformation, compositing, animations etc). There is a tutorial available on how to use it. Firefox 1.5+, Opera 9+, Safari only - excanvas adds support to Internet Explorer.

Implementations are not always heavily tested within different layouts and CSS, so while a preferred one may not work as expected, there should still be a way to add the effect (even if it involves more code).

A very light-weight way to do this would be via CSS 3 (as it supports multiple background images), but sadly only Safari supports this: demo. Could be some way off as the CSS 3 specification isn't finalized (but neither is CSS 2.1), although it is a useful feature that will likely not change (or be removed) and be adopted by newer versions of currently developed browsers (Firefox 3 and IE8 should hopefully have this).