Q:

JQuery UI tooltip extension using options.items vs title

I wrote the following extension to the JQuery UI tooltip widget that allows the tooltip to have context on getting its content from a HTMLElement's html. However, I have the 'title' attribute hard coded but I would like to use whatever attribute is defined in options.items. For example if they want the tooltip to use alt tag then the extention populates that attribute with the html content.
Also I am looking for the jquery ui way of correctly escaping the contentIdstring concatenation
$(function() {
    (function() {
        var cache = {};
        $.widget("custom.tooltipContent", $.ui.tooltip, {
            _init: function() {
                this._super();

                this.options.content = function() {
                    return $(this).attr("title");
                };

                this.element.attr("title", function() {
                    var contentId = $(this).attr("data-tooltip-content");

                    if (!cache[contentId]) {
                        cache[contentId] = $("[data-tooltip-content-id=" + contentId + "]").remove().html();
                    }

                    return cache[contentId];
                });
            }
        });
    })();
});

http://jsfiddle.net/5d7sqx89/1/

A:

Instead of title or items options I would suggest you to use a new option. You may call it itemsData. This in order to avoid to parse the content of items as a selector.
$("span").tooltipContent({
      itemsData: "data-tooltip-content",
      show: {
          effect: "slideDown",
          delay: 50
      }
 })

itemsData: selector of the data to be displayed according to your pattern: 
     data-tooltip-content  --> data-tooltip-content-id

(function () {
    $.widget("custom.tooltipContent", $.ui.tooltip, {
        _init: function () {
            this._super();
            var _self = this;
            var datasetName = 'tooltipContent';

            // this in order to fire always content function...
            _self.options.items = (_self.options.items.indexOf('[title]') != -1) ? '[data-tooltip-content]' :  _self.options.items;

            // normalize itemsData
            _self.options.itemsData = _self.options.itemsData || "data-tooltip-content";

            // get the html to be displayed later and save it into a data attribute
            var contentSelector = "[" + _self.options.itemsData + "-id=" + _self.element.data(datasetName) + "]";
            _self.element.data(datasetName, $(contentSelector).html());

            this.options.content = function () {
                return _self.element.data(datasetName);
            };
        }
    });
})();

$("span").tooltipContent({
    itemsData: "data-tooltip-content",
    show: {
        effect: "slideDown",
        delay: 50
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>


<span id="test1" data-tooltip-content="x">Help 1</span>
<span id="test2" data-tooltip-content="x">Help 1</span>
<span id="test3" data-tooltip-content="y">Help 2</span>
<span id="test4" data-tooltip-content="y">Help 2</span>

<div style="display:none" data-tooltip-content-id="x">
    Shared content for <b>help 1</b>
</div>

<div style="display:none" data-tooltip-content-id="y">
    <table style="width:100%">
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Age</th>
        </tr>
        <tr>
            <td>Jill</td>
            <td>Smith</td>
            <td>50</td>
        </tr>
        <tr>
            <td>Eve</td>
            <td>Jackson</td>
            <td>94</td>
        </tr>
    </table>
</div>

Another approach can be based on how a bootstrap button open a modal. Now your data-tooltip-content attribute has to contain the selector of the data to be displayed:
<span id="test1" data-tooltip-content="#x">Help 1</span>
<span id="test2" data-tooltip-content="#x">Help 1</span>
<span id="test3" data-tooltip-content="#y">Help 2</span>
<span id="test4" data-tooltip-content="#y">Help 2</span>

<div id="x" style="display:none">
    Shared content for <b>help 1</b>
</div>

<div id="y" style="display:none">
    <table style="width:100%">
.......................

The code now is more easy.

(function () {
    $.widget("custom.tooltipContent", $.ui.tooltip, {
        _init: function () {
            this._super();
            var _self = this;
            var datasetName = 'tooltipContent';

            // this in order to fire always content function...
            _self.options.items = (_self.options.items.indexOf('[title]') != -1) ? '[data-tooltip-content]' :  _self.options.items;

            // get the html to be displayed later and save it into a data attribute
            var html = '';
            if (_self.options.itemsData === undefined) {
                html = _self.element.attr('title') || '';
            } else {
                html = $(_self.element.data(datasetName)).html();
            }

            _self.element.data(datasetName, html);

            this.options.content = function () {
                return _self.element.data(datasetName);
            };
        }
    });
})();


$("span").tooltipContent({
    items: "span[id^=test]", // optional
    itemsData: "data-tooltip-content",
    show: {
        effect: "slideDown",
        delay: 50
    }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css" rel="stylesheet"/>
<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.js"></script>


<span id="test1" data-tooltip-content="#x">Help 1</span>
<span id="test2" data-tooltip-content="#x">Help 1</span>
<span id="test3" data-tooltip-content="#y">Help 2</span>
<span id="test4" data-tooltip-content="#y">Help 2</span>

<div id="x" style="display:none">
    Shared content for <b>help 1</b>
</div>

<div id="y" style="display:none">
    <table style="width:100%">
        <tr>
            <th>Firstname</th>
            <th>Lastname</th>
            <th>Age</th>
        </tr>
        <tr>
            <td>Jill</td>
            <td>Smith</td>
            <td>50</td>
        </tr>
        <tr>
            <td>Eve</td>
            <td>Jackson</td>
            <td>94</td>
        </tr>
    </table>
</div>

