From a0892eca70b59238e40082cc7c2e5a042fb5bae9 Mon Sep 17 00:00:00 2001 From: Alexander Schmitz Date: Mon, 24 Aug 2015 08:50:46 -0400 Subject: [PATCH] Tooltip: Style updates Ref #14246 --- tests/unit/tooltip/common-deprecated.js | 2 +- tests/unit/tooltip/common.js | 2 +- tests/unit/tooltip/core.js | 62 +++++++-------- tests/unit/tooltip/deprecated.js | 6 +- tests/unit/tooltip/events.js | 24 +++--- tests/unit/tooltip/methods.js | 27 ++++--- tests/unit/tooltip/options.js | 100 ++++++++++++------------ ui/widgets/tooltip.js | 10 +++ 8 files changed, 124 insertions(+), 109 deletions(-) diff --git a/tests/unit/tooltip/common-deprecated.js b/tests/unit/tooltip/common-deprecated.js index 75a688f0a..2a5437335 100644 --- a/tests/unit/tooltip/common-deprecated.js +++ b/tests/unit/tooltip/common-deprecated.js @@ -26,6 +26,6 @@ common.testWidget( "tooltip", { create: null, open: null } -}); +} ); } ); diff --git a/tests/unit/tooltip/common.js b/tests/unit/tooltip/common.js index 15c9dfad8..73797fe49 100644 --- a/tests/unit/tooltip/common.js +++ b/tests/unit/tooltip/common.js @@ -25,6 +25,6 @@ common.testWidget( "tooltip", { create: null, open: null } -}); +} ); } ); diff --git a/tests/unit/tooltip/core.js b/tests/unit/tooltip/core.js index e7e22b0e6..0dfdc5825 100644 --- a/tests/unit/tooltip/core.js +++ b/tests/unit/tooltip/core.js @@ -21,7 +21,7 @@ test( "markup structure", function( assert ) { equal( tooltip.length, 1, ".ui-tooltip exists" ); equal( tooltip.find( ".ui-tooltip-content" ).length, 1, ".ui-tooltip-content exists" ); -}); +} ); test( "accessibility", function() { expect( 15 ); @@ -61,7 +61,7 @@ test( "accessibility", function() { element.tooltip( "destroy" ); equal( liveRegion.parent().length, 0, "Tooltip liveregion element should be removed" ); -}); +} ); test( "delegated removal", function() { expect( 2 ); @@ -74,32 +74,32 @@ test( "delegated removal", function() { container.empty(); equal( $( ".ui-tooltip" ).length, 0 ); -}); +} ); test( "nested tooltips", function() { expect( 2 ); var child = $( "#contained-tooltipped" ), - parent = $( "#contains-tooltipped" ).tooltip({ + parent = $( "#contains-tooltipped" ).tooltip( { show: null, hide: null - }); + } ); parent.trigger( "mouseover" ); equal( $( ".ui-tooltip:visible" ).text(), "parent" ); child.trigger( "mouseover" ); equal( $( ".ui-tooltip" ).text(), "child" ); -}); +} ); // #8742 test( "form containing an input with name title", function() { expect( 4 ); - var form = $( "#tooltip-form" ).tooltip({ + var form = $( "#tooltip-form" ).tooltip( { show: null, hide: null - }), + } ), input = form.find( "[name=title]" ); equal( $( ".ui-tooltip" ).length, 0, "no tooltips on init" ); @@ -111,7 +111,7 @@ test( "form containing an input with name title", function() { form.trigger( "mouseover" ); equal( $( ".ui-tooltip" ).length, 0, "no tooltip for form" ); -}); +} ); test( "tooltip on .ui-state-disabled element", function() { expect( 2 ); @@ -124,18 +124,18 @@ test( "tooltip on .ui-state-disabled element", function() { container.empty(); equal( $( ".ui-tooltip" ).length, 0 ); -}); +} ); // http://bugs.jqueryui.com/ticket/8740 asyncTest( "programmatic focus with async content", function() { expect( 2 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function( response ) { - setTimeout(function() { + setTimeout( function() { response( "test" ); - }); + } ); } - }); + } ); element.on( "tooltipopen", function( event ) { deepEqual( event.originalEvent.type, "focusin" ); @@ -143,35 +143,35 @@ asyncTest( "programmatic focus with async content", function() { element.on( "tooltipclose", function( event ) { deepEqual( event.originalEvent.type, "focusout" ); start(); - }); + } ); - setTimeout(function() { + setTimeout( function() { element.trigger( "blur" ); - }); - }); + } ); + } ); element.trigger( "focus" ); -}); +} ); asyncTest( "destroy during hide animation; only one close event", function() { expect( 1 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { show: false, hide: true - }); + } ); element.on( "tooltipclose", function() { ok( true, "tooltip closed" ); - }); + } ); element.tooltip( "open" ); element.tooltip( "close" ); - setTimeout(function() { + setTimeout( function() { element.tooltip( "destroy" ); start(); - }); -}); + } ); +} ); // http://bugs.jqueryui.com/ticket/10602 asyncTest( "multiple active delegated tooltips", function() { @@ -181,7 +181,7 @@ asyncTest( "multiple active delegated tooltips", function() { input = anchor.next(), actions = []; - $( document ).tooltip({ + $( document ).tooltip( { show: false, hide: false, open: function( event, ui ) { @@ -190,7 +190,7 @@ asyncTest( "multiple active delegated tooltips", function() { close: function( event, ui ) { actions.push( "close:" + ui.tooltip.text() ); } - }); + } ); function step1() { anchor.simulate( "mouseover" ); @@ -219,7 +219,7 @@ asyncTest( "multiple active delegated tooltips", function() { } step1(); -}); +} ); // http://bugs.jqueryui.com/ticket/11272 test( "remove conflicting attributes from live region", function() { @@ -234,7 +234,7 @@ test( "remove conflicting attributes from live region", function() { "" ); $( "#tooltipped1" ) - .tooltip({ + .tooltip( { content: element, open: function() { equal( $( ".ui-helper-hidden-accessible [name]" ).length, 0, @@ -242,8 +242,8 @@ test( "remove conflicting attributes from live region", function() { equal( $( ".ui-helper-hidden-accessible [id]" ).length, 0, "no id attributes within live region" ); } - }) + } ) .tooltip( "open" ); -}); +} ); } ); diff --git a/tests/unit/tooltip/deprecated.js b/tests/unit/tooltip/deprecated.js index b1325057b..7fc7d91a4 100644 --- a/tests/unit/tooltip/deprecated.js +++ b/tests/unit/tooltip/deprecated.js @@ -7,10 +7,10 @@ module( "tooltip: (deprecated) options" ); test( "tooltipClass", function( assert ) { expect( 1 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { tooltipClass: "custom" - }).tooltip( "open" ); + } ).tooltip( "open" ); assert.hasClasses( $( "#" + element.data( "ui-tooltip-id" ) ), "custom" ); -}); +} ); } ); diff --git a/tests/unit/tooltip/events.js b/tests/unit/tooltip/events.js index 7ad36dc08..3cf65fc4e 100644 --- a/tests/unit/tooltip/events.js +++ b/tests/unit/tooltip/events.js @@ -13,17 +13,17 @@ test( "programmatic triggers", function() { element.one( "tooltipopen", function( event, ui ) { tooltip = ui.tooltip; ok( !( "originalEvent" in event ), "open" ); - strictEqual( ui.tooltip[0], - $( "#" + element.data( "ui-tooltip-id" ) )[0], "ui.tooltip" ); - }); + strictEqual( ui.tooltip[ 0 ], + $( "#" + element.data( "ui-tooltip-id" ) )[ 0 ], "ui.tooltip" ); + } ); element.tooltip( "open" ); element.one( "tooltipclose", function( event, ui ) { ok( !( "originalEvent" in event ), "close" ); - strictEqual( ui.tooltip[0], tooltip[0], "ui.tooltip" ); - }); + strictEqual( ui.tooltip[ 0 ], tooltip[ 0 ], "ui.tooltip" ); + } ); element.tooltip( "close" ); -}); +} ); test( "mouse events", function() { expect( 2 ); @@ -31,15 +31,15 @@ test( "mouse events", function() { element.on( "tooltipopen", function( event ) { deepEqual( event.originalEvent.type, "mouseover" ); - }); + } ); element.trigger( "mouseover" ); element.on( "tooltipclose", function( event ) { deepEqual( event.originalEvent.type, "mouseleave" ); - }); + } ); element.trigger( "focusout" ); element.trigger( "mouseleave" ); -}); +} ); test( "focus events", function() { expect( 2 ); @@ -47,14 +47,14 @@ test( "focus events", function() { element.on( "tooltipopen", function( event ) { deepEqual( event.originalEvent.type, "focusin" ); - }); + } ); element.trigger( "focusin" ); element.on( "tooltipclose", function( event ) { deepEqual( event.originalEvent.type, "focusout" ); - }); + } ); element.trigger( "mouseleave" ); element.trigger( "focusout" ); -}); +} ); } ); diff --git a/tests/unit/tooltip/methods.js b/tests/unit/tooltip/methods.js index d4c56e1f3..31fe86532 100644 --- a/tests/unit/tooltip/methods.js +++ b/tests/unit/tooltip/methods.js @@ -11,17 +11,17 @@ test( "destroy", function( assert ) { assert.domEqual( "#tooltipped1", function() { element.tooltip().tooltip( "destroy" ); - }); + } ); // Make sure that open tooltips are removed on destroy assert.domEqual( "#tooltipped1", function() { element .tooltip() - .tooltip( "open", $.Event( "mouseover", { target: element[0] }) ) + .tooltip( "open", $.Event( "mouseover", { target: element[ 0 ] } ) ) .tooltip( "destroy" ); - }); + } ); equal( $( ".ui-tooltip" ).length, 0 ); -}); +} ); test( "open/close", function() { expect( 3 ); @@ -37,14 +37,14 @@ test( "open/close", function() { element.tooltip( "close" ); ok( tooltip.is( ":hidden" ) ); $.fx.off = false; -}); +} ); // #8626 - Calling open() without an event test( "open/close with tracking", function() { expect( 3 ); $.fx.off = true; var tooltip, - element = $( "#tooltipped1" ).tooltip({ track: true }); + element = $( "#tooltipped1" ).tooltip( { track: true } ); equal( $( ".ui-tooltip" ).length, 0, "no tooltip on init" ); element.tooltip( "open" ); @@ -54,7 +54,7 @@ test( "open/close with tracking", function() { element.tooltip( "close" ); ok( tooltip.is( ":hidden" ) ); $.fx.off = false; -}); +} ); test( "enable/disable", function( assert ) { expect( 11 ); @@ -91,7 +91,7 @@ test( "enable/disable", function( assert ) { tooltip = $( "#" + element.data( "ui-tooltip-id" ) ); ok( tooltip.is( ":visible" ) ); $.fx.off = false; -}); +} ); test( "widget", function() { expect( 2 ); @@ -99,7 +99,7 @@ test( "widget", function() { widgetElement = element.tooltip( "widget" ); equal( widgetElement.length, 1, "one element" ); strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" ); -}); +} ); test( "preserve changes to title attributes on close and destroy", function() { expect( 6 ); @@ -110,14 +110,19 @@ test( "preserve changes to title attributes on close and destroy", function() { // 1. Changes to title attribute are preserved on close() tests[ 0 ] = { title: changed, expected: changed, method: "close" }; + // 2. Changes to title attribute are preserved on destroy() - tests[ 1 ] = { title: changed, expected: changed , method: "destroy" }; + tests[ 1 ] = { title: changed, expected: changed, method: "destroy" }; + // 3. Changes to title attribute are NOT preserved when set to empty string on close() tests[ 2 ] = { title: "", expected: original, method: "close" }; + // 4. Changes to title attribute are NOT preserved when set to empty string on destroy() tests[ 3 ] = { title: "", expected: original, method: "destroy" }; + // 5. Changes to title attribute NOT preserved when attribute has been removed on close() tests[ 4 ] = { expected: original, method: "close" }; + // 6. Changes to title attribute NOT preserved when attribute has been removed on destroy() tests[ 5 ] = { expected: original, method: "destroy" }; @@ -134,6 +139,6 @@ test( "preserve changes to title attributes on close and destroy", function() { equal( $( "#tooltipped1" ).attr( "title" ), test.expected ); } ); -}); +} ); } ); diff --git a/tests/unit/tooltip/options.js b/tests/unit/tooltip/options.js index 2833e68dd..a35d140fb 100644 --- a/tests/unit/tooltip/options.js +++ b/tests/unit/tooltip/options.js @@ -7,17 +7,17 @@ module( "tooltip: options" ); test( "disabled: true", function() { expect( 1 ); - $( "#tooltipped1" ).tooltip({ + $( "#tooltipped1" ).tooltip( { disabled: true - }).tooltip( "open" ); + } ).tooltip( "open" ); equal( $( ".ui-tooltip" ).length, 0 ); -}); +} ); test( "content: default", function() { expect( 1 ); var element = $( "#tooltipped1" ).tooltip().tooltip( "open" ); deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "anchortitle" ); -}); +} ); test( "content: default; HTML escaping", function() { expect( 2 ); @@ -31,130 +31,130 @@ test( "content: default; HTML escaping", function() { equal( $.ui.tooltip.hacked, false, "script did not execute" ); deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), scriptText, "correct tooltip text" ); -}); +} ); test( "content: return string", function() { expect( 1 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function() { return "customstring"; } - }).tooltip( "open" ); + } ).tooltip( "open" ); deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "customstring" ); -}); +} ); test( "content: return jQuery", function() { expect( 2 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function() { return $( "
" ).html( "customstring" ); } - }).tooltip( "open" ), + } ).tooltip( "open" ), liveRegion = element.tooltip( "instance" ).liveRegion; deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "customstring" ); equal( liveRegion.children().last().html().toLowerCase(), "
customstring
", "The accessibility live region will strip the ids but keep the structure" ); -}); +} ); asyncTest( "content: sync + async callback", function() { expect( 2 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function( response ) { - setTimeout(function() { - deepEqual( $( "#" + element.data("ui-tooltip-id") ).text(), "loading..." ); + setTimeout( function() { + deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "loading..." ); response( "customstring2" ); - setTimeout(function() { - deepEqual( $( "#" + element.data("ui-tooltip-id") ).text(), "customstring2" ); + setTimeout( function() { + deepEqual( $( "#" + element.data( "ui-tooltip-id" ) ).text(), "customstring2" ); start(); }, 13 ); }, 13 ); return "loading..."; } - }).tooltip( "open" ); -}); + } ).tooltip( "open" ); +} ); // http://bugs.jqueryui.com/ticket/8740 asyncTest( "content: async callback loses focus before load", function() { expect( 1 ); - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function( response ) { - setTimeout(function() { + setTimeout( function() { element.trigger( "mouseleave" ); - setTimeout(function() { + setTimeout( function() { response( "sometext" ); - setTimeout(function() { + setTimeout( function() { ok( !$( "#" + element.data( "ui-tooltip-id" ) ).is( ":visible" ), "Tooltip should not display" ); start(); - }); - }); - }); + } ); + } ); + } ); } - }); + } ); element.trigger( "mouseover" ); -}); +} ); test( "content: change while open", function() { expect( 2 ) ; - var element = $( "#tooltipped1" ).tooltip({ + var element = $( "#tooltipped1" ).tooltip( { content: function() { return "old"; } - }); + } ); element.one( "tooltipopen", function( event, ui ) { equal( ui.tooltip.text(), "old", "original content" ); element.tooltip( "option", "content", function() { return "new"; - }); + } ); equal( ui.tooltip.text(), "new", "updated content" ); - }); + } ); element.tooltip( "open" ); -}); +} ); test( "content: string", function() { expect( 1 ); - $( "#tooltipped1" ).tooltip({ + $( "#tooltipped1" ).tooltip( { content: "just a string", open: function( event, ui ) { equal( ui.tooltip.text(), "just a string" ); } - }).tooltip( "open" ); -}); + } ).tooltip( "open" ); +} ); test( "content: element", function() { expect( 1 ); var content = "

this is a test of the emergency broadcast system.

", element = $( content )[ 0 ]; - $( "#tooltipped1" ).tooltip({ + $( "#tooltipped1" ).tooltip( { content: element, open: function( event, ui ) { equal( ui.tooltip.children().html().toLowerCase(), content ); } - }).tooltip( "open" ); -}); + } ).tooltip( "open" ); +} ); test( "content: jQuery", function() { expect( 1 ); var content = "

this is a test of the emergency broadcast system.

", element = $( content ); - $( "#tooltipped1" ).tooltip({ + $( "#tooltipped1" ).tooltip( { content: element, open: function( event, ui ) { equal( ui.tooltip.children().html().toLowerCase(), content ); } - }).tooltip( "open" ); -}); + } ).tooltip( "open" ); +} ); test( "items", function() { expect( 2 ); var event, - element = $( "#qunit-fixture" ).tooltip({ + element = $( "#qunit-fixture" ).tooltip( { items: "#fixture-span" - }); + } ); event = $.Event( "mouseenter" ); event.target = $( "#fixture-span" )[ 0 ]; @@ -167,7 +167,7 @@ test( "items", function() { deepEqual( $( "#tooltipped1" ).data( "ui-tooltip-id" ), undefined ); element.tooltip( "destroy" ); -}); +} ); test( "track + show delay", function() { expect( 2 ); @@ -175,7 +175,7 @@ test( "track + show delay", function() { leftVal = 314, topVal = 159, offsetVal = 26, - element = $( "#tooltipped1" ).tooltip({ + element = $( "#tooltipped1" ).tooltip( { track: true, show: { delay: 1 @@ -184,7 +184,7 @@ test( "track + show delay", function() { my: "left+" + offsetVal + " top+" + offsetVal, at: "right bottom" } - }); + } ); event = $.Event( "mouseover" ); event.target = $( "#tooltipped1" )[ 0 ]; @@ -202,14 +202,14 @@ test( "track + show delay", function() { equal( $( ".ui-tooltip" ).css( "left" ), leftVal + offsetVal + "px" ); equal( $( ".ui-tooltip" ).css( "top" ), topVal + offsetVal + "px" ); -}); +} ); test( "track and programmatic focus", function() { expect( 1 ); - $( "#qunit-fixture div input" ).tooltip({ + $( "#qunit-fixture div input" ).tooltip( { track: true - }).trigger( "focus" ); + } ).trigger( "focus" ); equal( "inputtitle", $( ".ui-tooltip" ).text() ); -}); +} ); } ); diff --git a/ui/widgets/tooltip.js b/ui/widgets/tooltip.js index 6c4493052..512224050 100644 --- a/ui/widgets/tooltip.js +++ b/ui/widgets/tooltip.js @@ -42,13 +42,16 @@ $.widget( "ui.tooltip", { "ui-tooltip": "ui-corner-all ui-widget-shadow" }, 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: { @@ -123,6 +126,7 @@ $.widget( "ui.tooltip", { if ( key === "disabled" ) { this[ value ? "_disable" : "_enable" ](); this.options[ key ] = value; + // disable element style changes return; } @@ -158,6 +162,7 @@ $.widget( "ui.tooltip", { }, _enable: function() { + // restore title attributes this.element.find( this.options.items ).addBack().each( function() { var element = $( this ); @@ -170,6 +175,7 @@ $.widget( "ui.tooltip", { 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 ); @@ -304,6 +310,7 @@ $.widget( "ui.tooltip", { this._on( this.document, { mousemove: position } ); + // trigger once to override element-relative positioning position( event ); } else { @@ -315,6 +322,7 @@ $.widget( "ui.tooltip", { 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. @@ -464,6 +472,7 @@ $.widget( "ui.tooltip", { // Close open tooltips $.each( this.tooltips, function( id, tooltipData ) { + // Delegate to close method to handle common cleanup var event = $.Event( "blur" ), element = tooltipData.element; @@ -476,6 +485,7 @@ $.widget( "ui.tooltip", { // Restore the title if ( element.data( "ui-tooltip-title" ) ) { + // If the title attribute has changed since open(), don't restore if ( !element.attr( "title" ) ) { element.attr( "title", element.data( "ui-tooltip-title" ) );