Tooltip custom jQuery Widget

by jmeile

HTML

<script src="https://cms-author.ethz.ch/etc.clientlibs/clientlibs/granite/jquery.min.js"></script>
<script src="https://cms-author.ethz.ch/etc.clientlibs/clientlibs/granite/jquery-ui.min.js"></script>
<script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.12.1/css/jquery.dataTables.min.css">
<br/>
The <b><span style="color:red">Red</span></b> tooltip will be activated only on hover<br/>
Please also note that if you hover on the tooltip text, it will remain until<br/>
the mouse goes out from it<br/>
The <b><span style="color:green">Green</span></b> tooltip will be activated when clicking<br/>
on it. It will be only hidden when clicking on it again<br/>
The <b><span style="color:blue">Blue</span></b> tooltip will be activated when clicking<br/>
on it. It will be hidden when clicking on it again, or clicking on another<br/>
blue tooltip or when clicking on another area of the page<br/>
The <b><span style="color:orange">Orange</span></b> tooltip will be use the standad functionality,<br/>
but it will load the tooltip text from the specified URL, when opening it<br/>
Here the first tooltip: 
This tooltip will appear above the link because some space is missing on the top <div class="jm-tooltip-2">Hover me
  <div>
    Some long text<br/>
    line 2<br/>
    line 3<br/>
    line 4<br/>
    line 5<br/>
    line 6<br/>
    line 7<br/>
    line 8 (Scroll down to see other lines)<br/>
    line 9<br/>
    line 10<br/>
    line 11<br/>
    line 12<br/>
    line 13<br/>
    line 14<br/>
    line 15<br/>
  </div>
</div>
<div class="jm-tooltip-3">Click me
  <div>
    Some long text<br/>
    line 2<br/>
    line 3<br/>
    line 4<br/>
    line 5<br/>
    line 6<br/>
    line 7<br/>
    line 8 (Scroll down to see other lines)<br/>
    line 9<br/>
    line 10<br/>
    line 11<br/>
    line 12<br/>
    line 13<br/>
    line 14<br/>
    line 15<br/>
  </div>
</div>
<div class="jm-tooltip-4"...

CSS

/* This are the minimal css. They are needed because some calculations are done
 * based on the layout, so, tooltip containers must occupy the right space and
 * the tooltips must be hidden
 */
.jm-tooltip-widget,
.jm-tooltip-2,
.jm-tooltip-3,
.jm-tooltip-4 {
  position: relative;
  display: inline-block;
}

.jm-tooltip-widget > div,
.jm-tooltip-2 > div,
.jm-tooltip-3 > div,
.jm-tooltip-4 > div {
  display: none;
}

JavaScript

/* I used the following as a reference while implementing a custom jQuery
 * Widget:
 * - Extending Widgets with the Widget Factory
 *   https://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/
 * - How To Use the Widget Factory
 *   https://learn.jquery.com/jquery-ui/widget-factory/how-to-use-the-widget-factory/
 * - Chapter 9. Extending widgets with the widget factory
 *   https://livebook.manning.com/book/jquery-ui-in-action/chapter-9/17
 * - Widget Factory (Example)
 *   https://jqueryui.com/widget/#default
 * - Widget Factory (Methods and properties)
 *   https://api.jqueryui.com/jQuery.widget/
 * - Widget Method Invocation
 *   https://learn.jquery.com/jquery-ui/widget-factory/widget-method-invocation
 *   From this page, I tried the cleanest way for invoking my widget:
 *   $('.jm-tooltip-widget').jmTooltip();
 *   var widgetObj = $('.jm-tooltip-widget').data("jmtooltip");
 *   widgetObj.initializeEvents();
 *
 *   I also tried:
 *   $(".jm-tooltip-widget").jmTooltip("instance").initializeEvents();
 *
 *   But it didn't work, so, I have to stick with the ugly syntax:
 *   var widgetObj = $('.jm-tooltip-widget').jmTooltip();
 *   widgetObj.jmTooltip("initializeEvents");
 *
 *   or for short:
 *   $('.jm-tooltip-widget').jmTooltip().jmTooltip("initializeEvents");
 *
 * Update 27.09.2022: a data attribute was introduced for the tooltips: 'link';
 * it is usefull for avoiding loading large texts; instead of this, a link to
 * a json data must be entered, then the text will be loaded via ajax and JSONP
 * (Cross domain Ajax request). It is better to do it if you have lots of
 * elements and the tooltips have long texts; otherwise, the request will last
 * a lot of time until it loads. Please note that the link must be valid and
 * return a json object like: ({ "text" : "some text" }); yes, the parenthesis
 * are needed because what you are returning is not JSON, but a javascript
 * object.
 *
 * The php file looks like this:
   <?php
     $oid =...