Serialize iframe content from head to toe with HTML special characters in Javascript
I am using an iframe as my html editor and I load its content by setting the iframe src attribute. Afterwards I include the iframe designMode
so I can edit the loaded html content.
Once the user is ready, he will click the save button and I will try to get the edited html content and send it to the server. I just need the full content of the iframe including <html>
and <!doctype>
. The problem I am facing is that when I fetch the content of the iframe its inline javascript code has encoded everything <
in <
even in the Javascript code!
This is how I wrote my code:
<!DOCTYPE html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<iframe src="about: blank"></iframe>
<button>Save to textarea</button>
<textarea></textarea>
<script>
$(document).ready(function() {
var $iframe = $("iframe");
var $iframeBody = $iframe.contents().find('body');
$iframeBody.html('<scr'+'ipt>var x = 1 < 2;</scr'+'ipt><>&');
$iframe.contents().prop('designMode','on');
$("button").click(function() {
var serializer = new XMLSerializer();
var html = serializer.serializeToString($iframe.contents()[0])
$("textarea").val(html);
});
});
</script>
</body>
</html>
Pressing the save button will display:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<script>var x = 1 < 2;</script><>&
</body>
</html>
As you can see, the result is unusable because I cannot tell what <
should be replaced with <
(unless the text is parsing) !!
Does anyone know how to completely restore the content of an iframe without destroying it?
source to share
First of all - you don't need to XMLSerializer
. You are trying to serialize html
as xml
. I think you need one html
. Therefore it is better to use $iframe.contents().get(0).documentElement.outerHTML
. This will return the whole html
iframe without doctype
. For doctype, you can use this function:
function getDoctypeString (doc) {
var doctypeNode = doc.doctype;
if (!doctypeNode) {
return '';
}
return "<!DOCTYPE "
+ doctypeNode.name
+ (doctypeNode.publicId ? ' PUBLIC "' + doctypeNode.publicId + '"' : '')
+ (!doctypeNode.publicId && doctypeNode.systemId ? ' SYSTEM' : '')
+ (doctypeNode.systemId ? ' "' + doctypeNode.systemId + '"' : '')
+ '>';
}
And all together :
<!DOCTYPE html>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<iframe src="about: blank"></iframe><br>
<button>Save to textarea</button><br>
<textarea cols=55 rows=10></textarea>
<script>
$(function() {
function getDoctypeString(doc) {
var doctypeNode = doc.doctype;
if (!doctypeNode) {
return '';
}
return "<!DOCTYPE " + doctypeNode.name + (doctypeNode.publicId ? ' PUBLIC "' + doctypeNode.publicId + '"' : '') + (!doctypeNode.publicId && doctypeNode.systemId ? ' SYSTEM' : '') + (doctypeNode.systemId ? ' "' + doctypeNode.systemId + '"' : '') + '>';
}
var $iframe = $("iframe");
var $iframeBody = $iframe.contents().find('body');
var $textarea = $("textarea");
$iframeBody.html('<scr' + 'ipt>var x = 1 < 2;</scr' + 'ipt><>&');
$iframe.contents().prop('designMode', 'on');
$("button").click(function() {
var iframeDocument = $iframe.contents().get(0);
$textarea.val(getDoctypeString(iframeDocument) + iframeDocument.documentElement.outerHTML);
});
});
</script>
</body>
</html>
source to share
You can get html iframe without character replacement using:
document.getElementById('iframe').contentDocument.documentElement.outerHTML;
This is where JSBIN works .
The reason why you cannot find the doctype of the iframe may be because the iframe does not have a doctype.
Adding a doctype to an iframe is optional according to the W3C .
I took a look at the iframe in Firefox v33 and Chrome v39 and it didn't have a doctype. Only the owner document had a doctype. Try it in your browser with this JSBIN .
Also, doctypes are used for legacy reasons and if you are worried about older browsers you can simply add the doctype tag to your html line:
var html = document.getElementById('iframe').contentDocument.documentElement.outerHTML;
html = '<!DOCTYPE html>' + html;
$("textarea").val(html);
source to share