mirror of
https://github.com/jquery/jquery.git
synced 2024-12-09 08:04:24 +00:00
8eb35e8513
- iOS 12 and below do not support scrollTop/Left on the
window or document. Before 82169df
, window.supportsScroll
was always undefined. There were 2 issues: (1) iOS <=12 do
support scroll props on the body, so the support test
wasn't helpful. (2) one test checked the wrong window and
the value was always undefined, which meant those tests
never ran in any browser.
Closes gh-5506
846 lines
35 KiB
JavaScript
846 lines
35 KiB
JavaScript
( function() {
|
|
|
|
if ( !includesModule( "offset" ) ) {
|
|
return;
|
|
}
|
|
|
|
var alwaysScrollable, supportsFixedPosition, supportsScroll,
|
|
forceScroll = supportjQuery( "<div></div>" ).css( { width: 2000, height: 2000 } ),
|
|
checkSupport = function( assert ) {
|
|
|
|
// Only run once
|
|
checkSupport = false;
|
|
|
|
var checkFixed = supportjQuery( "<div/>" )
|
|
.css( { position: "fixed", top: "20px" } )
|
|
.appendTo( "#qunit-fixture" );
|
|
supportsFixedPosition = checkFixed[ 0 ].offsetTop === 20;
|
|
checkFixed.remove();
|
|
|
|
// Append forceScroll to the body instead of #qunit-fixture because the latter is hidden
|
|
forceScroll.appendTo( "body" );
|
|
window.scrollTo( 200, 200 );
|
|
supportsScroll = !!document.documentElement.scrollTop;
|
|
|
|
forceScroll.detach();
|
|
|
|
// Support: iOS <=7
|
|
// Hijack the iframe test infrastructure to detect viewport scrollability
|
|
// for pages with position:fixed document element
|
|
var done = assert.async();
|
|
testIframe(
|
|
null,
|
|
"offset/boxes.html",
|
|
function( assert, $, win, doc ) {
|
|
var scrollTop = win.pageYOffset,
|
|
scrollLeft = win.pageXOffset;
|
|
doc.documentElement.style.position = "fixed";
|
|
win.scrollTo( scrollLeft, scrollTop );
|
|
alwaysScrollable = win.pageXOffset !== 0;
|
|
done();
|
|
},
|
|
function mockQUnit_test( _, testCallback ) {
|
|
setTimeout( function() {
|
|
testCallback( assert );
|
|
} );
|
|
}
|
|
);
|
|
};
|
|
|
|
QUnit.module( "offset", { beforeEach: function( assert ) {
|
|
if ( typeof checkSupport === "function" ) {
|
|
checkSupport( assert );
|
|
}
|
|
|
|
// Force a scroll value on the main window to ensure incorrect results
|
|
// if offset is using the scroll offset of the parent window
|
|
forceScroll.appendTo( "body" );
|
|
window.scrollTo( 1, 1 );
|
|
forceScroll.detach();
|
|
}, afterEach: moduleTeardown } );
|
|
|
|
QUnit.test( "empty set", function( assert ) {
|
|
assert.expect( 2 );
|
|
assert.strictEqual( jQuery().offset(), undefined, "offset() returns undefined for empty set (trac-11962)" );
|
|
assert.strictEqual( jQuery().position(), undefined, "position() returns undefined for empty set (trac-11962)" );
|
|
} );
|
|
|
|
QUnit.test( "disconnected element", function( assert ) {
|
|
assert.expect( 4 );
|
|
|
|
var result = jQuery( document.createElement( "div" ) ).offset();
|
|
|
|
// These tests are solely for main/compat consistency
|
|
// Retrieving offset on disconnected/hidden elements is not officially
|
|
// valid input, but will return zeros for back-compat
|
|
assert.equal( result.top, 0, "Retrieving offset on disconnected elements returns zeros (gh-2310)" );
|
|
assert.equal( result.left, 0, "Retrieving offset on disconnected elements returns zeros (gh-2310)" );
|
|
assert.equal( Object.keys( result ).length, 2, "Retrieving offset on disconnected elements returns offset object (gh-3167)" );
|
|
assert.equal( jQuery.isPlainObject( result ), true, "Retrieving offset on disconnected elements returns plain object (gh-3612)" );
|
|
} );
|
|
|
|
QUnit.test( "hidden (display: none) element", function( assert ) {
|
|
assert.expect( 4 );
|
|
|
|
var node = jQuery( "<div style='display: none'></div>" ).appendTo( "#qunit-fixture" ),
|
|
result = node.offset();
|
|
|
|
node.remove();
|
|
|
|
// These tests are solely for main/compat consistency
|
|
// Retrieving offset on disconnected/hidden elements is not officially
|
|
// valid input, but will return zeros for back-compat
|
|
assert.equal( result.top, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" );
|
|
assert.equal( result.left, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" );
|
|
assert.equal( Object.keys( result ).length, 2, "Retrieving offset on hidden elements returns offset object (gh-3167)" );
|
|
assert.equal( jQuery.isPlainObject( result ), true, "Retrieving offset on hidden elements returns plain object (gh-3612)" );
|
|
} );
|
|
|
|
QUnit.test( "0 sized element", function( assert ) {
|
|
assert.expect( 4 );
|
|
|
|
var node = jQuery( "<div style='margin: 5px; width: 0; height: 0'></div>" ).appendTo( "#qunit-fixture" ),
|
|
result = node.offset();
|
|
|
|
node.remove();
|
|
|
|
assert.notEqual( result.top, 0, "Retrieving offset on 0 sized elements (gh-3167)" );
|
|
assert.notEqual( result.left, 0, "Retrieving offset on 0 sized elements (gh-3167)" );
|
|
assert.equal( Object.keys( result ).length, 2, "Retrieving offset on 0 sized elements returns offset object (gh-3167)" );
|
|
assert.equal( jQuery.isPlainObject( result ), true, "Retrieving offset on 0 sized elements returns plain object (gh-3612)" );
|
|
} );
|
|
|
|
QUnit.test( "hidden (visibility: hidden) element", function( assert ) {
|
|
assert.expect( 4 );
|
|
|
|
var node = jQuery( "<div style='margin: 5px; visibility: hidden'></div>" ).appendTo( "#qunit-fixture" ),
|
|
result = node.offset();
|
|
|
|
node.remove();
|
|
|
|
assert.notEqual( result.top, 0, "Retrieving offset on visibility:hidden elements (gh-3167)" );
|
|
assert.notEqual( result.left, 0, "Retrieving offset on visibility:hidden elements (gh-3167)" );
|
|
assert.equal( Object.keys( result ).length, 2, "Retrieving offset on visibility:hidden elements returns offset object (gh-3167)" );
|
|
assert.equal( jQuery.isPlainObject( result ), true, "Retrieving offset on visibility:hidden elements returns plain object (gh-3612)" );
|
|
} );
|
|
|
|
QUnit.test( "normal element", function( assert ) {
|
|
assert.expect( 4 );
|
|
|
|
var node = jQuery( "<div>" ).appendTo( "#qunit-fixture" ),
|
|
offset = node.offset(),
|
|
position = node.position();
|
|
|
|
node.remove();
|
|
|
|
assert.equal( Object.keys( offset ).length, 2, "Retrieving offset on normal elements returns offset object (gh-3612)" );
|
|
assert.equal( jQuery.isPlainObject( offset ), true, "Retrieving offset on normal elements returns plain object (gh-3612)" );
|
|
|
|
assert.equal( Object.keys( position ).length, 2, "Retrieving position on normal elements returns offset object (gh-3612)" );
|
|
assert.equal( jQuery.isPlainObject( position ), true, "Retrieving position on normal elements returns plain object (gh-3612)" );
|
|
} );
|
|
|
|
testIframe( "absolute", "offset/absolute.html", function( assert, $, iframe ) {
|
|
assert.expect( 4 );
|
|
|
|
var doc = iframe.document,
|
|
tests;
|
|
|
|
// get offset
|
|
tests = [
|
|
{ "id": "#absolute-1", "top": 1, "left": 1 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( jQuery( this.id, doc ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
|
|
assert.equal( jQuery( this.id, doc ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
|
|
} );
|
|
|
|
// get position
|
|
tests = [
|
|
{ "id": "#absolute-1", "top": 0, "left": 0 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( jQuery( this.id, doc ).position().top, this.top, "jQuery('" + this.id + "').position().top" );
|
|
assert.equal( jQuery( this.id, doc ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
|
|
} );
|
|
} );
|
|
|
|
testIframe( "absolute", "offset/absolute.html", function( assert, $ ) {
|
|
assert.expect( 178 );
|
|
|
|
var tests, offset;
|
|
|
|
// get offset tests
|
|
tests = [
|
|
{ "id": "#absolute-1", "top": 1, "left": 1 },
|
|
{ "id": "#absolute-1-1", "top": 5, "left": 5 },
|
|
{ "id": "#absolute-1-1-1", "top": 9, "left": 9 },
|
|
{ "id": "#absolute-2", "top": 20, "left": 20 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
|
|
} );
|
|
|
|
// get position
|
|
tests = [
|
|
{ "id": "#absolute-1", "top": 0, "left": 0 },
|
|
{ "id": "#absolute-1-1", "top": 1, "left": 1 },
|
|
{ "id": "#absolute-1-1-1", "top": 1, "left": 1 },
|
|
{ "id": "#absolute-2", "top": 19, "left": 19 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" );
|
|
assert.equal( $( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
|
|
} );
|
|
|
|
// test trac-5781
|
|
offset = $( "#positionTest" ).offset( { "top": 10, "left": 10 } ).offset();
|
|
assert.equal( offset.top, 10, "Setting offset on element with position absolute but 'auto' values." );
|
|
assert.equal( offset.left, 10, "Setting offset on element with position absolute but 'auto' values." );
|
|
|
|
// set offset
|
|
tests = [
|
|
{ "id": "#absolute-2", "top": 30, "left": 30 },
|
|
{ "id": "#absolute-2", "top": 10, "left": 10 },
|
|
{ "id": "#absolute-2", "top": -1, "left": -1 },
|
|
{ "id": "#absolute-2", "top": 19, "left": 19 },
|
|
{ "id": "#absolute-1-1-1", "top": 15, "left": 15 },
|
|
{ "id": "#absolute-1-1-1", "top": 5, "left": 5 },
|
|
{ "id": "#absolute-1-1-1", "top": -1, "left": -1 },
|
|
{ "id": "#absolute-1-1-1", "top": 9, "left": 9 },
|
|
{ "id": "#absolute-1-1", "top": 10, "left": 10 },
|
|
{ "id": "#absolute-1-1", "top": 0, "left": 0 },
|
|
{ "id": "#absolute-1-1", "top": -1, "left": -1 },
|
|
{ "id": "#absolute-1-1", "top": 5, "left": 5 },
|
|
{ "id": "#absolute-1", "top": 2, "left": 2 },
|
|
{ "id": "#absolute-1", "top": 0, "left": 0 },
|
|
{ "id": "#absolute-1", "top": -1, "left": -1 },
|
|
{ "id": "#absolute-1", "top": 1, "left": 1 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
$( this.id ).offset( { "top": this.top, "left": this.left } );
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
|
|
|
|
var top = this.top, left = this.left;
|
|
|
|
$( this.id ).offset( function( i, val ) {
|
|
assert.equal( val.top, top, "Verify incoming top position." );
|
|
assert.equal( val.left, left, "Verify incoming top position." );
|
|
return { "top": top + 1, "left": left + 1 };
|
|
} );
|
|
assert.equal( $( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + ( this.top + 1 ) + " })" );
|
|
assert.equal( $( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + ( this.left + 1 ) + " })" );
|
|
|
|
$( this.id )
|
|
.offset( { "left": this.left + 2 } )
|
|
.offset( { "top": this.top + 2 } );
|
|
assert.equal( $( this.id ).offset().top, this.top + 2, "Setting one property at a time." );
|
|
assert.equal( $( this.id ).offset().left, this.left + 2, "Setting one property at a time." );
|
|
|
|
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
|
|
$( this ).css( {
|
|
"top": props.top + 1,
|
|
"left": props.left + 1
|
|
} );
|
|
} } );
|
|
assert.equal( $( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + ( this.top + 1 ) + ", using: fn })" );
|
|
assert.equal( $( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + ( this.left + 1 ) + ", using: fn })" );
|
|
} );
|
|
} );
|
|
|
|
testIframe( "relative", "offset/relative.html", function( assert, $ ) {
|
|
assert.expect( 64 );
|
|
|
|
// get offset
|
|
var tests = [
|
|
{ "id": "#relative-1", "top": 7, "left": 7 },
|
|
{ "id": "#relative-1-1", "top": 15, "left": 15 },
|
|
{ "id": "#relative-2", "top": 142, "left": 27 },
|
|
{ "id": "#relative-2-1", "top": 149, "left": 52 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
|
|
} );
|
|
|
|
// get position
|
|
tests = [
|
|
{ "id": "#relative-1", "top": 6, "left": 6 },
|
|
{ "id": "#relative-1-1", "top": 5, "left": 5 },
|
|
{ "id": "#relative-2", "top": 141, "left": 26 },
|
|
{ "id": "#relative-2-1", "top": 5, "left": 5 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" );
|
|
assert.equal( $( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
|
|
} );
|
|
|
|
// set offset
|
|
tests = [
|
|
{ "id": "#relative-2", "top": 200, "left": 50 },
|
|
{ "id": "#relative-2", "top": 100, "left": 10 },
|
|
{ "id": "#relative-2", "top": -5, "left": -5 },
|
|
{ "id": "#relative-2", "top": 142, "left": 27 },
|
|
{ "id": "#relative-1-1", "top": 100, "left": 100 },
|
|
{ "id": "#relative-1-1", "top": 5, "left": 5 },
|
|
{ "id": "#relative-1-1", "top": -1, "left": -1 },
|
|
{ "id": "#relative-1-1", "top": 15, "left": 15 },
|
|
{ "id": "#relative-1", "top": 100, "left": 100 },
|
|
{ "id": "#relative-1", "top": 0, "left": 0 },
|
|
{ "id": "#relative-1", "top": -1, "left": -1 },
|
|
{ "id": "#relative-1", "top": 7, "left": 7 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
$( this.id ).offset( { "top": this.top, "left": this.left } );
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
|
|
|
|
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
|
|
$( this ).css( {
|
|
"top": props.top + 1,
|
|
"left": props.left + 1
|
|
} );
|
|
} } );
|
|
assert.equal( $( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + ( this.top + 1 ) + ", using: fn })" );
|
|
assert.equal( $( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + ( this.left + 1 ) + ", using: fn })" );
|
|
} );
|
|
} );
|
|
|
|
testIframe( "static", "offset/static.html", function( assert, $ ) {
|
|
assert.expect( 80 );
|
|
|
|
// get offset
|
|
var tests = [
|
|
{ "id": "#static-1", "top": 7, "left": 7 },
|
|
{ "id": "#static-1-1", "top": 15, "left": 15 },
|
|
{ "id": "#static-1-1-1", "top": 23, "left": 23 },
|
|
{ "id": "#static-2", "top": 122, left: 7 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
|
|
} );
|
|
|
|
// get position
|
|
tests = [
|
|
{ "id": "#static-1", "top": 6, "left": 6 },
|
|
{ "id": "#static-1-1", "top": 14, "left": 14 },
|
|
{ "id": "#static-1-1-1", "top": 22, "left": 22 },
|
|
{ "id": "#static-2", "top": 121, "left": 6 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
assert.equal( $( this.id ).position().top, this.top, "jQuery('" + this.top + "').position().top" );
|
|
assert.equal( $( this.id ).position().left, this.left, "jQuery('" + this.left + "').position().left" );
|
|
} );
|
|
|
|
// set offset
|
|
tests = [
|
|
{ "id": "#static-2", "top": 200, "left": 200 },
|
|
{ "id": "#static-2", "top": 100, "left": 100 },
|
|
{ "id": "#static-2", "top": -2, "left": -2 },
|
|
{ "id": "#static-2", "top": 121, "left": 6 },
|
|
{ "id": "#static-1-1-1", "top": 50, "left": 50 },
|
|
{ "id": "#static-1-1-1", "top": 10, "left": 10 },
|
|
{ "id": "#static-1-1-1", "top": -1, "left": -1 },
|
|
{ "id": "#static-1-1-1", "top": 22, "left": 22 },
|
|
{ "id": "#static-1-1", "top": 25, "left": 25 },
|
|
{ "id": "#static-1-1", "top": 10, "left": 10 },
|
|
{ "id": "#static-1-1", "top": -3, "left": -3 },
|
|
{ "id": "#static-1-1", "top": 14, "left": 14 },
|
|
{ "id": "#static-1", "top": 30, "left": 30 },
|
|
{ "id": "#static-1", "top": 2, "left": 2 },
|
|
{ "id": "#static-1", "top": -2, "left": -2 },
|
|
{ "id": "#static-1", "top": 7, "left": 7 }
|
|
];
|
|
jQuery.each( tests, function() {
|
|
$( this.id ).offset( { "top": this.top, "left": this.left } );
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
|
|
|
|
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
|
|
$( this ).css( {
|
|
"top": props.top + 1,
|
|
"left": props.left + 1
|
|
} );
|
|
} } );
|
|
assert.equal( $( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + ( this.top + 1 ) + ", using: fn })" );
|
|
assert.equal( $( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + ( this.left + 1 ) + ", using: fn })" );
|
|
} );
|
|
} );
|
|
|
|
testIframe( "fixed", "offset/fixed.html", function( assert, $ ) {
|
|
assert.expect( 38 );
|
|
|
|
var tests, $noTopLeft;
|
|
|
|
tests = [
|
|
{
|
|
"id": "#fixed-1",
|
|
"offsetTop": 1001,
|
|
"offsetLeft": 1001,
|
|
"positionTop": 0,
|
|
"positionLeft": 0
|
|
},
|
|
{
|
|
"id": "#fixed-2",
|
|
"offsetTop": 1021,
|
|
"offsetLeft": 1021,
|
|
"positionTop": 20,
|
|
"positionLeft": 20
|
|
}
|
|
];
|
|
|
|
jQuery.each( tests, function() {
|
|
if ( !supportsScroll ) {
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
|
|
} else if ( supportsFixedPosition ) {
|
|
assert.equal( jQuery.isPlainObject( $( this.id ).offset() ), true, "jQuery('" + this.id + "').offset() is plain object" );
|
|
assert.equal( jQuery.isPlainObject( $( this.id ).position() ), true, "jQuery('" + this.id + "').position() is plain object" );
|
|
assert.equal( $( this.id ).offset().top, this.offsetTop, "jQuery('" + this.id + "').offset().top" );
|
|
assert.equal( $( this.id ).position().top, this.positionTop, "jQuery('" + this.id + "').position().top" );
|
|
assert.equal( $( this.id ).offset().left, this.offsetLeft, "jQuery('" + this.id + "').offset().left" );
|
|
assert.equal( $( this.id ).position().left, this.positionLeft, "jQuery('" + this.id + "').position().left" );
|
|
} else {
|
|
|
|
// need to have same number of assertions
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
}
|
|
} );
|
|
|
|
tests = [
|
|
{ "id": "#fixed-1", "top": 100, "left": 100 },
|
|
{ "id": "#fixed-1", "top": 0, "left": 0 },
|
|
{ "id": "#fixed-1", "top": -4, "left": -4 },
|
|
{ "id": "#fixed-2", "top": 200, "left": 200 },
|
|
{ "id": "#fixed-2", "top": 0, "left": 0 },
|
|
{ "id": "#fixed-2", "top": -5, "left": -5 }
|
|
];
|
|
|
|
jQuery.each( tests, function() {
|
|
if ( supportsFixedPosition ) {
|
|
$( this.id ).offset( { "top": this.top, "left": this.left } );
|
|
assert.equal( $( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
|
|
assert.equal( $( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
|
|
|
|
$( this.id ).offset( { "top": this.top, "left": this.left, "using": function( props ) {
|
|
$( this ).css( {
|
|
"top": props.top + 1,
|
|
"left": props.left + 1
|
|
} );
|
|
} } );
|
|
assert.equal( $( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + ( this.top + 1 ) + ", using: fn })" );
|
|
assert.equal( $( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + ( this.left + 1 ) + ", using: fn })" );
|
|
} else {
|
|
|
|
// need to have same number of assertions
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
}
|
|
} );
|
|
|
|
// Bug 8316
|
|
$noTopLeft = $( "#fixed-no-top-left" );
|
|
if ( supportsFixedPosition ) {
|
|
assert.equal( $noTopLeft.offset().top, 1007, "Check offset top for fixed element with no top set" );
|
|
assert.equal( $noTopLeft.offset().left, 1007, "Check offset left for fixed element with no left set" );
|
|
} else {
|
|
|
|
// need to have same number of assertions
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
assert.ok( true, "Fixed position is not supported" );
|
|
}
|
|
} );
|
|
|
|
testIframe( "table", "offset/table.html", function( assert, $ ) {
|
|
assert.expect( 4 );
|
|
|
|
assert.equal( $( "#table-1" ).offset().top, 6, "jQuery('#table-1').offset().top" );
|
|
assert.equal( $( "#table-1" ).offset().left, 6, "jQuery('#table-1').offset().left" );
|
|
|
|
assert.equal( $( "#th-1" ).offset().top, 10, "jQuery('#th-1').offset().top" );
|
|
assert.equal( $( "#th-1" ).offset().left, 10, "jQuery('#th-1').offset().left" );
|
|
} );
|
|
|
|
testIframe( "scroll", "offset/scroll.html", function( assert, $, win ) {
|
|
assert.expect( 26 );
|
|
|
|
assert.equal( $( "#scroll-1" ).offset().top, 7, "jQuery('#scroll-1').offset().top" );
|
|
assert.equal( $( "#scroll-1" ).offset().left, 7, "jQuery('#scroll-1').offset().left" );
|
|
|
|
assert.equal( $( "#scroll-1-1" ).offset().top, 11, "jQuery('#scroll-1-1').offset().top" );
|
|
assert.equal( $( "#scroll-1-1" ).offset().left, 11, "jQuery('#scroll-1-1').offset().left" );
|
|
|
|
// These tests are solely for main/compat consistency
|
|
// Retrieving offset on disconnected/hidden elements is not officially
|
|
// valid input, but will return zeros for back-compat
|
|
assert.equal( $( "#hidden" ).offset().top, 0, "Hidden elements do not subtract scroll" );
|
|
assert.equal( $( "#hidden" ).offset().left, 0, "Hidden elements do not subtract scroll" );
|
|
|
|
// scroll offset tests .scrollTop/Left
|
|
assert.equal( $( "#scroll-1" ).scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" );
|
|
assert.equal( $( "#scroll-1" ).scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" );
|
|
|
|
assert.equal( $( "#scroll-1-1" ).scrollTop(), 0, "jQuery('#scroll-1-1').scrollTop()" );
|
|
assert.equal( $( "#scroll-1-1" ).scrollLeft(), 0, "jQuery('#scroll-1-1').scrollLeft()" );
|
|
|
|
// scroll method chaining
|
|
assert.equal( $( "#scroll-1" ).scrollTop( undefined ).scrollTop(), 5, ".scrollTop(undefined) is chainable (trac-5571)" );
|
|
assert.equal( $( "#scroll-1" ).scrollLeft( undefined ).scrollLeft(), 5, ".scrollLeft(undefined) is chainable (trac-5571)" );
|
|
|
|
win.name = "test";
|
|
|
|
if ( !supportsScroll ) {
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
assert.ok( true, "Browser doesn't support scroll position." );
|
|
} else {
|
|
assert.equal( $( win ).scrollTop(), 1000, "jQuery(window).scrollTop()" );
|
|
assert.equal( $( win ).scrollLeft(), 1000, "jQuery(window).scrollLeft()" );
|
|
|
|
assert.equal( $( win.document ).scrollTop(), 1000, "jQuery(document).scrollTop()" );
|
|
assert.equal( $( win.document ).scrollLeft(), 1000, "jQuery(document).scrollLeft()" );
|
|
}
|
|
|
|
// test jQuery using parent window/document
|
|
// jQuery reference here is in the iframe
|
|
window.scrollTo( 0, 0 );
|
|
assert.equal( $( window ).scrollTop(), 0, "jQuery(window).scrollTop() other window" );
|
|
assert.equal( $( window ).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" );
|
|
assert.equal( $( document ).scrollTop(), 0, "jQuery(window).scrollTop() other document" );
|
|
assert.equal( $( document ).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" );
|
|
|
|
// Tests scrollTop/Left with empty jquery objects
|
|
assert.notEqual( $().scrollTop( 100 ), null, "jQuery().scrollTop(100) testing setter on empty jquery object" );
|
|
assert.notEqual( $().scrollLeft( 100 ), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" );
|
|
assert.notEqual( $().scrollTop( null ), null, "jQuery().scrollTop(null) testing setter on empty jquery object" );
|
|
assert.notEqual( $().scrollLeft( null ), null, "jQuery().scrollLeft(null) testing setter on empty jquery object" );
|
|
assert.strictEqual( $().scrollTop(), undefined, "jQuery().scrollTop() testing getter on empty jquery object" );
|
|
assert.strictEqual( $().scrollLeft(), undefined, "jQuery().scrollLeft() testing getter on empty jquery object" );
|
|
} );
|
|
|
|
testIframe( "body", "offset/body.html", function( assert, $ ) {
|
|
assert.expect( 4 );
|
|
|
|
assert.equal( $( "body" ).offset().top, 1, "jQuery('#body').offset().top" );
|
|
assert.equal( $( "body" ).offset().left, 1, "jQuery('#body').offset().left" );
|
|
assert.equal( $( "#firstElement" ).position().left, 5, "$('#firstElement').position().left" );
|
|
assert.equal( $( "#firstElement" ).position().top, 5, "$('#firstElement').position().top" );
|
|
} );
|
|
|
|
QUnit.test( "chaining", function( assert ) {
|
|
assert.expect( 3 );
|
|
|
|
var coords = { "top": 1, "left": 1 };
|
|
assert.equal( jQuery( "#absolute-1" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) returns jQuery object" );
|
|
assert.equal( jQuery( "#non-existent" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) with empty jQuery set returns jQuery object" );
|
|
assert.equal( jQuery( "#absolute-1" ).offset( undefined ).jquery, jQuery.fn.jquery, "offset(undefined) returns jQuery object (trac-5571)" );
|
|
} );
|
|
|
|
// Test complex content under a variety of <html>/<body> positioning styles
|
|
( function() {
|
|
var POSITION_VALUES = [ "static", "relative", "absolute", "fixed" ],
|
|
|
|
// Use shorthands for describing an element's relevant properties
|
|
BOX_PROPS =
|
|
( "top left marginTop marginLeft borderTop borderLeft paddingTop paddingLeft" +
|
|
" style parent" ).split( /\s+/g ),
|
|
props = function() {
|
|
var propObj = {};
|
|
supportjQuery.each( arguments, function( i, value ) {
|
|
propObj[ BOX_PROPS[ i ] ] = value;
|
|
} );
|
|
return propObj;
|
|
},
|
|
|
|
// Values must stay synchronized with test/data/offset/boxes.html
|
|
divProps = function( position, parentId ) {
|
|
return props( 8, 4, 16, 8, 4, 2, 32, 16, position, parentId );
|
|
},
|
|
htmlProps = function( position ) {
|
|
return props( position === "static" ? 0 : 4096, position === "static" ? 0 : 2048,
|
|
64, 32, 128, 64, 256, 128, position );
|
|
},
|
|
bodyProps = function( position ) {
|
|
return props( position === "static" ? 0 : 8192, position === "static" ? 0 : 4096,
|
|
512, 256, 1024, 512, 2048, 1024, position,
|
|
position !== "fixed" && "documentElement" );
|
|
};
|
|
|
|
function getExpectations( htmlPos, bodyPos, scrollTop, scrollLeft ) {
|
|
|
|
// Initialize data about page elements
|
|
var expectations = {
|
|
"documentElement": htmlProps( htmlPos ),
|
|
"body": bodyProps( bodyPos ),
|
|
"relative": divProps( "relative", "body" ),
|
|
"relative-relative": divProps( "relative", "relative" ),
|
|
"relative-absolute": divProps( "absolute", "relative" ),
|
|
"absolute": divProps( "absolute", "body" ),
|
|
"absolute-relative": divProps( "relative", "absolute" ),
|
|
"absolute-absolute": divProps( "absolute", "absolute" ),
|
|
"fixed": divProps( "fixed" ),
|
|
"fixed-relative": divProps( "relative", "fixed" ),
|
|
"fixed-absolute": divProps( "absolute", "fixed" )
|
|
};
|
|
|
|
// Define position and offset expectations for page elements
|
|
supportjQuery.each( expectations, function( id, props ) {
|
|
var parent = expectations[ props.parent ],
|
|
|
|
// position() relates an element's margin box to its offset parent's padding box
|
|
pos = props.pos = {
|
|
top: props.top,
|
|
left: props.left
|
|
},
|
|
|
|
// offset() relates an element's border box to the document origin
|
|
offset = props.offset = {
|
|
top: pos.top + props.marginTop,
|
|
left: pos.left + props.marginLeft
|
|
};
|
|
|
|
// Account for ancestors differently by element position
|
|
// fixed: ignore them
|
|
// absolute: offset includes offsetParent offset+border
|
|
// relative: position includes parent padding (and also position+margin+border when
|
|
// parent is not offsetParent); offset includes parent offset+border+padding
|
|
// static: same as relative
|
|
for ( ; parent; parent = expectations[ parent.parent ] ) {
|
|
|
|
// position:fixed
|
|
if ( props.style === "fixed" ) {
|
|
break;
|
|
}
|
|
|
|
// position:absolute bypass
|
|
if ( props.style === "absolute" && parent.style === "static" ) {
|
|
continue;
|
|
}
|
|
|
|
// Offset update
|
|
offset.top += parent.offset.top + parent.borderTop;
|
|
offset.left += parent.offset.left + parent.borderLeft;
|
|
if ( props.style !== "absolute" ) {
|
|
offset.top += parent.paddingTop;
|
|
offset.left += parent.paddingLeft;
|
|
|
|
// position:relative or position:static position update
|
|
pos.top += parent.paddingTop;
|
|
pos.left += parent.paddingLeft;
|
|
if ( parent.style === "static" ) {
|
|
pos.top += parent.pos.top + parent.marginTop + parent.borderTop;
|
|
pos.left += parent.pos.left + parent.marginLeft + parent.borderLeft;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Viewport scroll affects position:fixed elements, except when the page is
|
|
// unscrollable.
|
|
if ( props.style === "fixed" &&
|
|
( alwaysScrollable || expectations.documentElement.style !== "fixed" ) ) {
|
|
|
|
offset.top += scrollTop;
|
|
offset.left += scrollLeft;
|
|
}
|
|
} );
|
|
|
|
// Support: IE<=10 only
|
|
// Fudge the tests to work around <html>.gBCR() erroneously including margins
|
|
if ( /MSIE (?:9|10)\./.test( navigator.userAgent ) ) {
|
|
expectations.documentElement.pos.top -= expectations.documentElement.marginTop -
|
|
scrollTop;
|
|
expectations.documentElement.offset.top -= expectations.documentElement.marginTop -
|
|
scrollTop;
|
|
expectations.documentElement.pos.left -= expectations.documentElement.marginLeft -
|
|
scrollLeft;
|
|
expectations.documentElement.offset.left -= expectations.documentElement.marginLeft -
|
|
scrollLeft;
|
|
if ( htmlPos !== "static" ) {
|
|
delete expectations.documentElement;
|
|
delete expectations.body;
|
|
delete expectations.relative;
|
|
delete expectations.absolute;
|
|
}
|
|
}
|
|
|
|
return expectations;
|
|
}
|
|
|
|
// Cover each combination of <html> position and <body> position
|
|
supportjQuery.each( POSITION_VALUES, function( _, htmlPos ) {
|
|
supportjQuery.each( POSITION_VALUES, function( _, bodyPos ) {
|
|
var label = "nonzero box properties - html." + htmlPos + " body." + bodyPos;
|
|
testIframe( label, "offset/boxes.html", function( assert, $, win, doc ) {
|
|
|
|
// Define expectations at runtime to properly account for scrolling
|
|
var scrollTop = win.pageYOffset,
|
|
scrollLeft = win.pageXOffset,
|
|
expectations = getExpectations( htmlPos, bodyPos, scrollTop, scrollLeft );
|
|
|
|
assert.expect( 3 * Object.keys( expectations ).length );
|
|
|
|
// Setup documentElement and body styles, preserving scroll position
|
|
doc.documentElement.style.position = htmlPos;
|
|
doc.body.style.position = bodyPos;
|
|
win.scrollTo( scrollLeft, scrollTop );
|
|
|
|
// Verify expected document offset
|
|
supportjQuery.each( expectations, function( id, descriptor ) {
|
|
assert.deepEqual(
|
|
supportjQuery.extend( {}, $( "#" + id ).offset() ),
|
|
descriptor.offset,
|
|
"jQuery('#" + id + "').offset(): top " + descriptor.offset.top +
|
|
", left " + descriptor.offset.left );
|
|
} );
|
|
|
|
// Verify expected relative position
|
|
supportjQuery.each( expectations, function( id, descriptor ) {
|
|
assert.deepEqual(
|
|
supportjQuery.extend( {}, $( "#" + id ).position() ),
|
|
descriptor.pos,
|
|
"jQuery('#" + id + "').position(): top " + descriptor.pos.top +
|
|
", left " + descriptor.pos.left );
|
|
} );
|
|
|
|
// Verify that values round-trip
|
|
supportjQuery.each( Object.keys( expectations ).reverse(), function( _, id ) {
|
|
var $el = $( "#" + id ),
|
|
pos = supportjQuery.extend( {}, $el.position() );
|
|
|
|
$el.css( { top: pos.top, left: pos.left } );
|
|
if ( $el.css( "position" ) === "relative" ) {
|
|
|
|
// $relative.position() includes parent padding; switch to absolute
|
|
// positioning so we don't double its effects.
|
|
$el.css( { position: "absolute" } );
|
|
}
|
|
assert.deepEqual( supportjQuery.extend( {}, $el.position() ), pos,
|
|
"jQuery('#" + id + "').position() round-trips" );
|
|
|
|
// TODO Verify .offset(...)
|
|
// assert.deepEqual( $el.offset( offset ).offset(), offset )
|
|
// assert.deepEqual( $el.offset( adjustedOffset ).offset(), adjustedOffset )
|
|
// assert.deepEqual( $new.offset( offset ).offset(), offset )
|
|
} );
|
|
} );
|
|
} );
|
|
} );
|
|
} )();
|
|
|
|
QUnit.test( "offsetParent", function( assert ) {
|
|
assert.expect( 13 );
|
|
|
|
var body, header, div, area;
|
|
|
|
body = jQuery( "body" ).offsetParent();
|
|
assert.equal( body.length, 1, "Only one offsetParent found." );
|
|
assert.equal( body[ 0 ], document.documentElement, "The html element is the offsetParent of the body." );
|
|
|
|
header = jQuery( "#qunit" ).offsetParent();
|
|
assert.equal( header.length, 1, "Only one offsetParent found." );
|
|
assert.equal( header[ 0 ], document.documentElement, "The html element is the offsetParent of #qunit." );
|
|
|
|
jQuery( "#qunit-fixture" ).css( "position", "absolute" );
|
|
div = jQuery( "#nothiddendivchild" ).offsetParent();
|
|
assert.equal( div.length, 1, "Only one offsetParent found." );
|
|
assert.equal( div[ 0 ], document.getElementById( "qunit-fixture" ), "The #qunit-fixture is the offsetParent of #nothiddendivchild." );
|
|
jQuery( "#qunit-fixture" ).css( "position", "" );
|
|
|
|
jQuery( "#nothiddendiv" ).css( "position", "relative" );
|
|
|
|
div = jQuery( "#nothiddendivchild" ).offsetParent();
|
|
assert.equal( div.length, 1, "Only one offsetParent found." );
|
|
assert.equal( div[ 0 ], jQuery( "#nothiddendiv" )[ 0 ], "The div is the offsetParent." );
|
|
|
|
div = jQuery( "body, #nothiddendivchild" ).offsetParent();
|
|
assert.equal( div.length, 2, "Two offsetParent found." );
|
|
assert.equal( div[ 0 ], document.documentElement, "The html element is the offsetParent of the body." );
|
|
assert.equal( div[ 1 ], jQuery( "#nothiddendiv" )[ 0 ], "The div is the offsetParent." );
|
|
|
|
area = jQuery( "<map name=\"imgmap\"><area shape=\"rect\" coords=\"0,0,200,50\"></map>" ).appendTo( "body" ).find( "area" );
|
|
assert.equal( area.offsetParent()[ 0 ], document.documentElement, "The html element is the offsetParent of a map area." );
|
|
area.remove();
|
|
|
|
div = jQuery( "<div>" ).css( { "position": "absolute" } ).appendTo( "body" );
|
|
assert.equal( div.offsetParent()[ 0 ], document.documentElement, "Absolutely positioned div returns html as offset parent, see trac-12139" );
|
|
div.remove();
|
|
} );
|
|
|
|
QUnit.test( "fractions (see trac-7730 and trac-7885)", function( assert ) {
|
|
assert.expect( 2 );
|
|
|
|
jQuery( "body" ).append( "<div id='fractions'></div>" );
|
|
|
|
var result,
|
|
expected = { "top": 1000, "left": 1000 },
|
|
div = jQuery( "#fractions" );
|
|
|
|
div.css( {
|
|
"position": "absolute",
|
|
"left": "1000.7432222px",
|
|
"top": "1000.532325px",
|
|
"width": 100,
|
|
"height": 100
|
|
} );
|
|
|
|
div.offset( expected );
|
|
|
|
result = div.offset();
|
|
|
|
// Support: Chrome <=45 - 46
|
|
// In recent Chrome these values differ a little.
|
|
assert.ok( Math.abs( result.top - expected.top ) < 0.25, "Check top within 0.25 of expected" );
|
|
assert.ok( Math.abs( result.left - expected.left ) < 0.25, "Check left within 0.25 of expected" );
|
|
|
|
div.remove();
|
|
} );
|
|
|
|
QUnit.test( "iframe scrollTop/Left (see gh-1945)", function( assert ) {
|
|
assert.expect( 2 );
|
|
|
|
var ifDoc = jQuery( "#iframe" )[ 0 ].contentDocument;
|
|
|
|
// Mobile Safari resize the iframe by its content meaning it's not possible to scroll
|
|
// the iframe but only its parent element.
|
|
// It seems (not confirmed) in android 4.0 it's not possible to scroll iframes from the code.
|
|
if (
|
|
/iphone os|ipad/i.test( navigator.userAgent ) ||
|
|
/android 4\.0/i.test( navigator.userAgent )
|
|
) {
|
|
assert.equal( true, true, "Can't scroll iframes in this environment" );
|
|
assert.equal( true, true, "Can't scroll iframes in this environment" );
|
|
|
|
} else {
|
|
|
|
// Tests scrollTop/Left with iframes
|
|
jQuery( "#iframe" ).css( "width", "50px" ).css( "height", "50px" );
|
|
ifDoc.write( "<div style='width: 1000px; height: 1000px;'></div>" );
|
|
|
|
jQuery( ifDoc ).scrollTop( 200 );
|
|
jQuery( ifDoc ).scrollLeft( 500 );
|
|
|
|
assert.equal( jQuery( ifDoc ).scrollTop(), 200, "$($('#iframe')[0].contentDocument).scrollTop()" );
|
|
assert.equal( jQuery( ifDoc ).scrollLeft(), 500, "$($('#iframe')[0].contentDocument).scrollLeft()" );
|
|
}
|
|
} );
|
|
|
|
} )();
|