jQuery: confirm if .html() is addable - javascript

To save up on performance, I load social links by adding them when user hovers over the follow/like buttons. Example:
jQuery(document).ready(function(){
jQuery('.trigger').bind('click mouseover', function(){
jQuery(this).html('<script src="http://platform.twitter.com/widgets.js"></script> Follow #twitter ');
jQuery('.trigger').unbind('click mouseover');
});
});
Works fine. In fact, you should do this as well.
The problem is that in Firefox when you use incognito mode, it blocks social links, so .html() doesn't output anything.
The same problem with some browser add-ons that blocks social links.
Is there anyway to find out if .html() did output the code, and if not, just add a link like:
jQuery(this).html('Follow');

You need to load the script yourself rather than this way and then check if it succeeded:
jQuery(document).ready(function($) {
$('.trigger').one('click mouseover', function(){
// we add just the HTML manually
$(this).html(' Follow #twitter ');
// and the script with jQuery
$.getScript("http://platform.twitter.com/widgets.js").fail(function(err) {
// react to errors here, for example set the .html
}).done(function(success) {
// here we can be sure the script loaded.
});
});
});
Note that a particularly clever ad blocker could intercept the request and return an empty response instead of a 404 - but in practice none do.
I also generally disagree with your assertion that they should be lazy loaded - in general it's mostly fine to just add the word async to the script and it won't block the page loading and load later:
<!--- NOTE THE 'async' --->
<script async src="http://platform.twitter.com/widgets.js"></script>
Follow #twitter
async - Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously. It has no effect on inline scripts (i.e., scripts that don't have the src attribute).
From MDN.
As general code review, ready takes a parameter which you can use to short name jQuery (as $ commonly), you should use the standard.on in favor of the deprecated deprecated .bind (and .off for unbind).
Update, I already realized that what you were doing with the bind/unbind (on/off) pair is essentially a one which fires an event only once on the first time - so I changed it to that.

Related

Why does DOM appendChild() fire on('load', ...) but jQuery append() does not?

I have the following to snippets of code:
$(document).ready(function() {
document.head.appendChild(
$('<script />').attr('src', 'source.js').on('load', function() {
...
})[0]
);
});
This will fire the load handler.
Whereas using the normal jQuery append():
$(document).ready(function() {
$('head').append(
$('<script />').attr('src', 'source.js').on('load', function() {
...
})
);
});
This will not fire the load hander.
What am I missing: why does jQuery append() not work?
Is using document.head.appendChild() a bad idea?
NOTE: I can't use $.getScript(). The code will run on a local file system and chrome throws cross site script errors.
Update
Some people had trouble reading the compact style, so I used extra line feeds to clarify which objects where calling which methods. I also made it explicit that my code is inside a $(document).ready block.
Solution
In the end I went with:
$(document).ready(function() {
$('head')[0].appendChild(
$('<script />').attr('src', 'source.js').on('load', function() {
…
})[0]
);
});
I think #istos was right in that something in domManip is breaking load.
jQuery is doing some funny business in its DOM manipulation code. If you look at jQuery's source, you'll see that it uses a method called domManip() inside the append() method.
This domManip() method creates a document fragment (it looks like the node is first appended to a "safe" fragment) and has a lot of checks and conditions regarding scripts. I'm not sure why it uses a document fragment or why all the checks about scripts exist but using the native appendChild() instead of jQuery's append() method fires the event successfully. Here is the code:
Live JSBin: http://jsbin.com/qubuyariba/1/edit
var url = 'http://d3js.org/d3.v3.min.js';
var s = document.createElement('script');
s.src = url;
s.async = true;
$(s).on('load', function(e) {
console.log(!!window.d3); // d3 exists
$(document.body).append('<h1>Load fired!</h1>');
});
$('head').get(0).appendChild(s);
Update:
appendChild() is a well supported method and there is absolutely no reason not to use it in this case.
Maybe the problem is when you choose DOM appendChild, actually you called the function is document.on('load',function(){});, however when you choose jQuery append(), your code is $('head').on('load', function(){}).
The document and head are different.
You can type the code below:
$(document).find('head').append($('<script />').attr('src', 'source.js').end().on('load', function() {
...
}));
You should probably make sure that the jquery append is fired when the document is ready. It could be that head is not actually in the dom when the append fires.
you don't have to ditch jquery completely, you could use zeptojs. Secondly, I couldn't find out how and why exactly this behavior is happening. Even though i felt answer was to be found in links below. So far i can tell that if you insert element before definig src element then load won't fire.
But for manual insertion it doesn't matter. (????)
However, what i was able to discover is that if you use appendTo it works.
Code :http://jsfiddle.net/techsin/tngxnkk7/
var $ele = $('<script />').attr('src', link).load(function(){ abc(); }) ).appendTo('head');
New Info: As is understood adding script tag to dom with src attribute on it, initiates the download process of script mentioned in src. Manual insertion causes page to load external script, using append or appendTo causes jquery to initiate downloading of external js file. But event is attached using jquery and jquery initiates download then event won't fire. But if it's the page itself initiates the download then it does. Even if event is added manually, without jquery, adding via jquery to dom won't make it fire.
Links in which i think should be the answer...
Append Vs AppendChild JQuery
http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/
http://www.blog.highub.com/javascript/decoding-jquery-dommanip-dom-manipulation/
https://github.com/jquery/jquery/blob/master/src/manipulation.js#L477-523
http://ejohn.org/blog/dom-documentfragments/

Best way of unobtrusive onload in plain JavaScript

What is the best unobtrusive way of invoking something after the page is being loaded in plain JavaScript? Of course in jQuery I would use:
$(document).ready(function(){...});
but I am not sure about the most reliable approach in plain js.
Clearly
window.onload = ...
is not proper solution, because it would overwrite previous declaration.
What I am trying to do is to insert an iframe into a div after the page is loaded, but maybe there are actually better ways of doing it. My plan is to do something like:
window.onload = function(divId){
var div = document.getElementById(divId);
div.innerHTML = "<iframe src='someUrl' .. >";
}
EDIT:
Apologies for not including all necessary details.
The script is not for my website - the idea is to show a part of my site (a form) on external web sites. The priority is to minimize the effort someone has to put to use my code. That is why I would like to keep everything in js file and absolutely nothing in <script> - except of <script src="http://my.website/code.js" />. If I change URL of an iframe or I would like to add some features, I would like to update the code on all other web sites without asking them to make any changes.
My approach might be wrong - any suggestions are very welcome.
//For modern browsers:
document.addEventListener( "DOMContentLoaded", someFunction, false );
//For IE:
document.attachEvent( "onreadystatechange", someFunction);
`attachEvent` and `addEventListener` allow you to register more than one event listener for a particular target.
See:
https://developer.mozilla.org/en/DOM/element.addEventListener
Also definitly worth looking at how jQuery does it:
http://code.jquery.com/jquery-1.7.js Search for bindReady.
Use window.addEventListener and the events load or DOMContentLoaded:
window.addEventListener('DOMContentLoaded',function(){alert("first handler");});
window.addEventListener('DOMContentLoaded',function(){alert("second handler");});
object.addEventListener('event',callback) will insert an event listener into a queue for that specific object event. See https://developer.mozilla.org/en/DOM/element.addEventListener for further information.
For IE5-8 use window.attachEvent('event',callback), see http://msdn.microsoft.com/en-us/library/ms536343%28VS.85%29.aspx. You can build yourself a little helper function:
function addEventHandler(object,szEvent,cbCallback){
if(typeof(szEvent) !== 'string' || typeof(cbCallback) !== 'function')
return false;
if(!!object.addEventListener){ // for IE9+
return object.addEventListener(szEvent,cbCallback);
}
if(!!object.attachEvent){ // for IE <=8
return object.attachEvent(szEvent,cbCallback);
}
return false;
}
addEventHandler(window,'load',function(){alert("first handler");});
addEventHandler(window,'load',function(){alert("second handler");});
Note that DOMContentLoaded isn't defined in IE lesser 9. If you don't know your recipient's browser use the event load.
Just put your script include at the very end of the document, immediately before or after the ending </body> tag, e.g.:
(content)
(content)
<script src="http://my.website/code.js"></script>
</body>
</html>
All of the markup above the script will be accessible via the usual DOM methods (reference). Obviously, not all ancillary resources (images and such) will be fully loaded yet, but presumably that's why you want to avoid the window load event (it happens so late).
The only real purpose of ready-style events is if you don't control where the script gets included (e.g., libraries) or you need to have something execute prior to the page load and something else after the page load, and you want to avoid having two HTTP requests (e.g., for two different scripts, one before load and one after).

What are the benefits and/or pitfalls of calling a function directly from an anchor tag vs creating events onload?

Is there a proper/standard way?
Link
vs
<script>
$(document).ready(function(){
$('#link1').click(function(){ ... });
});
</script>
Link
Personally I prefer the second. It allows me to separate my markup and script. This means that scripts could be placed in a separate file and since scripts are static resources they get cached, minified, obfuscated, ... And reduced markup size obviously leads to reduced bandwidth and so faster loading site. In a web page there are really 3 notions that should not be mixed:
markup
scripting
styling
From the top of my head:
The first one only allows one handler per time on a single element
The first one cannot have access to anything but global scope
The first one doesn't allow for event delegation, because some events need to use event capture in standards compliant browsers for delegation to work (namely blur and focus), and you cannot select whether to use capture or bubble there.
The first one ... read #DarinDimitrov's answer.
You would use the first one when... ask facebook or hotmail. I've got nothing on that.
My 2c:
Nowadays with the advent of heavy use of ajax and the versatility of jQuery, I like to centralize the processing management.
The
<a href='#' onClick= ...></a>
does not necessary require the href. On that, I, myself, avoid extra stress whenever not needed. So I do not code href on anchors that resolve to onClick. Secondly, unless I have a special need to manage anchors (like $('a ...)....), I do not use anchors either. I just use plain div or span or even paragraph (< p>).
the a (anchor) allows to automatic cursor:pointer and text-decoration handling for anchors.
The
$(document).ready( function () {
$('#link').click(...
is a good way to centralize processing where you can have all entries documented right there:
function a() { .. }
function b() { .. }
function c() { .. }
....
$(document).ready( function () {
// originated on thatfile.html
$('#clicka').click(a());
// originated on thisfile.asp
$('#clickb').click(b());
// originated on form c in file myforms.asp
$('#clickc').click(c());
});

jQuery .load() does not load plug-ins [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a main page with 2 links that load external files via .load(). The first file has a simple JavaScript rollover, which works when the content is loaded. The second file has a jQuery plug-in that does not work when loaded via .load() - but works fine when the data file is viewed by itself.
Main file: http://gator1105.hostgator.com/~carc/test-load.html
Second data file that works by itself, but not from .load(): (same URL as above, but the file is test-load-two.html - StackOverflow will allow me to create only 1 hyperlink)
Rather than paste my source code here, you can just view it from the pages themselves.
How can I get the second file with the slideshow to work when loaded with .load()?
I acutally did something similar with a site I'm working on. What you'll want to do is make a callback function for each page for the $.load() call on the main page.
See the following code from the jquery.load() documenation:
$('#result').load('ajax/test.html', function() {
alert('Load was performed.');
});
In your particular case, you'd want something like this on the main test-load.html page.
$(document).ready(
function(){
$('li').click(function(){
var showThisContent = this.id;
$('#content').load('test-load-'+showThisContent+'.html', function(){
if (showThisContent == "one"){
//Do logic for test-load-one.html
//Pre-load your images here.
//You may have to assign a class to your anchor tag
//and do something like:
$('a.assignedClass').mouseover(function(){});
$('a.assignedClass').mouseout(function(){});
} //end if
if (showThisContent =="two"){
//Do logic for test-load-two.html here
$('.slideshow').cycle({
fx: 'fade',
speed: 500,
timeout: 0,
next: '.nextSSimg',
prev: '.prevSSimg',
pager: '#SSnav',
cleartype: true,
cleartypeNoBg: true
}); //end .cycle()
} //end if
); //end .load(location, callback function())
}); //end $('li).click()
}); //end $(document).ready()
Now, obviously I didn't convert all your code, but what's happening here is that once document.ready is complete, the callback function will run, and since the elements like '.slideshow' are now loaded into the DOM, you're callback code will bind to them appropriately.
You could switch this code around in several ways to have the same result (i.e., wrap 2 $.load()s into conditions rather than doing the conditional logic in the .load callback, and/or put a callbackOne() and callbackTwo() function above document.ready and then call them appropriately) but that's your preference. You should be able to do what you want to using the callback function argument of the $.load().
Ignore this answer
Your second file does its initialization in a "document.ready" block. That's not going to be run when your content loads via AJAX. Try taking the code in the second page that's inside "document.ready" out of that, so that it's just a bare script block.
[edit] Oh I see - not only is the script inside a "document.ready" block (well, it's not anymore), but that second page is a complete HTML document. You can't really load a complete HTML document into the middle of another document; it doesn't make sense, and jQuery is only going to grab what's in the body. Thus, try moving your script tag into the body and see what happens. (You still don't want "document.ready", I don't think.)
[edit again] actually I take that back - I don't think jQuery strips anything out; I just bet the browser gets confused.
[edit yet again] ok, ok I see that you've changed it again - let me take a really close look.
OK here's a better answer: for reasons I don't understand, when you load a fragment (or a whole page; whatever) with jQuery using the special "selector" trick to pluck out just a portion of the document:
var showThisContent = this.id;
$('#content').load('test-load-' + showThisContent + '.html #content-area');
the jQuery library strips out the scripts completely from the content, and doesn't ever run them. Why? I don't know.
I know that you probably don't trust me anymore, but here's what I did with your source code: I took that second file (test-load-two) and stripped out the head and stuff; basically I made it a fragment containing only the "content-area". (I also got rid of the script tag that loads jquery, as you don't really need that since the outer page already has it.) Then I changed the main page (test-load) so that when it calls "load" it just passes in the URL without that '#content-area' selector. That works.
[edit] I just posted a question to the jQuery forum: http://forum.jquery.com/topic/the-load-function-and-script-blocks
Don't go for $.load. Try $.get instead, which might seem less comfortable, but it worked for me in a different case. Sample code as following.
$(li).click(function() {
// your code for finding the id
$.get('test-load-' + id + '.html', function(responseHtml){
$('div#content-area').empty().append($(responseHtml)); // remove all elements from #content-area
// $('...').html(responseHtml) will not work
});
});
I hope this solves your problem.

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