diff options
| author | Mark Otto <[email protected]> | 2014-10-26 22:31:59 -0700 |
|---|---|---|
| committer | Mark Otto <[email protected]> | 2014-10-26 22:31:59 -0700 |
| commit | d6b0f45fb711989cb8ac32f6717d6920ef5c68e0 (patch) | |
| tree | 48f08aacd9aadf5cf6fe9aaeeebfa6eb7fab26d0 /js/tests | |
| parent | d1660ad0788fa4e9b0d072323c1d70f9c6f5dbf2 (diff) | |
| parent | 66bb0b4fc963fec42e7168f40b18703d3f31bfa8 (diff) | |
| download | bootstrap-d6b0f45fb711989cb8ac32f6717d6920ef5c68e0.tar.xz bootstrap-d6b0f45fb711989cb8ac32f6717d6920ef5c68e0.zip | |
Merge branch 'master' into derp
Conflicts:
Gruntfile.js
dist/css/bootstrap-theme.css
dist/css/bootstrap-theme.css.map
dist/css/bootstrap-theme.min.css
dist/css/bootstrap.css
dist/css/bootstrap.css.map
dist/css/bootstrap.min.css
docs/_includes/components/dropdowns.html
docs/_includes/components/media.html
docs/_includes/components/navs.html
docs/_includes/components/progress-bars.html
docs/_includes/components/responsive-embed.html
docs/_includes/css/buttons.html
docs/_includes/css/forms.html
docs/_includes/css/less.html
docs/_includes/css/overview.html
docs/_includes/css/responsive-utilities.html
docs/_includes/customizer-variables.html
docs/_includes/getting-started/browser-device-support.html
docs/_includes/getting-started/grunt.html
docs/_includes/getting-started/template.html
docs/_includes/header.html
docs/_includes/js/alerts.html
docs/_includes/js/buttons.html
docs/_includes/js/carousel.html
docs/_includes/js/collapse.html
docs/_includes/js/dropdowns.html
docs/_includes/js/modal.html
docs/_includes/js/popovers.html
docs/_includes/js/scrollspy.html
docs/_includes/js/tabs.html
docs/_includes/js/tooltips.html
docs/_includes/nav/components.html
docs/_includes/nav/getting-started.html
docs/_layouts/default.html
docs/about.html
docs/assets/css/docs.min.css
docs/assets/css/src/docs.css
docs/assets/js/customize.min.js
docs/assets/js/docs.min.js
docs/assets/js/raw-files.min.js
docs/browser-bugs.html
docs/components.html
docs/components/navbar.md
docs/css.html
docs/dist/css/bootstrap-theme.css
docs/dist/css/bootstrap-theme.css.map
docs/dist/css/bootstrap-theme.min.css
docs/dist/css/bootstrap.css
docs/dist/css/bootstrap.css.map
docs/dist/css/bootstrap.min.css
docs/examples/blog/index.html
docs/examples/carousel/index.html
docs/examples/cover/index.html
docs/examples/dashboard/index.html
docs/examples/grid/index.html
docs/examples/jumbotron-narrow/index.html
docs/examples/jumbotron/index.html
docs/examples/justified-nav/index.html
docs/examples/navbar-fixed-top/index.html
docs/examples/navbar-static-top/index.html
docs/examples/navbar/index.html
docs/examples/non-responsive/index.html
docs/examples/offcanvas/index.html
docs/examples/signin/index.html
docs/examples/starter-template/index.html
docs/examples/sticky-footer-navbar/index.html
docs/examples/sticky-footer/index.html
docs/examples/theme/index.html
docs/examples/tooltip-viewport/index.html
docs/getting-started.html
docs/javascript.html
docs/migration.html
less/_animation.less
less/_modal.less
less/_navbar.less
less/_variables.less
less/glyphicons.less
less/navs.less
less/panels.less
less/progress-bars.less
Diffstat (limited to 'js/tests')
| -rw-r--r-- | js/tests/index.html | 5 | ||||
| -rw-r--r-- | js/tests/unit/button.js | 20 | ||||
| -rw-r--r-- | js/tests/unit/carousel.js | 101 | ||||
| -rw-r--r-- | js/tests/unit/collapse.js | 35 | ||||
| -rw-r--r-- | js/tests/unit/modal.js | 4 | ||||
| -rw-r--r-- | js/tests/unit/popover.js | 48 | ||||
| -rw-r--r-- | js/tests/unit/scrollspy.js | 69 | ||||
| -rw-r--r-- | js/tests/unit/tab.js | 101 | ||||
| -rw-r--r-- | js/tests/unit/tooltip.js | 271 | ||||
| -rw-r--r-- | js/tests/visual/dropdown.html | 41 |
10 files changed, 647 insertions, 48 deletions
diff --git a/js/tests/index.html b/js/tests/index.html index 1c025cf76..194f531aa 100644 --- a/js/tests/index.html +++ b/js/tests/index.html @@ -10,6 +10,11 @@ <!-- QUnit --> <link rel="stylesheet" href="vendor/qunit.css" media="screen"> <script src="vendor/qunit.js"></script> + <style> + #qunit-tests > li.pass { + display: none;/* Make it easier to see failing tests is Sauce screencasts */ + } + </style> <script> // See https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit var log = [] diff --git a/js/tests/unit/button.js b/js/tests/unit/button.js index bd431d546..73747cdd4 100644 --- a/js/tests/unit/button.js +++ b/js/tests/unit/button.js @@ -85,7 +85,7 @@ $(function () { }) test('should toggle active', function () { - var $btn = $('<button class="btn">mdo</button>') + var $btn = $('<button class="btn" data-toggle="button">mdo</button>') ok(!$btn.hasClass('active'), 'btn does not have active class') $btn.bootstrapButton('toggle') ok($btn.hasClass('active'), 'btn has class active') @@ -102,6 +102,24 @@ $(function () { ok($btn.hasClass('active'), 'btn has class active') }) + test('should toggle aria-pressed', function () { + var $btn = $('<button class="btn" data-toggle="button" aria-pressed="false">redux</button>') + equal($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $btn.bootstrapButton('toggle') + equal($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + + test('should toggle aria-pressed when btn children are clicked', function () { + var $btn = $('<button class="btn" data-toggle="button" aria-pressed="false">redux</button>') + var $inner = $('<i/>') + $btn + .append($inner) + .appendTo('#qunit-fixture') + equal($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $inner.click() + equal($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + test('should toggle active when btn children are clicked within btn-group', function () { var $btngroup = $('<div class="btn-group" data-toggle="buttons"/>') var $btn = $('<button class="btn">fat</button>') diff --git a/js/tests/unit/carousel.js b/js/tests/unit/carousel.js index 3f9e61a34..6f0b9642f 100644 --- a/js/tests/unit/carousel.js +++ b/js/tests/unit/carousel.js @@ -398,4 +398,105 @@ $(function () { strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') }) + + test('should go to previous item if left arrow key is pressed', function () { + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + + '<div class="carousel-inner">' + + '<div id="first" class="item">' + + '<img alt="">' + + '</div>' + + '<div id="second" class="item active">' + + '<img alt="">' + + '</div>' + + '<div id="third" class="item">' + + '<img alt="">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + + $template.bootstrapCarousel() + + strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + + $template.trigger($.Event('keydown', { which: 37 })) + + strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + }) + + test('should go to next item if right arrow key is pressed', function () { + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + + '<div class="carousel-inner">' + + '<div id="first" class="item active">' + + '<img alt="">' + + '</div>' + + '<div id="second" class="item">' + + '<img alt="">' + + '</div>' + + '<div id="third" class="item">' + + '<img alt="">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + + $template.bootstrapCarousel() + + strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.trigger($.Event('keydown', { which: 39 })) + + strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + }) + + test('should support disabling the keyboard navigation', function () { + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false" data-keyboard="false">' + + '<div class="carousel-inner">' + + '<div id="first" class="item active">' + + '<img alt="">' + + '</div>' + + '<div id="second" class="item">' + + '<img alt="">' + + '</div>' + + '<div id="third" class="item">' + + '<img alt="">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + + $template.bootstrapCarousel() + + strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.trigger($.Event('keydown', { which: 39 })) + + strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after right arrow press') + + $template.trigger($.Event('keydown', { which: 37 })) + + strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after left arrow press') + }) + + test('should only add mouseenter and mouseleave listeners when not on mobile', function () { + var isMobile = 'ontouchstart' in document.documentElement + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false" data-pause="hover">' + + '<div class="carousel-inner">' + + '<div id="first" class="item active">' + + '<img alt="">' + + '</div>' + + '<div id="second" class="item">' + + '<img alt="">' + + '</div>' + + '<div id="third" class="item">' + + '<img alt="">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML).bootstrapCarousel() + + $.each(['mouseover', 'mouseout'], function (i, type) { + strictEqual(type in $._data($template[0], 'events'), !isMobile, 'does' + (isMobile ? ' not' : '') + ' listen for ' + type + ' events') + }) + }) }) diff --git a/js/tests/unit/collapse.js b/js/tests/unit/collapse.js index 825f79360..c1d78575c 100644 --- a/js/tests/unit/collapse.js +++ b/js/tests/unit/collapse.js @@ -263,4 +263,39 @@ $(function () { $target3.click() }) + test('should not fire show event if show is prevented because other element is still transitioning', function () { + stop() + + var accordionHTML = '<div id="accordion">' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '</div>' + var showFired = false + var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel') + + var $target1 = $('<a data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0)) + + $('<div id="body1" class="collapse"/>') + .appendTo($groups.eq(0)) + .on('show.bs.collapse', function () { + showFired = true + }) + + var $target2 = $('<a data-toggle="collapse" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1)) + var $body2 = $('<div id="body2" class="collapse"/>').appendTo($groups.eq(1)) + + $target2.click() + + $body2 + .toggleClass('in collapsing') + .data('bs.collapse').transitioning = 1 + + $target1.click() + + setTimeout(function () { + ok(!showFired, 'show event didn\'t fire') + start() + }, 1) + }) + }) diff --git a/js/tests/unit/modal.js b/js/tests/unit/modal.js index 2262465a4..efd478b20 100644 --- a/js/tests/unit/modal.js +++ b/js/tests/unit/modal.js @@ -141,7 +141,7 @@ $(function () { notEqual($('#modal-test').length, 0, 'modal insterted into dom') $('.contents').click() ok($('#modal-test').is(':visible'), 'modal visible') - $('#modal-test').click() + $('#modal-test .modal-backdrop').click() }) .on('hidden.bs.modal', function () { ok(!$('#modal-test').is(':visible'), 'modal hidden') @@ -196,7 +196,7 @@ $(function () { $('<div id="modal-test"><div class="contents"/></div>') .on('shown.bs.modal', function () { triggered = 0 - $('#modal-test').click() + $('#modal-test .modal-backdrop').click() }) .on('hide.bs.modal', function () { triggered += 1 diff --git a/js/tests/unit/popover.js b/js/tests/unit/popover.js index 5cb4cafdd..466ebace2 100644 --- a/js/tests/unit/popover.js +++ b/js/tests/unit/popover.js @@ -30,7 +30,7 @@ $(function () { }) test('should render popover element', function () { - var $popover = $('<a href="#" title="mdo" data-content="http://twitter.com/mdo">@mdo</a>') + var $popover = $('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>') .appendTo('#qunit-fixture') .bootstrapPopover('show') @@ -40,7 +40,7 @@ $(function () { }) test('should store popover instance in popover data object', function () { - var $popover = $('<a href="#" title="mdo" data-content="http://twitter.com/mdo">@mdo</a>').bootstrapPopover() + var $popover = $('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>').bootstrapPopover() ok($popover.data('bs.popover'), 'popover instance exists') }) @@ -173,4 +173,48 @@ $(function () { ok(!$._data($popover[0], 'events').mouseover && !$._data($popover[0], 'events').mouseout, 'popover does not have any events') }) + test('should render popover element using delegated selector', function () { + var $div = $('<div><a href="#" title="mdo" data-content="http://twitter.com/mdo">@mdo</a></div>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + selector: 'a', + trigger: 'click' + }) + + $div.find('a').click() + notEqual($('.popover').length, 0, 'popover was inserted') + + $div.find('a').click() + equal($('.popover').length, 0, 'popover was removed') + }) + + test('should render popover elements using different delegated selectors on the same node', function () { + var popoverHTML = '<div>' + + '<a href="#" class="first" title="mdo" data-content="http://twitter.com/mdo">@mdo</a>' + + '<a href="#" class="second" title="mdo" data-content="http://twitter.com/mdo">@mdo</a>' + + '</div>' + + var $div = $(popoverHTML) + .appendTo('#qunit-fixture') + .bootstrapPopover({ + selector: 'a.first', + trigger: 'click' + }) + .bootstrapPopover({ + selector: 'a.second', + trigger: 'click' + }) + + $div.find('a.first').click() + notEqual($('.popover').length, 0, 'first popover was inserted') + + $div.find('a.first').click() + equal($('.popover').length, 0, 'first popover removed') + + $div.find('a.second').click() + notEqual($('.popover').length, 0, 'second popover was inserted') + + $div.find('a.second').click() + equal($('.popover').length, 0, 'second popover removed') + }) }) diff --git a/js/tests/unit/scrollspy.js b/js/tests/unit/scrollspy.js index c071d0f65..0c9081491 100644 --- a/js/tests/unit/scrollspy.js +++ b/js/tests/unit/scrollspy.js @@ -29,22 +29,6 @@ $(function () { strictEqual($scrollspy[0], $el[0], 'collection contains element') }) - // Does not work properly ATM, #13500 will fix this - test('should switch "active" class on scroll', function () { - var topbarHTML = '<div class="topbar">' - + '<div class="topbar-inner">' - + '<div class="container">' - + '<h3><a href="#">Bootstrap</a></h3>' - + '<li><a href="#masthead">Overview</a></li>' - + '</ul>' - + '</div>' - + '</div>' - + '</div>' - var $topbar = $(topbarHTML).bootstrapScrollspy() - - ok($topbar.find('.active', true)) - }) - test('should only switch "active" class on current target', function () { stop() @@ -77,9 +61,9 @@ $(function () { var $section = $(sectionHTML).appendTo('#qunit-fixture') var $scrollspy = $section - .show() - .find('#scrollspy-example') - .bootstrapScrollspy({ target: '#ss-target' }) + .show() + .find('#scrollspy-example') + .bootstrapScrollspy({ target: '#ss-target' }) $scrollspy.on('scroll.bs.scrollspy', function () { ok($section.hasClass('active'), '"active" class still on root node') @@ -89,7 +73,7 @@ $(function () { $scrollspy.scrollTop(350) }) - test('middle navigation option correctly selected when large offset is used', function () { + test('should correctly select middle navigation option when large offset is used', function () { stop() var sectionHTML = '<div id="header" style="height: 500px;"></div>' @@ -107,8 +91,8 @@ $(function () { + '</div>' var $section = $(sectionHTML).appendTo('#qunit-fixture') var $scrollspy = $section - .show() - .filter('#content') + .show() + .filter('#content') $scrollspy.bootstrapScrollspy({ target: '#navigation', offset: $scrollspy.position().top }) @@ -158,4 +142,45 @@ $(function () { .then(function () { return testElementIsActiveAfterScroll('#li-2', '#div-2') }) }) + test('should clear selection if above the first section', function () { + stop() + + var sectionHTML = '<div id="header" style="height: 500px;"></div>' + + '<nav id="navigation" class="navbar">' + + '<ul class="nav navbar-nav">' + + '<li class="active"><a id="one-link" href="#one">One</a></li>' + + '<li><a id="two-link" href="#two">Two</a></li>' + + '<li><a id="three-link" href="#three">Three</a></li>' + + '</ul>' + + '</nav>' + $(sectionHTML).appendTo('#qunit-fixture') + + var scrollspyHTML = '<div id="content" style="height: 200px; overflow-y: auto;">' + + '<div id="spacer" style="height: 100px;"/>' + + '<div id="one" style="height: 100px;"/>' + + '<div id="two" style="height: 100px;"/>' + + '<div id="three" style="height: 100px;"/>' + + '<div id="spacer" style="height: 100px;"/>' + + '</div>' + var $scrollspy = $(scrollspyHTML).appendTo('#qunit-fixture') + + $scrollspy + .bootstrapScrollspy({ + target: '#navigation', + offset: $scrollspy.position().top + }) + .one('scroll.bs.scrollspy', function () { + strictEqual($('.active').length, 1, '"active" class on only one element present') + strictEqual($('.active').has('#two-link').length, 1, '"active" class on second section') + + $scrollspy + .one('scroll.bs.scrollspy', function () { + strictEqual($('.active').length, 0, 'selection cleared') + start() + }) + .scrollTop(0) + }) + .scrollTop(201) + }) + }) diff --git a/js/tests/unit/tab.js b/js/tests/unit/tab.js index 8e50614ec..9b2a18d57 100644 --- a/js/tests/unit/tab.js +++ b/js/tests/unit/tab.js @@ -101,4 +101,105 @@ $(function () { .bootstrapTab('show') }) + test('should fire hide and hidden events', function () { + stop() + + var tabsHTML = '<ul class="tabs">' + + '<li><a href="#home">Home</a></li>' + + '<li><a href="#profile">Profile</a></li>' + + '</ul>' + + $(tabsHTML) + .find('li:first a') + .on('hide.bs.tab', function () { + ok(true, 'hide event fired') + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + + $(tabsHTML) + .find('li:first a') + .on('hidden.bs.tab', function () { + ok(true, 'hidden event fired') + start() + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + test('should not fire hidden when hide is prevented', function () { + stop() + + var tabsHTML = '<ul class="tabs">' + + '<li><a href="#home">Home</a></li>' + + '<li><a href="#profile">Profile</a></li>' + + '</ul>' + + $(tabsHTML) + .find('li:first a') + .on('hide.bs.tab', function (e) { + e.preventDefault() + ok(true, 'hide event fired') + start() + }) + .on('hidden.bs.tab', function () { + ok(false, 'hidden event fired') + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + test('hide and hidden events contain correct relatedTarget', function () { + stop() + + var tabsHTML = '<ul class="tabs">' + + '<li><a href="#home">Home</a></li>' + + '<li><a href="#profile">Profile</a></li>' + + '</ul>' + + $(tabsHTML) + .find('li:first a') + .on('hide.bs.tab', function (e) { + equal(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget') + }) + .on('hidden.bs.tab', function (e) { + equal(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget') + start() + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + test('selected tab should have aria-expanded', function () { + var tabsHTML = '<ul class="nav nav-tabs">' + + '<li class="active"><a href="#home" toggle="tab" aria-expanded="true">Home</a></li>' + + '<li><a href="#profile" toggle="tab" aria-expanded="false">Profile</a></li>' + + '</ul>' + var $tabs = $(tabsHTML).appendTo('#qunit-fixture') + + $tabs.find('li:first a').bootstrapTab('show') + equal($tabs.find('.active a').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') + equal($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + + $tabs.find('li:last a').click() + equal($tabs.find('.active a').attr('aria-expanded'), 'true', 'after click, shown tab has aria-expanded = true') + equal($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'after click, hidden tab has aria-expanded = false') + + $tabs.find('li:first a').bootstrapTab('show') + equal($tabs.find('.active a').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') + equal($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + + $tabs.find('li:first a').click() + equal($tabs.find('.active a').attr('aria-expanded'), 'true', 'after second show event, shown tab still has aria-expanded = true') + equal($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'after second show event, hidden tab has aria-expanded = false') + }) + }) diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js index c75924e9f..351dd61cb 100644 --- a/js/tests/unit/tooltip.js +++ b/js/tests/unit/tooltip.js @@ -235,6 +235,37 @@ $(function () { equal($('.tooltip').length, 0, 'tooltip was removed from dom') }) + test('should show tooltips with different delegate selectors on the same node on click', function () { + var tooltipHTML = '<div>' + + '<a href="#" class="first" rel="tooltip" title="First delegated tooltip"/>' + + '<a href="#" class="second" rel="tooltip" title="Second delegated tooltip"/>' + + '</div>' + + var $div = $(tooltipHTML) + .append() + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + selector: 'a.first[rel="tooltip"]', + trigger: 'click' + }) + .bootstrapTooltip({ + selector: 'a.second[rel="tooltip"]', + trigger: 'click' + }) + + $div.find('a.first').click() + ok($('.tooltip').is('.fade.in'), 'first tooltip is faded in') + + $div.find('a.first').click() + equal($('.tooltip').length, 0, 'first tooltip was removed from dom') + + $div.find('a.second').click() + ok($('.tooltip').is('.fade.in'), 'second tooltip is faded in') + + $div.find('a.second').click() + equal($('.tooltip').length, 0, 'second tooltip was removed from dom') + }) + test('should show tooltip when toggle is called', function () { $('<a href="#" rel="tooltip" title="tooltip on toggle"/>') .appendTo('#qunit-fixture') @@ -382,6 +413,164 @@ $(function () { $style.remove() }) + test('should position tip on top if viewport has enough space and placement is "auto top"', function () { + var styles = '<style>' + + 'body { padding-top: 100px; }' + + '#section { height: 300px; border: 1px solid red; padding-top: 50px }' + + 'div[rel="tooltip"] { width: 150px; border: 1px solid blue; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="section"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'auto top', + viewport: '#section' + }) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + + test('should position tip on bottom if the tip\'s dimension exceeds the viewport area and placement is "auto top"', function () { + var styles = '<style>' + + 'body { padding-top: 100px; }' + + '#section { height: 300px; border: 1px solid red; }' + + 'div[rel="tooltip"] { width: 150px; border: 1px solid blue; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="section"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'auto top', + viewport: '#section' + }) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + + test('should display the tip on top whenever scrollable viewport has enough room if the given placement is "auto top"', function () { + var styles = '<style>' + + '#scrollable-div { height: 200px; overflow: auto; }' + + '.tooltip-item { margin: 200px 0 400px; width: 150px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'top auto', + viewport: '#scrollable-div' + }) + + $('#scrollable-div').scrollTop(100) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + + test('should display the tip on bottom whenever scrollable viewport doesn\'t have enough room if the given placement is "auto top"', function () { + var styles = '<style>' + + '#scrollable-div { height: 200px; overflow: auto; }' + + '.tooltip-item { padding: 200px 0 400px; width: 150px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'top auto', + viewport: '#scrollable-div' + }) + + $('#scrollable-div').scrollTop(200) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + + test('should display the tip on bottom whenever scrollable viewport has enough room if the given placement is "auto bottom"', function () { + var styles = '<style>' + + '#scrollable-div { height: 200px; overflow: auto; }' + + '.spacer { height: 400px; }' + + '.spacer:first-child { height: 200px; }' + + '.tooltip-item { width: 150px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>') + .appendTo($container) + .before('<div class="spacer"/>') + .after('<div class="spacer"/>') + .bootstrapTooltip({ + placement: 'bottom auto', + viewport: '#scrollable-div' + }) + + $('#scrollable-div').scrollTop(200) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + + test('should display the tip on top whenever scrollable viewport doesn\'t have enough room if the given placement is "auto bottom"', function () { + var styles = '<style>' + + '#scrollable-div { height: 200px; overflow: auto; }' + + '.tooltip-item { margin-top: 400px; width: 150px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div id="scrollable-div"/>').appendTo('#qunit-fixture') + var $target = $('<div rel="tooltip" title="tip" class="tooltip-item">Tooltip Item</div>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'bottom auto', + viewport: '#scrollable-div' + }) + + $('#scrollable-div').scrollTop(400) + + $target.bootstrapTooltip('show') + ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + + $target.bootstrapTooltip('hide') + equal($('.tooltip').length, 0, 'tooltip removed from dom') + + $styles.remove() + }) + test('should adjust the tip\'s top position when up against the top of the viewport', function () { var styles = '<style>' + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' @@ -609,7 +798,7 @@ $(function () { }, 0) }) - test('should show tooltip if leave event hasn\'t occured before delay expires', function () { + test('should show tooltip if leave event hasn\'t occurred before delay expires', function () { stop() var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') @@ -777,6 +966,47 @@ $(function () { $circle.bootstrapTooltip('show') }) + test('should correctly determine auto placement based on container rather than parent', function () { + stop() + + var styles = '<style>' + + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }' + + '.tooltip { position: absolute; display: block; font-size: 12px; line-height: 1.4; }' + + '.tooltip .tooltip-inner { max-width: 200px; padding: 3px 8px; font-family: Helvetica; text-align: center; }' + + '#trigger-parent {' + + ' position: fixed;' + + ' top: 100px;' + + ' right: 17px;' + + '}' + + '</style>' + var $styles = $(styles).appendTo('head') + + $('#qunit-fixture').append('<span id="trigger-parent"><a id="tt-trigger" title="If a_larger_text is written here, it won\'t fit using older broken version of BS">HOVER OVER ME</a></span>') + var $trigger = $('#tt-trigger') + + $trigger + .on('shown.bs.tooltip', function () { + var $tip = $('.tooltip-inner') + var tipXrightEdge = $tip.offset().left + $tip.width() + var triggerXleftEdge = $trigger.offset().left + ok(tipXrightEdge < triggerXleftEdge, 'tooltip with auto left placement, when near the right edge of the viewport, gets left placement') + $trigger.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + $styles.remove() + $(this).remove() + equal($('.tooltip').length, 0, 'tooltip removed from dom') + start() + }) + .bootstrapTooltip({ + container: 'body', + placement: 'auto left', + trigger: 'manual' + }) + + $trigger.bootstrapTooltip('show') + }) + test('should not reload the tooltip on subsequent mouseenter events', function () { var titleHtml = function () { var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip') @@ -859,6 +1089,7 @@ $(function () { .on('hidden.bs.tooltip', function () { $styles.remove() $(this).remove() + equal($('.tooltip').length, 0, 'tooltip removed from dom') start() }) .bootstrapTooltip({ @@ -869,4 +1100,42 @@ $(function () { .bootstrapTooltip('show') }) + test('should correctly position tooltips on transformed elements', function () { + var styleProps = document.documentElement.style + if (!('transform' in styleProps) && !('webkitTransform' in styleProps) && !('msTransform' in styleProps)) { + expect(0) + return + } + + stop() + + var styles = '<style>' + + '#qunit-fixture { top: 0; left: 0; }' + + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }' + + '.tooltip { position: absolute; }' + + '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }' + + '#target { position: absolute; top: 100px; left: 50px; width: 100px; height: 200px; -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); transform: rotate(270deg); }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $element = $('<div id="target" title="1"/>').appendTo('#qunit-fixture') + + $element + .on('shown.bs.tooltip', function () { + var offset = $('.tooltip').offset() + $styles.remove() + ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location') + ok(Math.abs(offset.top - 126) <= 1, 'tooltip has correct vertical location') + $element.bootstrapTooltip('hide') + start() + }) + .bootstrapTooltip({ + container: 'body', + placement: 'top', + trigger: 'manual' + }) + + $element.bootstrapTooltip('show') + }) + }) diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html index 455a4f571..6c7f52b2f 100644 --- a/js/tests/visual/dropdown.html +++ b/js/tests/visual/dropdown.html @@ -28,21 +28,21 @@ <li class="dropdown"> <a id="drop1" href="#" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a> <ul class="dropdown-menu" role="menu" aria-labelledby="drop1"> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Something else here</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Another action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Something else here</a></li> <li role="presentation" class="divider"></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Separated link</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Separated link</a></li> </ul> </li> <li class="dropdown"> <a href="#" id="drop2" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 2 <b class="caret"></b></a> <ul class="dropdown-menu" role="menu" aria-labelledby="drop2"> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Something else here</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Another action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Something else here</a></li> <li role="presentation" class="divider"></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Separated link</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Separated link</a></li> </ul> </li> </ul> @@ -50,11 +50,11 @@ <li id="fat-menu" class="dropdown"> <a href="#" id="drop3" role="button" class="dropdown-toggle" data-toggle="dropdown">Dropdown 3 <b class="caret"></b></a> <ul class="dropdown-menu" role="menu" aria-labelledby="drop3"> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Something else here</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Another action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Something else here</a></li> <li role="presentation" class="divider"></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Separated link</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Separated link</a></li> </ul> </li> </ul> @@ -67,21 +67,21 @@ <li class="dropdown"> <a id="drop4" role="button" data-toggle="dropdown" href="#">Dropdown <b class="caret"></b></a> <ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4"> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Something else here</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Another action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Something else here</a></li> <li role="presentation" class="divider"></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Separated link</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Separated link</a></li> </ul> </li> <li class="dropdown"> <a id="drop5" role="button" data-toggle="dropdown" href="#">Dropdown 2 <b class="caret"></b></a> <ul id="menu2" class="dropdown-menu" role="menu" aria-labelledby="drop5"> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Another action</a></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Something else here</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Another action</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Something else here</a></li> <li role="presentation" class="divider"></li> - <li role="presentation"><a role="menuitem" tabindex="-1" href="http://twitter.com/fat">Separated link</a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" href="https://twitter.com/fat">Separated link</a></li> </ul> </li> </ul> @@ -92,6 +92,7 @@ <script src="../vendor/jquery.min.js"></script> <script src="../../transition.js"></script> <script src="../../dropdown.js"></script> +<script src="../../collapse.js"></script> </body> </html> |
