I have a scroll into view already which works, however I was thinking to make it smarter.
This is my code so far
((IJavaScriptExecutor)driver).ExecuteScript("arguments[0].scrollIntoView(true);", element);
which is hooked into my OnClicking event listener - so whenever it goes to click an element, first it scrolls it into view.
This is great and it does what I want it to, however when running my tests my page is scrolling up and down even if the element is in the middle of the screen.
So my question is, how do I set a parameter on this to say, if the element is below 3/4 on the viewable screen then scroll?
I think. You can try it.
var element = driver.FindElement(By.Xpath("//*/blabla"));
var js = driver as IJavaScriptExecutor;
js.ExecuteScript("window.scrollTo(" + element.Location.X + ","+(element.Location.Y - 100) + ");");
You can use javascript to get the X/Y cordinates:
var cumulativeOffset = function(element) {
var top = 0, left = 0;
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent;
} while(element);
return {
top: top,
left: left
};
};
In this case you want the Y coordinate.
And use this: http://www.w3schools.com/jsref/met_win_scrollto.asp
Or... take a look at this:
Javascript scrollIntoView() middle alignment?
I know this is old post, but if people looking for answer, here it is
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView({block: \"center\"});", webElement);
Related
jQuery documentation for offset() states:
Also, dimensions may be incorrect when the page is zoomed by the user; browsers do not expose an API to detect this condition.
However, is there a way I could calculate the correct offset in browsers in touch environment when using spread to zoom in the contents of a page?
I created a small sample demonstrating the issue: https://jsfiddle.net/dhykgsmp/4/ (open in Chrome). Please scroll down and click zoom in. The offset of the autocomplete input is wrong.
Thank you.
I had the same problem and found a workaround.
You need a root child element with zero offsets to make this work.
$.fn.oldOffset = $.fn.offset;
$.fn.offset = function () {
var c = $.fn.oldOffset.apply(this, arguments);
// root child element with zero offset
var wrc = $('body').children().first().oldOffset();
var needToFix = wrc.left > 0 || wrc.top > 0;
if (needToFix) {
return {
left: c.left - wrc.left,
top: c.top - wrc.top
};
} else {
return c;
}
}
I'm not sure what the intended functionality of this code is, but if you'd like the 'autocomplete input' element to be positioned relative to the 'autocomplete container' I would suggest using the .style.top attribute, or getting the location with Element.getBoundingClientRect() and setting the position accordingly in your positionDropdown() function.
I have a button back-to-top that is affixed to the left side of the screen - it uses scrollTop to slide-scroll to the top of the page when it's clicked. When the page the loads, the button is visible and does not cover anything that is readable etc.
When a user scrolls down the page, the button goes over certain DIVs that have text content. When the button goes into such a DIV I want it to hide using .hide(). Can't get it to work, here's what I have:
var p = $('a.back-to-top');
var position = p.position();
if(position == $('#about-me')){
$('a.back-to-top').hide();
}
Is if(position == $('#about-me')) the correct way to check if the button's position is in the #about-me DIV? Or, should I create a variable similar to position for the DIV?
EDIT: A messy but simple fiddle
You will need to do this check inside of a callback .. probably $(window).scroll so that it is checked each time the window scrolls; otherwise, it is only checked when the page loads.
I don't think you want to use position either as that is position relative to parent. Instead, you probably want .offset. This returns an object with top and left members. An == comparison does not make sense, especially to a jQuery object. You want to use:
$(window).on('scroll', function () {
var offset = $("a.back-to-top").offset().top;
var within = $("#about-me").offset().top;
if (offset >= within && offset <= within + $("#about-me").height()) {
$("a.back-to-top").hide();
}
else {
$("a.back-to-top").show();
}
});
The offset of .back-to-top changes with scrolling if it has a fixed position, but the offset of the static block does not change, so you can do this comparison.
See it in action: http://jsfiddle.net/QnhgF/
http://api.jquery.com/position/ - position() method returns a position object which has .left and .top properties. So basically, you can't compare position to some object returned by a selector. Instead, you should compare the "top" property values of both elements.
For example you have:
var p = $('a.back-to-top');
var position = p.position();
Also get this:
var aboutMePosition = $('#about-me').position();
And then you can compare:
aboutMePosition.top and position.top whichever way you need.
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions
I'm trying to use the left variable to replace '1493' in this code. It works fine when it's a number but when I changed it over to use 'left' the if statement stops working.
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var postCount = $(".post").length;
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
if(left >= columnLength) {
$(".num").text(left);
}
});
Does anyone have any ideas where I'm going wrong with this? Any pointers would be great.
You may need to force it to be an integer:
var left = parseInt($(document).scrollLeft());
Lets take a look at the math you have really quick.
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
You are basically cancelling out width, and (postCount*743). It leaves you with --1493 which is positive 1493. The following would have the same effect:
var columnLength = 1493;
So, the reason the if statement fires when you put in the static value 1493, is because columnLength ALWAYS equals 1493 which, of course satisfies this condition:
if (1493 >= columnLength)
You could as easily write:
if (1493 >= 1493)
That said, it should still, theoretically fire when left becomes greater than or equal to 1493. But left is the current horizontal scroll position in pixels. It would be a HUGELY wide page to hit a scroll position of 1493.
Edit: Here's a fiddle to give an idea of how fast the scroll position increases: http://jsfiddle.net/vdQ7B/16/
EDIT 2:
Here is an update in response to your comment.
As I understand it, you were trying to get a horizontal scrollbar that would, essentially, scroll forever.
Please see the following fiddle for a demo: http://jsfiddle.net/vdQ7B/40/
The code is below:
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var viewportwidth = window.innerWidth;
// If our scrollbar gets to the end,
// add 50 more pixels. This could be set
// to anything.
if((left + viewportwidth) === width) {
$("body").css("width", width + 50);
}
});
Per the comments in the code, we simply increase the width of the body if we determine we've reached the end. scrollLeft() will only tell us the number of pixels that are currently not visible to the left of the viewable area. So, we need to know how much viewable area we have, and how much is hidden to the left to know if we've scrolled all the way to the end.
If you have a scroll bar on an inner element, like a div, you'd need to update with width of the div, not the body.
Note: You may also need to use $(window) instead of $(document) to get scrollLeft() to work across all browsers.
Note: See here about using "innerWidth". There are some compatibility issues, and you may need to expand it a bit to handle other cases (IE6).
If I have a div with overflow:auto so that it is a scrollable div and I load it with information that makes a significant scroll area, is there a way that when I load the information, the div shows the bottom results? Or essentially scrolls to the bottom?
I've seen jQuery solutions but this is for use in an HTA so I cannot use jQuery. Is there a purely javascript way to accomplish this?
var myDiv = document.getElementById('myDiv');
myDiv.scrollTop = myDiv.scrollHeight;
Works in Firefox, Safari, Opera, Chrome and even Internet Explorer, which is more than I can say for the SSE test case I Set up... lol
I will spare you the rant about the obtuse solutions offered by others, and here is an example of code that could be used for an instant messaging type client.
document.body.onload = function()
{
var myDiv = document.getElementById('myDiv');
// Pick your poison below, server sent events, websockets, AJAX, etc.
var messageSource = new EventSource('somepage');
messageSource.onmessage = function(event)
{
// You must add border widths, padding and margins to the right.
var isScrolled = myDiv.scrollTop == myDiv.scrollHeight - myDiv.offsetHeight;
myDiv.innerHTML += event.data;
if(isScrolled)
myDiv.scrollTop = myDiv.scrollHeight;
};
};
The part of that example that is relevant checks to see if the div is already scrolled to the bottom, and if it is, scrolls it to the bottom after adding data to it. If it is not already scrolled to the bottom, the div's scroll position will stay such that the visible content of the div is unaffected by adding the data.
document.getElementById('mydiv').scrollTop = 9999999;
The scrollTop property specifies the scrolling offset in pixels from the top of the region. Setting it to a very large value will force it to the bottom.
How about this?
function scroll_to_max(elm) { // {{{
if(!scroll_to_max_el) {
scroll_to_max_el = elm;
setTimeout(scroll_to_max, 10); // Allow for the element to be updated
} else {
var el = scroll_to_max_el;
var t = el.scrollTop;
el.scrollTop = t+100;
if(el.scrollTop != t) {
setTimeout(scroll_to_max, 10); // Keep scrolling till we hit max value
} else {
scroll_to_max_el = null;
}
}
}
var scroll_to_max_el = null; // Global var!
// }}}
(NOTE: Only tested it in Chrome...)
Late answer but this is much more helpful
$('#mydiv').scrollTop(($('#mydiv').height()*2));
I think you need to set the scrollTop after the element is updated.
setTimeout(function (){
el.scrollTop = 999999999
}, 10)
also, in chrome at least, 99999999999 will scroll to the bottom. but 999999999999 (an extra 9) will scroll to the top. it's probably converted to an int in the C side of webkit.