Tuesday, December 08, 2009

Open-source spell checkers

A friend of mine recently put out a call for help, looking for open-source spell checking APIs. I knew of a few, so I've assembled a list here.

  • GNU Aspell The most widely used open-source spell checker that I know of. Supersedes Ispell apparently.
  • Hunspell Used by Firefox 3, OpenOffice.org and Google. It's been ported, or had bindings written, for many languages include Java
  • JaSpell I thought this was a Java port of Aspell, but it doesn't mention Aspell, so it must be original.
  • Jazzy A Java implementation of Aspell's algorithms. Interesting article about it here.
  • Speller Pages This looks interesting: a JavaScript spell-checker for web pages.
  • After the Deadline I think this is also online based, but there's a Python library. Does a lot more than just spell checking: take a look at the page for more info.

Monday, May 04, 2009

Controlling Spotify

I love Spotify, but unfortunately it doesn't include an AppleScript dictionary. This is a little limiting when it comes to controlling it, but Mac OS X has a useful work around: GUI scripting.

With GUI scripting, you can use the "System Events" application to effectively click any item on the screen, including those of non-AppleScript applications. Using this principle, I modified my iTunes global Play/Pause script as follows to also control Spotify:

tell application "System Events"
 -- Check whether iTunes or Spotify is running
 set iTunes_instances to count (every process whose name is "iTunes")
 set Spotify_instances to count (every process whose name is "Spotify")
end tell

if iTunes_instances > 0 then
 -- iTunes support AppleScript, so is easy to control:
 tell application "iTunes" to playpause
else if Spotify_instances > 0 then
 -- Spotify doesn't. We want to keep it in the background, so check which app's active.
 set ActiveApp to (path to frontmost application as Unicode text)
 -- Bring Spotify forward so we can control it.
 tell application "Spotify" to activate
 
 -- Activate its "Play/Pause" control
 tell application "System Events"
  tell process "Spotify"
   click menu item 1 of menu "Playback" of menu bar 1
  end tell
 end tell
 
 -- Restore the previously-active app to the front
 tell application ActiveApp to activate
end if

So there you have it: a way to control Spotify without having to touch the mouse. Things will flash momentarily on the screen, but this shouldn't be too disruptive as you're telling the script to run anyway. I use QuickSilver to run this script whenever I hit F8. Very useful for working.

Thursday, December 04, 2008

IE box clipping with 'filter' hack

For some time now, there's been a glitch on the SUSU front page. I'm entirely to blame, and it's partly through my apathy for IE that it remained. Yesterday however, I decided enough was enough and fixed it.

The problem was a negatively positioned image which would get clipped when rendered in IE (of any version). I'd done this on other pages with no problems, whether using negative margins (margin-top: -25px;) or positioning (position: relative; top: -25px;). In this case, I was using absolute positioning, so I could also right-align the image within its containing div.

I can't remember what lead me to try this, but I removed a little IE hack from the containing div's style, which was used to render a PNG with alpha transparency properly in IE5.5+. As it was, it was hardly necessary for this PNG, as its background was plain. The 'hack', if you're unaware, looks a little like this:

.styled-div {
   background: url('alpha.png') no-repeat !important;
   background: transparent;
   filter: progid:DXImageTransform.Microsoft.AlphaImageLoader (src='alpha.png', sizingMethod='crop');
}

The fundamental part is the filter property, which is unique to IE. It calls a special utility in IE's renderer to load an alpha image, which is then rendered just like IE7, Firefox, Safari, etc. The background tricks are needed to hide the normal background image in IE (IE doesn't understand what !important means).

The interesting thing that I discovered is that this property was affecting how the div's child elements were rendered too. When I tried to position an element outside of its box, regardless of any overflow values I tried, they'd be clipped.

The solution was simple: don't use filter. In my case, I could easily change the background image so it didn't need alpha transparency. Actually, I tweaked the PNG file so it still renders with transparency, but IE uses a different background colour (Photoshop calls this the matte colour). I used TweakPNG to do this. What should you do if you need nested alpha transparency though?

Unfortunately, it doesn't work. Well, you can nest transparent images as much as you like, just don't expect them to leave the parent's bounding box. I did a little experiment, trying different values for sizingMethod, and different combinations of divs with and without the filter property. As long as the parent box has filter set, all its children will be cropped at its edges. Oh well, I guess you get what you pay for!

Saturday, November 22, 2008

Adding table rows with JS in IE

Phew, I finally cracked it! After about three hours of stressing over the lack of a debugger in IE, I manage to fix my code. I'm using the mootols JavaScript library, as it has some useful features that make JS considerably easier. Also, it was the JS library already included in the page I was editing (otherwise, I'd have likely used JQuery). Anyway, here's a bit of code:

 function add_blank_team(){
  var table = $('forms');
  var row = table.getElement('tr').clone();
  var boxes = row.getElements('input');
  for(var i = 0; i < boxes.length; i++) {
   var name = boxes[i].getAttribute('name');
   if(name == "QuizTeamName[]" || name == "QuizTeamID[]") {
    boxes[i].value = "";
   }
   else if(name == "QuizTeamScore[]") {
    boxes[i].value = 0;
   }
  }
  table.adopt(row);
 }

As a quick explanation, this is a function which adds a blank row to a score card table. It's for a pub quiz event! Anyway, the table has the id 'forms', there are two cells per row with four inputs overall (but two are hidden). The idea is to clone an existing row (which means no need to recreate a mini-DOM for a table row in JS!), empty the relevant boxes, and attach it at the end of the table.

As the code is shown above, it'll work flawlessly in everything but IE. Why? Well, as I've just discovered, IE takes the DOM a little more literally than other browsers. It's all to do with TBODY...

Not many people bother with the TBODY tag in HTML (I certainly don't), but it's a part of the spec, and browsers deal with its absence by adding it to the DOM automatically. Most browsers know that they're done this, so if you try to do something silly, like add a row to a table outside of the body, it does what it thinks you meant: add the row to the TBODY. Indeed, this worked in Firefox, Safari and Opera. IE however, isn't happy with that (though it won't tell you!).

The fix is simple: change that first line as follows

  var table = $('forms').getElement('tbody');

This works for all browsers. Even if you don't think there's a TBODY, it really is there. Just take a look in the DOM explorer (varies between browsers).

Wednesday, October 15, 2008

DisplayPort: now with more Mini

So Apple announced a whole new line of MacBooks yesterday, and I was quite excited. In fact, if I had the money, I'd probably buy a new 13" MacBook right now.

Unfortunately, as ever, Apple seem to be confusing things with their new 'Mini DisplayPort'. I'm willing to accept that having the same connector across the whole range makes sense. Unfortunately, it seems they've had to miniaturise the standard DisplayPort connector for the Air's sake.

Personally, I'd rather see standard DisplayPort across the range (including desktops when they're updated) and Mini DisplayPort only on the Air. That way, everyone saves money except Air owners, and they have more money than sense as it is!

This links with the brilliant new 24" LED display too. Beautifully conceived for notebook users, I love the idea of a built-in charger, and hooking up audio, iSight and a hub over USB. But why the non-standard connector? Surely Apple have lost a potential market of PC users who use Apple Cinema Displays (and they do exist, I assure you)? It's not like there's an adapter (yet) to attach a standard DisplayPort to a Mini DisplayPort, or vice-versa.

I also wonder if some of the advantages of DisplayPort have been lost. For example, there's a 1GBit auxillary data path in DisplayPort, ideal for routing USB, FireWire or video from the iSight. As it is, all this (except FireWire) has been done with the USB port. I wonder if it was really that much cheaper to use plain USB?

Which bring me onto FireWire... WHY APPLE? WHY?!

FireWire has great advantages on a Mac, and is well exploited by existing machines and the OS. It's been on every Apple machine since the iMac DV. It was even the requirement of installing Tiger! (Does this mean Tiger won't install on a new MacBook?) It's really disappointing that Apple have decided to drop it, though I understand it's probably due to cost.

Here's my idea though (even if it's too late): The DisplayPort's auxiliary data path has more than enough bandwidth for FireWire 800, let alone 400. So why not pass it through there? There could be an adapter to get the port, or the ports could be included on the new 24" Cinema Display. Great huh? Makes things simple, and cheaper for Apple. Oh well!

Oh also, where's the TV out gone? It's rare to find a flat-panel with DisplayPort, and certainly where I live, even flat panels aren't that common. *whimper*