What is causing this web page to scroll down when it loads? - javascript

I have a page with bunch of 3rd party JS scripts. When I load the page, it scrolls down to a specific div.
I already spent 2 hours trying to find out which code is causing the scroll.
Is there a way to find out which script / part of the code is triggering the scroll?

Wow, was this hard to debug. Seems like the debugger has some missing features, like tracking the emitter of an event.
The problem is WooCommerce. Specifically, it appears that WooCommerce is setting autofocus on the billing_last_name input field. The browser is then automatically scrolling the page to bring the field into view.
One would hope that there is a configuration option to turn off autofocus, but it appears WooCommerce does not provide this.
You can try adding this to your theme
function disable_autofocus_firstname($fields) {
$fields['billing']['billing_first_name']['autofocus'] = false;
return $fields;
}
add_filter('woocommerce_checkout_fields', 'disable_autofocus_firstname');
If that doesn't work, you can create a CSS rule to hide the billing name field and then run a delayed JS function to show the billing name field after the page is fully loaded.
How I debugged it
Per the OP's request, and considering the bounty offered, I will describe how I debugged this.
I'm a little embarrassed that I didn't just say to myself "Hmm, the page scrolls up to a form, the cursor is in the first field of the form, I wonder if it has autofocus set." Unfortunately, I'm not mainly a front-end programmer, and autofocus did not come to mind at first.
I started with the idea that it was being scrolled via JavaScript, either an explicit call to a scroll function or by setting scrollTop on something. I put an event breakpoint on the scroll event and tried to determine where the scroll event was being generated. Although I found the scroll event, I did not find the source of it. All I could determine at this stage is that the scroll event was targeting the document, not something inside it.
I used monitorEvents to listen for events on document and found only 3, a click and 2 scrolls, the last of which was caused by a delayed scroll-to-top function inserted by the OP to work around the first scroll. I put an execution breakpoint on setting that timeout (not executing the function) in an attempt to "divide and conquer", that is, to see if the scroll was happening before or after that. I maintained that breakpoint for the rest of my debugging effort.
The weird thing was that generally, the page would not scroll before it hit that breakpoint, but sometimes it did. I thought that was odd, and although I didn't know what to make of it, it had me on the lookout for something unusual.
I tried searching all the JavaScript for "scroll" and "update" (text) to look for more breakpoints to set, and set a bunch at JavaScript that did scrolling, but nothing hit.
I noticed that there was a lot of JavaScript dynamically updating the page, and thought that maybe the scroll was due to an update of some sort.
I tried putting a jQuery event listener that logged all events on document (since the JS was using custom events not logged by monitorEvents, and I had already determined that document was the target of the scroll event) to emit all the events and see if it was some custom update event. There were a bunch of custom events, and I later generated the events in the console to see if the page would scroll in response. Since I could not get the page to scroll that way, I concluded that events were likely a dead end.
I switched tactics. I looked at where the page was scrolling to, and saw it was scrolling the WooCommerce form into place. So, while stopped at the execution breakpoint (described above), I deleted the entire WooCommerce form from the DOM, and verified that the page no longer scrolled. This had me convinced that whatever the problem was, it was caused by WooCommerce.
Unfortunately, my Google Fu failed me, and I did not immediately find the problem through a Google search. Instead I found how WooCommerce scrolls the page on errors to make sure the error messages are visible. This led me back to the JavaScript.
Still, there was a lot of JavaScript, a lot of it dynamically creating the form (localizing it on the fly), and a bunch of German (which I don't speak), and I wasn't finding any JavaScript causing scrolling. I really wanted to narrow down which JS file was causing the scroll.
Chrome allows you to set a breakpoint on "script first statement" (under Event Listener Breakpoints -> Scripts), so I did that. In addition to stopping at the first line in every script file, it stops at the beginning of every <script> tag on the page. I found this script tag near the bottom of the page
<script type="text/javascript">
if(typeof jQuery == 'undefined' || typeof jQuery.fn.on == 'undefined') {
document.write('<script src="https://www.prored3.de/wp-includes/js/jquery/jquery.js"><\/script>');
document.write('<script src="https://www.prored3.de/wp-includes/js/jquery/jquery-migrate.min.js"><\/script>');
}
</script>
The weird thing about this script tag was that the scroll happened immediately after this script tag was processed, but jQuery was already loaded, so the script actually did nothing. I was also able to confirm via the console that both before and after this script tag (which is before and after the scroll), the DOM was not flagged as ready. This means that all the jQuery ready handlers had not run by the time the scroll happened. That eliminates a lot of JavaScript, and got me thinking about why the scroll happened after but not before this tag.
I guessed that internally, the browser saw the document.write calls and determined that the DOM was not complete until after it passed that tag, but as soon as it was past it, the DOM was complete and it could start processing page-level attributes. That, along with the earlier observations, led me to look at the WooCommerce form more closely and discover the autofocus attribute set on the billing_first_name field.
Oddly enough, I was not able to prevent the scrolling by deleting the autofocus attribute. I don't know why, but I'm guessing it has to do with browser internals and the fact that the DOM was not ready. I was, however, able to prevent the scrolling by hiding the the billing_first_name in put element via CSS, which convinced me it was the cause of the scroll.
Adding "autofocus" to my Google search led me to other complaints of similar behavior with WooCommerce, and combining posts led me to the PHP solution I posted.

Updated
As I don't have OP's page for testing, the following method of finding registered event listener actually DO NOT solve the issue OP is addressing.
However, this is the general method when I want to find a specific event, just reserved for someone's reference.
If I understand your meaning correctly, you want a method to tell you where do the specific events occur. Please tell me if this is not doing what you want.
You can try to add a breakpoint on chrome debugger.
F12 -> Sources -> Event Listener Breakpoints (in list with those Breakpoints, Scope, etc) -> Control -> Click the box of scroll.
For Sure it may captures some other scroll event you are not interested, but you can go through it next by next until you find the one you want.
Besides, there may be also event not related to scroll, you may also need to try focus or DOM Mutation -> DOMFocusIn.

Related

How do I debug jQuery events using Firefox debugger?

I've been wracking my brain over this and cannot figure it out for the life of me.
Here's a test page I built for the sake of this discussion:
http://jsbin.com/garokalocu
Let's assume this page is very complex and I didn't build it, and I'm trying to see the code that runs when the user clicks "Do It." So I open the debugger, open the side pane and click "Events." I checkmark the click event for #execute which is the button.
Now I click the button, and the code hits the breakpoint. But strangely, the name "Bob" has already been filled in, so clearly it flew right past the actual code, and lands me here:
I don't understand what's going on here. So I tried something else, a new feature in Firefox that I thought might be handy. If I inspect the code, there are little "ev" tags on certain DOM elements. Supposedly you can click those and see the code.
Well, that was fruitless. I'd be forever grateful if someone could please tell me how on earth to debug jQuery events, and see the actual code that gets executed. Thanks!
You see jQuery as the handler because you used jQuery to make those listeners. jQuery code is called when event is triggered. If you used normal JS addEventListener, they will show up in the event without having to step through.
According to the article here the feature is coming in Firefox 34, so if you use Firefox beta it should have the behavior you want.

Is it possible for a browser scroll event to be triggered by DOM manipulation (other than user actions or explicitly calling eg. $.ScrollTop)?

I am researching a problem where a user triggers a scroll event, we process it, and in the process of doing so are somehow triggering a second scroll event. Our code is similar to this. In real life, 'thead' is buried inside many levels of containers, etc.
$(window).on('scroll', function(){
$('thead').css('position','fixed');
})
The triggering action seems to be fixing the position of an element. This causes document.height to change, which makes sense, but such actions do not normally cause a scroll event to occur (from what I can tell).
I can reproduce this in our app (which is a mountain of jQuery) with very specific combinations of browser height and document height (I can't see a pattern to it, though; I just know values that work).
I can't reproduce it in a simple case, and I've been trying to all day.
I am confident that $.ScrollTop() or equivalent functions are not being called, and that the user is only making a single gesture.
The jQuery event object looks to me like it is a second user initiated event, eg. there is nothing to suggest that event #2 was caused by event #1.
This is happening on Chrome, haven't tried other browsers. Any suggestions appreciated.
When you make any element to be position:fixed/absolute, your document's height is changed because changed element become out-of-normal-flow and does not push next elements down (read CSS position property). It's the same as removing element from your page.
So, if you're at the bottom of the page and one of elements is gone, browser scrolls page up to compensate removed element's height (to leave you at the bottom of the page).

check document if there is mouse moving or touching like screensaver

as the title says, i would like to know if theres any possibility in javascript (jquery) to check if there is any action in the document, and if not. something like a screensaver should pop up!
if someone is on the page and looks here, looks there and after a while he doesnt do anything, the mouse (or touch finger) stands still, i want to say the document after a minute without activity...
function noactivity() { //after 60000ms start something here }
i want that global for the whole document!
thanks ted
It can be done relatively simply in jquery using:
setTimeout();
http://jsfiddle.net/bernie1227/hNkTy/1/
I had this issue a while back while I was working on an iframe resizing issue. What I wanted was to tell the parent page whenever there is a change in height of the document.
What I found was that jQuery does not give such facility directly. The main reason for this is that there are too many activities happening to DOM which are not visible, when you are watching it (bind). You could however watch for a specific property like mouse moving on a document.
$(document).mousemove(function(e){
console.log(e.pageY);
console.log(e.pageX);
});
But then again that does not at all mean that the user is interacting with your page. That merely signifies that the user is on your page and his mouse is moving. The user might also be not moving the mouse and merely using his keyboard to interact with your page. So now you would have to watch for keyboard interaction aswell.
$(document).keyup(function(e){
console.log('active');
});
Using these you could create a countdown function which checks for a flag after a set interval of time. You could set the flag if user makes an activity. And after a set amount of time that function the 'noactivity()' function id the flag has not been set.
Another approach to watching the document activity could be you watching the DOM subtree being modified.
jQuery(document).bind('DOMSubtreeModified', function() {
console.log('active');
});
This works for Chrome/FireFox/IE8+ but not on Opera (any version). The main reason being that the operation is too heavy on your browser's resources. And I would discourage using this approach because listening for DOM mutation events may harm performance and the relevant W3C working groups are trying to find a better way to do this and deprecate DOM mutation events for this reason - it's hard or impossible to make a good and performant implementation.
I am not saying that the other options that I mentioned above are good either. They are also expensive operations if you are watching document and should be avoided. Another issue with those options is that the iframe content is not particularly the part of your document and these options will not work if user is interacting with iframe content.
So the conclusion is that W3C did not yet finalize a cheap way where user can watch changes in document subtree.

jquery event for on render an element

I am trying to do all dom manipulations off screen and then make it visible. Which works, except now I have the situation where I am trying to do it with a form which I want to focus on the first input text upon rendering it on the browser.
Something like: myForm.prependTo(myDiv).show().find('input:first').focus();
Problem is that the focus is being called before the form has finished rendering which is causing the lovely error 'Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus'
How do other web developers handle the similiar situation of manipulating elements off screen and then making it visible? I wish jQuery had something like myForm.prependTo(myDiv, function() { /* on render code here */ })
I know one way of doing it is setting a timeout and when it fires I put focus on the input, but I feel like that's not really the cleanest way to do things. I know the iframe has an onload event, so I'm curious if people usually draw their elements in some hidden iframe and listen for its load event to know when the element has finished rendering? If so could you point me to an example of doing this?
myForm.prependTo(myDiv).show(function(e){
$(this).find('input:first').focus();
});​
I know I'm 7 years late, but I had a similar problem, which I solved by putting the stuff I needed to happen after the render in a ready handler.
I had a restore function that worked, but there was zero or near zero visual feedback that the element had been restored.
I tried emptying the element first. It still worked, but still had zero visual feedback.
$("#someSelector").empty();
restore();
Then I discovered ready() happens after the rendering; so I changed it to something like....
$("#someSelector").empty().ready(function() {
restore();
});
Now the restore() doesn't happen until after the empty() action RENDERS. This means my element APPEARS to empty out and then refill (it always did, but now the user can see it happen).
I found this solution somehow a few days ago for a different problem with some vague search that I can't remember. Then I needed it again but couldn't exactly remember what I did. Now my searches included the word "jquery" and "render" and lead me here.
I ended up going thru my code to find out what I did, and I thought it might be a good idea to post it here in case other people stumble on this post and actually need to execute something AFTER rendering happens.
Cheers.

jQuery & Chrome - Finding Button Hooks

Using Chrome's developer tools I am trying to determine what jQuery function is hooking an input button on the page for debugging purposes. I usually just keep searching until I find it, but I figured I'd ask this time.
Is there a way to find a jQuery button hook for a specific button in Chrome? I've tried looking through the Event Listener Breakpoints, but can never seem to find the right thing to pause it.
Basically, I need to know what jQuery / Javascript is being executed after the button is clicked.
The hooks are implemented in the application like so:
$('.button_class').click(function (){
$('#button_id').click(function(){
etc...
try this :
$(yourbutton).data('events');
Depending on the number of events/timers on the page this doesn't always work. But you can try "pausing" before clicking the button you want to debug in the JavaScript debug window. That way the debugger will pause on the next line that executes. The thing that occasionally prevents you from using that is if there is a "hover" or mouse move/in/out event tied on an element you have to pass over to get to the button (including the button itself). In that case I just remove those events (if I can) until I get the one I want. The event listener breakpoints would be more ideal but they're sometimes difficult when using jQuery or another library, I've actually put in a feature request to the Chrome Dev Tools team to address this very issue. (allowing you to specify what files are "yours" and only "breaking" in those specific files)
good luck -ck

Categories