offset is now a setter

This commit is contained in:
Brandon Aaron 2009-09-15 19:15:04 +00:00
parent f55fb36e54
commit daffb954e3
4 changed files with 248 additions and 83 deletions

View file

@ -1,7 +1,12 @@
if ( "getBoundingClientRect" in document.documentElement ) { if ( "getBoundingClientRect" in document.documentElement ) {
jQuery.fn.offset = function() { jQuery.fn.offset = function( options ) {
var elem = this[0]; var elem = this[0];
if ( !elem || !elem.ownerDocument ) { return null; } if ( !elem || !elem.ownerDocument ) { return null; }
if ( options ) {
return this.each(function() {
jQuery.offset.setOffset( this, options );
});
}
if ( elem === elem.ownerDocument.body ) { if ( elem === elem.ownerDocument.body ) {
return jQuery.offset.bodyOffset( elem ); return jQuery.offset.bodyOffset( elem );
} }
@ -13,9 +18,14 @@ if ( "getBoundingClientRect" in document.documentElement ) {
return { top: top, left: left }; return { top: top, left: left };
}; };
} else { } else {
jQuery.fn.offset = function() { jQuery.fn.offset = function( options ) {
var elem = this[0]; var elem = this[0];
if ( !elem || !elem.ownerDocument ) { return null; } if ( !elem || !elem.ownerDocument ) { return null; }
if ( options ) {
return this.each(function() {
jQuery.offset.setOffset( this, options );
});
}
if ( elem === elem.ownerDocument.body ) { if ( elem === elem.ownerDocument.body ) {
return jQuery.offset.bodyOffset( elem ); return jQuery.offset.bodyOffset( elem );
} }
@ -25,18 +35,18 @@ if ( "getBoundingClientRect" in document.documentElement ) {
var offsetParent = elem.offsetParent, prevOffsetParent = elem, var offsetParent = elem.offsetParent, prevOffsetParent = elem,
doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement, doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
body = doc.body, defaultView = doc.defaultView, body = doc.body, defaultView = doc.defaultView,
prevComputedStyle = defaultView.getComputedStyle(elem, null), prevComputedStyle = defaultView.getComputedStyle( elem, null ),
top = elem.offsetTop, left = elem.offsetLeft; top = elem.offsetTop, left = elem.offsetLeft;
while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) { while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { break; } if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) { break; }
computedStyle = defaultView.getComputedStyle(elem, null); computedStyle = defaultView.getComputedStyle(elem, null);
top -= elem.scrollTop; top -= elem.scrollTop;
left -= elem.scrollLeft; left -= elem.scrollLeft;
if ( elem === offsetParent ) { if ( elem === offsetParent ) {
top += elem.offsetTop; top += elem.offsetTop;
left += elem.offsetLeft; left += elem.offsetLeft;
if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) { if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.nodeName)) ) {
@ -100,7 +110,7 @@ jQuery.offset = {
jQuery.offset.initialize = function(){}; jQuery.offset.initialize = function(){};
}, },
bodyOffset: function(body) { bodyOffset: function( body ) {
var top = body.offsetTop, left = body.offsetLeft; var top = body.offsetTop, left = body.offsetLeft;
jQuery.offset.initialize(); jQuery.offset.initialize();
@ -111,6 +121,27 @@ jQuery.offset = {
} }
return { top: top, left: left }; return { top: top, left: left };
},
setOffset: function( elem, options ) {
// set position first, in-case top/left are set even on static elem
if ( /static/.test( jQuery.curCSS( elem, 'position' ) ) ) {
elem.style.position = 'relative';
}
var curElem = jQuery( elem ),
curOffset = curElem.offset(),
curTop = parseInt( jQuery.curCSS( elem, 'top', true ), 10 ) || 0,
curLeft = parseInt( jQuery.curCSS( elem, 'left', true ), 10) || 0,
props = {
top: (options.top - curOffset.top) + curTop,
left: (options.left - curOffset.left) + curLeft
};
if ( 'using' in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
} }
}; };

View file

@ -6,7 +6,7 @@
<title>relative</title> <title>relative</title>
<style type="text/css" media="screen"> <style type="text/css" media="screen">
body { margin: 1px; padding: 5px; } body { margin: 1px; padding: 5px; }
div.relative { position: relative; margin: 1px; border: 2px solid #000; padding: 5px; width: 100px; height: 100px; background: #fff; overflow: hidden; } div.relative { position: relative; top: 0; left: 0; margin: 1px; border: 2px solid #000; padding: 5px; width: 100px; height: 100px; background: #fff; overflow: hidden; }
#relative-2 { top: 20px; left: 20px; } #relative-2 { top: 20px; left: 20px; }
#marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; }
</style> </style>

View file

@ -6,7 +6,7 @@
<title>static</title> <title>static</title>
<style type="text/css" media="screen"> <style type="text/css" media="screen">
body { margin: 1px; padding: 5px; } body { margin: 1px; padding: 5px; }
div.static { position: static; margin: 1px; border: 2px solid #000; padding: 5px; width: 100px; height: 100px; background: #fff; overflow: hidden; } div.static { position: static; top: 0; left: 0; margin: 1px; border: 2px solid #000; padding: 5px; width: 100px; height: 100px; background: #fff; overflow: hidden; }
#static-2 { top: 20px; left: 20px; } #static-2 { top: 20px; left: 20px; }
#marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; }
</style> </style>

View file

@ -1,107 +1,241 @@
module("offset"); module("offset");
testoffset("absolute", function( jQuery ) { testoffset("absolute", function( jQuery ) {
equals( jQuery('#absolute-1').offset().top, 1, "jQuery('#absolute-1').offset().top" ); // get offset tests
equals( jQuery('#absolute-1').offset().left, 1, "jQuery('#absolute-1').offset().left" ); var tests = [
{ id: '#absolute-1', top: 1, left: 1 },
equals( jQuery('#absolute-1-1').offset().top, 5, "jQuery('#absolute-1-1').offset().top" ); { id: '#absolute-1-1', top: 5, left: 5 },
equals( jQuery('#absolute-1-1').offset().left, 5, "jQuery('#absolute-1-1').offset().left" ); { id: '#absolute-1-1-1', top: 9, left: 9 },
{ id: '#absolute-2', top: 20, left: 20 }
equals( jQuery('#absolute-1-1-1').offset().top, 9, "jQuery('#absolute-1-1-1').offset().top" ); ];
equals( jQuery('#absolute-1-1-1').offset().left, 9, "jQuery('#absolute-1-1-1').offset().left" ); jQuery.each( tests, function() {
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
equals( jQuery('#absolute-2').offset().top, 20, "jQuery('#absolute-2').offset().top" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
equals( jQuery('#absolute-2').offset().left, 20, "jQuery('#absolute-2').offset().left" ); });
equals( jQuery('#absolute-1').position().top, 0, "jQuery('#absolute-1').position().top" ); // get position
equals( jQuery('#absolute-1').position().left, 0, "jQuery('#absolute-1').position().left" ); 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() {
equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" );
equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
});
equals( jQuery('#absolute-1-1').position().top, 1, "jQuery('#absolute-1-1').position().top" );
equals( jQuery('#absolute-1-1').position().left, 1, "jQuery('#absolute-1-1').position().left" );
equals( jQuery('#absolute-1-1-1').position().top, 1, "jQuery('#absolute-1-1-1').position().top" ); // set offset
equals( jQuery('#absolute-1-1-1').position().left, 1, "jQuery('#absolute-1-1-1').position().left" ); tests = [
{ id: '#absolute-2', top: 30, left: 30 },
equals( jQuery('#absolute-2').position().top, 19, "jQuery('#absolute-2').position().top" ); { id: '#absolute-2', top: 10, left: 10 },
equals( jQuery('#absolute-2').position().left, 19, "jQuery('#absolute-2').position().left" ); { 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() {
jQuery( this.id ).offset({ top: this.top, left: this.left });
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
jQuery( this ).css({
top: props.top + 1,
left: props.left + 1
});
}});
equals( jQuery( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + (this.top + 1) + ", using: fn })" );
equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
});
}); });
testoffset("relative", function( jQuery ) { testoffset("relative", function( jQuery ) {
// IE is collapsing the top margin of 1px
var ie = jQuery.browser.msie && parseInt( jQuery.browser.version ) < 8; var ie = jQuery.browser.msie && parseInt( jQuery.browser.version ) < 8;
// IE is collapsing the top margin of 1px // get offset
equals( jQuery('#relative-1').offset().top, ie ? 6 : 7, "jQuery('#relative-1').offset().top" ); var tests = [
equals( jQuery('#relative-1').offset().left, 7, "jQuery('#relative-1').offset().left" ); { id: '#relative-1', top: ie ? 6 : 7, left: 7 },
{ id: '#relative-1-1', top: ie ? 13 : 15, left: 15 },
// IE is collapsing the top margin of 1px { id: '#relative-2', top: ie ? 141 : 142, left: 27 }
equals( jQuery('#relative-1-1').offset().top, ie ? 13 : 15, "jQuery('#relative-1-1').offset().top" ); ];
equals( jQuery('#relative-1-1').offset().left, 15, "jQuery('#relative-1-1').offset().left" ); jQuery.each( tests, function() {
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
// IE is collapsing the top margin of 1px equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
equals( jQuery('#relative-2').offset().top, ie ? 141 : 142, "jQuery('#relative-2').offset().top" ); });
equals( jQuery('#relative-2').offset().left, 27, "jQuery('#relative-2').offset().left" );
// IE is collapsing the top margin of 1px // get position
equals( jQuery('#relative-1').position().top, ie ? 5 : 6, "jQuery('#relative-1').position().top" ); tests = [
equals( jQuery('#relative-1').position().left, 6, "jQuery('#relative-1').position().left" ); { id: '#relative-1', top: ie ? 5 : 6, left: 6 },
{ id: '#relative-1-1', top: ie ? 4 : 5, left: 5 },
{ id: '#relative-2', top: ie ? 140 : 141, left: 26 }
];
jQuery.each( tests, function() {
equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.id + "').position().top" );
equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.id + "').position().left" );
});
// IE is collapsing the top margin of 1px
equals( jQuery('#relative-1-1').position().top, ie ? 4 : 5, "jQuery('#relative-1-1').position().top" );
equals( jQuery('#relative-1-1').position().left, 5, "jQuery('#relative-1-1').position().left" );
// IE is collapsing the top margin of 1px // set offset
equals( jQuery('#relative-2').position().top, ie ? 140 : 141, "jQuery('#relative-2').position().top" ); tests = [
equals( jQuery('#relative-2').position().left, 26, "jQuery('#relative-2').position().left" ); { 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() {
jQuery( this.id ).offset({ top: this.top, left: this.left });
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
jQuery( this ).css({
top: props.top + 1,
left: props.left + 1
});
}});
equals( jQuery( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + (this.top + 1) + ", using: fn })" );
equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
});
}); });
testoffset("static", function( jQuery ) { testoffset("static", function( jQuery ) {
// IE is collapsing the top margin of 1px
var ie = jQuery.browser.msie && parseInt( jQuery.browser.version ) < 8; var ie = jQuery.browser.msie && parseInt( jQuery.browser.version ) < 8;
// IE is collapsing the top margin of 1px // get offset
equals( jQuery('#static-1').offset().top, ie ? 6 : 7, "jQuery('#static-1').offset().top" ); var tests = [
equals( jQuery('#static-1').offset().left, 7, "jQuery('#static-1').offset().left" ); { id: '#static-1', top: ie ? 6 : 7, left: 7 },
{ id: '#static-1-1', top: ie ? 13 : 15, left: 15 },
// IE is collapsing the top margin of 1px { id: '#static-1-1-1', top: ie ? 20 : 23, left: 23 },
equals( jQuery('#static-1-1').offset().top, ie ? 13 : 15, "jQuery('#static-1-1').offset().top" ); { id: '#static-2', top: ie ? 121 : 122, left: 7 }
equals( jQuery('#static-1-1').offset().left, 15, "jQuery('#static-1-1').offset().left" ); ];
jQuery.each( tests, function() {
// IE is collapsing the top margin of 1px equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
equals( jQuery('#static-1-1-1').offset().top, ie ? 20 : 23, "jQuery('#static-1-1-1').offset().top" ); equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
equals( jQuery('#static-1-1-1').offset().left, 23, "jQuery('#static-1-1-1').offset().left" ); });
// IE is collapsing the top margin of 1px
equals( jQuery('#static-2').offset().top, ie ? 121 : 122, "jQuery('#static-2').offset().top" );
equals( jQuery('#static-2').offset().left, 7, "jQuery('#static-2').offset().left" );
// IE is collapsing the top margin of 1px // get position
equals( jQuery('#static-1').position().top, ie ? 5 : 6, "jQuery('#static-1').position().top" ); tests = [
equals( jQuery('#static-1').position().left, 6, "jQuery('#static-1').position().left" ); { id: '#static-1', top: ie ? 5 : 6, left: 6 },
{ id: '#static-1-1', top: ie ? 12 : 14, left: 14 },
{ id: '#static-1-1-1', top: ie ? 19 : 22, left: 22 },
{ id: '#static-2', top: ie ? 120 : 121, left: 6 }
];
jQuery.each( tests, function() {
equals( jQuery( this.id ).position().top, this.top, "jQuery('" + this.top + "').position().top" );
equals( jQuery( this.id ).position().left, this.left, "jQuery('" + this.left +"').position().left" );
});
// IE is collapsing the top margin of 1px
equals( jQuery('#static-1-1').position().top, ie ? 12 : 14, "jQuery('#static-1-1').position().top" );
equals( jQuery('#static-1-1').position().left, 14, "jQuery('#static-1-1').position().left" );
// IE is collapsing the top margin of 1px // set offset
equals( jQuery('#static-1-1-1').position().top, ie ? 19 : 22, "jQuery('#static-1-1-1').position().top" ); tests = [
equals( jQuery('#static-1-1-1').position().left, 22, "jQuery('#static-1-1-1').position().left" ); { id: '#static-2', top: 200, left: 200 },
{ id: '#static-2', top: 100, left: 100 },
// IE is collapsing the top margin of 1px { id: '#static-2', top: -2, left: -2 },
equals( jQuery('#static-2').position().top, ie ? 120 : 121, "jQuery('#static-2').position().top" ); { id: '#static-2', top: 121, left: 6 },
equals( jQuery('#static-2').position().left, 6, "jQuery('#static-2').position().left" ); { 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() {
jQuery( this.id ).offset({ top: this.top, left: this.left });
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
jQuery( this ).css({
top: props.top + 1,
left: props.left + 1
});
}});
equals( jQuery( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + (this.top + 1) + ", using: fn })" );
equals( jQuery( this.id ).offset().left, this.left + 1, "jQuery('" + this.id + "').offset({ left: " + (this.left + 1) + ", using: fn })" );
});
}); });
if ( jQuery.offset.supportsFixedPosition ) { testoffset("fixed", function( jQuery ) {
testoffset("fixed", function( jQuery ) { jQuery.offset.initialize();
equals( jQuery('#fixed-1').offset().top, 1001, "jQuery('#fixed-1').offset().top" );
equals( jQuery('#fixed-1').offset().left, 1001, "jQuery('#fixed-1').offset().left" );
equals( jQuery('#fixed-2').offset().top, 1021, "jQuery('#fixed-2').offset().top" ); var tests = [
equals( jQuery('#fixed-2').offset().left, 1021, "jQuery('#fixed-2').offset().left" ); { id: '#fixed-1', top: 1001, left: 1001 },
{ id: '#fixed-2', top: 1021, left: 1021 }
];
jQuery.each( tests, function() {
if ( jQuery.offset.supportsFixedPosition ) {
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset().top" );
equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset().left" );
} else {
// need to have same number of assertions
ok( true, 'Fixed position is not supported' );
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 ( jQuery.offset.supportsFixedPosition ) {
jQuery( this.id ).offset({ top: this.top, left: this.left });
equals( jQuery( this.id ).offset().top, this.top, "jQuery('" + this.id + "').offset({ top: " + this.top + " })" );
equals( jQuery( this.id ).offset().left, this.left, "jQuery('" + this.id + "').offset({ left: " + this.left + " })" );
jQuery( this.id ).offset({ top: this.top, left: this.left, using: function( props ) {
jQuery( this ).css({
top: props.top + 1,
left: props.left + 1
});
}});
equals( jQuery( this.id ).offset().top, this.top + 1, "jQuery('" + this.id + "').offset({ top: " + (this.top + 1) + ", using: fn })" );
equals( jQuery( 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
ok( true, 'Fixed position is not supported' );
ok( true, 'Fixed position is not supported' );
ok( true, 'Fixed position is not supported' );
ok( true, 'Fixed position is not supported' );
}
});
});
testoffset("table", function( jQuery ) { testoffset("table", function( jQuery ) {
var ie = jQuery.browser.msie; var ie = jQuery.browser.msie;