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.
Related
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.
I'd like something similar to the document.ready event, but for any DOM element.
In more details, I'm hacking away at an app which has a custom framework. I'm trying to add a loading screen. This screen should disappear whenever a certain element pops up on the screen.
Now I don't really know how I'd do this in a clean way, or what a recommended way of doing such things would be, but at the moment, for me it would be enough if I could implement this pseudocode
container.show_loading_spinner()
// .. other stuff ...
// this should only trigger when the next line, which starts creating elements begins
container.on_drawing_begin(function()
{container.hide_loading_spinner()})
//when this begins drawing, the spinner should get hidden.
container.create_some_elements()
I realise this is probably quite complex, and kind of hope I won't be disregarded as a noob but I'm mainly focused on backend development. Is this thing that I'm asking even possible, or should I think this through in a completely different way?
[EDIT]
Q: What is my definition of "rendering"?
A: The moment when an element is present in the DOM and visible on the screen, I call it "rendered". The moment when it's not in the DOM, it's unrendered. Rendering is the process which takes the DOM (and corresponding screen - if the element is visible) from the first state to the second.
More casually though I just want "some event" which is triggered very close in time to the moment when an element begins to render. I need the beginning, because that's when I want to turn off the spinner. I don't want the spinner to be present on the screen at the same time as my elements.
What if you trigger a custom event like hideSpinner when you start rendering your elements?
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
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).
I am wondering if there are any HTML5 events associated with whether or not an element has been viewed or "scrolled into view" by the user.
An example could be a longer page with elements at the bottom, which has yet to be scrolled into the users view...
I have seen jQuery solutions to this problem, however I am only interested in figuring out if weather or not this is achievable purely though the use of HTML5 events and JavaScript.
It should be noted that I have already had a look at the "onfocus" event, which (from it's official description) seems to only be applicable if the user selects or "clicks" somewhere on or within the element itself.
In plain JavaScript you can use the event "scroll" along with getBoundingClientRect().bottom <= window.innerHeight to determine if an html element has come into view.
document.addEventListener("scroll", inView);
function inView() {
if (document.getElementById("viewElement").getBoundingClientRect().bottom <= window.innerHeight) {
console.log("in view");
// uncomment below if you only want it to notify once
// document.removeEventListener("scroll", inView);
}
}
The console prints "in view" when the element comes into view.
<div id="viewElement">Hello there!</div>
There are no built-in events that tell you when an entire DOM element has become viewable/visible on the page due to scrolling or window resizing.
The only way to do this is to keep track of resize and scroll events (which can each cause more or less of your page to be visible) and then use the scroll position and window height and DOM element positions to calculate if your entire DOM element is visible.
Some relevant pieces of code you can either consider using or look into how they work (these tend to be jQuery-based because they are harder to share if not based on a common DOM library):
Lazy Load Plugin for jQuery
Element "in view" Event jQuery Plugin
Check if Element is Visible After Scrolling - plain JS
I had to do something similar to this when I built http://f1circle.com.
When the bottom banner becomes visible, I have to show a spotlight to the user asking him to login.
The code that achieves it using angularjs can be viewed at https://github.com/rajegannathan/angularUtilities/blob/master/directives/eagerload.js
Though it is an angularjs directive, the main logic is in plain javascript. Basically I check if the the last feed's bottom edge is visible and then trigger the spotlight.
I can explain more if required.
As already mentioned, there is no "event" but someone already wrote a method to "detect if a DOM Element is Truly Visible" (the title). It doesn't require JQuery. You might want to check for the value on several events like the document load, scroll or window resize.
I'm looking for a way to capture HTML of objects that are rendered on rollover. An example would be:
Mouse over object to get popup
Press button or key to pause js (to prevent mouse out trigger)
Right click and inspect element to get HTML
Does anyone know of a way to do this?
To your main question, there are two ways to pause the execution of a Javascript thread:
Hit a breakpoint in a debugger
Insert an alert() into the javascript thread and when it fires, it will suspend the execution of that javascript thread until the alert dialog is dismissed.
You haven't described the environment you're operating in and what types of modifications you can or can't make to the host page for us to advise more specifically.
To approach the problem differently, to capture some dynamically inserted HTML there are other strategies. For example, you can use your own javascript (like a bookmarklet) to attach an event handler to the mouse over. You can then set a timer that will watch for when the dynamically generated HTML seems to be present and grab a copy of it. Keep in mind that javascript is single threaded so your own timer will only run when the other javascript thread is waiting for user input, but if the general model is that it pops something up on mouseover and then waits for additional mouse events, then this could work.
yes, <object onmouseover="functionPopup();" onmouseout="functionWrap();">
then place your onkeyup-event to detect the button/key.
The trick is to leave the functionWrap on the object ALONE!!! and OVERWRITE this function functionWrap() (that is referenced by object's onmouseout) with the updated instructions (this works pretty good crossbrowser -even older ones-, since this uses the traditional event model :P ).
Happy tweaking!!