(function($){
function ghost_focus() {
var $this = $(this);

if ($.trim($this.val()) === $this.data("ghost")) {
$this.val("");
$this.removeClass("ghosted");
}
}

function ghost_blur() {
var $this = $(this);
var val = $.trim($this.val());
var ghost = $this.data("ghost");

// this arguably does the Wrong Thing if the user manually enters the
// ghost text into the field (it will disappear), but is necessary to
// handle browsers' auto-filling ghost text
if (val === "" || val === ghost) {
$this.val(ghost);
$this.addClass("ghosted");
}
}

$.fn.ghost = function(method, option, value) {
// this plugin mimics the behavior of jQuery UI widgets, both to
// provide a familiar interface and provide forward compatibility if
// it becomes a "real" widget later

if (method === undefined && option === undefined && value === undefined) {
return this.each(function() {
var $this = $(this);

if ($this.data("ghost")) return;

$this.data("ghost", $this.attr("title"))
.removeAttr("title")
.focus(ghost_focus)
.blur(ghost_blur);

// the blur handler adds ghost text, if necessary
ghost_blur.call(this);
});
} else if (method === "destroy") {
return this.each(function() {
var $this = $(this);

if (!$this.data("ghost")) return;

// the focus handler removes ghost text, if necessary
ghost_focus.call(this);

$this.attr("title", $this.data("ghost"))
.removeData("ghost")
.unbind("focus", ghost_focus)
.unbind("blur", ghost_blur);
});
} else if (method === "option") {
if (option !== "text") {
throw "invalid option '" + option + "'"
}

if (typeof value === "undefined") {
// only returns the ghost text for the first element in the
// set, but that matches the behavior of real widgets
return this.data("ghost");
} else {
return this.each(function() {
var $this = $(this);

// calling .ghost("option", ...) doesn't change focus, so
// currently-focused fields will be handled automatically
// by the blur handler
if ($this.hasClass("ghosted")) {
$this.val(value);
}
}).data("ghost", value);
}
} else {
throw "no such method '" + method + "'";
}
};
})(jQuery);

