March 24th, 2014 at 12:03 am

Dynamically show size of a browser window

As a web developer, you want to check your work in different browser sizes. Here’s a tool that will show you a browser window’s current size, even when resizing. It’s a simple HTML page with a bit of JavaScript, which you may upload to your own server and adapt if necessary. Enjoy!

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Size info</title>
    </head>
    <body>
        <p>
            <code>
                width: <span id='width'>0</span>px<br />
                height: <span id='height'>0</span>px
            </code>
        </p>
 
        <script type='text/javascript'>/* <![CDATA[ */
 
            var recalc = function()
            {
                document.getElementById('width').firstChild.data = window.innerWidth;
                document.getElementById('height').firstChild.data = window.innerHeight;
            };
 
            if (window.attachEvent) { window.attachEvent('onresize', recalc); }
            else if (window.addEventListener) { window.addEventListener('resize', recalc, false); }
            else { document.addEventListener('resize', recalc, false); }
 
            recalc();
 
        /* ]]> */</script>
 
 
    </body>
</html>

Or check out the demo.

November 20th, 2013 at 1:48 pm

Decimal number formatter in JavaScript

Today we’ll build a decimal number formatter for JavaScript. A common use case is the display of numbers with a fixed amount of digits (like a price amount), even if the actual value has more or less digits.

This is a bit more complicated that it may seem at first glance: The internal representation of a float value is in some cases not what you see, but a weird number such as 100.000000000023. Therefore it’s not sufficient to round the vaule and chop off a bit at the end. Our approach is a bit more complicated, but bullet-proof. At the end, we receive a string (NB: not a float!) that is the exact representation of the figure we want to show.

Note: We are using the pad() function that has been introduced in an earlier post.

 
/**
 * Formats float values to a string representation with a fixed number of decimals
 *
 * @param val the numeric value to format (required)
 * @param _decimals number of decimals (optional, default: 2)
 * @param _sep the decimal separator (optional, default: ".")
 *
 */
var numberFormat = function(val, _decimals, _sep)
{
    var
        decimals = _decimals || 2,
        sep = _sep || '.',
        floatVal = parseFloat(val) || 0,
        intpart = Math.floor(floatVal),
        factor = Math.pow(10, decimals),
        fractpart = floatVal*factor - intpart*factor;
 
    fractpart = pad(Math.round(fractpart), decimals, '0');
 
    return '' + intpart + sep + fractpart;
};
// Some tests
alert(numberFormat(234.2247)); // "234.22"
alert(numberFormat(234.2)); // "234.20"
alert(numberFormat(234.2247, 3)); // "234.225"
alert(numberFormat(234.2247, 2, ',')); // "234,22"
March 12th, 2013 at 2:45 pm

OpenSource gaming: Hedgewars

I’m not much of a gamer, but I enjoy playing a little game during breaks now and then. One of my favourites has always been the classical Worms. Being a Linux user, I was looking for a Worms clone that would run on Linux.

I eventually found Hedgewars – an OpenSource Worms clone with hedgehogs as main characters. Hedgewars comes with lovely graphics and a nice selection of weapons. The game physics are implemented very well, this goes for moving the hedgehogs (walk, leap, jump) as well as for using the the weapons/tools.

Hedgewars even features an AI, with different levels of strength. However, across all levels, the AI characters still act very predictable. Also – this being my only critisism –, even the “weak” AI characters often shoot very precisely over long distances, and with a perfect timing of grenades (so they hit you exactly when detonating), which I find annoying, because a weaker human character would never shoot that good. Therefore, playing agains the AI is currently not so much fun – but it might improve over the next releases.

There are different ways to play the game: You can play a training match, alone against the AI, a hot-seat game, or you can play a network game against other players around the world. (I haven’t tried network so far, didn’t dare yet. ;))

There are dozens of nice features, the Dev Team and the Hedgewars community put a lot of work in the core game, as well as in addons. You can create your own hedgehog teams, your own maps, etc. For local matches, you can select maps or sets of available weapons. You can even create custom match profiles, and re-use them.

Hedgewars is available for the major desktop platforms, i.e. Linux, *BSD, Windows, Mac – as binary or source downloads.

Thumbs up for the Hedgewars team for a great game!

February 6th, 2013 at 1:20 am

Universal padding function for JavaScript

Here’s a little helper that will help with padding numbers or short strings with arbitrary characters to a given length. It can also be used to fake right-aligning text in a fixed-width container (e.g. a printer emulator).

function pad(_val, _len, _fill)
{
    var
        val = _val.toString(),
        len = _len || 2,
        fill = _fill ?  _fill.toString() : ' ',
        padChars = '';
 
    while (val.length < len)
    {
        val = fill + val;
    }
 
    return val;
}

The val parameter is the value to be padded, the len parameter specifies the desired length of the final string, the fill parameter is the chacacter that will be used for padding.

December 6th, 2012 at 1:28 pm

Simple and secure backups to a remote server

Well, backups … neverending story. Of course, everybody has got an external drive they regularily attach to their machine, in order to backup all important data, and everybody performs a restore proceedure every now and then to check the backups are functional and complete. *cough*

The solution shown in this post does not aim at backing up all of your data, but only the most important, yet in a very secure way: Encrypted and off-site on a remote server. Because your external drive won’t help you when your house burns down or thieves come visiting.

The following script will create an archive file of your most important folders. (They should not be larger than around 100 MBs, or everything will take very long.) The archive is then encrypted symmetrically¹ and uploaded to a remote server. In order to check consistency, we will also generate an md5 sum² of the archive.

What do we need for this? Simply a remote server running SSH, as well as some common shell tools on our home Linux (or BSD or OS X, for that matter) machine: gpg, bzip, tar, scp, md5sum. So here we go:

#!/bin/bash
 
### configuration
 
FOLDERS="letters projects"          # folders to backup
PASSWORD="myFunnyPassword123yeah"   # encryption passphrase
 
SERVER="example.com"                # server name
USER="john"                         # user login name
TARGET="/home/john/backups/"        # target path on server
PORT="22"                           # SSH port, 22 is default
 
 
############################################################
 
 
BUILDTIME="$(date +%s)"
FILENAME="backup-$BUILDTIME.tar.bz2"
 
echo -n "* creating archive … "
tar -cjf $FILENAME -C "$(pwd)" $FOLDERS
echo "done."
 
echo -n "* encryption … "
gpg --batch --passphrase $PASSWORD --symmetric "$FILENAME"
md5sum "$FILENAME.gpg" > "$FILENAME.gpg.md5"
echo "done."
 
echo -n "* uploading … "
scp -qP $PORT $FILENAME.gpg $FILENAME.gpg.md5 $USER@$SERVER:$TARGET
echo "done."
 
echo -n "* cleaning up … "
rm $FILENAME $FILENAME.gpg $FILENAME.gpg.md5
echo "done."
 
exit 0

Restoring is quite easy. Download one of the encrypted archives along with its .md5 file, check the md5 sum, decrypt, unarchive, voilà.

¹ Using symmetric encryption and a plain text passphrase in the above script is nothing to worry about. The passphrase will never leave your home. Of course, you should have your hard drive encrypted, and restrict any local or network access to the script’s location. (For example, you could simply set the permissions of your $HOME directory to 700.)

² The md5 file can obviously not ensure consistency if the encrypted archive is manipulated on purpose, it’s just to check that there were no transmission errors.

November 17th, 2012 at 11:42 am

Extremely simple tooltip plugin for jQuery

There are tons of tooltip plugins for jQuery, but most of them are extremely bloated or are badly coded. So here’s my shot at an extremely lightweight tooltip for jQuery:

The JavaScript:

(function($) {
    $.fn.tooltip = function($elem) {
        var
            $tooltip = $("<div class='tooltip'>").html($elem).appendTo('body'),
            $this = $(this);
 
        $this
            .hover(function(){
                var offset = $this.offset();
                $tooltip.show().css({
                    top: offset.top + 'px',
                    left: (offset.left - ($tooltip.outerWidth() + 2))+'px'
                });
            }, function(){
                $tooltip.hide();
            });
 
        return this;
    };
})(jQuery);

The CSS:

div.tooltip {
    /* these settings are mandatory */
    display: none; position: absolute;
 
    /* you can play with these */
    width: 180px; background: #f9f9f9; padding: 5px 8px 8px;
    font-size: 12px; line-height: 14px; box-shadow: 0 0 5px #aaa;
}

Usage:

$('#foobar').tooltip('Now this is the story all about how my life got flipped, turned upside down …');

Feel free to use this as a basis for your own implementation.

November 8th, 2012 at 1:34 pm

Tip for using sudo in shell scripts

When you use sudo in a shell script, the script may run for some time before the user is asked for the password. This can be bad, e.g. when the user expects the process to run in the background and directs his attention to something different — only to see later that the script got hung at some point where it waits for the user to enter the password.

Therefore, it’s a good idea to request the password at the beginning of the script:

# trigger passwort dialog, so we don't get bothered later
sudo true || exit 1

Keep in mind that sudo must be set up to remember the password for some time, and this period must be longer than the script execution time. Otherwise, this hack doesn’t make much sense.

October 2nd, 2012 at 12:05 pm

Different types of exceptions in PHP

It appears to be still obscure to many web developers what different types of exceptions are for in PHP, so I’ve decided to write up some notes about the use and usage of them.

An exception indicates that something has failed. If your code doesn’t use exceptions too much, you may tend to only use PHP’s base Exception. But even PHP itself provides different types of exceptions, so what’s the use of them?

Subroutines can fail because of different reasons. A common, but bad thing is to handle all exceptions the same: Maybe log the error message somewhere, and then proceed as if nothing has happened. Or: blame all exceptions on the user – we all remember Windows error messages like “A fatal exception 0E has occurred at 0028 …” – and you asked yourself: “So, what can I do about it?”.

Obviously, different types of errors require different types of exceptions. But how to accomplish that in your code? First, let’s classify how things could go wrong. Let’s start with three categories: (1) The user has provided bad input, (2) an external system doesn’t behave correctly, (3) we have an internal problem. An example for category 1 would be a situation where form validation fails, category 2 would contain things such as failed HTTP calls, and category 3 would be everything else – because if we can’t blame it on external sources (and maybe not even name the cause), there is a mistake in our system.

Now we could create subcategories. For example, category 1 could contain type mismatches, set mismatches, or out-of-bound errors. Category 2 could contain connection errors, protocoll errors, or payload parsing errors. Category 3 could contain runtime errors, database connection errors, resource limit errors. (By the way, errors where earlier input causes output errors should be considered an internal error, because it is not the current user’s fault that we have accepted faulty input in the first place.) But let’s stay with our 3 categories.

To create an own type of exception, we simply write a class that is derived from the base Exception class (or any other exception class). Our exception class doesn’t even need a body to be useful.

class ExternalException extends Exception
{
}

Now if we create a try-catch-block, we may specifically look out for this exception and ignore all others:

try
{
    $foo = getDataFromExternalService();
}
catch(ExternalException $e)
{
    printf("The external call failed: %s", $e->getMessage());
}

This code will only catch ExternalException exceptions and potential children. All other exceptions are ignored and need to be caught in another place. Looking at the error message, we see the benefit of the dedicated exception: The catch part knows what type of error there has been, and it can be handled in place.

There’s another benefit of different exception types: We can process the error within the exception itself, for example log internal errors to a file:

class InternalException extends Exception
{
    private $eNum = 0;
 
    public function __construct($msg, $code=0, $prev=null)
    {
        parent::__construct($msg, $code, $prev);
 
        $currentE = $this;
        $prevE = null;
 
        while ($currentE && $currentE != $prevE)
        {
            $this->logException($currentE);
            $prevE = $currentE;
            $currentE = $this->getPrevious();
        }
    }
 
    private function logException(Exception $e)
    {
        file_put_contents(
            'exceptions.log',
            sprintf("EXCEPTION HISTORY, %s: %s\n%s", ++$this->eNum, $e->getMessage(), $e->getTraceAsString()),
            FILE_APPEND);
    }
}

This way, we don’t have to disclose internal exceptions to the user – it’s not of any use for them anyway. Let’s simply log it and output a generic “sorry” message.

try
{
    // we assume that this goes well, otherwise it would throw an ExternalException
    getDataFromExternalService();
 
    // let's pretend the DB connection has failed
    throw new InternalException('DB connection failed: ');
}
catch (ExternalException $eExternal)
{
        printf("The external call failed: %s", $e->getMessage());
}
catch (InternalException $eInternal)
{
    // message is logged in InternalException, but no need to disclose details
    printf("Sorry, there has been an internal error. The administrators have been notified and will take care of this.");
}

As you certainly have guessed, the first catch is not executed, because it doesn’t match the exception type. The second catch will be executed, because there is an InternalException thrown in the try part.

The actual error with all details is logged inside our InternalException as declared above – but the user doesn’t need to, and will not, know about any of the details.

August 30th, 2012 at 3:03 pm

Faenza icons for CKEditor

After messing a bit with CKEditor’s link dialog yesterday, here’s a fresh icon theme for CKEditor’s toolbar. It’s based on the marvelous Faenza icon theme by Matthieu James.

I’ve replaced most of the original CKEditor toolbar icons, except the ones for table and form editing, because the Faenza icon theme doesn’t have any of these – not even remotely. I think most of the replacements are suitable to represent their meaning, although (e.g. in the case of the smiley icon), this is not the perfect solution.

Anyway, have a look at the fresh new CKEditor toolbar.

This is the full toolbar, here you can also see the non-“translated” icons (click for original size):

 

This is a reduced toolbar, which still covers most of CKEditor’s features and contains only Faenza icons:

 

This is a very reduced toolbar, also featuring a few CSS improvements:

 

If you want to have your CKEditor toolbar look like in one of the first pictures, simply download the following PNG file and save it as /path/to/ckeditor/skins/kama/icons.png.

As the Faenza icons as well as CKEditor are released under the GNU GPL, the icon file is also subject to that license. I do however not claim any credits, just make sure to respect the original author’s copyrights.

Please note: There’s one little thing you should change or add to your CSS: CKEditor sets an opacity of 0.7 for the toolbar icons. As the Faenza icons already are quite grey-ish, you should set the opacity to 1:

.cke_skin_kama .cke_button a,
.cke_skin_kama .cke_button a:hover,
.cke_skin_kama .cke_button a:focus,
.cke_skin_kama .cke_button a:active,
.cke_skin_kama .cke_button a.cke_off,
.cke_skin_kama .cke_toolgroup,
.cke_skin_kama .cke_rcombo a,
.cke_skin_kama .cke_rcombo a:active,
.cke_skin_kama .cke_rcombo a:hover          { opacity: 1 !important; }

Final note: This works nice with CKEditor 3.6.4 (the current one, at the time of writing this post), I haven’t tested other versions.

August 29th, 2012 at 10:39 am

Simplify CKEditor’s link dialog

CKEditor‘s original “insert link” dialog is certainly too much for most users. I mean, if you understand all the option it gives, you usually don’t need a WYSIWYG editor.

You don’t need to write an entirely new plugin to provide a lean alternative, it’s sufficient to hack a bit with CKEditor’s JavaScript API:

CKEDITOR.on('dialogDefinition', function(e) {
    var
        dd = e.data.definition, // NOTE: this is an instance of CKEDITOR.dialog.definitionObject, not CKEDITOR.dialog.definition
        tabInfo;
 
    if (e.data.name === 'link')
    {
        dd.removeContents('advanced');
        dd.removeContents('target');
 
        tabInfo = dd.getContents('info');
        tabInfo.remove('url');
        tabInfo.remove('linkType');
        tabInfo.remove('browse');
        tabInfo.remove('protocol');
 
        tabInfo.add({
            type : 'text',
            id : 'urlNew',
            label : 'URL',
            setup : function(data)
            {
                if (typeof(data.url) !== 'undefined')
                {
                    this.setValue(data.url.url);
                }
            },
            commit : function(data)
            {
                data.url = { url: this.getValue() };
            }
        });
 
        tabInfo.add({
            type : 'checkbox',
            id : 'newPage',
            label : 'Open link in a new page',
            commit : function(data)
            {
                if (this.getValue())
                {
                    data.target = '_blank';
                }
                return data;
            }
        });
    }
});

Here’s what it looks like, along with some other enhancements (which I’m going to explain in another post):