(function(F/*fossil object*/){
/**
A very basic tooltip widget.
Requires: fossil.bootstrap, fossil.dom
*/
const D = F.dom;
/**
Creates a new tooltip widget using the given options object.
The options are available to clients after this returns via
theTooltip.options.
Options:
.refresh: required callback which is called whenever the tooltip
is revealed or moved. It must refresh the contents of the
tooltip, if needed, by applying it to this.e, which is the base
DOM element for the tooltip.
.adjustX: an optional callback which is called when the tooltip
is to be displayed at a given position and passed the X
coordinate. This routine must either return its argument as-is
or return an adjusted value. This API assumes that clients give it
viewport-relative coordinates, and it will take care to translate
those to page-relative.
.adjustY: the Y counterpart of adjustX.
.init: optional callback called one time to initialize the
state of the tooltip. This is called after the this.e has
been created and added (initially hidden) to the DOM.
All callback options are called with the TooltipWidget object as
their "this".
.cssClass: optional CSS class, or list of classes, to apply to
the new element.
.style: optional object of properties to copy directly into
the element's style object.
Example:
const tip = new fossil.TooltipWidget({
adjustX: (x)=>x+20,
adjustY: function(y){return y - this.e.clientHeight/2},
refresh: function(){
// (re)populate/refresh the contents of the main
// wrapper element, this.e.
}
});
*/
F.TooltipWidget = function f(opt){
opt = F.mergeLastWins(f.defaultOptions,opt);
this.options = opt;
const e = this.e = D.addClass(D.div(), opt.cssClass);
this.show(false);
if(opt.style){
let k;
for(k in opt.style){
if(opt.style.hasOwnProperty(k)) e.style[k] = opt.style[k];
}
}
D.append(document.body, e/*must be in the DOM for size calc. to work*/);
if(opt.init){
opt.init.call(this);
}
};
F.TooltipWidget.defaultOptions = {
cssClass: 'fossil-tooltip',
style: {/*properties copied as-is into element.style*/},
adjustX: (x)=>x,
adjustY: (y)=>y,
refresh: function(hw){
console.error("TooltipWidget refresh() option must be provided by the client.");
}
};
F.TooltipWidget.prototype = {
isShown: function(){return !this.e.classList.contains('hidden')},
/** Calls the refresh() method of the options object. */
refresh: function(){this.options.refresh.call(this)},
/**
Usages:
(bool showIt) => hide it or reveal it at its last position.
(x, y) => reveal/move it at/to the given
relative-to-the-viewport position, which will be adjusted to make
it page-relative.
(DOM element) => reveal/move it ad/to a position based on the
the given element (adjusted slightly).
For the latter two, this.options.adjustX() and adjustY() will
be called to adjust it further.
Returns this object.
*/
show: function(){
var x = 0, y = 0, showIt;
if(2===arguments.length){
x = arguments[0];
y = arguments[1];
showIt = true;
}else if(1===arguments.length){
if(arguments[0] instanceof HTMLElement){
const p = arguments[0];
const r = p.getBoundingClientRect();
x = r.x + r.x/5;
y = r.y - r.height/2;
showIt = true;
}else{
showIt = !!arguments[0];
}
}
if(showIt){
this.refresh();
x = this.options.adjustX.call(this,x);
y = this.options.adjustY.call(this,y);
x += window.pageXOffset;
y += window.pageYOffset;
}
D[showIt ? 'removeClass' : 'addClass'](this.e, 'hidden');
if(x || y){
this.e.style.left = x+"px";
this.e.style.top = y+"px";
//console.debug("TooltipWidget.show()", arguments, x, y);
}
return this;
}
}/*/F.TooltipWidget.prototype*/;
})(window.fossil);