Archive for 2010

SelectList Available on GitHub

Thursday, 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

Tuesday, 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

Monday, 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

Saturday, 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

Thursday, 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

Thursday, 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 -- its 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 the 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

Tuesday, 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

Friday, 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

ImgZoom 0.2

Thursday, September 9th, 2010

As promised, I’m releasing imgZoom version 0.2. This is a major update compared to the previous release, as it adds several features that make the plugin an usable alternative to Lightbox (and its numerous clones) — most importantly, the ability to navigate between multiple images (you might have already seen this in the sample gallery that I posted some time ago).

Nonetheless, there are still some features which are obviously missing, like keyboard support and auto-scaling of large images. These are planned for version 0.3, which I hope to develop soon (but, as always, no promises).

The new features are described in the updated documentation. I still need to add some usage examples, though.

As usual, I’m looking forward to your feedback.

ImgZoom 0.2 Almost There

Saturday, August 28th, 2010

A few months back I announced a new version of imgZoom (the Lightbox-esque image zooming jQuery plugin) and exhibited a sample gallery that showed it in action. Most of the new features were already implemented back then, and I hoped to finish it quickly and release the new version, but then I stumbled over a number of problems with Internet Explorer, got somewhat frustrated, and gave it up for a while.

Now, I have finally found enough inner strength to get back to working on it. For the past few days, I’ve been fighting all those nasty Internet Explorer bugs and its insane behavior. It was even more painful than I expected, as often fixing one problem lead to another, a workaround for IE7 triggered a bug in IE6, and so on.

So far, all the time I spent developing the new version can be accurately represented by this pie chart:

You might notice that it bears a close resemblance to another chart that you might have seen on the interwebs:


(source: EatLiver.com)

Conclusion: screw you, Internet Explorer.

Ok, enough whining. The good news is, it seems I managed to resolve or work around all the problems, and now it’s just a matter of a couple more tests and code cleanups to get the new version ready for release — so expect it in a few days.

Unless, of course, the tests reveal more IE-related problems and I get a nervous breakdown. In that case expect a tweet from a mental institution.

  • Archives

  • Categories

  • Meta

  • Latest Tweets


    Warning: Illegal string offset 'last_access' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 334

    Warning: Illegal string offset 'time_limit' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 334

    Warning: Illegal string offset 'last_access' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 336

    Warning: Illegal string offset 'twitter_api' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 234

    Warning: Illegal string offset 'user_token' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 262

    Warning: Illegal string offset 'user_secret' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 263

    Warning: Illegal string offset 'consumer_key' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 264

    Warning: Illegal string offset 'consumer_secret' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 265

    Warning: Illegal string offset 'twitter_username' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 270

    Warning: Illegal string offset 'show_retweets' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 272

    Warning: Illegal string offset 'exclude_replies' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 275

    Warning: Illegal string offset 'twitter_data' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 282

    Warning: Illegal string offset 'twitter_data' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 350

    Warning: Illegal string offset 'twitter_data' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 351
    Twitter outputted an error:
    .
    Warning: Illegal string offset 'time_format' in /usr/local/www/odyniec.net/public/blog/wp-content/plugins/twitget/twitget.php on line 484
  • Follow odyniec on Twitter