jQuery does not seem to document how it behaves when using $.html() or $.load() to insert an HTML document fragment into the current DOM:
What does it do with < script > tags?
They are executed, though. But are nowhere to be found in the DOM. It seems jQuery inserts the script blocks just for a moment into the DOM or evals it.
There is no documentation this regard. Do you know any way to tune it, i.e. disable it?
This has implications of security in nature!
The <script> tags are stripped out of the code and explicitly executed after the DOM has been updated.
If you use "$.load()" with a URL that's got a selector in it (it's a hack-y feature of the API), like this:
$.load("http://something #stuff", ... )
then it will not run the scripts.
Related
I'm doing some experiments, and I found that when you execute that code on any web pages :
document.documentElement.innerHTML = document.documentElement.innerHTML;
Javascript scripts just get 'disabled'. So here is a little script I wrote that re-execute those scripts using jQuery ( so you'll need to inject jQuery on some websites ( I'm using Firebug + FireQuery )) :
// Disabling all javascript scripts
document.documentElement.innerHTML = document.documentElement.innerHTML;
// Saving scripts tags and his parent
var scripts = [];
jQuery('html').find('script').each(function(){
scripts.push([jQuery(this),jQuery(this).parent()]);
}).remove(); // REMOVING ALL SCRIPT TAGS
// Re-appending those deleted script tags in the right place
for (var i in scripts) {
scripts[i][1].append(scripts[i][0]);
}
So this script works on most of the website I tried, except one : Google ( in Firefox )
The thing I'm actually trying to do is storing Google HTML, and pasting it into an iframe ( via Firefox Extension ). So everything is working well except that I can't get the Javascript scripts working ( no autocomplete, buttons are not working... ). Here are the errors i get :
gapi.loaded_0 is not a function
window.google.pmc is undefined
I was thinking that, this may be due to an execution order issue or something. But how can I fix that. Is there any other way to re-run Javascript scripts ? Or any better way doing what I'm doing ?
Thank you !
Yes! There is a better way to do what you are doing.
First, what is happening:
When you use innerHTML the existing elements removed from the DOM. Not quite in a 'burn and salt the earth' because other references might survive, but they are off the DOM.
Fortunately, there is an easy way to deal with this:
This is a wonderful discussion of Event Delegation that describes what you need to do. It's worth reading to understand behind the scenes.
Once you have that, look at the jQuery's Event Delgation which does a bunch of work for you:
Since you didn't show any HTML, I'll invent some:
<div id="contents-will-be-replaced">
<button>Click me</button>
</div>
// Attach to the DIV
// But listen for buttons
$( "#contents-will-be-replaced" ).on( "click", "button", function() {
alert("Button pushed");
});
U can simply use Jquery's .html() to load a script dynamically in the dom. Basically, jquery will inspect your html when it added to the DOM and then create a script tag in the head automatically. It's pretty slick. See if it works for you.
From the docs:
By design, any jQuery constructor or method that accepts an HTML string — jQuery(), .append(), .after(), etc. — can potentially execute code. This can occur by injection of script tags or use of HTML attributes that execute code (for example, <img onload="">). Do not use these methods to insert strings obtained from untrusted sources such as URL query parameters, cookies, or form inputs. Doing so can introduce cross-site-scripting (XSS) vulnerabilities. Remove or escape any user input before adding content to the document.
I have a problem.
We are doing a Captive Portal.
Go to any site, for example www.php.net
Then in Chrome's console, use this:
$("html").load( "https://www.ccc.co.il/Suspend.aspx" );
You will notice, the DOM is replaced, but not quite the way it should be:
The wrapper elements of the loaded webpage (title, body for example) are missing!
This causes problems of course on the injected page.
How do I replace the entire initial DOM?
And please dont suggest to me using a link, or normal redirect.
Those are the restrictions, I need to replace the entire DOM tree please.
Thanks!
This is fundamentally a feature of browsers.
Here's a snip from the jQuery docs for .load():
jQuery uses the browser's .innerHTML property to parse the retrieved document and insert it into the current document. During this process, browsers often filter elements from the document such as <html>, <title>, or <head> elements. As a result, the elements retrieved by .load() may not be exactly the same as if the document were retrieved directly by the browser.
While I don't recommend what you're suggesting at all, I will attempt to answer your question:
Using a server-side language (like PHP, for example), return documents as parsed json:
{
"head": [head string],
"body": [body string]
}
Then your JavaScript can individually replace each element.
You'll need to switch from .load() to something more configurable, like .ajax()
I think you would have to use an iframe in this case as I don't think that you can replace an entire DOM with another.
$('body').html("<iframe height=100% width=100% frameBorder=0 src='https://www.ccc.co.il/Suspend.aspx'></iframe>");
http://jsfiddle.net/c7EbY/
$.get("https://www.ccc.co.il/Suspend.aspx", function(html){$("html").html(html)});
I'm using a regular AJAX function here because it shouldn't strip anything.
Sorry about those 4 htmls in a row. :P
I want to add a script that applies to a DOM object of a certain type right after it is loaded/rendered. This type of object always comes together with the javascript script, and I want to put them together within some tag. Is it right to do it as below? If so, I suspect span is not the best tag to be used here because it may interact with the way the element inside will be displayed. What tag should I use?
<span>
<div>the dom object to be modified by the script</div>
<script>theJavascriptFunctionThatModifiesTheDomObject()</script>
</span>
I doubt this is the best way to load your script just after a particular element has been loaded by DOM due to these reasons:-
It makes your page load slower.
User will see your complete page in a discrete way.
Instead you should do this:-
Specify a selector to your element.
Include your single javascript code at the end of body.
Update DOM elements using that script.
EDIT:
Solution1: Append your JS at the end of body so that it has access to all the DOM elements.
Since you are injecting the element in DOM using ajax, you can define a success handler for XHR object which will modify your element in DOM.
Solution2: You can define a separate method in your JS and bind this method on some event. In your HTML markup define a data-event attribute and in your success handler append the element to DOM, extract the data-event using jquery data method and trigger that event.
Atleast it will keep you markup far away from scripting logic.
Some useful Links:
Best practices for speeding up your website - yahoo
Why we should load scripts at end - SO Link
The problem here is the script tag does not know where it is located in the DOM. It would be better to do something like add a class to the element[s] you want to alter. On DOM ready, you look up the element[s] and do your magic.
I would avoid this approach; scripts block the page loading
– so if you did this after several dom elements the page would run slow (or not at all if errors were found)
Try using jquery onready - example here : http://api.jquery.com/ready/
And scripts [usually] need to go on the bottom of the page to allow the page to load first
…there are exceptions to this rule such as the well known modernizer script library that needs to go first so it can evaluate the dom as it loads
I have placed all my javascript calls inside jQuery.ready() to ensure the DOM is fully loaded before accessing them. But for function definitions (ones that I wrote myself), what's the best practice in placing them (before their corresponding called of course). At the beginning of <body>? Or at the end of <body>? Or inside jQuery.ready()? Or it simply doesn't matter? Thanks.
Do not place functions inside the ready() function.
You should declare them above the ready call and ideally all of your js is handled at the bottom of the html.
If you place your JavaScript in the head or top of the body, you will need to use jQuery ready IF they rely on some part of the DOM. As a shortcut, you can just pass your code to $, like so:
$(function(){
$("#domID").method();
});
However, you can forego this whole mess by putting your script at the bottom. The browser reads your HTML top to bottom. If the script that accesses domID, appears below the DOM element with id domID then it will work fine. So the above code snippet can be further simplified via:
$("domID").method();
As a note, this is not always the case. I have noticed you can not access canvas elements immediately. It may be safer to use $ or $.ready, then remove them as you become more comfortable with how the DOM and JavaScript are loaded.
I'm trying to dynamically insert the Tweetmeme button using Javascript. I'm currently using jQuery throughout the site. Here's the script that I'm using. I basically want to cycle through all the blog entries with a class of journal-entry and append the following JavaScript to the end. This Javascript comes straight from tweetmeme.com. This doesn't work for me though and it has something to do with the code between append(). It doesn't like the second set of script tags.
<script type="text/javascript">
$(document).ready(function() {
$('.journal-entry').each(function(index) {
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></script>');
});
});
</script>
Any help is appreciated.
Thanks.
Don't do this.
Inserting <script> HTML content into the DOM is unreliable: it works subtly differently in different browsers, and jQuery won't protect you from the differences.
In particularly, writing innerHTML never causes a <script> element's content to execute, but subsequently moving the <script> element from where it is to a new parent (which is part of jQuery's append process) may cause the script to execute, but not always (it depends on the browser).
In any case, it'll never work, because looking at button.js, it is calling document.write(). That function only makes sense to call at initial document parsing time; if you call it from an event afterwards, the call will simply replace the entire page content, destroying your existing page. A script that calls document.write() can only be run at document load time, from inside the execution path of a <script> element. You can't include the script in dynamically-created content at all, because it's not designed for it.
(If it makes you feel any better, it's barely designed at all; the button.js script is a badly broken load of old crap, including improper URL-escaping—using escape instead of the correct encodeURIComponent—and missing HTML-escaping. You may be better off well away from these total idiots.)
The closing </script> in the string in your append(...) call is closing the overall <script>
Try splitting it up into two strings. E.g:
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></'+'script>');