ImgAreaSelect 0.9.4

March 8th, 2011

A new minor release of imgAreaSelect is out. It fixes a small issue that affected bordered images, and adds a new option, resizeMargin, which allows you to set the space near the border of the selection area where resizing is allowed (previously hardcoded to 10px).

As usual, thanks and kudos to all the nice people who reported bugs and sent feedback.

By the way, this release is also the first one to be available on GitHub, so you can go and fork the hell out of it.

Engine Swap

January 15th, 2011

Vroom vroom vroom vroom!

That’s the sound of my website running on a new engine.

For the past three years, the awesome alien technology behind my website was a bunch of PHP classes that I quickly put together, in a lousy attempt to build a lightweight MVC-like framework. That did the job, but it was kind of a duct tape solution which I didn’t particularly appreciate, and I finally took the time to replace it with something more decent.

I decided to go with Symfony as the basis for the new engine. Rebuilding went pretty quick, and the only thing that took some time was WordPress integration (for the curious, I used a slightly modified version of this method).

You might also notice that the design has changed a bit. It’s not very different from the previous one, but that’s just the visual part — the HTML has undergone significant changes. My primary goals were:

  • Keep the HTML structure as simple as possible, with no meaningless elements
  • Use a minimum number of images for the basic layout (gradients and rounded corners are now made with CSS)
  • Degrade nicely for older browsers, including IE6 with JavaScript disabled

Now, one might question whether it makes any sense to acknowledge IE6 anymore, considering that many websites have already turned their backs on it, and that the content of my website makes it targeted at web-savvy visitors using modern browsers. Ok, so I did it mostly for the lulz. And I’m happy with the overall result.

Vroomity vroom vroom!

SelectList Available on GitHub

December 30th, 2010

With the last update to selectList, I made the plugin code available on GitHub. A few people have requested this, so there it is — go and grab it, fork it, or do whatever you can imagine with it.

My other projects will probably follow — however, I’m not migrating them to GitHub, I’m just using it as another means of making my code available to the world. Everything will still be hosted here on this website, and being the cloud-phobe that I am, I don’t expect this to change anytime soon.

SelectList 0.4

December 21st, 2010

SelectList 0.4 has just been released. This is a major update which introduces a different (better) approach to how the original multiple selection element is handled and how the plugin stores the selected options.

In the previous versions, the multiple select element was transformed into a single selection drop-down list by stripping off its multiple attribute, so there was no multiple select in the document anymore, and the selected options had to be stored in a series of type="hidden" input elements. However, this turned out to cause significant problems with obtaining the selected values with the core jQuery .val() method, and with serialization through .serialize().

I modified the code so that the original multiple selection element stays hidden in the document and continues to serve as a container for the selected options. This way the .val() and .serialize() methods are unaffected and can be used in the conventional manner.

This solution also has a few drawbacks (for example, it makes validation a bit more complicated), but it’s much easier to work around them than dealing with the quirks of the previous method.

The new version works with jQuery 1.3.2 up to 1.4.4. Oh, and the refactoring also happened to have made it smaller than the previous version.

Catching up

November 29th, 2010

I haven’t been posting for a while — in the past couple of weeks I’ve been extremely busy with running my company, which translates to little time for personal projects and other stuff I might want to share with the world. Now, as things have cooled down a bit, I’m getting back to it.

Some issues have been reported with my jQuery plugins, and I’ll be looking into them in the next few days (always thankful for your feedback, keep it coming). It seems the recent new releases of jQuery (1.4.3 released mid-October and 1.4.4 shortly thereafter) broke some of the plugins’ functionality, so I’m going to first bring the code up to date with the latest version.

I’m also resuming work on a related project, which is a JavaScript testing application, codenamed “JSweet”. It’s already operational (I use it to automate the testing process of jQuery plugins), but definitely needs some polishing before it can be released to the public.

So that’s it for a quick catch-up. Going back to my JS debugging session…

ImgAreaSelect 0.9.3

October 30th, 2010

I released imgAreaSelect 0.9.3 today. It fixes two minor bugs — incorrect behavior of the persistent option under some circumstances, and a problem with displaying handles which manifests itself when the plugin is used with jQuery 1.4.3 (which was released a couple days ago). Thanks to Tim for reporting the latter problem.

SelectList 0.3.3

September 30th, 2010

A new minor release of selectList is out, fixing a bug with incorrect handling of special characters in item names. Thanks to Sung Pae for reporting it and suggesting a solution.

Moving Windows to the Current Workspace in Gnome/Compiz

September 23rd, 2010

On my home workstation, I have a pretty vanilla installation of Ubuntu (10.04), with Gnome as my desktop environment, and Compiz. I use four workspaces, and usually have around 50-60 application windows open and scattered around the workspaces. With this many applications, every once in a while I faced the problem of not being able to quickly find the one particular window that I wanted, because it was lost somewhere on one of the workspaces.

I frequently had this issue with KeePassX, a neat password management application. Often, when I wanted to log in to a website/service/whatever, and needed KeePassX to get the login credentials, I had to first go through all the workspaces to find the KeePassX window and drag it to the workspace where I wanted it. This was annoying.

Annoyance is the mother of invention, so I solved this problem with a shell script that locates the application’s window and brings it to the current workspace. If the script finds that the application is not running, it starts it. It takes two arguments, the first argument is a string that is used to locate the “lost” window — the script looks for a window with a title that contains that string. The second argument is the program to run if no window is found (optionally followed by program arguments).

This is how I use it to find/run KeePassX:

summon.sh 'passwords.kdb - KeePassX' keepassx

The KeePassX window title is "/path/to/passwords.kdb - KeePassX", and I use the "passwords.kdb - KeePassX" part as the title string. Just "KeePassX" might be insufficient, if, for instance, there is a web browser window open with the KeePassX homepage and also has "KeePassX" in the title. The "passwords.kdb - KeePassX" string is distinctive enough.

I have this set up as a launcher in my Gnome panel, so I can simply click the KeePassX icon and have the window pop up on the current workspace:

KeePassX Gnome panel launcher

So in case you’d like to use the script for a similar purpose, here it is:

#!/bin/sh

#
# summon.sh - Brings application window to current workspace or starts the
#             application if it isn't running. Intended for use with Gnome and
#             Compiz.
#
# Usage: summon.sh <window title> <program> [arguments]...
#
#        <window title> is the title (or a substring of it) of the window to be
#        found.
#
#        <program> is the application to run if no window is found. May be
#        followed by arguments.
#

SELF=`basename $0`

if [ $# -lt 2 ]; then
    cat <<END
Usage: $SELF <window title> <program> [arguments]...

    Brings application window to current workspace or starts the application if
    it isn't running. Intended for use with Gnome and Compiz.

    <window title> is the title (or a substring of it) of the window to be
    found.

    <program> is the application to run if no window is found. May be followed
    by arguments.
END
    exit 1
fi

TITLE_SUBSTR=$1
shift

# Check if the application is running
WINDOW_ID=`wmctrl -l | grep "$TITLE_SUBSTR" | sed -r 's/\s.*//'`

if [ -z $WINDOW_ID ]; then
    # Not running -- start it
    exec $@
else
    # Application is running -- it's window is $WINDOW_ID

    # Get the dimensions of a single workspace
    XDPYINFO_OUT=`xdpyinfo | grep 'dimensions:'`
    WORKSPACE_WIDTH=`echo "$XDPYINFO_OUT" | sed -r 's/.*:\s+([0-9]+)x.*/\1/'`
    WORKSPACE_HEIGHT=`echo "$XDPYINFO_OUT" \
        | sed -r 's/.*:\s+[0-9]+x([0-9]+).*/\1/'`

    # Get the X and Y offset of the current workspace
    XPROP_OUT=`xprop -root -notype _NET_DESKTOP_VIEWPORT`
    CURRENT_X=`echo "$XPROP_OUT" | sed -r 's/.*= ([0-9]+),.*/\1/'`
    CURRENT_Y=`echo "$XPROP_OUT" | sed -r 's/.*= [0-9]+,\s*([0-9]+).*/\1/'`

    # Get the coordinates of the top left corner of KeePassX window
    XWININFO_OUT=`xwininfo -id "$WINDOW_ID"`
    WINDOW_X=`echo "$XWININFO_OUT" | grep 'Absolute upper-left X' \
        | sed -r 's/.*:\s+([0-9-]+).*/\1/'`
    WINDOW_Y=`echo "$XWININFO_OUT" | grep 'Absolute upper-left Y' \
        | sed -r 's/.*:\s+([0-9-]+).*/\1/'`

    # Calculate the new location of the window
    NEW_WINDOW_X=`echo "($CURRENT_X + ($WINDOW_X)) % $WORKSPACE_WIDTH" | bc`
    NEW_WINDOW_Y=`echo "($CURRENT_Y + ($WINDOW_Y)) % $WORKSPACE_HEIGHT" | bc`

    # Move the window to the new location and raise it
    wmctrl -i -r "$WINDOW_ID" -e 10,"$NEW_WINDOW_X","$NEW_WINDOW_Y",-1,-1
    wmctrl -i -R "$WINDOW_ID"
fi

The script uses several command-line tools: wmctrl, xdpyinfo, xprop, xwininfo, and bc. I’m pretty sure they are available by default in a standard Ubuntu installation (and probably most other Linux distros, for that matter). If, however, any of them happen to be missing in your system, install the appropriate packages first.

ImgZoom 0.2.1

September 21st, 2010

I’ve just released a new version of imgZoom. This is a minor update which brings a few bugfixes and small code improvements.

Thanks to Marc Hoyois for his feedback.

Decrypting the User Agent String in JavaScript

September 10th, 2010

I test all my jQuery plugin releases in a simple testing environment that I developed. It’s nothing sophisticated, but it allows me to do much of the testing automatically and generates nice reports. The results of the tests are saved in a database, and for each test there is (among other stuff) information about which plugin version was tested, with which jQuery version, and on what browser.

For that purpose, I wanted to extract the browser name and version number from the user agent string that browsers use to reveal their identity to web pages. However, it’s not that simple, since there is no common format of the user agent string and each browser vendor seems to have their own idea of what to put in it.

For example — which version of Opera is this?

Opera/9.80 (X11; Linux i686; U; en) Presto/2.2.15 Version/10.10


Is it 9.80, or 10.10? If you’re curious, it’s 10.10, and this Dev.Opera blog post explains it.

(If you’re even more curious about why this user agent string business is such a mess, I recommend you read this story — apart from being informative, it’s also funny.)

Anyway, for my testing platform I wrote a JavaScript function that extracts the browser name and version (by default just the major and minor release number) from the user agent string. I’m posting it here in case someone finds it useful too. It recognizes the “big five” browsers that have a significant market share (Firefox, Internet Explorer, Opera, Chrome, and Safari), as these are the browsers that I test my plugins on.

Here’s the source code:

/**
 * Extracts the browser name and version number from user agent string.
 *
 * @param userAgent
 *            The user agent string to parse. If not specified, the contents of
 *            navigator.userAgent are parsed.
 * @param elements
 *            How many elements of the version number should be returned. A
 *            value of 0 means the whole version. If not specified, defaults to
 *            2 (major and minor release number).
 * @return A string containing the browser name and version number, or null if
 *         the user agent string is unknown.
 */
function identifyBrowser(userAgent, elements) {
    var regexps = {
            'Chrome': [ /Chrome\/(\S+)/ ],
            'Firefox': [ /Firefox\/(\S+)/ ],
            'MSIE': [ /MSIE (\S+);/ ],
            'Opera': [
                /Opera\/.*?Version\/(\S+)/,     /* Opera 10 */
                /Opera\/(\S+)/                  /* Opera 9 and older */
            ],
            'Safari': [ /Version\/(\S+).*?Safari\// ]
        },
        re, m, browser, version;

    if (userAgent === undefined)
        userAgent = navigator.userAgent;

    if (elements === undefined)
        elements = 2;
    else if (elements === 0)
        elements = 1337;

    for (browser in regexps)
        while (re = regexps[browser].shift())
            if (m = userAgent.match(re)) {
                version = (m[1].match(new RegExp('[^.]+(?:\.[^.]+){0,' + --elements + '}')))[0];
                return browser + ' ' + version;
            }

    return null;
}

A few examples of user agent strings and the returned results:

Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.9) Gecko/20100825 Ubuntu/9.10 (karmic) Firefox/3.6.9 Firefox 3.6 Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.19 Safari/533.4 Chrome 5.0 Opera/9.80 (X11; Linux i686; U; en) Presto/2.2.15 Version/10.10 Opera 10.10 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0) MSIE 8.0