Please visit my new campsite listing site ukcampingmap.co.uk


Posts Tagged ‘javascript’

It’s not what you say, it’s which font you say it in

Wednesday, March 3rd, 2010

I’m redesigning this site at the moment and one thing I wanted to pay closer attention to this time around was choice of fonts. Notwithstanding the fact that web browsers were, until recently, pretty shoddy at allowing you to use the fonts you wanted to, the main reason I hadn’t paid much attention to fonts in the past was that it’s so darn hard picking one, for a number of reasons:

  1. There’s so damn many of them
  2. There’s no relation between names and appearance (as opposed to, say, #f60283 being guessable as a garish pink, closer to red than to mauve)
  3. They’re difficult to preview and compare

So in the interests of productivity, quality and, dare I say it, working smarter, not harder, I’ve devoted some time to sorting out how I choose fonts, reduced to the following four steps:

  1. Organise your fonts in themed folders
  2. Find a good stand alone font previewer i.e. don’t rely on photoshop and windows’ poor tools
  3. Narrow down to a short list
  4. Use javascript to make quick comparisons easy

Read on if your curiosity is piqued.

1. Organising the fonts

Windows’s default font collection (and, I imagine, Apple’s too) and the collection of 2000 fonts I also use are organised alphabetically which is rubbish. Unless you have web design OCD you’re unlikely to want to narrow down your choice of font by it’s first-letter. But, on the other hand, it is difficult to categorise fonts; I’m yet to see a website do it effectively, and I’m not entirely happy with my choice. But in the end I plumped for the following: serif, sans-serif, script, stylised, symbol, stencil.

Stencil could easily fall within stylised, and stylised could easily be split into subfolders (Art Deco, Gothic, Celtic …), and I realised part way through that I should have a subfolder within symbol for fonts depicting alphabets other than Roman, but I think a minimal folder system would be serif, sans-serif and other. In the serif and sans-serif folders I included only sensible fonts you could print a book not aimed at children in, which I think is a useful distinction to make; often the hardest task when picking fonts is to find the one which is subtly different to other ordinary fonts, but somehow suits the design better than almost indistinguishable alternatives. Cutting out all the fancy fonts makes this task a lot easier.

So once you have all these folders put a copy of each font you have in one of them, and you’re ready for the next step. You don’t need to bother with installing them yet.

2. Previewing your fonts

My criteria for a good font-previewer are:

  1. Choice of text to use for the preview
  2. Choice of text-size and colour
  3. Ability to organise fonts how you want them organised
  4. Speed and ease of switching between one font and another
  5. Ease of installing a font

Windows’ control panel fails to meet conditions 1 and 2, and Photoshop’s built-in font selector fails to meet 3 and 4, and they both force you to install a font before using it. The best free solution I’ve come across for Windows which meets all 5 conditions is Fast Font Preview.

3. Short-listing

Once you’ve got Fast Font Preview installed you can start picking your shortlist. Simply browse to your organised font folders, click on settings to type in your sample text, adjust the font-size to what you want, and double click on any contenders. Once the font is opened you can install with one click. While the font is open you’ll also want to jot down its official font name.

4. Use javascript to make comparisons

This is where I stop being pedantic and hopefully can be of some use. Insert the following script into the head of your web-page-in-need-of-a-font, substitute your list of font names and the id/tag name of the elements to be affected and, hey presto, a handy font-switcher should appear, making choosing exactly the right font much easier. If your web page already uses javascript then add the body of the function to your existing onload event. (NOTE: It tends to work better in Google Chrome than other browsers as Google Chrome seems to be a bit more forgiving when it comes to font names).

window.onload = function() {
 var body = document.getElementsByTagName('body')[0];
 var id = '';
 var tagName = '';
 var fonts = 'Comma,separated,list,of font,names';
 fonts = fonts.split(',');
 var elements = (id)      ? [document.getElementById(id)] :
                (tagName) ? document.getElementsByTagName(tagName):
                            [body];
 var switcher = document.createElement('DIV');
 switcher.setAttribute('style','position:absolute;top:0;right:0;background:white;z-index:200;padding:10px;');
 for(var i=0, il = fonts.length;i<il;i++){
   createButton(i);
 }
 body.appendChild(switcher);
 var buttons = switcher.childNodes
 loadFont(0);

 function createButton(pos) {
   var button = document.createElement('a');
   button.innerHTML = fonts[pos];
   button.setAttribute('style','display:block;padding:2px;');
   button.setAttribute('href','#');
   button.onclick = function() {loadFont(pos);};
   switcher.appendChild(button);
 }

 function loadFont(pos) {
   for (var i=0,il=elements.length;i<il;i++)
   {
     elements[i].style.fontFamily = fonts[pos];
   }
   for (var j=0,jl=buttons.length;j<jl;j++) {
     buttons[j].style.backgroundColor='';
   }
   buttons[pos].style.backgroundColor='yellow';
   return false;
 };
};

Remove text nodes function

Wednesday, February 17th, 2010

Here’s a fairly useful function for when you’re using javascript in a web page without using  library like jQuery to take care of the nitty gritty.

It tackles problems that occur when you get the child nodes (eg myList.childNodes) of a DOM node, but there is whitespace in the html. Each of these whitespaces gets counted as a DOM node of its own, a text node, so if you run code to iterate through eg all the children of a <ul> you will find that your code throws an error as not every node is an <li> as you expected.

function removeTextNodes(nodeList) {
  list = Array.prototype.slice.apply(nodeList);
  for(var i=0, il=list.length;i<il;i++)
  {
    if(list[i].nodeType == 3)
    {
      list.splice(i,1);
      i--;
      il--;
    }
  }
  return list;
}

var myUL = document.getElementById('myUl');
var myLIs = removeTextNodes(myUL.childNodes);

I haven’t tested it in any browsers apart from firefox as I’m a bit busy, but if you find it’s buggy in Internet Explorer or elsewhere leave a comment.

(By the way, if you’re wondering about eth relevance of the image, if you search for “too many children” in flickr it throws up lots of photos of a very serious looking texas school board meeting. Too many children in Texas, apparently!).

Delicious, though not so easy to swallow

Thursday, February 11th, 2010

For a long time I’ve wanted to work with the Delicious API. Initially it was because the Delicious website not only had the difficult to remember del.icio.us url, but was also very badly designed. If you compared its progress – addition of new features, cleaning up of design, making use of new techniques suchas AJAX – with its web2.0 compatriots (Flickr, Digg, boris-johnson.com) it lagged way behind.

So I initially planned to build a new front-end for it, making it easier to work with your bookmarks, but before I could progress far enough in my coding abilities they completely redesigned the site; a vast improvement.

Though still not perfect. For a while I’ve found it frustrating that there is no easy way to simultaneously see the content of a bookmarked page and delete the bookmark if you deem it no longer useful, so my delicious account gradually got more and more cluttered. Well, this afternoon I decided to do something about it (and not just because I’m avoiding doing more important stuff).

But I was foiled for a long time by the laziness of the Delicious developers. My initial plan was to use javascript to get a JSON of all my bookmarks (or alternatively request one at a time) and go through them one by one, displaying the webpage in an iframe, and offering the option to discard or keep the bookmark. However, delicious only publish this data as XML which means, due to cross-domain restrictions on AJAX, you can’t just use javascript. I may be a bit hasty in pinning this on developer laziness, but I imagine creating alternate templates (because that’s all the difference between JSON and XML really) wouldn’t be too time consuming, and would greatly enhance the versatility of the API.

Anyway, I realised I would have to use a bit of PHP to get the XML and create pages from which my javascript would be able to access the data. Luckily, before I dived straight in I came across phpdelicious (which, appropriately, I have now bookmarked in Delicious) , a very easy to use php class for wrapping the Delicious API, which is very handy indeed. Less than an hour later I had built exactly what I wanted.

I reckon a few more hours development and I can make it a publicly available service.  All I need to do is include a form for other users to be able to login, and (ideally) preload websites in the iframe to speed things up (though this is problematic as some sites force the whole web page to be redirect if you try and put them in an iframe).

Sorted

Tuesday, February 9th, 2010

One of the problems I had to solve when writing my new jQuery listSplitter plugin was sorting an array of arrays/multidimensional array by one given column, eg

testArray = [[a, b], [b, a]];

How would you sort by the second column of the array?

I’m not sure if mine is the best solution, but here it is (it also works for an array of objects as well as an array of arrays):

/**
* sorts an array of arrays or objects using a specified column/property
*
* @param column (str/int) - the name/index of the column to use for sorting
* @param sortFunction (func) - the sort function to use for sorting (sort functions
*                             that can be used by array.sort() will also work here)
* @return array
*/
Array.prototype.sortByColumn = function(column, sortFunction) {
  return this.sort(function(a,b) {
    var testArray = [a[column], b[column]];
    testArray = (sortFunction) ? testArray.sort(sortFunction) : testArray.sort();
    return (testArray[0] == a[column]) ? -1 : 1;
  });
}

And to apply it to an array use it similarly to the array.sort() method, eg

myArray.sortByColumn(5);//sort alphabetically by column 5 of the array
myArray.sortByColumn('title', sortByLength); //sort by length of title attribute
function sortByLength(a,b) {
   return a.length - b.length;
}
myArray.sortByColumn('price',function(a,b){return a - b}); // sort by price

How it works

It runs the normal array.sort() method, but uses as its sort function a clever little function which picks out the values to be sorted by, creates a new test array out of these values and sorts it. Using the ternary operator, it checks if the test array is unchanged after this sort. If it is unchanged it means that the items in the original array are already in the right order so no change is made, otherwise they are swapped in the original array too.

Immunodeficiency

Tuesday, January 26th, 2010

I just solved  a bug which stemmed from the fact I forgot that javascript is a referential language, i.e. if you have a variable and you set another variable equal to it then it doesn’t in general clone the original variable, but merely just points both variables towards the same underlying object. This only applies to Arrays and Objects though, and to prove it here is a little demo (it turns out you can embed javascript straight into wordpress posts now!)

Irritatingly, if you have a bug which is caused by forgetting this principle then this will also make it hard to debug because it also affects how firebug reports information to you. When you console.log() an object or an array, firebug does the same as javascript – it creates a reference to an underlying object in the DOM. So, if you’ve been logging an object repeatedly in order to pinpoint when a rogue change takes place firebug will consistently provide you with references to the object as it is after your script’s finished running – not much use.

However, there is an easy way out*. console has methods other than .log(), and possibly the most useful is console.dir(). console.dir() takes a snapshot of any object or array, printing out each of its properties without maintaining a reference to the underlying object, and therefore giving a you a snapshot of an object as it is at the time.

*And a hard way (console.log() the properties of an object individually), which is how I resolved my bug, before  looked into what other methods console had

But it works for me!!!

Monday, November 16th, 2009

The lines of javascript below, included at the top of your scripts, could save you a lifetime of confusing conversations with clients where they say an application doesn’t work and you can clearly see that it works on your laptop.

The difference is that you have firebug installed and they don’t, so for you console is defined, but for them it is not, so if you leave any references to it in the app it will throw an error for them. But this fixes that;

if(!console) {
 var console = {};
 console.log = function() {
   return null;
 };
}

To splice or not to delete

Friday, August 14th, 2009

I haven’t blogged much about programming recently due to being too busy… too busy to blog, not too busy to program.

This is just a swift post to highlight an important distinction that I haven’t seen mentioned anywhere else, and which recently I realised the siginificance of.

In javascript, what’s the difference between

delete my_array[i];

and

my_array.splice(i, 1);

Superficially they’re the same – they each remove the ith element from an array. But the crucial difference is that delete leaves a gap in the array, so there will no longer be an ith element – the array jumps straight from the (i-1)th to the (i+1)th element. But splice moves the (i+1)th element into the ith place in the array, and so on, shortening the array by one but moving everything along to fill the gap.

Why is this important?

If your code relies often on iterating through an array thus:

for(i=0;i<my_array.length;i++)
{
    //some code
}

then any future iterations over the array will throw errors if you used delete to remove the ith element. But the iterations should still work if you used the splice method.

One note of caution, if you carry out

my_array.splice(i, 1);

within a loop over i, you should add the line

i--;

immediately after, to make sure you don’t miss out the next array element (which is now, of course, not in the (i+1)th place, but in the ith place).

In defence of jQuery browser detection

Friday, May 22nd, 2009

I read somewhere the other week that jQuery is deprecating its jQuery.browser method, which means that in the future (though not yet, as the method still works but will not continue to be developed/supported, and will eventually be dropped) you will not be able to directly ask jQuery which browser it is being run in.

The rationale behind doing this is on the face of it sound: The reason you want to check what the browser is is that you want to check if a feature of javascript is available in that browser… so why not just ask if that feature is available, then the question of which browser it is becomes irrelevant. This will enable your script to continue to function (most probably) even in the unlikely event that eg Microsoft bring out a patch for ie6 that makes it fully support javascript.

But there is a flaw in this reasoning. It assumes that the only reason you would want to serve some different script to a browser is because of flaws in the browser’s javascript implementation, but in fact there are other reasons for doing this too, principally the browser’s failure to render CSS correctly.

While the new jQuery.support method does include tests for boxModel (ie6 and 7′s incorrect rendering of the CSS box model being the principle reason behind serving different CSS to different browsers) and one or two other CSS bugs, this simply isn’t up to the task. The box model is broken in ie6 and ie7, but broken in different ways, so normally to fix a layout bug I will want to serve different CSS to both.

Using various combinations of jQuery.support, eg

!jQuery.support.boxModel && jQuery.support.objectAll

you can still detect ie6 and ie7… but is this really an improvement on jQuery.browser?

jQuery.browser.msie && jQuery.browser.version.substr(0,1)=="6"

With jQuery.browser it is wholly transparent what you’re trying to detect, and if the code within the conditional’s braces contains a hefty amount of CSS rules your average developer should be able to work out the reason for the browser detection is to fix CSS bugs.

One other reason for explicitly detecting a browser (which I need at the moment as I’m developing a jQuery plugin) is that different browsers render form elements differently (the most obvious black sheep is safari’s making most elements look blue and glossy, but there are subtle differences in other browsers too). If I, say, want to fake a <select> element  by using a <ul>, and want it to look convincing in all browsers I need to supply each browser with differentiated CSS. jQuery.browser would be the obvious way to do this. No matter how many CSS bugs get fixed in browsers, how to render form elements by default isn’t specified by CSS/html, so there will always be this reason to want to detect browsers.

jQuery.browser is a very useful feature and it’ll be a shame when it goes.

Animated navigation effect… without javascript or flash!

Monday, July 28th, 2008

I can make a ball bounce up and down in flash, and that’s about it. And my javascript is rapidly improving, but still leaves a lot to be desired, but simple animation effects using flash or javascript can really enhance a design.

For example, one of my favourite site-designs, http://www.futurelab.org.uk/ (I love the classy, formal look, aimed at senior teachers, but also with splashes of colour and animation to suggest innovation and fun), uses flash to create a subtle bouncing navigation effect.

So what’s a boy to do?

A week or so ago Sitepoint published a cute little tutorial on how to make surprising animations react to browser resizing… and the magic of it was that it only used a gif and a jpeg to achieve this. Inspired by this, I decided to make the futurelab navigation using just animated gifs, and the results are pretty good I reckon. And it only needs a couple of 1 pixel wide gifs per navigation item – less than 1kb in total. (I also only learned how to make animated gifs in photoshop this afternoon, using this tutorial).

A note of caution: my navigation items are all the same colour, so you’d think I could use the same gifs for each item… but not so. Something to do with how firefox renders animated gifs means it doesn’t animate the hover-off image if it’s used on another navigation item too. The solution is simple: make a few copies of the hover-off gif with different names.