diff --git a/examples/tip.html b/examples/tip.html index 28efc0f..6b18a21 100644 --- a/examples/tip.html +++ b/examples/tip.html @@ -32,6 +32,9 @@ position: absolute; width: 200px; } + .tooltip:focus { + outline: 0; + } @@ -74,6 +77,13 @@ Pastrami boudin pig, swine filet mignon venison flank chuck. +
  • + Persistent Tip. +
    + Bresaola salami short loin tongue t-bone venison turkey fatback pancetta frankfurter swine hamburger. + close +
    +
  • diff --git a/grunt.js b/grunt.js index d56b8ee..0ba38c1 100644 --- a/grunt.js +++ b/grunt.js @@ -41,7 +41,7 @@ module.exports = function(grunt) { 'http://localhost:1337/test/placeholder/placeholder.html', 'http://localhost:1337/test/$/$.html', 'http://localhost:1337/test/list/list.html', - //'http://localhost:1337/test/tip/tip.html', + 'http://localhost:1337/test/tip/tip.html', 'http://localhost:1337/test/carousel/carousel.html', 'http://localhost:1337/test/dropdown/dropdown.html', 'http://localhost:1337/test/switch/switch.html', diff --git a/scripts/components/Tip.js b/scripts/components/Tip.js index 6bbf0e7..6071eaf 100644 --- a/scripts/components/Tip.js +++ b/scripts/components/Tip.js @@ -85,6 +85,14 @@ Tip = Abstract.extend( function (Abstract){ */ className: 'tooltip', + /** + * Class of target that will close a persistent tip + * @property closeClass + * @type String + * @private + */ + closeClass: '.close', + /** * CSS styles for the Tip * @property style @@ -94,13 +102,13 @@ Tip = Abstract.extend( function (Abstract){ style: '', /** - * If set to true the tip will remain open until the mouse has left the tip. - * @property interactive + * If set to true the tip will remain open until the user clicks the close button or outside of the tip + * @property persistent * @type Boolean * @private * @default true */ - interactive: TRUE, + persistent: FALSE, /** * The buffer in pixels around the element to be used in determing if the user has stopped @@ -160,21 +168,13 @@ Tip = Abstract.extend( function (Abstract){ */ href, - /** - * An indicator of whether or not the tip should remain open - * @property stuck - * @type Boolean - * @private - */ - stuck, - /** * Whether the element is an input or not * @property isInput * @type Boolean * @private */ - isInput = ($element[0].tagName.toLowerCase() === 'input'), + isInput = ( $element[0].tagName.toLowerCase() === 'input' ), /** * Array of decorators to apply to a Tip instance @@ -241,8 +241,19 @@ Tip = Abstract.extend( function (Abstract){ function handleMouseEnter ( event ){ event.stopPropagation(); - //set up a listener on the document to be used in determing if the user has moused out of the threshold - $document.on( 'mousemove.lu.tip', handleMouseMove ); + if( !settings.persistent ) { + //set up a listener on the document to be used in determing if the user has moused out of the threshold + $document.on( 'mousemove.lu.tip', handleMouseMove ); + } else { + // if the user clicks outside of a persistent tip close it + $document.on( 'click', function( evt) { + var $target = $( evt.target ); + + if( $target.closest( '.' + settings.className ).length === 0 ) { + self.hide(); + } + } ); + } self.show(); } @@ -297,11 +308,13 @@ Tip = Abstract.extend( function (Abstract){ function handleFocus( event ){ event.stopPropagation(); - $element.on( 'blur.lu.tip', function( event ){ - event.stopPropagation(); - $element.off( 'blur.lu.tip' ); - self.hide(); - } ); + if( !settings.persistent ) { + $element.on( 'blur.lu.tip', function( event ){ + event.stopPropagation(); + $element.off( 'blur.lu.tip' ); + self.hide(); + } ); + } self.show(); } @@ -316,7 +329,7 @@ Tip = Abstract.extend( function (Abstract){ */ this.show = function(){ if( rendered === FALSE ){ - TipContainer.trigger( 'load', [href] ); + TipContainer.trigger( 'load', { content: href } ); } else { $tip.css( self.getPosition() ); $tip.show(); @@ -332,15 +345,18 @@ Tip = Abstract.extend( function (Abstract){ * @method hide * @return {Void} */ - this.hide = function(){ + this.hide = function( noDelay ){ var timeout; + if( rendered === TRUE ){ - timeout = window.setTimeout( function(){ - if( !stuck || !settings.interactive ){ + if( !noDelay ){ + timeout = window.setTimeout( function(){ $tip.hide(); window.clearTimeout( timeout ); - } - }, settings.delay ); + }, settings.delay ); + } else { + $tip.hide(); + } } }; @@ -383,8 +399,17 @@ Tip = Abstract.extend( function (Abstract){ } else { $element.on( 'focus', handleFocus ); } - // use losing focus on tip to enforce one tip at a time - $tip.on( 'blur', self.hide ); + + if( settings.persistent ) { + // close button for persistent tips + $tip.on( 'click', settings.closeClass, function( evt ) { + evt.preventDefault(); + self.hide( true ); // close tip with no delay + } ); + } else { + // use losing focus on tip to enforce one (non-persistent) tip at a time + $tip.on( 'blur', self.hide ); + } // === DECORATION === switch( settings.placement ){ diff --git a/test/tip/test.js b/test/tip/test.js index 0b8fc67..785d3f5 100644 --- a/test/tip/test.js +++ b/test/tip/test.js @@ -2,38 +2,92 @@ function execute(){ var mouseTipEl = $( '#mouse-tip' ), mouseTipComponent = mouseTipEl.lu( 'getComponent', 'Tip' ), inputTipEl = $( '#input-tip' ), - inputTipComponent = inputTipEl.lu( 'getComponent', 'Tip' ); + inputTipComponent = inputTipEl.lu( 'getComponent', 'Tip' ), + persistentTipEl = $( '#persistent-tip' ), + persistentTipComponent = persistentTipEl.lu( 'getComponent', 'Tip' ); - QUnit.module( 'Lu Tips' ); + $.when.apply( $, [ mouseTipComponent.deferral, + inputTipComponent.deferral, + persistentTipComponent.deferral ] ).done( function () { - QUnit.asyncTest( 'Mouse triggered tip.' , function() { - mouseTipComponent.ready(function() { + QUnit.module( 'API Tests' ); + + test( 'Programmatic show', 1, function() { + mouseTipComponent.instance.show(); + if( $( '.mouse-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is shown' ); + } + } ); + + test( 'Programmatic getPosition', 1, function() { + var position = mouseTipComponent.instance.getPosition(); + + if( position.top && position.left ) { + ok( true, 'Postion object has correct attributes' ); + } + } ); + + asyncTest( 'Programmatic hide', 1, function() { + mouseTipComponent.instance.hide(); + setTimeout( function() { + if( !$( '.mouse-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is hidden' ); + start(); + } + }, 500 ); + } ); + + QUnit.module( 'Interaction Tests' ); + + test( 'Mouse over show', 2, function() { mouseTipEl.trigger( 'mouseenter' ); - expect( 2 ); - ok( $.trim( $( '.mouse-tip' ).html() ) === 'Fatback pork belly flank salami cow t-bone ground round pancetta short ribs jerky pig pork sausage.', 'Tip content is correct.' ); - start(); - $(document).trigger( 'mousemove' ); - stop(); - setTimeout(function() { - ok( $( '.mouse-tip' ).css('display') === 'none', 'Tip has been hidden.' ); - start(); - }, 300); - }); - }); - - QUnit.asyncTest( 'Focus triggered tip.' , function() { - inputTipComponent.ready(function() { + ok( $.trim( $( '.mouse-tip' ).html() ) === 'Mouse tooltip content.', 'Tip content is correct.' ); + if( $( '.mouse-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is shown' ); + } + } ); + + asyncTest( 'Mouse leave hide', 1, function() { + $( document ).trigger( 'mousemove' ); + setTimeout( function() { + if( !$( '.mouse-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is hidden' ); + start(); + } + }, 500 ); + } ); + + test( 'Focus show', 2, function() { inputTipEl.trigger( 'focus' ); - expect( 2 ); - ok( $.trim( $( '.input-tip' ).html() ) === 'Pastrami boudin pig, swine filet mignon venison flank chuck.', 'Tip content is correct.' ); - start(); - inputTipEl.trigger( 'blur' ); - stop(); - setTimeout(function() { - ok( $( '.input-tip' ).css( 'display' ) === 'none', 'Tip has been hidden.' ); - start(); - }, 300); - }); - }); + ok( $.trim( $( '.input-tip' ).html() ) === 'Input tooltip content.', 'Tip content is correct.' ); + if( $( '.input-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is shown' ); + } + } ); + + asyncTest( 'Blur hide', 1, function() { + $( inputTipEl ).trigger( 'blur' ); + setTimeout( function() { + if( !$( '.input-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is hidden' ); + start(); + } + }, 500 ); + } ); + + test( 'Show persistent tip', 1, function() { + persistentTipEl.trigger( 'mouseenter' ); + if( $( '.persistent-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is shown' ); + } + } ); + + test( 'Hide persistent tip (with close button)', 1, function() { + $( '.persistent-tip .close' ).trigger( 'click' ); + if( !$( '.persistent-tip' ).is( ':visible' ) ) { + ok( true, 'Tip is hidden' ); + } + } ); + } ); } \ No newline at end of file diff --git a/test/tip/tip.html b/test/tip/tip.html index 5ebc063..1cbb657 100644 --- a/test/tip/tip.html +++ b/test/tip/tip.html @@ -4,6 +4,17 @@ Tip Tests + @@ -14,13 +25,21 @@
  • Mouse Tip.
    - Fatback pork belly flank salami cow t-bone ground round pancetta short ribs jerky pig pork sausage. + Mouse tooltip content.
  • - Pastrami boudin pig, swine filet mignon venison flank chuck. + Input tooltip content. +
    +
  • +
  • + Persistent Tip. +
    + Persistent tooltip content. + Close