Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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/

like image 717
CuriousDeveloper Avatar asked Apr 25 '19 15:04

CuriousDeveloper


2 Answers

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>
like image 200
gaetanoM Avatar answered Nov 03 '22 01:11

gaetanoM


I am not sure if this needs to be a widget. I would do the following:

$(function() {
  $("span").tooltip({
    items: "[data-tooltip-rel]",
    content: function() {
      var id = $(this).attr("data-tooltip-rel");
      var cont = $("[data-tooltip-content-id='" + id + "']");
      return cont.html();
    }
  });
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<span id="test" data-tooltip-rel="x">Help 1</span>
<span data-tooltip-rel="x">Help 1</span>
<span data-tooltip-rel="y">Help 2</span>
<span data-tooltip-rel="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>

If you feel you need to custom widget, you could do this.

$(function() {
  $.widget("custom.tooltipContent", $.ui.tooltip, {
    options: {
      items: "[data-tooltip-rel]",
      content: function() {
        return $("[data-tooltip-content-id='" + $(this).attr("data-tooltip-rel") + "']").html();
      }
    }
  });
  $("span").tooltipContent();
});
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<span id="test" data-tooltip-rel="x">Help 1</span>
<span data-tooltip-rel="x">Help 1</span>
<span data-tooltip-rel="y">Help 2</span>
<span data-tooltip-rel="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>

Hope that helps.

like image 42
Twisty Avatar answered Nov 03 '22 01:11

Twisty