diff options
Diffstat (limited to 'bootstrap/js/tests')
27 files changed, 6844 insertions, 0 deletions
diff --git a/bootstrap/js/tests/README.md b/bootstrap/js/tests/README.md new file mode 100755 index 0000000..9e3d7cc --- /dev/null +++ b/bootstrap/js/tests/README.md @@ -0,0 +1,61 @@ +## How does Bootstrap's test suite work? + +Bootstrap uses [QUnit](https://api.qunitjs.com/), a powerful, easy-to-use JavaScript unit test framework. Each plugin has a file dedicated to its tests in `unit/<plugin-name>.js`. + +* `unit/` contains the unit test files for each Bootstrap plugin. +* `vendor/` contains jQuery. +* `visual/` contains "visual" tests which are run interactively in real browsers and require manual verification by humans. + +To run our unit tests on a real web browser [Karma](https://karma-runner.github.io/2.0/index.html), run `grunt test-js` or you can +open `index.html`. + + +## How do I add a new unit test? + +1. Locate and open the file dedicated to the plugin which you need to add tests to (`unit/<plugin-name>.js`). +2. Review the [QUnit API Documentation](https://api.qunitjs.com/) and use the existing tests as references for how to structure your new tests. +3. Write the necessary unit test(s) for the new or revised functionality. +4. Run `grunt test-js` to see the results of your newly-added test(s). + +**Note:** Your new unit tests should fail before your changes are applied to the plugin, and should pass after your changes are applied to the plugin. + + +## What should a unit test look like? + +* Each test should have a unique name clearly stating what unit is being tested. +* Each test should test only one unit per test, although one test can include several assertions. Create multiple tests for multiple units of functionality. +* Each test should begin with [`assert.expect`](https://api.qunitjs.com/expect/) to ensure that the expected assertions are run. +* Each test should follow the project's [JavaScript Code Guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#js) + +### Example tests + +```javascript +// Synchronous test +QUnit.test('should describe the unit being tested', function (assert) { + assert.expect(1) + var templateHTML = '<div class="alert alert-danger fade in">' + + '<a class="close" href="#" data-dismiss="alert">×</a>' + + '<p><strong>Template necessary for the test.</p>' + + '</div>' + var $alert = $(templateHTML).appendTo('#qunit-fixture').bootstrapAlert() + + $alert.find('.close').click() + + // Make assertion + assert.strictEqual($alert.hasClass('in'), false, 'remove .in class on .close click') +}) + +// Asynchronous test +QUnit.test('should describe the unit being tested', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"></div>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + assert.ok(true, '"shown" event was fired after calling "show"') + done() + }) + .bootstrapTooltip('show') +}) +``` diff --git a/bootstrap/js/tests/index.html b/bootstrap/js/tests/index.html new file mode 100755 index 0000000..bb86baa --- /dev/null +++ b/bootstrap/js/tests/index.html @@ -0,0 +1,168 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Bootstrap Plugin Test Suite</title> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <!-- jQuery --> + <script src="vendor/jquery.min.js"></script> + <script> + // Disable jQuery event aliases to ensure we don't accidentally use any of them + (function () { + var eventAliases = [ + 'blur', + 'focus', + 'focusin', + 'focusout', + 'load', + 'resize', + 'scroll', + 'unload', + 'click', + 'dblclick', + 'mousedown', + 'mouseup', + 'mousemove', + 'mouseover', + 'mouseout', + 'mouseenter', + 'mouseleave', + 'change', + 'select', + 'submit', + 'keydown', + 'keypress', + 'keyup', + 'error', + 'contextmenu', + 'hover', + 'bind', + 'unbind', + 'delegate', + 'undelegate' + ] + for (var i = 0, len = eventAliases.length; i < len; i++) { + var eventAlias = eventAliases[i] + $.fn[eventAlias] = function () { + throw new Error('Using the ".' + eventAlias + '()" method is not allowed, so that Bootstrap can be compatible with custom jQuery builds which exclude the "event aliases" module that defines said method. See https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#js') + } + } + })() + </script> + + <!-- QUnit --> + <link rel="stylesheet" href="../../node_modules/qunitjs/qunit/qunit.css" media="screen"> + <script src="../../node_modules/qunitjs/qunit/qunit.js"></script> + <script> + // See https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit + var log = [] + // Require assert.expect in each test + QUnit.config.requireExpects = true + QUnit.done(function (testResults) { + var tests = [] + for (var i = 0, len = log.length; i < len; i++) { + var details = log[i] + tests.push({ + name: details.name, + result: details.result, + expected: details.expected, + actual: details.actual, + source: details.source + }) + } + testResults.tests = tests + + window.global_test_results = testResults + }) + + QUnit.testStart(function (testDetails) { + $(window).scrollTop(0) + QUnit.log(function (details) { + if (!details.result) { + details.name = testDetails.name + log.push(details) + } + }) + }) + + // Cleanup + QUnit.testDone(function () { + $('#qunit-fixture').empty() + $('#modal-test, .modal-backdrop').remove() + }) + + // Display fixture on-screen on iOS to avoid false positives + if (/iPhone|iPad|iPod/.test(navigator.userAgent)) { + QUnit.begin(function() { + $('#qunit-fixture').css({ top: 0, left: 0 }) + }) + + QUnit.done(function () { + $('#qunit-fixture').css({ top: '', left: '' }) + }) + } + + // Disable deprecated global QUnit method aliases in preparation for QUnit v2 + (function () { + var methodNames = [ + 'async', + 'asyncTest', + 'deepEqual', + 'equal', + 'expect', + 'module', + 'notDeepEqual', + 'notEqual', + 'notPropEqual', + 'notStrictEqual', + 'ok', + 'propEqual', + 'push', + 'start', + 'stop', + 'strictEqual', + 'test', + 'throws' + ]; + for (var i = 0, len = methodNames.length; i < len; i++) { + var methodName = methodNames[i]; + window[methodName] = undefined; + } + })(); + </script> + + <!-- Plugin sources --> + <script src="../../js/alert.js"></script> + <script src="../../js/button.js"></script> + <script src="../../js/carousel.js"></script> + <script src="../../js/collapse.js"></script> + <script src="../../js/dropdown.js"></script> + <script src="../../js/modal.js"></script> + <script src="../../js/scrollspy.js"></script> + <script src="../../js/tab.js"></script> + <script src="../../js/tooltip.js"></script> + <script src="../../js/popover.js"></script> + <script src="../../js/affix.js"></script> + + <!-- Unit tests --> + <script src="unit/alert.js"></script> + <script src="unit/button.js"></script> + <script src="unit/carousel.js"></script> + <script src="unit/collapse.js"></script> + <script src="unit/dropdown.js"></script> + <script src="unit/modal.js"></script> + <script src="unit/scrollspy.js"></script> + <script src="unit/tab.js"></script> + <script src="unit/tooltip.js"></script> + <script src="unit/popover.js"></script> + <script src="unit/affix.js"></script> + + </head> + <body> + <div id="qunit-container"> + <div id="qunit"></div> + <div id="qunit-fixture"></div> + </div> + </body> +</html> diff --git a/bootstrap/js/tests/unit/.jshintrc b/bootstrap/js/tests/unit/.jshintrc new file mode 100755 index 0000000..22e8785 --- /dev/null +++ b/bootstrap/js/tests/unit/.jshintrc @@ -0,0 +1,6 @@ +{ + "extends" : "../../.jshintrc", + "devel" : true, + "es3" : false, + "qunit" : true +} diff --git a/bootstrap/js/tests/unit/affix.js b/bootstrap/js/tests/unit/affix.js new file mode 100755 index 0000000..98dfb52 --- /dev/null +++ b/bootstrap/js/tests/unit/affix.js @@ -0,0 +1,123 @@ +$(function () { + 'use strict'; + + QUnit.module('affix plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).affix, 'affix method is defined') + }) + + QUnit.module('affix', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapAffix = $.fn.affix.noConflict() + }, + afterEach: function () { + $.fn.affix = $.fn.bootstrapAffix + delete $.fn.bootstrapAffix + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.affix, undefined, 'affix was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>').appendTo('#qunit-fixture') + var $affix = $el.bootstrapAffix() + assert.ok($affix instanceof $, 'returns jquery collection') + assert.strictEqual($affix[0], $el[0], 'collection contains element') + }) + + QUnit.test('should exit early if element is not visible', function (assert) { + assert.expect(1) + var $affix = $('<div style="display: none"/>') + .appendTo('#qunit-fixture') + .bootstrapAffix() + + $affix.data('bs.affix').checkPosition() + assert.ok(!$affix.hasClass('affix'), 'affix class was not added') + }) + + QUnit.test('should trigger affixed event after affix', function (assert) { + // Disable for iOS because of: https://bugs.webkit.org/show_bug.cgi?id=172854 + if (window.navigator.userAgent.match(/iPhone/i)) { + assert.expect(0) + return + } + + assert.expect(2) + var done = assert.async() + + var templateHTML = '<div id="affixTarget">' + + '<ul>' + + '<li>Please affix</li>' + + '<li>And unaffix</li>' + + '</ul>' + + '</div>' + + '<div id="affixAfter" style="height: 20000px; display: block;"/>' + $(templateHTML).appendTo(document.body) + + $('#affixTarget').bootstrapAffix({ + offset: $('#affixTarget ul').position() + }) + + $('#affixTarget') + .on('affix.bs.affix', function () { + assert.ok(true, 'affix event fired') + }).on('affixed.bs.affix', function () { + assert.ok(true, 'affixed event fired') + $('#affixTarget, #affixAfter').remove() + done() + }) + + setTimeout(function () { + window.scrollTo(0, document.body.scrollHeight - 5) + + // for testing in a browser + setTimeout(function () { + window.scroll(0, 0) + }, 150) + }, 0) + }) + + QUnit.test('should affix-top when scrolling up to offset when parent has padding', function (assert) { + // Disable for iOS because of: https://bugs.webkit.org/show_bug.cgi?id=172854 + if (window.navigator.userAgent.match(/iPhone/i)) { + assert.expect(0) + return + } + + assert.expect(1) + var done = assert.async() + + var templateHTML = '<div id="padding-offset" style="padding-top: 20px;">' + + '<div id="affixTopTarget">' + + '<p>Testing affix-top class is added</p>' + + '</div>' + + '<div style="height: 1000px; display: block;"/>' + + '</div>' + $(templateHTML).appendTo(document.body) + + $('#affixTopTarget') + .bootstrapAffix({ + offset: { top: 120, bottom: 0 } + }) + .on('affixed-top.bs.affix', function () { + assert.ok($('#affixTopTarget').hasClass('affix-top'), 'affix-top class applied') + $('#padding-offset').remove() + done() + }) + + setTimeout(function () { + window.scrollTo(0, document.body.scrollHeight - 5) + + setTimeout(function () { + window.scroll(0, 119) + }, 250) + }, 0) + }) +}) diff --git a/bootstrap/js/tests/unit/alert.js b/bootstrap/js/tests/unit/alert.js new file mode 100755 index 0000000..ef9bdf2 --- /dev/null +++ b/bootstrap/js/tests/unit/alert.js @@ -0,0 +1,83 @@ +$(function () { + 'use strict'; + + QUnit.module('alert plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).alert, 'alert method is defined') + }) + + QUnit.module('alert', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapAlert = $.fn.alert.noConflict() + }, + afterEach: function () { + $.fn.alert = $.fn.bootstrapAlert + delete $.fn.bootstrapAlert + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.alert, undefined, 'alert was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $alert = $el.bootstrapAlert() + assert.ok($alert instanceof $, 'returns jquery collection') + assert.strictEqual($alert[0], $el[0], 'collection contains element') + }) + + QUnit.test('should fade element out on clicking .close', function (assert) { + assert.expect(1) + var alertHTML = '<div class="alert alert-danger fade in">' + + '<a class="close" href="#" data-dismiss="alert">×</a>' + + '<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>' + + '</div>' + var $alert = $(alertHTML).bootstrapAlert() + + $alert.find('.close').trigger('click') + + assert.strictEqual($alert.hasClass('in'), false, 'remove .in class on .close click') + }) + + QUnit.test('should remove element when clicking .close', function (assert) { + assert.expect(2) + var done = assert.async() + + var alertHTML = '<div class="alert alert-danger fade in">' + + '<a class="close" href="#" data-dismiss="alert">×</a>' + + '<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>' + + '</div>' + var $alert = $(alertHTML).appendTo('#qunit-fixture').bootstrapAlert() + + assert.notEqual($('#qunit-fixture').find('.alert').length, 0, 'element added to dom') + + $alert.on('closed.bs.alert', function () { + assert.strictEqual($('#qunit-fixture').find('.alert').length, 0, 'element removed from dom') + done() + }) + + $alert.find('.close').trigger('click') + }) + + QUnit.test('should not fire closed when close is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + $('<div class="alert"/>') + .on('close.bs.alert', function (e) { + e.preventDefault() + assert.ok(true, 'close event fired') + done() + }) + .on('closed.bs.alert', function () { + assert.ok(false, 'closed event fired') + }) + .bootstrapAlert('close') + }) + +}) diff --git a/bootstrap/js/tests/unit/button.js b/bootstrap/js/tests/unit/button.js new file mode 100755 index 0000000..691796c --- /dev/null +++ b/bootstrap/js/tests/unit/button.js @@ -0,0 +1,168 @@ +$(function () { + 'use strict'; + + QUnit.module('button plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).button, 'button method is defined') + }) + + QUnit.module('button', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapButton = $.fn.button.noConflict() + }, + afterEach: function () { + $.fn.button = $.fn.bootstrapButton + delete $.fn.bootstrapButton + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.button, undefined, 'button was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $button = $el.bootstrapButton() + assert.ok($button instanceof $, 'returns jquery collection') + assert.strictEqual($button[0], $el[0], 'collection contains element') + }) + + QUnit.test('should return set state to loading', function (assert) { + assert.expect(4) + var $btn = $('<button class="btn" data-loading-text="fat">mdo</button>') + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + $btn.bootstrapButton('loading') + var done = assert.async() + setTimeout(function () { + assert.strictEqual($btn.html(), 'fat', 'btn text equals fat') + assert.ok($btn[0].hasAttribute('disabled'), 'btn is disabled') + assert.ok($btn.hasClass('disabled'), 'btn has disabled class') + done() + }, 0) + }) + + QUnit.test('should return reset state', function (assert) { + assert.expect(7) + var $btn = $('<button class="btn" data-loading-text="fat">mdo</button>') + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + $btn.bootstrapButton('loading') + var doneOne = assert.async() + setTimeout(function () { + assert.strictEqual($btn.html(), 'fat', 'btn text equals fat') + assert.ok($btn[0].hasAttribute('disabled'), 'btn is disabled') + assert.ok($btn.hasClass('disabled'), 'btn has disabled class') + doneOne() + var doneTwo = assert.async() + $btn.bootstrapButton('reset') + setTimeout(function () { + assert.strictEqual($btn.html(), 'mdo', 'btn text equals mdo') + assert.ok(!$btn[0].hasAttribute('disabled'), 'btn is not disabled') + assert.ok(!$btn.hasClass('disabled'), 'btn does not have disabled class') + doneTwo() + }, 0) + }, 0) + }) + + QUnit.test('should work with an empty string as reset state', function (assert) { + assert.expect(7) + var $btn = $('<button class="btn" data-loading-text="fat"/>') + assert.strictEqual($btn.html(), '', 'btn text equals ""') + $btn.bootstrapButton('loading') + var doneOne = assert.async() + setTimeout(function () { + assert.strictEqual($btn.html(), 'fat', 'btn text equals fat') + assert.ok($btn[0].hasAttribute('disabled'), 'btn is disabled') + assert.ok($btn.hasClass('disabled'), 'btn has disabled class') + doneOne() + var doneTwo = assert.async() + $btn.bootstrapButton('reset') + setTimeout(function () { + assert.strictEqual($btn.html(), '', 'btn text equals ""') + assert.ok(!$btn[0].hasAttribute('disabled'), 'btn is not disabled') + assert.ok(!$btn.hasClass('disabled'), 'btn does not have disabled class') + doneTwo() + }, 0) + }, 0) + }) + + QUnit.test('should toggle active', function (assert) { + assert.expect(2) + var $btn = $('<button class="btn" data-toggle="button">mdo</button>') + assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + $btn.bootstrapButton('toggle') + assert.ok($btn.hasClass('active'), 'btn has class active') + }) + + QUnit.test('should toggle active when btn children are clicked', function (assert) { + assert.expect(2) + var $btn = $('<button class="btn" data-toggle="button">mdo</button>') + var $inner = $('<i/>') + $btn + .append($inner) + .appendTo('#qunit-fixture') + assert.ok(!$btn.hasClass('active'), 'btn does not have active class') + $inner.trigger('click') + assert.ok($btn.hasClass('active'), 'btn has class active') + }) + + QUnit.test('should toggle aria-pressed', function (assert) { + assert.expect(2) + var $btn = $('<button class="btn" data-toggle="button" aria-pressed="false">redux</button>') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $btn.bootstrapButton('toggle') + assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + + QUnit.test('should toggle aria-pressed when btn children are clicked', function (assert) { + assert.expect(2) + var $btn = $('<button class="btn" data-toggle="button" aria-pressed="false">redux</button>') + var $inner = $('<i/>') + $btn + .append($inner) + .appendTo('#qunit-fixture') + assert.strictEqual($btn.attr('aria-pressed'), 'false', 'btn aria-pressed state is false') + $inner.trigger('click') + assert.strictEqual($btn.attr('aria-pressed'), 'true', 'btn aria-pressed state is true') + }) + + QUnit.test('should check for closest matching toggle', function (assert) { + assert.expect(12) + var groupHTML = '<div class="btn-group" data-toggle="buttons">' + + '<label class="btn btn-primary active">' + + '<input type="radio" name="options" id="option1" checked="true"> Option 1' + + '</label>' + + '<label class="btn btn-primary">' + + '<input type="radio" name="options" id="option2"> Option 2' + + '</label>' + + '<label class="btn btn-primary">' + + '<input type="radio" name="options" id="option3"> Option 3' + + '</label>' + + '</div>' + var $group = $(groupHTML).appendTo('#qunit-fixture') + + var $btn1 = $group.children().eq(0) + var $btn2 = $group.children().eq(1) + + assert.ok($btn1.hasClass('active'), 'btn1 has active class') + assert.ok($btn1.find('input').prop('checked'), 'btn1 is checked') + assert.ok(!$btn2.hasClass('active'), 'btn2 does not have active class') + assert.ok(!$btn2.find('input').prop('checked'), 'btn2 is not checked') + $btn2.find('input').trigger('click') + assert.ok(!$btn1.hasClass('active'), 'btn1 does not have active class') + assert.ok(!$btn1.find('input').prop('checked'), 'btn1 is not checked') + assert.ok($btn2.hasClass('active'), 'btn2 has active class') + assert.ok($btn2.find('input').prop('checked'), 'btn2 is checked') + + $btn2.find('input').trigger('click') // clicking an already checked radio should not un-check it + assert.ok(!$btn1.hasClass('active'), 'btn1 does not have active class') + assert.ok(!$btn1.find('input').prop('checked'), 'btn1 is not checked') + assert.ok($btn2.hasClass('active'), 'btn2 has active class') + assert.ok($btn2.find('input').prop('checked'), 'btn2 is checked') + }) + +}) diff --git a/bootstrap/js/tests/unit/carousel.js b/bootstrap/js/tests/unit/carousel.js new file mode 100755 index 0000000..39d2505 --- /dev/null +++ b/bootstrap/js/tests/unit/carousel.js @@ -0,0 +1,718 @@ +$(function () { + 'use strict'; + + QUnit.module('carousel plugin') + + QUnit.test('should be defined on jQuery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).carousel, 'carousel method is defined') + }) + + QUnit.module('carousel', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapCarousel = $.fn.carousel.noConflict() + }, + afterEach: function () { + $.fn.carousel = $.fn.bootstrapCarousel + delete $.fn.bootstrapCarousel + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.carousel, undefined, 'carousel was set back to undefined (orig value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $carousel = $el.bootstrapCarousel() + assert.ok($carousel instanceof $, 'returns jquery collection') + assert.strictEqual($carousel[0], $el[0], 'collection contains element') + }) + + QUnit.test('should not fire slid when slide is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + $('<div class="carousel"/>') + .on('slide.bs.carousel', function (e) { + e.preventDefault() + assert.ok(true, 'slide event fired') + done() + }) + .on('slid.bs.carousel', function () { + assert.ok(false, 'slid event fired') + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should reset when slide is prevented', function (assert) { + assert.expect(6) + var carouselHTML = '<div id="carousel-example-generic" class="carousel slide">' + + '<ol class="carousel-indicators">' + + '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + + '</ol>' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item">' + + '<div class="carousel-caption"/>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + + '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + + '</div>' + var $carousel = $(carouselHTML) + + var done = assert.async() + $carousel + .one('slide.bs.carousel', function (e) { + e.preventDefault() + setTimeout(function () { + assert.ok($carousel.find('.item:eq(0)').is('.active'), 'first item still active') + assert.ok($carousel.find('.carousel-indicators li:eq(0)').is('.active'), 'first indicator still active') + $carousel.bootstrapCarousel('next') + }, 0) + }) + .one('slid.bs.carousel', function () { + setTimeout(function () { + assert.ok(!$carousel.find('.item:eq(0)').is('.active'), 'first item still active') + assert.ok(!$carousel.find('.carousel-indicators li:eq(0)').is('.active'), 'first indicator still active') + assert.ok($carousel.find('.item:eq(1)').is('.active'), 'second item active') + assert.ok($carousel.find('.carousel-indicators li:eq(1)').is('.active'), 'second indicator active') + done() + }, 0) + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should fire slide event with direction', function (assert) { + assert.expect(4) + var carouselHTML = '<div id="myCarousel" class="carousel slide">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>First Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Second Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Third Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + var $carousel = $(carouselHTML) + + var done = assert.async() + + $carousel + .one('slide.bs.carousel', function (e) { + assert.ok(e.direction, 'direction present on next') + assert.strictEqual(e.direction, 'left', 'direction is left on next') + + $carousel + .one('slide.bs.carousel', function (e) { + assert.ok(e.direction, 'direction present on prev') + assert.strictEqual(e.direction, 'right', 'direction is right on prev') + done() + }) + .bootstrapCarousel('prev') + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should fire slid event with direction', function (assert) { + assert.expect(4) + var carouselHTML = '<div id="myCarousel" class="carousel slide">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>First Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Second Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Third Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + var $carousel = $(carouselHTML) + + var done = assert.async() + + $carousel + .one('slid.bs.carousel', function (e) { + assert.ok(e.direction, 'direction present on next') + assert.strictEqual(e.direction, 'left', 'direction is left on next') + + $carousel + .one('slid.bs.carousel', function (e) { + assert.ok(e.direction, 'direction present on prev') + assert.strictEqual(e.direction, 'right', 'direction is right on prev') + done() + }) + .bootstrapCarousel('prev') + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should fire slide event with relatedTarget', function (assert) { + assert.expect(2) + var template = '<div id="myCarousel" class="carousel slide">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>First Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Second Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Third Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + + var done = assert.async() + + $(template) + .on('slide.bs.carousel', function (e) { + assert.ok(e.relatedTarget, 'relatedTarget present') + assert.ok($(e.relatedTarget).hasClass('item'), 'relatedTarget has class "item"') + done() + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should fire slid event with relatedTarget', function (assert) { + assert.expect(2) + var template = '<div id="myCarousel" class="carousel slide">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>First Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Second Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Third Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + + var done = assert.async() + + $(template) + .on('slid.bs.carousel', function (e) { + assert.ok(e.relatedTarget, 'relatedTarget present') + assert.ok($(e.relatedTarget).hasClass('item'), 'relatedTarget has class "item"') + done() + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should set interval from data attribute', function (assert) { + assert.expect(4) + var templateHTML = '<div id="myCarousel" class="carousel slide">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>First Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Second Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '<div class="item">' + + '<img alt="">' + + '<div class="carousel-caption">' + + '<h4>Third Thumbnail label</h4>' + + '<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec ' + + 'id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ' + + 'ultricies vehicula ut id elit.</p>' + + '</div>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#myCarousel" data-slide="prev">‹</a>' + + '<a class="right carousel-control" href="#myCarousel" data-slide="next">›</a>' + + '</div>' + var $carousel = $(templateHTML) + $carousel.attr('data-interval', 1814) + + $carousel.appendTo('body') + $('[data-slide]').first().trigger('click') + assert.strictEqual($carousel.data('bs.carousel').options.interval, 1814) + $carousel.remove() + + $carousel.appendTo('body').attr('data-modal', 'foobar') + $('[data-slide]').first().trigger('click') + assert.strictEqual($carousel.data('bs.carousel').options.interval, 1814, 'even if there is an data-modal attribute set') + $carousel.remove() + + $carousel.appendTo('body') + $('[data-slide]').first().trigger('click') + $carousel.attr('data-interval', 1860) + $('[data-slide]').first().trigger('click') + assert.strictEqual($carousel.data('bs.carousel').options.interval, 1814, 'attributes should be read only on initialization') + $carousel.remove() + + $carousel.attr('data-interval', false) + $carousel.appendTo('body') + $carousel.bootstrapCarousel(1) + assert.strictEqual($carousel.data('bs.carousel').options.interval, false, 'data attribute has higher priority than default options') + $carousel.remove() + }) + + QUnit.test('should skip over non-items when using item indices', function (assert) { + assert.expect(2) + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="1814">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '</div>' + + '<script type="text/x-metamorph" id="thingy"/>' + + '<div class="item">' + + '<img alt="">' + + '</div>' + + '<div class="item">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + + $template.bootstrapCarousel() + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.bootstrapCarousel(1) + + assert.strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + }) + + QUnit.test('should skip over non-items when using next/prev methods', function (assert) { + assert.expect(2) + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="1814">' + + '<div class="carousel-inner">' + + '<div class="item active">' + + '<img alt="">' + + '</div>' + + '<script type="text/x-metamorph" id="thingy"/>' + + '<div class="item">' + + '<img alt="">' + + '</div>' + + '<div class="item">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + + $template.bootstrapCarousel() + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.bootstrapCarousel('next') + + assert.strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + }) + + QUnit.test('should go to previous item if left arrow key is pressed', function (assert) { + assert.expect(2) + 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() + + assert.strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + + $template.trigger($.Event('keydown', { which: 37 })) + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + }) + + QUnit.test('should go to next item if right arrow key is pressed', function (assert) { + assert.expect(2) + 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() + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.trigger($.Event('keydown', { which: 39 })) + + assert.strictEqual($template.find('.item')[1], $template.find('.active')[0], 'second item active') + }) + + QUnit.test('should support disabling the keyboard navigation', function (assert) { + assert.expect(3) + 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() + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + $template.trigger($.Event('keydown', { which: 39 })) + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after right arrow press') + + $template.trigger($.Event('keydown', { which: 37 })) + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after left arrow press') + }) + + QUnit.test('should ignore keyboard events within <input>s and <textarea>s', function (assert) { + assert.expect(7) + var templateHTML = '<div id="myCarousel" class="carousel" data-interval="false">' + + '<div class="carousel-inner">' + + '<div id="first" class="item active">' + + '<img alt="">' + + '<input type="text" id="in-put">' + + '<textarea id="text-area"></textarea>' + + '</div>' + + '<div id="second" class="item">' + + '<img alt="">' + + '</div>' + + '<div id="third" class="item">' + + '<img alt="">' + + '</div>' + + '</div>' + + '</div>' + var $template = $(templateHTML) + var $input = $template.find('#in-put') + var $textarea = $template.find('#text-area') + + assert.strictEqual($input.length, 1, 'found <input>') + assert.strictEqual($textarea.length, 1, 'found <textarea>') + + $template.bootstrapCarousel() + + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item active') + + + $input.trigger($.Event('keydown', { which: 39 })) + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after right arrow press in <input>') + + $input.trigger($.Event('keydown', { which: 37 })) + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after left arrow press in <input>') + + + $textarea.trigger($.Event('keydown', { which: 39 })) + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after right arrow press in <textarea>') + + $textarea.trigger($.Event('keydown', { which: 37 })) + assert.strictEqual($template.find('.item')[0], $template.find('.active')[0], 'first item still active after left arrow press in <textarea>') + }) + + QUnit.test('should only add mouseenter and mouseleave listeners when not on mobile', function (assert) { + assert.expect(2) + 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) { + assert.strictEqual(type in $._data($template[0], 'events'), !isMobile, 'does' + (isMobile ? ' not' : '') + ' listen for ' + type + ' events') + }) + }) + + QUnit.test('should wrap around from end to start when wrap option is true', function (assert) { + assert.expect(3) + var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="true">' + + '<ol class="carousel-indicators">' + + '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + + '</ol>' + + '<div class="carousel-inner">' + + '<div class="item active" id="one">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="two">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="three">' + + '<div class="carousel-caption"/>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + + '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + + '</div>' + var $carousel = $(carouselHTML) + var getActiveId = function () { return $carousel.find('.item.active').attr('id') } + + var done = assert.async() + + $carousel + .one('slid.bs.carousel', function () { + assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide') + $carousel + .one('slid.bs.carousel', function () { + assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide') + $carousel + .one('slid.bs.carousel', function () { + assert.strictEqual(getActiveId(), 'one', 'carousel wrapped around and slid from 3rd to 1st slide') + done() + }) + .bootstrapCarousel('next') + }) + .bootstrapCarousel('next') + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should wrap around from start to end when wrap option is true', function (assert) { + assert.expect(1) + var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="true">' + + '<ol class="carousel-indicators">' + + '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + + '</ol>' + + '<div class="carousel-inner">' + + '<div class="item active" id="one">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="two">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="three">' + + '<div class="carousel-caption"/>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + + '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + + '</div>' + var $carousel = $(carouselHTML) + + var done = assert.async() + + $carousel + .on('slid.bs.carousel', function () { + assert.strictEqual($carousel.find('.item.active').attr('id'), 'three', 'carousel wrapped around and slid from 1st to 3rd slide') + done() + }) + .bootstrapCarousel('prev') + }) + + QUnit.test('should stay at the end when the next method is called and wrap is false', function (assert) { + assert.expect(3) + var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="false">' + + '<ol class="carousel-indicators">' + + '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + + '</ol>' + + '<div class="carousel-inner">' + + '<div class="item active" id="one">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="two">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="three">' + + '<div class="carousel-caption"/>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + + '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + + '</div>' + var $carousel = $(carouselHTML) + var getActiveId = function () { return $carousel.find('.item.active').attr('id') } + + var done = assert.async() + + $carousel + .one('slid.bs.carousel', function () { + assert.strictEqual(getActiveId(), 'two', 'carousel slid from 1st to 2nd slide') + $carousel + .one('slid.bs.carousel', function () { + assert.strictEqual(getActiveId(), 'three', 'carousel slid from 2nd to 3rd slide') + $carousel + .one('slid.bs.carousel', function () { + assert.ok(false, 'carousel slid when it should not have slid') + }) + .bootstrapCarousel('next') + assert.strictEqual(getActiveId(), 'three', 'carousel did not wrap around and stayed on 3rd slide') + done() + }) + .bootstrapCarousel('next') + }) + .bootstrapCarousel('next') + }) + + QUnit.test('should stay at the start when the prev method is called and wrap is false', function (assert) { + assert.expect(1) + var carouselHTML = '<div id="carousel-example-generic" class="carousel slide" data-wrap="false">' + + '<ol class="carousel-indicators">' + + '<li data-target="#carousel-example-generic" data-slide-to="0" class="active"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="1"/>' + + '<li data-target="#carousel-example-generic" data-slide-to="2"/>' + + '</ol>' + + '<div class="carousel-inner">' + + '<div class="item active" id="one">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="two">' + + '<div class="carousel-caption"/>' + + '</div>' + + '<div class="item" id="three">' + + '<div class="carousel-caption"/>' + + '</div>' + + '</div>' + + '<a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"/>' + + '<a class="right carousel-control" href="#carousel-example-generic" data-slide="next"/>' + + '</div>' + var $carousel = $(carouselHTML) + + $carousel + .on('slid.bs.carousel', function () { + assert.ok(false, 'carousel slid when it should not have slid') + }) + .bootstrapCarousel('prev') + assert.strictEqual($carousel.find('.item.active').attr('id'), 'one', 'carousel did not wrap around and stayed on 1st slide') + }) +}) diff --git a/bootstrap/js/tests/unit/collapse.js b/bootstrap/js/tests/unit/collapse.js new file mode 100755 index 0000000..cd37689 --- /dev/null +++ b/bootstrap/js/tests/unit/collapse.js @@ -0,0 +1,447 @@ +$(function () { + 'use strict'; + + QUnit.module('collapse plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).collapse, 'collapse method is defined') + }) + + QUnit.module('collapse', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapCollapse = $.fn.collapse.noConflict() + }, + afterEach: function () { + $.fn.collapse = $.fn.bootstrapCollapse + delete $.fn.bootstrapCollapse + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.collapse, undefined, 'collapse was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $collapse = $el.bootstrapCollapse() + assert.ok($collapse instanceof $, 'returns jquery collection') + assert.strictEqual($collapse[0], $el[0], 'collection contains element') + }) + + QUnit.test('should show a collapsed element', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<div class="collapse"/>') + .on('shown.bs.collapse', function () { + assert.ok($(this).hasClass('in'), 'has class "in"') + assert.ok(!/height/i.test($(this).attr('style')), 'has height reset') + done() + }) + .bootstrapCollapse('show') + }) + + QUnit.test('should hide a collapsed element', function (assert) { + assert.expect(1) + var $el = $('<div class="collapse"/>').bootstrapCollapse('hide') + + assert.ok(!$el.hasClass('in'), 'does not have class "in"') + }) + + QUnit.test('should not fire shown when show is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div class="collapse"/>') + .on('show.bs.collapse', function (e) { + e.preventDefault() + assert.ok(true, 'show event fired') + done() + }) + .on('shown.bs.collapse', function () { + assert.ok(false, 'shown event fired') + }) + .bootstrapCollapse('show') + }) + + QUnit.test('should reset style to auto after finishing opening collapse', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<div class="collapse" style="height: 0px"/>') + .on('show.bs.collapse', function () { + assert.strictEqual(this.style.height, '0px', 'height is 0px') + }) + .on('shown.bs.collapse', function () { + assert.strictEqual(this.style.height, '', 'height is auto') + done() + }) + .bootstrapCollapse('show') + }) + + QUnit.test('should remove "collapsed" class from target when collapse is shown', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.ok(!$target.hasClass('collapsed'), 'target does not have collapsed class') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should add "collapsed" class to target when collapse is hidden', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hidden.bs.collapse', function () { + assert.ok($target.hasClass('collapsed'), 'target has collapsed class') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should remove "collapsed" class from all triggers targeting the collapse when the collapse is shown', function (assert) { + assert.expect(2) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture') + var $alt = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.ok(!$target.hasClass('collapsed'), 'target trigger does not have collapsed class') + assert.ok(!$alt.hasClass('collapsed'), 'alt trigger does not have collapsed class') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should add "collapsed" class to all triggers targeting the collapse when the collapse is hidden', function (assert) { + assert.expect(2) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture') + var $alt = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hidden.bs.collapse', function () { + assert.ok($target.hasClass('collapsed'), 'target has collapsed class') + assert.ok($alt.hasClass('collapsed'), 'alt trigger has collapsed class') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should not close a collapse when initialized with "show" option if already shown', function (assert) { + assert.expect(0) + var done = assert.async() + + var $test = $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hide.bs.collapse', function () { + assert.ok(false) + }) + + $test.bootstrapCollapse('show') + + setTimeout(done, 0) + }) + + QUnit.test('should open a collapse when initialized with "show" option if not already shown', function (assert) { + assert.expect(1) + var done = assert.async() + + var $test = $('<div id="test1" />') + .appendTo('#qunit-fixture') + .on('show.bs.collapse', function () { + assert.ok(true) + }) + + $test.bootstrapCollapse('show') + + setTimeout(done, 0) + }) + + QUnit.test('should not show a collapse when initialized with "hide" option if already hidden', function (assert) { + assert.expect(0) + var done = assert.async() + + $('<div class="collapse"></div>') + .appendTo('#qunit-fixture') + .on('show.bs.collapse', function () { + assert.ok(false, 'showing a previously-uninitialized hidden collapse when the "hide" method is called') + }) + .bootstrapCollapse('hide') + + setTimeout(done, 0) + }) + + QUnit.test('should hide a collapse when initialized with "hide" option if not already hidden', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div class="collapse in"></div>') + .appendTo('#qunit-fixture') + .on('hide.bs.collapse', function () { + assert.ok(true, 'hiding a previously-uninitialized shown collapse when the "hide" method is called') + }) + .bootstrapCollapse('hide') + + setTimeout(done, 0) + }) + + QUnit.test('should remove "collapsed" class from active accordion target', function (assert) { + assert.expect(3) + var done = assert.async() + + var accordionHTML = '<div class="panel-group" id="accordion">' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '</div>' + var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel') + + var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0)) + + $('<div id="body1" class="in"/>').appendTo($groups.eq(0)) + + var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1)) + + $('<div id="body2"/>').appendTo($groups.eq(1)) + + var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent="#accordion"/>').appendTo($groups.eq(2)) + + $('<div id="body3"/>') + .appendTo($groups.eq(2)) + .on('shown.bs.collapse', function () { + assert.ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"') + assert.ok($target2.hasClass('collapsed'), 'inactive target 2 does have class "collapsed"') + assert.ok(!$target3.hasClass('collapsed'), 'active target 3 does not have class "collapsed"') + + done() + }) + + $target3.trigger('click') + }) + + QUnit.test('should allow dots in data-parent', function (assert) { + assert.expect(3) + var done = assert.async() + + var accordionHTML = '<div class="panel-group accordion">' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '</div>' + var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel') + + var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent=".accordion"/>').appendTo($groups.eq(0)) + + $('<div id="body1" class="in"/>').appendTo($groups.eq(0)) + + var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" data-parent=".accordion"/>').appendTo($groups.eq(1)) + + $('<div id="body2"/>').appendTo($groups.eq(1)) + + var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent=".accordion"/>').appendTo($groups.eq(2)) + + $('<div id="body3"/>') + .appendTo($groups.eq(2)) + .on('shown.bs.collapse', function () { + assert.ok($target1.hasClass('collapsed'), 'inactive target 1 does have class "collapsed"') + assert.ok($target2.hasClass('collapsed'), 'inactive target 2 does have class "collapsed"') + assert.ok(!$target3.hasClass('collapsed'), 'active target 3 does not have class "collapsed"') + + done() + }) + + $target3.trigger('click') + }) + + QUnit.test('should set aria-expanded="true" on target when collapse is shown', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1" aria-expanded="false"/>').appendTo('#qunit-fixture') + + $('<div id="test1"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.strictEqual($target.attr('aria-expanded'), 'true', 'aria-expanded on target is "true"') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should set aria-expanded="false" on target when collapse is hidden', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" href="#test1" aria-expanded="true"/>').appendTo('#qunit-fixture') + + $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hidden.bs.collapse', function () { + assert.strictEqual($target.attr('aria-expanded'), 'false', 'aria-expanded on target is "false"') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should set aria-expanded="true" on all triggers targeting the collapse when the collapse is shown', function (assert) { + assert.expect(2) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1" aria-expanded="false"/>').appendTo('#qunit-fixture') + var $alt = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1" aria-expanded="false"/>').appendTo('#qunit-fixture') + + $('<div id="test1"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.strictEqual($target.attr('aria-expanded'), 'true', 'aria-expanded on target is "true"') + assert.strictEqual($alt.attr('aria-expanded'), 'true', 'aria-expanded on alt is "true"') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should set aria-expanded="false" on all triggers targeting the collapse when the collapse is hidden', function (assert) { + assert.expect(2) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" href="#test1" aria-expanded="true"/>').appendTo('#qunit-fixture') + var $alt = $('<a role="button" data-toggle="collapse" href="#test1" aria-expanded="true"/>').appendTo('#qunit-fixture') + + $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hidden.bs.collapse', function () { + assert.strictEqual($target.attr('aria-expanded'), 'false', 'aria-expanded on target is "false"') + assert.strictEqual($alt.attr('aria-expanded'), 'false', 'aria-expanded on alt is "false"') + done() + }) + + $target.trigger('click') + }) + + QUnit.test('should change aria-expanded from active accordion target to "false" and set the newly active one to "true"', function (assert) { + assert.expect(3) + var done = assert.async() + + var accordionHTML = '<div class="panel-group" id="accordion">' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '<div class="panel"/>' + + '</div>' + var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.panel') + + var $target1 = $('<a role="button" data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0)) + + $('<div id="body1" aria-expanded="true" class="in"/>').appendTo($groups.eq(0)) + + var $target2 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1)) + + $('<div id="body2" aria-expanded="false"/>').appendTo($groups.eq(1)) + + var $target3 = $('<a class="collapsed" data-toggle="collapse" role="button" href="#body3" data-parent="#accordion"/>').appendTo($groups.eq(2)) + + $('<div id="body3" aria-expanded="false"/>') + .appendTo($groups.eq(2)) + .on('shown.bs.collapse', function () { + assert.strictEqual($target1.attr('aria-expanded'), 'false', 'inactive target 1 has aria-expanded="false"') + assert.strictEqual($target2.attr('aria-expanded'), 'false', 'inactive target 2 has aria-expanded="false"') + assert.strictEqual($target3.attr('aria-expanded'), 'true', 'active target 3 has aria-expanded="false"') + + done() + }) + + $target3.trigger('click') + }) + + QUnit.test('should not fire show event if show is prevented because other element is still transitioning', function (assert) { + assert.expect(1) + var done = assert.async() + + 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 role="button" 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 role="button" data-toggle="collapse" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1)) + var $body2 = $('<div id="body2" class="collapse"/>').appendTo($groups.eq(1)) + + $target2.trigger('click') + + $body2 + .toggleClass('in collapsing') + .data('bs.collapse').transitioning = 1 + + $target1.trigger('click') + + setTimeout(function () { + assert.ok(!showFired, 'show event did not fire') + done() + }, 1) + }) + + QUnit.test('should add "collapsed" class to target when collapse is hidden via manual invocation', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1" class="in"/>') + .appendTo('#qunit-fixture') + .on('hidden.bs.collapse', function () { + assert.ok($target.hasClass('collapsed')) + done() + }) + .bootstrapCollapse('hide') + }) + + QUnit.test('should remove "collapsed" class from target when collapse is shown via manual invocation', function (assert) { + assert.expect(1) + var done = assert.async() + + var $target = $('<a role="button" data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture') + + $('<div id="test1"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.collapse', function () { + assert.ok(!$target.hasClass('collapsed')) + done() + }) + .bootstrapCollapse('show') + }) +}) diff --git a/bootstrap/js/tests/unit/dropdown.js b/bootstrap/js/tests/unit/dropdown.js new file mode 100755 index 0000000..747bf60 --- /dev/null +++ b/bootstrap/js/tests/unit/dropdown.js @@ -0,0 +1,454 @@ +$(function () { + 'use strict'; + + QUnit.module('dropdowns plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).dropdown, 'dropdown method is defined') + }) + + QUnit.module('dropdowns', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapDropdown = $.fn.dropdown.noConflict() + }, + afterEach: function () { + $.fn.dropdown = $.fn.bootstrapDropdown + delete $.fn.bootstrapDropdown + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.dropdown, undefined, 'dropdown was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $dropdown = $el.bootstrapDropdown() + assert.ok($dropdown instanceof $, 'returns jquery collection') + assert.strictEqual($dropdown[0], $el[0], 'collection contains element') + }) + + QUnit.test('should not open dropdown if target is disabled via attribute', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<button disabled href="#" class="btn dropdown-toggle" data-toggle="dropdown">Dropdown</button>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click') + + assert.ok(!$dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + }) + + QUnit.test('should set aria-expanded="true" on target when dropdown menu is shown', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + .trigger('click') + + assert.strictEqual($dropdown.attr('aria-expanded'), 'true', 'aria-expanded is set to string "true" on click') + }) + + QUnit.test('should set aria-expanded="false" on target when dropdown menu is hidden', function (assert) { + assert.expect(1) + var done = assert.async() + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" aria-expanded="false" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + $dropdown + .parent('.dropdown') + .on('hidden.bs.dropdown', function () { + assert.strictEqual($dropdown.attr('aria-expanded'), 'false', 'aria-expanded is set to string "false" on hide') + done() + }) + + $dropdown.trigger('click') + $(document.body).trigger('click') + }) + + QUnit.test('should not open dropdown if target is disabled via class', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<button href="#" class="btn dropdown-toggle disabled" data-toggle="dropdown">Dropdown</button>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click') + + assert.ok(!$dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + }) + + QUnit.test('should add class open to menu if clicked', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click') + + assert.ok($dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + }) + + QUnit.test('should test if element has a # before assuming it\'s a selector', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="/foo/" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML).find('[data-toggle="dropdown"]').bootstrapDropdown().trigger('click') + + assert.ok($dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + }) + + + QUnit.test('should remove "open" class if body is clicked', function (assert) { + assert.expect(2) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + .trigger('click') + + assert.ok($dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + $(document.body).trigger('click') + assert.ok(!$dropdown.parent('.dropdown').hasClass('open'), '"open" class removed') + }) + + QUnit.test('should remove "open" class if body is clicked, with multiple dropdowns', function (assert) { + assert.expect(7) + var dropdownHTML = '<ul class="nav">' + + '<li><a href="#menu1">Menu 1</a></li>' + + '<li class="dropdown" id="testmenu">' + + '<a class="dropdown-toggle" data-toggle="dropdown" href="#testmenu">Test menu <span class="caret"/></a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#sub1">Submenu 1</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + + '<div class="btn-group">' + + '<button class="btn">Actions</button>' + + '<button class="btn dropdown-toggle" data-toggle="dropdown"><span class="caret"/></button>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Action 1</a></li>' + + '</ul>' + + '</div>' + var $dropdowns = $(dropdownHTML).appendTo('#qunit-fixture').find('[data-toggle="dropdown"]') + var $first = $dropdowns.first() + var $last = $dropdowns.last() + + assert.strictEqual($dropdowns.length, 2, 'two dropdowns') + + $first.trigger('click') + assert.strictEqual($first.parents('.open').length, 1, '"open" class added on click') + assert.strictEqual($('#qunit-fixture .open').length, 1, 'only one dropdown is open') + $(document.body).trigger('click') + assert.strictEqual($('#qunit-fixture .open').length, 0, '"open" class removed') + + $last.trigger('click') + assert.strictEqual($last.parent('.open').length, 1, '"open" class added on click') + assert.strictEqual($('#qunit-fixture .open').length, 1, 'only one dropdown is open') + $(document.body).trigger('click') + assert.strictEqual($('#qunit-fixture .open').length, 0, '"open" class removed') + }) + + QUnit.test('should fire show and hide event', function (assert) { + assert.expect(2) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var done = assert.async() + + $dropdown + .parent('.dropdown') + .on('show.bs.dropdown', function () { + assert.ok(true, 'show was fired') + }) + .on('hide.bs.dropdown', function () { + assert.ok(true, 'hide was fired') + done() + }) + + $dropdown.trigger('click') + $(document.body).trigger('click') + }) + + + QUnit.test('should fire shown and hidden event', function (assert) { + assert.expect(2) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var done = assert.async() + + $dropdown + .parent('.dropdown') + .on('shown.bs.dropdown', function () { + assert.ok(true, 'shown was fired') + }) + .on('hidden.bs.dropdown', function () { + assert.ok(true, 'hidden was fired') + done() + }) + + $dropdown.trigger('click') + $(document.body).trigger('click') + }) + + QUnit.test('should fire shown and hidden event with a relatedTarget', function (assert) { + assert.expect(2) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + var done = assert.async() + + $dropdown.parent('.dropdown') + .on('hidden.bs.dropdown', function (e) { + assert.strictEqual(e.relatedTarget, $dropdown[0]) + done() + }) + .on('shown.bs.dropdown', function (e) { + assert.strictEqual(e.relatedTarget, $dropdown[0]) + $(document.body).trigger('click') + }) + + $dropdown.trigger('click') + }) + + QUnit.test('should ignore keyboard events within <input>s and <textarea>s', function (assert) { + assert.expect(3) + var done = assert.async() + + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#">Secondary link</a></li>' + + '<li><a href="#">Something else here</a></li>' + + '<li class="divider"/>' + + '<li><a href="#">Another link</a></li>' + + '<li><input type="text" id="input"></li>' + + '<li><textarea id="textarea"/></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + var $input = $('#input') + var $textarea = $('#textarea') + + $dropdown + .parent('.dropdown') + .on('shown.bs.dropdown', function () { + assert.ok(true, 'shown was fired') + + $input.trigger('focus').trigger($.Event('keydown', { which: 38 })) + assert.ok($(document.activeElement).is($input), 'input still focused') + + $textarea.trigger('focus').trigger($.Event('keydown', { which: 38 })) + assert.ok($(document.activeElement).is($textarea), 'textarea still focused') + + done() + }) + + $dropdown.trigger('click') + }) + + QUnit.test('should skip disabled element when using keyboard navigation', function (assert) { + assert.expect(1) + var dropdownHTML = '<ul class="tabs">' + + '<li class="dropdown">' + + '<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown</a>' + + '<ul class="dropdown-menu">' + + '<li class="disabled"><a href="#">Disabled link</a></li>' + + '<li><a href="#">Another link</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + .trigger('click') + + $dropdown.trigger($.Event('keydown', { which: 40 })) + $dropdown.trigger($.Event('keydown', { which: 40 })) + + assert.ok(!$(document.activeElement).parent().is('.disabled'), '.disabled is not focused') + }) + + QUnit.test('should not close the dropdown if the user clicks on a text field', function (assert) { + assert.expect(1) + var dropdownHTML = '<div class="btn-group">' + + '<button type="button" data-toggle="dropdown">Dropdown</button>' + + '<ul class="dropdown-menu">' + + '<li><input id="textField" type="text" /></li>' + + '</ul>' + + '</div>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + .trigger('click') + + $('#textField').trigger('click') + + assert.ok($dropdown.parent('.btn-group').hasClass('open'), 'dropdown menu is open') + }) + + QUnit.test('should not close the dropdown if the user clicks on a textarea', function (assert) { + assert.expect(1) + var dropdownHTML = '<div class="btn-group">' + + '<button type="button" data-toggle="dropdown">Dropdown</button>' + + '<ul class="dropdown-menu">' + + '<li><textarea id="textArea"></textarea></li>' + + '</ul>' + + '</div>' + var $dropdown = $(dropdownHTML) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + .trigger('click') + + $('#textArea').trigger('click') + + assert.ok($dropdown.parent('.btn-group').hasClass('open'), 'dropdown menu is open') + }) + + QUnit.test('should handle # in data-target', function (assert) { + assert.expect(1) + var done = assert.async() + + var html = [ + '<div class="dropdown">', + ' <a id="dLabel" data-target="#" href="http://example.com/" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">', + ' Dropdown trigger', + ' </a>', + ' <ul class="dropdown-menu" aria-labelledby="dLabel">', + ' <li><a href="/test">One</a></li>', + ' <li><a href="/test2">Two</a></li>', + ' </ul>', + '</div>' + ].join('') + + var $dropdown = $(html) + .appendTo('#qunit-fixture') + .find('[data-toggle="dropdown"]') + .bootstrapDropdown() + + $dropdown + .parent('.dropdown') + .on('shown.bs.dropdown', function () { + assert.ok($dropdown.parent('.dropdown').hasClass('open'), '"open" class added on click') + done() + }) + + $dropdown.trigger('click') + }) +}) diff --git a/bootstrap/js/tests/unit/modal.js b/bootstrap/js/tests/unit/modal.js new file mode 100755 index 0000000..a38d0fe --- /dev/null +++ b/bootstrap/js/tests/unit/modal.js @@ -0,0 +1,466 @@ +$(function () { + 'use strict'; + + QUnit.module('modal plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).modal, 'modal method is defined') + }) + + QUnit.module('modal', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapModal = $.fn.modal.noConflict() + }, + afterEach: function () { + $.fn.modal = $.fn.bootstrapModal + delete $.fn.bootstrapModal + $('#qunit-fixture').html('') + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.modal, undefined, 'modal was set back to undefined (orig value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div id="modal-test"/>').appendTo('#qunit-fixture') + var $modal = $el.bootstrapModal() + assert.ok($modal instanceof $, 'returns jquery collection') + assert.strictEqual($modal[0], $el[0], 'collection contains element') + }) + + QUnit.test('should expose defaults var for settings', function (assert) { + assert.expect(1) + assert.ok($.fn.bootstrapModal.Constructor.DEFAULTS, 'default object exposed') + }) + + QUnit.test('should insert into dom when show method is called', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div id="modal-test"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should fire show event', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div id="modal-test"/>') + .appendTo('#qunit-fixture') + .on('show.bs.modal', function () { + assert.ok(true, 'show event fired') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should not fire shown when show was prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div id="modal-test"/>') + .appendTo('#qunit-fixture') + .on('show.bs.modal', function (e) { + e.preventDefault() + assert.ok(true, 'show event fired') + done() + }) + .on('shown.bs.modal', function () { + assert.ok(false, 'shown event fired') + }) + .bootstrapModal('show') + }) + + QUnit.test('should hide modal when hide is called', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<div id="modal-test"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').is(':visible'), 'modal visible') + assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom') + $(this).bootstrapModal('hide') + }) + .on('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should toggle when toggle is called', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<div id="modal-test"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').is(':visible'), 'modal visible') + assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom') + $(this).bootstrapModal('toggle') + }) + .on('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('toggle') + }) + + QUnit.test('should remove from dom when click [data-dismiss="modal"]', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<div id="modal-test"><span class="close" data-dismiss="modal"/></div>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').is(':visible'), 'modal visible') + assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom') + $(this).find('.close').trigger('click') + }) + .on('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('toggle') + }) + + QUnit.test('should allow modal close with "backdrop:false"', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<div id="modal-test" data-backdrop="false"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').is(':visible'), 'modal visible') + $(this).bootstrapModal('hide') + }) + .on('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should close modal when clicking outside of modal-content', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<div id="modal-test"><div class="contents"/></div>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + assert.notEqual($('#modal-test').length, 0, 'modal inserted into dom') + $('.contents').trigger('click') + assert.ok($('#modal-test').is(':visible'), 'modal visible') + $('#modal-test').trigger('click') + }) + .on('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should close modal when escape key is pressed via keydown', function (assert) { + assert.expect(3) + var done = assert.async() + + var $div = $('<div id="modal-test"/>').appendTo('#qunit-fixture') + $div + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').length, 'modal inserted into dom') + assert.ok($('#modal-test').is(':visible'), 'modal visible') + $div.trigger($.Event('keydown', { which: 27 })) + + setTimeout(function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + $div.remove() + done() + }, 0) + }) + .bootstrapModal('show') + }) + + QUnit.test('should not close modal when escape key is pressed via keyup', function (assert) { + assert.expect(3) + var done = assert.async() + + var $div = $('<div id="modal-test"/>').appendTo('#qunit-fixture') + $div + .on('shown.bs.modal', function () { + assert.ok($('#modal-test').length, 'modal inserted into dom') + assert.ok($('#modal-test').is(':visible'), 'modal visible') + $div.trigger($.Event('keyup', { which: 27 })) + + setTimeout(function () { + assert.ok($div.is(':visible'), 'modal still visible') + $div.remove() + done() + }, 0) + }) + .bootstrapModal('show') + }) + + QUnit.test('should trigger hide event once when clicking outside of modal-content', function (assert) { + assert.expect(1) + var done = assert.async() + + var triggered + + $('<div id="modal-test"><div class="contents"/></div>') + .appendTo('#qunit-fixture') + .on('shown.bs.modal', function () { + triggered = 0 + $('#modal-test').trigger('click') + }) + .on('hide.bs.modal', function () { + triggered += 1 + assert.strictEqual(triggered, 1, 'modal hide triggered once') + done() + }) + .bootstrapModal('show') + }) + + QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>') + .appendTo('#qunit-fixture') + .one('shown.bs.modal', function () { + $('#close').trigger('click') + }) + .one('hidden.bs.modal', function () { + // after one open-close cycle + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + $(this) + .one('shown.bs.modal', function () { + $('#close').trigger('click') + }) + .one('hidden.bs.modal', function () { + assert.ok(!$('#modal-test').is(':visible'), 'modal hidden') + done() + }) + .bootstrapModal('show') + }) + .bootstrapModal('show') + }) + + QUnit.test('should restore focus to toggling element when modal is hidden after having been opened via data-api', function (assert) { + assert.expect(1) + var done = assert.async() + + var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture') + + $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div></div>') + .appendTo('#qunit-fixture') + .on('hidden.bs.modal', function () { + setTimeout(function () { + assert.ok($(document.activeElement).is($toggleBtn), 'toggling element is once again focused') + done() + }, 0) + }) + .on('shown.bs.modal', function () { + $('#close').trigger('click') + }) + .appendTo('#qunit-fixture') + + $toggleBtn.trigger('click') + }) + + QUnit.test('should not restore focus to toggling element if the associated show event gets prevented', function (assert) { + assert.expect(1) + var done = assert.async() + var $toggleBtn = $('<button data-toggle="modal" data-target="#modal-test"/>').appendTo('#qunit-fixture') + var $otherBtn = $('<button id="other-btn"/>').appendTo('#qunit-fixture') + + $('<div id="modal-test"><div class="contents"><div id="close" data-dismiss="modal"/></div>') + .appendTo('#qunit-fixture') + .one('show.bs.modal', function (e) { + e.preventDefault() + $otherBtn.trigger('focus') + setTimeout($.proxy(function () { + $(this).bootstrapModal('show') + }, this), 0) + }) + .on('hidden.bs.modal', function () { + setTimeout(function () { + assert.ok($(document.activeElement).is($otherBtn), 'focus returned to toggling element') + done() + }, 0) + }) + .on('shown.bs.modal', function () { + $('#close').trigger('click') + }) + .appendTo('#qunit-fixture') + + $toggleBtn.trigger('click') + }) + + QUnit.test('should restore inline body padding after closing', function (assert) { + assert.expect(2) + var done = assert.async() + var originalBodyPad = 0 + var $body = $(document.body) + + $body.css('padding-right', originalBodyPad) + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + var currentBodyPad = parseInt($body.css('padding-right'), 10) + assert.notStrictEqual($body.attr('style'), '', 'body has non-empty style attribute') + assert.strictEqual(currentBodyPad, originalBodyPad, 'original body padding was not changed') + $body.removeAttr('style') + done() + }) + .on('shown.bs.modal', function () { + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should ignore values set via CSS when trying to restore body padding after closing', function (assert) { + assert.expect(1) + var done = assert.async() + var $body = $(document.body) + var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head') + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + assert.ok(!$body.attr('style'), 'body does not have inline padding set') + $style.remove() + done() + }) + .on('shown.bs.modal', function () { + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should ignore other inline styles when trying to restore body padding after closing', function (assert) { + assert.expect(2) + var done = assert.async() + var $body = $(document.body) + var $style = $('<style>body { padding-right: 42px; }</style>').appendTo('head') + + $body.css('color', 'red') + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + assert.strictEqual($body[0].style.paddingRight, '', 'body does not have inline padding set') + assert.strictEqual($body[0].style.color, 'red', 'body still has other inline styles set') + $body.removeAttr('style') + $style.remove() + done() + }) + .on('shown.bs.modal', function () { + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should properly restore non-pixel inline body padding after closing', function (assert) { + assert.expect(1) + var done = assert.async() + var $body = $(document.body) + + $body.css('padding-right', '5%') + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + assert.strictEqual($body[0].style.paddingRight, '5%', 'body does not have inline padding set') + $body.removeAttr('style') + done() + }) + .on('shown.bs.modal', function () { + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should add padding-right of scrollbar width to .navbar-fixed-top and .navbar-fixed-bottom before open', function (assert) { + assert.expect(2) + var Modal = $.fn.bootstrapModal.Constructor + var done = assert.async() + var $body = $(document.body) + var scrollbarWidth + + // simulate overflow scroll + $body.css({ height: '2000px' }) + + var $fixedTop = $('<nav class="navbar navbar-fixed-top" />').appendTo($body) + var $fixedBottom = $('<nav class="navbar navbar-fixed-bottom" />').appendTo($body) + + // patch setScrollbar function to get scrollbar width + var setScrollbar = Modal.prototype.setScrollbar + Modal.prototype.setScrollbar = function () { + setScrollbar.call(this) + scrollbarWidth = this.scrollbarWidth + 'px' + } + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + $fixedTop.remove() + $fixedBottom.remove() + $body.removeAttr('style') + // restore original setScrollbar + Modal.prototype.setScrollbar = setScrollbar + done() + }) + .on('shown.bs.modal', function () { + var fixedTopPaddingRight = $fixedTop.css('padding-right') + var fixedBottomPaddingRight = $fixedBottom.css('padding-right') + + assert.strictEqual(scrollbarWidth, fixedTopPaddingRight, + '.navbar-fixed-top has padding-right (' + fixedTopPaddingRight + ') equal to scrollbar width (' + scrollbarWidth + ')') + + assert.strictEqual(scrollbarWidth, fixedBottomPaddingRight, + '.navbar-fixed-bottom has padding-right (' + fixedBottomPaddingRight + ') equal to scrollbar width (' + scrollbarWidth + ')') + + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) + + QUnit.test('should restore inline padding-right for .navbar-fixed-top and .navbar-fixed-bottom after close', function (assert) { + assert.expect(2) + var done = assert.async() + var $body = $(document.body) + + var $styleshhet = $('<link rel="stylesheet" href="../../dist/css/bootstrap.css" />').appendTo(document.head) + var $fixedTop = $('<nav class="navbar navbar-fixed-top" style="padding-right: 10px;" />').appendTo($body) + var $fixedBottom = $('<nav class="navbar navbar-fixed-bottom" style="padding-right: 5%;" />').appendTo($body) + + // simulate overflow scroll + $body.css({ height: '2000px' }) + + $('<div id="modal-test"/>') + .on('hidden.bs.modal', function () { + assert.strictEqual($fixedTop.css('padding-right'), '10px', + '.navbar-fixed-top has inline padding-right restored') + + assert.strictEqual($fixedBottom[0].style.paddingRight, '5%', + '.navbar-fixed-bottom has right padding-right restored') + + $fixedTop.remove() + $fixedBottom.remove() + $body.removeAttr('style') + $styleshhet.remove() + done() + }) + .on('shown.bs.modal', function () { + $(this).bootstrapModal('hide') + }) + .bootstrapModal('show') + }) +}) diff --git a/bootstrap/js/tests/unit/popover.js b/bootstrap/js/tests/unit/popover.js new file mode 100755 index 0000000..f8fd613 --- /dev/null +++ b/bootstrap/js/tests/unit/popover.js @@ -0,0 +1,338 @@ +$(function () { + 'use strict'; + + QUnit.module('popover plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).popover, 'popover method is defined') + }) + + QUnit.module('popover', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapPopover = $.fn.popover.noConflict() + }, + afterEach: function () { + $.fn.popover = $.fn.bootstrapPopover + delete $.fn.bootstrapPopover + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.popover, undefined, 'popover was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $popover = $el.bootstrapPopover() + assert.ok($popover instanceof $, 'returns jquery collection') + assert.strictEqual($popover[0], $el[0], 'collection contains element') + }) + + QUnit.test('should render popover element', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>') + .appendTo('#qunit-fixture') + .on('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + $(this).bootstrapPopover('hide') + }) + .on('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover removed') + done() + }) + .bootstrapPopover('show') + }) + + QUnit.test('should store popover instance in popover data object', function (assert) { + assert.expect(1) + var $popover = $('<a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a>').bootstrapPopover() + + assert.ok($popover.data('bs.popover'), 'popover instance exists') + }) + + QUnit.test('should store popover trigger in popover instance data object', function (assert) { + assert.expect(1) + var $popover = $('<a href="#" title="ResentedHook">@ResentedHook</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover() + + $popover.bootstrapPopover('show') + + assert.ok($('.popover').data('bs.popover'), 'popover trigger stored in instance data') + }) + + QUnit.test('should get title and content from options', function (assert) { + assert.expect(4) + var done = assert.async() + + var $popover = $('<a href="#">@fat</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + title: function () { + return '@fat' + }, + content: function () { + return 'loves writing tests (╯°□°)╯︵ ┻━┻' + } + }) + .on('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.strictEqual($('.popover .popover-title').text(), '@fat', 'title correctly inserted') + assert.strictEqual($('.popover .popover-content').text(), 'loves writing tests (╯°□°)╯︵ ┻━┻', 'content correctly inserted') + + $popover.bootstrapPopover('hide') + }) + .on('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + + $popover.bootstrapPopover('show') + }) + + QUnit.test('should not duplicate HTML object', function (assert) { + assert.expect(6) + var done = assert.async() + var $div = $('<div/>').html('loves writing tests (╯°□°)╯︵ ┻━┻') + + var $popover = $('<a href="#">@fat</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + content: function () { + return $div + } + }) + + $popover.one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.equal($('.popover .popover-content').html(), $div, 'content correctly inserted') + + $popover.one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + + $popover.one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.equal($('.popover .popover-content').html(), $div, 'content correctly inserted') + + $popover.one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + $popover.bootstrapPopover('hide') + }) + $popover.bootstrapPopover('show') + }) + + $popover.bootstrapPopover('hide') + }) + + $popover.bootstrapPopover('show') + }) + + QUnit.test('should get title and content from attributes', function (assert) { + assert.expect(4) + var done = assert.async() + + $('<a href="#" title="@mdo" data-content="loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻" >@mdo</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover() + .one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.strictEqual($('.popover .popover-title').text(), '@mdo', 'title correctly inserted') + assert.strictEqual($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted') + + $(this).bootstrapPopover('hide') + }) + .one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + .bootstrapPopover('show') + }) + + + QUnit.test('should get title and content from attributes ignoring options passed via js', function (assert) { + assert.expect(4) + var done = assert.async() + + $('<a href="#" title="@mdo" data-content="loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻" >@mdo</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + title: 'ignored title option', + content: 'ignored content option' + }) + .one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.strictEqual($('.popover .popover-title').text(), '@mdo', 'title correctly inserted') + assert.strictEqual($('.popover .popover-content').text(), 'loves data attributes (づ。◕‿‿◕。)づ ︵ ┻━┻', 'content correctly inserted') + + $(this).bootstrapPopover('hide') + }) + .one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + .bootstrapPopover('show') + }) + + QUnit.test('should respect custom template', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<a href="#">@fat</a>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + title: 'Test', + content: 'Test', + template: '<div class="popover foobar"><div class="arrow"></div><div class="inner"><h3 class="title"></h3><div class="content"><p></p></div></div></div>' + }) + .one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.ok($('.popover').hasClass('foobar'), 'custom class is present') + + $(this).bootstrapPopover('hide') + }) + .one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + .bootstrapPopover('show') + }) + + QUnit.test('should destroy popover', function (assert) { + assert.expect(7) + var $popover = $('<div/>') + .bootstrapPopover({ + trigger: 'hover' + }) + .on('click.foo', $.noop) + + assert.ok($popover.data('bs.popover'), 'popover has data') + assert.ok($._data($popover[0], 'events').mouseover && $._data($popover[0], 'events').mouseout, 'popover has hover event') + assert.strictEqual($._data($popover[0], 'events').click[0].namespace, 'foo', 'popover has extra click.foo event') + + $popover.bootstrapPopover('show') + $popover.bootstrapPopover('destroy') + + assert.ok(!$popover.hasClass('in'), 'popover is hidden') + assert.ok(!$popover.data('popover'), 'popover does not have data') + assert.strictEqual($._data($popover[0], 'events').click[0].namespace, 'foo', 'popover still has click.foo') + assert.ok(!$._data($popover[0], 'events').mouseover && !$._data($popover[0], 'events').mouseout, 'popover does not have any events') + }) + + QUnit.test('should render popover element using delegated selector', function (assert) { + assert.expect(2) + var done = assert.async() + + var $div = $('<div><a href="#" title="mdo" data-content="https://twitter.com/mdo">@mdo</a></div>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + selector: 'a', + trigger: 'click' + }) + + $div.one('shown.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + + $div.find('a').trigger('click') + }) + .one('hidden.bs.popover', function () { + assert.strictEqual($('.popover').length, 0, 'popover was removed') + done() + }) + $div.find('a').trigger('click') + }) + + QUnit.test('should detach popover content rather than removing it so that event handlers are left intact', function (assert) { + assert.expect(1) + var $content = $('<div class="content-with-handler"><a class="btn btn-warning">Button with event handler</a></div>').appendTo('#qunit-fixture') + + var handlerCalled = false + $('.content-with-handler .btn').on('click', function () { + handlerCalled = true + }) + + var $div = $('<div><a href="#">Show popover</a></div>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ + html: true, + trigger: 'manual', + container: 'body', + content: function () { + return $content + } + }) + + var done = assert.async() + $div + .one('shown.bs.popover', function () { + $div + .one('hidden.bs.popover', function () { + $div + .one('shown.bs.popover', function () { + $('.content-with-handler .btn').trigger('click') + $div.bootstrapPopover('destroy') + assert.ok(handlerCalled, 'content\'s event handler still present') + done() + }) + .bootstrapPopover('show') + }) + .bootstrapPopover('hide') + }) + .bootstrapPopover('show') + }) + + QUnit.test('should throw an error when initializing popover on the document object without specifying a delegation selector', function (assert) { + assert.expect(1) + assert.throws(function () { + $(document).bootstrapPopover({ title: 'What am I on?', content: 'My selector is missing' }) + }, new Error('`selector` option must be specified when initializing popover on the window.document object!')) + }) + + QUnit.test('should do nothing when an attempt is made to hide an uninitialized popover', function (assert) { + assert.expect(1) + + var $popover = $('<span data-toggle="popover" data-title="some title" data-content="some content">some text</span>') + .appendTo('#qunit-fixture') + .on('hidden.bs.popover shown.bs.popover', function () { + assert.ok(false, 'should not fire any popover events') + }) + .bootstrapPopover('hide') + assert.strictEqual($popover.data('bs.popover'), undefined, 'should not initialize the popover') + }) + + QUnit.test('should throw an error when template contains multiple top-level elements', function (assert) { + assert.expect(1) + assert.throws(function () { + $('<span data-toggle="popover" data-title="some title" data-content="some content">some text</span>') + .appendTo('#qunit-fixture') + .bootstrapPopover({ template: '<div>Foo</div><div>Bar</div>' }) + .bootstrapPopover('show') + }, new Error('popover `template` option must consist of exactly 1 top-level element!')) + }) + + QUnit.test('should fire inserted event', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#">@Johann-S</a>') + .appendTo('#qunit-fixture') + .on('inserted.bs.popover', function () { + assert.notEqual($('.popover').length, 0, 'popover was inserted') + assert.ok(true, 'inserted event fired') + done() + }) + .bootstrapPopover({ + title: 'Test', + content: 'Test' + }) + .bootstrapPopover('show') + }) + +}) diff --git a/bootstrap/js/tests/unit/scrollspy.js b/bootstrap/js/tests/unit/scrollspy.js new file mode 100755 index 0000000..be6808e --- /dev/null +++ b/bootstrap/js/tests/unit/scrollspy.js @@ -0,0 +1,278 @@ +$(function () { + 'use strict'; + + QUnit.module('scrollspy plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).scrollspy, 'scrollspy method is defined') + }) + + QUnit.module('scrollspy', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapScrollspy = $.fn.scrollspy.noConflict() + }, + afterEach: function () { + $.fn.scrollspy = $.fn.bootstrapScrollspy + delete $.fn.bootstrapScrollspy + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.scrollspy, undefined, 'scrollspy was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $scrollspy = $el.bootstrapScrollspy() + assert.ok($scrollspy instanceof $, 'returns jquery collection') + assert.strictEqual($scrollspy[0], $el[0], 'collection contains element') + }) + + QUnit.test('should only switch "active" class on current target', function (assert) { + assert.expect(1) + var done = assert.async() + + var sectionHTML = '<div id="root" class="active">' + + '<div class="topbar">' + + '<div class="topbar-inner">' + + '<div class="container" id="ss-target">' + + '<ul class="nav">' + + '<li><a href="#masthead">Overview</a></li>' + + '<li><a href="#detail">Detail</a></li>' + + '</ul>' + + '</div>' + + '</div>' + + '</div>' + + '<div id="scrollspy-example" style="height: 100px; overflow: auto;">' + + '<div style="height: 200px;">' + + '<h4 id="masthead">Overview</h4>' + + '<p style="height: 200px">' + + 'Ad leggings keytar, brunch id art party dolor labore.' + + '</p>' + + '</div>' + + '<div style="height: 200px;">' + + '<h4 id="detail">Detail</h4>' + + '<p style="height: 200px">' + + 'Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard.' + + '</p>' + + '</div>' + + '</div>' + + '</div>' + var $section = $(sectionHTML).appendTo('#qunit-fixture') + + var $scrollspy = $section + .show() + .find('#scrollspy-example') + .bootstrapScrollspy({ target: '#ss-target' }) + + $scrollspy.on('scroll.bs.scrollspy', function () { + assert.ok($section.hasClass('active'), '"active" class still on root node') + done() + }) + + $scrollspy.scrollTop(350) + }) + + QUnit.test('should correctly select middle navigation option when large offset is used', function (assert) { + assert.expect(3) + var done = assert.async() + + 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>' + + '<div id="content" style="height: 200px; overflow-y: auto;">' + + '<div id="one" style="height: 500px;"></div>' + + '<div id="two" style="height: 300px;"></div>' + + '<div id="three" style="height: 10px;"></div>' + + '</div>' + var $section = $(sectionHTML).appendTo('#qunit-fixture') + var $scrollspy = $section + .show() + .filter('#content') + + $scrollspy.bootstrapScrollspy({ target: '#navigation', offset: $scrollspy.position().top }) + + $scrollspy.on('scroll.bs.scrollspy', function () { + assert.ok(!$section.find('#one-link').parent().hasClass('active'), '"active" class removed from first section') + assert.ok($section.find('#two-link').parent().hasClass('active'), '"active" class on middle section') + assert.ok(!$section.find('#three-link').parent().hasClass('active'), '"active" class not on last section') + done() + }) + + $scrollspy.scrollTop(550) + }) + + QUnit.test('should add the active class to the correct element', function (assert) { + assert.expect(2) + var navbarHtml = + '<nav class="navbar">' + + '<ul class="nav">' + + '<li id="li-1"><a href="#div-1">div 1</a></li>' + + '<li id="li-2"><a href="#div-2">div 2</a></li>' + + '</ul>' + + '</nav>' + var contentHtml = + '<div class="content" style="overflow: auto; height: 50px">' + + '<div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>' + + '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>' + + '</div>' + + $(navbarHtml).appendTo('#qunit-fixture') + var $content = $(contentHtml) + .appendTo('#qunit-fixture') + .bootstrapScrollspy({ offset: 0, target: '.navbar' }) + + var done = assert.async() + var testElementIsActiveAfterScroll = function (element, target) { + var deferred = $.Deferred() + var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top) + $content.one('scroll', function () { + assert.ok($(element).hasClass('active'), 'target:' + target + ', element' + element) + deferred.resolve() + }) + $content.scrollTop(scrollHeight) + return deferred.promise() + } + + $.when(testElementIsActiveAfterScroll('#li-1', '#div-1')) + .then(function () { return testElementIsActiveAfterScroll('#li-2', '#div-2') }) + .then(function () { done() }) + }) + + QUnit.test('should add the active class correctly when there are nested elements at 0 scroll offset', function (assert) { + assert.expect(6) + var times = 0 + var done = assert.async() + var navbarHtml = '<nav id="navigation" class="navbar">' + + '<ul class="nav">' + + '<li id="li-1"><a href="#div-1">div 1</a>' + + '<ul>' + + '<li id="li-2"><a href="#div-2">div 2</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + + '</nav>' + + var contentHtml = '<div class="content" style="position: absolute; top: 0px; overflow: auto; height: 50px">' + + '<div id="div-1" style="padding: 0; margin: 0">' + + '<div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>' + + '</div>' + + '</div>' + + $(navbarHtml).appendTo('#qunit-fixture') + + var $content = $(contentHtml) + .appendTo('#qunit-fixture') + .bootstrapScrollspy({ offset: 0, target: '#navigation' }) + + !function testActiveElements() { + if (++times > 3) return done() + + $content.one('scroll', function () { + assert.ok($('#li-1').hasClass('active'), 'nav item for outer element has "active" class') + assert.ok($('#li-2').hasClass('active'), 'nav item for inner element has "active" class') + testActiveElements() + }) + + $content.scrollTop($content.scrollTop() + 10) + }() + }) + + QUnit.test('should clear selection if above the first section', function (assert) { + assert.expect(3) + var done = assert.async() + + 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 () { + assert.strictEqual($('.active').length, 1, '"active" class on only one element present') + assert.strictEqual($('.active').has('#two-link').length, 1, '"active" class on second section') + + $scrollspy + .one('scroll.bs.scrollspy', function () { + assert.strictEqual($('.active').length, 0, 'selection cleared') + done() + }) + .scrollTop(0) + }) + .scrollTop(201) + }) + + QUnit.test('should correctly select navigation element on backward scrolling when each target section height is 100%', function (assert) { + assert.expect(5) + var navbarHtml = + '<nav class="navbar">' + + '<ul class="nav">' + + '<li id="li-100-1"><a href="#div-100-1">div 1</a></li>' + + '<li id="li-100-2"><a href="#div-100-2">div 2</a></li>' + + '<li id="li-100-3"><a href="#div-100-3">div 3</a></li>' + + '<li id="li-100-4"><a href="#div-100-4">div 4</a></li>' + + '<li id="li-100-5"><a href="#div-100-5">div 5</a></li>' + + '</ul>' + + '</nav>' + var contentHtml = + '<div class="content" style="position: relative; overflow: auto; height: 100px">' + + '<div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>' + + '<div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>' + + '<div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>' + + '<div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>' + + '<div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>' + + '</div>' + + $(navbarHtml).appendTo('#qunit-fixture') + var $content = $(contentHtml) + .appendTo('#qunit-fixture') + .bootstrapScrollspy({ offset: 0, target: '.navbar' }) + + var testElementIsActiveAfterScroll = function (element, target) { + var deferred = $.Deferred() + var scrollHeight = Math.ceil($content.scrollTop() + $(target).position().top) + $content.one('scroll', function () { + assert.ok($(element).hasClass('active'), 'target:' + target + ', element: ' + element) + deferred.resolve() + }) + $content.scrollTop(scrollHeight) + return deferred.promise() + } + + var done = assert.async() + $.when(testElementIsActiveAfterScroll('#li-100-5', '#div-100-5')) + .then(function () { return testElementIsActiveAfterScroll('#li-100-4', '#div-100-4') }) + .then(function () { return testElementIsActiveAfterScroll('#li-100-3', '#div-100-3') }) + .then(function () { return testElementIsActiveAfterScroll('#li-100-2', '#div-100-2') }) + .then(function () { return testElementIsActiveAfterScroll('#li-100-1', '#div-100-1') }) + .then(function () { done() }) + }) + +}) diff --git a/bootstrap/js/tests/unit/tab.js b/bootstrap/js/tests/unit/tab.js new file mode 100755 index 0000000..83bdd67 --- /dev/null +++ b/bootstrap/js/tests/unit/tab.js @@ -0,0 +1,216 @@ +$(function () { + 'use strict'; + + QUnit.module('tabs plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).tab, 'tabs method is defined') + }) + + QUnit.module('tabs', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapTab = $.fn.tab.noConflict() + }, + afterEach: function () { + $.fn.tab = $.fn.bootstrapTab + delete $.fn.bootstrapTab + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.tab, undefined, 'tab was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>') + var $tab = $el.bootstrapTab() + assert.ok($tab instanceof $, 'returns jquery collection') + assert.strictEqual($tab[0], $el[0], 'collection contains element') + }) + + QUnit.test('should activate element by tab id', function (assert) { + assert.expect(2) + var tabsHTML = '<ul class="tabs">' + + '<li><a href="#home">Home</a></li>' + + '<li><a href="#profile">Profile</a></li>' + + '</ul>' + + $('<ul><li id="home"/><li id="profile"/></ul>').appendTo('#qunit-fixture') + + $(tabsHTML).find('li:last a').bootstrapTab('show') + assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile') + + $(tabsHTML).find('li:first a').bootstrapTab('show') + assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home') + }) + + QUnit.test('should activate element by tab id', function (assert) { + assert.expect(2) + var pillsHTML = '<ul class="pills">' + + '<li><a href="#home">Home</a></li>' + + '<li><a href="#profile">Profile</a></li>' + + '</ul>' + + $('<ul><li id="home"/><li id="profile"/></ul>').appendTo('#qunit-fixture') + + $(pillsHTML).find('li:last a').bootstrapTab('show') + assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile') + + $(pillsHTML).find('li:first a').bootstrapTab('show') + assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home') + }) + + QUnit.test('should not fire shown when show is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div class="tab"/>') + .on('show.bs.tab', function (e) { + e.preventDefault() + assert.ok(true, 'show event fired') + done() + }) + .on('shown.bs.tab', function () { + assert.ok(false, 'shown event fired') + }) + .bootstrapTab('show') + }) + + QUnit.test('show and shown events should reference correct relatedTarget', function (assert) { + assert.expect(2) + var done = assert.async() + + var dropHTML = '<ul class="drop">' + + '<li class="dropdown"><a data-toggle="dropdown" href="#">1</a>' + + '<ul class="dropdown-menu">' + + '<li><a href="#1-1" data-toggle="tab">1-1</a></li>' + + '<li><a href="#1-2" data-toggle="tab">1-2</a></li>' + + '</ul>' + + '</li>' + + '</ul>' + + $(dropHTML) + .find('ul > li:first a') + .bootstrapTab('show') + .end() + .find('ul > li:last a') + .on('show.bs.tab', function (e) { + assert.strictEqual(e.relatedTarget.hash, '#1-1', 'references correct element as relatedTarget') + }) + .on('shown.bs.tab', function (e) { + assert.strictEqual(e.relatedTarget.hash, '#1-1', 'references correct element as relatedTarget') + done() + }) + .bootstrapTab('show') + }) + + QUnit.test('should fire hide and hidden events', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 () { + assert.ok(true, 'hide event fired') + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + + $(tabsHTML) + .find('li:first a') + .on('hidden.bs.tab', function () { + assert.ok(true, 'hidden event fired') + done() + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + QUnit.test('should not fire hidden when hide is prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + 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() + assert.ok(true, 'hide event fired') + done() + }) + .on('hidden.bs.tab', function () { + assert.ok(false, 'hidden event fired') + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + QUnit.test('hide and hidden events contain correct relatedTarget', function (assert) { + assert.expect(2) + var done = assert.async() + + 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) { + assert.strictEqual(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget') + }) + .on('hidden.bs.tab', function (e) { + assert.strictEqual(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget') + done() + }) + .bootstrapTab('show') + .end() + .find('li:last a') + .bootstrapTab('show') + }) + + QUnit.test('selected tab should have aria-expanded', function (assert) { + assert.expect(8) + 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') + assert.strictEqual($tabs.find('.active a').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') + assert.strictEqual($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + + $tabs.find('li:last a').trigger('click') + assert.strictEqual($tabs.find('.active a').attr('aria-expanded'), 'true', 'after click, shown tab has aria-expanded = true') + assert.strictEqual($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') + assert.strictEqual($tabs.find('.active a').attr('aria-expanded'), 'true', 'shown tab has aria-expanded = true') + assert.strictEqual($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'hidden tab has aria-expanded = false') + + $tabs.find('li:first a').trigger('click') + assert.strictEqual($tabs.find('.active a').attr('aria-expanded'), 'true', 'after second show event, shown tab still has aria-expanded = true') + assert.strictEqual($tabs.find('li:not(.active) a').attr('aria-expanded'), 'false', 'after second show event, hidden tab has aria-expanded = false') + }) + +}) diff --git a/bootstrap/js/tests/unit/tooltip.js b/bootstrap/js/tests/unit/tooltip.js new file mode 100755 index 0000000..d26224f --- /dev/null +++ b/bootstrap/js/tests/unit/tooltip.js @@ -0,0 +1,1709 @@ +$(function () { + 'use strict'; + + QUnit.module('tooltip plugin') + + QUnit.test('should be defined on jquery object', function (assert) { + assert.expect(1) + assert.ok($(document.body).tooltip, 'tooltip method is defined') + }) + + QUnit.module('tooltip', { + beforeEach: function () { + // Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode + $.fn.bootstrapTooltip = $.fn.tooltip.noConflict() + }, + afterEach: function () { + $.fn.tooltip = $.fn.bootstrapTooltip + delete $.fn.bootstrapTooltip + $('#qunit-fixture').html('') + } + }) + + QUnit.test('should provide no conflict', function (assert) { + assert.expect(1) + assert.strictEqual($.fn.tooltip, undefined, 'tooltip was set back to undefined (org value)') + }) + + QUnit.test('should return jquery collection containing the element', function (assert) { + assert.expect(2) + var $el = $('<div/>').appendTo('#qunit-fixture') + var $tooltip = $el.bootstrapTooltip() + assert.ok($tooltip instanceof $, 'returns jquery collection') + assert.strictEqual($tooltip[0], $el[0], 'collection contains element') + }) + + QUnit.test('should expose default settings', function (assert) { + assert.expect(1) + assert.ok($.fn.bootstrapTooltip.Constructor.DEFAULTS, 'defaults is defined') + }) + + QUnit.test('should empty title attribute', function (assert) { + assert.expect(1) + var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip() + + assert.strictEqual($trigger.attr('title'), '', 'title attribute was emptied') + }) + + QUnit.test('should add data attribute for referencing original title', function (assert) { + assert.expect(1) + var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip() + + assert.strictEqual($trigger.attr('data-original-title'), 'Another tooltip', 'original title preserved in data attribute') + }) + + QUnit.test('should add aria-describedby to the trigger on show', function (assert) { + assert.expect(3) + var done = assert.async() + + var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + + $trigger + .bootstrapTooltip() + .on('shown.bs.tooltip', function () { + var id = $('.tooltip').attr('id') + + assert.strictEqual($('#' + id).length, 1, 'has a unique id') + assert.strictEqual($('.tooltip').attr('aria-describedby'), $trigger.attr('id'), 'tooltip id and aria-describedby on trigger match') + assert.ok($trigger[0].hasAttribute('aria-describedby'), 'trigger has aria-describedby') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should remove aria-describedby from trigger on hide', function (assert) { + assert.expect(2) + var done = assert.async() + + var $trigger = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .bootstrapTooltip() + .appendTo('#qunit-fixture') + + $trigger.one('shown.bs.tooltip', function () { + assert.ok($trigger[0].hasAttribute('aria-describedby'), 'trigger has aria-describedby') + $trigger.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.ok(!$trigger[0].hasAttribute('aria-describedby'), 'trigger does not have aria-describedby') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should assign a unique id tooltip element', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + var id = $('.tooltip').attr('id') + + assert.strictEqual($('#' + id).length, 1, 'tooltip has unique id') + assert.strictEqual(id.indexOf('tooltip'), 0, 'tooltip id has prefix') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should place tooltips relative to placement option', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + $tooltip.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed') + done() + }) + .bootstrapTooltip({ placement: 'bottom' }) + + $tooltip.bootstrapTooltip('show') + }) + + QUnit.test('should allow html entities', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="<b>@fat</b>"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ html: true }) + + $tooltip.one('shown.bs.tooltip', function () { + assert.notEqual($('.tooltip b').length, 0, 'b tag was inserted') + $tooltip.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should respect custom classes', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ template: '<div class="tooltip some-class"><div class="tooltip-arrow"/><div class="tooltip-inner"/></div>' }) + + $tooltip.one('shown.bs.tooltip', function () { + assert.ok($('.tooltip').hasClass('some-class'), 'custom class is present') + $tooltip.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should fire show event', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"/>') + .on('show.bs.tooltip', function () { + assert.ok(true, 'show event fired') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should fire inserted event', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<div title="tooltip title"/>') + .appendTo('#qunit-fixture') + .on('inserted.bs.tooltip', function () { + assert.notEqual($('.tooltip').length, 0, 'tooltip was inserted') + assert.ok(true, 'inserted event fired') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should fire shown event', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"></div>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + assert.ok(true, 'shown was called') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should not fire shown event when show was prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"/>') + .on('show.bs.tooltip', function (e) { + e.preventDefault() + assert.ok(true, 'show event fired') + done() + }) + .on('shown.bs.tooltip', function () { + assert.ok(false, 'shown event fired') + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should fire hide event', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + $(this).bootstrapTooltip('hide') + }) + .on('hide.bs.tooltip', function () { + assert.ok(true, 'hide event fired') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should fire hidden event', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + $(this).bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.ok(true, 'hidden event fired') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should not fire hidden event when hide was prevented', function (assert) { + assert.expect(1) + var done = assert.async() + + $('<div title="tooltip title"/>') + .appendTo('#qunit-fixture') + .on('shown.bs.tooltip', function () { + $(this).bootstrapTooltip('hide') + }) + .on('hide.bs.tooltip', function (e) { + e.preventDefault() + assert.ok(true, 'hide event fired') + done() + }) + .on('hidden.bs.tooltip', function () { + assert.ok(false, 'hidden event fired') + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should destroy tooltip', function (assert) { + assert.expect(7) + var $tooltip = $('<div/>') + .bootstrapTooltip() + .on('click.foo', function () {}) + + assert.ok($tooltip.data('bs.tooltip'), 'tooltip has data') + assert.ok($._data($tooltip[0], 'events').mouseover && $._data($tooltip[0], 'events').mouseout, 'tooltip has hover events') + assert.strictEqual($._data($tooltip[0], 'events').click[0].namespace, 'foo', 'tooltip has extra click.foo event') + + $tooltip.bootstrapTooltip('show') + $tooltip.bootstrapTooltip('destroy') + + assert.ok(!$tooltip.hasClass('in'), 'tooltip is hidden') + assert.ok(!$._data($tooltip[0], 'bs.tooltip'), 'tooltip does not have data') + assert.strictEqual($._data($tooltip[0], 'events').click[0].namespace, 'foo', 'tooltip still has click.foo') + assert.ok(!$._data($tooltip[0], 'events').mouseover && !$._data($tooltip[0], 'events').mouseout, 'tooltip does not have hover events') + }) + + QUnit.test('should show tooltip with delegate selector on click', function (assert) { + assert.expect(2) + var done = assert.async() + + var $div = $('<div><a href="#" rel="tooltip" title="Another tooltip"/></div>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + selector: 'a[rel="tooltip"]', + trigger: 'click' + }) + + $div.one('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.in'), 'tooltip is faded in') + $div.find('a').trigger('click') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip was removed from dom') + done() + }) + + $div.find('a').trigger('click') + }) + + QUnit.test('should show tooltip when toggle is called', function (assert) { + assert.expect(1) + $('<a href="#" rel="tooltip" title="tooltip on toggle"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ trigger: 'manual' }) + .bootstrapTooltip('toggle') + + assert.ok($('.tooltip').is('.fade.in'), 'tooltip is faded in') + }) + + QUnit.test('should hide previously shown tooltip when toggle is called on tooltip', function (assert) { + assert.expect(1) + $('<a href="#" rel="tooltip" title="tooltip on toggle">@ResentedHook</a>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ trigger: 'manual' }) + .bootstrapTooltip('show') + + $('.tooltip').bootstrapTooltip('toggle') + assert.ok($('.tooltip').not('.fade.in'), 'tooltip was faded out') + }) + + QUnit.test('should place tooltips inside body when container is body', function (assert) { + assert.expect(3) + var done = assert.async() + + $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ container: 'body' }) + .one('shown.bs.tooltip', function () { + assert.notEqual($('body > .tooltip').length, 0, 'tooltip is direct descendant of body') + assert.strictEqual($('#qunit-fixture > .tooltip').length, 0, 'tooltip is not in parent') + + $(this).bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('body > .tooltip').length, 0, 'tooltip was removed from dom') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should add position class before positioning so that position-specific styles are taken into account', function (assert) { + assert.expect(1) + var styles = '<style>' + + '.tooltip.right { white-space: nowrap; }' + + '.tooltip.right .tooltip-inner { max-width: none; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div/>').appendTo('#qunit-fixture') + var $target = $('<a href="#" rel="tooltip" title="very very very very very very very very long tooltip in one line"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'right', + viewport: null + }) + .bootstrapTooltip('show') + var $tooltip = $container.find('.tooltip') + + // this is some dumb hack shit because sub pixels in firefox + var top = Math.round($target.offset().top + ($target[0].offsetHeight / 2) - ($tooltip[0].offsetHeight / 2)) + var top2 = Math.round($tooltip.offset().top) + var topDiff = top - top2 + assert.ok(topDiff <= 1 && topDiff >= -1) + $target.bootstrapTooltip('hide') + + $container.remove() + $styles.remove() + }) + + QUnit.test('should use title attribute for tooltip text', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#" rel="tooltip" title="Simple tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip() + .one('shown.bs.tooltip', function () { + assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title from title attribute is set') + + $(this).bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip('show') + + }) + + QUnit.test('should prefer title attribute over title option', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#" rel="tooltip" title="Simple tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + title: 'This is a tooltip with some content' + }) + .one('shown.bs.tooltip', function () { + assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'Simple tooltip', 'title is set from title attribute while preferred over title option') + $(this).bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should use title option', function (assert) { + assert.expect(2) + var done = assert.async() + + $('<a href="#" rel="tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + title: 'This is a tooltip with some content' + }) + .one('shown.bs.tooltip', function () { + assert.strictEqual($('.tooltip').children('.tooltip-inner').text(), 'This is a tooltip with some content', 'title from title option is set') + $(this).bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should be placed dynamically to viewport with the dynamic placement option', function (assert) { + assert.expect(6) + var done = assert.async() + + var $style = $('<style> div[rel="tooltip"] { position: absolute; } #qunit-fixture { top: inherit; left: inherit } </style>').appendTo('head') + var $container = $('<div/>') + .css({ + position: 'relative', + height: '100%' + }) + .appendTo('#qunit-fixture') + + var $topTooltip = $('<div style="left: 0; top: 0;" rel="tooltip" title="Top tooltip">Top Dynamic Tooltip</div>') + .appendTo($container) + .bootstrapTooltip({ placement: 'auto', viewport: '#qunit-fixture' }) + + var topDone = false + var rightDone = false + var leftDone = false + + function isDone() { + if (topDone && rightDone && leftDone) { + $container.remove() + $style.remove() + done() + } + } + + function leftTooltip() { + var $leftTooltip = $('<div style="left: 0;" rel="tooltip" title="Left tooltip">Left Dynamic Tooltip</div>') + .appendTo($container) + .bootstrapTooltip({ placement: 'auto left', viewport: '#qunit-fixture' }) + + $leftTooltip + .one('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.right'), 'left positioned tooltip is dynamically positioned right') + $leftTooltip.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'left positioned tooltip removed from dom') + leftDone = true + isDone() + }) + .bootstrapTooltip('show') + } + + function rightTooltip() { + var $rightTooltip = $('<div style="right: 0;" rel="tooltip" title="Right tooltip">Right Dynamic Tooltip</div>') + .appendTo($container) + .bootstrapTooltip({ placement: 'right auto', viewport: '#qunit-fixture' }) + + $rightTooltip + .one('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.in'), 'right positioned tooltip is dynamically positioned left') + $rightTooltip.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'right positioned tooltip removed from dom') + rightDone = true + leftTooltip() + }) + .bootstrapTooltip('show') + } + + $topTooltip + .one('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom') + $topTooltip.bootstrapTooltip('hide') + }) + .one('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'top positioned tooltip removed from dom') + topDone = true + rightTooltip() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should position tip on top if viewport has enough space and placement is "auto top"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should position tip on top if viewport has enough space and is not parent', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '#section { height: 300px; border: 1px solid red; margin-top: 100px; }' + + '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: '#qunit-fixture' + }) + + $target + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.top'), 'top positioned tooltip is dynamically positioned to top') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should position tip on bottom if the tip\'s dimension exceeds the viewport area and placement is "auto top"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.bottom'), 'top positioned tooltip is dynamically positioned to bottom') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should display the tip on top whenever scrollable viewport has enough room if the given placement is "auto top"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should display the tip on bottom whenever scrollable viewport doesn\'t have enough room if the given placement is "auto top"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should display the tip on bottom whenever scrollable viewport has enough room if the given placement is "auto bottom"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.bottom.in'), 'has correct classes applied') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should display the tip on top whenever scrollable viewport doesn\'t have enough room if the given placement is "auto bottom"', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + .on('shown.bs.tooltip', function () { + assert.ok($('.tooltip').is('.fade.top.in'), 'has correct classes applied') + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should adjust the tip\'s top position when up against the top of the viewport', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div/>').appendTo('#qunit-fixture') + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; left: 0px;"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'right', + viewport: { + selector: 'body', + padding: 12 + } + }) + + $target + .on('shown.bs.tooltip', function () { + assert.strictEqual(Math.round($container.find('.tooltip').offset().top), 12) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should adjust the tip\'s top position when up against the bottom of the viewport', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div/>').appendTo('#qunit-fixture') + var $target = $('<a href="#" rel="tooltip" title="tip" style="bottom: 0px; left: 0px;"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'right', + viewport: { + selector: 'body', + padding: 12 + } + }) + + $target + .on('shown.bs.tooltip', function () { + var $tooltip = $container.find('.tooltip') + var padding = 50 + var result = Math.round($tooltip.offset().top) + var resultMax = result + padding + var resultMin = result - padding + var expected = Math.round($(window).height() - 12 - $tooltip[0].offsetHeight) + + assert.ok(expected < resultMax && expected > resultMin) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should adjust the tip\'s left position when up against the left of the viewport', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div/>').appendTo('#qunit-fixture') + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; left: 0px;"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'bottom', + viewport: { + selector: 'body', + padding: 12 + } + }) + + $target + .on('shown.bs.tooltip', function () { + assert.strictEqual(Math.round($container.find('.tooltip').offset().left), 12) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should adjust the tip\'s left position when up against the right of the viewport', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div/>').appendTo('body') + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 0px; right: 0px;"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'bottom', + viewport: { + selector: 'body', + padding: 12 + } + }) + + $target + .on('shown.bs.tooltip', function () { + var $tooltip = $container.find('.tooltip') + assert.strictEqual(Math.round($tooltip.offset().left), Math.round($(window).width() - 12 - $tooltip[0].offsetWidth)) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should adjust the tip when up against the right of an arbitrary viewport', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip, .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + '.container-viewport { position: absolute; top: 50px; left: 60px; width: 300px; height: 300px; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div class="container-viewport"/>').appendTo(document.body) + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 50px; left: 350px;"/>') + .appendTo($container) + .bootstrapTooltip({ + placement: 'bottom', + viewport: '.container-viewport' + }) + + $target + .on('shown.bs.tooltip', function () { + var $tooltip = $container.find('.tooltip') + assert.strictEqual(Math.round($tooltip.offset().left), Math.round(60 + $container.width() - $tooltip[0].offsetWidth)) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should get viewport element from function', function (assert) { + assert.expect(3) + var done = assert.async() + + var styles = '<style>' + + '.tooltip, .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; }' + + '.container-viewport { position: absolute; top: 50px; left: 60px; width: 300px; height: 300px; }' + + 'a[rel="tooltip"] { position: fixed; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div class="container-viewport"/>').appendTo(document.body) + var $target = $('<a href="#" rel="tooltip" title="tip" style="top: 50px; left: 350px;"/>').appendTo($container) + $target + .bootstrapTooltip({ + placement: 'bottom', + viewport: function ($element) { + assert.strictEqual($element[0], $target[0], 'viewport function was passed target as argument') + return ($element.closest('.container-viewport')) + } + }) + + $target + .on('shown.bs.tooltip', function () { + var $tooltip = $container.find('.tooltip') + assert.strictEqual(Math.round($tooltip.offset().left), Math.round(60 + $container.width() - $tooltip[0].offsetWidth)) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should not misplace the tip when the right edge offset is greater or equal than the viewport width', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }' + + '.container-viewport, .container-viewport *, .container-viewport *:before, .container-viewport *:after { box-sizing: border-box; }' + + '.tooltip, .tooltip .tooltip-inner { width: 50px; height: 50px; max-width: none; background: red; }' + + '.container-viewport { padding: 100px; margin-left: 100px; width: 100px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + var $container = $('<div class="container-viewport"/>').appendTo(document.body) + var $target = $('<a href="#" rel="tooltip" title="tip">foobar</a>') + .appendTo($container) + .bootstrapTooltip({ + viewport: '.container-viewport' + }) + + $target + .on('shown.bs.tooltip', function () { + var $tooltip = $container.find('.tooltip') + var expected = Math.round($target.position().left + $target.width() / 2 - $tooltip[0].offsetWidth / 2) + var result = Math.round($tooltip.offset().left) + assert.ok(result === (expected - 1) || result === expected) + $target.bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + $container.remove() + $styles.remove() + done() + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should not error when trying to show an auto-placed tooltip that has been removed from the dom', function (assert) { + assert.expect(1) + var passed = true + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .one('show.bs.tooltip', function () { + $(this).remove() + }) + .bootstrapTooltip({ placement: 'auto' }) + + try { + $tooltip.bootstrapTooltip('show') + } catch (err) { + passed = false + console.log(err) + } + + assert.ok(passed, '.tooltip(\'show\') should not throw an error if element no longer is in dom') + }) + + QUnit.test('should place tooltip on top of element', function (assert) { + assert.expect(1) + var done = assert.async() + + var containerHTML = '<div>' + + '<p style="margin-top: 200px">' + + '<a href="#" title="very very very very very very very long tooltip">Hover me</a>' + + '</p>' + + '</div>' + + var $container = $(containerHTML) + .css({ + position: 'absolute', + bottom: 0, + left: 0, + textAlign: 'right', + width: 300, + height: 300 + }) + .appendTo('#qunit-fixture') + + var $trigger = $container + .find('a') + .css('margin-top', 200) + .bootstrapTooltip({ + placement: 'top', + animate: false + }) + .bootstrapTooltip('show') + + var $tooltip = $container.find('.tooltip') + + setTimeout(function () { + assert.ok(Math.round($tooltip.offset().top + $tooltip.outerHeight()) <= Math.round($trigger.offset().top)) + done() + }, 0) + }) + + QUnit.test('should place tooltip inside viewport', function (assert) { + assert.expect(1) + var done = assert.async() + + var $container = $('<div/>') + .css({ + position: 'absolute', + width: 200, + height: 200, + bottom: 0, + left: 0 + }) + .appendTo('#qunit-fixture') + + $('<a href="#" title="Very very very very very very very very long tooltip">Hover me</a>') + .css({ + position: 'absolute', + top: 0, + left: 0 + }) + .appendTo($container) + .bootstrapTooltip({ + placement: 'top' + }) + .bootstrapTooltip('show') + + setTimeout(function () { + assert.ok($('.tooltip').offset().left >= 0) + done() + }, 0) + }) + + QUnit.test('should show tooltip if leave event hasn\'t occurred before delay expires', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: 150 }) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip is not faded in') + }, 100) + + setTimeout(function () { + assert.ok($('.tooltip').is('.fade.in'), '200ms: tooltip is faded in') + done() + }, 200) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should not show tooltip if leave event occurs before delay expires', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: 150 }) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in') + $tooltip.trigger('mouseout') + }, 100) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '200ms: tooltip not faded in') + done() + }, 200) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should not hide tooltip if leave event occurs and enter event occurs within the hide delay', function (assert) { + assert.expect(3) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: { show: 0, hide: 150 }}) + + setTimeout(function () { + assert.ok($('.tooltip').is('.fade.in'), '1ms: tooltip faded in') + $tooltip.trigger('mouseout') + + setTimeout(function () { + assert.ok($('.tooltip').is('.fade.in'), '100ms: tooltip still faded in') + $tooltip.trigger('mouseenter') + }, 100) + + setTimeout(function () { + assert.ok($('.tooltip').is('.fade.in'), '200ms: tooltip still faded in') + done() + }, 200) + }, 0) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should not show tooltip if leave event occurs before delay expires', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: 150 }) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in') + $tooltip.trigger('mouseout') + }, 100) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '200ms: tooltip not faded in') + done() + }, 200) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should not show tooltip if leave event occurs before delay expires, even if hide delay is 0', function (assert) { + assert.expect(2) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: { show: 150, hide: 0 }}) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '100ms: tooltip not faded in') + $tooltip.trigger('mouseout') + }, 100) + + setTimeout(function () { + assert.ok(!$('.tooltip').is('.fade.in'), '250ms: tooltip not faded in') + done() + }, 250) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should wait 200ms before hiding the tooltip', function (assert) { + if (window.__karma__) { + assert.expect(0) + return + } + + assert.expect(3) + var done = assert.async() + + var $tooltip = $('<a href="#" rel="tooltip" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ delay: { show: 0, hide: 150 }}) + + setTimeout(function () { + assert.ok($tooltip.data('bs.tooltip').$tip.is('.fade.in'), '1ms: tooltip faded in') + + $tooltip.trigger('mouseout') + + setTimeout(function () { + assert.ok($tooltip.data('bs.tooltip').$tip.is('.fade.in'), '100ms: tooltip still faded in') + }, 100) + + setTimeout(function () { + assert.ok(!$tooltip.data('bs.tooltip').$tip.is('.in'), '200ms: tooltip removed') + done() + }, 200) + + }, 0) + + $tooltip.trigger('mouseenter') + }) + + QUnit.test('should correctly position tooltips on SVG elements', function (assert) { + if (!window.SVGElement) { + // Skip IE8 since it doesn't support SVG + assert.expect(0) + return + } + assert.expect(2) + + var done = assert.async() + + var styles = '<style>' + + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }' + + '.tooltip { position: absolute; }' + + '.tooltip .tooltip-inner { width: 24px; height: 24px; font-family: Helvetica; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + $('#qunit-fixture').append( + '<div style="position: fixed; top: 0; left: 0;">' + + ' <svg width="200" height="200">' + + ' <circle cx="100" cy="100" r="10" title="m" id="theCircle" />' + + ' </svg>' + + '</div>') + var $circle = $('#theCircle') + + $circle + .on('shown.bs.tooltip', function () { + var offset = $('.tooltip').offset() + $styles.remove() + assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location') + $circle.bootstrapTooltip('hide') + + }) + .on('hidden.bs.tooltip', function () { + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip({ container: 'body', placement: 'top', trigger: 'manual' }) + + $circle.bootstrapTooltip('show') + }) + + QUnit.test('should correctly determine auto placement based on container rather than parent', function (assert) { + assert.expect(2) + var done = assert.async() + + 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 + assert.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() + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip({ + container: 'body', + placement: 'auto left', + trigger: 'manual' + }) + + $trigger.bootstrapTooltip('show') + }) + + QUnit.test('should not reload the tooltip on subsequent mouseenter events', function (assert) { + assert.expect(1) + var titleHtml = function () { + var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip') + return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>' + } + + var $tooltip = $('<span id="tt-outer" rel="tooltip" data-trigger="hover" data-placement="top">some text</span>') + .appendTo('#qunit-fixture') + + $tooltip.bootstrapTooltip({ + html: true, + animation: false, + trigger: 'hover', + delay: { show: 0, hide: 500 }, + container: $tooltip, + title: titleHtml + }) + + $('#tt-outer').trigger('mouseenter') + + var currentUid = $('#tt-content').text() + + $('#tt-content').trigger('mouseenter') + assert.strictEqual(currentUid, $('#tt-content').text()) + }) + + QUnit.test('should not reload the tooltip if the mouse leaves and re-enters before hiding', function (assert) { + assert.expect(4) + var titleHtml = function () { + var uid = $.fn.bootstrapTooltip.Constructor.prototype.getUID('tooltip') + return '<p id="tt-content">' + uid + '</p><p>' + uid + '</p><p>' + uid + '</p>' + } + + var $tooltip = $('<span id="tt-outer" rel="tooltip" data-trigger="hover" data-placement="top">some text</span>') + .appendTo('#qunit-fixture') + + $tooltip.bootstrapTooltip({ + html: true, + animation: false, + trigger: 'hover', + delay: { show: 0, hide: 500 }, + container: $tooltip, + title: titleHtml + }) + + var obj = $tooltip.data('bs.tooltip') + + $('#tt-outer').trigger('mouseenter') + + var currentUid = $('#tt-content').text() + + $('#tt-outer').trigger('mouseleave') + assert.strictEqual(currentUid, $('#tt-content').text()) + + assert.ok(obj.hoverState == 'out', 'the tooltip hoverState should be set to "out"') + + $('#tt-content').trigger('mouseenter') + assert.ok(obj.hoverState == 'in', 'the tooltip hoverState should be set to "in"') + + assert.strictEqual(currentUid, $('#tt-content').text()) + }) + + QUnit.test('should position arrow correctly when tooltip is moved to not appear offscreen', function (assert) { + assert.expect(2) + var done = assert.async() + + var styles = '<style>' + + '.tooltip, .tooltip *, .tooltip *:before, .tooltip *:after { box-sizing: border-box; }' + + '.tooltip { position: absolute; }' + + '.tooltip-arrow { position: absolute; width: 0; height: 0; }' + + '.tooltip .tooltip-inner { max-width: 200px; padding: 3px 8px; }' + + '</style>' + var $styles = $(styles).appendTo('head') + + $('<a href="#" title="tooltip title" style="position: absolute; bottom: 0; right: 0;">Foobar</a>') + .appendTo('body') + .on('shown.bs.tooltip', function () { + var arrowStyles = $(this).data('bs.tooltip').$tip.find('.tooltip-arrow').attr('style') + assert.ok(/left/i.test(arrowStyles) && !/top/i.test(arrowStyles), 'arrow positioned correctly') + $(this).bootstrapTooltip('hide') + }) + .on('hidden.bs.tooltip', function () { + $styles.remove() + $(this).remove() + assert.strictEqual($('.tooltip').length, 0, 'tooltip removed from dom') + done() + }) + .bootstrapTooltip({ + container: 'body', + placement: 'top', + trigger: 'manual' + }) + .bootstrapTooltip('show') + }) + + QUnit.test('should correctly position tooltips on transformed elements', function (assert) { + var styleProps = document.documentElement.style + if ((!('transform' in styleProps) && !('webkitTransform' in styleProps) && !('msTransform' in styleProps)) || window.__karma__) { + assert.expect(0) + return + } + + assert.expect(2) + + var done = assert.async() + + 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() + assert.ok(Math.abs(offset.left - 88) <= 1, 'tooltip has correct horizontal location') + assert.ok(Math.abs(offset.top - 126) <= 1, 'tooltip has correct vertical location') + $element.bootstrapTooltip('hide') + done() + }) + .bootstrapTooltip({ + container: 'body', + placement: 'top', + trigger: 'manual' + }) + + $element.bootstrapTooltip('show') + }) + + QUnit.test('should throw an error when initializing tooltip on the document object without specifying a delegation selector', function (assert) { + assert.expect(1) + assert.throws(function () { + $(document).bootstrapTooltip({ title: 'What am I on?' }) + }, new Error('`selector` option must be specified when initializing tooltip on the window.document object!')) + }) + + QUnit.test('should do nothing when an attempt is made to hide an uninitialized tooltip', function (assert) { + assert.expect(1) + + var $tooltip = $('<span data-toggle="tooltip" title="some tip">some text</span>') + .appendTo('#qunit-fixture') + .on('hidden.bs.tooltip shown.bs.tooltip', function () { + assert.ok(false, 'should not fire any tooltip events') + }) + .bootstrapTooltip('hide') + assert.strictEqual($tooltip.data('bs.tooltip'), undefined, 'should not initialize the tooltip') + }) + + QUnit.test('should throw an error when template contains multiple top-level elements', function (assert) { + assert.expect(1) + assert.throws(function () { + $('<a href="#" data-toggle="tooltip" title="Another tooltip"></a>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ template: '<div>Foo</div><div>Bar</div>' }) + .bootstrapTooltip('show') + }, new Error('tooltip `template` option must consist of exactly 1 top-level element!')) + }) + + QUnit.test('should not remove tooltip if multiple triggers are set and one is still active', function (assert) { + assert.expect(41) + var $el = $('<button>Trigger</button>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ trigger: 'click hover focus', animation: false }) + var tooltip = $el.data('bs.tooltip') + var $tooltip = tooltip.tip() + + function showingTooltip() { return $tooltip.hasClass('in') || tooltip.hoverState == 'in' } + + var tests = [ + ['mouseenter', 'mouseleave'], + + ['focusin', 'focusout'], + + ['click', 'click'], + + ['mouseenter', 'focusin', 'focusout', 'mouseleave'], + ['mouseenter', 'focusin', 'mouseleave', 'focusout'], + + ['focusin', 'mouseenter', 'mouseleave', 'focusout'], + ['focusin', 'mouseenter', 'focusout', 'mouseleave'], + + ['click', 'focusin', 'mouseenter', 'focusout', 'mouseleave', 'click'], + ['mouseenter', 'click', 'focusin', 'focusout', 'mouseleave', 'click'], + ['mouseenter', 'focusin', 'click', 'click', 'mouseleave', 'focusout'] + ] + + assert.ok(!showingTooltip()) + + $.each(tests, function (idx, triggers) { + for (var i = 0, len = triggers.length; i < len; i++) { + $el.trigger(triggers[i]) + assert.equal(i < (len - 1), showingTooltip()) + } + }) + }) + + QUnit.test('should disable sanitizer', function (assert) { + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + sanitize: false + }) + + var tooltip = $trigger.data('bs.tooltip') + assert.strictEqual(tooltip.options.sanitize, false) + }) + + QUnit.test('should sanitize template by removing disallowed tags', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<div>', + ' <script>console.log("oups script inserted")</script>', + ' <span>Some content</span>', + '</div>' + ].join('') + }) + + var tooltip = $trigger.data('bs.tooltip') + assert.strictEqual(tooltip.options.template.indexOf('script'), -1) + }) + + QUnit.test('should sanitize template by removing disallowed attributes', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<div>', + ' <img src="x" onError="alert(\'test\')">Some content</img>', + '</div>' + ].join('') + }) + + var tooltip = $trigger.data('bs.tooltip') + assert.strictEqual(tooltip.options.template.indexOf('onError'), -1) + }) + + QUnit.test('should sanitize template by removing tags with XSS', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<div>', + ' <a href="javascript:alert(7)">Click me</a>', + ' <span>Some content</span>', + '</div>' + ].join('') + }) + + var tooltip = $trigger.data('bs.tooltip') + assert.strictEqual(tooltip.options.template.indexOf('javascript'), -1) + }) + + QUnit.test('should allow custom sanitization rules', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(2) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<a href="javascript:alert(7)">Click me</a>', + '<span>Some content</span>' + ].join(''), + whiteList: { + span: null + } + }) + + var tooltip = $trigger.data('bs.tooltip') + + assert.strictEqual(tooltip.options.template.indexOf('<a'), -1) + assert.ok(tooltip.options.template.indexOf('span') !== -1) + }) + + QUnit.test('should allow passing a custom function for sanitization', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<span>Some content</span>' + ].join(''), + sanitizeFn: function (input) { + return input + } + }) + + var tooltip = $trigger.data('bs.tooltip') + + assert.ok(tooltip.options.template.indexOf('span') !== -1) + }) + + QUnit.test('should allow passing aria attributes', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<span aria-pressed="true">Some content</span>' + ].join('') + }) + + var tooltip = $trigger.data('bs.tooltip') + + assert.ok(tooltip.options.template.indexOf('aria-pressed') !== -1) + }) + + QUnit.test('should not take into account sanitize in data attributes', function (assert) { + if (!document.implementation || !document.implementation.createHTMLDocument) { + assert.expect(0) + + return + } + + assert.expect(1) + + var $trigger = $('<a href="#" rel="tooltip" data-sanitize="false" data-trigger="click" title="Another tooltip"/>') + .appendTo('#qunit-fixture') + .bootstrapTooltip({ + template: [ + '<span aria-pressed="true">Some content</span>' + ].join('') + }) + + var tooltip = $trigger.data('bs.tooltip') + + assert.strictEqual(tooltip.options.sanitize, true) + }) +}) diff --git a/bootstrap/js/tests/vendor/jquery.min.js b/bootstrap/js/tests/vendor/jquery.min.js new file mode 100755 index 0000000..e836475 --- /dev/null +++ b/bootstrap/js/tests/vendor/jquery.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)},input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0; +}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName("body")[0],c&&c.style?(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(d.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),V=["Top","Right","Bottom","Left"],W=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/<tbody/i;function ia(a){Z.test(a.type)&&(a.defaultChecked=a.checked)}function ja(a,b,c,d,e){for(var f,g,h,i,j,k,m,o=a.length,p=ca(b),q=[],r=0;o>r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?"<table>"!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ma.test(f)?this.mouseHooks:la.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=g.srcElement||d),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,h.filter?h.filter(a,g):a},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button,h=b.fromElement;return null==a.pageX&&null!=b.clientX&&(e=a.target.ownerDocument||d,f=e.documentElement,c=e.body,a.pageX=b.clientX+(f&&f.scrollLeft||c&&c.scrollLeft||0)-(f&&f.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(f&&f.scrollTop||c&&c.scrollTop||0)-(f&&f.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&h&&(a.relatedTarget=h===a.target?b.toElement:h),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ra()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ra()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=d.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)}:function(a,b,c){var d="on"+b;a.detachEvent&&("undefined"==typeof a[d]&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?pa:qa):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:qa,isPropagationStopped:qa,isImmediatePropagationStopped:qa,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=pa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=pa,a&&!this.isSimulated&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=pa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submit||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?n.prop(b,"form"):void 0;c&&!n._data(c,"submit")&&(n.event.add(c,"submit._submit",function(a){a._submitBubble=!0}),n._data(c,"submit",!0))})},postDispatch:function(a){a._submitBubble&&(delete a._submitBubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.change||(n.event.special.change={setup:function(){return ka.test(this.nodeName)?("checkbox"!==this.type&&"radio"!==this.type||(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._justChanged=!0)}),n.event.add(this,"click._change",function(a){this._justChanged&&!a.isTrigger&&(this._justChanged=!1),n.event.simulate("change",this,a)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;ka.test(b.nodeName)&&!n._data(b,"change")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a)}),n._data(b,"change",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!ka.test(this.nodeName)}}),l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d){return sa(this,a,b,c,d)},one:function(a,b,c,d){return sa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=qa),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ta=/ jQuery\d+="(?:null|\d+)"/g,ua=new RegExp("<(?:"+ba+")[\\s/>]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/<script|<style|<link/i,xa=/checked\s*(?:[^=]|=\s*.checked.)/i,ya=/^true\/(.*)/,za=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ja[0].contentWindow||Ja[0].contentDocument).document,b.write(),b.close(),c=La(a,b),Ja.detach()),Ka[a]=c),c}var Na=/^margin/,Oa=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Pa=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Qa=d.documentElement;!function(){var b,c,e,f,g,h,i=d.createElement("div"),j=d.createElement("div");if(j.style){j.style.cssText="float:left;opacity:.5",l.opacity="0.5"===j.style.opacity,l.cssFloat=!!j.style.cssFloat,j.style.backgroundClip="content-box",j.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===j.style.backgroundClip,i=d.createElement("div"),i.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",j.innerHTML="",i.appendChild(j),l.boxSizing=""===j.style.boxSizing||""===j.style.MozBoxSizing||""===j.style.WebkitBoxSizing,n.extend(l,{reliableHiddenOffsets:function(){return null==b&&k(),f},boxSizingReliable:function(){return null==b&&k(),e},pixelMarginRight:function(){return null==b&&k(),c},pixelPosition:function(){return null==b&&k(),b},reliableMarginRight:function(){return null==b&&k(),g},reliableMarginLeft:function(){return null==b&&k(),h}});function k(){var k,l,m=d.documentElement;m.appendChild(i),j.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",b=e=h=!1,c=g=!0,a.getComputedStyle&&(l=a.getComputedStyle(j),b="1%"!==(l||{}).top,h="2px"===(l||{}).marginLeft,e="4px"===(l||{width:"4px"}).width,j.style.marginRight="50%",c="4px"===(l||{marginRight:"4px"}).marginRight,k=j.appendChild(d.createElement("div")),k.style.cssText=j.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",k.style.marginRight=k.style.width="0",j.style.width="1px",g=!parseFloat((a.getComputedStyle(k)||{}).marginRight),j.removeChild(k)),j.style.display="none",f=0===j.getClientRects().length,f&&(j.style.display="",j.innerHTML="<table><tr><td></td><td>t</td></tr></table>",j.childNodes[0].style.borderCollapse="separate",k=j.getElementsByTagName("td"),k[0].style.cssText="margin:0;border:0;padding:0;display:none",f=0===k[0].offsetHeight,f&&(k[0].style.display="",k[1].style.display="none",f=0===k[0].offsetHeight)),m.removeChild(i)}}}();var Ra,Sa,Ta=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ra=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c.getPropertyValue(b)||c[b]:void 0,""!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Oa.test(g)&&Na.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0===g?g:g+""}):Qa.currentStyle&&(Ra=function(a){return a.currentStyle},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Oa.test(g)&&!Ta.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Ua(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Va=/alpha\([^)]*\)/i,Wa=/opacity\s*=\s*([^)]*)/i,Xa=/^(none|table(?!-c[ea]).+)/,Ya=new RegExp("^("+T+")(.*)$","i"),Za={position:"absolute",visibility:"hidden",display:"block"},$a={letterSpacing:"0",fontWeight:"400"},_a=["Webkit","O","Moz","ms"],ab=d.createElement("div").style;function bb(a){if(a in ab)return a;var b=a.charAt(0).toUpperCase()+a.slice(1),c=_a.length;while(c--)if(a=_a[c]+b,a in ab)return a}function cb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&W(d)&&(f[g]=n._data(d,"olddisplay",Ma(d.nodeName)))):(e=W(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function db(a,b,c){var d=Ya.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function eb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+V[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+V[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+V[f]+"Width",!0,e))):(g+=n.css(a,"padding"+V[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+V[f]+"Width",!0,e)));return g}function fb(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=Ra(a),g=l.boxSizing&&"border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=Sa(a,b,f),(0>e||null==e)&&(e=a.style[b]),Oa.test(e))return e;d=g&&(l.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+eb(a,b,c||(g?"border":"content"),d,f)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Sa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=U.exec(c))&&e[1]&&(c=X(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Sa(a,b,d)),"normal"===f&&b in $a&&(f=$a[b]),""===c||c?(e=parseFloat(f),c===!0||isFinite(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Xa.test(n.css(a,"display"))&&0===a.offsetWidth?Pa(a,Za,function(){return fb(a,b,d)}):fb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ra(a);return db(a,c,d?eb(a,b,d,l.boxSizing&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Wa.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Va,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Va.test(f)?f.replace(Va,e):f+" "+e)}}),n.cssHooks.marginRight=Ua(l.reliableMarginRight,function(a,b){return b?Pa(a,{display:"inline-block"},Sa,[a,"marginRight"]):void 0}),n.cssHooks.marginLeft=Ua(l.reliableMarginLeft,function(a,b){return b?(parseFloat(Sa(a,"marginLeft"))||(n.contains(a.ownerDocument,a)?a.getBoundingClientRect().left-Pa(a,{ +marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+"px":void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k="none"===j?n._data(a,"olddisplay")||Ma(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==Ma(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))"inline"===("none"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(pb(k,j.opts.specialEasing);g>f;f++)if(d=qb.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,nb,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(qb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return X(c.elem,a,U.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],qb.tweeners[c]=qb.tweeners[c]||[],qb.tweeners[c].unshift(b)},prefilters:[ob],prefilter:function(a,b){b?qb.prefilters.unshift(a):qb.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(W).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=qb(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&kb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(mb(b,!0),a,d,e)}}),n.each({slideDown:mb("show"),slideUp:mb("hide"),slideToggle:mb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(hb=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),hb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ib||(ib=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(ib),ib=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a,b=d.createElement("input"),c=d.createElement("div"),e=d.createElement("select"),f=e.appendChild(d.createElement("option"));c=d.createElement("div"),c.setAttribute("className","t"),c.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],b.setAttribute("type","checkbox"),c.appendChild(b),a=c.getElementsByTagName("a")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==c.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=f.selected,l.enctype=!!d.createElement("form").enctype,e.disabled=!0,l.optDisabled=!f.disabled,b=d.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value}();var rb=/\r/g,sb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(sb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>-1)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var tb,ub,vb=n.expr.attrHandle,wb=/^(?:checked|selected)$/i,xb=l.getSetAttribute,yb=l.input;n.fn.extend({attr:function(a,b){return Y(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ub:tb)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?yb&&xb||!wb.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(xb?c:d)}}),ub={set:function(a,b,c){return b===!1?n.removeAttr(a,c):yb&&xb||!wb.test(c)?a.setAttribute(!xb&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=vb[b]||n.find.attr;yb&&xb||!wb.test(b)?vb[b]=function(a,b,d){var e,f;return d||(f=vb[b],vb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,vb[b]=f),e}:vb[b]=function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),yb&&xb||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):tb&&tb.set(a,b,c)}}),xb||(tb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},vb.id=vb.name=vb.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:tb.set},n.attrHooks.contenteditable={set:function(a,b,c){tb.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var zb=/^(?:input|select|textarea|button|object)$/i,Ab=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return Y(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):zb.test(a.nodeName)||Ab.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var Bb=/[\t\r\n\f]/g;function Cb(a){return n.attr(a,"class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,Cb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,Cb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,Cb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=Cb(this),b&&n._data(this,"__className__",b),n.attr(this,"class",b||a===!1?"":n._data(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+Cb(c)+" ").replace(Bb," ").indexOf(b)>-1)return!0;return!1}}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Db=a.location,Eb=n.now(),Fb=/\?/,Gb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(Gb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new a.DOMParser,c=d.parseFromString(b,"text/xml")):(c=new a.ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var Hb=/#.*$/,Ib=/([?&])_=[^&]*/,Jb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Kb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Lb=/^(?:GET|HEAD)$/,Mb=/^\/\//,Nb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ob={},Pb={},Qb="*/".concat("*"),Rb=Db.href,Sb=Nb.exec(Rb.toLowerCase())||[];function Tb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Ub(a,b,c,d){var e={},f=a===Pb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Vb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Wb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Xb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rb,type:"GET",isLocal:Kb.test(Sb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Qb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Vb(Vb(a,n.ajaxSettings),b):Vb(n.ajaxSettings,a)},ajaxPrefilter:Tb(Ob),ajaxTransport:Tb(Pb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var d,e,f,g,h,i,j,k,l=n.ajaxSetup({},c),m=l.context||l,o=l.context&&(m.nodeType||m.jquery)?n(m):n.event,p=n.Deferred(),q=n.Callbacks("once memory"),r=l.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!k){k={};while(b=Jb.exec(g))k[b[1].toLowerCase()]=b[2]}b=k[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(l.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return j&&j.abort(b),y(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,l.url=((b||l.url||Rb)+"").replace(Hb,"").replace(Mb,Sb[1]+"//"),l.type=c.method||c.type||l.method||l.type,l.dataTypes=n.trim(l.dataType||"*").toLowerCase().match(G)||[""],null==l.crossDomain&&(d=Nb.exec(l.url.toLowerCase()),l.crossDomain=!(!d||d[1]===Sb[1]&&d[2]===Sb[2]&&(d[3]||("http:"===d[1]?"80":"443"))===(Sb[3]||("http:"===Sb[1]?"80":"443")))),l.data&&l.processData&&"string"!=typeof l.data&&(l.data=n.param(l.data,l.traditional)),Ub(Ob,l,c,w),2===u)return w;i=n.event&&l.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),l.type=l.type.toUpperCase(),l.hasContent=!Lb.test(l.type),f=l.url,l.hasContent||(l.data&&(f=l.url+=(Fb.test(f)?"&":"?")+l.data,delete l.data),l.cache===!1&&(l.url=Ib.test(f)?f.replace(Ib,"$1_="+Eb++):f+(Fb.test(f)?"&":"?")+"_="+Eb++)),l.ifModified&&(n.lastModified[f]&&w.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&w.setRequestHeader("If-None-Match",n.etag[f])),(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",l.contentType),w.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+("*"!==l.dataTypes[0]?", "+Qb+"; q=0.01":""):l.accepts["*"]);for(e in l.headers)w.setRequestHeader(e,l.headers[e]);if(l.beforeSend&&(l.beforeSend.call(m,w,l)===!1||2===u))return w.abort();v="abort";for(e in{success:1,error:1,complete:1})w[e](l[e]);if(j=Ub(Pb,l,c,w)){if(w.readyState=1,i&&o.trigger("ajaxSend",[w,l]),2===u)return w;l.async&&l.timeout>0&&(h=a.setTimeout(function(){w.abort("timeout")},l.timeout));try{u=1,j.send(s,y)}catch(x){if(!(2>u))throw x;y(-1,x)}}else y(-1,"No Transport");function y(b,c,d,e){var k,s,t,v,x,y=c;2!==u&&(u=2,h&&a.clearTimeout(h),j=void 0,g=e||"",w.readyState=b>0?4:0,k=b>=200&&300>b||304===b,d&&(v=Wb(l,w,d)),v=Xb(l,v,w,k),k?(l.ifModified&&(x=w.getResponseHeader("Last-Modified"),x&&(n.lastModified[f]=x),x=w.getResponseHeader("etag"),x&&(n.etag[f]=x)),204===b||"HEAD"===l.type?y="nocontent":304===b?y="notmodified":(y=v.state,s=v.data,t=v.error,k=!t)):(t=y,!b&&y||(y="error",0>b&&(b=0))),w.status=b,w.statusText=(c||y)+"",k?p.resolveWith(m,[s,y,w]):p.rejectWith(m,[w,y,t]),w.statusCode(r),r=void 0,i&&o.trigger(k?"ajaxSuccess":"ajaxError",[w,l,k?s:t]),q.fireWith(m,[w,y]),i&&(o.trigger("ajaxComplete",[w,l]),--n.active||n.event.trigger("ajaxStop")))}return w},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}});function Yb(a){return a.style&&a.style.display||n.css(a,"display")}function Zb(a){if(!n.contains(a.ownerDocument||d,a))return!0;while(a&&1===a.nodeType){if("none"===Yb(a)||"hidden"===a.type)return!0;a=a.parentNode}return!1}n.expr.filters.hidden=function(a){return l.reliableHiddenOffsets()?a.offsetWidth<=0&&a.offsetHeight<=0&&!a.getClientRects().length:Zb(a)},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var $b=/%20/g,_b=/\[\]$/,ac=/\r?\n/g,bc=/^(?:submit|button|image|reset|file)$/i,cc=/^(?:input|select|textarea|keygen)/i;function dc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||_b.test(a)?d(a,e):dc(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)dc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)dc(c,a[c],b,e);return d.join("&").replace($b,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&cc.test(this.nodeName)&&!bc.test(a)&&(this.checked||!Z.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(ac,"\r\n")}}):{name:b.name,value:c.replace(ac,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return this.isLocal?ic():d.documentMode>8?hc():/^(get|post|head|put|delete|options)$/i.test(this.type)&&hc()||ic()}:hc;var ec=0,fc={},gc=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in fc)fc[a](void 0,!0)}),l.cors=!!gc&&"withCredentials"in gc,gc=l.ajax=!!gc,gc&&n.ajaxTransport(function(b){if(!b.crossDomain||l.cors){var c;return{send:function(d,e){var f,g=b.xhr(),h=++ec;if(g.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(f in b.xhrFields)g[f]=b.xhrFields[f];b.mimeType&&g.overrideMimeType&&g.overrideMimeType(b.mimeType),b.crossDomain||d["X-Requested-With"]||(d["X-Requested-With"]="XMLHttpRequest");for(f in d)void 0!==d[f]&&g.setRequestHeader(f,d[f]+"");g.send(b.hasContent&&b.data||null),c=function(a,d){var f,i,j;if(c&&(d||4===g.readyState))if(delete fc[h],c=void 0,g.onreadystatechange=n.noop,d)4!==g.readyState&&g.abort();else{j={},f=g.status,"string"==typeof g.responseText&&(j.text=g.responseText);try{i=g.statusText}catch(k){i=""}f||!b.isLocal||b.crossDomain?1223===f&&(f=204):f=j.text?200:404}j&&e(f,i,j,g.getAllResponseHeaders())},b.async?4===g.readyState?a.setTimeout(c):g.onreadystatechange=fc[h]=c:c()},abort:function(){c&&c(void 0,!0)}}}});function hc(){try{return new a.XMLHttpRequest}catch(b){}}function ic(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=d.head||n("head")[0]||d.documentElement;return{send:function(e,f){b=d.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||f(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var jc=[],kc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=jc.pop()||n.expando+"_"+Eb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(kc.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&kc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(kc,"$1"+e):b.jsonp!==!1&&(b.url+=(Fb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,jc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ja([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var lc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&lc)return lc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h,a.length)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function mc(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?("undefined"!=typeof e.getBoundingClientRect&&(d=e.getBoundingClientRect()),c=mc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Qa})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return Y(this,function(a,d,e){var f=mc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ua(l.pixelPosition,function(a,c){return c?(c=Sa(a,b),Oa.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({ +padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n}); diff --git a/bootstrap/js/tests/visual/affix-with-sticky-footer.html b/bootstrap/js/tests/visual/affix-with-sticky-footer.html new file mode 100755 index 0000000..aab26d2 --- /dev/null +++ b/bootstrap/js/tests/visual/affix-with-sticky-footer.html @@ -0,0 +1,317 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Affix</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <style> + html { + position: relative; + min-height: 100%; + } + body { + /* Margin bottom by footer height */ + margin-bottom: 200px; + } + .footer { + position: absolute; + bottom: 0; + width: 100%; + /* Set the fixed height of the footer here */ + height: 200px; + background-color: #f5f5f5; + } + /* Test Styles */ + .affixed-element-top.affix { + top: 10px; + } + .affixed-element-top.affix-bottom { + position: absolute; + } + .affixed-element-bottom { + margin-bottom: 0; + } + .affixed-element-bottom.affix { + bottom: 10px; + } + .affixed-element-bottom.affix-bottom { + position: relative; + } + .grow-btn, .shrink-btn { + color: #FFF; + } + .grow-btn { + background-color: #2ECC40; + } + .grow-btn:hover { + background-color: #3D9970; + } + .shrink-btn { + background-color: #FF4136; + } + .shrink-btn:hover { + background-color: #85144B; + } + </style> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header js-page-header"> + <h1>Affix <small>Bootstrap Visual Test</small></h1> + </div> + + <div class="col-md-3"> + <ul class="list-group affixed-element-top js-affixed-element-top"> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Porta ac consectetur ac</li> + </ul> + </div> + + <div class="col-md-6 js-content"> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + </div> + + <div class="col-md-3"> + <ul class="list-group affixed-element-bottom js-affixed-element-bottom"> + <li class="list-group-item">Sit necessitatibus aspernatur.</li> + <li class="list-group-item">Adipisicing alias dolor!</li> + <li class="list-group-item">Ipsum molestiae impedit.</li> + <li class="list-group-item">Amet quis iste?</li> + <li class="list-group-item">Ipsum quaerat porro.</li> + <li class="list-group-item">Elit lorem libero.</li> + <li class="list-group-item">Ipsum dolore facilis.</li> + <li class="list-group-item">Elit ad atque.</li> + <li class="list-group-item">Dolor amet sequi!</li> + <li class="list-group-item">Consectetur voluptatum facilis!</li> + <li class="list-group-item">Sit neque eligendi?</li> + <li class="list-group-item">Amet fuga consectetur!</li> + <li class="list-group-item">Amet molestias repellat!</li> + <li class="list-group-item">Consectetur minima repellendus.</li> + <li class="list-group-item grow-btn js-grow-btn">Grow content</li> + <li class="list-group-item shrink-btn js-shrink-btn">Shrink content</li> + </ul> + </div> + + +</div> + +<footer class="footer js-footer"> + <div class="container"> + <p class="text-muted">Place sticky footer content here.</p> + </div> +</footer> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../affix.js"></script> + + +<!-- JavaScript Test --> +<script> +$(function () { + $('.js-affixed-element-top').affix({ + offset: { + top: $('.js-page-header').outerHeight(true) - 10 + , bottom: $('.js-footer').outerHeight(true) + 10 + } + }) + // todo(fat): sux you have to do this. + .on('affix.bs.affix', function (e) { + $(e.target).width(e.target.offsetWidth) + }) + + $('.js-affixed-element-bottom').affix({ + offset: { + bottom: $('.js-footer').outerHeight(true) + 10 + } + }) + + $('.js-grow-btn').on('click', function() { + $('.js-content').append('<p>Ipsum corrupti ipsam est temporibus.</p>') + }) + $('.js-shrink-btn').on('click', function() { + $('.js-content p').last().remove() + }) +}) +</script> +</body> +</html> diff --git a/bootstrap/js/tests/visual/affix.html b/bootstrap/js/tests/visual/affix.html new file mode 100755 index 0000000..5437fcc --- /dev/null +++ b/bootstrap/js/tests/visual/affix.html @@ -0,0 +1,316 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Affix</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <style> + /* Test Styles */ + .affixed-element-top.affix { + top: 10px; + } + .affixed-element-top.affix-bottom { + position: absolute; + } + .affixed-element-bottom { + margin-bottom: 0; + } + .affixed-element-bottom.affix { + bottom: 10px; + } + .affixed-element-bottom.affix-bottom { + position: relative; + } + .grow-btn, .shrink-btn { + color: #FFF; + } + .grow-btn { + background-color: #2ECC40; + } + .grow-btn:hover { + background-color: #3D9970; + } + .shrink-btn { + background-color: #FF4136; + } + .shrink-btn:hover { + background-color: #85144B; + } + </style> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header js-page-header"> + <h1>Affix <small>Bootstrap Visual Test</small></h1> + + <div id="affixTarget">Affix target with XSS</div> + </div> + + <div class="col-md-3"> + <ul class="list-group affixed-element-top js-affixed-element-top"> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Cras justo odio</li> + <li class="list-group-item">Dapibus ac facilisis in</li> + <li class="list-group-item">Morbi leo risus</li> + <li class="list-group-item">Porta ac consectetur ac</li> + <li class="list-group-item">Vestibulum at eros</li> + <li class="list-group-item">Porta ac consectetur ac</li> + </ul> + </div> + + <div class="col-md-6 js-content"> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + + </div> + + <div class="col-md-3"> + <ul class="list-group affixed-element-bottom js-affixed-element-bottom"> + <li class="list-group-item">Sit necessitatibus aspernatur.</li> + <li class="list-group-item">Adipisicing alias dolor!</li> + <li class="list-group-item">Ipsum molestiae impedit.</li> + <li class="list-group-item">Amet quis iste?</li> + <li class="list-group-item">Ipsum quaerat porro.</li> + <li class="list-group-item">Elit lorem libero.</li> + <li class="list-group-item">Ipsum dolore facilis.</li> + <li class="list-group-item">Elit ad atque.</li> + <li class="list-group-item">Dolor amet sequi!</li> + <li class="list-group-item">Consectetur voluptatum facilis!</li> + <li class="list-group-item">Sit neque eligendi?</li> + <li class="list-group-item">Amet fuga consectetur!</li> + <li class="list-group-item">Amet molestias repellat!</li> + <li class="list-group-item">Consectetur minima repellendus.</li> + <li class="list-group-item grow-btn js-grow-btn">Grow content</li> + <li class="list-group-item shrink-btn js-shrink-btn">Shrink content</li> + </ul> + </div> + + <div class="col-md-12 js-footer"> + <hr> + + <p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Maecenas sed diam eget risus varius blandit sit amet non magna.</p> + + <p>Nullam id dolor id nibh ultricies vehicula ut id elit. Etiam porta sem malesuada magna mollis euismod. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Curabitur blandit tempus porttitor. Cras justo odio, dapibus ac facilisis in, egestas eget quam.</p> + + <p>Sed posuere consectetur est at lobortis. Maecenas faucibus mollis interdum. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Nulla vitae elit libero, a pharetra augue. Nulla vitae elit libero, a pharetra augue.</p> + + <p>Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Nulla vitae elit libero, a pharetra augue. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Cras mattis consectetur purus sit amet fermentum. Sed posuere consectetur est at lobortis. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + </div> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../affix.js"></script> + + +<!-- JavaScript Test --> +<script> +$(function () { + try { + $('#affixTarget').bootstrapAffix({ + target: '<img src=1 onerror=\'alert(0)\'>' + }) + } catch (e) { + console.error(e) + } + + $('.js-affixed-element-top').affix({ + offset: { + top: $('.js-page-header').outerHeight(true) - 10 + , bottom: $('.js-footer').outerHeight(true) + 10 + } + }) + // todo(fat): sux you have to do this. + .on('affix.bs.affix', function (e) { + $(e.target).width(e.target.offsetWidth) + }) + + $('.js-affixed-element-bottom').affix({ + offset: { + bottom: $('.js-footer').outerHeight(true) + 10 + } + }) + + $('.js-grow-btn').on('click', function() { + $('.js-content').append('<p>Ipsum corrupti ipsam est temporibus.</p>') + }) + $('.js-shrink-btn').on('click', function() { + $('.js-content p').last().remove() + }) +}) +</script> +</body> +</html> diff --git a/bootstrap/js/tests/visual/alert.html b/bootstrap/js/tests/visual/alert.html new file mode 100755 index 0000000..ed6f25d --- /dev/null +++ b/bootstrap/js/tests/visual/alert.html @@ -0,0 +1,48 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Alert</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Alert <small>Bootstrap Visual Test</small></h1> + </div> + + <div class="alert alert-warning fade in"> + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> + <strong>Holy guacamole!</strong> Best check yo self, you're not looking too good. + </div> + + <div class="alert alert-danger fade in"> + <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> + <h4>Oh snap! You got an error!</h4> + <p>Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.</p> + <p> + <button type="button" class="btn btn-danger">Take this action</button> + <button type="button" class="btn btn-default">Or do this</button> + </p> + </div> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../alert.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/button.html b/bootstrap/js/tests/visual/button.html new file mode 100755 index 0000000..2fc4bc6 --- /dev/null +++ b/bootstrap/js/tests/visual/button.html @@ -0,0 +1,79 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Button</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Button <small>Bootstrap Visual Test</small></h1> + </div> + + <button type="button" data-loading-text="Loading for 3 seconds..." class="btn btn-primary js-loading-button"> + Loading state + </button> + + <button type="button" class="btn btn-primary" data-toggle="button">Single toggle</button> + + <p>For checkboxes and radio buttons, ensure that keyboard behavior is functioning correctly.</p> + <p>Navigate to the checkboxes with the keyboard (generally, using <kbd>TAB</kbd> / <kbd>SHIFT + TAB</kbd>), and ensure that <kbd>SPACE</kbd> toggles the currently focused checkbox. Click on one of the checkboxes using the mouse, ensure that focus was correctly set on the actual checkbox, and that <kbd>SPACE</kbd> toggles the checkbox again.</p> + + <div class="btn-group" data-toggle="buttons"> + <label class="btn btn-primary"> + <input type="checkbox"> checkbox 1 + </label> + <label class="btn btn-primary"> + <input type="checkbox"> checkbox 2 + </label> + <label class="btn btn-primary"> + <input type="checkbox"> checkbox 3 + </label> + </div> + + <p>Navigate to the radio button group with the keyboard (generally, using <kbd>TAB</kbd> / <kbd>SHIFT + TAB</kbd>). If no radio button was initially set to be selected, the first/last radio button should receive focus (depending on whether you navigated "forward" to the group with <kbd>TAB</kbd> or "backwards" using <kbd>SHIFT + TAB</kbd>). If a radio button was already selected, navigating with the keyboard should set focus to that particular radio button. Only one radio button in a group should receive focus at any given time. Ensure that the selected radio button can be changed by using the <kbd>←</kbd> and <kbd>→</kbd> arrow keys. Click on one of the radio buttons with the mouse, ensure that focus was correctly set on the actual radio button, and that <kbd>←</kbd> and <kbd>→</kbd> change the selected radio button again.</p> + + <div class="btn-group" data-toggle="buttons"> + <label class="btn btn-primary"> + <input type="radio" name="options" id="option1"> Radio 1 + </label> + <label class="btn btn-primary"> + <input type="radio" name="options" id="option2"> Radio 2 + </label> + <label class="btn btn-primary"> + <input type="radio" name="options" id="option3"> Radio 3 + </label> + </div> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../button.js"></script> + +<!-- JavaScript Test --> +<script> +$(function () { + $('.js-loading-button').on('click', function () { + var btn = $(this).button('loading') + setTimeout(function (){ + btn.button('reset') + }, 3000) + }) +}) +</script> +</body> +</html> diff --git a/bootstrap/js/tests/visual/carousel.html b/bootstrap/js/tests/visual/carousel.html new file mode 100755 index 0000000..018fa3c --- /dev/null +++ b/bootstrap/js/tests/visual/carousel.html @@ -0,0 +1,58 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Carousel</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Carousel <small>Bootstrap Visual Test</small></h1> + </div> + + <div id="carousel-example-generic" class="carousel slide" data-ride="carousel"> + <ol class="carousel-indicators"> + <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> + <li data-target="#carousel-example-generic" data-slide-to="1" class=""></li> + <li data-target="#carousel-example-generic" data-slide-to="2" class=""></li> + </ol> + <div class="carousel-inner"> + <div class="item active"> + <img alt="First slide" src="https://37.media.tumblr.com/tumblr_m8tay0JcfG1qa42jro1_1280.jpg"> + </div> + <div class="item"> + <img alt="Second slide" src="https://37.media.tumblr.com/tumblr_m8tazfiVYJ1qa42jro1_1280.jpg"> + </div> + <div class="item"> + <img alt="Third slide" src="https://38.media.tumblr.com/tumblr_m8tb2rVsD31qa42jro1_1280.jpg"> + </div> + </div> + <a class="left carousel-control" href="#carousel-example-generic" data-slide="prev"> + <span class="glyphicon glyphicon-chevron-left"></span> + </a> + <a class="right carousel-control" href="#carousel-example-generic" data-slide="next"> + <span class="glyphicon glyphicon-chevron-right"></span> + </a> + </div> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../carousel.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/collapse.html b/bootstrap/js/tests/visual/collapse.html new file mode 100755 index 0000000..77cbc71 --- /dev/null +++ b/bootstrap/js/tests/visual/collapse.html @@ -0,0 +1,84 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Collapse</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Collapse <small>Bootstrap Visual Test</small></h1> + </div> + + <div class="panel-group" id="accordion"> + <div class="panel panel-default"> + <div class="panel-heading"> + <h4 class="panel-title"> + <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne"> + Collapsible Group Item #1 + </a> + </h4> + </div> + <div id="collapseOne" class="panel-collapse collapse in"> + <div class="panel-body"> + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <h4 class="panel-title"> + <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo"> + Collapsible Group Item #2 + </a> + </h4> + </div> + <div id="collapseTwo" class="panel-collapse collapse"> + <div class="panel-body"> + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading"> + <h4 class="panel-title"> + <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseThree"> + Collapsible Group Item #3 + </a> + </h4> + </div> + <div id="collapseThree" class="panel-collapse collapse"> + <div class="panel-body"> + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + </div> + </div> + </div> + </div> + <button class="btn" data-toggle="collapse" data-target="<img src=x onerror=alert(0)>"> + Collapse with an XSS + </button> + + <a role="button" class="btn btn-primary" data-toggle="collapse" data-parent="<img src=1 onerror=\'alert(0)\'>" href="#collapseThree"> + Collapse with an XSS in data-parent + </a> +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../collapse.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/dropdown.html b/bootstrap/js/tests/visual/dropdown.html new file mode 100755 index 0000000..b1edb6f --- /dev/null +++ b/bootstrap/js/tests/visual/dropdown.html @@ -0,0 +1,108 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Dropdown</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Dropdown <small>Bootstrap Visual Test</small></h1> + </div> + + <nav id="navbar-example" class="navbar navbar-default navbar-static"> + <div class="container-fluid"> + <div class="navbar-header"> + <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target=".bs-example-js-navbar-collapse"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="#">Project Name</a> + </div> + <div class="collapse navbar-collapse bs-example-js-navbar-collapse"> + <ul class="nav navbar-nav"> + <li class="dropdown"> + <a id="drop1" href="#" role="button" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="drop1"> + <li><a href="#">Action</a></li> + <li><a href="#">Another action</a></li> + <li><a href="#">Something else here</a></li> + <li role="separator" class="divider"></li> + <li><a href="#">Separated link</a></li> + </ul> + </li> + <li class="dropdown"> + <a href="#" id="drop2" role="button" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown 2 <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="drop2"> + <li><a href="#">Action</a></li> + <li><a href="#">Another action</a></li> + <li><a href="#">Something else here</a></li> + <li role="separator" class="divider"></li> + <li><a href="#">Separated link</a></li> + </ul> + </li> + </ul> + <ul class="nav navbar-nav navbar-right"> + <li id="fat-menu" class="dropdown"> + <a href="#" id="drop3" role="button" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown 3 <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="drop3"> + <li><a href="#">Action</a></li> + <li><a href="#">Another action</a></li> + <li><a href="#">Something else here</a></li> + <li role="separator" class="divider"></li> + <li><a href="#">Separated link</a></li> + </ul> + </li> + </ul> + </div> + </div> + </nav> + + <ul class="nav nav-pills"> + <li class="active"><a href="#">Regular link</a></li> + <li class="dropdown"> + <a id="drop4" role="button" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul id="menu1" class="dropdown-menu" aria-labelledby="drop4"> + <li><a href="#">Action</a></li> + <li><a href="#">Another action</a></li> + <li><a href="#">Something else here</a></li> + <li role="separator" class="divider"></li> + <li><a href="#">Separated link</a></li> + </ul> + </li> + <li class="dropdown"> + <a id="drop5" role="button" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">Dropdown 2 <b class="caret"></b></a> + <ul id="menu2" class="dropdown-menu" aria-labelledby="drop5"> + <li><a href="#">Action</a></li> + <li><a href="#">Another action</a></li> + <li><a href="#">Something else here</a></li> + <li role="separator" class="divider"></li> + <li><a href="#">Separated link</a></li> + </ul> + </li> + </ul> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../dropdown.js"></script> +<script src="../../collapse.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/modal.html b/bootstrap/js/tests/visual/modal.html new file mode 100755 index 0000000..39e2089 --- /dev/null +++ b/bootstrap/js/tests/visual/modal.html @@ -0,0 +1,208 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Modal</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + + <style> + #tall { + height: 1500px; + width: 100px; + background-color: black; + color: white; + } + </style> +</head> +<body> + +<nav class="navbar navbar-default navbar-static-top"> + <div class="container-fluid"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="#">navbar-static-top</a> + </div> + <div id="navbar" class="navbar-collapse collapse"> + <ul class="nav navbar-nav"> + <li><a href="#about">About</a></li> + <li><a href="#contact">Contact</a></li> + </ul> + <ul class="nav navbar-nav navbar-right"> + <li><a href="#">This should not jump to the left when the modal is shown.</a></li> + </ul> + </div><!--/.nav-collapse --> + </div> +</nav> + +<div class="container"> + + <div class="page-header"> + <h1>Modal <small>Bootstrap Visual Test</small></h1> + </div> + + <div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> + <div class="modal-dialog"> + <div class="modal-content"> + + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="myModalLabel">Modal Heading</h4> + </div> + <div class="modal-body"> + <h4>Text in a modal</h4> + <p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula.</p> + + <h4>Popover in a modal</h4> + <p>This <a href="#" role="button" class="btn btn-default js-popover" title="A Title" data-content="And here's some amazing content. It's very engaging. right?" data-placement="left">button</a> should trigger a popover on click.</p> + + <h4>Tooltips in a modal</h4> + <p><a href="#" class="js-tooltip" title="Tooltip">This link</a> and <a href="#" class="js-tooltip" title="Tooltip">that link</a> should have tooltips on hover.</p> + + <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingOne"> + <h4 class="panel-title"> + <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> + Collapsible Group Item #1 + </a> + </h4> + </div> + <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> + <div class="panel-body"> + Lorem ipsum + </div> + </div> + </div> + <div class="panel panel-default"> + <div class="panel-heading" role="tab" id="headingTwo"> + <h4 class="panel-title"> + <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> + Collapsible Group Item #2 + </a> + </h4> + </div> + <div id="collapseTwo" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingTwo"> + <div class="panel-body"> + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS. + </div> + </div> + </div> + </div> + + <hr> + + <h4>Overflowing text to show scroll behavior</h4> + <p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p> + <p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p> + <p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p> + <p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p> + <p>Cras mattis consectetur purus sit amet fermentum. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.</p> + <p>Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.</p> + <p>Aenean lacinia bibendum nulla sed consectetur. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec sed odio dui. Donec ullamcorper nulla non metus auctor fringilla.</p> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-default" data-dismiss="modal">Close</button> + <button type="button" class="btn btn-primary">Save changes</button> + </div> + + </div> + </div> + </div> + + <div id="myModal2" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel2"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h4 class="modal-title" id="myModalLabel2">Modal Heading</h4> + </div> + <div class="modal-body"> + <ol> + <li>Ensure you're using Firefox.</li> + <li>Open a new tab and then switch back to this tab.</li> + <li>Click into this input: <input type="text" id="ff-bug-input"></li> + <li>Switch to the other tab and then back to this tab.</li> + </ol> + <p>Test result: <strong id="ff-bug-test-result"></strong></p> + </div> + </div> + </div> + </div> + + <button class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal"> + Launch demo modal + </button> + + <button id="tall-toggle" class="btn btn-default">Toggle tall <body> content</button> + <br><br> + <button class="btn btn-secondary btn-lg" data-toggle="modal" data-target="#myModal2"> + Launch Firefox bug test modal + </button> + (<a href="https://github.com/twbs/bootstrap/issues/18365">See Issue #18365</a>) + <br><br> + <div id="tall" style="display: none;"> + Tall body content to force the page to have a scrollbar. + </div> + + <button class="btn btn-primary btn-lg" data-toggle="modal" data-target="<div class="modal fade the-bad" tabindex="-1" role="dialog"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title">The Bad Modal</h4></div><div class="modal-body">This modal's HTTML source code is declared inline, inside the data-target attribute of it's show-button</div></div></div></div>"> + Launch XSS modal + </button> +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../modal.js"></script> +<script src="../../tooltip.js"></script> +<script src="../../popover.js"></script> +<script src="../../collapse.js"></script> + +<!-- JavaScript Test --> +<script> +var firefoxTestDone = false +function reportFirefoxTestResult(result) { + if (!firefoxTestDone) { + $('#ff-bug-test-result') + .addClass(result ? 'text-success' : 'text-danger') + .text(result ? 'PASS' : 'FAIL') + } + firefoxTestDone = true +} + +$(function () { + $('.js-popover').popover() + $('.js-tooltip').tooltip() + $('#tall-toggle').click(function () { + $('#tall').toggle() + }) + $('#ff-bug-input').one('focus', function () { + $('#myModal2').on('focus', function () { + reportFirefoxTestResult(false) + }) + $('#ff-bug-input').on('focus', function () { + reportFirefoxTestResult(true) + }) + }) +}) +</script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/popover.html b/bootstrap/js/tests/visual/popover.html new file mode 100755 index 0000000..0498cbc --- /dev/null +++ b/bootstrap/js/tests/visual/popover.html @@ -0,0 +1,54 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Popover</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Popover <small>Bootstrap Visual Test</small></h1> + </div> + + <button type="button" class="btn btn-default js-popover" data-container="body" data-toggle="popover" data-placement="left" data-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." data-original-title="" title=""> + Popover on left + </button> + <button type="button" class="btn btn-default js-popover" data-container="body" data-toggle="popover" data-placement="top" data-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." data-original-title="" title=""> + Popover on top + </button> + <button type="button" class="btn btn-default js-popover" data-container="body" data-toggle="popover" data-placement="bottom" data-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." data-original-title="" title=""> + Popover on bottom + </button> + <button type="button" class="btn btn-default js-popover" data-container="body" data-toggle="popover" data-placement="right" data-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." data-original-title="" title=""> + Popover on right + </button> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../tooltip.js"></script> +<script src="../../popover.js"></script> + +<!-- JavaScript Test --> +<script> +$(function () { + $('.js-popover').popover() +}) +</script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/scrollspy.html b/bootstrap/js/tests/visual/scrollspy.html new file mode 100755 index 0000000..10e6404 --- /dev/null +++ b/bootstrap/js/tests/visual/scrollspy.html @@ -0,0 +1,108 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Scrollspy</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <style> + body { padding-top: 70px; } + </style> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body data-spy="scroll" data-target=".navbar" data-offset="70"> + +<div class="container"> + + <nav class="navbar navbar-default navbar-fixed-top"> + <div class="container-fluid"> + <div class="navbar-header"> + <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target=".js-navbar-scrollspy"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="#">Project Name</a> + </div> + <div class="collapse navbar-collapse js-navbar-scrollspy"> + <ul class="nav navbar-nav"> + <li class=""><a href="#fat">@fat</a></li> + <li class=""><a href="#mdo">@mdo</a></li> + <li class="dropdown"> + <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu"> + <li class=""><a href="#one">one</a></li> + <li><a href="#two">two</a></li> + <li role="separator" class="divider"></li> + <li><a href="#three">three</a></li> + </ul> + </li> + </ul> + </div> + </div> + </nav> + + <h2 id="fat">@fat</h2> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <hr> + <h2 id="mdo">@mdo</h2> + <p>Veniam marfa mustache skateboard, adipisicing fugiat velit pitchfork beard. Freegan beard aliqua cupidatat mcsweeney's vero. Cupidatat four loko nisi, ea helvetica nulla carles. Tattooed cosby sweater food truck, mcsweeney's quis non freegan vinyl. Lo-fi wes anderson +1 sartorial. Carles non aesthetic exercitation quis gentrify. Brooklyn adipisicing craft beer vice keytar deserunt.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <hr> + <h2 id="one">one</h2> + <p>Occaecat commodo aliqua delectus. Fap craft beer deserunt skateboard ea. Lomo bicycle rights adipisicing banh mi, velit ea sunt next level locavore single-origin coffee in magna veniam. High life id vinyl, echo park consequat quis aliquip banh mi pitchfork. Vero VHS est adipisicing. Consectetur nisi DIY minim messenger bag. Cred ex in, sustainable delectus consectetur fanny pack iphone.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <hr> + <h2 id="two">two</h2> + <p>In incididunt echo park, officia deserunt mcsweeney's proident master cleanse thundercats sapiente veniam. Excepteur VHS elit, proident shoreditch +1 biodiesel laborum craft beer. Single-origin coffee wayfarers irure four loko, cupidatat terry richardson master cleanse. Assumenda you probably haven't heard of them art party fanny pack, tattooed nulla cardigan tempor ad. Proident wolf nesciunt sartorial keffiyeh eu banh mi sustainable. Elit wolf voluptate, lo-fi ea portland before they sold out four loko. Locavore enim nostrud mlkshk brooklyn nesciunt.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <hr> + <h2 id="three">three</h2> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Keytar twee blog, culpa messenger bag marfa whatever delectus food truck. Sapiente synth id assumenda. Locavore sed helvetica cliche irony, thundercats you probably haven't heard of them consequat hoodie gluten-free lo-fi fap aliquip. Labore elit placeat before they sold out, terry richardson proident brunch nesciunt quis cosby sweater pariatur keffiyeh ut helvetica artisan. Cardigan craft beer seitan readymade velit. VHS chambray laboris tempor veniam. Anim mollit minim commodo ullamco thundercats. + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + <p>Ad leggings keytar, brunch id art party dolor labore. Pitchfork yr enim lo-fi before they sold out qui. Tumblr farm-to-table bicycle rights whatever. Anim keffiyeh carles cardigan. Velit seitan mcsweeney's photo booth 3 wolf moon irure. Cosby sweater lomo jean shorts, williamsburg hoodie minim qui you probably haven't heard of them et cardigan trust fund culpa biodiesel wes anderson aesthetic. Nihil tattooed accusamus, cred irony biodiesel keffiyeh artisan ullamco consequat.</p> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../scrollspy.js"></script> +<script src="../../dropdown.js"></script> +<script src="../../collapse.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/tab.html b/bootstrap/js/tests/visual/tab.html new file mode 100755 index 0000000..0063c32 --- /dev/null +++ b/bootstrap/js/tests/visual/tab.html @@ -0,0 +1,172 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Tab</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <style> + h4 { + margin: 40px 0 10px; + } + + .nav-tabs { + margin-bottom: 15px; + } + </style> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Tab <small>Bootstrap Visual Test</small></h1> + </div> + + <h4>Tabs without fade</h4> + + <ul id="myTab" class="nav nav-tabs"> + <li class="active"><a href="#home" data-toggle="tab">Home</a></li> + <li><a href="#profile" data-toggle="tab">Profile</a></li> + <li class="dropdown"> + <a href="#" id="myTabDrop1" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="myTabDrop1"> + <li><a href="#dropdown1" data-toggle="tab">@fat</a></li> + <li><a href="#dropdown2" data-toggle="tab">@mdo</a></li> + </ul> + </li> + </ul> + <div id="myTabContent" class="tab-content"> + <div class="tab-pane active" id="home"> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + </div> + <div class="tab-pane" id="profile"> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + </div> + <div class="tab-pane" id="dropdown1"> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + </div> + <div class="tab-pane" id="dropdown2"> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + </div> + </div> + + <h4>Tabs with fade</h4> + + <ul id="myTab1" class="nav nav-tabs"> + <li class="active"><a href="#home1" data-toggle="tab">Home</a></li> + <li><a href="#profile1" data-toggle="tab">Profile</a></li> + <li class="dropdown"> + <a href="#" id="myTabDrop2" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="myTabDrop2"> + <li><a href="#dropdown1-1" data-toggle="tab">@fat</a></li> + <li><a href="#dropdown1-2" data-toggle="tab">@mdo</a></li> + </ul> + </li> + </ul> + <div id="myTabContent1" class="tab-content"> + <div class="tab-pane fade in active" id="home1"> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + </div> + <div class="tab-pane fade" id="profile1"> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + </div> + <div class="tab-pane fade" id="dropdown1-1"> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + </div> + <div class="tab-pane fade" id="dropdown1-2"> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + </div> + </div> + + <h4>Tabs without fade (no initially active pane)</h4> + + <ul id="myTab2" class="nav nav-tabs"> + <li><a href="#home2" data-toggle="tab">Home</a></li> + <li><a href="#profile2" data-toggle="tab">Profile</a></li> + <li class="dropdown"> + <a href="#" id="myTabDrop3" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="myTabDrop3"> + <li><a href="#dropdown2-1" data-toggle="tab">@fat</a></li> + <li><a href="#dropdown2-2" data-toggle="tab">@mdo</a></li> + </ul> + </li> + </ul> + <div id="myTabContent2" class="tab-content"> + <div class="tab-pane" id="home2"> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + </div> + <div class="tab-pane" id="profile2"> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + </div> + <div class="tab-pane" id="dropdown2-1"> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + </div> + <div class="tab-pane" id="dropdown2-2"> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + </div> + </div> + + <h4>Tabs with fade (no initially active pane)</h4> + + <ul id="myTab3" class="nav nav-tabs"> + <li><a href="#home3" data-toggle="tab">Home</a></li> + <li><a href="#profile3" data-toggle="tab">Profile</a></li> + <li class="dropdown"> + <a href="#" id="myTabDrop4" class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown <b class="caret"></b></a> + <ul class="dropdown-menu" aria-labelledby="myTabDrop4"> + <li><a href="#dropdown3-1" data-toggle="tab">@fat</a></li> + <li><a href="#dropdown3-2" data-toggle="tab">@mdo</a></li> + </ul> + </li> + </ul> + <div id="myTabContent3" class="tab-content"> + <div class="tab-pane fade" id="home3"> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + <p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p> + </div> + <div class="tab-pane fade" id="profile3"> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + <p>Food truck fixie locavore, accusamus mcsweeney's marfa nulla single-origin coffee squid. Exercitation +1 labore velit, blog sartorial PBR leggings next level wes anderson artisan four loko farm-to-table craft beer twee. Qui photo booth letterpress, commodo enim craft beer mlkshk aliquip jean shorts ullamco ad vinyl cillum PBR. Homo nostrud organic, assumenda labore aesthetic magna delectus mollit. Keytar helvetica VHS salvia yr, vero magna velit sapiente labore stumptown. Vegan fanny pack odio cillum wes anderson 8-bit, sustainable jean shorts beard ut DIY ethical culpa terry richardson biodiesel. Art party scenester stumptown, tumblr butcher vero sint qui sapiente accusamus tattooed echo park.</p> + </div> + <div class="tab-pane fade" id="dropdown3-1"> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + <p>Etsy mixtape wayfarers, ethical wes anderson tofu before they sold out mcsweeney's organic lomo retro fanny pack lo-fi farm-to-table readymade. Messenger bag gentrify pitchfork tattooed craft beer, iphone skateboard locavore carles etsy salvia banksy hoodie helvetica. DIY synth PBR banksy irony. Leggings gentrify squid 8-bit cred pitchfork. Williamsburg banh mi whatever gluten-free, carles pitchfork biodiesel fixie etsy retro mlkshk vice blog. Scenester cred you probably haven't heard of them, vinyl craft beer blog stumptown. Pitchfork sustainable tofu synth chambray yr.</p> + </div> + <div class="tab-pane fade" id="dropdown3-2"> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + <p>Trust fund seitan letterpress, keytar raw denim keffiyeh etsy art party before they sold out master cleanse gluten-free squid scenester freegan cosby sweater. Fanny pack portland seitan DIY, art party locavore wolf cliche high life echo park Austin. Cred vinyl keffiyeh DIY salvia PBR, banh mi before they sold out farm-to-table VHS viral locavore cosby sweater. Lomo wolf viral, mustache readymade thundercats keffiyeh craft beer marfa ethical. Wolf salvia freegan, sartorial keffiyeh echo park vegan.</p> + </div> + </div> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../tab.js"></script> +<script src="../../dropdown.js"></script> + +</body> +</html> diff --git a/bootstrap/js/tests/visual/tooltip.html b/bootstrap/js/tests/visual/tooltip.html new file mode 100755 index 0000000..d7e99f9 --- /dev/null +++ b/bootstrap/js/tests/visual/tooltip.html @@ -0,0 +1,52 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title>Tooltip</title> + <link rel="stylesheet" href="../../../dist/css/bootstrap.min.css"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> +</head> +<body> + +<div class="container"> + + <div class="page-header"> + <h1>Tooltip <small>Bootstrap Visual Test</small></h1> + </div> + + <p class="muted" style="margin-bottom: 0;">Tight pants next level keffiyeh <a href="#" data-toggle="tooltip" title="" data-original-title="Default tooltip">you probably</a> haven't heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's fixie sustainable quinoa 8-bit american apparel <a href="#" data-toggle="tooltip" title="" data-original-title="Another tooltip">have a</a> terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's cleanse vegan chambray. A really ironic artisan <a href="#" data-toggle="tooltip" title="" data-original-title="Another one here too">whatever keytar</a>, scenester farm-to-table banksy Austin <a href="#" data-toggle="tooltip" title="" data-original-title="The last tip!">twitter handle</a> freegan cred raw denim single-origin coffee viral. + </p> + <hr> + <p> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="left" title="" data-original-title="Tooltip on left">Tooltip on left</button> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="top" title="Tooltip on top">Tooltip on top</button> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="bottom" title="Tooltip on bottom">Tooltip on bottom</button> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-placement="right" title="Tooltip on right">Tooltip on right</button> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-container="<img src=1 onerror=\'alert(0)\'>" title="Tooltip on right">Tooltip with XSS on data-container</button> + <button type="button" class="btn btn-default" data-toggle="tooltip" data-viewport="<img src=1 onerror=\'alert(0)\'>" title="Tooltip on right">Tooltip with XSS on data-viewport</button> + </p> + +</div> + +<!-- JavaScript Includes --> +<script src="../vendor/jquery.min.js"></script> +<script src="../../transition.js"></script> +<script src="../../tooltip.js"></script> + +<!-- JavaScript Test --> +<script> +$(function () { + $('[data-toggle="tooltip"]').tooltip() +}) +</script> + +</body> +</html> |