I have a static html page that I cannot edit- it does refer to a js file though, so what I do is redirect that url request on my IIS server to my js file- where I dynamically inject jQuery so I can use it. Here's the code I use to insert jQuery:
var script = document.createElement( 'script' );
script.src = 'http://code.jquery.com/jquery-1.9.1.js';
script.type = 'text/javascript';
script.onload = jqueryReady; //most browsers
script.onreadystatechange = function () { //ie
if ( this.readyState == 'complete' ) {
jqueryReady();
}
};
This works great except in one specific case- if I call history.go() on the page when the browser is IE and the page is being served up from an internal web server. Hitting F5 also does not reload the page properly. I have to put the cursor in the address bar and hit enter to get it to load right.
Edit: Forgot to mention the obvious- I have a breakpoint in the jqueryReady() function- and it never gets hit- which is where the problem lies...
It works fine from IE in my dev environment if I serve the page up and then fire history.go() (with a button click). It works with chrome, haven't tested firefox.
So is there an alternative to history.go() to fire a 'true' page reload like what hitting enter in the address bar?
This is also a HUGE page - 6000 lines of html (I didn't write it) and jQuery and all javascript is being loaded in the head- I know you are supposed to load js stuff at the end of the page. Maybe this is related? It feels like a timing issue...
Anyone have any thoughts as to things to check/try? Or know what's going on?
Okay found it... so the solution was here
Bottom line is the code I was using isn't correct, this is the recommended approach to dynamically insert a script into a document and then handle the ready event:
var script = document.createElement( "script" );
script.src = "/reporter/scripts/jquery-1.9.1.min.js";
if ( script.addEventListener ) {
script.addEventListener( "load", jqueryReady, false );
}
else if ( script.readyState ) {
script.onreadystatechange = jqueryReady;
}
document.getElementsByTagName( 'head' )[0].appendChild( script );
Additionally, I needed to check if jQuery was loaded in my jqueryReady function:
function jqueryReady() {
// Check if jQuery exists
if ( typeof jQuery != 'undefined' ) {
// do stuff like $(document).ready()
}
}
This seemed to work in all cases that I could find.
Hope this helps someone else!
Related
How can I remove script elements before they are being executed?
I thought about using the DOMNodeInserted event, but apparently it doesn't catch script elements. I've also tried using the jQuery livequery plugin like that:
$("script").livequery(function () {
$(this).remove();
});
It did remove the script element, but after it was executed.
I'm looking for a cross-browser solution, but I'm not even sure if that's possible. I read about Mutation Observers which seems close enough but I'm not sure if it can solve my problem.
It would be even better if there was a way to modify the script content before it is being executed without removing and recreating it.
Removing a script element does not do anything. If you can somehow access a script element, it was executed a long time ago and removing it will have no effect.
So we need to work around it. If your script element is at the top of the page like this:
<head>
<script src="yourscript.js"></script>
You could make a synchronous ajax request to the same page, so you can parse its content into a new document, modify all script tags and then replace
the current document with the modified document.
var xhr = new XMLHttpRequest,
content,
doc,
scripts;
xhr.open( "GET", document.URL, false );
xhr.send(null);
content = xhr.responseText;
doc = document.implementation.createHTMLDocument(""+(document.title || ""));
doc.open();
doc.write(content);
doc.close();
scripts = doc.getElementsByTagName("script");
//Modify scripts as you please
[].forEach.call( scripts, function( script ) {
script.removeAttribute("src");
script.innerHTML = 'alert("hello world");';
});
//Doing this will activate all the modified scripts and the "old page" will be gone as the document is replaced
document.replaceChild( document.importNode(doc.documentElement, true), document.documentElement);
Unfortunately this cannot be set up in jsfiddle or jsbin. But you should be able to copy paste this code exactly as it is into this
page's console in google chrome. You should see the alerts and when you inspect the live dom, each script was modified.
The difference is that we are running this after scripts have been executed on the page, so the old scripts should still have a working effect on the page.
That's why, for this to work, you need to be the very first script on the page to do it.
Tested to work in google chrome. Firefox is completely ignoring the doc.write call for some reason.
i donot know what you are trying to do. But it is better to load them on request rather than delete on some conditions.
$.getScript('helloworld.js', function() {
$("#content").html('
Javascript is loaded successful!
');
});
If you wants to remove scripts before there execution, its not possible.
But what you can do is, remove script programatically on a condition & if have an issue with memory-leaks, then you can call below code before remove script.
var var1 = 'hello';
var cleanAll = function () {
delete window.var1;
delete window.cleanAll;
};
// unload all resources
cleanAll();
I have a weird issue with IE and Edge. When I first load a page everything works fine. However when I navigate away from the page by going to a new page on the same website, JavaScript on the new page will show errors. If I now go back to the previous page, it, too will no longer work properly and dev. console will show errors.
If I leave dev. console open while navigating and attempt to set breakpoints where the console mentioned errors occur, they are not triggered.
If I refresh the page (with or without dev. tools open) everything works as expected.
In Chrome and FireFox everything just works.
Here's the page in question:
(Sorry according to guidelines I was forced to submit it as a picture, and I was not allowed to submit a direct link)
The first time you load it, everything should be fine. However, when you say click on "Products" the "Products" page will load with JS errors, and if you go back, the original page will no longer work.
From my attempts to solve the issue it seems that it has to do with the fact that IE no longer executes scripts in the proper order once they are cached. However why it always works in other browsers then?
This is not the answer I was hoping for, but I found a workaround (though the original IE/Edge behavior remains unexplained).
Basically I was dynamically loading scripts like so:
function bmpl_loadScript(scriptName, callback, async, crossorigin, integrity, defer) {
if (!bmpl_arr[scriptName]) {
bmpl_arr[scriptName] = true;
var body = document.getElementsByTagName('body')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptName;
if (async) { script.async = 1; }
if (defer) { script.defer = 1; }
if (integrity) { script.integrity = integrity; }
if (crossorigin) { script.crossOrigin = crossorigin; }
if (callback) { script.onload = callback; }
body.appendChild(script);
}
}
//Load scripts
//bootstrap depends on jquery, and scripts depends on both, hence they are not async and are nested
bmpl_loadScript('//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js', function () {
bmpl_loadScript('//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js', function () {
bmpl_loadScript('/v3/js/scripts.min.js', function () {
//Do final JS loading here
}, false,false,false,true);
}, false, 'anonymous', 'sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS',true);
},false,false,false,true);
So, apparently, unlike Chrome and FireFox, IE/Edge cannot figure out how to run the same routine properly if scripts are already in cache. Therefore I had to go back to the original:
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="/v3/js/jquery.fallback.min.js"><\/script>')</script>
<script>bmpl_window_onload();</script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script>jQuery.fn.tooltip || document.write('<script src="/v3/js/bootstrap.fallback.min.js"><\/script>')</script>
<script src="/v3/js/scripts.min.js"></script>
This has the added benefit that it allows for fallbacks in case loading from CDN fails.
The reason why I wanted to go with the dynamic loading approach was that Google's Page Speed Insights tool complained about render-blocking JS. However I suppose first priority should be that a site works, and then how fast it loads, considering that the difference between load speeds would probably be minimal.
I still hope someone might shed a light on this IE/Edge behavior, so I am not marking this as an answer.
Using JavaScript, is there a way to detect whether or not an external script (from a third-party vendor) has completely loaded?
The script in question is used to pull in and embed the markup for a list of jobs and, unfortunately, doesn't make use of any variables or functions. It uses document.write to output all of the content that gets embedded in my page.
Ideally, I'd like to display some kind of loading message while I'm waiting for the external script to load, and if it fails to load, display a "We're sorry, check back later..." message.
I'm using jQuery on the site, but this external script is called before I make the jQuery call.
Here's what the document.write stuff from the external script looks like:
document.write('<div class="jt_job_list">');
document.write("
<div class=\"jt_job jt_row2\">
<div class=\"jt_job_position\">
Position Title
</div>
<div class=\"jt_job_location\">City, State</div>
<div class=\"jt_job_company\">Job Company Name</div>
</div>
");
Attach an function to the load event:
<script type="text/javascript" src="whatever.js" onload ="SomeFunction()" />
As far as your loading... problem goes, try displaying a div for loading and then just display:none-ing it in your onload function. Make sure to handle cases where your script fails to load too, though.
Script tags block downloads, so as long as the content dependent on your script is below where your script it loaded, you should be fine. This is true even if the script is in-line in the body of your page.
This website has a great example of how this works.
This obviously does not work if you're loading the scripts asynchronously.
Scripts without async or defer attributes are fetched and executed immediately, before the browser continues to parse the page.
Source: MDN
You could put a script block after it on the page:
<script src="external_script.js"></script>
<script type="text/javascript">
ExternalScriptHasLoaded();
</script>
Thanks for the assistance above, especially ngmiceli for the Steve Souders link!
I decided to take what's probably a "lazy" approach, and also forego the "loading" message:
$(document).ready(function(){
if ($('.jt_job_list').length === 0){
$('#job-board').html("<p>We're sorry, but the Job Board isn't currently available. Please try again in a few minutes.</p>");
};
});
Pretty simple, but I'm looking to see if an element with the .jt_job_list class is in the dom. If it isn't, I display an error message.
This worked for me: it does however, rely on the newer querySelector interface which most modern browsers support. But if you're using really old browsers, you can use getElement... and run a for loop.
function loadJS(file, callback, error, type) {
var _file = file ;
var loaded = document.querySelector('script[src="'+file+'"]') ;
if (loaded) {
loaded.onload = callback ;
loaded.onreadystatechange = callback;
return
}
var script = document.createElement("script");
script.type = (typeof type ==="string" ? type : "application/javascript") ;
script.src = file;
script.async = false ;
script.defer = false ;
script.onload = callback ;
if (error) {
script.onerror = error ;
}
else {
script.onerror = function(e) {
console.error("Script File '" + _file + "' not found :-(");
};
}
script.onreadystatechange = callback;
document.body.appendChild(script);
}
You could give what ever your looking for an ID
and check whether not the ID has been loaded using document.getElementById("ID");
Is that what your looking for not sure I fully understand?
Does anybody know a way to detect if the jQuery library was loaded and if not append it and start a script as a fallback solution after it's loaded to the DOM?
Here's my script:
if (typeof jQuery == 'undefined') {
// if jQuery Library is not loaded
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js';
document.body.appendChild(script);
startScript();
} else {
// cool, jQuery Library is loaded
startScript();
}
function startScript() {
$.noConflict();
jQuery(document).ready(function($){
.... // my jquery code
});
}
Of course, above appends jQuery correctly but doesn't do anything because the script starts immidiately after appending. Any hint on this?
I appreciate any answer. Thanks!
You're fine except, as you said, that you can't call startScript immediately after appending the new script element. Instead, do a setTimeout loop:
// ...
document.body.appendChild(script);
maybeStart();
Where maybeStart looks like this (not within the body of the if, function declarations aren't valid there):
function maybeStart() {
if (typeof jQuery === "undefined") {
setTimeout(maybeStart, 100);
}
else {
startScript();
}
}
That checks if jQuery is loaded and, if not, waits a 10th of a second and checks again. When jQuery is found, it calls your startScript.
You might want to put a time limit in there (in case jQuery never loads, so you don't loop forever).
Alternately, you can hook a "load"-style event on the script element, but the mechanics of it vary from browser to browser. On some browsers it's just load as with, say, an img element; on IE (at least older versions), you have to use readystatechange, and on some versions of IE both work. So you have to keep a flag so you know whether you've fired off your script, etc., and...well, the above is less complicated in the case where you know the script creates a well-known global symbol (as is the case with jQuery).
I'm looking for a bookmarklet to disable the tinymce visual editor. This is to say, some code that could be pasted into the address bar to disable the editor (and also bookmarked).
Anyone have any ideas?
The page I want to use it on is using an older version of TinyMce, I think the same version that is used on this page: http://www.imathas.com/editordemo/demo.html
Just to reiterate, I want to remove the TinyMce editor and leave the textarea.
If you would like to see the functionality I am talking about, you could also visit this example page: http://www.matracas.org/sentido/tinymce/examples/full.html and click on the enable / disable buttons below the editor.
The problem here is that the syntax relies on knowing what editor id to put into the .get() function.
tinyMCE.get('elm1').hide();
tinyMCE.get('elm1').show();
The bookmarklet would ideally just use tinMCE's show / hide functionality, but it would work for all editors on a page.
Here you go!
javascript:(function(){var arr=Object.keys(tinyMCE.editors);for(var i=0;i<arr.length;i++){try{tinyMCE.editors[arr[i]].remove();}catch(e){}}})()
More visibly pleasing, but same code:
javascript:
(function(){
var arr=Object.keys(tinyMCE.editors);
for(var i=0;i<arr.length;i++){
try{
tinyMCE.editors[arr[i]].remove();
}
catch(e){
}
}
}
)()
I start all my bookmarklets with jQuery, although this may work better as a greasemonkey script depending on what you're trying to do.
javascript:
function loadScript(url, callback){
var head = document.getElementsByTagName("head")[0];
var script = document.createElement("script");
script.src = url;
var done = false;
script.onload = script.onreadystatechange = function() {
if( !done && ( !this.readyState
|| this.readyState == "loaded"
|| this.readyState == "complete") )
{
done = true;
callback();
script.onload = script.onreadystatechange = null;
head.removeChild( script );
}
};
head.appendChild(script);
}
loadScript("http://code.jquery.com/jquery-latest.js", function(){
jQuery('.mceEditor').remove(); }
I have added a TinyMCE remover to my bookmarklet collection:
http://richardbronosky.github.com/Perfect-Bookmarklets/tinymce.html
It has one major advantage over the others I have seen. It restores the content of the textarea back to what was in the source. I don't know if others have experienced this, but we have a web admin to our CMS and TinyMCE, when removed leaves the code altered. I have resolved this.
Here is the code:
for(var i=0;i<tinymce.editors.length;i++){
var tmpId=tinymce.editors[i].id;
var tmpVal=document.getElementById(tmpId).value;
tinyMCE.execCommand("mceRemoveControl",true,tmpId);
document.getElementById(tmpId).value=tmpVal
}
Also on github:
https://github.com/RichardBronosky/Perfect-Bookmarklets/blob/master/tinymce.html