define( [ "qunit", "jquery", "lib/common", "lib/helper", "ui/position" ], function( QUnit, $, common, helper ) { "use strict"; var win = $( window ), scrollTopSupport = function() { var support = win.scrollTop( 1 ).scrollTop() === 1; win.scrollTop( 0 ); scrollTopSupport = function() { return support; }; return support; }; QUnit.module( "position", { beforeEach: function() { win.scrollTop( 0 ).scrollLeft( 0 ); }, afterEach: helper.moduleAfterEach } ); QUnit.test( "my, at, of", function( assert ) { assert.expect( 4 ); $( "#elx" ).position( { my: "left top", at: "left top", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "left top, left top" ); $( "#elx" ).position( { my: "left top", at: "left bottom", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "left top, left bottom" ); $( "#elx" ).position( { my: "left", at: "bottom", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 55, left: 50 }, "left, bottom" ); $( "#elx" ).position( { my: "left foo", at: "bar baz", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 45, left: 50 }, "left foo, bar baz" ); } ); QUnit.test( "multiple elements", function( assert ) { assert.expect( 3 ); var elements = $( "#el1, #el2" ), result = elements.position( { my: "left top", at: "left bottom", of: "#parent", collision: "none" } ), expected = { top: 10, left: 4 }; assert.deepEqual( result, elements ); elements.each( function() { assert.deepEqual( $( this ).offset(), expected ); } ); } ); QUnit.test( "positions", function( assert ) { assert.expect( 18 ); var offsets = { left: 0, center: 3, right: 6, top: 0, bottom: 6 }, start = { left: 4, top: 4 }, el = $( "#el1" ); $.each( [ 0, 1 ], function( my ) { $.each( [ "top", "center", "bottom" ], function( vindex, vertical ) { $.each( [ "left", "center", "right" ], function( hindex, horizontal ) { var _my = my ? horizontal + " " + vertical : "left top", _at = !my ? horizontal + " " + vertical : "left top"; el.position( { my: _my, at: _at, of: "#parent", collision: "none" } ); assert.deepEqual( el.offset(), { top: start.top + offsets[ vertical ] * ( my ? -1 : 1 ), left: start.left + offsets[ horizontal ] * ( my ? -1 : 1 ) }, "Position via " + QUnit.dump.parse( { my: _my, at: _at } ) ); } ); } ); } ); } ); QUnit.test( "of", function( assert ) { assert.expect( 10 + ( scrollTopSupport() ? 1 : 0 ) ); var done = assert.async(); var event; $( "#elx" ).position( { my: "left top", at: "left top", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "selector" ); $( "#elx" ).position( { my: "left top", at: "left bottom", of: $( "#parentx" ), collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "jQuery object" ); $( "#elx" ).position( { my: "left top", at: "left top", of: $( "#parentx" )[ 0 ], collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 40, left: 40 }, "DOM element" ); $( "#elx" ).position( { my: "right bottom", at: "right bottom", of: document, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: $( document ).height() - 10, left: $( document ).width() - 10 }, "document" ); $( "#elx" ).position( { my: "right bottom", at: "right bottom", of: $( document ), collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: $( document ).height() - 10, left: $( document ).width() - 10 }, "document as jQuery object" ); win.scrollTop( 0 ); $( "#elx" ).position( { my: "right bottom", at: "right bottom", of: window, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: win.height() - 10, left: win.width() - 10 }, "window" ); $( "#elx" ).position( { my: "right bottom", at: "right bottom", of: win, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: win.height() - 10, left: win.width() - 10 }, "window as jQuery object" ); if ( scrollTopSupport() ) { win.scrollTop( 500 ).scrollLeft( 200 ); $( "#elx" ).position( { my: "right bottom", at: "right bottom", of: window, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: win.height() + 500 - 10, left: win.width() + 200 - 10 }, "window, scrolled" ); win.scrollTop( 0 ).scrollLeft( 0 ); } event = $.extend( $.Event( "someEvent" ), { pageX: 200, pageY: 300 } ); $( "#elx" ).position( { my: "left top", at: "left top", of: event, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 300, left: 200 }, "event - left top, left top" ); event = $.extend( $.Event( "someEvent" ), { pageX: 400, pageY: 600 } ); $( "#elx" ).position( { my: "left top", at: "right bottom", of: event, collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 600, left: 400 }, "event - left top, right bottom" ); try { $( "#elx" ).position( { my: "left top", at: "right bottom", of: "", collision: "none" } ); } catch ( e ) {} setTimeout( function() { assert.equal( window.globalOf, undefined, "of treated as a selector" ); delete window.globalOf; done(); }, 500 ); } ); QUnit.test( "offsets", function( assert ) { assert.expect( 9 ); var offset; $( "#elx" ).position( { my: "left top", at: "left+10 bottom+10", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 70, left: 50 }, "offsets in at" ); $( "#elx" ).position( { my: "left+10 top-10", at: "left bottom", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 50, left: 50 }, "offsets in my" ); $( "#elx" ).position( { my: "left top", at: "left+50% bottom-10%", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 58, left: 50 }, "percentage offsets in at" ); $( "#elx" ).position( { my: "left-30% top+50%", at: "left bottom", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 65, left: 37 }, "percentage offsets in my" ); $( "#elx" ).position( { my: "left-30.001% top+50.0%", at: "left bottom", of: "#parentx", collision: "none" } ); offset = $( "#elx" ).offset(); assert.equal( Math.round( offset.top ), 65, "decimal percentage offsets in my" ); assert.equal( Math.round( offset.left ), 37, "decimal percentage offsets in my" ); $( "#elx" ).position( { my: "left+10.4 top-10.6", at: "left bottom", of: "#parentx", collision: "none" } ); offset = $( "#elx" ).offset(); assert.equal( Math.round( offset.top ), 49, "decimal offsets in my" ); assert.equal( Math.round( offset.left ), 50, "decimal offsets in my" ); $( "#elx" ).position( { my: "left+right top-left", at: "left-top bottom-bottom", of: "#parentx", collision: "none" } ); assert.deepEqual( $( "#elx" ).offset(), { top: 60, left: 40 }, "invalid offsets" ); } ); QUnit.test( "using", function( assert ) { assert.expect( 10 ); var count = 0, elems = $( "#el1, #el2" ), of = $( "#parentx" ), expectedPosition = { top: 60, left: 60 }, expectedFeedback = { target: { element: of, width: 20, height: 20, left: 40, top: 40 }, element: { width: 6, height: 6, left: 60, top: 60 }, horizontal: "left", vertical: "top", important: "vertical" }, originalPosition = elems.position( { my: "right bottom", at: "rigt bottom", of: "#parentx", collision: "none" } ).offset(); elems.position( { my: "left top", at: "center+10 bottom", of: "#parentx", using: function( position, feedback ) { assert.deepEqual( this, elems[ count ], "correct context for call #" + count ); assert.deepEqual( position, expectedPosition, "correct position for call #" + count ); assert.deepEqual( feedback.element.element[ 0 ], elems[ count ] ); delete feedback.element.element; delete feedback.target.element.prevObject; assert.deepEqual( feedback, expectedFeedback ); count++; } } ); elems.each( function() { assert.deepEqual( $( this ).offset(), originalPosition, "elements not moved" ); } ); } ); function collisionTest( assert, config, result, msg ) { var elem = $( "#elx" ).position( $.extend( { my: "left top", at: "right bottom", of: "#parent" }, config ) ); assert.deepEqual( elem.offset(), result, msg ); } function collisionTest2( assert, config, result, msg ) { collisionTest( assert, $.extend( { my: "right bottom", at: "left top" }, config ), result, msg ); } QUnit.test( "collision: fit, no collision", function( assert ) { assert.expect( 2 ); collisionTest( assert, { collision: "fit" }, { top: 10, left: 10 }, "no offset" ); collisionTest( assert, { collision: "fit", at: "right+2 bottom+3" }, { top: 13, left: 12 }, "with offset" ); } ); QUnit.test( "collision: fit, collision", function( assert ) { assert.expect( 2 + ( scrollTopSupport() ? 1 : 0 ) ); collisionTest2( assert, { collision: "fit" }, { top: 0, left: 0 }, "no offset" ); collisionTest2( assert, { collision: "fit", at: "left+2 top+3" }, { top: 0, left: 0 }, "with offset" ); if ( scrollTopSupport() ) { win.scrollTop( 300 ).scrollLeft( 200 ); collisionTest( assert, { collision: "fit" }, { top: 300, left: 200 }, "window scrolled" ); win.scrollTop( 0 ).scrollLeft( 0 ); } } ); QUnit.test( "collision: flip, no collision", function( assert ) { assert.expect( 2 ); collisionTest( assert, { collision: "flip" }, { top: 10, left: 10 }, "no offset" ); collisionTest( assert, { collision: "flip", at: "right+2 bottom+3" }, { top: 13, left: 12 }, "with offset" ); } ); QUnit.test( "collision: flip, collision", function( assert ) { assert.expect( 2 ); collisionTest2( assert, { collision: "flip" }, { top: 10, left: 10 }, "no offset" ); collisionTest2( assert, { collision: "flip", at: "left+2 top+3" }, { top: 7, left: 8 }, "with offset" ); } ); QUnit.test( "collision: flipfit, no collision", function( assert ) { assert.expect( 2 ); collisionTest( assert, { collision: "flipfit" }, { top: 10, left: 10 }, "no offset" ); collisionTest( assert, { collision: "flipfit", at: "right+2 bottom+3" }, { top: 13, left: 12 }, "with offset" ); } ); QUnit.test( "collision: flipfit, collision", function( assert ) { assert.expect( 2 ); collisionTest2( assert, { collision: "flipfit" }, { top: 10, left: 10 }, "no offset" ); collisionTest2( assert, { collision: "flipfit", at: "left+2 top+3" }, { top: 7, left: 8 }, "with offset" ); } ); QUnit.test( "collision: none, no collision", function( assert ) { assert.expect( 2 ); collisionTest( assert, { collision: "none" }, { top: 10, left: 10 }, "no offset" ); collisionTest( assert, { collision: "none", at: "right+2 bottom+3" }, { top: 13, left: 12 }, "with offset" ); } ); QUnit.test( "collision: none, collision", function( assert ) { assert.expect( 2 ); collisionTest2( assert, { collision: "none" }, { top: -6, left: -6 }, "no offset" ); collisionTest2( assert, { collision: "none", at: "left+2 top+3" }, { top: -3, left: -4 }, "with offset" ); } ); QUnit.test( "collision: fit, with margin", function( assert ) { assert.expect( 2 ); $( "#elx" ).css( { marginTop: 6, marginLeft: 4 } ); collisionTest( assert, { collision: "fit" }, { top: 10, left: 10 }, "right bottom" ); collisionTest2( assert, { collision: "fit" }, { top: 6, left: 4 }, "left top" ); } ); QUnit.test( "collision: flip, with margin", function( assert ) { assert.expect( 3 ); $( "#elx" ).css( { marginTop: 6, marginLeft: 4 } ); collisionTest( assert, { collision: "flip" }, { top: 10, left: 10 }, "left top" ); collisionTest2( assert, { collision: "flip" }, { top: 10, left: 10 }, "right bottom" ); collisionTest2( assert, { collision: "flip", my: "left top" }, { top: 0, left: 4 }, "right bottom" ); } ); QUnit.test( "within", function( assert ) { assert.expect( 7 ); collisionTest( assert, { within: document }, { top: 10, left: 10 }, "within document" ); collisionTest( assert, { within: "#within", collision: "fit" }, { top: 4, left: 2 }, "fit - right bottom" ); collisionTest2( assert, { within: "#within", collision: "fit" }, { top: 2, left: 0 }, "fit - left top" ); collisionTest( assert, { within: "#within", collision: "flip" }, { top: 10, left: -6 }, "flip - right bottom" ); collisionTest2( assert, { within: "#within", collision: "flip" }, { top: 10, left: -6 }, "flip - left top" ); collisionTest( assert, { within: "#within", collision: "flipfit" }, { top: 4, left: 0 }, "flipfit - right bottom" ); collisionTest2( assert, { within: "#within", collision: "flipfit" }, { top: 4, left: 0 }, "flipfit - left top" ); } ); // jQuery 3.2 incorrectly handle scrollbars in WebKit/Blink-based browsers. // This is fixed in version 3.3, see https://github.com/jquery/jquery/issues/3589. // As the data here comes from jQuery directly and the changes to fix it // are non-trivial: https://github.com/jquery/jquery/pull/3656, just accept // that scrollbar data in this jQuery version is inaccurate. QUnit[ jQuery.fn.jquery.substring( 0, 4 ) === "3.2." ? "skip" : "test" ]( "with scrollbars", function( assert ) { assert.expect( 4 ); $( "#scrollx" ).css( { width: 100, height: 100, left: 0, top: 0 } ); collisionTest( assert, { of: "#scrollx", collision: "fit", within: "#scrollx" }, { top: 90, left: 90 }, "visible" ); $( "#scrollx" ).css( { overflow: "scroll" } ); var scrollbarInfo = $.position.getScrollInfo( $.position.getWithinInfo( $( "#scrollx" ) ) ); collisionTest( assert, { of: "#scrollx", collision: "fit", within: "#scrollx" }, { top: 90 - scrollbarInfo.height, left: 90 - scrollbarInfo.width }, "scroll" ); $( "#scrollx" ).css( { overflow: "auto" } ); collisionTest( assert, { of: "#scrollx", collision: "fit", within: "#scrollx" }, { top: 90, left: 90 }, "auto, no scroll" ); $( "#scrollx" ).css( { overflow: "auto" } ).append( $( "