YUI3 Tooltip module
by Ron on Apr.09, 2010, under Javascript
Just quickly posting this bit of code that I’ve written to have a play with YUI3. There’s definitely room for improvement (e.g. making Tooltip inherit from the Overlay widget) and I haven’t tested the code thoroughly yet. But for a first try with a library, I figured it was nice enough to get the expected result:
YUI.add('tooltip', function (Y) {
var Tip = function (config) {
Tip.superclass.constructor.apply(this, arguments);
};
Tip.ATTRS = {
offsetX: {
value: 10,
setter: function (val) {
return val;
}
},
offsetY: {
value: 10,
setter: function (val) {
return val;
}
},
showDelay: {
value: 0.5,
setter: function (val) {
return val*1000;
},
validator: function (val) {
return Y.Lang.isNumber(val) && (val >= 0);
}
},
hideDelay: {
value: 1.5,
setter: function (val) {
return val*1000;
},
validator: function (val) {
return Y.Lang.isNumber(val) && (val >= 0);
}
}
};
Tip.HTML_PARSER = {
header: function (srcNode) {
var h = srcNode.getAttribute("title").match(/header=\[([^\]]*)\]/);
if (h !== null && h.length > 1) {
return h[1];
}
return "";
},
body: function (srcNode) {
var b = srcNode.getAttribute("title").match(/body=\[([^\]]*)\]/);
if (b !== null && b.length > 1) {
return b[1];
}
return "";
}
};
Tip.NAME = "tooltip";
Y.extend(Tip, Y.Widget, {
_srcNode: null,
_tipNode: null,
_config: null,
_timers: null,
initializer: function (config) {
this._config = config;
this._srcNode = config.srcNode;
this._createTipNode(config.header, config.body);
this._timers = {
show: null,
hide: null
};
Y.on("mouseenter", Y.bind(this._onMouseEnter, this), this._srcNode);
Y.on("mouseleave", Y.bind(this._onMouseLeave, this), this._srcNode);
},
destructor: function () {
this._onMouseEnter.detach();
this._onMouseLeave.detach();
this._tipNode.remove();
},
_createTipNode: function (header, body) {
this._tipNode = new Y.Overlay({
headerContent: header,
bodyContent: body,
visible: false,
width:"280px",
constrain: true
});
this._srcNode.setAttribute("title", "");
this._tipNode.render();
},
_onMouseEnter: function (e) {
if (Y.BOL.activeTooltip !== null) {
Y.BOL.activeTooltip.hide();
Y.BOL.activeTooltip = null;
}
if (this._timers.hide !== null) {
this._timers.hide = clearTimeout(this._timers.hide);
}
this._timers.show = setTimeout(Y.bind(function () {
this._tipNode.set("xy", [e.pageX+this.get("offsetX"), e.pageY+this.get("offsetY")]);
this._tipNode.show();
Y.BOL.activeTooltip = this;
}, this), this.get("showDelay"));
},
_onMouseLeave: function (e) {
if (this._timers.show !== null) {
this._timers.show = clearTimeout(this._timers.show);
}
this._timers.hide = setTimeout(Y.bind(function () {
this.hide();
Y.BOL.activeTooltip = null;
}, this), this.get("hideDelay"));
},
hide: function () {
if (this._timers.show !== null) {
this._timers.show = clearTimeout(this._timers.show);
}
this._tipNode.hide();
}
});
Y.namespace('BOL');
Y.BOL.Tooltip = Tip;
Y.BOL.activeTooltip = null;
},
'1.0',
{
requires: ['event-mouseenter', 'overlay']
});
To use it, the HTML needs to look like this:
<div id="testDiv" class="tooltip_trigger" title="header=[Verzendkosten per bestelling] body=[Nederland: &euro; 1,95<br>Belgi&euml;: &euro; 0,00<br>Overige Europa, Noord- en Midden-Amerika, Cara&iuml;bisch gebied, Azi&euml;, Australi&euml;, Nieuw-Zeeland: van &euro; 3,45 tot &euro; 19,80<br><br><strong>Let op!</strong> Software, pc-accessoires, elektronica en telefonie worden niet in het buitenland bezorgd.<br><br>]">Test</div>
And finally, to call it:
YUI().use('tooltip', function (Y) {
Y.all(".tooltip_trigger").each(function (trgNode) {
var tip = new Y.BOL.Tooltip({
srcNode: trgNode
});
})
})

May 14th, 2010 on 15:11
Most important improvement for me would be to use only one tooltip instance for all tooltips on the page and dynamically switch content. Much more resource efficient. It would mean moving the Y.all function inside and just referencing the tooltip class in the constructor.