Showing posts with label jQuery. Show all posts
Showing posts with label jQuery. Show all posts

Saturday, August 23, 2014

Making GalleryView items clickable with FancyBox

I am currently making use of the GalleryView jQuery plugin which feels great but it lacks a functionality that I needed: clicking on the images to show them in a modal dialog.

I therefore integrated a separate plugin called FancyBox that handles modal functionality beautifully.

To do this, I first did a minor change to jquery.galleryview.js, where I added the following underneath var img = $('<img />');:
img.attr('class', 'clickable');
img.attr('alt', gvImage.attrs.title);

This is so that I can access the images in the GalleryView image gallery whenever an image is clicked, and I reference them with a class clickable. I also fetch the description of the image and store it in the alt tag.

Then I simply hook to those images and open fancy box with the current image that's displayed on the slideshow:
$('.clickable').live('click', function(e){ 
    var img = $(this);
    var imgSrc = img.attr('src');
    var imgDesc = img.attr('alt');
    
    $.fancybox.open([ { href : imgSrc, title : imgDesc } ], { padding : 0 });
});

And here's a demo.

Sunday, September 23, 2012

Webroulette: Take me somewhere random!

So once again, what follows is the result of a weekend-project-during-the-week kind of thing.

Similar to chatroulette.com where you shuffle through random people, I wrote this so that you can shuffle through random websites instead:


You can also specify a single word to be used as a form of bias:


You can see it in action here: http://dreasgrech.com/upload/webroulette/.

Source code

As usual, the source for this project resides on github.

How it's done

In a nutshell, I basically do a Google Custom Search API call with a randomly constructed query and then show the first result from the collection of hits.

The server
On the server, I have a file of ~8.5k commonly used English words, and based on the length query string value, I select a number of these words in a random manner.

Note that I enforce a hard limit on the range for the allowed values of length; currently, the range is [0, 10]. If no length is specified, I default it to 3.

This is the word-list that I'm currently using is at http://dreasgrech.com/upload/webroulette/komuni.txt

If a bias is specified, I use it as the first word in the phrase and once this phrase is built, it's echoed so that it can be read by the client.

Here are some examples of the script in action:

http://dreasgrech.com/upload/webroulette/louie.php
http://dreasgrech.com/upload/webroulette/louie.php?bias=obfuscation
http://dreasgrech.com/upload/webroulette/louie.php?bias=douglasadams&length=6

The client
So what the client does is an Ajax call to this PHP script to get the query and then do an Ajax call to the Google Custom Search API to get a list of hits. Btw, I'm also using a query string which I termed iesux which I use for a unix timestamp, and I had to do this because calls to the same url were being cached by Internet Explorer and so I needed this timestamp to introduce variety to the urls.

What I then show on screen is the first result from the list of google hits from that query.

Why not embed an I'm Feeling Lucky link in the iframe?
Halfway during the project, I realized that this functionality is pretty similar to the I'm Feeling Lucky functionality that Google still offers (for some reason?).

I figured that this way, I would eliminate the need to use the API (which, btw, has a 100 queries a day limit) but instead use an I'm Feeling Lucky url (like http://www.google.com/search?&btnI=745&q=obfuscation) for the source of the iframe.

But after I tried a couple of queries like this, I realized that sometimes, an I'm Feeling Lucky url redirects to an actual Google Search page and since Google prevents their site to be rendered in an <iframe>, I was getting a lot of blank pages in the <iframe>...and that sucks.

What about the 100 query limit?
For the free offering of the Google Custom Search API, Google enforces a 100 queries per day (per project) limit.

To work around this, I created five projects (i.e. 5 API keys) and whenever someone loads the page, I serve one of the five keys at random. If it turns out that that particular key is used up, the client requests another API key.

You can also specify your own API key (make sure your that the the Custom Search API service is turned on) using the key query string, as follows:

http://dreasgrech.com/upload/webroulette/?key=AIzaSyCCv2V9wF1cO1uck19H5uuAodJ-Ml0rBgg

Thursday, January 26, 2012

Promoting your Chrome extension with a yellow infobar

This is a jQuery plugin I wrote which emulates Chrome's infobar for promoting a Google Chrome extension.

The following are Chrome's infobar and the one I wrote for the plugin, respectively:

Demo

I've set up a small demo of the plugin here: http://www.dreasgrech.com/upload/extinfobar/.

Download

Until the jQuery plugins page is restored, you're gonna have to download this plugin directly from github.

The plugin can be found at the jQuery plugins site: http://plugins.jquery.com/extinfobar/

You can get the full source of the plugin from https://github.com/dreasgrech/ChromeExtInfoBar

These are all the images that you need:






Usage

The simplest way to use the plugin is to simply invoke it using just your Chrome extension ID:
$.fn.extInfobar({
    id: 'nbilgjjflfiiijecdjpnbganoiafneph'
});

You can also specify a custom message to be displayed on the infobar, as opposed to the default message:
$.fn.extInfobar({
    id: 'nbilgjjflfiiijecdjpnbganoiafneph',
    message: 'This is my custom message I want to show on the infobar'
});

There are three other optional parameters you can pass; redirectIfInstallFails, rememberClose and rememberRedirect. All three default to true if unspecified.
$.fn.extInfobar({
    id: 'nbilgjjflfiiijecdjpnbganoiafneph',
    message: 'This is my custom message I want to show on the infobar',
    redirectIfInstallFails: false,
    rememberClose: false,
    rememberRedirect: false
});

redirectIfInstallFails specifies whether the plugin should redirect the user to the extension's Chrome Webstore page if the installation happens to fail or if the site you're using the plugin on is not verified (more info on that below).

When the user clicks on the close button, the action is remembered via localStorage so that the bar is not displayed again for him but the rememberClose parameter allows you to override this functionality; so if you set it to false, the bar will keep appearing on subsequent page visits even if the user closed it.

The last parameter, rememberRedirect, is used to save the action of the plugin redirecting the user to the extension's Chrome Webstore; by default, the action is saved which means that once a user is redirected to the Chrome Webstore page, the bar will not be shown to him on subsequent visits to your page, but you can of course override this functionality by setting rememberRedirect to false.

How it works

The plugin makes use of Chrome's inline installation functionality, but note that this only works if your extension's website is verified and this plugin is invoked from the same domain as the verified site.

When you click on the 'Install' button on the infobar, and the context meets the two aforementioned criteria, the following modal dialog will pop up:


Otherwise, the user will be redirected directly to the extension's page on the Chrome Webstore (unless the redirectIfInstallFails option is explicitly set to false).


Wednesday, February 3, 2010

Scrolling page title with JavaScript and jQuery

The following is a jQuery function I wrote that allows you to make a scrolling page title.

I admit...it's a pretty useless "feature" but I just made it to kill some time =D

Usage

The simplest usage is as follows:

$.marqueeTitle();

The above snippet will use your existing title text to scroll.

You can also pass in an object with options to alter the script's behavior. The options are the following:
  • text - Use this parameter to set custom text if you don't want the scrolling text to be taken from the title
  • dir - "left" or "right"; by default, it's set to "left"
  • speed - The time it takes, in ms, for one character rotation

Here's another example, now demonstrating the parameters:

$.marqueeTitle({
  text: "This my custom text",
  dir: "right",
  speed: 500
});

Source

(function ($) {
    var shift = {
        "left": function (a) {
            a.push(a.shift());
        },
        "right": function (a) {
            a.unshift(a.pop());
        }
    };
    $.marqueeTitle = function (options) {
        var opts = $.extend({},
        {
            text: "",
            dir: "left",
            speed: 200
        }, options),
            t = (opts.text || document.title).split("");
        if (!t) {
            return;
        }
        t.push(" ");
        setInterval(function () {
            var f = shift[opts.dir];
            if (f) {
                f(t);
                document.title = t.join("");
            }
        }, opts.speed);
    };
}(jQuery));

Thursday, December 31, 2009

Identifying from where JavaScript libraries invoke your callback functions, with Firebug

There comes a time where one would need to dig beyond the abstractions to see what is really going on under the covers.

Say for example you wanted to see how a certain library computes parameters for your callback, how would you do it? Scanning the library and figuring out the logic step by step is one way you can do it, but that is very time consuming and with complex libraries such as jQuery, it's nearly impossible to exactly pinpoint from where your callback function is being invoked.

In this post we will see how we can use Firebug to pinpoint exactly from where your callback functions are called in the abstraction.

A simple library

Let's take an example with a very small hypothetical "library" example:

var alibrary = (function () {
    var callback, 
    privatefun = function (p) {
        callback(p);
    }; 

    return {
        setCallback: function (fn) {
            callback = fn;
        },
        doIt: function () {
            var params = ['some', 'parameters', 22 + 20];
            privatefun(params);
        }
   };
}());

This 'library' offers 2 public functions; setCallback, which takes a function and stores it into the callback parameter and the doIt function that invokes the function that was stored previously.

Here's how this library can be used:

alibrary.setCallback(function (p) {
    console.log(p);
});

alibrary.doIt();


When the doIt function is called, the callback function that was passed previously will be invoked, passing in some parameters from behind. The library is passing an array as a parameter and the third element of that array is a computation of 22 + 20.

Now, as users of the library, we want to check how that 42 is computed from our callback function; and we will do this with Mozilla Firefox's best friend, Firebug

Tracing the steps

Open your Firebug (F12) and head onto the Script tab and choose the script from where you are defining your callback function. Then find your function and put a breakpoint in the function:



To set a breakpoint, click next to the line number in the and a red dot will appear.

The next step is to perform the action that will invoke your callback, and in my case this 'action' is a page refresh.

So now after my page refresh, the library will invoke my callback and the breakpoint will be hit:



When the breakpoint is hit, the line will be highlighted in yellow.

Now comes the part where we trace the steps back to where the callback was invoked. If you look closely to the upper part of the Script tab, you will see the following:



From there, you can now trace the path to where the function was invoked! Now let's click on the first step, privatefun().




Upon clicking, Firebug takes you directly to that function, privatefun, and now from this function we can see how our callback function was invoked:



Now although we can see from there the function was invoked, we still don't know from where that 42 is coming from, and so we must check which function invoked privatefun and to do that, we move a step back through the invocation line, the doIt() step:





From here, we can now see how that 42 was being computed because we have finally arrived to the step we wanted to.



Now obviously this technique isn't that much useful for this example because the code of this 'library' is so small that it doesn't require backtracking of the function calls, but it can be used very effectively on much larger libraries to quickly identify how certain parameters are being computed and sent to your functions, amongst other uses.


Tuesday, December 22, 2009

jsLaTeX: A jQuery plugin to directly embed LaTeX into your website or blog



jsLaTeX is the latest plugin I developed for jQuery and I wrote it so that I could easily be able to embed LaTeX directly into my blog but anyone can use it for their site.

You can download the normal, unpacked version for development or the packed version for production.

Click here to view a demo

Here is a link to the jQuery plugin page, where you can find all the releases.

Usage Instructions


1. Download the jquery.jslatex.js file from one of the above-mentioned links and add it to your page along with jQuery (if it is not already added):

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script src="jquery.jslatex.js"></script>


2. The simplest way to invoke the script is by calling the plugin with no parameters:

<script>
$(function () {
    $(".latex").latex();
});
</script>
<div class="latex">
    \int_{0}^{\pi}\frac{x^{4}\left(1-x\right)^{4}}{1+x^{2}}dx =\frac{22}{7}-\pi
</div>

The above will render the following:


\int_{0}^{\pi}\frac{x^{4}\left(1-x\right)^{4}}{1+x^{2}}dx =\frac{22}{7}-\pi


The plugin works by taking the inner HTML of the specified container obviously assuming that it is valid LaTeX, and displays the image using CodeCogs LaTeX engine. The rendered output replaces the equation inside the container.



The plugin also accepts 3 optional parameters:
  • format
  • url
  • callback

[format]
The format parameter is used to specify the format of the returned output. There are currently 3 supported formats:
  • gif
  • png
  • swf

[url]
The url parameter is used to change the engine of the LaTeX generator. Let's take an example with a different engine, and in this case I will be using SITMO's LaTeX engine.
The url SITMO's engine uses to render the output is as follows:

http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq=equation


where equation is the the LaTeX equation you wish to render.

Now we must tell the plugin where to put the equation and we do this by using the {e} specifier. This is how it can be used:

$(".latex").latex({url: 'http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq={e}'});

As you can see from the above example, we placed the {e} specifier where the equation should be and then the engine takes care of the rest.

Here is an example of using the new engine to render the output:


\int_{0}^{\pi}\frac{x^{4}\left(1-x\right)^{4}}{1+x^{2}}dx =\frac{22}{7}-\pi


The plugin currently supports another specifier: {f} and this is used for those engines that allow you to specify a file-format output. The file-types that are currently supported are the ones mentioned in the [format] section.

If we take the 'original' engine url, we can turn into a url with specifiers like such:

http://latex.codecogs.com/{f}.latex?{e}


Here are examples of Engines you can use (ready with specifiers):


Engines
http://latex.codecogs.com/{f}.latex?{e}
http://www.sitmo.com/gg/latex/latex2png.2.php?z=100&eq={e}
http://www.forkosh.dreamhost.com/mathtex.cgi?{e}
http://chart.apis.google.com/chart?cht=tx&chl={e}


[callback]
The callback parameter allows you to pass a function that will be executed after the image has been retrieved. In your callback function, this will refer to the newly created element (as a jQuery object) that contains the rendered output.

The following example will set a border around your rendered output.

$(".latex").latex({
    callback : function() {
        this.css({ border: '1px solid black'});
    }                        
});

With the above callback, we can now render the following:


\int_{0}^{\pi}\frac{x^{4}\left(1-x\right)^{4}}{1+x^{2}}dx =\frac{22}{7}-\pi



Sunday, December 20, 2009

Centering a container on screen with JavaScript (jQuery plugin)

Recently I needed a way to center an image on screen for a 'Coming Soon' kind of page, and so I wrote this jQuery plugin that does in fact this.

You can download the normal, unpacked version for development or the packed version for production.

Click here to view a demo

The container needs to have a preset width and height for this to work


Here is the unpacked code:

/*
 * CenterScreen v1.1 - jQuery plugin
 * 
 *  Copyright (c) 2009 - 2010 Andreas Grech
 *
 *  Dual licensed under the MIT and GPL licenses:
 *    http://www.opensource.org/licenses/mit-license.php
 *    http://www.gnu.org/licenses/gpl.html
 *
 * http://blog.dreasgrech.com
 */

(function ($) {
    $.fn.centerScreen = function () {
        return this.each(function () {
            var $this = $(this),
                $window = $(window),
                center = function () {
                    var winWidth = $window.width(),
                        winHeight = $window.height();
                    $this.css({
                        position: 'absolute',
                        left: ((winWidth / 2) - ($this.outerWidth() / 2)),
                        top: ((winHeight / 2) - ($this.outerHeight() / 2))
                    });
                };
            $window.resize(center);
            center();
        });
    };
}(jQuery));

Tuesday, November 24, 2009

'What I was listening to' box in my posts

I recently implemented a 'system' in where I show one or more songs I was listening to whilst writing a blog post, in this form:



To do that, I wrote a small script:

var blogmusic = function () {
    var lastContainerDone = 0;
    return function (music) {
        var musiccount = music.length,
            blogmusic = $(".blogmusic").eq(lastContainerDone++),
            header = $("<div/>").addClass("header");
        header.append("<center>What I was listening to</center>");
        var musiclist = $("<div/>").addClass("musiclist");
        for (var i = 0; i & lt; musiccount; i += 1) {
            var song = music[i];
            var listing = $("<div/>").addClass("listing");
            var songname = $("<span/>").addClass("songname").html('<a href="' + (song.link || '#') + '" target="_blank">"' + song.name + '"</a>');
            var artist = $("<span/>").addClass("artist").html('- ' + song.artist);
            listing.append(songname);
            listing.append(artist);
            musiclist.append(listing);
        }
        blogmusic.html(header);
        blogmusic.append(musiclist);
    };
} ();

And I invoke the script in my blog posts like such:

<div class="blogmusic">
<script>
blogmusic([
{ 
    artist : 'Jerry Lee Lewis',
    name : 'Whole Lotta Shakin\'',
    link : 'http://listen.grooveshark.com/#/song/Whole_Lotta_Shakin/6325468'
}
]);
</script>
</div>

Sunday, November 15, 2009

ShowSlow - A jQuery plugin for displaying elements in order, one by one with a delay

Recently I needed the functionality for displaying some hidden divs, in order, one by one, and with a timed-delay between each one.

Thus I wrote this jQuery plugin that does infact this (demo):

/*
 * ShowSlow v1.1 - jQuery plugin
 * 
 *  Copyright (c) 2009-2010 Andreas Grech
 *
 *  Dual licensed under the MIT and GPL licenses:
 *    http://www.opensource.org/licenses/mit-license.php
 *    http://www.gnu.org/licenses/gpl.html
 *
 * http://blog.dreasgrech.com
 */

(function($) {
    $.fn.showSlow = function(options) {
        var opts = $.extend({}, $.fn.showSlow.defaults, options),
        elementCounter = 0,
        $elements = this,
        isStopped = 0,
        isPaused = 0,
        callbackExecuted = 0,
        executeCallback = function(val) {
            if (typeof opts.callback == "function") {
                callbackExecuted = 1;
                opts.callback(getValues());
            }
        },
        getValues = function() {
            return {
                elementsDone: elementCounter
            };
        },
        showNextDiv = function($element) {
            if (isPaused || isStopped) {
                return;
            }
            if (!$element.length) {
                executeCallback();
                return;
            }
            $element.slideDown(opts.slideTime, function() {
                setTimeout(function() {
                    showNextDiv($elements.eq(elementCounter++));
                },
                opts.displayTime);
            });
        };

        return {
            start: function() {
                if (isStopped || elementCounter < $elements.length) {
                    $elements.css("display", "none");
                    elementCounter = 0;
                } else if (isPaused) {
                    elementCounter -= 1;
                }
                isStopped = 0;
                isPaused = 0;
                callbackExecuted = 0;
                showNextDiv($elements.eq(elementCounter++));
            },
            stop: function() {
                isStopped = 1;
                if (!callbackExecuted) {
                    executeCallback();
                }
                return elementCounter; //return the number of elements displayed before stopped
            },
            pause: function() {
                isPaused = 1;
            }
        };
    };

    $.fn.showSlow.defaults = {
        slideTime: 1000,
        displayTime: 500
    };
})(jQuery);