This:
function myFunction()
{
document.write("sup");
}
called in html like:
<div id="myDiv">
<script>myFunction();</script>
</div>t
adds a string sup to the myDiv div element. Which is what I want, exactly. However, this:
function loadFile(uri)
{
var r = new XMLHttpRequest();
document.write("trying to open: " + uri);
r.open('GET', uri, true);
r.send(null);
r.onreadystatechange = function()
{
if (r.readyState == 4)
{
myFunction();
}
}
}
function myFunction()
{
document.write("sup");
}
called like this:
<div id="myDiv">
<script>loadFile("filename.txt");</script>
</div>
seems to be overwriting my whole html file. I.e. when I run it in Firefox it shows me only the string sup (that's the whole content of the page) but the page seems to be still loading (the loading icon of FF is still there animating, apparently infinitely).
First of all, this is going to be used only locally, offline, as a fast and handy way of presenting data (using html+js and web browser instead of plain text file). What I want is to load a local text file and then put some of its content as a part of the html page. The same as in my first example but with loading the text file first.
The issue is that when you run document.write after the document has loaded, it overwrites the entire document. If it is run before that, it does not overwrite it.
What you want to do is set the innerHtml of a specific element, something like:
document.getElementById("myDiv").innerHTML="Sup";
Lets go over what a browser does when it receives an html file.
The window document is opened for writing. Imagine opening a text file.
Browser writes the contents to the document. A lot of magic happens in this step - objects get created and html rendered as boxes.
The window document closes the document. Kind of like saving the text file.
Now, modern browsers also expose a document API that allow you to do exactly those tasks using javascript.
You can open a document for writing using document.open(). You can also start writing content to the document using document.write(). Finally, you can close the document for writing using document.close(). Since the document always needs to be opened for writing before you write, calling document.write() always results in an implicit document.open().
Interspersing document.write() calls throughout an html body is a commonly used technique used to insert string contents dynamically into an html page.
For example, if you execute document.write("<p>holla</p>") in the body of an html file, the browser will do the following upon receiving the html file.
Open the document for writing.
Start writing the html contents to the document.
JavaScript engine will execute document.write() when it encounters it and then write "<p>holla</p>" into that specific line in the document, just as if the string was already part of the html file! Since document.write() is called during the parsing of an html file, it just gets parsed as part of the page.
Close the document for writing. Parsing complete.
If that's how you use document.write(), there would have been no surprise. Instead, you call document.write() after the html is parsed.
So what do you think should happen?
As I mentioned before, a document needs to be opened for writing before it is written to. In theory, we could either append to the existing content or just overwrite it. Well, if we append to the content, we'll end up with an invalid html page because the new values will appear after the closing tags. So the more sensible behavior is to overwrite the content and that's exactly what happens.
Related
I'm playing with inject JavaScript code into an existing DOM.
I've seen that if I put the script by hand in the browser's DOM elements inspector
<script>alert("XSS test");</script>
the script node is added to the DOM, but it has no effect. I mean, no alert box is shown.
On the other hand, if I put the script as plain text through the JavaScript console using document.write(), in this case the code got parsed and executed immediately, and the alert box is shown as expected.
document.write('<script>alert("XSS test");</script>');
I'm used to see that hand made changes to the DOM elements in the inspector reflects immediately in the page, while it seems that JavaScript nodes are an exception.
Why web browsers do not execute JavaScript nodes put by hand in the inspector?
Is there another way to send the script node to the DOM and make it run immediately?
script tags added via innerHTML and related methods (insertAdjacentHTML, etc.) are not executed. (The exact rules are somewhere in the script portion of the HTML specification but it's heavy going.) This may be because early on it was identified that poorly-written pages might use innerHTML and such to append user content, and so not executing it was a quick and simple way to avoid very, very basic XSS attacks. But only very, very basic ones.
You can add a script tag to the DOM and have it executed by creating and appending a script tag:
const script = document.createElement("script");
script.textContent = `console.log("Hi there");`;
document.body.appendChild(script);
You can do that from the console tab in devtools, for instance, rather than the DOM inspector tab.
try going to the web page you want and then in the URL bar at the top add
javascript:[your script]
for example
javascript:alert("Hello World!");
As the title says, if I remove a script tag from the DOM using:
$('#scriptid').remove();
Does the javascript itself remain in memory or is it cleaned?
Or... am I completely misunderstanding the way in which browsers treat javascript? Which is quite possible.
For those interested in my reason for asking see below:
I am moving some common javascript interactions from static script files into dynamically generated ones in PHP. Which are loaded on demand when a user requires them.
The reason for doing this is in order to move the logic serverside and and run a small script, returned from the server, clientside. Rather than have a large script which contains a huge amount of logic, clientside.
This is a similar approach to what facebook does...
Facebook talks frontend javascript
If we take a simple dialog for instance. Rather than generating the html in javascript, appending it to the dom, then using jqueryUI's dialog widget to load it, I am now doing the following.
Ajax request is made to dialog.php
Server generates html and javascript that is specific to this dialog then encodes them as JSON
JSON is returned to client.
HTML is appended to the <body> then once this is rendered, the javascript is also appended into the DOM.
The javascript is executed automatically upon insertion and the dynamic dialog opens up.
Doing this has reduced the amount of javasript on my page dramatically however I am concerned about clean up of the inserted javascript.
Obviously once the dialog has been closed it is removed from the DOM using jQuery:
$('#dialog').remove();
The javascript is appended with an ID and I also remove this from the DOM via the same method.
However, as stated above, does using jQuery's .remove() actually clean out the javascript from memory or does it simple remove the <script> element from the DOM?
If so, is there any way to clean this up?
No. Once a script is loaded, the objects and functions it defines are kept in memory. Removing a script element does not remove the objects it defines. This is in contrast to CSS files, where removing the element does remove the styles it defines. That's because the new styles can easily be reflowed. Can you imagine how hard it would be to work out what a script tag created and how to remove it?
EDIT: However, if you have a file that defines myFunction, then you add another script that redefines myFunction to something else, the new value will be kept. You can remove the old script tag if you want to keep the DOM clean, but that's all removing it does.
EDIT2: The only real way to "clean up" functions that I can think of is to have a JS file that basically calls delete window.myFunction for every possible object and function your other script files may define. For obvious reasons, this is a really bad idea.
If your scripts have already executed removing the DOM elements are not going to get rid of them. Go to any page with JavaScript, open up your preferred javascript console and type $("script").remove(). Everything keeps running.
And this demonstrates #Kolink answer:
http://jsfiddle.net/X2mk8/2/
HTML:
<div id="output"></div>
<script id="yourDynamicGeneratedScript">
function test(n) {
$output = $("#output")
$output.append("test " + n + "<br/>")
}
test(1);
</script>
Javascript:
$("script").remove();
// or $("#yourDynamicGeneratedScript").remove();
test(2);
test(3);
test(4);
function test(n) {
$output = $("#output")
$output.append("REDEFINED! " + n + "<br/>")
}
test(5);
test(6);
test(7);
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.
I am working on some code that uses jQuery to parse data out of html documents from the web. This decision was made because jQuery, with its awesome ability to select objects on a page, makes it excellent for parsing.
The code works like this (where 'html_string' is the html of a whole web page):
var page = $(html_string);
The problem I am having is that javascript is being evaluated and executed within the html_string as well. This results in new threads being formed that in some cases, contain infinite loops that make repeated requests to the server and eventually crash the whole client-side of application (not the server).
Is there a way to somehow prevent the execution of javascript in this situation. In this situation, the execution of javascript is an unwanted side effect.
Thanks so much!
Here is a crappy little jsfiddle that shows you the js does not run when you load the html_string into $. When you click run you will see an immediate alert 'wtf'. Three seconds later, the html is loaded into $ and the body is updated to say 'moo', you should not see the alert.
http://jsfiddle.net/9BAkE/
One way would be to parse the html string befor you wrap it with jQuery.
Something like:
var page = html_string;
//then find the script tag (untested code)
int beginning_of_script = page.indexOf('<script>');
int end_of_script = page.indexOf('</script>');
// remove the script
page = page.remove(beginning_of_script, end_of_script);
You could load this syntax into the browser initially as a comment
<script>
/* var page = $(html_string); */
</script>
and then extract the contents of the comment later. The advantage here is that the browser is not going to parse and execute the comment on page load.
You can also explore using jQuery's .load() function, not sure if that will suit your needs.
If you donot care having one extra element, check this! http://jsfiddle.net/UbCFc/4/
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>');