/*
Validation tooltips
Tim Lucas
http://toolmantim.com
See the effect at:
http://www.viddler.com/explore/toolmantim/videos/14
Written against the prototype & scriptaculous included in Rails 0.14.3
Originally used with this RJS helper:
module ValidationTooltipsHelper
def add_validation_tooltip(id, message)
"ValidationTooltip.add('#{id}','#{escape_javascript(message.to_a.join(', '))}');"
end
def remove_validation_tooltip(id)
"ValidationTooltip.remove('#{id}');"
end
def remove_all_validation_tooltips
"ValidationTooltip.removeAll();"
end
end
and then used from RJS like so:
unless @cancelled
[:name, :email].each do |field|
if @person.errors[field]
page.hide "#{field}-valid"
page << add_validation_tooltip("person_#{field}", @person.errors[field])
else
page.visual_effect :appear, "#{field}-valid", :duration => 0.25
page << remove_validation_tooltip("person_#{field}")
end
end
end
if @person.valid?
page << remove_all_validation_tooltips
page.delay(@cancelled ? 0.5 : 1) do
page.replace_html 'profile-view', :partial => 'view'
end
end
with an obtrusive looking view like so:
<%= form_remote_tag :url => { :action => 'save' } %>
<p>
Name: <%= text_field :person, :name, :length => 8 %>
<%= image_tag('icon-valid', :id => 'name-valid', :style => 'display: none') %>
<%= image_tag('icon-exclamation', :id => 'name-error', :style => 'display: none') %>
</p>
<p>
Email: <%= text_field :person, :email, :length => 8 %>
<%= image_tag('icon-valid', :id => 'email-valid', :style => 'display: none') %>
<%= image_tag('icon-exclamation', :id => 'email-error', :style => 'display: none') %>
</p>
<p class="save"><%= link_to_remote image_tag('cancel'), :method => 'get', :url => { :action => 'cancel' } %> <%= image_submit_tag 'save' %></p>
<%= end_form_tag %>
*/
ValidationTooltip = Class.create();
ValidationTooltip.Register = {
instances: $H(),
all: function() {
return this.instances.values();
},
register: function(element, tooltip) {
this.instances[element] = tooltip;
},
get: function(element) {
return this.instances[element];
},
each: function(x) {
return this.instances.values().each(x);
},
remove: function(element) {
delete this.instances[element];
}
};
ValidationTooltip.add = function(element, message, options) {
if (ValidationTooltip.Register.get(element)) {
ValidationTooltip.remove(element);
}
tooltip = new ValidationTooltip(element,message,options);
ValidationTooltip.Register.register(element, tooltip);
tooltip.show();
}
ValidationTooltip.remove = function(element) {
if (tooltip = ValidationTooltip.Register.get(element)) {
ValidationTooltip.Register.remove(element);
tooltip.hide();
}
}
ValidationTooltip.removeAll = function() {
ValidationTooltip.Register.each(function(tooltip) {
tooltip.hide();
});
};
ValidationTooltip.prototype = {
initialize: function(element, message, options) {
this.element = $(element);
this.message = message;
this.timer = null;
this.tooltip = null;
this.options = Object.extend({
idPrefix: 'validation_tooltip_',
className: 'validation-tooltip',
appearDuration: 0.25,
fade: true,
fadeDuration: 0.25,
onShow: null,
onHide: null
}, options || {});
this.options.onShow = this.options.onShow || function(tooltip) {
if (tooltip.options.fade) {
new Effect.Appear(tooltip.tooltip, {duration: tooltip.options.appearDuration});
} else {
Element.show(tooltip.tooltip);
}
};
this.options.onHide = this.options.onHide || function(tooltip) {
if (tooltip.options.fade) {
new Effect.Fade(tooltip.tooltip, {duration: tooltip.options.fadeDuration});
} else {
Element.hide(tooltip.tooltip);
}
};
this.createTooltip();
this.show();
},
createTooltip: function() {
this.tooltip = document.createElement("span");
this.tooltip.appendChild(document.createTextNode(this.message));
this.tooltip.id = this.id();
Element.addClassName(this.tooltip, this.options.className);
this.tooltip.style.display = 'none';
this.tooltip.style.width = this.message.length / 1.5 + 'em';
this.tooltip.style.position = 'absolute';
Position.clone(this.element, this.tooltip, {setWidth: false, setHeight: false, offsetTop: -this.element.offsetHeight, offsetLeft: this.element.offsetWidth});
this.element.parentNode.parentNode.appendChild(this.tooltip);
},
show: function() {
this.options.onShow(this);
},
hide: function() {
this.options.onHide(this);
},
id: function() {
return this.options.idPrefix + this.element.id;
}
}