/*! * jQuery UI Tooltip - v1.10.4 * http://jqueryui.com * * Copyright 2014 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * http://api.jqueryui.com/tooltip/ */ define([ 'jquery', 'jquery-ui-modules/core', 'jquery-ui-modules/widget', 'jquery-ui-modules/position' ], function ($) { var increments = 0; function addDescribedBy(elem, id) { var describedby = (elem.attr("aria-describedby") || "").split(/\s+/); describedby.push(id); elem .data("ui-tooltip-id", id) .attr("aria-describedby", $.trim(describedby.join(" "))); } function removeDescribedBy(elem) { var id = elem.data("ui-tooltip-id"), describedby = (elem.attr("aria-describedby") || "").split(/\s+/), index = $.inArray(id, describedby); if (index !== -1) { describedby.splice(index, 1); } elem.removeData("ui-tooltip-id"); describedby = $.trim(describedby.join(" ")); if (describedby) { elem.attr("aria-describedby", describedby); } else { elem.removeAttr("aria-describedby"); } } $.widget("ui.tooltip", { version: "1.10.4", options: { content: function () { // support: IE<9, Opera in jQuery <1.7 // .text() can't accept undefined, so coerce to a string var title = $(this).attr("title") || ""; // Escape title, since we're going from an attribute to raw HTML return $("").text(title).html(); }, hide: true, // Disabled elements have inconsistent behavior across browsers (#8661) items: "[title]:not([disabled])", position: { my: "left top+15", at: "left bottom", collision: "flipfit flip" }, show: true, tooltipClass: null, track: false, // callbacks close: null, open: null }, _create: function () { this._on({ mouseover: "open", focusin: "open" }); // IDs of generated tooltips, needed for destroy this.tooltips = {}; // IDs of parent tooltips where we removed the title attribute this.parents = {}; if (this.options.disabled) { this._disable(); } }, _setOption: function (key, value) { var that = this; if (key === "disabled") { this[value ? "_disable" : "_enable"](); this.options[key] = value; // disable element style changes return; } this._super(key, value); if (key === "content") { $.each(this.tooltips, function (id, element) { that._updateContent(element); }); } }, _disable: function () { var that = this; // close open tooltips $.each(this.tooltips, function (id, element) { var event = $.Event("blur"); event.target = event.currentTarget = element[0]; that.close(event, true); }); // remove title attributes to prevent native tooltips this.element.find(this.options.items).addBack().each(function () { var element = $(this); if (element.is("[title]")) { element .data("ui-tooltip-title", element.attr("title")) .attr("title", ""); } }); }, _enable: function () { // restore title attributes this.element.find(this.options.items).addBack().each(function () { var element = $(this); if (element.data("ui-tooltip-title")) { element.attr("title", element.data("ui-tooltip-title")); } }); }, open: function (event) { var that = this, target = $(event ? event.target : this.element) // we need closest here due to mouseover bubbling, // but always pointing at the same event target .closest(this.options.items); // No element to show a tooltip for or the tooltip is already open if (!target.length || target.data("ui-tooltip-id")) { return; } if (target.attr("title")) { target.data("ui-tooltip-title", target.attr("title")); } target.data("ui-tooltip-open", true); // kill parent tooltips, custom or native, for hover if (event && event.type === "mouseover") { target.parents().each(function () { var parent = $(this), blurEvent; if (parent.data("ui-tooltip-open")) { blurEvent = $.Event("blur"); blurEvent.target = blurEvent.currentTarget = this; that.close(blurEvent, true); } if (parent.attr("title")) { parent.uniqueId(); that.parents[this.id] = { element: this, title: parent.attr("title") }; parent.attr("title", ""); } }); } this._updateContent(target, event); }, _updateContent: function (target, event) { var content, contentOption = this.options.content, that = this, eventType = event ? event.type : null; if (typeof contentOption === "string") { return this._open(event, target, contentOption); } content = contentOption.call(target[0], function (response) { // ignore async response if tooltip was closed already if (!target.data("ui-tooltip-open")) { return; } // IE may instantly serve a cached response for ajax requests // delay this call to _open so the other call to _open runs first that._delay(function () { // jQuery creates a special event for focusin when it doesn't // exist natively. To improve performance, the native event // object is reused and the type is changed. Therefore, we can't // rely on the type being correct after the event finished // bubbling, so we set it back to the previous value. (#8740) if (event) { event.type = eventType; } this._open(event, target, response); }); }); if (content) { this._open(event, target, content); } }, _open: function (event, target, content) { var tooltip, events, delayedShow, positionOption = $.extend({}, this.options.position); if (!content) { return; } // Content can be updated multiple times. If the tooltip already // exists, then just update the content and bail. tooltip = this._find(target); if (tooltip.length) { tooltip.find(".ui-tooltip-content").html(content); return; } // if we have a title, clear it to prevent the native tooltip // we have to check first to avoid defining a title if none exists // (we don't want to cause an element to start matching [title]) // // We use removeAttr only for key events, to allow IE to export the correct // accessible attributes. For mouse events, set to empty string to avoid // native tooltip showing up (happens only when removing inside mouseover). if (target.is("[title]")) { if (event && event.type === "mouseover") { target.attr("title", ""); } else { target.removeAttr("title"); } } tooltip = this._tooltip(target); addDescribedBy(target, tooltip.attr("id")); tooltip.find(".ui-tooltip-content").html(content); function position(event) { positionOption.of = event; if (tooltip.is(":hidden")) { return; } tooltip.position(positionOption); } if (this.options.track && event && /^mouse/.test(event.type)) { this._on(this.document, { mousemove: position }); // trigger once to override element-relative positioning position(event); } else { tooltip.position($.extend({ of: target }, this.options.position)); } tooltip.hide(); this._show(tooltip, this.options.show); // Handle tracking tooltips that are shown with a delay (#8644). As soon // as the tooltip is visible, position the tooltip using the most recent // event. if (this.options.show && this.options.show.delay) { delayedShow = this.delayedShow = setInterval(function () { if (tooltip.is(":visible")) { position(positionOption.of); clearInterval(delayedShow); } }, $.fx.interval); } this._trigger("open", event, {tooltip: tooltip}); events = { keyup: function (event) { if (event.keyCode === $.ui.keyCode.ESCAPE) { var fakeEvent = $.Event(event); fakeEvent.currentTarget = target[0]; this.close(fakeEvent, true); } }, remove: function () { this._removeTooltip(tooltip); } }; if (!event || event.type === "mouseover") { events.mouseleave = "close"; } if (!event || event.type === "focusin") { events.focusout = "close"; } this._on(true, target, events); }, close: function (event) { var that = this, target = $(event ? event.currentTarget : this.element), tooltip = this._find(target); // disabling closes the tooltip, so we need to track when we're closing // to avoid an infinite loop in case the tooltip becomes disabled on close if (this.closing) { return; } // Clear the interval for delayed tracking tooltips clearInterval(this.delayedShow); // only set title if we had one before (see comment in _open()) if (target.data("ui-tooltip-title")) { target.attr("title", target.data("ui-tooltip-title")); } removeDescribedBy(target); tooltip.stop(true); this._hide(tooltip, this.options.hide, function () { that._removeTooltip($(this)); }); target.removeData("ui-tooltip-open"); this._off(target, "mouseleave focusout keyup"); // Remove 'remove' binding only on delegated targets if (target[0] !== this.element[0]) { this._off(target, "remove"); } this._off(this.document, "mousemove"); if (event && event.type === "mouseleave") { $.each(this.parents, function (id, parent) { $(parent.element).attr("title", parent.title); delete that.parents[id]; }); } this.closing = true; this._trigger("close", event, {tooltip: tooltip}); this.closing = false; }, _tooltip: function (element) { var id = "ui-tooltip-" + increments++, tooltip = $("
") .attr({ id: id, role: "tooltip" }) .addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content " + (this.options.tooltipClass || "")); $("
") .addClass("ui-tooltip-content") .appendTo(tooltip); tooltip.appendTo(this.document[0].body); this.tooltips[id] = element; return tooltip; }, _find: function (target) { var id = target.data("ui-tooltip-id"); return id ? $("#" + id) : $(); }, _removeTooltip: function (tooltip) { tooltip.remove(); delete this.tooltips[tooltip.attr("id")]; }, _destroy: function () { var that = this; // close open tooltips $.each(this.tooltips, function (id, element) { // Delegate to close method to handle common cleanup var event = $.Event("blur"); event.target = event.currentTarget = element[0]; that.close(event, true); // Remove immediately; destroying an open tooltip doesn't use the // hide animation $("#" + id).remove(); // Restore the title if (element.data("ui-tooltip-title")) { element.attr("title", element.data("ui-tooltip-title")); element.removeData("ui-tooltip-title"); } }); } }); });