Javascript works only on reloading page - javascript

On https://bm-translations.de/dolmetscher-franzoesisch-deutsch.php you can see the Header doesnt work like it does here: https://bm-translations.de
I guess out of some reason JS isnt working. But the strange thing is on reloading the page (strg + F5) its working. Whats wrong here?
I am loading Jquery first and in footer my own JS.

This is most likely a race condition. You're probably running your javascript before the DOM has had a chance to load. The reason it works on the second reload is that the browser is using the cached version of the scripts.
There are a few ways you can deal with this:
Make sure you script tags don't have an async attribute. This tells them they're allowed to load in any order they'd like so your script may load before jQuery has had a chance to load.
Make sure your scripts are in the right order. The simplest is to move your scripts into the bottom of the body so that the browser loads it last. Make sure your scripts go after any dependent scripts, such as jQuery.
<script src="jquery.js"></script>
<script src="myscript.js"></script>
</body>
The other option is to use a "ready" event. Since you're using JQuery, you already have access to this by simply wrapping your function in a jQuery object with a callback function.
console.log('this will run before the DOM is loaded');
// wait for DOM to load inside jquery callback
$(function() {
console.log('this will run after the DOM has loaded');
});
console.log('this will also run before the DOM is loaded');
The output of the above code would read:
'this will run before the DOM is loaded'
'this will also run before the DOM is loaded'
'this will also run before the DOM is loaded'

because you have added async attribute to jquery script tag.
you can not use the async attribute here if some other script is depending on jquery.
in https://bm-translations.de/dolmetscher-franzoesisch-deutsch.php
<script async src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">
</script>
<script async src="https://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>
while in https://bm-translations.de
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">
</script>
<script async="" src="https://cdnjs.cloudflare.com/ajax/libs/jquery.lazyload/1.9.1/jquery.lazyload.min.js"></script>
more about async attribute.

Related

Defer execution of <Script> tag until after jQuery .load completes

I'm trying to 'include' some generated HTML code on my page with jQuery load (injecting it into #loadhead div):
<script>
$("#loadhead").load("head.php");
</script>
<script defer>
... rest of the code
</script>
I want the second part of the script to load only after head.php is done loading. I tried to enforce execution of the second script tag with defer, but it deson't seem to work - still, once in a while, head.php doesn't manage to load before the rest of the code. What can I do to ensure it is always loaded completely? It generates some JavaScript values that are used by the 'defer' script.
Two options for you:
1. Use a function you call from load's callback
Put your second script's code in a function, so it's loaded but not run, and then call that function from load's success callback.
Example:
<script>
$("#loadhead").load("head.php", otherStuff);
function otherStuff() {
// ...
}
</script>
(I didn't see any reason they should be in separate script tags, so they aren't.)
I'd probably put that all in a .js file and link it rather than having script embedded in the HTML inline.
2. Load the script when load is done
Don't include the second script tag at all; load the script later in the load success callback, either using $.getScript or appending a script element.
Example:
<script>
$("#loadhead").load("head.php", function() {
$.getScript("otherstuff.js");
});
</script>
(I didn't see any reason they should be in separate script tags, so they aren't.)
I'd very much go with Option #1, to avoid unnecessary delays.

Javascript on page load: works in console, but not on load

I want to run this javascript on my homepage when it loads:
$(".mm-page").css({"position":"inherit"});
I added this at the bottom of my home.html.erb:
<% content_for(:after_js) do %>
<script type="text/javascript">
console.log("before");
$(".mm-page").css({"position":"inherit"});
console.log("after");
</script>
<% end %>
Both console.log appear in the console, but the jquery has no effect. If I manually run the jquery line in the console, it works as expected.
How should I proceed to fix this ?
Since you want to make it work on page when it load you should wrap it inside ready handler.The ready() method specifies what happens when a ready event occurs.
Two syntaxes can be used:
$(document).ready(function(){
$(".mm-page").css({"position":"inherit"});
});
OR
$(function() {
$(".mm-page").css({"position":"inherit"});
});
Also be sure that the element .mm-page exists in the moment you're using it with the jQuery selector.
To ensure that all of the DOM elements it operates on exist, put the script tag at the very bottom of the HTML, just prior to the closing </body> tag. All of the elements defined by the HTML above it will then be available for use. This also ensures that the browser can show the user the page prior to downloading any external script files you reference. E.g.:
<!doctype html>
<html>
<!-- ...your page here... -->
<script src="jquery.js"></script>
<script>
console.log("before");
$(".mm-page").css({"position":"inherit"});
console.log("after");
</script>
</body>
</html>
You'll need to translate that to whatever rendering engine you're using, but you get the idea. The end result going to the browser should look like that.
Alternately, you can use jQuery's ready callback, but with the script tags in the correct location, it's unnecessary.
Side note: The default type is JavaScript, there's no need to specify it on the script tag.
console.log appear in the console
Because your DOM has finished loading and it is now ready to use.
That's why you are getting jQuery effect.
In your current script,it is not waiting to finish DOM loading and directly operating on it which is not available as it is not finished loading.
Eiher write script it in
$( document ).ready(function() {
// Handler for .ready() called.
});
OR :
$(function() {
// Handler for .ready() called.
});

Is there a way to load doubleclick.net ad tags on document.ready?

I tried to load doubleclick.net ad tags on document.ready, but the ads don't show up.
HTML
<script language="JavaScript" type="text/javascript" data-ad-src="http://ad.ch.doubleclick.net/adj/swisswebcams/;lng=de;kw=home;tile=3;dcopt=ist;sz=160x600;ord=1874680027?"></script>
JavaScript (requires jQuery)
$(document).ready(function(){
$('script[data-ad-src]').each(function(){
this.src = $(this).attr('data-ad-src');
$(this).removeAttr('data-ad-src');
});
});
The script shows up correct in the generated source code, but it doesn't load the ads anymore. Does the script require the document.ready event? Is there maybe a way to load this script just before document.ready - or to trigger document.ready again?
PS: I prefer to use the "sync" tags over the "async" tags, because "async" is creating an iFrame which then is not flexible in width/height anymore when showing 3rd party networks dynamically.
Try this
<script>
var wr = document.write, dchtml=[];
document.write=function(str) {
// you may want to catch '<script' and add the src to the head when needed
dchtml.push(str);
}
</script>
<script language="JavaScript" type="text/javascript" data-ad-src="http://ad.ch.doubleclick.net/adj/swisswebcams/;lng=de;kw=home;tile=3;dcopt=ist;sz=160x600;ord=1874680027?"></script>
<script>
$(function() { // assuming jQuery is loaded before this block
$("#whereIWantMyAds").html(dchtml.join("\n"));
});
<script>
Check your JavaScript errors. Most likely this is a problem with asynchronous downloading of the script, in fact: I'm sure. This is in the script from doubleclick (downloaded from the link you provided:
document.write('\x3cdiv...
a document.write doesn't work since document.ready already closed the document DOM. You specifically need to add the code to an element in your DOM, which can't be done with document.write. In order to make this work you have to either contact doubleclick and make them change every document.write to something that attaches the code to an element in your page, or asynchronously load the code (including the script) in an iframe.

Intercepting script load

What I need is to hook/intercept other external JS load.
I can place js anywhere in document
Example:
<script src="hook.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
Hook.js should intercept a.js and b.js. Problem is, that when hook.js is executed, i cannot see other scripts (document.scripts contains only hook.js) and document ready event is too late (scripts a.js and b.js are executed).
Is there any way to "see" other script tags, before are executed ?
Thanks for any help
Edit
I need to do any "magic" inside hook.js without modyfing (statically) other HTML.
No jQuery
Credit goes here: https://stackoverflow.com/a/59424277/2016831
You can use a MutationObserver to see what elements are being added to the DOM, and when they are being added, simply change the source code, or if its referencing another URL, just redirect it to your own server, with the original URL as a get parameter instead, and return the modified code that way.
Based on the above answer, you could do something like this:
<script>
new MutationObserver((m, o) => {
let potentialScript = document.querySelector("script + script");
console.log(potentialScript.textContent);
if(potentialScript) {
o.disconnect();
potentialScript
.textContent =
potentialScript
.textContent
.replace(
"})()",
`
window.wow = mySecretMethod;
})()
`
);
}
}).observe(
document.body,
{
childList:1
}
);
</script>
<script>
(function() {
let mySecretMethod = () => {
//does a bunch of evil secret stuff
console.log("HA!");
};
})();
wow()
</script>
<script>
console.log(wow())
</script>
Alternatively you can redirect the HTTP requests with a chrome extension, see https://stackoverflow.com/a/61202516/2016831 for more
If I understand what you're trying to do correctly...
If you can control how scripts A and B are loaded, the best approach is to place them on the same domain as the current page (possibly via proxy), load the files via AJAX, and insert your hooks that way. A library like jQuery as m.casey suggested would make the details of the AJAX and executing the script quite simple.
Otherwise, Javascript does not really have the ability to interact with the parsing of the document (which is what is causing scripts a and b to be loaded in your example, and what would be need to be modified to "intercept" script loading), except by using the evil of document.write to modify the HTML stream. Of course, this only works if hook.js is loaded synchronously (as it is in your example code), if it's loaded into HTML and not XHTML, if you can place a second hook afterwards to postprocess the modified HTML stream, and if you are sure the HTML stream won't escape your mechanism.
For example..
<script id="hook1">document.write("<"+"textarea id='capture'>");</script>
<script src="a.js"></script>
<script src="b.js"></script>
<script id="hook2">document.write("<"+"/textarea");</script>
<script id="hook3">doSomethingWith(document.getElementById("capture").value)</script>
Note that this is a huge hack and you probably shouldn't be doing it.
If you're using jQuery, you could have hook.js load the scripts you wish to intercept as follows:
$.getScript("a.js");
$.getScript("b.js");
This would dynamically create the script tags and you would be certain that hook.js would always proceed a.js and b.js.

JavaScript TinyMCE/jQuery race condition on firefox

I have a website with a form that uses TinyMCE; independently, I use jQuery. When I load the form from staging server on Firefox 3 (MacOS X, Linux), TinyMCE doesn't finish loading. There is an error in Firefox console, saying that t.getBody() returned null. t.getBody(), as far as I understand from TinyMCE docs, is a function that returns document's body element to be inspected for some features. Problem doesn't occur when I use Safari, nor when I use Firefox with the same site running from localhost.
Original, failing JavaScript-related code looked like this:
<script type="text/javascript" src="http://static.alfa.foo.pl/json2.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.ui.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({ mode:"specific_textareas", editor_selector:"mce", theme:"simple", language:"pl" });
</script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.jeditable.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.tinymce.js"></script>
<script type="text/javascript" charset="utf-8" src="http://static.alfa.foo.pl/foo.js"></script>
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ });
</script>
I tried changing script loading order, moving tinyMCE.init() call to the <script/> tag containing $(document).ready() call—before, after, and inside this call. No result. When tinyMCE.init() was called from within $(document).ready() handler, the browser did hang on request—looks like it was too late to call the init function.
Then, after googling a bit about using TinyMCE together with jQuery, I changed tinyMCE.init() call to:
tinyMCE.init({ mode:"none", theme:"simple", language:"pl" });
and added following jQuery call to the $(document).ready() handler:
$(".mce").each( function(i) { tinyMCE.execCommand("mceAddControl",true,this.id); });
Still the same error. But, and here's where things start to look like real voodoo, when I added alert(i); before the tinyMCE.execCommand() call, alerts were given, and TinyMCE textareas were initialized correctly. I figured this can be a matter of delay introduced by waiting for user dismissing the alert, so I introduced a second of delay by changing the call, still within the $(document).ready() handler, to following:
setTimeout('$(".mce").each( function(i) { tinyMCE.execCommand("mceAddControl",true,this.id); });',1000);
With the timeout, TinyMCE textareas initialize correctly, but it's duct taping around the real problem. The problem looks like an evident race condition (especially when I consider that on the same browser, but when server is on localhost, problem doesn't occur). But isn't JavaScript execution single-threaded? Could anybody please enlighten me as to what's going on here, where is the actual problem, and what can I do to have it actually fixed?
The browser executes scripts in the order they're loaded, not written. Your immediate scripts -- tinyMCE.init(...) and $(document.ready(...)); -- can execute before the files finish loading.
So, the problem is probably network latency -- especially with 6 separate scripts (each requiring a different HTTP conversation between the browser and server). So, the browser is probably trying to execute tinyMCE.init() before tiny_mce.js has finished being parsed and tinyMCE is fully defined.
If don't have Firebug, get it. ;)
It has a Net tab that will show you how long it's taking all of your scripts to load.
While you may consider the setTimeout to be duct taping, it's actually a decent solution. Only problem I see is that it assumes 1 second will always fix. A fast connection and they could see the pause. A slow connection and it doesn't wait long enough -- you still get the error.
Alternatively, you might be able to use window.onload -- assuming jQuery isn't already using it. (Can anyone else verify?)
window.onload = function () {
tinyMCE.init(...);
$(document).ready(...);
};
Also, was that a direct copy?
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ }
</script>
It's missing the ) ending ready:
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ })
</script>
Missing punctuation can cause plenty of damage. The parser is just going to keep reading until it finds it -- messing up anything in between.
Since this is the first page which came in google when I asked myself the same question, this is what i found about this problem.
source
There's a callback function in tinyMCE which is fired when the component is loaded and ready. you can use it like this :
tinyMCE.init({
...
setup : function(ed) {
ed.onInit.add(function(ed) {
console.log('Editor is loaded: ' + ed.id);
});
}
});
If you are using jquery.tinymce.js then you don't need tiny_mce.js because TinyMCE will try to load it with an ajax request. If you are finding that window.tinymce (or simply tinymce) is undefined then this means that the ajax is not yet complete (which might explain why using setTimeout worked for you). This is the typical order of events:
Load jquery.js with a script tag (or google load).
Load TinyMCE's jQuery plugin, jquery.tinymce.js, with a script tag.
Document ready event fires; this is where you call .tinymce(settings) on your textareas. E.g.
$('textarea').tinymce({ script_url: '/tiny_mce/tiny_mce.js' })
Load tiny_mce.js this step is done for you by TinyMCE's jQuery plugin, but it could happen after the document ready event fires.
Sometimes you might really need to access window.tinymce, here's the safest way to do it:
$(document).tinymce({
'script_url': '/tiny_mce/tiny_mce.js'
'setup': function() {
alert(tinymce);
}
});
TinyMCE will go so far as to create a tinymce.Editor object and execute the setup callback. None of the editor's events are triggered and the editor object created for the document is not added to tinymce.editors.
I also found that TinyMCE's ajax call was interfering with my .ajaxStop functions so I also used a setTimeout:
$(document).tinymce({
'script_url': '/tiny_mce/tiny_mce.js'
'setup': function() {
setTimeout(function () {
$(document).ajaxStart(function(e) {/* stuff /});
$(document).ajaxStop(function(e) {/ stuff */});
}, 0);
}
});

Categories