Run Code After Function is Finished OR DIV Appears - javascript

I have written a Userscript for Facebook and it groups similar notifications together. Now, using just a static HTML page with old notifications I had, the script works 100%.
Here's the problem: the DIV that holds notifications by default, has no notifications in it until the user clicks on the Notification button. Facebook has an inline onclick event that displays the DIV (Notifications menu) and uses AJAX to grab the notifications. Since my userscript only runs on startup, it finds nothing there - it has no effect on the page. I tried using a .click() event but right when you click the Notifications button it runs my code. The thing is, Facebook is still running it's AJAX request for the notifications, meaning that there are still no notifications for my script to work with, making it have no effect.
I don't want to use a generic setTimeout because I don't want the user to have to see the notifications before and then suddenly see them after. Is there a way to monitor the DIV so once the notifications are added, it runs? Or that once Facebook finishes it's AJAX request, it will run my code?

You can setInterval() to monitor the div's innerHTML, once populated you can run.

Here's the problem: the DIV that holds notifications by default, has no notifications in it until the user clicks on the Notification button. Facebook has an inline onclick event that displays the DIV (Notifications menu) and uses AJAX to grab the notifications.
...
I don't want to use a generic setTimeout because I don't want the user to have to see the notifications before and then suddenly see them after. Is there a way to monitor the DIV so once the notifications are added, it runs?
Yes there is:
var notificationDiv = document.getElementById(...);
var lastTimeoutID = null;
var main = function(evt){
// evt.target is the inserted element
// if you expect more elements, then do the following:
lastTimeoutID = setTimeout(function(){
lastTimeoutID = null;
// uncomment below block if you only need to do the work once.
/*
notificationDiv.removeEventListener("DOMNodeInserted", main, false);
*/
// do your work here.
}, 500); // waiting 500ms for next element to be added, otherwise doing work.
if (lastTimeoutID) {
clearTimeout(lastTimeoutID);
lastTimeoutID = null;
}
};
notificationDiv.addEventListener("DOMNodeInserted", main, false);
All of the timeout code above might be removable depending on what it is you're userscript is doing.

Maybe you can add a setTimeout loop. Something like
setTimeout(function(){
/* check for divs */
if(/* divs are found */){
//apply code
}
else {
setTimeout(/* loop again */);
}
},1000);

Related

How do I wait for my scroll function to finish before starting the next function?

I have a chrome extension that scrolls to the bottom of a users page in order to load all their items (the site uses lazy load)
function makeProgressCountingAllItems() {
// start off by counting all the items you see on the page
allItems = document.getElementsByClassName('items');
// scroll the last item currently loaded
allItems[allItems.length - 1].scrollIntoView();
document.dispatchEvent(new MouseEvent('scroll'));
}
I then want to get all the items on the page (including the newly loaded ones) and put them in an array
function selectItems() {
return document.getElementsByClassName('items')
}
But if I call both of these functions like this
makeProgressCountingAllItems();
selectItems();
The problem is my selectItems function runs before the makeProgressCountingAllItems function gets a chance to scroll to the bottom of the page.
How do I run the second function after the first function is complete?
I think that your Question's title it's not appropiate for the feature you're asking, because ideally you want to listen for new items to be added you don't need to worry about waiting the scroll function to finish.
For listening changes in the DOM you can use a MutationObserver.
See this question as reference.
If you want to wait until the scroll function finishes it's not possible with the current API.
At this moment there's an open request to include a callback when scrollIntoView animation ends, you can see the thread of this request here and a workaround for your question here.
Adding a setTimeout is the best option you have, here's an example:
makeProgressCountingAllItems();
setTimeOut(()=> { selectItems(); },500);

Run jquery animated gif on form next button

I have a form that has multiple pages, on one of the page I’m using a web service to return a value (triggered on the next button) that is then displayed on the next page.
The value return takes over 20 second and want to use an animated gif to let the user know something is happening, I am using a jquery page animation that is normally fired using
$(window).load(function() {
// Animate loader off screen
$(".se-pre-con").fadeOut("slow");;
});
I have tried $(window).unload(function() nut this seems to fire straight away andnever leaves the animation.
Ideally I would like to fire the animation on the next button:
Next
And run while the web service is getting the information but npo sure hope this is done.
I have tried
$(document).ready(function () {
$('.button').on('click', getAn);
});
function getAn () {
$(".se-pre-con").fadeOut("slow");;
});
But this doesn’t fire. I also don't have acess to modify the html.
Is it possible to use an animated gif like this or is it really only for page loading?

Adding an extra button in facebook post using google chrome extension

I was successful to track all "uiStreamSource" that holds the link associated with each facebook post (status, image, etc) to add one extra button next to the date to do some other tasks using google chrome extensions. This button does a predefined job which not important to mention in this context.
I wrote this content script:
contentscript.js
var nodeslist=document.getElementsByClassName("uiStreamSource");
alert(nodeslist.length);
Each time a facebook page is loaded, the alert shows me 10 detected classes (i.e., 10 posts). But when I scroll down, new posts show up and this code fails to detect them. Since I need to update all uiStreamSource nodes in all posts, how can I solve this?
UPDATE
I tried this code in contentscript.js:
load();
document.addEventListener("DOMNodeInsertedIntoDocument", load, false);
function load(){
var nodeslist=document.getElementsByClassName("uiStreamSource");
alert(nodeslist.length);
}
The first time it runs, I get the correct number of the current nodes (current facebook posts) but once I scroll down and more posts are fetched, the alert shows up indicating that load function is called but the number of nodes printed is 0. Why is that?
Thanks on advance.
You can add a DOMNodeInserted event and check if the element that is going to be inserted is a post by checking its classes.
Or an easy solution is to use the jcade plugin. It can call a callback function when an element with specified selector is inserted.
Listen to the scroll event and add any new posts to nodeslist. You could use setInterval as well to catch any posts that are added when the user is not scrolling.

replacing content on pages that use ajax

I'm working on a extension for a fb game that adds some extra info to popup boxes, hides some useless information and run some timers so you can see how long till you have to do something even if you are not on the game page.
My problem is that a while back they went over to using ajax to change between pages and I am wondering if I am using the right approach to handle this.
I run a setInterval that checks if I am on a page where i want to add/remove soemting and i havent done it yet, if this is true I do my stuff, the code looks something like this:
function myFunction() {
if($(selector for some element I am looking for).length > 0 && $(selector for some item I add).length == 0) {
//do some stuff
}
}
setInterval("myFunction()",1000);
Is this the right way of handling ajax page change from an content script in an extension?
If so is there a better way to see if I am on the right page or if i have added to this page already other than doing a selection?
You can use livequery jquery plugin to catch when new element is created on a page:
$("#ajax-element").livequery(function({
//ajax-element is created
});
You can also listen to DOMSubtreeModified event which fires when DOM changes:
document.addEventListener("DOMSubtreeModified", function(event){
//something has changed, possibly ajax-element was added
});
There are also more specific DOMNodeInsertedIntoDocument and DOMNodeRemovedFromDocument events.

JavaScript interrupt event

Here is the situation :
If I am in page-1 now I am clicking a link from page-1 to navigate to page-2. Before page-2 is loaded I am hitting escape so that still I am staying in page-1.
At that point I want to track that event.
Is there any JavaScript event so that I can track the above scenario?
More Info :
To avoid concurrent request to the "page-2", when the user clicks a link from page-1 I am redirecting to page-2 and disabling the link (to avoid multiple request to "page-2). At this point when we hit Esc and abort loading page-2, I need to enable the link again in page-1.
I tried using this code:
<html>
<head>
<script>
document.onkeypress = KeyPressed;
function KeyPressed(e)
{
if (!e) e = window.event; //IE Compatibility
alert(e.keyCode);
}
</script>
</head>
<body>
Stack Overflow
</body>
</html>
It detects any key pressed while you're on the page. Once you click on the SO link and hit escape, nothing happens. The browser is already receiving a response from the SO server and is starting to process it, this page has already been "left", despite appearances when you see "Waiting for http://stackoverflow.com" in your browser's status bar.
Your idea of handling this event is plain wrong. Blocking the button is required to make the user unable to do double post data. However, the request is sent instantaneously(!) after the click on the link.
So, if you click the link once, stop the page, then click second time - it will submit it twice, and that is not what is intended to happen.
Two events are triggered when the page unloads.
window.onUnload
window.onBeforeUnload
You can use these events to cancel the unload of the page, however after that, there page is considered done.
What you can do is make the page wait 5 secs or so before going to the new page:
eg:
window.onunload = (function() {
var time = new Date();
var cancel = false;
window.onkeypress = function (e) {
if ((e || window.event).keyCode == 27) cancel = true;
};
while(time > new Date() - 5000) {
if (cancel) return false;
}
});
In fact that may cause some browsers to hang since you're taking up all process time given to the JS script. ie: in the while block.
You could probably avoid that by doing a blocking function call, that isn't so process intensive, like one that is bound by network latency. eg: XMLHttpRequest() etc. I don't think calls that are queued such as setTimeout() will work here, as they don't block.
Since the <a href> tag tells the browser to move to another page, it's up to it to decide if it will still have your script running. If I were it, I wouldn't listen.
If you want to override that, I guess you should tell the browser not to listen to that particular onClick event, and put a callback in place that loads the target page in the background. This assures your page is still active. After the target page has loaded (by your script), you could kindly ask the browser to update itself with the received content.
So that's the theory. I have no idea if the DOM lets you just override the content of a loaded page, but I guess it does.

Categories

Resources