Using document.implementation.createDocument to create a new HTML document - javascript

I am being passed html as a string. My goal is to create a new document from the html that has all the appropriate nodes so that I can do things like call doc.getElementsByTagName on the doc I create and have it work as expected. An example of my code is here.
var doc = window.document.implementation.createDocument
('http://www.w3.org/1999/xhtml', 'html', null);
doc.getElementsByTagName('html')[0].innerHTML =
'<head><script>somejs</script>' +
'<script>var x = 5; var y = 2; var foo = x + y;</script>' +
'</head><body></body>';
var scripts = doc.getElementsByTagName('script');
console.log(scripts[0] + " code = " + scripts[0].innerHTML);
I am having the following issues:
If something inside a script tag contains a character like < (eg in the example above in the "var foo = x + y;" statement change the + to a < symbol), I get an INVALID_STATE_ERR: DOM Exception 11.
Even if nothing inside the script tag uses such characters, when I run the above I get the output "[object Element] code =undefined"
So my questions are:
A. How do I handle characters such as < that give DOM Exception 11 when I try to use them in whatever I am setting the innerHTML to
B. How do I make the document properly parse the script tags and put their code into their innerHTML attribute so that I can later read it.
EDIT: As Ryan P pointed out this code actually works in FF. So if anyone could help me get it working in chrome that would be much appreciated!

Taken from https://github.com/rails/turbolinks,
why dont you try to create the document this way:
doc = document.implementation.createHTMLDocument("");
doc.open("replace");
doc.write(html);
doc.close();
where the html should be your html contents.
I havent tested it and dont know if you should escape characters first.

A. You need to convert any < to an HTML entity (<). The rules don't cease to apply just cause you're in a script tag.
B. You call your variable 'doc' but try to get the script tags from an undefined variable 'tempDoc'. When I run your code in my browser after changing that variable, it all seems to work fine.

Related

what's the difference between appending a child element and setting innerHTML

In the first example, the script was executed, but not in the second example, the Dom results are the same.
// executable
var c = 'alert("append a div in which there is a script element")';
var div = document.createElement('div');
var script_2 = document.createElement('script');
script_2.textContent = c;
div.appendChild(script_2);
document.body.appendChild(div);
// unexecutable although the dom result is same as above case
var d = '<script>alert("append a div that has script tag as innerHTML")';
var div_d = document.createElement('div');
div_d.innerHTML = d;
document.body.appendChild(div_d);
.innerHTML allows you to add as much HTML as you want in one easy call.
.appendChild allows you to add a single element (Or multiple elements if you append a DocumentFragment).
If you use .innerHTML then you need to include the opening and closing tags correctly. Your HTML must be proper.
When elements that were created using document.createElement then auto generate the appropriate opening and closing tags.
Your example for .innerHTML is not properly formed. Instead of:
var d = '<script>alert("append a div that has script tag as innerHTML")';
it should be:
var d = '<script>alert("append a div that has script tag as innerHTML")</script>';
UPDATE:
Interesting!!
I know that, in the past, your second example would have worked. But it seems that, probably for security reasons, the browser no longer allows you to insert <script> through .innerHTML.
I tried on Chrome 62 and it fails. Firefox 57 fails and Safari 11.0.2 fails.
My best guess is that this is a security update.
Look here:
https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML
And go down to the Security considerations section.
It reads:
It is not uncommon to see innerHTML used to insert text in a web page. This comes with a security risk.
const name = "John";
// assuming 'el' is an HTML DOM element
el.innerHTML = name; // harmless in this case
// ...
name = "<script>alert('I am John in an annoying alert!')</script>";
el.innerHTML = name; // harmless in this case
Although this may look like a cross-site scripting attack, the result is harmless. HTML5 specifies that a tag inserted via innerHTML should not execute.

Javascript: match using dom loaded page

I am trying to grab all links from google search result using Chrome console.
First I wanted to get the dom loaded source. I tried below code.
var source = document.documentElement.innerHTML;
Now when I type source in console source it shows the correct dom loaded source. But if I run alert(source); It's showing default html source of page.
So problem is when I run below code
source.match(/class="r"><a href="(.*?)"/);
It is returning null, because variable source has the source code before dom loaded.
You can use DOM API (i.e. getElementsByTagName) to find all a tags in a page. Take a look:
var anchors = document.getElementsByTagName('A');
var matchingHrefs = Array.prototype.slice.call(anchors).filter(function(a) {
return a.className == 'r';
}).map(function(a) {
return a.href;
});
A
B
C
The Array.prototype.slice.call call turns node list into regular array.
Probably, you need to add /g flag to your regex to match globally.
Like this:
yourHtml.match(/href="([^"]*")/g)

jquery replace the content of a div persistently

I am trying to replace the content of a div tag with a certain value every 50sec via polling and jQuery. And I would like to access the value of that updated div, so I can save a request to the backend.
My problem is that once the content has been replaced, the browser displays it correctly, however the HTML stays the same as the beginning. I'm afraid this is a rather basic question, but I'm really curious about this.
Here I prepared an example to illustrate the issue: http://jsfiddle.net/LJgN6/7/
And you can see it out ot JSfiddle's context to check the final HTML here: http://jsfiddle.net/LJgN6/7/show
I would like to achieve a way to have in the final HTML(i.e. right click, view page source):
num 1.1 replaced with num 1.2
num 2.1 replaced with num 2.2
...
The code that you see in the View Source window is the HTML that was sent to the browser before anything client side was allowed to modify the DOM. If you want to see the source as it is modified by your javascript, you need to inspect the DOM (IE F12, Firebug, etc.)
If you need to access this value that was inserted earlier, using javascript to access the contents of your element (ie. $('#number-2').text()) should return its contents as they are currently in the DOM.
EDIT: Corrected typo
It looks like you're already familiar with jQuery so I would go ahead and head over to the extremely helpful API and take a look at AJAX calls. There is plenty of documentation there that will help you.
http://api.jquery.com/jQuery.ajax/
Here's an idea. Take a look at my fiddle of your problem
$(document).ready(function(){
$('#number-1').html("num " + 1.1);
$('#number-2').html("num " + 2.2);
$('#number-3').html("num " + 3.3);
$('#number-4').html("num " + 4.4);
setInterval(function(){newInfo();}, 3000);
});
function newInfo(){
var firstDiv = $('#number-1');
var secDiv = $('#number-2');
var thdDiv = $('#number-3');
var frthDiv = $('#number-4');
var firstDivInfo = firstDiv.text().substr(4);
var secDivNewInfo = firstDiv.text().substr(4);
var thdDivNewInfo = secDiv.text().substr(4);
var frthDivNewInfo = thdDiv.text().substr(4);
var newNumber = (Math.random() + 1).toFixed(1);
secDiv.html("num " + secDivNewInfo);
thdDiv.html("num " + thdDivNewInfo);
frthDiv.html("num " + frthDivNewInfo);
firstDiv.html("num " + newNumber);
}

How do I display the value of a jQuery variable for testing?

I am working on a slider that uses jQuery. Some elements of the slider are working correctly, but there is a problem that I am trying to troubleshoot with some of the code. To test it I would like to be able to display the values of the variables in the statement.
Here is the code block I am working with:
$('.marquee_nav a.marquee_nav_item').click(function(){
$('.marquee_nav a.marquee_nav_item').removeClass('selected');
$(this).addClass('selected');
var navClicked = $(this).index();
var marqueeWidth = $('.marquee_container').width();
var distanceToMove = marqueeWidth * (-1);
var newPhotoPosition = (navClicked * distanceToMove) + 'px';
var newCaption = $('.marquee_panel_caption').get(navClicked);
$(' .marquee_photos').animate({left: newPhotoPosition}, 1000);
});
I added a div called 'test' where I would like to display the values of the variables to make sure they are returning expected results:
<div class="test"><p>The value is: <span></span></p></div>
For example, to test the values, I inserted this into the statement above:
$('.test span').append(marqueeWidth);
However, I don't get any results. What is the correct way to include a test inside that code block to make sure I am getting the expected results?
Thanks.
Just use JavaScript's console functions to log your variables within your browser's console.
var myVar = 123;
console.log(myVar, "Hello, world!");
If you're unsure how to open the console within your browser, see: https://webmasters.stackexchange.com/questions/8525/how-to-open-the-javascript-console-in-different-browsers
append is used to append either an HTML string, a DOM element, an array of DOM elements, or a jQuery element. Since you are just trying to show a number (marqueeWidth), you probably want to set the text of the span instead:
$('.test span').text(marqueeWidth);
Also, is there a particular reason why you don't just use the console? It may be worth reading over a Debugging JavaScript walkthrough.
you can use the following.
$('.test span').html(marqueeWidth);
However doing a console.log(yourvariable); or alert(yourvariable); is better.

Using .append() in if statments?

I am trying to use .append() with if statements, I have a lot of them maybe 10. What I'm trying to do is add to a div if something happens. if A is less then 5 I want to add to the div, so on and so on. .append() works good for me if I put all of the things I want to add in one .append(). But if I try to do it separately it will not work for me. I don't know what I will be adding a head of time, it depends on user data so I can't add everything I want in one .append(). My code is long so I have put a fiddle below. I know i may have other issues with this code but, just asking about .append() or a way to add to my div like i want
if(k3a<5) {
msg3="need to work on q3"
var c = $('<p>'+msg3+'</p>')
$('#output1').append(c);
$output1.text(msg3);
}
if(k4a<5) {
msg4="need to work on q4"
var e = $('<p>'+msg4+'</p>')
$('#output1').append(e);
$output1.text(msg4);
}
if(k5a<5) {
msg5="need to work on q5"
var e = $('<p>'+msg5+'</p>')
$('#output1').append(e);
$output1.text(msg5);
}
I know I can do something like below, but I need to add them one by one if the condition is meet, not at once.
if (k1 < 10) {
msg1 = "This will not space like a want.<br/>";
msg2 = "I don know why not.<br/>";
msg3 = "How come.<br/>";
var e = $('<p>'+msg1+'</p>'+'<p>'+msg2+'</p>'+'<p>'+msg3+'</p>');
$('#output1').append(e);
}
http://jsfiddle.net/G24aQ/21/
This looks like you don't understand what the code is doing; (assuming $output1 is $('#output1)) current code is (just one part)
msg4="need to work on q4"; // set global variable `msg4`
var e = $('<p>'+msg4+'</p>'); // set local variable `e`
$('#output1').append(e); // append html to element
$output1.text(msg4); // re-set content of element as text
You most likely want just
var msg4="need to work on q4", // set local variable `msg4`
e = $('<p>'+msg4+'</p>'); // set local variable `e`
$('#output1').append(e); // append html to element
What is $output1? That should be a variable, but you don't assign anything to it. Also, there is no need to use $() to put HTML into just for the sake of assigning it to your c or e variable. $() gets content. You just need to make a String, like:
var c = '<p>'+msg3+'</p>';
although I would have var e, c above all your code, if I was going to reuse it, so you don't have to rewrite var, and I wouldn't store msg3 in a variable at all. My code would contain, something like:
var out1 = $('#output1');
if(k3a<5)out1.append('<p>need to work on q3</p>');
if(k4a<5)out1.append('<p>need to work on q4</p>');
if(k5a<5)out1.append('<p>need to work on q5</p>');
Your code is different on you jsFiddle page. For instance, k3a does not exist. Don't redefine var total in your code, either. There may be more problems with your code, but this should put you on the right path.
you may find it easier to define a small function to output the messages. something like
function showMessage( strMsg, targetID ) {
$('#'+targetID).empty().append("<p>" + strMsg + "</p>");
}
and call it using
showMessage( "message one", "output" );
showMessage( "message two", "output1" );
This way when you decide you want to display them in another fashion, you only have to change it in one place.

Categories

Resources