i have a page on which there an event handler attached to an onclick event. when the event fires it passes contents of a textbox to a GET request. since the url is not in the same domain so i create a script tag and and attach the url to its source like this
elem.onclick=fire;
function fire()
{
var text=document.getElementById('text').value;
var script=document.createElement("script");
script.className="temp";
script.src="some url"+"?param="+text;
document.body.appendChild(script);
}
now if that event is fired and more than one time i want to cancel all the previous GET request(because they still might be receiving response) and make the GET request with latest text. But for this i need to cancel the previous requests.
i tried
document.body.removeChild(script);
script.src=null;
but this does not work in Firefox(i am using Firefox 5) although this works in Google Chrome.Does anyone know if these requests can be cancelled in Firefox and if yes then how?
UPDATE
As suggested by Alfred, i used window.stop to cancel a request but does not cancel a request but hangs it up. It means that when i look into firebug it looks like the request is being made but there is no response.
The solution is simple: for creating HTTP requests, use <img> instead of <script> element. Also you always have to change the src attribute of the same element.
var img;
function fire()
{
var text = document.getElementById('text').value;
var im = img || (img = new Image());
im.src = "url"+"?param="+text;
}
You may ascertain that it actually works by doing the following: the URL you request should have a huge response time (you can ensure this using e.g. PHP's sleep function). Then, open Net tab in Firebug. If you click the button multiple times, you'll see that all incomplete requests are aborted.
This is entirely shooting from the hip, but if the script tag has not finished loading you can probably simply script.parentElement.removeChild( script ). That is more or less what mootools does anyway. (Technically, they replace /\s+/ with ' ' first, but that does not seem to be terribly important).
Would it be ok for you to use a JS framework? If so, MooTools has this functionality built into its Request.JSONP object
I'm not sure if this is what you're looking for, but it seems like a similar issue:
http://www.velocityreviews.com/forums/t506018-how-to-cancel-http-request-from-javascript.html
To get around the cross-domain issue, you might be able to use CORS instead (assuming you can change what's on the server):
http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/
If you do this, you could then use the more standard XMLHttpRequest's abort() function.
CORS is compatible with all the major modern browsers except Opera (http://caniuse.com/cors).
Related
I want to create a custom profiler for Javascript as a Chrome DevTools Extension. To do so, I'd have to instrument all Javascript code of a website (parse to AST, inject hooks, generate new source). This should've been easily possible using chrome.devtools.inspectedWindow.reload() and its parameter preprocessorScript described here: https://developer.chrome.com/extensions/devtools_inspectedWindow.
Unfortunately, this feature has been removed (https://bugs.chromium.org/p/chromium/issues/detail?id=438626) because nobody was using it.
Do you know of any other way I could achieve the same thing with a Chrome Extension? Is there any other way I can replace an incoming Javascript source with a changed version? This question is very specific to Chrome Extensions (and maybe extensions to other browsers), I'm asking this as a last resort before going a different route (e.g. dedicated app).
Use the Chrome Debugging Protocol.
First, use DOMDebugger.setInstrumentationBreakpoint with eventName: "scriptFirstStatement" as a parameter to add a break-point to the first statement of each script.
Second, in the Debugger Domain, there is an event called scriptParsed. Listen to it and if called, use Debugger.setScriptSource to change the source.
Finally, call Debugger.resume each time after you edited a source file with setScriptSource.
Example in semi-pseudo-code:
// Prevent code being executed
cdp.sendCommand("DOMDebugger.setInstrumentationBreakpoint", {
eventName: "scriptFirstStatement"
});
// Enable Debugger domain to receive its events
cdp.sendCommand("Debugger.enable");
cdp.addListener("message", (event, method, params) => {
// Script is ready to be edited
if (method === "Debugger.scriptParsed") {
cdp.sendCommand("Debugger.setScriptSource", {
scriptId: params.scriptId,
scriptSource: `console.log("edited script ${params.url}");`
}, (err, msg) => {
// After editing, resume code execution.
cdg.sendCommand("Debugger.resume");
});
}
});
The implementation above is not ideal. It should probably listen to the breakpoint event, get to the script using the associated event data, edit the script and then resume. Listening to scriptParsed and then resuming the debugger are two things that shouldn't be together, it could create problems. It makes for a simpler example, though.
On HTTP you can use the chrome.webRequest API to redirect requests for JS code to data URLs containing the processed JavaScript code.
However, this won't work for inline script tags. It also won't work on HTTPS, since the data URLs are considered unsafe. And data URLs are can't be longer than 2MB in Chrome, so you won't be able to redirect to large JS files.
If the exact order of execution of each script isn't important you could cancel the script requests and then later send a message with the script content to the page. This would make it work on HTTPS.
To address both issues you could redirect the HTML page itself to a data URL, in order to gain more control. That has a few negative consequences though:
Can't reload page because URL is fixed to data URL
Need to add or update <base> tag to make sure stylesheet/image URLs go to the correct URL
Breaks ajax requests that require cookies/authentication (not sure if this can be fixed)
No support for localStorage on data URLs
Not sure if this works: in order to fix #1 and #4 you could consider setting up an HTML page within your Chrome extension and then using that as the base page instead of a data URL.
Another idea that may or may not work: Use chrome.debugger to modify the source code.
How do I check if a call to window.location failed because the given URL was invalid, etc? Is there some event I can set on the window object or on some other object that can catch this?
Finally got it to work using a "workaround" that is not a generic solution as I originally hoped:
I am using the fact that the link I am trying to open is a custom url scheme (e.g. myxx://localhost) on mobile, and if it fails, the action I want to perform is a redirection to a standard appstore URL (os-specific). The workaround tries to open the custom URL, and if it fails, the timeout function kicks in shortly after, and opens an alternative url:
setTimeout(function() { window.location=alternateUrl; }, 25);
window.location = customUrl;
The downside is that when the customURL fails, a standard safari browser shows a message box that the site could not be opened, but at least it still redirects the user to the appstore.
Not really possible, because when window.location = someURL is executed, before the URL is even tested, your document is removed from the window. You have no code remaining that could test if it worked.
If the link is on the same origin, you may issue an XMLHttpRequest to test if the page is reachable but there doesn't seem to be a way to test if a page isn't requestable just due to cross origin request or because the URL is wrong.
For a general document, I don't know any way to test if a foreign origin page is reachable (but it can be done for an image using the onload event handler).
you can check if page exists using ajax. didn't test code, but it should work.
var rekuest= new XMLHttpRequest();
rekuest.open('GET', 'http://www.thisdoesnotexits.org', true);
rekuest.send();
if (rekuest.status === "404") {alert("not exist!"); }
I am using this type of line in an JS response
if (history && history.pushState){
history.pushState(null, null, '<%=j home_path %>');
}
but when I click back in the browser, I see the JS code of the response instead of the previous page.
Is there a way to make the back button work so it would re-request the page of the last url (before home_path as pushStated in?
Update:
I've found this.. it seems other have the same issue with.. History.js doesn't fix it either
So to confirm some of the comments there.. This happens only in chrome
What I think
I think the root of all this is that the popstate requests the same type of the pushstate document (js response). What needs to be done is on popstate request the html response.. I just don't know how
More updates:
seeing http://railscasts.com/episodes/246-ajax-history-state it mentions to use
$(window).bind("popstate", function() {
$.getScript(location.href);
});
this solves the issue but according to understanding jQuery $.getScript() withtout ajax caching it will add timestamps.. which pollutes the url.. turning it off makes it not work again with the same effect..
Anyone knows how to solves this?
Even more Updates
I tracked the trails of the issue all over the interweb and ended with an issue in chrome which points to a rails issue (firefox works fine however) and an issue in rails-ujs concerning not including Vary Header in the responses
Example can be found here
I am currently playing around with doing
response.headers['Vary'] = 'Accept'
which seems to solve the problem, at first look.
If anyone has the same issue, please check it and let me know
You need to add a listener to the popstate event
window.onpopstate = function(event) {
//load the page
};
When the back button is pressed the url is changed and then the popstate event is fired. It's your responsibility to load the details in your popstate listener that match the changed url.
A nice popstate example
Some browsers fire a popstate event when the page first loads, causing an infinite page loading loop. This can be avoided by adding the following check
var loadPage = window.history.state;
window.onpopstate = function(event) {
if (loadPage)
//load the page
};
Then set the loadPage to true when pushState is called
history.pushState(null, null, '<%=j home_path %>');
loadPage = true;
This technique works in all browsers that support html5 history api.
It happened my with sinatra & chrome.
Solved it with:
$.ajaxSetup({ cache: false });
I've tested this code on my browser using a local HTML file and I've gotten a console security error:
SecurityError: The operation is insecure.
history.pushState(null, null, '<%=j home_path %>');
I can see how manipulating browser history may be considered a potentially dangerous behaviour, so I guess you should check that this is not happening for you as well. Try using the Firebug Javascript console. It is also possible that there might be differences in behaviour between local and http:// HTML files.
Said this, for what I've seen the last element of the history array is basically the current page, so if you want to change the previous one, you might do it by using two pushState() commands - first you push the previous element that you desire, then you push the current path again. If I understood your problem correctly.
I have a problem with ajax requests, which forces me to use javascript linking. I link this way:
window.location.href = ('file:///android_asset/www/custom/kontakty.html');
I would like to know is it possible to set transition/animation when such link is clicked.
Not reliably, no..
If you are running a script until the browser changes location.. chances are that with most browsers the script would get killed once it established a connection.
What you could probably do is request the page via ajax and replace the body tag or whole page in the success handler, where you could also stop/finish your animation.
I'm using xmlhttprequest to call servlet. It is working fine in Firefox. But, in IE, only if I click refresh button, it is working(that too sometimes). Otherwise, it is not triggering. Moreover, the response text is displayed without calling the servlet. Is that using Cache or what? I don't have any idea . Help me out please.
MSIE is too eager in caching XHR requests. The only feasible way to get around this is to add a querystring with a timestamp to the XHR URL.
var url = '/url/to/your/servlet?' + new Date().getTime();
Thanks one and all. Actually, I used "GET" instead of "POST" while calling the servlet in javascript. When I tried POST, it is working fine.
To get around IEs over zelous caching of xhr you must get your servlet to add
Cach-Control:max-age=0
to the response headers of all html and .js files served up.
This will cause a revalidate of all files with this response, next time they are requested from IE including XHR. (must-revalidate did not seem to work on xhr loaded java script file, not sure why)
Be sure to clear the IE cache after this is done for it to take effect the next load.
IE will behave nicely with this setting. But dont put this into production of course.