Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

528 строки
14 KiB

  1. /*!
  2. * jQuery UI Tooltip 1.13.1
  3. * http://jqueryui.com
  4. *
  5. * Copyright jQuery Foundation and other contributors
  6. * Released under the MIT license.
  7. * http://jquery.org/license
  8. */
  9. //>>label: Tooltip
  10. //>>group: Widgets
  11. //>>description: Shows additional information for any element on hover or focus.
  12. //>>docs: http://api.jqueryui.com/tooltip/
  13. //>>demos: http://jqueryui.com/tooltip/
  14. //>>css.structure: ../../themes/base/core.css
  15. //>>css.structure: ../../themes/base/tooltip.css
  16. //>>css.theme: ../../themes/base/theme.css
  17. ( function( factory ) {
  18. "use strict";
  19. if ( typeof define === "function" && define.amd ) {
  20. // AMD. Register as an anonymous module.
  21. define( [
  22. "jquery",
  23. "../keycode",
  24. "../position",
  25. "../unique-id",
  26. "../version",
  27. "../widget"
  28. ], factory );
  29. } else {
  30. // Browser globals
  31. factory( jQuery );
  32. }
  33. } )( function( $ ) {
  34. "use strict";
  35. $.widget( "ui.tooltip", {
  36. version: "1.13.1",
  37. options: {
  38. classes: {
  39. "ui-tooltip": "ui-corner-all ui-widget-shadow"
  40. },
  41. content: function() {
  42. var title = $( this ).attr( "title" );
  43. // Escape title, since we're going from an attribute to raw HTML
  44. return $( "<a>" ).text( title ).html();
  45. },
  46. hide: true,
  47. // Disabled elements have inconsistent behavior across browsers (#8661)
  48. items: "[title]:not([disabled])",
  49. position: {
  50. my: "left top+15",
  51. at: "left bottom",
  52. collision: "flipfit flip"
  53. },
  54. show: true,
  55. track: false,
  56. // Callbacks
  57. close: null,
  58. open: null
  59. },
  60. _addDescribedBy: function( elem, id ) {
  61. var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
  62. describedby.push( id );
  63. elem
  64. .data( "ui-tooltip-id", id )
  65. .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) );
  66. },
  67. _removeDescribedBy: function( elem ) {
  68. var id = elem.data( "ui-tooltip-id" ),
  69. describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
  70. index = $.inArray( id, describedby );
  71. if ( index !== -1 ) {
  72. describedby.splice( index, 1 );
  73. }
  74. elem.removeData( "ui-tooltip-id" );
  75. describedby = String.prototype.trim.call( describedby.join( " " ) );
  76. if ( describedby ) {
  77. elem.attr( "aria-describedby", describedby );
  78. } else {
  79. elem.removeAttr( "aria-describedby" );
  80. }
  81. },
  82. _create: function() {
  83. this._on( {
  84. mouseover: "open",
  85. focusin: "open"
  86. } );
  87. // IDs of generated tooltips, needed for destroy
  88. this.tooltips = {};
  89. // IDs of parent tooltips where we removed the title attribute
  90. this.parents = {};
  91. // Append the aria-live region so tooltips announce correctly
  92. this.liveRegion = $( "<div>" )
  93. .attr( {
  94. role: "log",
  95. "aria-live": "assertive",
  96. "aria-relevant": "additions"
  97. } )
  98. .appendTo( this.document[ 0 ].body );
  99. this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
  100. this.disabledTitles = $( [] );
  101. },
  102. _setOption: function( key, value ) {
  103. var that = this;
  104. this._super( key, value );
  105. if ( key === "content" ) {
  106. $.each( this.tooltips, function( id, tooltipData ) {
  107. that._updateContent( tooltipData.element );
  108. } );
  109. }
  110. },
  111. _setOptionDisabled: function( value ) {
  112. this[ value ? "_disable" : "_enable" ]();
  113. },
  114. _disable: function() {
  115. var that = this;
  116. // Close open tooltips
  117. $.each( this.tooltips, function( id, tooltipData ) {
  118. var event = $.Event( "blur" );
  119. event.target = event.currentTarget = tooltipData.element[ 0 ];
  120. that.close( event, true );
  121. } );
  122. // Remove title attributes to prevent native tooltips
  123. this.disabledTitles = this.disabledTitles.add(
  124. this.element.find( this.options.items ).addBack()
  125. .filter( function() {
  126. var element = $( this );
  127. if ( element.is( "[title]" ) ) {
  128. return element
  129. .data( "ui-tooltip-title", element.attr( "title" ) )
  130. .removeAttr( "title" );
  131. }
  132. } )
  133. );
  134. },
  135. _enable: function() {
  136. // restore title attributes
  137. this.disabledTitles.each( function() {
  138. var element = $( this );
  139. if ( element.data( "ui-tooltip-title" ) ) {
  140. element.attr( "title", element.data( "ui-tooltip-title" ) );
  141. }
  142. } );
  143. this.disabledTitles = $( [] );
  144. },
  145. open: function( event ) {
  146. var that = this,
  147. target = $( event ? event.target : this.element )
  148. // we need closest here due to mouseover bubbling,
  149. // but always pointing at the same event target
  150. .closest( this.options.items );
  151. // No element to show a tooltip for or the tooltip is already open
  152. if ( !target.length || target.data( "ui-tooltip-id" ) ) {
  153. return;
  154. }
  155. if ( target.attr( "title" ) ) {
  156. target.data( "ui-tooltip-title", target.attr( "title" ) );
  157. }
  158. target.data( "ui-tooltip-open", true );
  159. // Kill parent tooltips, custom or native, for hover
  160. if ( event && event.type === "mouseover" ) {
  161. target.parents().each( function() {
  162. var parent = $( this ),
  163. blurEvent;
  164. if ( parent.data( "ui-tooltip-open" ) ) {
  165. blurEvent = $.Event( "blur" );
  166. blurEvent.target = blurEvent.currentTarget = this;
  167. that.close( blurEvent, true );
  168. }
  169. if ( parent.attr( "title" ) ) {
  170. parent.uniqueId();
  171. that.parents[ this.id ] = {
  172. element: this,
  173. title: parent.attr( "title" )
  174. };
  175. parent.attr( "title", "" );
  176. }
  177. } );
  178. }
  179. this._registerCloseHandlers( event, target );
  180. this._updateContent( target, event );
  181. },
  182. _updateContent: function( target, event ) {
  183. var content,
  184. contentOption = this.options.content,
  185. that = this,
  186. eventType = event ? event.type : null;
  187. if ( typeof contentOption === "string" || contentOption.nodeType ||
  188. contentOption.jquery ) {
  189. return this._open( event, target, contentOption );
  190. }
  191. content = contentOption.call( target[ 0 ], function( response ) {
  192. // IE may instantly serve a cached response for ajax requests
  193. // delay this call to _open so the other call to _open runs first
  194. that._delay( function() {
  195. // Ignore async response if tooltip was closed already
  196. if ( !target.data( "ui-tooltip-open" ) ) {
  197. return;
  198. }
  199. // JQuery creates a special event for focusin when it doesn't
  200. // exist natively. To improve performance, the native event
  201. // object is reused and the type is changed. Therefore, we can't
  202. // rely on the type being correct after the event finished
  203. // bubbling, so we set it back to the previous value. (#8740)
  204. if ( event ) {
  205. event.type = eventType;
  206. }
  207. this._open( event, target, response );
  208. } );
  209. } );
  210. if ( content ) {
  211. this._open( event, target, content );
  212. }
  213. },
  214. _open: function( event, target, content ) {
  215. var tooltipData, tooltip, delayedShow, a11yContent,
  216. positionOption = $.extend( {}, this.options.position );
  217. if ( !content ) {
  218. return;
  219. }
  220. // Content can be updated multiple times. If the tooltip already
  221. // exists, then just update the content and bail.
  222. tooltipData = this._find( target );
  223. if ( tooltipData ) {
  224. tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
  225. return;
  226. }
  227. // If we have a title, clear it to prevent the native tooltip
  228. // we have to check first to avoid defining a title if none exists
  229. // (we don't want to cause an element to start matching [title])
  230. //
  231. // We use removeAttr only for key events, to allow IE to export the correct
  232. // accessible attributes. For mouse events, set to empty string to avoid
  233. // native tooltip showing up (happens only when removing inside mouseover).
  234. if ( target.is( "[title]" ) ) {
  235. if ( event && event.type === "mouseover" ) {
  236. target.attr( "title", "" );
  237. } else {
  238. target.removeAttr( "title" );
  239. }
  240. }
  241. tooltipData = this._tooltip( target );
  242. tooltip = tooltipData.tooltip;
  243. this._addDescribedBy( target, tooltip.attr( "id" ) );
  244. tooltip.find( ".ui-tooltip-content" ).html( content );
  245. // Support: Voiceover on OS X, JAWS on IE <= 9
  246. // JAWS announces deletions even when aria-relevant="additions"
  247. // Voiceover will sometimes re-read the entire log region's contents from the beginning
  248. this.liveRegion.children().hide();
  249. a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
  250. a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
  251. a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
  252. a11yContent.appendTo( this.liveRegion );
  253. function position( event ) {
  254. positionOption.of = event;
  255. if ( tooltip.is( ":hidden" ) ) {
  256. return;
  257. }
  258. tooltip.position( positionOption );
  259. }
  260. if ( this.options.track && event && /^mouse/.test( event.type ) ) {
  261. this._on( this.document, {
  262. mousemove: position
  263. } );
  264. // trigger once to override element-relative positioning
  265. position( event );
  266. } else {
  267. tooltip.position( $.extend( {
  268. of: target
  269. }, this.options.position ) );
  270. }
  271. tooltip.hide();
  272. this._show( tooltip, this.options.show );
  273. // Handle tracking tooltips that are shown with a delay (#8644). As soon
  274. // as the tooltip is visible, position the tooltip using the most recent
  275. // event.
  276. // Adds the check to add the timers only when both delay and track options are set (#14682)
  277. if ( this.options.track && this.options.show && this.options.show.delay ) {
  278. delayedShow = this.delayedShow = setInterval( function() {
  279. if ( tooltip.is( ":visible" ) ) {
  280. position( positionOption.of );
  281. clearInterval( delayedShow );
  282. }
  283. }, 13 );
  284. }
  285. this._trigger( "open", event, { tooltip: tooltip } );
  286. },
  287. _registerCloseHandlers: function( event, target ) {
  288. var events = {
  289. keyup: function( event ) {
  290. if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
  291. var fakeEvent = $.Event( event );
  292. fakeEvent.currentTarget = target[ 0 ];
  293. this.close( fakeEvent, true );
  294. }
  295. }
  296. };
  297. // Only bind remove handler for delegated targets. Non-delegated
  298. // tooltips will handle this in destroy.
  299. if ( target[ 0 ] !== this.element[ 0 ] ) {
  300. events.remove = function() {
  301. var targetElement = this._find( target );
  302. if ( targetElement ) {
  303. this._removeTooltip( targetElement.tooltip );
  304. }
  305. };
  306. }
  307. if ( !event || event.type === "mouseover" ) {
  308. events.mouseleave = "close";
  309. }
  310. if ( !event || event.type === "focusin" ) {
  311. events.focusout = "close";
  312. }
  313. this._on( true, target, events );
  314. },
  315. close: function( event ) {
  316. var tooltip,
  317. that = this,
  318. target = $( event ? event.currentTarget : this.element ),
  319. tooltipData = this._find( target );
  320. // The tooltip may already be closed
  321. if ( !tooltipData ) {
  322. // We set ui-tooltip-open immediately upon open (in open()), but only set the
  323. // additional data once there's actually content to show (in _open()). So even if the
  324. // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
  325. // the period between open() and _open().
  326. target.removeData( "ui-tooltip-open" );
  327. return;
  328. }
  329. tooltip = tooltipData.tooltip;
  330. // Disabling closes the tooltip, so we need to track when we're closing
  331. // to avoid an infinite loop in case the tooltip becomes disabled on close
  332. if ( tooltipData.closing ) {
  333. return;
  334. }
  335. // Clear the interval for delayed tracking tooltips
  336. clearInterval( this.delayedShow );
  337. // Only set title if we had one before (see comment in _open())
  338. // If the title attribute has changed since open(), don't restore
  339. if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
  340. target.attr( "title", target.data( "ui-tooltip-title" ) );
  341. }
  342. this._removeDescribedBy( target );
  343. tooltipData.hiding = true;
  344. tooltip.stop( true );
  345. this._hide( tooltip, this.options.hide, function() {
  346. that._removeTooltip( $( this ) );
  347. } );
  348. target.removeData( "ui-tooltip-open" );
  349. this._off( target, "mouseleave focusout keyup" );
  350. // Remove 'remove' binding only on delegated targets
  351. if ( target[ 0 ] !== this.element[ 0 ] ) {
  352. this._off( target, "remove" );
  353. }
  354. this._off( this.document, "mousemove" );
  355. if ( event && event.type === "mouseleave" ) {
  356. $.each( this.parents, function( id, parent ) {
  357. $( parent.element ).attr( "title", parent.title );
  358. delete that.parents[ id ];
  359. } );
  360. }
  361. tooltipData.closing = true;
  362. this._trigger( "close", event, { tooltip: tooltip } );
  363. if ( !tooltipData.hiding ) {
  364. tooltipData.closing = false;
  365. }
  366. },
  367. _tooltip: function( element ) {
  368. var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
  369. content = $( "<div>" ).appendTo( tooltip ),
  370. id = tooltip.uniqueId().attr( "id" );
  371. this._addClass( content, "ui-tooltip-content" );
  372. this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
  373. tooltip.appendTo( this._appendTo( element ) );
  374. return this.tooltips[ id ] = {
  375. element: element,
  376. tooltip: tooltip
  377. };
  378. },
  379. _find: function( target ) {
  380. var id = target.data( "ui-tooltip-id" );
  381. return id ? this.tooltips[ id ] : null;
  382. },
  383. _removeTooltip: function( tooltip ) {
  384. // Clear the interval for delayed tracking tooltips
  385. clearInterval( this.delayedShow );
  386. tooltip.remove();
  387. delete this.tooltips[ tooltip.attr( "id" ) ];
  388. },
  389. _appendTo: function( target ) {
  390. var element = target.closest( ".ui-front, dialog" );
  391. if ( !element.length ) {
  392. element = this.document[ 0 ].body;
  393. }
  394. return element;
  395. },
  396. _destroy: function() {
  397. var that = this;
  398. // Close open tooltips
  399. $.each( this.tooltips, function( id, tooltipData ) {
  400. // Delegate to close method to handle common cleanup
  401. var event = $.Event( "blur" ),
  402. element = tooltipData.element;
  403. event.target = event.currentTarget = element[ 0 ];
  404. that.close( event, true );
  405. // Remove immediately; destroying an open tooltip doesn't use the
  406. // hide animation
  407. $( "#" + id ).remove();
  408. // Restore the title
  409. if ( element.data( "ui-tooltip-title" ) ) {
  410. // If the title attribute has changed since open(), don't restore
  411. if ( !element.attr( "title" ) ) {
  412. element.attr( "title", element.data( "ui-tooltip-title" ) );
  413. }
  414. element.removeData( "ui-tooltip-title" );
  415. }
  416. } );
  417. this.liveRegion.remove();
  418. }
  419. } );
  420. // DEPRECATED
  421. // TODO: Switch return back to widget declaration at top of file when this is removed
  422. if ( $.uiBackCompat !== false ) {
  423. // Backcompat for tooltipClass option
  424. $.widget( "ui.tooltip", $.ui.tooltip, {
  425. options: {
  426. tooltipClass: null
  427. },
  428. _tooltip: function() {
  429. var tooltipData = this._superApply( arguments );
  430. if ( this.options.tooltipClass ) {
  431. tooltipData.tooltip.addClass( this.options.tooltipClass );
  432. }
  433. return tooltipData;
  434. }
  435. } );
  436. }
  437. return $.ui.tooltip;
  438. } );