Chrome Extension: How to reload/re-execute content script on Ajax request - javascript

I'm trying to execute a content script for a certain site (inject a button or change the link) however I would like to do this as the user browses the website.
The problem is that the web page is built dynamically with ajax requests as the user browses.
I had solved this earlier in an extension I had written by actually injecting my JavaScript into the web page.
I was wondering whether there is a better alternative of just being able to register for an ajaxComplete event or something similar in my content script so that I can re-execute.
I can do the following:
function listener()
{
console.debug("listener fired.");
}
document.addEventListener("DOMSubtreeModified", listener, false);
However that fires way too many times during one page load.

There is no ajax listener that I am aware of, but it wouldn't help much anyway as you need to catch when page is modified, not ajax request is sent/received (page modification usually happens later and can be not tied to ajax request at all).
DOMSubtreeModified is the right way to go, just implement some protection from too frequent calls:
function listener()
{
console.debug("listener fired.");
}
var timeout = null;
document.addEventListener("DOMSubtreeModified", function() {
if(timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(listener, 500);
}, false);
This way it would trigger listener if there was no other events within 500ms.

The best answer I found was a bit interesting and involved a bit of message passing in between the content scripts and the background.html file.
I'll post the code then explain:
Background.html
function updatePageAction(tabId)
{
chrome.tabs.sendRequest(tabId, {is_content_script: true}, function(response) {
if (response.is_content_script)
chrome.pageAction.show(tabId);
});
};
chrome.tabs.onUpdated.addListener(function(tabId, change, tab) {
if (change.status == "complete") {
updatePageAction(tabId);
}
});
content_script.js
// The background page is asking us to find an address on the page.
if (window == top) {
chrome.extension.onRequest.addListener(function(req, sender, sendResponse) {
if (req.is_content_script)
start_content_script();
sendResponse({is_content_script: true});
});
};
You want to solve updating or re-executing the script on DOM changes. Luckily the DOM changes involved a URL change (although it was AJAX DOM changes to update the page).
The URL change however fires a onUpdated event. However every tab is firing these "events" and we want to make sure we only care about the one in which we have matched our content scripts too (you can specify a match in the manifest!).
By passing a messgae to the content_script being executed in the current tab, we are asking "Are you my content script? If so, please re-start."

Related

Making ajax call on navigating away from page

I am working on a site that has multiple links to other sites. What I want is to send an ajax call to report that the user is going away when someone clicks and navigates away from the page. I put an alert on click of the links, which works but for some reason the controller never gets the ping.
Any assistance will be appreciated on how to achieve it.
Can't be done.
When you go to navigate away, there is only one event that can catch that, the onbeforeunload event, and that is quite limited in what it can do.
Not to mention there are other ways of leaving the page without navigating away:
Losing network connection
Closing the browser.
Losing power.
The only thing you can do is to set up a heartbeat kind of thing that pings the server every so many milliseconds and says 'I'm Alive.'
Depending on what you are trying to do, there is usually a better option, however.
You can try to simply set click event handler which will check the href attribute of every link before navigating. If it goes to another website, the handler sends AJAX request and then (after server responding) redirects to the page.
var redirect = '';
$('a').click(function() {
if (this.href.host != document.location.host) {
if (redirect) return false; // means redirect is about to start, clicking other links has no effect
redirect = this.href;
$.ajax({
url: '/away',
success: function(){document.location.href = redirect;}
});
return false;
});
However it can't work properly, if user has opened your page in multiple tabs.
The only reliable way to do this these days is by hooking (i.e. add event listener) your code in so called sendBeacon method from Beacon API on beforeunload event (i.e. when user tries to navigate away from page).
The navigator.sendBeacon() method asynchronously sends a small amount of data over HTTP to a web server. It’s intended to be used for sending analytics data to a web server, and avoids some of the problems with legacy techniques for sending analytics, such as the use of XMLHttpRequest:
<script>
var URL = 'https://your.domain/your-page.php';
// on 'beforeunload'
window.addEventListener('beforeunload', function (event) {
navigator.sendBeacon(URL);
// more safely is to wait a bit
var wait_until = new Date().getTime() + 500;
while (new Date().getTime() <= wait_until);
});
</script>
You can try:
$(window).on('beforeunload', function(){
return "This should create a pop-up";
});
You can achieve it by capturing clicks on all the links on the page (or all the relevant links) and then call ev.preventDefault() on it to prevent the browser from navigating directly to that page.
Instead, you can make an AJAX call to your server and when that call returns, you can set window.location to the URL the user was trying to navigate to.
Here is a workaround you could try.
At the loading of the page, use jquery to move all href attributes to tempHref attribute. Then, attach a method to catch the click event.
This way, clicking on the links will not automatically move to the intended destination.
When the click occurs, simply perform the ajax call, and then using javascript, move to the other page.
$('a').each(function () {
var link = $(this);
link.attr('tempHref', link.attr('href'));
link.removeAttr('href');
});
$(document).on('click', 'a', function ()
{
//perform ajax call;
location.href = $(location).attr('tempHref');
});

fire event on closing the page

I wonder if i've unset($_SESSION['enough']); and want to free it up on closing the page.
[ suppose visitor is viewing page of the website pages in new tab ]
i'm using this code
<script language="javascript">
window.onbeforeunload = function() {
console.log('event');
return false;
}
</script>
i wonder how can i apply to fire this code unset($_SESSION['login_id']); , it might look ridicules but this is the basic idea and i'm gonna give example what can be used for
For example : media website would like members not to watching more than one video in same time so the watching page drop session and free it on closing it so can watch more! js indeed is essential for website using jwplayer so no chance of talking about members with disabled js.
In order to load the killsession.php that runs the unset() command, you can run that page with ajax with async:false
Have a look at
Ajax request with JQuery on page unload
jQuery.ajax({url:"http://localhost/killsession.php", async:false})
You can use jQuery to fire on unload with the unload function (http://api.jquery.com/unload/).
$( window ).unload(function() {
// On the unload, we can fire a request back to the server
// .get(), .post(), and .ajax() may be useful.
});

PageLoaded Event Handler At Application Level

In my Windows 8 application, I need to run some code when a page is loaded, but I need to run it at the application level in my default.js file. Is there an event I can use to generically attach to when a page is loaded into the DOM?
In default.js, there's already a reference to WinJS.Navigation, so you could do something like:
nav.addEventListener("navigated", function (e) {
console.log('loaded a new page ' + e.detail.location);
});
That will fire when you navigate from page to page versus actually loading into the DOM (not sure how specific you mean that).
If you want to have something happen when you truly load a page into the DOM, you could add a override load in your pages that then invoke a method on WinJS.Application, for example (Where the unload is part of the page code you get already generated)
load: function()
{
WinJS.Application.doSomething();
},
unload: function () {
this._items.dispose();
},
and in the code for the application in app.js, you'd have
app.doSomething = function () { console.log("I did something"); }
There's a glitch here though that I'm hunting down. Once I override load, I'm seeing an HierarchyRequestError on the second invocation.

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.

Is there a way to catch the back button event in javascript?

Is there a way to respond to the back button being hit (or backspace being pressed) in javascript when only the location hash changes? That is to say when the browser is not communicating with the server or reloading the page.
Use the hashchange event:
window.addEventListener("hashchange", function(e) {
// ...
})
If you need to support older browsers, check out the hashChange Event section in Modernizr's HTML5 Cross Browser Polyfills wiki page.
I did a fun hack to solve this issue to my satisfaction. I've got an AJAX site that loads content dynamically, then modifies the window.location.hash, and I had code to run upon $(document).ready() to parse the hash and load the appropriate section. The thing is that I was perfectly happy with my section loading code for navigation, but wanted to add a way to intercept the browser back and forward buttons, which change the window location, but not interfere with my current page loading routines where I manipulate the window.location, and polling the window.location at constant intervals was out of the question.
What I ended up doing was creating an object as such:
var pageload = {
ignorehashchange: false,
loadUrl: function(){
if (pageload.ignorehashchange == false){
//code to parse window.location.hash and load content
};
}
};
Then, I added a line to my site script to run the pageload.loadUrl function upon the hashchange event, as such:
window.addEventListener("hashchange", pageload.loadUrl, false);
Then, any time I want to modify the window.location.hash without triggering this page loading routine, I simply add the following line before each window.location.hash = line:
pageload.ignorehashchange = true;
and then the following line after each hash modification line:
setTimeout(function(){pageload.ignorehashchange = false;}, 100);
So now my section loading routines are usually running, but if the user hits the 'back' or 'forward' buttons, the new location is parsed and the appropriate section loaded.
Check out history.js. There is a html 5 statechange event and you can listen to it.
onLocationChange may also be useful. Not sure if this is a Mozilla-only thing though, appears that it might be.
Did you took a look at this? http://developer.yahoo.com/yui/history/

Categories

Resources