jQuery: How to replace the whole DOM with another HTML using .load - javascript

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

Related

Non-invasive Javascript HTML injection

I'm looking for a non-invasive javascript HTML/CSS/JS injection into page.
I'm ideally looking to use document.write, but keep the original contents that were on the page. So doing the following:
javascript:document.write("blablabla"); - this removes all the content on page, I don't want to use innerHTML += to append the data.
Any suggestions?
If document.write is called after the onload event for the document it needs to re-open the document - effectively truncating it. While you can explicitly call document.write() inline (either with javascript directly embedded in the page or with a tag which does not use defer/async) this is considered bad practice as it blocks all the other processing of the page.
You can inject elements by constructing them in Javascript personally I prefer to set the innerHTML of an existing placeholder to an HTML fragment:
<div id='placeholder/></div>
...
document.getElementById('placeholder').innerHTML="<h2>hello world!</h2>";
(using createElement becomes messy and slow when creating/injecting complex HTML)
document.write will always overwrite the whole page as far I know. One option is to append/prepend your code to a div or to the bottom of your body.
$(elementObj).append(contents);
//or
$(elementObj).prepend(contents);
You can createElement() then use one of the methods above to inject your code into the newly created element.

Executing Javascript scripts after pasting HTML code

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.

Adding a script to a DOM object

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

When should one use .innerHTML and when document.write in JavaScript

Is there a general rule, when one should use document.write to change the website content and when to use .innerHTML?
So far my rules were:
1) Use document.write when adding new content
2) Use .innerHTML when changing existing content
But I got confused, since someone told me that on the one hand .innerHTML is a strange Microsoft standard, but on the other hand I read that document.write is not allowed in XHTML.
Which structures should I use to manipulate my source code with JavaScript?
innerHTML can be used to change the contents of the DOM by string munging. So if you wanted to add a paragraph with some text at the end of a selected element you could so something like
document.getElementById( 'some-id' ).innerHTML += '<p>here is some text</p>'
Though I'd suggest using as much DOM manipulation specific API as possible (e.g. document.createElement, document.createDocumentFragment, <element>.appendChild, etc.). But that's just my preference.
The only time I've seen applicable use of document.write is in the HTML5 Boilerplate (look at how it checks if jQuery was loaded properly). Other than that, I would stay away from it.
innerHTML and document.write are not really comparable methods to dynamically change/insert content, since their usage is different and for different purposes.
document.write should be tied to specific use cases. When a page has been loaded and the DOM is ready you cannot use that method anymore. That's why is generally most used in conditional statements in which you can use it to syncronously load external javascript file (javascript libraries), including <script> blocks (e.g. when you load jQuery from the CDN in HTML5 Boilerplate).
What you read about this method and XHTML is true when the page is served along with the application/xhtml+xml mime type: From w3.org
document.write (like document.writeln) does not work in XHTML documents (you'll get a "Operation is not supported" (NS_ERROR_DOM_NOT_SUPPORTED_ERR) error on the error console). This is the case if opening a local file with a .xhtml file extension or for any document served with an application/xhtml+xml MIME type
Another difference between these approaches is related on insertion node: when you use .innerHTML method you can choose where to append the content, while using document.write the insertion node is always the part of document in which this method was used.
1) document.write() puts the contents directly to the browser where the user can see it.
this method writes HTML expressions or JavaScript code to a document.
The below example will just print ‘Hello World’ into the document
<html>
<body>
<script>
document.write("Hello World!");
</script>
</body>
</html>
2) document.innerHTML changes the inner content of an element
It changes the existing content of an element
The below code will change the content of p tag
<html>
<body>
<p id="test" onclick="myFun()">Click me to change my HTML content or my inner HTML</p>
<script>
function myFun() {
document.getElementById("test").innerHTML = "I'm replaced by exiesting element";
}
</script>
</body>
</html>
you could use document.write() without any connected HTML, but if you already have HTML that you want to change, then document.innerHTML would be the obvious choice.
I agree with the above comments. Basically:
document.write can be useful while the page is loading, to output new HTML tags or content while the browser is building the document object model. That content is output precisely where the JavaScript statement is embedded.
.innerHTML is useful at any time to insert new HTML tags/content as a string, and can be more easily directed to specific elements in the DOM regardless of when/where the JavaScript is run.
A couple of additional notes...
When document.write is called from a script outside of the body element, its output will be appended to the body element if called while the page is loading; but once the page is loaded, that same document.write will overwrite the entire document object model, effectively erasing your page. It all depends on the timing of document.write with the page load.
If you are using document.write to append new content to the end of the body element, you may be better off using this:
document.body.innerHTML += "A string of new content!";
It's a bit safer.

Possible to create custom "DOMs" by loading HTML from string in Javascript?

I'm trying to parse HTML in the browser. The browser receives 2 HTML files as strings, eg. HTML1 and HTML2.
I now need to parse these "documents" just as one would parse the current document. This is why I was wondering if it is possible to create custom documents based on these HTML strings (these strings are provided by the server or user).
So that for example the following would be valid:
$(html1Document).$("#someDivID")...
If anything is unclear, please ask me to clarify more.
Thanks.
var $docFragment = $(htmlString);
$docFragment.find("a"); // all anchors in the HMTL string
Note that this ignores any document structure tags (<html>, <head> and <body>), but any contained tags will be available.
With jQuery you can do this:
$(your_document_string).someParsingMethod().another();
You can always append your html to some hidden div (though innerHTML or jQuery .html(..)). It won't be treated exactly as a new document, but still will be able to search its contents.
It has a few side-effects, though. For example, if your html defines any script tags, they'll be loaded. Also, browser may (and probably will) remove html, body and similar tags.
edit
If you specifically need title and similar tags, you may try iframe loading content from your server.

Categories