jQuery: searching and highlighting text

Searching and highlighting text is simple with jQuery. Here's a basic code for accomplishing this task:

function highlight () {

$('#search').submit(function() {
    
        var $query = $('#search #q').val();
        var re = new RegExp($query, 'g');
        var targetHtml = $('#text').html();

       if(re.test(targetHtml)) {
       
           var matches = targetHtml.match(re);
           
           $('#text').html(targetHtml.replace(re, '<span class="highlight">'+matches[0]+'</span>'));          
       
       } else {
       
           alert('Term not found.');
       
       }
    
        return false;
    });


}

$(document).ready(function() {

    highlight();
    


});

As you can see, I've used the RegExp object to turn user input into a regular expression. Then I performed a global search using the test() and match() methods of this object. You can see the final result here.

jQuery: sending an email with AJAX

Sending emails with AJAX is a common feature in a Web 2.0 application. jQuery can actually ease this process through its $.ajax() wrapper. To accomplish this task, you basically need a server side script for processing data and sending the email. For example, if you use PHP, you need something like this:

header('Content-Type: text/plain');

$subject = $_POST['subject'];
$message = $_POST['message'];
$email_from = 'you@site.com';
$to = $_POST['to'];
$headers = "From: John" . " " .  "Doe" . " " . "<". $email_from . ">" . "\r\n";

$recipient = "<" . $to . ">";

if(mail($recipient, $subject, $message, $headers)) {
        
        echo '<p class="success">Email sent successfully.</p>';
  
 } else {
        
        echo  '<p class="error">Problem with sending email.</p>';
 }

Adding jQuery is quite easy at this point:

function sendEmail() {

    $('#email-form').submit(function() {
    
    var subject = $('#email-form #subject').val();
 var message = $('#email-form #message').val();
 var to = $('#email-form #to').val();
 
 var data = 'to='+to+'&subject='+subject+'&message='+message;
 
 $.ajax({
     type: 'POST',
     url: 'http://yoursite.com/mail.php',
     data: data,
     success: function(html) {
     
         $(html).appendTo('#email-form');
       
     }
 });
 return false;
 
    
    
    });


}

Note two things in our example:

  1. I've used return false to prevent the form from performing its default action (that is, opening the URL specified in the action attribute)
  2. I've served the response as text/plain, because it's considerably faster than other types of responses.

CSS3: The border-radius shorthand property

The CSS3 border-radius property can be a little tricky when used as a shorthand property. The sad truth is that at the time of this writing some browsers support this property as a proprietary extension (for example, -moz-border-radius and -webkit-border-radius) with proprietary notations that can vary from a browser to another when it comes to single border properties, so using the shorthand version is a good thing to avoid confusion.

Anyway, most developers think that this property works exactly as other border properties, that is, following the order top-right-bottom-left. Right? Almost. Here are the exact values used for the border-radius shorthand property in the correct order:

border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-top-left-radius

These values set:

  1. the top right border
  2. the bottom right border
  3. the bottom left border
  4. the top left border

Let's say that you want to set only the top left and bottom right borders of a box. You can write something like this:

#box {
  background: gray;
  -moz-border-radius: 0 6px 0 6px;
  -webkit-border-radius: 0 6px 0 6px;
  border-radius: 0 6px 0 6px;
}

Note that we've used the proprietary extensions first. This is considered a good practice to make sure that a browser will always use the standard property, if it supports it.

jQuery: a peculiarity of AJAX URLs

I was developing a simple AJAX search engine with jQuery but things didn't work in the sense that for each query I got more results than I did expect. Most of you know that the $.ajax() object has a member called data, which is basically a property that stores all the data passed along with an AJAX request. In my code, the data property had this form:

$.ajax({
  type: 'GET',
  url: 'http://app.com/search.php',
  data: '?query=' + query.toLowerCase() + '&search-options=' + searchOption,
  success: function(html) {
    // do something
  }
});

Do you see the point? The trailing question mark (?) prepended to the data string makes all the search query invalid or, more precisely, makes the query return a mismatched set of search results. If you remove the question mark, everything works just fine. So the point is: never prepend invalid tokens to the data string, because jQuery doesn't need them. On the contrary, you might actually get unexpected results if you do so.

CSS turned off: a good approach to web development

Turning CSS off is a good way to check whether the underlying HTML structure is well-structured and makes sense without any styles. There are several reasons for following this approach. The first, and most important, is SEO: search engines spiders behave exactly as textual browsers (like Lynx) and all they see is a bare HTML structure. For example, if you've put your navigation bar first in the source, and then shifted it to left with floating or positioning, the spiders will parse it first so that there are reasonable chances to see a list of links in your search results (and this is not what you want), especially when you didn't provide a good description in your meta tags.

Another reason is accessibility and this topic is strictly related to SEO. In fact, assistive technologies read a web document exactly as a spider and you should bear this in mind when you structure your document. So if you have the aforementioned list of links before the main contents of your site, a screen reader will be forced to read aloud every single link of your list. To mitigate this problem, you can either choose to put a skip link before the navigation bar or move this list elsewhere on the page. One last thing: don't forget to take care of textual browsers by putting an hr element just after the end of each section of your page. This aids readability and provides a better user experience to those who use this kind of browsers.

Finally, keep in mind that all we said earlier also applies to mobile devices, especially those with a limited bandwidth. Not all the users of this kind of devices owns the latest version of their platform, so it's a best practice to make sure that the whole content of your document is still usable with CSS turned off.

Using CSS comments for debugging

Unlike JavaScript, CSS has no notion of break points. Break points are an useful way to adopt a step-by-step approach to debugging. For example, in JavaScript you can write something like this:

var test = document.getElementById('test');
alert(test);
var items = test.getElementsByTagName('li');
alert(items);

In this case, you're simply checking whether specific nodes exist or not. In CSS, you can use comments for debugging. Suppose that you have a code like this:

#box {
  width: 200px;
  border: 1px solid green;
}
#box div {
  width: 190px;
  padding: 10px;
  background: silver;
  border: 2px solid red;
}

There's a problem here: the inner box overflows its container. Where's the problem? If you use CSS comments, you can do something like this:

#box div {
  width: 190px;
  padding: 10px;
  background: silver;
  /* border: 2px solid red; */
}

By removing the last rule with a comment, you make sure that this rule is actually causing the problem. For complex CSS, this is a really useful way to handle debugging.

Problems with CSS layouts: bugs and anomalies

In this article from O'Reilly is condensed a good approach to problems with CSS layouts:

To fully understand CSS layout, you must not only be aware of it's benefits, but you must also be ready for some problems it presents. Most of these problems stem out from CSS's immaturity. Yes, the recommendation itself has been around for a while, but CSS layouts are only recently possible, and even more recently taken seriously by developers. Expect this immaturity to result in problems, such as:

  1. Layout limitations: The fact is that CSS layout will not currently allow you to do everything you can do with tables. This can be a real frustration, and has stopped many people from exploring what CSS can do. (I'll show you in this article that CSS can do quite a bit.)
  2. Slight differences in browser display: CSS is difficult for browser makers to implement, and the W3C recommendations can be vague and confusing. So you can expect even the most recent browsers to behave differently when dealing with some aspects of CSS layout. Keep your layout simple enough and you will likely get a nearly identical display in Opera 5+, NS6, and IE5+. But as your layout increases in complexity, the odds that different browsers will render pages differently also increases.
  3. Difficulty in switching from tables to CSS: For designers and developers accustomed to wrangling tables, using CSS for layout can be a confusing change. There is a "table mentality" that we developers have taken on over the years, and we are in large part unaware that it exists. Some take offense when this is pointed out, complaining instead that CSS is just difficult and non-intuitive. But if you were accustomed to driving a car with a steering wheel and you were then asked to head out on the freeway in a car steered with foot pedals, you certainly wouldn't be offended at the suggestion you had a "steering wheel mentality." The fact is, we are generally comfortable with tables. CSS layout is different, but we must not confuse differences with increased complexity.

So then, with all these problems, why use CSS? You'll have to make this decision yourself. Many people I know use CSS layouts for personal web projects, but still resort to tables when working on commercial sites. The time is coming when CSS will be suitable and preferred for all site layout, but many reasonably argue that the time has not yet arrived.

I use CSS because I believe in the fundamental principle of the separation of structure and presentation, and I am willing to put up with the problems CSS presents as I look forward to a time when CSS is as robust and simple to implement as tables are today. That time will come, and the web will be a better place for it.

Problems usually fall into two categories: bug and anomalies. Bugs are explicit violations of the CSS specifications. For example, all the rendering inconsistencies of IE 6 and 7 due to the hasLayout property are clearly bugs. On the other hand, anomalies are just different interpretations of the specifications. Different interpretations occur either when CSS specifications are not clear on a topic or when they don't say anything at all. For example, table rendering is a perfect example of the former case, whereas form elements is a good example of the latter.

You should always read carefully the CSS specifications to make clear to yourself when you're dealing with a bug or an anomaly. For example, negative text indentation works correctly in all browsers except that it fails in IE 6 and 7. Basically, if the affected text overflows the box boundaries (e.g. in the case of hanging text), IE will crop the exceeding text while other browsers will show it as expected. CSS specifications state that the text-indent property can accepts negative values, but they didn't say how browsers should handle this particular case.

In short, when there's a dubious case, browsers can either choose not to implement something or to implement it with some kind of limitations. If you bear this in mind, you will most probably spare much time in testing and debugging.

CSS: the auto value of the top property

I first found this technique in a useful article on CommunityMX and I decided to make some tests that I didn't publish because they only show what has already been said several times since now. Finally I decided to publish more advanced tests that you can find here. Anyway, the top property accepts an auto value like all the other positioning properties. The interesting thing here is that if the absolutely positioned elements follow a static element in the source, then the absolutely positioned element will be put exactly under the static element. Remember, however, that this technique works only if a static element comes first in the source. You may use this technique in several possible scenarios, for example to display a navigation bar under a title or image captions inside a box where you need a finer control over the default positioning of caption text. It's only a matter of choice and particular needs.

CSS ID and class selectors: details

The first concept we need to grasp about CSS ID and class selectors is their usage: an ID selector can be used only once per page, whereas a class selector can be used more than once. Speaking from a SGML and DOM perspective, an ID must be unique throughout the page. If we use the same ID more than once, we stumble on a validation error and a DOM ambiguity (though browsers consider only the first ID in a series as a valid ID).

On the contrary, a class attribute can actually refer to multiple elements. For example:

<div class="evident"></div>
<p class="evident"></p>
<p><span class="evident"></span></p>

We can specify the following styles for the above markup:

.evident {
  background: yellow;
  padding: 0.3em;
}

These styles apply to all element disregarding their type. If we want to be more specific, we can add an element type before the class declaration, like so:

.evident {
  background: yellow;
  padding: 0.3em;
}

div.evident {
  border: thick solid orange;
}

Now the div with the CSS class evident will also have a thick orange border plus a yellow background and some padding. Another thing due to the cascade is the fact that CSS classes can actually be cumulative, in the sense that they can combine different styles by merging non-conflicting CSS rules taken from different class names. Example:

<div class="evident"></div>
<p class="evident"></p>
<p><span class="evident"></span></p>
<div class="evident pullquote"></div>

Here are the styles:

.evident {
  background: yellow;
  padding: 0.3em;
}

.pullquote {
  float: left;
  width: 200px;
  border: 3px solid orange;
}

The final result will be a left-floated div with a yellow background, some padding, a solid orange border and a width of 200px. Note that in this case the CSS rules are non-conflicting, because there are five different rules. If I specify a width of 100px in the first class, this declaration will be overridden by the second class because of the cascade (the second class definition comes later in the source).

ID selectors, instead, can be used to stylize very specific sections of a page. They're also used in scripting to create hooks for triggering DOM events or manipulate the DOM itself. From a JavaScript and DOM perspective, IDs are much faster than classes in terms of performance, because less steps are required to walk the DOM tree. An interesting and useful technique that involves IDs consists of setting a different ID on the body element of different pages, usually when they represent different sections of a web site. This is useful, because we can take advantage of the cascade to write page-specific styles, like so:

#navigation {
   float: left;
}
#content {
  float:right;
}

body#articles #navigation {
  float: right;
}
body#articles #content {
  float: left;
}

In this case, we get the effect of inverted column order on a specific page / section of our site. Really handy.

CSS3: The :not (negation) pseudo-class

What is, in its essence, the CSS3 :not pseudo-class? It's a filter that is used to separate certain elements from others depending on the presence of a certain condition. In technical terms, this pseudo-class uses a Boolean expression that negates a given condition. In human terms, it tells the browser not to consider an element with a given condition. For example:

p:not([class]) {
    color: green;
}

We're telling the browser to match each p element which has not a class attribute set on it. Very simple. Another example:

a:not(:link) {
  text-decoration: none;
}

In this case, we're matching an a element which is not a link (e.g. an anchor). As you can see, this pseudo-class negates the given condition. More information at http://www.w3.org/TR/css3-selectors/#negation.

jQuery: how to handle events after an Ajax request

In my previous post I said that I had some problems with events after an Ajax request. Problem solved: you have to use the success() method of the $.ajax() wrapper. For example:

$.ajax({
    //... more methods/properties here
    success: function(html) {
        $(html).appendTo('body');
        $('p').click(function() {
            alert('OK');
        });
    }
});

The fact is that the success() method encompasses also the DOM events occurring after the response is complete and the fetched content is retrieved.

Absolute positioning and CSS tables

CSS specifications don't define the behavior of absolute positioning within table elements. I ran a couple of tests (like this (XML)) that show clearly how browsers handle such situations. Basically, in XHTML and HTML browsers tend to honor the specified styles by using their default algorithms for tables, but in XML they full honor the specs that don't say much about this issue. In a nutshell: layouts look fine in HTML and XHTML, but they're completely broken in XML. So don't try this at home! However, it would be useful to be allowed to absolutely position elements within table elements, though in this case the CSS specifications show a lack in their definitions, mainly due to the correct rules to handle a block formatting context (BFC) in elements such as table cells.

jQuery: handling events after an AJAX request

I stumbled on a curious problem with some AJAX links that retrieve HTML content from a PHP script. Basically, the content retrieved has the following form:

<p class="info">Info <img src="close.gif"/></p>

When I click on the link, the AJAX request takes place and correctly insert the above content. So far so good. The problem is that you can't attach a click event on the image (a closing button). I guess this is somewhat related to the event chaining after the DOMContentLoaded event takes place. A short-term solution would probably be a quick insertion of the AJAX content before the request is even performed, that is, I should fetch only the responseText of the request and inject it into a pre-formed DOM structure that will be hidden before the AJAX call (including the image), for example when the DOM is ready.

I ran a quick search on Google but results are really inconsistent. For example, this article shows you how to write accessible AJAX links with jQuery, but it doesn't say much about my particular problem. I'll let you know if my tests succeed. Stay tuned!

jQuery: passing Ajax data

There is a big difference between the $.ajax() method and $.get() and $.post(). This method always expects that you pass data to the server along with your request. For example, this won't work:

$.ajax({
  type: 'GET',
  url: 'test.php',
  data: null,
  success: someMethod
});

If you want a simpler approach to Ajax, use the $.get() and $.post() methods for handling GET and POST requests, respectively.

jQuery: using the Google's CDN copy

jQuery LogoIn terms of performance, delivery and caching, is always a better choice to use the jQuery's copy hosted by Google's CDN, as explained clearly in this article. I don't think is a good choice to use a personal copy of jQuery hosted on your own web server, because Google optimizes the delivery for you, so I don't see the point in following this approach. More information at http://code.google.com/apis/ajaxlibs/documentation/

Writing standard JavaScript code

Web standards trinityWhile developing this demo, I was struck by the fact that most of the JavaScript code we write is not meant to be full standard compliant but rather an attempt to make it work also in non-compliant browsers. In other words, we should code to the standards, not to the lowest common denominator (Internet Explorer). I think that IE's developers rely on the fact that the overwhelming majority of JavaScript scripts and libraries work on their browser just because web developers are forced to write non-standard code to make their scripts work even on a browser that is absolutely non-standard compliant.

In fact, Internet Explorer has the lowest implementation of ECMAScript and W3C DOM specifications. Most developers use an if...else approach to deal with IE inconsistencies and proprietary features. I think that this is a wrong approach, because if we continue to do so, Internet Explorer's developers won't probably build a better JavaScript engine just because they can count on the backward support used by scripts and libraries. So if we want that IE be a better browser, we should write standard JavaScript code without taking into account IE's inconsistencies and proprietary features.

When IE's developers will see that many web sites don't work on their browser anymore, they will probably start to reconsider their approach to web standards which, as many of you already know, has always been inconsistent and absolutely wrong.

Beginning HTML5 and CSS3: Next Generation Web Standards

Book coverBeginning HTML5 and CSS3: Next Generation Web Standards is a new book on HTML5 and CSS3 that is up to be released (see Amazon). As always with Amazon, there's also a brief insight of book contents:

If you are a web developer, then Beginning HTML5 and CSS3 is your introduction to the new features and elements of HTML5—all the leaner, cleaner, and more efficient code you’ve hoped for is available now with HTML5, along with some new tools that will allow you to create more meaningful and richer content. For everyone involved in web design, this book also introduces the new structural integrity and styling flexibility of CSS 3—which means better-looking pages and smarter content in your website projects.

For all forward-looking web professionals who want to start enjoying and deploying the new HTML5 and CSS3 features right away, this book provides you with an in-depth look the new capabilities—including audio and video—that are new to web standards. You’ll learn about the new HTML5 structural sections, plus HTML5 and CSS3 layouts. You’ll also discover why some people think HTML5 is going to be a Flash killer, when you see how to create transitions and animations with these new technologies. So get ahead in your web development through the practical, step-by-step approaches offered to you in Beginning HTML5 and CSS3.

This seems interesting and I've already added this book to my wish list. Oh, but there's also the new book of Mark Pilgrim on the subject. So, which will be? One? Both? I don't know!

Why negative CSS text-indent doesn't always work

Negative text indentation is used in CSS to create the effect of some text hanging out of a block. For example:

#box h1 {
  text-indent: -1em;
}

In this case, some versions of Internet Explorer will crop the text on the left (or right, depending on the writing direction). Is this a bug? Though many web developers think so, this is a typical case of lack of details in the CSS specifications, not of a bug per se. In fact, CSS specifications don't take this particular case into account. They only say that the text-indent property accepts negative values, but nothing more. How negative text indentation must be handled is up to every single browser.

Currently, many browsers have accepted the convention of showing the given text hanging out of its block and this is exactly the final effect that web developers want to achieve. On the contrary, we can't say that not showing the text or cropping it is actually a bug, but rather a different interpretation of the specifications which, as said earlier, don't say much about this particular case.

jQuery: turning preformatted text into a list

Sometimes using a pre element is not the optimal choice for handling preformatted text. We can turn preformatted text into a list with jQuery. Here's the code:

$(document).ready(function() {

    $('pre.css').each(function() {
    
        var $html = $(this).html();
 
        $(this).replaceWith('<ol class="css">' + $html + '</ol>');
 
 
    });
    
    
    $('ol.css').each(function() {
    
       var items = [];
        var oldHTML = $(this).html();
 
        var lines = oldHTML.split(/\r\n|\n/);
       
       
 
        for(var i=0; i<lines.length; i++) {
 
 var item;
 
 if(lines[i].indexOf('{') != -1 || lines[i].indexOf('}') != -1) {
 
     item = '<li>'+lines[i]+'</li>';
     
 } else {
 
     item = '<li class="indent">' + lines[i] + '</li>';
     
 }
 
 items.push(item);
 
 
        }
 
        for(var j=0; j<items.length; j++) {
 
 
 if(items[j] == '<li></li>' || items[j] == '<li class="indent"></li>') {
 
     items.pop(items[j]);
     
 }
 
        }
 

        var newHTML = items.join('');
 
         $(this).html(newHTML);
    
    
    });
    
    

});

Basically, I've simply replaced a pre element with an ol element. Then I've split up its contents into several lines and formatted them accordingly. You can see the result here.

Note

This demo doesn't work in Internet Explorer.

Type hinting in JavaScript variables

JavaScript is a loosely typed language and has no notion of type hinting. Anyway, we can mimic this behavior by prefixing our variables with some letters that serve as a reminder to developers. Here are some prefixes:

Type prefixes
Prefix Type
o Object
s String
a Array
n Number

Some examples:

var aTest = ['a', 'b', 'c'];
var sBar = 'Bar';
var oFoo = new Foo();

Embedding and using Google Web Fonts in your pages

Google Web Fonts are a useful feature that can actually enhance the visual appealing of your web pages. First of all, you need to select a font from the Font Directory. Then, just click on Embed to get the code. For example, if you want to use the Yanone Kaffeesatz font, you get a code like this:

<link href=' http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz' rel='stylesheet' type='text/css'>

The URL contained in the above link element actually retrieves the following style sheet:

@font-face {
  font-family: 'Yanone Kaffeesatz';
  font-style: normal;
  font-weight: 400;
  src: local('Yanone Kaffeesatz'), url('http://themes.googleusercontent.com/font?kit=YDAoLskQQ5MOAgvHUQCcLdZ76ZYKVLHIjRQjrp3kYFc') format('truetype');
}

Of course you can use these styles with an @import rule, like so:

@import url(http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);

The above declaration must be put at the very beginning of your CSS file. After this, you can use the downloaded font this way:

h1 { font-family: 'Yanone Kaffeesatz', Arial, sans-serif; }

JAST: WAI-ARIA JavaScript framework

JAST is a powerful JavaScript toolkit written by Diego La Monica that supports the WAI-ARIA standard and technologies in order to make RIAs accessible even to assistive technologies users. In its core, called JAST.src, JAST provides some useful methods to deal with WAI-ARIA attributes. For example:

ARIA: {
  addRole: function(e, role){
   e.setAttribute('role',role);
  },
  setProperty: function(e, property, value){
   if(typeof (property) == 'object'){
    for(p in property){
     e.setAttribute('aria-' + p, property[p]);
    }
   }else{
    e.setAttribute('aria-' + property,value);
   }
  },
  getProperty: function(e, property){
   return e.getAttribute('aria-' + property); 
  },
  focusNextNode: function(node){
   
   var p = node.parentNode;
   if(p==null) return false;
   var nodes = p.childNodes;
   if(node.id==null || node.id=='') node.id = JASTEggIt.generateUniqueId('jast');
   var isCurrent = false;
   for (var i = 0; i < nodes.length; i++) {
    if(nodes[i].nodeType==1){
     if(isCurrent){
      nodes[i].focus();
      return;
     } 
     isCurrent = (node.id== nodes[i].id);
    }
   }
  },
  focusPreviousNode: function(node){
   var p = node.parentNode;
   if(p==null) return false;
   var nodes = p.childNodes;
   if(node.id==null || node.id=='') node.id = JASTEggIt.generateUniqueId('jast');
   
   var previousItem = null;
   
   for(var i = 0; i<nodes.length; i++){
    if( nodes[i].nodeType==1){ // è un nodo HTML del DOM
     if (node.id== nodes[i].id) { 
      if (previousItem == null) return false;

      previousItem.focus();
      return true;
     }
     previousItem = nodes[i];
    }
   }
   if(previousItem!=null) previousItem.focus();
   return true;
  }

 }

The ARIA object contains the following methods:

  1. addRole() - adds an ARIA role attribute
  2. setProperty/getProperty() - getter/setter for ARIA object properties
  3. focusNextNode() - giving focus to a DOM node is a basic requirement when dealing with keyboard navigation; this method gives focus to adiacent nodes
  4. focusPreviousNode() - same as above, except that this method gives focus to a preceding node in the DOM tree.

As you can see, JAST doesn't create a global wrapper for chaining methods and properties (for example, jQuery follows this approach). Instead, it uses a global namespace, so you're not forced to write $(element)[0].method() to use a simple DOM property or method. The approach followed by JAST is much similar to the YUI library's one.

jQuery: generating a random link from a Google sitemap

Generating a random link from a Google sitemap is quite simple with jQuery. First of all, we need to define some method and properties within our class:

/**   @name SiteManager
      @access Public
      
      Main class to handle site contents */
      


var SiteManager = new function () {
    
    var that = this;
    
    var pageURL = location.href;
    var pageTitle = document.title;
    
    this.execute = function(callback) {
        
 
 return callback.method(callback.parameters);
    };
    
    
    var isActualContent = function(term) {
    
        
 return that.execute({
 
     parameters: pageTitle,
     method: function(parameters) {
     
         if(parameters.indexOf(term) == -1) {
  
      return true;
      
  } else {
  
      return false;
      
  }
     
     
     }
 
 
 });
    
    
    };
    
    this.XHR = function(type, url, callback) {
    
 url = 'http://www.yoursite.com/' + url;
 
 switch(type) {
     case 'xml':
       return $.get(url, callback);
       break;
       
     case 'html':
       return $.ajax({
    url: url,
    data: null,
    dataType: 'html',
    success: callback
       });
       break;
     
       
     default:
         break;     
     
 
 }
    
    
    
    };

Then we can create our custom method to fetch the data we need from the sitemap:

this.getRelatedResources = function() {
        
     var related = [];
        if(isActualContent('Home')) {
        return this.execute({
     
     parameters: [$('#content-sub > h2:first-child'), pageURL, '<div class="resource res single-res"><h3>Related resource</h3><ul><li>'],
     method: function(parameters) {
     
         return that.XHR('xml', 'sitemap.xml', function(data) {
  
      $(data).find('loc').each(function() {
      
         var text = $(this).text();

               var rawURL = parameters[1].replace('http://www.yoursite.com/', '').replace('index.html', '');
         
         var urlChunks = rawURL.split('/');
         
         var baseDir = urlChunks[0];
         var currentDir = urlChunks[1];

         
         if(text.indexOf(baseDir) != -1) {
         
             if(text.indexOf(currentDir) == -1) {
         
                 
          var re = /\/.+\.html$/;
          var link;
          
          if(re.test(text)) {
          
              link = '';
          
          } else {
          
          
              related.push(text);
          
          }
          
          
          
   
          
      }
          
         
         }
      
      });
      
      
      var currentIndex = Math.floor(Math.random() * (related.length));
      
      var html = parameters[2];
      
      html += '<a href="' + related[currentIndex] + '">Read</a></li></ul></div>';
      
      
      $(html).insertAfter('#content-sub h2:first-child + div.resource');
      
      
  });
     
     }
     
 });
 
 } else {
 
     return;
     
 }
    
    
    
    };

We fetch our sitemap through Ajax and we parse all the URLs by filtering the URL of the current page. Then all this data is pushed into the related array. Finally, we create a random index for this array and we extract only a single link. Do more with less!

jQuery: object detection and hasLayout

When it comes to CSS bugs, there is only one name that often occurs in the nightmares of web developers: Internet Explorer 6 and 7. The problem with these two browsers is that they're affected by the hasLayout property. hasLayout is a JavaScript read-only property that is attached to every single element on the page. It has a Boolean value that tells IE if a given element has layout or not. Depending on whether an element has layout or not, certain bugs may occur or not.

The syntax of this property is as follows:

element.currentStyle.hasLayout

To detect if we're dealing with IE 6 and 7 and with hasLayout, we could write something like this:

var test = $('#test')[0];
alert(test.currentStyle.hasLayout); // true or false

Note that we're using the bracket notation to access the above test element. By doing so, we can use DOM and JavaScript properties and methods which are not directly accessible within the jQuery global wrapper ($). We can also improve our routine with a try.. catch block:

try {
  alert($('#test')[0].currentStyle.hasLayout);
} catch(e) {
  alert('hasLayout not supported!');
}

Using object detection for hasLayout allows us to check if we're dealing with IE 6 and 7. What's more, we might also add a bug fixing routine, like so:

if(!test.currentStyle.hasLayout) {
    if($('#test').css('display') == 'block') {
        $('#test').css('height', '1%');
    } else if($('#test').css('display') == 'inline') {
        $('#test').css('zoom', '1');
    }
}

Of course we can also use different CSS classes. Here CSS styles have been inserted through jQuery just for the sake of simplicity.

Dialup is not dead

DialupSometimes I check my Google Analytics stats to find out something about my visitors. Today I found out that some of my visitors use a dialup connection. More precisely, 74 visitors during the last month. I must apologize with these visitors if they found my site really heavy to load. The fact is that I'm lazy and easily distracted. I don't check my stats on a regular base, so I missed some important details. People who use a fast connection often forget how much a dialup connection is slow. I mean, really slow. Dialup connections are the last signs and relics of the World Wide Wait model of the '90s. Anyway, if accessibility and usability really matter, we can't overlook this datum. We should provide a way to access our site contents in a reasonable time span. If I think that my 74 visitors had to wait almost a minute to load my blog, there's only one thing that comes into my mind: I am a stupid!

Yes, stupid. Because I've burdened my blog with a lot of extra widgets that add a really little meaning to the overall context. Users, contents, context: in a word, usability. As developers, we must take a decision: developing a web site that takes into account all the needs of dialup users or, on the contrary, an oversized web site with a lot of widgets and micro applications. Of course there's no need to be drastic. If those widgets are really important to the site, we should provide a low-content version of our pages, for example removing all unnecessary widgets and graphics (and scripts too). By doing so, dialup users won't have to wait a month until a page finishes loading. And this is all good reputation that we actually get and if we plan a site accordingly, we deserve it.

jQuery accessible dropdown menu

Building a dropdown menu with jQuery is quite simple. Builiding an accessible dropdown menu, instead, requires some basic knowledge of web accessibility. First of all, we start with a basic markup like this:

<div id="navigation">

<ul>

<li><a href="#">Home</a></li>
<li><a href="#">Articles</a></li>
<li class="more"><a href="#">About</a>

<ul>

<li><a href="#">Portfolio</a></li>
<li><a href="#">Resumé</a></li>

</ul>

</li>

<li><a href="#">Contact</a></li>

</ul>

</div>

Our CSS styles are as follows:

body {
 
     margin: 0;
     padding: 0;
     font: 62.5%/1 Arial, sans-serif;
     background: #fff;
     color: #333;
 
 }
 
 #navigation {
 
     width: 100%;
     float: left;
     margin: 0;
     background: #666;
     color: #fff;
     font-size: 1.4em;
 
 
 }
 
 #navigation ul {
 
     
     margin: 0;
     padding: 0;
     list-style: none;
     width: 100%;
 
 
 }
 
 
 #navigation ul li {
 
     float: left;
     height: 5em;
     margin: 0;
 
 }
 
 #navigation ul li a {
 
     color: #fff;
     text-decoration: none;
     float: left;
     display: block;
     height: 100%;
     line-height: 5;
     padding: 0 1em; 
 }
 
 #navigation ul li a:hover {
 
     background: #333;
     text-decoration: underline;
 
 }
 
 #navigation ul li.more ul {
 
     width: 15em;
     background: #333;
     position: absolute;
     top: -1000em;
 
 }
 
 #navigation ul li.more ul li {
 
     float: none;
     height: 100%;
 
 }
 
 #navigation ul li.more ul li a {
 
     float: none;
     width: 100%;
     display: block;
     line-height: normal;
     padding: 0.5em 0;
     text-indent: 0.5em;
 
 }
 
 #navigation ul li.more ul li a:hover {
 
     background: #666;
 
 }
 
 span.plus {
 
     padding-left: 4px;
 
 }

We didn't use display: none to hide the submenu, because this declaration prevents screen readers from reading the content of the element. Instead, we used negative absolute positioning. Our jQuery code takes into account this solution:

$(document).ready(function() {

    $('<span class="plus"></span>').text('+').appendTo('#navigation ul li.more > a:first-child');

    var subMenuPos = $('#navigation ul li.more').position();
    var subMenuLeft = subMenuPos.left;
    var subMenuHeight = $('#navigation ul li.more').height();
    
    $('#navigation ul li.more').hover(function() {
    
        $('#navigation ul li.more ul').css({'top': subMenuHeight, 'left': subMenuLeft});    
    },
    
    function() {
    
        
        $('#navigation ul li.more ul').css({'top': '-1000em', 'left': '-1000em'});
    
    
    }
    
    
    
    );

});

Our submenu will be absolutely positioned using the coordinates of its parent element. When a user moves his/her mouse out of the submenu, the submenu itself is hidden again using negative absolute positioning. You can see the final result here.

Internet Explorer, hasLayout and ordered lists

During Saturdays and Sundays I generally work on the restyling of my main site. I was testing a code like this:

.list-container {
  height: 100%;
  background: #eee;
}

.list-container ol {
  height: 100%;
  background: #fff;
}

In Internet Explorer 6 and 7 the list markers (that is, the automatic numbering) disappear. This is due to the declaration height: 100% set on the list. In this case, giving layout to the element causes the bug. Removing the height declaration on the list fixes the bug. On ordered lists, even declaring an height on list items may cause the same bug, so be careful.

Flickr mashups with PHP and JavaScript

Flickr, PHP, JavaScript: three faces of the same coin. Since I believe that the Web 2.0 phenomenon has still to show out all its potential, it's sometimes useful to study some code written by others. A good example of this is surely Flickr Mashups by David Wilkinson. This book is an exciting and stimulating resource on all the possible combinations of Flickr API, PHP and JavaScript. For example, here's a combination of PHP, JSON and JavaScript for creating badges:

PHP

include("http://api.flickr.com/services/feeds/groups_pool.gne?id=myID&format=php");

$s = "";

$s .= '<div class="badge">';
$s .= '<p class="badge-title"><a href="' . $feed['url'] . '">' . $feed['title'] . '</a></p>';
$s .= '<ul class="badge-items">';

$items = $feed['items'];

for ($i = 0; $i < count($items); $i++)
{
  if (preg_match('/(http:\/\/static.flickr.com\/\d+\/\d+_[0-9a-z]+)_m\.jpg/',
    $items[$i]['description'], $result))
  {
    $image = $result[1] . '_s.jpg'; 
    $s .= '<li class="badge-item"><a href="' . $items[$i]['url'] . '"><img src="' . $image . '" /></a></li>';
  }
}

$s .= '</ul></div>';

echo($s);

This script includes an HTML snippet made up by all the required images, plus their title and description. The PCRE used in the above code serves as an handy way to select only the desired images. The JavaScript way, instead, requires the JSON format. You need to include the following script element in your page:

<head>
<script src="http://api.flickr.com/services/feeds/groups_pool.gne?id=81474450@N00&format=json" type="text/javascript"></script>
</head>

Then you can add your custom script for retrieving and parsing images:

JavaScript

function jsonFlickrFeed(feed)
{
  var imgPattern = /(http:\/\/static.flickr.com\/\d+\/\d+_[0-9a-z]+)_m\.jpg/;
  var s = "";

  s += '<div class="badge">';
  s += '<p class="badge-title"><a href="' + feed['link'] + '">' + feed['title'] 
      + '</a></p>';
  s += '<ul class="badge-items">';

  var items = feed['items'];
  for (var i = 0; i < items.length; i++)
  {
    var result = imgPattern.exec(items[i]['description']);

    if (result != null)
    {
      var image = result[1] + '_s.jpg';            
      s += '<li class="badge-item"><a href="' + items[i]['link'] + '"><img src="' 
          + image + '" /></a></li>';
    }
  }

  s += '</ul></div>';

  document.writeln(s);
}

Of course you can avoid the writeln() method by inserting a placeholder in your page and using the innerHTML property instead.