Article
Better Living Through Bookmarklets
Page: 1 2
A shorter version is available for IE. This version sacrifices the header support to fit within the 508 character limit: Expand HTML shorthand IE.
Expand HTML shorthand:
----
javascript:(function() { var tas = document.getElementsByTagName('textarea'); for (var i = 0; i < tas.length; i++) { var ta = tas[i]; var text = ta.value.replace(/(\r\n|\r|\n)/g, '\n'); var paras = text.split(/\n{2,}/); for (var i = 0; i < paras.length; i++) { if (/^\* /.test(paras[i])) { var lines = paras[i].split('\n'); for (var j = 0; j < lines.length; j++) { lines[j] = ' <li>' + lines[j].replace(/^\* /, '') + '</li>'; } paras[i] = '<ul>\n' + lines.join('\n') + '\n</ul>'; } if (/^= /.test(paras[i])) { paras[i] = '<h4>' + paras[i].replace(/^= /, '') + '</h4>'; } if (!/^<(p|ul|li|h4)>/.test(paras[i])) { paras[i] = '<p>' + paras[i]; } if (!/<\/(p|ul|li|h4)>$/.test(paras[i])) { paras[i] += '</p>'; } } ta.value = paras.join('\n\n'); } })();
----
Expand HTML shorthand IE:
----
javascript:(function(){var tas=document.getElementsByTagName('textarea'),ta,t,ps,i,l,j;for(i=0;i<tas.length;i++){ta=tas[i];
t=ta.value.replace(/(\r\n|\r|\n)/g,'\n');ps=t.split(/\n{2,}/);for(i=0;i<ps.length;i++){if(/^\* /.test(ps[i])){l=ps[i].split('\n');for(j=0;j<l.length;j++){l[j]=' <li>'+l[j].replace(/^\* /,'')+'</li>';}ps[i]='<ul>\n'+l.join('\n')+'\n</ul>';}if(!/^<(p|ul|li|h4)>/.test(ps[i])){ps[i]='
<p>'+ps[i];}if(!/<\/(p|ul|li|h4)>$/.test(ps[i])){ps[i]+='</p>';}}ta.value=ps.join('\n\n');}})();
----
The unexpanded source (before whitespace removal) looks like this:
javascript:(function() {
var tas = document.getElementsByTagName('textarea');
for (var i = 0; i < tas.length; i++) {
var ta = tas[i];
var text = ta.value.replace(/(\r\n|\r|\n)/g, '\n');
var paras = text.split(/\n{2,}/);
for (var i = 0; i < paras.length; i++) {
if (/^\* /.test(paras[i])) {
var lines = paras[i].split('\n');
for (var j = 0; j < lines.length; j++) {
lines[j] = ' <li>' + lines[j].replace(/^\* /, '') + '</li>';
}
paras[i] = '<ul>\n' + lines.join('\n') + '\n</ul>';
}
if (/^= /.test(paras[i])) {
paras[i] = '<h4>' + paras[i].replace(/^= /, '') + '</h4>';
}
if (!/^<(p|ul|li|h4)>/.test(paras[i])) {
paras[i] = '<p>' + paras[i];
}
if (!/<\/(p|ul|li|h4)>$/.test(paras[i])) {
paras[i] += '</p>';
}
}
ta.value = paras.join('\n\n');
}
})();
Tools for Bookmarklet Creation
You can create bookmarklets with nothing more than a text editor -- or, if you're really confident, you can type them straight in to your browser's "New Bookmark" field. For anything more complicated than a simple navigation bookmarklet, however, it makes sense to take advantage of dedicated tools.
If you're using Firefox, you already have access to some useful aids for bookmarklet creation. Firefox's JavaScript console is an invaluable debugging tool, and the DOM inspector is a great aid for exploring the DOM tree of a page when writing bookmarklets that modify page contents. Jesse Ruderman's shell bookmarklet for Firefox and Mozilla provides an interactive JavaScript prompt attached to the context of the current page and is a great way to try out new techniques before you commit them to a text editor.
While bookmarklets cannot contain line breaks, it's essential that you keep your source code indented when you write anything more than a handful of statements. My remove linebreaks bookmarklet (below) is a tool that removes tabs, newlines and multiple spaces from a block of JavaScript. In many cases, this is all you need to do to create a bookmarklet from a simple block of code, although you must remember to terminate each line with a semi-colon before you convert it. The bookmarklet is also an example of an HTML page embedded in a bookmark.
Remove linebreaks:
----
javascript:'<textarea rows=%2220%22 cols=%2260%22 id=%22ta%22></textarea><br><a href=%22http://%22 onclick=%22ta=document.getElementById(\'ta\'); ta.value = ta.value.replace(/\\n|\\t/g, \' \').replace(/ +/g, \' \'); return false;%22>Replace newlines and tabs</a>';
----
Variable Scope Avoidance
A potential problem introduced by bookmarklets is that of namespace collisions: what if your bookmarklet uses or redefines a variable that is already in use by other scripts on the page? One technique to avoid this is to use random variable names that are unlikely to already be in use, but this can make bookmarklet code even more difficult to read and adds unnecessary length to the bookmarklet. A better solution is to create the bookmarklet as an anonymous function with its own variable scope. Here's how this works:
javascript:(function() {
/* Bookmarklet code here - declare variables with 'var' before use */
})();
The function() { } part of this is an anonymous function -- a function that does not have a name declared for it. By wrapping the function in parenthesis and adding () at the end the function is executed once as soon as it has been created, i.e. the instant the bookmarklet is activated. As long as variables within the anonymous function body are declared using the 'var' keyword, they will be constrained to the scope of the function and will not interfere with variables with the same name in the rest of the document.
Thanks to JavaScript's functional nature, you can even declare other functions within the anonymous function without adding them to the document's global scope.
Appending Longer Scripts
I mentioned earlier that a method exists for bypassing Internet Explorer's limit on the length of bookmarks. This method also allows bookmarklets to be written in standard indented JavaScript without needing to keep the whole script on a single line, making it a useful technique for more complicated bookmarklets implemented for any browser. The trick is to host the actual bookmarklet implementation as an external .js file on a Web server somewhere. The bookmarklet then just needs to contain "stub" code that loads in the rest of the script -- a task that's achieved easily within the 508 character limit.
Here's the loading stub bookmarklet code, indented for readability:
javascript:(function() {
var s = document.createElement('script');
s.setAttribute('src', 'http://url-of-main-bookmarklet-script');
s.setAttribute('type', 'text/javascript');
document.getElementsByTagName('head')[0].appendChild(s);
})();
With whitespace removed, the above code (minus the external script URL) comes to 193 characters.
This code has one drawback: it doesn't work with IE5 for the Macintosh. If IE5 Mac support is important for your bookmarklet, liorean has an extended version of the loading stub that uses browser detection to cater for that browser as well.
Further Reading
The best way to learn about bookmarklets is to look at those written by others:
I hope that this whirlwind tour of bookmarklets has inspired you to try your hand at creating your own.