aboutsummaryrefslogtreecommitdiff
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/tests/index.html135
-rw-r--r--js/tests/unit/tooltip.js81
-rw-r--r--js/tests/vendor/qunit.css70
-rw-r--r--js/tests/vendor/qunit.js138
-rw-r--r--js/tooltip.js102
5 files changed, 349 insertions, 177 deletions
diff --git a/js/tests/index.html b/js/tests/index.html
index c6d3d27af..120ed933c 100644
--- a/js/tests/index.html
+++ b/js/tests/index.html
@@ -1,77 +1,78 @@
-<!DOCTYPE HTML>
+<!DOCTYPE html>
<html>
-<head>
- <title>Bootstrap Plugin Test Suite</title>
+ <head>
+ <meta charset="utf-8">
+ <title>Bootstrap Plugin Test Suite</title>
- <!-- jQuery -->
- <script src="vendor/jquery.js"></script>
+ <!-- jQuery -->
+ <script src="vendor/jquery.js"></script>
- <!-- QUnit -->
- <link rel="stylesheet" href="vendor/qunit.css" media="screen">
- <script src="vendor/qunit.js"></script>
- <script>
- // See https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
- var log = []
- QUnit.done = function (test_results) {
- var tests = log.map(function (details) {
- return {
- name: details.name,
- result: details.result,
- expected: details.expected,
- actual: details.actual,
- source: details.source
- }
- })
- test_results.tests = tests
+ <!-- QUnit -->
+ <link rel="stylesheet" href="vendor/qunit.css" media="screen">
+ <script src="vendor/qunit.js"></script>
+ <script>
+ // See https://github.com/axemclion/grunt-saucelabs#test-result-details-with-qunit
+ var log = []
+ QUnit.done = function (test_results) {
+ var tests = log.map(function (details) {
+ return {
+ name: details.name,
+ result: details.result,
+ expected: details.expected,
+ actual: details.actual,
+ source: details.source
+ }
+ })
+ test_results.tests = tests
- // Delaying results a bit because in real-world scenario you won't get them immediately
- setTimeout(function () {
- window.global_test_results = test_results
- }, 2000)
- }
+ // Delaying results a bit because in real-world scenario you won't get them immediately
+ setTimeout(function () {
+ window.global_test_results = test_results
+ }, 2000)
+ }
- QUnit.testStart(function (testDetails) {
- QUnit.log = function (details) {
- if (!details.result) {
- details.name = testDetails.name
- log.push(details)
+ QUnit.testStart(function (testDetails) {
+ QUnit.log = function (details) {
+ if (!details.result) {
+ details.name = testDetails.name
+ log.push(details)
+ }
}
- }
- })
- </script>
+ })
+ </script>
- <!-- Plugin sources -->
- <script>$.support.transition = false</script>
- <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>
+ <!-- Plugin sources -->
+ <script>$.support.transition = false</script>
+ <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>
+ <!-- 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>
- <div id="qunit"></div>
- <div id="qunit-fixture"></div>
- </div>
-</body>
+ </head>
+ <body>
+ <div>
+ <div id="qunit"></div>
+ <div id="qunit-fixture"></div>
+ </div>
+ </body>
</html>
diff --git a/js/tests/unit/tooltip.js b/js/tests/unit/tooltip.js
index 9df234236..e670883e3 100644
--- a/js/tests/unit/tooltip.js
+++ b/js/tests/unit/tooltip.js
@@ -337,12 +337,12 @@ $(function () {
})
test('should add position class before positioning so that position-specific styles are taken into account', function () {
- $('head').append('<style> .tooltip.right { white-space: nowrap; } .tooltip.right .tooltip-inner { max-width: none; } </style>')
+ $('head').append('<style id="test"> .tooltip.right { white-space: nowrap; } .tooltip.right .tooltip-inner { max-width: none; } </style>')
var container = $('<div />').appendTo('body'),
target = $('<a href="#" rel="tooltip" title="very very very very very very very very long tooltip in one line"></a>')
.appendTo(container)
- .tooltip({placement: 'right'})
+ .tooltip({placement: 'right', viewport: null})
.tooltip('show'),
tooltip = container.find('.tooltip')
@@ -352,6 +352,7 @@ $(function () {
var topDiff = top - top2
ok(topDiff <= 1 && topDiff >= -1)
target.tooltip('hide')
+ $('head #test').remove()
})
test('tooltip title test #1', function () {
@@ -428,4 +429,80 @@ $(function () {
ttContainer.remove()
})
+ test('should adjust the tip\'s top when up against the top of the viewport', function () {
+ $('head').append('<style id="test"> .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; } </style>')
+
+ var container = $('<div />').appendTo('body'),
+ target = $('<a href="#" rel="tooltip" title="tip" style="position: fixed; top: 0px; left: 0px;"></a>')
+ .appendTo(container)
+ .tooltip({placement: 'right', viewport: {selector: 'body', padding: 12}})
+ .tooltip('show'),
+ tooltip = container.find('.tooltip')
+
+ ok( Math.round(tooltip.offset().top) === 12 )
+ target.tooltip('hide')
+ $('head #test').remove()
+ })
+
+ test('should adjust the tip\'s top when up against the bottom of the viewport', function () {
+ $('head').append('<style id="test"> .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; } </style>')
+
+ var container = $('<div />').appendTo('body'),
+ target = $('<a href="#" rel="tooltip" title="tip" style="position: fixed; bottom: 0px; left: 0px;"></a>')
+ .appendTo(container)
+ .tooltip({placement: 'right', viewport: {selector: 'body', padding: 12}})
+ .tooltip('show'),
+ tooltip = container.find('.tooltip')
+
+ ok( Math.round(tooltip.offset().top) === Math.round($(window).height() - 12 - tooltip[0].offsetHeight) )
+ target.tooltip('hide')
+ $('head #test').remove()
+ })
+
+ test('should adjust the tip\'s left when up against the left of the viewport', function () {
+ $('head').append('<style id="test"> .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; } </style>')
+
+ var container = $('<div />').appendTo('body'),
+ target = $('<a href="#" rel="tooltip" title="tip" style="position: fixed; top: 0px; left: 0px;"></a>')
+ .appendTo(container)
+ .tooltip({placement: 'bottom', viewport: {selector: 'body', padding: 12}})
+ .tooltip('show'),
+ tooltip = container.find('.tooltip')
+
+ ok( Math.round(tooltip.offset().left) === 12 )
+ target.tooltip('hide')
+ $('head #test').remove()
+ })
+
+ test('should adjust the tip\'s left when up against the right of the viewport', function () {
+ $('head').append('<style id="test"> .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; } </style>')
+
+ var container = $('<div />').appendTo('body'),
+ target = $('<a href="#" rel="tooltip" title="tip" style="position: fixed; top: 0px; right: 0px;"></a>')
+ .appendTo(container)
+ .tooltip({placement: 'bottom', viewport: {selector: 'body', padding: 12}})
+ .tooltip('show'),
+ tooltip = container.find('.tooltip')
+
+ ok( Math.round(tooltip.offset().left) === Math.round($(window).width() - 12 - tooltip[0].offsetWidth) )
+ target.tooltip('hide')
+ $('head #test').remove()
+ })
+
+ test('should adjust the tip when up against the right of an arbitrary viewport', function () {
+ $('head').append('<style id="test"> .tooltip, .tooltip .tooltip-inner { width: 200px; height: 200px; max-width: none; } </style>')
+ $('head').append('<style id="viewport-style"> .container-viewport { position: absolute; top: 50px; left: 60px; width: 300px; height: 300px; } </style>')
+
+ var container = $('<div />', {class: 'container-viewport'}).appendTo('body'),
+ target = $('<a href="#" rel="tooltip" title="tip" style="position: fixed; top: 50px; left: 350px;"></a>')
+ .appendTo(container)
+ .tooltip({placement: 'bottom', viewport: '.container-viewport'})
+ .tooltip('show'),
+ tooltip = container.find('.tooltip')
+
+ ok( Math.round(tooltip.offset().left) === Math.round(60 + container.width() - tooltip[0].offsetWidth) )
+ target.tooltip('hide')
+ $('head #test').remove()
+ $('head #viewport-style').remove()
+ })
})
diff --git a/js/tests/vendor/qunit.css b/js/tests/vendor/qunit.css
index 26a85d24b..93026e3ba 100644
--- a/js/tests/vendor/qunit.css
+++ b/js/tests/vendor/qunit.css
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.13.0
+ * QUnit 1.14.0
* http://qunitjs.com/
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-01-04T17:09Z
+ * Date: 2014-01-31T16:40Z
*/
/** Font Family and Sizes */
@@ -32,32 +32,29 @@
#qunit-header {
padding: 0.5em 0 0.5em 1em;
- color: #8699a4;
- background-color: #0d3349;
+ color: #8699A4;
+ background-color: #0D3349;
font-size: 1.5em;
line-height: 1em;
- font-weight: normal;
+ font-weight: 400;
border-radius: 5px 5px 0 0;
- -moz-border-radius: 5px 5px 0 0;
- -webkit-border-top-right-radius: 5px;
- -webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
- color: #c2ccd1;
+ color: #C2CCD1;
}
#qunit-header a:hover,
#qunit-header a:focus {
- color: #fff;
+ color: #FFF;
}
#qunit-testrunner-toolbar label {
display: inline-block;
- padding: 0 .5em 0 .1em;
+ padding: 0 0.5em 0 0.1em;
}
#qunit-banner {
@@ -67,14 +64,14 @@
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
- background-color: #eee;
+ background-color: #EEE;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
- background-color: #2b81af;
- color: #fff;
+ background-color: #2B81AF;
+ color: #FFF;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
@@ -90,7 +87,7 @@
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
- border-bottom: 1px solid #fff;
+ border-bottom: 1px solid #FFF;
list-style-position: inside;
}
@@ -104,7 +101,7 @@
#qunit-tests li a {
padding: 0.5em;
- color: #c2ccd1;
+ color: #C2CCD1;
text-decoration: none;
}
#qunit-tests li a:hover,
@@ -121,11 +118,9 @@
margin-top: 0.5em;
padding: 0.5em;
- background-color: #fff;
+ background-color: #FFF;
border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
}
.qunit-collapsed {
@@ -134,13 +129,13 @@
#qunit-tests table {
border-collapse: collapse;
- margin-top: .2em;
+ margin-top: 0.2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
- padding: 0 .5em 0 0;
+ padding: 0 0.5em 0 0;
}
#qunit-tests td {
@@ -154,26 +149,26 @@
}
#qunit-tests del {
- background-color: #e0f2be;
- color: #374e0c;
+ background-color: #E0F2BE;
+ color: #374E0C;
text-decoration: none;
}
#qunit-tests ins {
- background-color: #ffcaca;
+ background-color: #FFCACA;
color: #500;
text-decoration: none;
}
/*** Test Counts */
-#qunit-tests b.counts { color: black; }
+#qunit-tests b.counts { color: #000; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
- background-color: #fff;
+ background-color: #FFF;
border-bottom: none;
list-style-position: inside;
}
@@ -181,8 +176,8 @@
/*** Passing Styles */
#qunit-tests li li.pass {
- color: #3c510c;
- background-color: #fff;
+ color: #3C510C;
+ background-color: #FFF;
border-left: 10px solid #C6E746;
}
@@ -190,7 +185,7 @@
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
-#qunit-tests .pass .test-expected { color: #999999; }
+#qunit-tests .pass .test-expected { color: #999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
@@ -198,24 +193,21 @@
#qunit-tests li li.fail {
color: #710909;
- background-color: #fff;
+ background-color: #FFF;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- -webkit-border-bottom-right-radius: 5px;
- -webkit-border-bottom-left-radius: 5px;
}
-#qunit-tests .fail { color: #000000; background-color: #EE5757; }
+#qunit-tests .fail { color: #000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
-#qunit-tests .fail .module-name { color: #000000; }
+#qunit-tests .fail .module-name { color: #000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
-#qunit-tests .fail .test-expected { color: green; }
+#qunit-tests .fail .test-expected { color: #008000; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
@@ -225,13 +217,13 @@
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
- color: #2b81af;
+ color: #2B81AF;
background-color: #D2E0E6;
- border-bottom: 1px solid white;
+ border-bottom: 1px solid #FFF;
}
#qunit-testresult .module-name {
- font-weight: bold;
+ font-weight: 700;
}
/** Fixture */
diff --git a/js/tests/vendor/qunit.js b/js/tests/vendor/qunit.js
index a2fb2e884..0e279fde1 100644
--- a/js/tests/vendor/qunit.js
+++ b/js/tests/vendor/qunit.js
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.13.0
+ * QUnit 1.14.0
* http://qunitjs.com/
*
* Copyright 2013 jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-01-04T17:09Z
+ * Date: 2014-01-31T16:40Z
*/
(function( window ) {
@@ -22,6 +22,7 @@ var QUnit,
// Keep a local reference to Date (GH-283)
Date = window.Date,
setTimeout = window.setTimeout,
+ clearTimeout = window.clearTimeout,
defined = {
document: typeof window.document !== "undefined",
setTimeout: typeof window.setTimeout !== "undefined",
@@ -238,6 +239,9 @@ config = {
// by default, modify document.title when suite is done
altertitle: true,
+ // by default, scroll to top of the page when suite is done
+ scrolltop: true,
+
// when enabled, all tests must call expect()
requireExpects: false,
@@ -271,20 +275,24 @@ config = {
// Initialize more QUnit.config and QUnit.urlParams
(function() {
- var i,
+ var i, current,
location = window.location || { search: "", protocol: "file:" },
params = location.search.slice( 1 ).split( "&" ),
length = params.length,
- urlParams = {},
- current;
+ urlParams = {};
if ( params[ 0 ] ) {
for ( i = 0; i < length; i++ ) {
current = params[ i ].split( "=" );
current[ 0 ] = decodeURIComponent( current[ 0 ] );
+
// allow just a key to turn on a flag, e.g., test.html?noglobals
current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- urlParams[ current[ 0 ] ] = current[ 1 ];
+ if ( urlParams[ current[ 0 ] ] ) {
+ urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
+ } else {
+ urlParams[ current[ 0 ] ] = current[ 1 ];
+ }
}
}
@@ -296,7 +304,16 @@ config = {
// Exact match of the module name
config.module = urlParams.module;
- config.testNumber = parseInt( urlParams.testNumber, 10 ) || null;
+ config.testNumber = [];
+ if ( urlParams.testNumber ) {
+
+ // Ensure that urlParams.testNumber is an array
+ urlParams.testNumber = [].concat( urlParams.testNumber );
+ for ( i = 0; i < urlParams.testNumber.length; i++ ) {
+ current = urlParams.testNumber[ i ];
+ config.testNumber.push( parseInt( current, 10 ) );
+ }
+ }
// Figure out if we're running the tests from a server or not
QUnit.isLocal = location.protocol === "file:";
@@ -558,8 +575,8 @@ QUnit.load = function() {
runLoggingCallbacks( "begin", QUnit, {} );
// Initialize the config, saving the execution queue
- var banner, filter, i, label, len, main, ol, toolbar, userAgent, val,
- urlConfigCheckboxesContainer, urlConfigCheckboxes, moduleFilter,
+ var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
+ urlConfigContainer, moduleFilter, userAgent,
numModules = 0,
moduleNames = [],
moduleFilterHtml = "",
@@ -578,17 +595,55 @@ QUnit.load = function() {
if ( typeof val === "string" ) {
val = {
id: val,
- label: val,
- tooltip: "[no tooltip available]"
+ label: val
};
}
config[ val.id ] = QUnit.urlParams[ val.id ];
- urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
- "' name='" + escapeText( val.id ) +
- "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) +
- " title='" + escapeText( val.tooltip ) +
- "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
- "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
+ if ( !val.value || typeof val.value === "string" ) {
+ urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
+ "' name='" + escapeText( val.id ) +
+ "' type='checkbox'" +
+ ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
+ ( config[ val.id ] ? " checked='checked'" : "" ) +
+ " title='" + escapeText( val.tooltip ) +
+ "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
+ "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
+ } else {
+ urlConfigHtml += "<label for='qunit-urlconfig-" + escapeText( val.id ) +
+ "' title='" + escapeText( val.tooltip ) +
+ "'>" + val.label +
+ ": </label><select id='qunit-urlconfig-" + escapeText( val.id ) +
+ "' name='" + escapeText( val.id ) +
+ "' title='" + escapeText( val.tooltip ) +
+ "'><option></option>";
+ selection = false;
+ if ( QUnit.is( "array", val.value ) ) {
+ for ( j = 0; j < val.value.length; j++ ) {
+ urlConfigHtml += "<option value='" + escapeText( val.value[j] ) + "'" +
+ ( config[ val.id ] === val.value[j] ?
+ (selection = true) && " selected='selected'" :
+ "" ) +
+ ">" + escapeText( val.value[j] ) + "</option>";
+ }
+ } else {
+ for ( j in val.value ) {
+ if ( hasOwn.call( val.value, j ) ) {
+ urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
+ ( config[ val.id ] === j ?
+ (selection = true) && " selected='selected'" :
+ "" ) +
+ ">" + escapeText( val.value[j] ) + "</option>";
+ }
+ }
+ }
+ if ( config[ val.id ] && !selection ) {
+ urlConfigHtml += "<option value='" + escapeText( config[ val.id ] ) +
+ "' selected='selected' disabled='disabled'>" +
+ escapeText( config[ val.id ] ) +
+ "</option>";
+ }
+ urlConfigHtml += "</select>";
+ }
}
for ( i in config.modules ) {
if ( config.modules.hasOwnProperty( i ) ) {
@@ -665,20 +720,27 @@ QUnit.load = function() {
label.innerHTML = "Hide passed tests";
toolbar.appendChild( label );
- urlConfigCheckboxesContainer = document.createElement("span");
- urlConfigCheckboxesContainer.innerHTML = urlConfigHtml;
- urlConfigCheckboxes = urlConfigCheckboxesContainer.getElementsByTagName("input");
+ urlConfigContainer = document.createElement("span");
+ urlConfigContainer.innerHTML = urlConfigHtml;
// For oldIE support:
// * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change"
+ // * Use "click" instead of "change" for checkboxes
// * Fallback from event.target to event.srcElement
- addEvents( urlConfigCheckboxes, "click", function( event ) {
+ addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
var params = {},
target = event.target || event.srcElement;
- params[ target.name ] = target.checked ? true : undefined;
+ params[ target.name ] = target.checked ?
+ target.defaultValue || true :
+ undefined;
window.location = QUnit.url( params );
});
- toolbar.appendChild( urlConfigCheckboxesContainer );
+ addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
+ var params = {},
+ target = event.target || event.srcElement;
+ params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
+ window.location = QUnit.url( params );
+ });
+ toolbar.appendChild( urlConfigContainer );
if (numModules > 1) {
moduleFilter = document.createElement( "span" );
@@ -807,7 +869,7 @@ function done() {
}
// scroll back to top to show results
- if ( window.scrollTo ) {
+ if ( config.scrolltop && window.scrollTo ) {
window.scrollTo(0, 0);
}
@@ -824,7 +886,7 @@ function validTest( test ) {
var include,
filter = config.filter && config.filter.toLowerCase(),
module = config.module && config.module.toLowerCase(),
- fullName = (test.module + ": " + test.testName).toLowerCase();
+ fullName = ( test.module + ": " + test.testName ).toLowerCase();
// Internally-generated tests are always valid
if ( test.callback && test.callback.validTest === validTest ) {
@@ -832,8 +894,10 @@ function validTest( test ) {
return true;
}
- if ( config.testNumber ) {
- return test.testNumber === config.testNumber;
+ if ( config.testNumber.length > 0 ) {
+ if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
+ return false;
+ }
}
if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
@@ -1375,7 +1439,7 @@ Test.prototype = {
total: this.assertions.length,
runtime: this.runtime,
// DEPRECATED: this property will be removed in 2.0.0, use runtime instead
- duration: this.runtime,
+ duration: this.runtime
});
QUnit.reset();
@@ -1543,7 +1607,7 @@ assert = QUnit.assert = {
ok = false;
// 'expected' is optional
- if ( typeof expected === "string" ) {
+ if ( !message && typeof expected === "string" ) {
message = expected;
expected = null;
}
@@ -1557,16 +1621,30 @@ assert = QUnit.assert = {
config.current.ignoreGlobalErrors = false;
if ( actual ) {
+
// we don't want to validate thrown error
if ( !expected ) {
ok = true;
expectedOutput = null;
+
+ // expected is an Error object
+ } else if ( expected instanceof Error ) {
+ ok = actual instanceof Error &&
+ actual.name === expected.name &&
+ actual.message === expected.message;
+
// expected is a regexp
} else if ( QUnit.objectType( expected ) === "regexp" ) {
ok = expected.test( errorString( actual ) );
+
+ // expected is a string
+ } else if ( QUnit.objectType( expected ) === "string" ) {
+ ok = expected === errorString( actual );
+
// expected is a constructor
} else if ( actual instanceof expected ) {
ok = true;
+
// expected is a validation function which returns true is validation passed
} else if ( expected.call( {}, actual ) === true ) {
expectedOutput = null;
diff --git a/js/tooltip.js b/js/tooltip.js
index eb7875c9f..f27beacc6 100644
--- a/js/tooltip.js
+++ b/js/tooltip.js
@@ -34,14 +34,19 @@
title: '',
delay: 0,
html: false,
- container: false
+ container: false,
+ viewport: {
+ selector: 'body',
+ padding: 0
+ }
}
Tooltip.prototype.init = function (type, element, options) {
- this.enabled = true
- this.type = type
- this.$element = $(element)
- this.options = this.getOptions(options)
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
var triggers = this.options.trigger.split(' ')
@@ -157,18 +162,14 @@
var actualHeight = $tip[0].offsetHeight
if (autoPlace) {
- var $parent = this.$element.parent()
-
var orgPlacement = placement
- var docScroll = document.documentElement.scrollTop
- var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
- var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
- var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
-
- placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
- placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
- placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
- placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ var $parent = this.$element.parent()
+ var parentDim = this.getPosition($parent)
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - parentDim.scroll > parentDim.height ? 'top' :
+ placement == 'top' && pos.top - parentDim.scroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentDim.width ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentDim.left ? 'right' :
placement
$tip
@@ -228,29 +229,20 @@
var actualHeight = $tip[0].offsetHeight
if (placement == 'top' && actualHeight != height) {
- replace = true
offset.top = offset.top + height - actualHeight
}
- if (/bottom|top/.test(placement)) {
- var delta = 0
+ var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
- if (offset.left < 0) {
- delta = offset.left * -2
- offset.left = 0
+ if (delta.left) offset.left += delta.left
+ else offset.top += delta.top
- $tip.offset(offset)
-
- actualWidth = $tip[0].offsetWidth
- actualHeight = $tip[0].offsetHeight
- }
+ var arrowDelta = delta.left ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
+ var arrowPosition = delta.left ? 'left' : 'top'
+ var arrowOffsetPosition = delta.left ? 'offsetWidth' : 'offsetHeight'
- this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
- } else {
- this.replaceArrow(actualHeight - height, actualHeight, 'top')
- }
-
- if (replace) $tip.offset(offset)
+ $tip.offset(offset)
+ this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], arrowPosition)
}
Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
@@ -303,12 +295,15 @@
return this.getTitle()
}
- Tooltip.prototype.getPosition = function () {
- var el = this.$element[0]
- return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
- width: el.offsetWidth,
- height: el.offsetHeight
- }, this.$element.offset())
+ Tooltip.prototype.getPosition = function ($element) {
+ $element = $element || this.$element
+ var el = $element[0]
+ var isBody = el.tagName == 'BODY'
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : null, {
+ scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop(),
+ width: isBody ? $(window).width() : $element.outerWidth(),
+ height: isBody ? $(window).height() : $element.outerHeight()
+ }, isBody ? {top: 0, left: 0} : $element.offset())
}
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
@@ -316,6 +311,35 @@
placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+
+ }
+
+ Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
+ var delta = { top: 0, left: 0 }
+ if (!this.$viewport) return delta
+
+ var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
+ var viewportDimensions = this.getPosition(this.$viewport)
+
+ if (/right|left/.test(placement)) {
+ var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
+ var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
+ if (topEdgeOffset < viewportDimensions.top) { // top overflow
+ delta.top = viewportDimensions.top - topEdgeOffset
+ } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
+ delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
+ }
+ } else {
+ var leftEdgeOffset = pos.left - viewportPadding
+ var rightEdgeOffset = pos.left + viewportPadding + actualWidth
+ if (leftEdgeOffset < viewportDimensions.left) { // left overflow
+ delta.left = viewportDimensions.left - leftEdgeOffset
+ } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow
+ delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
+ }
+ }
+
+ return delta
}
Tooltip.prototype.getTitle = function () {