Thursday, 30 May 2013


Pairwise an array in Javascript


function pairwise(arr) {
    return arr.map(function (item, index, _arr) {
        return _arr.map(function (_item) {
            if (item != _item) {
                return [item, _item];
            }
        }).filter(Boolean);
    });
}

an example:


pairwise(["Cat","Dog","Bird"]);
# outputs: 
array(3): {
   [0]:  array(2): {
      [0]:  array(2): {
         [0]:  string(3): "Cat"
         [1]:  string(3): "Dog"
      }
      [1]:  array(2): {
         [0]:  string(3): "Cat"
         [1]:  string(4): "Bird"
      }
   }
   [1]:  array(2): {
      [0]:  array(2): {
         [0]:  string(3): "Dog"
         [1]:  string(3): "Cat"
      }
      [1]:  array(2): {
         [0]:  string(3): "Dog"
         [1]:  string(4): "Bird"
      }
   }
   [2]:  array(2): {
      [0]:  array(2): {
         [0]:  string(4): "Bird"
         [1]:  string(3): "Cat"
      }
      [1]:  array(2): {
         [0]:  string(4): "Bird"
         [1]:  string(3): "Dog"
      }
   }
}

Friday, 10 May 2013

The return of preloading images!

Normally I'm not a big fan of preloading images. I feel if your site is well designed, waiting for a few images shouldn't effect the overall user experience.
When and if you do need images preloaded you should just handle them on a case-by-case bases in JavaScript with something like this:

var image = new Image();
image.onload = function() { container.appendChild(image); };
image.src = 'mysrc.png';
Now the user does not have to watch the image load up in the background of your page.
What if you have many images to load for say, a canvas application. This can become very tedious and a lot of code. My solution was just to write a simple ( and small ) preloader that allowed comprehensive callbacks as well as a managed list of images for me to work with. Here is my result:

function preload(list, callback, imageCallback ) {
    var at = len = list.length;
    return list = list.map(function (item) {
        var pItem = new Image();
        pItem.onload = function (i) {
            imageCallback && imageCallback.call(this, this, len-at, len);
            if (!--at) {
                callback(list);
            }
        };
        pItem.src = item;
        return pItem;
    });
}

Example usage:  

var list = preload(["1.png","2.png","3.png" ... ], function complete(list) {
   console.log('images all loaded!');
}, function loaded(image, index, listCount) {
   console.log('image ' + index + ' of + 'listCount is loaded');
});


Download the code here: https://gist.github.com/rlemon/5556905

Monday, 7 January 2013

Seizure.js - a Colourful bookmarklet.

A while ago a few associates and myself were throwing around little garbage scripts joking with some 'not malicious but malicious' client side js. One of the scripts ( I called seizure.js ) interested @loktar00 enough for him to make a bookmarklet out of it and post it on his blog: Rainbow bright bookmarklet.

His script is changed a bit, and takes away from the original 'effect' a bit in my opinion so here is the original on all of it's twitchy glory.


/* Changes background and foreground colours  for all elements on the page */
function r() {
    return Math.floor(Math.random() * 255);
}
 
function lemon() {
    with(this.style) {
        color = ['rgb(', [r(), r(), r()].join(','), ')'].join('');
        backgroundColor = ['rgb(', [r(), r(), r()].join(','), ')'].join('');
    }
}
 
function rocks() {
    Array.prototype.forEach.call(document.all, function(item) {
        setTimeout(function() {
            lemon.call(item);
        }, Math.random() * 100 + 100);
    });
    setTimeout(rocks, Math.random() * 500 + 100);
}
 
rocks();

I have setup a small demo page on codepen.io or you can install the bookmarklet by dragging the link below into your bookmarks bar:
Seizure.js

You can browser some more of the fun snippets I came up with as well as this one on github: https://gist.github.com/4444273


Friday, 4 January 2013

So I went ahead and wrote you a plugin.

If you know me at all you will know that I don't often suggest or use third party libraries for Javascript. Not because I think i'm too good for them or anything, I just enjoy understanding my own code and being able to debug with some degree of certainty.
With this said; I created a very simple plugin that provides the 'Return to Top' buttons you see on so many pages. Introducing: mcToppy.jquery.js (If you can think of a better name, by all means tell me!).

$.mcToppy function(options{
    var btn $('<button></button>'),
        defaults {
            css{
                position'fixed',
                bottom'16px',
                right'16px',
                backgroundColor'#FFF',
                color'#444',
                padding'4px 6px',
                borderRadius'4px',
                display'none'
            },
            text'Top',
            speed500,
            callbackundefined
        };
    options options || {};
    options $.extend({}defaultsoptions);
    btn.css(options.css).text(options.text).on('click'handle_click).appendTo('body');
    $(window).on('scroll'handle_scroll);

    function handle_scroll({
        if ($(this).scrollTop(!= 0{
            btn.fadeIn('fast');
            return;
        }
        btn.fadeOut('fast');
    }


    function handle_click({
        $('html,body').animate({
            scrollTop0
        }options.speed).promise().done(options.callback);
    }


};
$.mcToppy();

The plugin is self explanatory for the most part (I hope), but let me try to walk you through how to write this and why:
The Plugin: There are two basic forms of a jQuery plugin. One actions on the elements returned from the selector, the second is just a method attached to the $ namespace. Because we are not associating this with an HTML Element on the page we will choose the latter and attach directly to the jQuery ($) namespace.

$.mcToppy function(options{

The Button: There needs to be an element for the user to click. For this script I choose to use a button. For ease of use create this by passing the button as an HTML string to the jQuery selector. The library will return a jQuery object containing the HTML Element for the button.

var btn $('<button></button>')

The Defaults: We like customization right? Well there needs to be some defaults to customize! Here they are defined in a semantic way. The CSS is defined in it's own object which can later be directly passed to the .css() jQuery function. The text, speed, and callbacks all are for exactly what their name implies: Text is the button text, speed determines the time taken to return to the top, and the callback is invoked after the script has completed (you are at the top of the page).

defaults {
    css{
        position'fixed',
        bottom'16px',
        right'16px',
        backgroundColor'#FFF',
        color'#444',
        padding'4px 6px',
        borderRadius'4px',
        display'none'
    },
    text'Top',
    speed500,
    callbackundefined
};

Extending the defaults and building the button: Merging the options and the defaults is important. This allows the user to set up some but not all of the options and still fall back on the defaults provided. To accomplish this use the jQuery.extend() function. Pass in an empty object, then the defaults, then the options. The options will over write the defaults where applicable then the entire thing will be pushed to a new object (first argument) and returned. After that the options need to be applied to the button and the button needs to be appended to the body.

options options || {}; // if nothing is passed in
options $.extend({}defaultsoptions);
btn.css(options.css).text(options.text).on('click'handle_click).appendTo('body');

Handling the scroll and click events: Using the .on() method listen for 'scroll' on the window object. When the user scrolls check to see if they are at the top or not and action accordingly. When the user clicks on the button we want the page to scroll back upto the top. Using .animate() here will allow this scroll to be seen over a time delay and not just 'jump' back to the top. Like mentioned above we need to wait for both animations to complete before calling the callback function. To achieve this we use jQuery's .promise().

$(window).on('scroll'handle_scroll);
function handle_scroll({
    if ($(this).scrollTop(!= 0{
        btn.fadeIn('fast');
        return;
    }
    btn.fadeOut('fast');
}


function handle_click({
    $('html,body').animate({
        scrollTop0
    }options.speed).promise().done(options.callback);
}


And there you have it! Want to see a demo? Click on the 'Result' tab and scroll down a bit.


You can Fork or download the source code for the plugin from https://gist.github.com/4453414
Enjoy!