Make Your Own Bookmarklets With jQuery

Smashing-magazine-advertisement in Make Your Own Bookmarklets With jQuery
 in Make Your Own Bookmarklets With jQuery  in Make Your Own Bookmarklets With jQuery  in Make Your Own Bookmarklets With jQuery

Bookmarklets are small JavaScript-powered applications in link form. Often “one-click” tools and functions, they’re typically used to extend the functionality of the browser and to interact with Web services. They can do things like post to your WordPress or Tumblr blog, submit any selected text to Google Search, or modify a current page’s CSS… and many other things!

Because they run on JavaScript (a client-side programming language), bookmarklets (sometimes called “favelets”) are supported by all major browsers on all platforms, without any additional plug-ins or software needed. In most instances, the user can just drag the bookmarklet link to their toolbar, and that’s it!

Makeyourownbookmarklets in Make Your Own Bookmarklets With jQuery

In this article, we’ll go through how to make your own bookmarklets, using the jQuery JavaScript framework.

[By the way: The network tab (on the top of the page) is updated several times a day. It features selected articles from the best web design blogs!]

Getting Started

You can make a faux URI with JavaScript by prefacing the code with javascript:, like so:

<a href="javascript: alert('Arbitrary JS code!');">Alert!</a>

Notice that when we put it in the href attribute, we replace what would normally be double quotes (") with single quotes ('), so that the href attribute’s value and JavaScript function don’t get cut off midway. This is not the only way to circumvent the problem, but it’ll do for now.

We can take this concept as far as we want, adding multiple lines of JavaScript inside these quotation marks, with each line separated by a semicolon (;), sans line break. If your bookmarklet won’t need to be updated later, this method of “all inclusiveness” is probably fine. For this tutorial, we’ll externalize the JavaScript code and store it in a .js file, which we’ll host somewhere else.

Here is what a link to an externalized bookmarklet looks like:

<a href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://foo.bar/baz.js';})();">Externalized Bookmarklet</a>

This link looks for the document’s body and appends a <script> element to it, with a src that we’ve defined—in this case, http://foo.bar/baz.js. Keep in mind that if the user is on an empty tab or a place that for some reason has no body, nothing will happen because there is nothing to append to.

You can host the .js file wherever is convenient, but keep bandwidth in mind if you expect a ton of traffic.

Enter jQuery

Because many of you will be familiar with the jQuery framework, we’ll use it to build our bookmarklet.

The easiest way to get it inside our .js file is to append Google’s CDN, but with a bit of extra logic:

if (typeof jQuery == 'undefined') {
	var jQ = document.createElement('script');
	jQ.type = 'text/javascript';
	jQ.onload=runthis;
	jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
	document.body.appendChild(jQ);
} else {
	runthis();
}

function runthis() {
	// your JavaScript code goes here!
}

Clean and simple. This first checks to see whether jQuery is already loaded, because many pages you visit might already use it, and we don’t want to be redundant. If it’s not already loaded, we bring it in from Google and set the function runthis() to run when it is done loading. If jQuery has already loaded, we skip straight to runthis().

Grabbing Information

Depending on the kind of bookmarklet you’re making, it might be worthwhile to grab information from the current page. The two most important things are document.location, which returns the page’s URL, and document.title, which returns the page’s title.

You could also return any text that the user may have selected, but that’s a little more complicated:

function getSelText() {
	var SelText = '';
	if (window.getSelection) {
		SelText = window.getSelection();
	} else if (document.getSelection) {
		SelText = document.getSelection();
	} else if (document.selection) {
		SelText = document.selection.createRange().text;
	}
	return SelText;
}

(Modified from JavaScript Get Selected.)

Without going into too much detail, this code first defines an empty SelText variable, and then uses a couple of different functions to try to fill it with any selected text or content, with each method specific to certain browsers. Not as simple or as clean as we might like, but it’s functional.

Another option is to use JavaScript’s input function to query the user with a pop-up:

var yourname = prompt("What's your name?", "my name...");

Character Encoding

If you’ll be putting all of your JavaScript in the link itself rather than in an external file, you might want a better way to nest double quotation marks (as in, “a quote ‘within a quote’”), rather than demoting them to single quotation marks. Use &quot; in their place (as in, “a quote &quot;within a quote&quot;“):

<a
href="javascript:var%20yourname=prompt(&quot;What%20is%20your%20name?&quot;);alert%20(&quot;Hello,%20"+yourname+"!&quot;)">What is your name?</a>

In this example, we have encoded the spaces as %20, which might benefit older browsers or ensure that the link doesn’t fall apart in transit somewhere.

In JavaScript, you might sometimes need to escape quotes. You can do so by prefacing them with a backslash (\):

alert("This is a \"quote\" within a quote.");

Putting It All Together

Just for fun, let’s make a little bookmarklet that checks whether a word is selected on the page and, if one is, searches Wikipedia and shows the results in a jQuery-animated iFrame.

Wikiframe in Make Your Own Bookmarklets With jQuery

We’ll start by combining the framework from “Enter jQuery” with the text selection function from “Grabbing Information”:

if (typeof jQuery == 'undefined') {
	var jQ = document.createElement('script');
	jQ.type = 'text/javascript';
	jQ.onload=runthis;
	jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
	document.body.appendChild(jQ);
} else {
	runthis();
}

function runthis() {
	// your JavaScript code goes here!
}

function getSelText() {
	var s = '';
	if (window.getSelection) {
		s = window.getSelection();
	} else if (document.getSelection) {
		s = document.getSelection();
	} else if (document.selection) {
		s = document.selection.createRange().text;
	}
	return s;
}

Next, we’ll look for any selected text and save it to a variable, “s.” If nothing is selected, we’ll try to prompt the user for something:

var s = "";
s = getSelText();
if (s == "") {
	var s = prompt("Forget something?");
}

After checking that we’ve actually received a value for “s,” we’ll append the new content to the document’s body. In it will be the following: a container DIV (wikiframe), a background veil (wikiframe_veil) and a “Loading…” paragraph, the iFrame itself and some CSS to make things look pretty and to affix everything over top the page.

if ((s != "") && (s != null)) {
	$("body").append("\
	<div id='wikiframe'>\
		<div id='wikiframe_veil' style=''>\
			<p>Loading...</p>\
		</div>\
		<iframe src='http://en.wikipedia.org/w/index.php?&search="+s+"' onload=\"$('#wikiframe iframe').slideDown(500);\">Enable iFrames.</iframe>\
		<style type='text/css'>\
			#wikiframe_veil { display: none; position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: rgba(255,255,255,.25); cursor: pointer; z-index: 900; }\
			#wikiframe_veil p { color: black; font: normal normal bold 20px/20px Helvetica, sans-serif; position: absolute; top: 50%; left: 50%; width: 10em; margin: -10px auto 0 -5em; text-align: center; }\
			#wikiframe iframe { display: none; position: fixed; top: 10%; left: 10%; width: 80%; height: 80%; z-index: 999; border: 10px solid rgba(0,0,0,.5); margin: -5px 0 0 -5px; }\
		</style>\
	</div>");
	$("#wikiframe_veil").fadeIn(750);
}

We set the iFrame’s src attribute to Wikipedia’s search URL, plus “s.” Its CSS sets it to display: none; by default, so we can give it a grander entrance when the page is loaded via its onload attribute and a jQuery animation.

After all this is added to the page, we’ll fade in the background veil.

Notice the backslashes at the end of each line of appended HTML. These allow for multiple rows and make everything easier on the eyes for editing.

Almost done. But we need to make sure that these elements don’t already exist before appending them. We can accomplish this by throwing the above code into a ($("#wikiframe").length == 0) conditional statement, accompanied by some code to remove it all if the statement returns negative.

The resulting .js file:

if (typeof jQuery == 'undefined') {
	// http://www.hunlock.com/blogs/Howto_Dynamically_Insert_Javascript_And_CSS
	var jQ = document.createElement('script');
	jQ.type = 'text/javascript';
	jQ.onload=runthis;
	jQ.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
	document.body.appendChild(jQ);
} else {
	runthis();
}

function runthis() {
	if ($("#wikiframe").length == 0) {
		var s = "";
		s = getSelText();
		if (s == "") {
			var s = prompt("Forget something?");
		}
		if ((s != "") && (s != null)) {
			$("body").append("\
			<div id='wikiframe'>\
				<div id='wikiframe_veil' style=''>\
					<p>Loading...</p>\
				</div>\
				<iframe src='http://en.wikipedia.org/w/index.php?&search="+s+"' onload=\"$('#wikiframe iframe').slideDown(500);\">Enable iFrames.</iframe>\
				<style type='text/css'>\
					#wikiframe_veil { display: none; position: fixed; width: 100%; height: 100%; top: 0; left: 0; background-color: rgba(255,255,255,.25); cursor: pointer; z-index: 900; }\
					#wikiframe_veil p { color: black; font: normal normal bold 20px/20px Helvetica, sans-serif; position: absolute; top: 50%; left: 50%; width: 10em; margin: -10px auto 0 -5em; text-align: center; }\
					#wikiframe iframe { display: none; position: fixed; top: 10%; left: 10%; width: 80%; height: 80%; z-index: 999; border: 10px solid rgba(0,0,0,.5); margin: -5px 0 0 -5px; }\
				</style>\
			</div>");
			$("#wikiframe_veil").fadeIn(750);
		}
	} else {
		$("#wikiframe_veil").fadeOut(750);
		$("#wikiframe iframe").slideUp(500);
		setTimeout("$('#wikiframe').remove()", 750);
	}
	$("#wikiframe_veil").click(function(event){
		$("#wikiframe_veil").fadeOut(750);
		$("#wikiframe iframe").slideUp(500);
		setTimeout("$('#wikiframe').remove()", 750);
	});
}

function getSelText() {
	var s = '';
	if (window.getSelection) {
		s = window.getSelection();
	} else if (document.getSelection) {
		s = document.getSelection();
	} else if (document.selection) {
		s = document.selection.createRange().text;
	}
	return s;
}

Note that we fade out and remove the wikiframe content if the user re-clicks the bookmarklet after it has loaded and if the user clicks on its background veil.

Here is the HTML bookmarklet to load that script:

<a href="javascript:(function(){document.body.appendChild(document.createElement('script')).src='http://iamnotagoodartist.com/stuff/wikiframe.js';})();">WikiFrame</a>

WikiFrame

And there you have it. A working example of what you can do with a bookmarklet and jQuery!

Make It Better

This example was fun, but it definitely could be better.

For starters, it isn’t compressed. If your script will be accessed a lot, keeping two versions of your code may be a good idea: one normal working version and one compressed minimized version. Serving the compressed one to your users will save loading time for them and bandwidth for you. Check the resource links below for some good JavaScript compressors.

While the bookmarklet technically works in IE6, its use of static positioning means that it just kind of appends itself to the bottom of the page. Not very user-friendly! With some more time and attention to rendering differences in IE, the bookmarklet could be made to function and look the same (or at least comparable) in different browsers.

In our example, we used jQuery, which is an excellent tool for developing more advanced JavaScript applications. But if your bookmarklet is simple and doesn’t require a lot of CSS manipulation or animation, chances are you may not need something so advanced. Plain old JavaScript might suffice. Remember, the less you force the user to load, the faster their experience and the happier they will be.

Bookmarklets in Make Your Own Bookmarklets With jQuery

Things to Keep in Mind and Best Practices

Untested code is broken code, as old-school programmers will tell you. While bookmarklets will run on any browser that supports JavaScript, testing them in as many browsers as you can wouldn’t hurt. Especially when working with CSS, a whole slew of variables can affect the way your script works. At the very least, enlist your friends and family to test the bookmarklet on their computers and their browsers.

Speaking of CSS, remember that any content you add to a page will be affected by that page’s CSS. So, applying a reset to your elements to override any potentially inherited margins, paddings or font stylings would be wise.

Because bookmarklets are, by definition, extraneous, many of the guidelines for JavaScript—such as unobtrusiveness and graceful degradation—aren’t as sacred as they normally are. For the most part, though, a healthy understanding of best practices for traditional JavaScript and its frameworks will only help you:

  • Develop a coding style and stick to it. Keep it consistent, and keep it neat.
  • Take it easy on the browser. Don’t run processes that you don’t need, and don’t create unnecessary global variables.
  • Use comments where appropriate. They make jumping back into the code later on much easier.
  • Avoid shorthand JavaScript. Use plenty of semi-colons, even when your browser would let you get away without them.

Further Resources

Helpful JavaScript Tools

JavaScript and CSS Compressors

Collections

(al)


© Tommy Saylor for Smashing Magazine, 2010. | Permalink | 24 comments | Add to del.icio.us | Digg this | Stumble on StumbleUpon! | Tweet it! | Submit to Reddit | Forum Smashing Magazine
Post tags:

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

17 + cinque =

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.