Posts Tagged ‘jquery’

I’ve been writing JavaScript for almost as long as the language has existed. My first “script” was a simple onMouseOver="window.status='Hello World'" affair back in the days of Netscape 2. I spent the dot.com years writing popup windows and hover images and scrolling boxes and other basic stuff. Then I took a break from doing much JavaScript – this almost exactly coincided with the years that some “proper” programmers took a a look at the language and applied a bit of rigour to it. So when I got back into JavaScript a few years ago I was way behind the curve.

I’ve managed to catch up a little and by using the jQuery library plus a few plugins I’ve done some quite cool things despite not having the sort of knowledge that real JavaScript pros have these days.

I’m a front end engineer, I’m not a “proper” programmer, I don’t come from a programming background and have had close to zero formal training. I only vaguely understand the principles behind object oriented programming and design patterns and so on and I think that I think that they are good things, but I have no real idea of how to apply them to my code.

Speaking of which, unminified it’s 70Kb, 1500 lines and growing. There’s a big refactoring job that needs doing there before it becomes impossible to maintain. But how to start?

Bookwise, I have Jon Resig’s Pro JavaScript Techniques and Douglas Crockford’s JavaScript: The Good Parts and a few others. Are there any others that I should be looking at? What about training? Web sites? Blogs I should be following? Where do I go from here?


Today I …

  • Had my photo used in a (gay) mockup of a what our Valentine’s Day homepage could look like.
  • Had lots of fun combining Ajax, JSON, RSS, JSP and jQuery in various combinations.
  • Moved the breadcrumb trail from just inside the main content area to just before it … in many, many templates.
  • Wondered whether any of the ARIA landmark roles was suitable for a block that contained a breadcrumb trail, a print button and an RSS feed button. contentinfo or nothing seem to be the options.
  • Told my boss that I needed to refactor all the JavasScript (that I had written in the first place) on the whole site.
  • Wasn’t ill enough to go home to bed, maybe tomorrow. (Damn this really quite good immune system!)
  • Boggled at the photos of Ben Dalby in a straight jacket!
  • Spent most of Survivors thinking about the benefits of CGI vs something actually decent looking when it came to collapsing buildings.

One of my goals over the last year has been to convert most of the JavaScript I use on visitlondon.com to use the jQuery library. One of the big advantages of jQuery is a library of pre-existing and thoroughly tested plugins for simplifying a lot of common tasks.

Here’s what I’ve been using; if you use jQuery, what plugins do you think are essential?


  1. There’s a problem with Webkit powered browsers – if the item to be dragged is an image map then the mousedown action never reaches the drag code. Hence Chrome and Safari users will see a box with scrollbars instead on that page.

‘cos I’m a muppet who doesn’t have a development version of this blog, things will shortly get ugly as I’m going to be redoing al the templates, css and javascript on the fly.

Updates

  1. Browser Support
    • As this is a personal blog support for IE6 is dropped from here on.
    • Supported browsers as of today will be what I have installed on this machine – IE8, Opera 9.6, Firefox 3, Safari 3.2, Chrome 2.
    • Support for IE7 will be added as and when I find it convenient to do so
  2. BTW, I’m not totally a muppet – I did back up the old files before I started
  3. Two hours later and the basics of the styling are back in place
  4. Nearly there, threaded comments look okay, moving onto the comments form.
  5. Comments form done, dinosaur pages skin done, cross-browser testing next…
  6. Looking good. Not a bad day’s work, comments and print stylesheet much better than before. CSS and JS reduced in size.

The contents of this post are a few years old now and I can’t recommend them as best practice. If you’re tempted to use this technique then bear in mind the fact that Opera 10.5 and Internet Explorer 9 now support the CSS3 border-radius property. Supporting old versions of Opera is rarely worth the effort so I would use if ($.browser.msie && $.browser.version < 9) to apply this technique to old IE versions only.

Picking up from my first attempt here’s a more methodical approach.

Objectives

  1. Buttons (both <input type="submit"/> and links masquerading as buttons that have rounded corners.
  2. Works in recent versions of Gecko, WebKit, Opera and Internet Explorer
  3. As little extra mark up as possible
  4. Any JavaScript used must be generic and not tied to one particular style of button, i.e. change element.className not element.style

HTML + CSS

Let’s start with the standards based solution that works in Gecko and WebKit based browsers.

<input class="button-rounded" type="submit" value="Go"/>

<a href="#" class="button-rounded right">Go

.button-rounded {
  font: bold 100%/1 Verdana, sans-serif;
  text-decoration: none;
  background-color: #2e4c37;
  color: #fff;
  border: 2px solid #fff;
  border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
}

As you can see from Example 2A this works very nicely in Gecko but has a few issues with padding and line heights in WebKit. If you examine the code of the example you’ll see some extra styles to tweak the padding so that the button and the link look the same (at least in Firefox) and also to produce examples where the buttons are floated (this variation is widely found on the web and also through up some problems during testing).


Add elements via JavaScript

As prevously we’re now going to use JavaScript (in the example code jQuery) to wrap the button in a span and then insert four extra elements into that span. We also add a new class to the button itself.

if($.browser.msie || $.browser.opera)  {
  $('.button-rounded').addClass('wrapped').wrap(
    '<span class="button-rounded"></span>'
  );
  $('span.button-rounded').append(
    '<i class="tl"></i><i class="tr"></i><i class="bl"></i><i class="br"></i>'
  );
};

.button-rounded.wrapped {
  border: none;
  background: transparent none;
  float: none;
  margin: 0;
}
span.button-rounded {
  position: relative;
}
span.button-rounded i {
  position: absolute;
  width: 4px;
  height: 4px;
  background: url(corners.png) no-repeat;
}
span.button-rounded i.tl {
  top: -2px; left: -2px;
  background-position: 0 0;
}
span.button-rounded i.tr {
  top: -2px; right: -2px;
  background-position: -4px 0;
}
span.button-rounded i.bl {
  bottom: -2px; left: -2px;
  background-position: 0 -4px;
}
span.button-rounded i.br {
  bottom: -2px; right: -2px;
  background-position: -4px -4px;
}

This removes most of the styles from the button and applies them to the wrapping span – this helps a lot as spans are more predictable than inputs.

But a quick look at Example 2B reveals that the floated elements don’t seem to be in the right place anymore. We forgot that there are two classes and hence two sets of styles on these buttons.

$('.button-rounded.right').removeClass('right').parent('span').addClass('right');
$('.button-rounded.left').removeClass('left').parent('span').addClass('left');

Okay, Example 2C is a step in the right direction but there are still a number of issues. In IE the floated buttons are two wide and the inline input is missing its bottom border. In Opera the two inline examples have a problem with the location of the right side corners.


Fine Tuning Internet Explorer

Add display: inline-block; to the styles for .button-wrapped. Simple and works brilliantly, Example 2d.


Fine Tuning Opera

As the browser with the smallest market share we’ve left Opera to last and hence it’s been the victim of a few CSS style choices that have been made with IE and Firefox in mind. We could deploy some CSS hacks to feed it different styles but this time I decided to use JavaScript instead.

if ($.browser.opera) {
  $('input.button-rounded').addClass('opPad');
  $('span.button-rounded').each( function() {
    if($(this).css('float') == 'none') {
      $(this).children('i.tr, i.br').addClass('opNoFlo');
    };
  });
};

input.button-rounded.opPad {
  padding: 1px 5px 2px 5px;
}
span.button-rounded i.opNoFlo {
  right: -4px;
}

So there we are, Example 2e.


If you want a hover effect on your buttons just add .button-rounded:hover and change the background and border properties. It may be easier to change the span.button-rounded:hover i background image but it’s probably better practice to change the background-position values instead and use a single corners.png as your CSS sprite holder for both normal and hover states. (Or take the easy way out and just change the text colour as I did in the last example.)

If you have multiple styles of buttons then use contextual selectors to set different CSS whilst keeping the JavaScript common across the entire site. In a real world case I have a common style that gets changed for a few <form id="foo">.


Now for the bad news. I’ve tested this in IE 7, FF 3, Opera 9.6, Safari 3, Chrome 0.4.154.22 on Windows XP. I’ll be testing in IE 6 and IE 8b2 shortly but would appreciate feedback regarding other platforms and browsers.


That last post? Some of you may have noticed that it doesn’t work very well.

The styles applied to the button and the button’s parent element make a difference in how IE (and to a lesser extent Opera) handle the positioned elements.

My current line of attack is to use more jQuery to remove some styles from the button itself and apply them to the inserted span. For Opera, I’m looking at the SVG solution.

This time I may wait until I’ve finished testing before posting.


The contents of this post are a few years old now and I can’t recommend them as best practice.

Today I decided to try and build rounded corners on a button that would work in both CSS 3 compliant browsers (Gecko and WebKit based browsers, i.e. Firefox, Camino, Safari, Chrome, etc.) and also in IE and Opera.

The HTML

<input type="submit" value="Go" class="button-rounded"/>

Nice and clean.

The CSS

.button-rounded {
        border: 2px solid #fff;
        padding: 0 2px;
        background-color: #2e4c37;
        color: #fff;
        font-weight: bold;
        border-radius: 4px;
        -moz-border-radius: 4px;
        -webkit-border-radius: 4px;
}

This is enough to do the trick in the known good browsers and in any unknown CSS 3 compliant browsers. (This part of the CSS 3 spec, whilst still not finalised, is unlikely to change.)

More CSS

span.corners {position: relative;}
span.corners i {position: absolute; width: 4px; height: 4px; background: url(corners.png) no-repeat;}
span.corners i.tl {top: 0; left: 0; background-position: 0 0;}
span.corners ispan.corners ispan.corners i.tr {top: 0; right: 0;  background-position: -4px 0;}
.bl {bottom: 0; left: 0; background-position: 0 -4px;}
.br {bottom: 0; right: 0; background-position: -4px -4px;}

Yet more CSS for IE (use a conditional comment or your hack of choice)

span.corners i.tl, span.corners i.tr {top: 1px;}
span.corners i.bl, span.corners i.br {bottom: 1px;}

(There’s a one pixel difference betwen the way Opera and IE draw the button, hence the branched CSS. This may not always be the case, depending on the CSS styles you use for the border but with a 2px wide border with a 4px corner radius it was the case.)

[Update] It seems that IE8 differs from IE7 in this respect. I’ll revisit this article when IE8 leaves beta.

The graphic

, a bit small, here it is ×4 . That’s all four corners in one graphic, for use as CSS Sprites in the above CSS code.

But where are these elements that this extra CSS references? They get added by JavaScript, in this case using the jQuery library.

The JavaScript

if(($.browser.msie && $.browser.version == '7.0') || $.browser.opera) {
        $('.button-rounded').wrap('<span class="corners">>/span>');
        $('span.corners').append('<i class="tl"></i><i class="tr"></i><i class="bl"></i><i class="br"></i>');
};

Why <i>? Because it uses the least code. If you like you can use <span> instead.

Why browser sniff? Because we don’t want to write extra code into the page for browsers that don’t need it and it’s hard to include IE and Opera but exclude FF and Safari by other means.

Remember that any browser excluded from the JavaScript and incapable of using CSS 3 will get a button with square corners. We are not excluding anyone from functionality, nor from the general design – just from one small detail.

The result

So Firefox and Safari get rounded corners via CSS. IE7 and Opera get some extra code which positions graphics over the corners of the buttons.

Still to do

IE6 has some problems with using the right and bottom CSS properties. Hence for the moment I exclude it from the JavaScript. This is what I hope to resolve in part 2.

There’s also a potential future-proofing issue – when Opera and IE start supporting border-radius this code will position the graphics over the rounded corners, which may or may not work depending on how closely their rounded corners match the ones Gecko draws (the graphic was produced from a screen shot of the corners in Firefox).

Part 2, in a few days.


On the dino pages I’ve updated the lists to include the latest releases from Fenryll, some very old Metal Magic caveman now available via Mega Minis and a general update of the Jeff Valent listings.

As promised only two and half months ago I’ve now upgraded the blog to use the standard WordPress sidebar syntax which makes it much more widget-friendly. I’ve also converted what little JavaScript I was using to use jQuery as part of my ongoing learning process.

I’ve added a few new plugins to the mix: Sociable, Better Blogroll and MyTwitter.


I’ve been meaning to learn how to use a JavaScript library for some time. I first learnt JavaScript when it originally appeared in Netscape 2 and wasn’t working with it much in the years when it was knocked into shape by some proper programmers, so a library seemed to be the best short cut to more modern coding styles.

Looking at the various libraries I ranked them in order of attractiveness as jQuery > YUI > Prototype > Dojo. This was based on a first glance at file size, amount of documentation and supported features. That was over a year ago.

With jQuery in the lead it would be surprising of John Resig’s talk at @media would do much to change it my mind. But I decided to put his advice into practice and download a library and try it out. Twenty minutes after downloading jQuery I was starting to update a copy of the code used on VisitLondon.com

From this (not the greatest piece of JavaScript in the world – it was written by multiple authors in a bit of a rush – but not the worst either):

function topmenuClear() {
 var navRoot = document.getElementById("topmenu");
 for (var i=0; i<navRoot.childNodes.length; i++) {
  var node = navRoot.childNodes[i];
   if (node.nodeName=="LI") {
    node.className=node.className.replace("over", "");
    node.childNodes[0].className="";
   }
 }
}
function topmenuHover() {
 if(document.getElementById("topmenu")) {
  var navRoot = document.getElementById("topmenu");
  for (var i=0; i<navRoot.childNodes.length; i++) {
   var node = navRoot.childNodes[i];
   if (node.nodeName=="LI") {
    node.onmouseover=function() {
     clearTimeout(navTimer); topmenuClear();
     this.className+=" over";
     this.childNodes[0].className="over";
    };
    node.onmouseout=function() {
     navTimer = setTimeout(topmenuClear,2000);
    };
   }
  }
 }
}
function showlang() {
 if(document.getElementById('lang-list').style.display == "none") {
  document.getElementById('lang-list').style.display = "block";
 } else if (document.getElementById('lang-list').style.display == "block") {
  document.getElementById('lang-list').style.display = "none";
 }
}

To this:

function topmenuClear() {
 $("#topmenu > li").removeClass("over");
 $("#topmenu > li > *").removeClass("over");
}
function topmenuHover() {
 $("#topmenu > li").mouseover(function(){
  clearTimeout(navTimer); topmenuClear();
  $(this).addClass("over");
  $(this).find(":first").addClass("over");
 });
 $("#topmenu > li").mouseout(function(){
  navTimer = setTimeout(topmenuClear,2000);
 });
}
function showlang() {
 $("#lang-list").toggle();
}

Okay, so that’s probably the easiest part of our code to modify as it’s doing a very basic task – toggling visibility and adding event handlers – but it makes a dramatic difference to the complexity of the code. I’ve still got a lot of work and testing to do but I’d like to reach the point where the only JavaScript coding I have to do is implementing our functionality rather than reimplementing common functions.