JavaScript TinyMCE/jQuery race condition on firefox
Solution 1
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.
Solution 2
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.
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);
});
}
});
Solution 3
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 yourtextarea
s. 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); } });
user1639001
Web infrastructure consultant. Chef and Docker enthusiast.
Updated on July 03, 2022Comments
-
user1639001 almost 2 years
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()
returnednull
.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. WhentinyMCE.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?
-
user1639001 over 15 yearsTypo at the end was a typo made when copying code here, in actual code it's correct. I've edited the question. <code>$(document).ready()</code> installs callback to be executed when DOM tree is ready, called by jQuery from <code>window.onload</code>, I suppose.
-
user1639001 over 15 yearsTinyMCE does something I don't really understand with onLoad events (maybe it conflicts with jQuery?) and adds SCRIPT tags to document. Firebug, when bug occurs, shows in HTML inspector only HTML tag, with HEAD tag (no BODY), and in HEAD only two SCRIPT tags which I didn't put there.
-
nickf over 15 yearsin your new onload, you can check to see if there was an existing onload and call that as well.