document.write become invalid within Javascript file which is added by appendChild - javascript

when I add the script tag in body tag of my index.html directly, like below:
<script type="text/javascript" src='**doc_write_in_it.js**'></script>
It works well, the "test doc write" is output there.
But if I write in another way, like below:
<script type="text/javascript">
var model = document.createElement('script');
model.setAttribute('type','text/javascript');
model.setAttribute('src','doc_write_in_it.js');
var bd = document.getElementsByTagName('body')[0];
bd.appendChild(model);
</script>
document.write become invalid within Javascript file which is added by appendChild.
The alert in doc_write_in_it.js will show, but the text in document.write doesn't.
doc_write_in_it.js file is like this:
alert('activited');
document.write('test doc write");
Hope someone can help...
Thanks a lot...

as mentioned above, document.write does not work when the page has already been loaded.
I suggest use innerHTML property whenever you can.
example:
var bd = document.getElementsByTagName('body')[0];
bd.innerHTML = "some text";

document.write will overwrite anything else before it. So, if you are absolutely sure that it is what you want to be doing. Then you should probably wait for the page to load, and then fire the document.write. Something on the lines of the below..
<script>
function my_onload_fn() {
document.write("test document write");
}
</script>
<body onload="my_onload_fn();">

Actually, document.write can't affects when page is loaded, but you can invoke document.open() to make it posible.
Putting script code in script tag is synchronous, while loading script file via DOM manipulation is asynchronous, so,if the page is simple, page may have been loaded when document.write(..) runs and make document.write(...) do nothing if document.open() is not invoked.
alert('activited');
document.open();
document.write('test doc write');
document.close();
This will work.
And check this link to learn more.

Related

Dynamically generated script tag does not execute after it is appended to the head tag [duplicate]

I am trying to load a certain script after page load executes, something like this:
function downloadJSAtOnload(){
var element = document.createElement("script");
element.src = "scriptSrc";
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
And while this script seems to execute and download 'scriptSrc', and append it right before the end of the body tag, it yields the following message (not an error) in the console (chrome)
Failed to execute 'write' on 'Document': It isn't possible to write into a document from an asynchronously-loaded external script unless it is explicitly opened.
What does this even mean? And am I supposed to do something differently? Even though I get the expected behavior?
An asynchronously loaded script is likely going to run AFTER the document has been fully parsed and closed. Thus, you can't use document.write() from such a script (well technically you can, but it won't do what you want).
You will need to replace any document.write() statements in that script with explicit DOM manipulations by creating the DOM elements and then inserting them into a particular parent with .appendChild() or .insertBefore() or setting .innerHTML or some mechanism for direct DOM manipulation like that.
For example, instead of this type of code in an inline script:
<div id="container">
<script>
document.write('<span style="color:red;">Hello</span>');
</script>
</div>
You would use this to replace the inline script above in a dynamically loaded script:
var container = document.getElementById("container");
var content = document.createElement("span");
content.style.color = "red";
content.innerHTML = "Hello";
container.appendChild(content);
Or, if there was no other content in the container that you needed to just append to, you could simply do this:
var container = document.getElementById("container");
container.innerHTML = '<span style="color:red;">Hello</span>';
A bit late to the party, but Krux has created a script for this, called Postscribe. We were able to use this to get past this issue.
In case this is useful to anyone I had this same issue. I was bringing in a footer into a web page via jQuery. Inside that footer were some Google scripts for ads and retargeting. I had to move those scripts from the footer and place them directly in the page and that eliminated the notice.
You can also call
document.open() before document.write()
call
document.close()
when you're done.
It may not be best practice for a real webpage but for testing etc.. can be used.

How to use a function in the src tag of an Javascript script

I have some HTML code and there somewhere I want to display a video with Javascript. I have a function that gives me a valid link to the video player and source. So if I post it directly without function in src it works fine.
So my question is how can I use my function in the src tag?
<script type="text/javascript" src="get_link()"</script>
A solution without jQuery/document.* is wanted if possible. I know I could do something like that document.getElementById("iframeid").setAttribute("src","link").
Edit
All of the solutions were not working in my case. But anyways it's not a solution for me to do it in Javascript because of security issues. And there is no way to use nodejs. So thanks for your comments anyway. =)
Try adding script in JavaScript like this:
var script = document.createElement('script');
script.setAttribute('src', get_link());
var head = document.getElementsByTagName('head')[0];
head.appendChild(script);
If you want to set this attribute through JavaScript, you can't do so by directly putting it in the src attribute. You can attach some event handler on the HTML, such as onclick="handler()", or something of that sort, which when triggered will give you access to the element within the function. Something like this.
function handler() {
this.src= 'my_link.js
}
EDIT:
Not that the above solution is ideal, but just to meet the criteria of the question. It is possible, without any use of document to do this.
On your script tag, set an onerror="change_link()". Then define an
function change_link() {
this.src= get_link();
}
And last, you should add a faulty src attribute to the script tag. Again, this is stupid and you shouldn't do it in production code, but I'm just showing you that it's possible.

Intercepting script load

What I need is to hook/intercept other external JS load.
I can place js anywhere in document
Example:
<script src="hook.js"></script>
<script src="a.js"></script>
<script src="b.js"></script>
Hook.js should intercept a.js and b.js. Problem is, that when hook.js is executed, i cannot see other scripts (document.scripts contains only hook.js) and document ready event is too late (scripts a.js and b.js are executed).
Is there any way to "see" other script tags, before are executed ?
Thanks for any help
Edit
I need to do any "magic" inside hook.js without modyfing (statically) other HTML.
No jQuery
Credit goes here: https://stackoverflow.com/a/59424277/2016831
You can use a MutationObserver to see what elements are being added to the DOM, and when they are being added, simply change the source code, or if its referencing another URL, just redirect it to your own server, with the original URL as a get parameter instead, and return the modified code that way.
Based on the above answer, you could do something like this:
<script>
new MutationObserver((m, o) => {
let potentialScript = document.querySelector("script + script");
console.log(potentialScript.textContent);
if(potentialScript) {
o.disconnect();
potentialScript
.textContent =
potentialScript
.textContent
.replace(
"})()",
`
window.wow = mySecretMethod;
})()
`
);
}
}).observe(
document.body,
{
childList:1
}
);
</script>
<script>
(function() {
let mySecretMethod = () => {
//does a bunch of evil secret stuff
console.log("HA!");
};
})();
wow()
</script>
<script>
console.log(wow())
</script>
Alternatively you can redirect the HTTP requests with a chrome extension, see https://stackoverflow.com/a/61202516/2016831 for more
If I understand what you're trying to do correctly...
If you can control how scripts A and B are loaded, the best approach is to place them on the same domain as the current page (possibly via proxy), load the files via AJAX, and insert your hooks that way. A library like jQuery as m.casey suggested would make the details of the AJAX and executing the script quite simple.
Otherwise, Javascript does not really have the ability to interact with the parsing of the document (which is what is causing scripts a and b to be loaded in your example, and what would be need to be modified to "intercept" script loading), except by using the evil of document.write to modify the HTML stream. Of course, this only works if hook.js is loaded synchronously (as it is in your example code), if it's loaded into HTML and not XHTML, if you can place a second hook afterwards to postprocess the modified HTML stream, and if you are sure the HTML stream won't escape your mechanism.
For example..
<script id="hook1">document.write("<"+"textarea id='capture'>");</script>
<script src="a.js"></script>
<script src="b.js"></script>
<script id="hook2">document.write("<"+"/textarea");</script>
<script id="hook3">doSomethingWith(document.getElementById("capture").value)</script>
Note that this is a huge hack and you probably shouldn't be doing it.
If you're using jQuery, you could have hook.js load the scripts you wish to intercept as follows:
$.getScript("a.js");
$.getScript("b.js");
This would dynamically create the script tags and you would be certain that hook.js would always proceed a.js and b.js.

Javascript adding <script> tag after page loads

Got a little problem here. Basically, I'm trying to add a script tag after the page loads.
This is what I am doing:
index.php:
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
function getad()
{
$.post('assets/getad.php', "ad", function(response) {
response = response.replace('document.write','document.getElementById("ad").innerHTML = ');
eval(response);
console.log(response);
});
}
getad();
</script>
<div id="ad"></div>
</body>
</html>
getad.php:
<?php
echo file_get_contents("http://ads1.qadabra.com/t?id=a823aca3-9e3c-4ddd-a0cc-14b497cad85b&size=300x250");
?>
You can find a demo here: http://dev.cj.gy/game/
As you can see, the #ad div DOES get filled with the correct script tag, but it doesnt actually run, If I edit the page to include the script tag right at page load, it does run.
Yes, <script> tags cause execution when parsed as part of the main document; they don't execute from being written to innerHTML.
You can create an executing script element outside of that initial parse using the DOM method of calling createElement('script'), setting its src/content and adding it to the document. This is what jQuery's getScript does.
However it wouldn't do you much good because the next script, that ads1.qadabra.com is document.writeing to the page, also itself calls document.write.
You could work your way around both of these calls at the client side (ie without getad.php), by assigning your own custom function to document.write that, instead of writing to the loading page, attempts to extract the source of the script tag passed to it, and load that in a DOM-created script element.
But in general these are scripts designed to work synchronously at document load time; anything you do to try to force them to run in a way they weren't intended to is likely to be fragile and stop working when the ad network change anything.
If you want to load a third-party ad without pausing the loading of the parent document, I suggest putting it in an iframe.

Can someone explain to me how this is possible? (Picture in comments)

So I'm trying to link up my html and javascript files in notepad++, but it isn't working properly.
I wanted to know how it is possible that it writes test, but doesn't remove the div. Can anyone explain this? Thanks in advance!
1, jQuery isn't linked. Meaning, you don't have <script type='text/javascript' src='myjQueryfile.js'></script> in your HTML, you'll want to put it before your script.
2:
Because the element with the ID of blue, doesn't exist yet. The DOM - basically the object of your HTML - has yet to be constructed when your script is run, which in this case is the top of the page, before blue comes into existence. You'll want to use an event to fix this, typically $(function(){ ... }); which will execute your code when the DOM is ready.
Also, document.write just writes code then and there, meaning exactly where the document.write calls is made, the HTML will be outputted.
You should have linked jquery. You're trying to use it without having it linked.
The script is loaded in the head. At the time the script executes the body of the document is not built, so nothing is removed. If you were to use the document.ready callback (and had properly included jQuery) it would work
$(function(){ $("#blue").remove(); });
A plain js version of this is
window.onload = function(){
var b = document.getElementById("blue");
b.parentNode.remove(b);
};
At the time the script runs, only the portion of the document up to the <script> tag has been loaded. You need to delay until the DOM has fully loaded before the script can target the DOM:
document.addEventListener("DOMContentLoaded", function(event) {
$("#blue").remove();
});

Categories