Saturday, June 16, 2012

SSH bookmarklet

When developing server software for a company, you might be troubleshooting an issue on a development server other than your own and you want to login to that server. Specifically I'm talking about when you are looking at say a QA person's issue in a web browser and you want to login to their box and see what's wrong.

I found out recently that my MacBook has the ssh protocol registerred already where if you click on a link with this scheme: ssh://, then that executes ssh I wanted to figure out a way to utilize this in a bookmarklet. I also wanted it to be easy enough such that you could enter a different username, like root or the QA person's username if you have certain access restrictions on that server.

Here is my attempt to create that bookmarklet. Just drag it to your browser's toolbar:


Here is my breakdown of what happens:
// prompt for a user to ssh as, save that in the window for next time
window.sshuser = prompt('Login to ' + window.location.hostname + ' as', window.sshuser || '');

// construct the user@ string
user = (window.sshuser ? window.sshuser + '@' : '');

// construct the url and execute it
window.location = 'ssh://' + user + window.location.hostname

This works great, but I really want to figure out how to make multiple programs that register the ssh:// protocol for any operating system or browser. Something like this link explains:

Windows is pretty easy to create a batch script that adds registry keys for an ssh protocol to run putty (or even cygwin ssh). I would like to know how to do the same on Ubuntu (or any Linux). I'm pretty stoked that the Macbook already has it. I don't know if its related to me installing mac developer tools, but I'm pretty satisfied.

Anyway, Hope this bookmarklet helps!

Weird jQuery bug

My software was recently upgraded from jQuery 1.5.2 to 1.7.2.

Luckily we had a bunch of automated tests for our ui code and we found a lot of issues with our code that toggles checkboxes or the disabled state of a tag.  Previously you could say
$('#my_checkbox').attr('checked', 'checked'); // check the checkbox
$('#my_checkbox').attr('checked', ''); // uncheck the checkbox

$('#my_input').attr('disabled', 'disabled'); // disable the input
$('#my_input').attr('disabled', ''); // enable the input
We had code all over the place that did this. But when we used empty string, attr didn't enable or uncheck the elements.

The fixes we found were to either use a boolean value instead of a string, or you could use the removeAttr function:
$('#my_checkbox').attr('checked', true); // check the checkbox
$('#my_checkbox').attr('checked', false); // uncheck the checkbox
$('#my_checkbox').removeAttr('checked'); // alternative to uncheck the checkbox

$('#my_input').attr('disabled', true); // disable the input
$('#my_input').attr('disabled', false); // enable the input
$('#my_input').removeAttr('disabled'); // alternative to enable the input
We needed to figure out the best way to change our code with little impact and it looked like using removeAttr would cause more code since you would have to litter your code with if/else statements to figure out whether to use the attr or the removeAttr case.

So because of this we tried to enforce using booleans. But you could run into issues where you didn't know the type of the second parameter to attr.
var checked = $('#my_checkbox').attr('checked'); // get the checkbox state:
//   'checked' or ''
$('#other_checkbox').attr('checked', checked); // set another checkbox to the same state
// same thing appplies to disabled
I did some digging and found that jQuery 1.6.2 had a fix to change attr('checked') to return the actual html value of checked instead of a boolean value:
<input id="my_checkbox" type="checkbox" checked="checked" />
var checkState = $('#my_checkbox').attr('checked'); // returns 'checked' as of jQuery 1.6.2 instead of true.  When it is unchecked, you get undefined returned.
// See this link for a list of more quirks: 
So, to remedy this, we decided to always ensure you pass a boolean to the attr function for disabled or checked. Don't use empty string to uncheck or enable your element. If you still want to rely on the return string of the attr function, you can booleanize it like this:

var check_state = $('#my_checkbox').attr('checked'); // get the checkbox state:
//    'checked' or undefined
$('#other_checkbox').attr('checked', !!check_state); // set another checkbox to the same state using a boolean
// !!undefined yields false, 
// !!'checked' yields true
// same thing applies to disabled
Now you know, and knowing is half the battle.

I have to say that I'm pretty unimpressed with jQuery since no one caught this.  Changing apis that are so important, like attr, is bad mojo and will cause many developers to curse your name late at night as they debug these unexpected api upgrade bugs.  jQuery is supposed to be so awesome because it is easy going and does what you expect.  This is a step backwards for all of us.
</ rant>