Determine when a script called from another script is loaded - javascript

I have a script, let's call it Script A. When Script A loads, it injects another script into the head of the document, Script B. Script B is where most of the important code lives.
When Script A is added to the host document it looks something like this:
<script async src="http//script-a.js" onload="doSomething();"></script>
In the doSomething function, I would like to trigger something from Script B. Unfortunately, it hasn't loaded yet, so an error occurs.
I'm trying to figure out a way to do this that keeps the document in which Script A is embedded as simple as possible. How can I do this?

You could use something like this and replace the url in the script for your "Script B."
document.getElementById("demo").src = "https://my-random-script.glitch.me/script.js" // put your "Script B" here
<h1>Hello World</h1>
<h2>Try to find a Hi! Alert Box</h2>
<script id="demo"></script>
The one where it calls something from external scripts
document.getElementById("demo").src = "https://my-random-script.glitch.me/scriptb.js"
var b = "Hi!"
document.getElementById("text").innerHTML = b;
alert("Hi")
function AlertAgain() {
alert("hi") // you can't use this, because the other site is blocking all scripts once all of the alerts are over! (you also can look at the site's js)
}
<h1 id="text">Of course, load your scripts!</h1>
<script id="demo"></script>
<button onclick="AlertAgain()">Click to say hi again</button>
Demo without script that removes all scripts
var b = "Hi!"
document.getElementById("text").innerHTML = b;
alert("Hi")
function AlertAgain() {
alert("hi")
}
<h1 id="text">Of course, load your scripts!</h1>
<script id="demo"></script>
<button onclick="AlertAgain()">Click to say hi again</button>
You can also have two different scripts on your HTML page.

Related

Conditionally call a script tag from a JavaScript function?

I'm using Angular and need to call a third party script from a function inside another script tag.
For example:
In the index.html
let showOnHomePage = () => {
if (window.location.href === 'http://localhost:4100/') {
** I'm trying to run the scripts below conditionally. If taken out of the function the below scripts work. **
<script> var _ctct_m = "my_numberic_key would go here"; </script>
<script id="newScript" src="https://thewebsite.min.js" async defer></script>
}
}
showOnHomePage();
</script>```
You can create elements from code, including script tags:
function log(){console.log(stuff);}
function script(){
let s=document.createElement("script");
s.innerText="let stuff=10;";
document.body.appendChild(s);
}
<button onclick="log()">Log</button><br>
<button onclick="script()">Script</button>
(try pressing Log, see error message, then Script and Log again)
The same should work with non-local source too, like
let s=document.createElement("script");
s.id="newScript";
s.src="https://thewebsite.min.js";
s.async=true;
s.defer=true;
document.body.appendChild(s);

How to execute a script on click

I'm trying to create a cookie only when a visitor clicks on the Accept button, but can't make the script execute on click. Here is my code:
function myFunction(){
var scripts = document.getElementsByTagName("script");
for (s of scripts) {
if (s.type == "text/plain") {
s.setAttribute('type', 'text/javascript');
eval(s);
}
}
}
<head>
# Some other scripts and title
<script type="text/plain">
document.cookie = "username=John Doe";
alert();
</script>
</head>
<body>
<button href="javascript:void(0);" onclick="myFunction();">
Accept
</button>
</body>
When I click on the button, I can see that the type of the script is changed from text/plain to text/javascript, but I didn't manage to execute the script after this, even with eval() (after inspecting the application's cookies, the new cookie is not created so I assume it was not executed).
I saw some other solutions on StackOverflow but they involved putting the content of the script I want to be executed in myFunction() and I don't want to do that (if possible).
Thanks for your help.
var scripts = document.getElementsByTagName("script");
for (s of scripts) {
if (s.type == "text/plain") {
//s.setAttribute('type', 'text/javascript');
eval(s);
}
}
eval(s) does not make sense here, s does not contain JavaScript code in text form, it is a reference to the DOM element.
eval(s.innerText) would eval the content of your script element.
(And you don’t need to modify its type then either, because the script element itself is not involved in the execution any more, it just provides the “data”.)

Chrome Extensions: Pass data from popup to another script file before the script is injected

Problem
Let's assume I go to a website called RENT.com. Let's also assume for this chrome extension there is a script A (JS) that is injected to RENT.com. Script A is a large script file that does a lot of interacting with RENT.com's HTML elements such as form fields. Before the script runs however, it needs some DOM ID's of a couple elements such as the email field because it modifies them.
Objective
I'd like to create a couple input fields (let's call them InputEmail and InputName) in popup.html to enter in the ID's of the elements on RENT.com. Obviously I'd be looking up the ID's manually by viewing the source, this is intentional.
A button in popup.html let's call it "GO BUTTON" will then read the value of InputEmail and InputName and send it to Script A. Script A now has everything it needs to function properly and is now injected into the page.
The appropriate interactions from Script A and RENT.com are now completed.
I've tried a few things, read a ton of information from Docs and Stack but I don't understand I think fundamentally how this can work. I want to pass data to Script A via popup.js before I execute content_script which ultimately is just injecting Script A. Seems like a chicken/egg problem and I'm not hungry for breakfast or lunch ;).
Thanks guys!
popup.html
<!doctype html>
<html>
<head>
<title>Getting Started Extension's Popup</title>
</head>
<body>
<ul>
<li><label>Email ID</label><input type="text" id="emailID"></input></li>
<li><label>Company ID</label><input type="text" id="nameID"></input></li>
</ul>
<input type="button" id="Modify" style="" value="GO BUTTON"></input>
<script src="popup.js"></script>
</body>
</html>
Popup.js
function click(e) {
//Ideally pass these values to Script A somehow
var email = document.getElementById("emailID").value;
var company = document.getElementById("nameID").value;
//then execute this or pass the ID's to content_script, inject into Script A, then inject into page
chrome.tabs.executeScript(null, {file:"contentscript.js"});
window.close();
}
document.addEventListener('DOMContentLoaded', function () {
var d = document.getElementById("Modify");
d.addEventListener('click',click);
});
ContentScript to inject Script A
var s2 = document.createElement('script');
s2.src =chrome.extension.getURL("ScriptA.js");
s2.async = false;
s2.onload = function() {
s2.parentNode.removeChild(s2);
};
(document.head||document.documentElement).appendChild(s2);
There are several ways to accomplish this. One would be:
function click(e) {
var elementIDs = {
email: document.getElementById("emailID").value,
company: document.getElementById("nameID").value
};
chrome.tabs.executeScript({
code: 'window.elementIDs='+JSON.stringify(elementIDs)
}, function() {
chrome.tabs.executeScript({file: "ScriptA.js"});
});
window.close();
}
This way, ScriptA will be able to access the values in window.elementIDs. This will work because content scripts from the same extension on the same page will share the execution environment, and the chaining of the calls to chrome.tabs.executeScript ensures that the script defining the global variable has run before ScriptA is run.

How to call external JavaScript function in HTML

I have a small chunk of code I can't seem to get working. I am building a website and using JavaScript for the first time. I have my JavaScript code in an external file 'Marq_Msg.js' which looks like this:
var Messages = new Array();
Messages[0] = "This is message 1";
Messages[1] = "This is message 2";
Messages[2] = "This is message 3";
Messages[3] = "This is message 4";
function scroll_messages()
{
for (var i = 0; i < Messages.length; i++)
document.write(Message[i]);
}
and in my HTML file 'Index.html' I am trying to call it like this:
<div id="logo">
<marquee scrollamount="5" direction="left" loop="true" height="100%" width="100%">
<strong><font color="white"><script src="Marq_Msg.js">scroll_messages()</script></font></strong>
</marquee>
</div>
The 'logo' div is a CSS piece that I'm trying to marquee inside of. If I put the code embedded inside the 'head' tag and call it, it works perfectly! There are a few other things id like to do with this code (like space the messages out a little) but I can't get the code to work in the first place. I've also tried adding:
<script src="Marq_Msg.js"></script>
in the 'head' tag with a separate call, that was a no go. I also tried instead using:
<script type="text/javascript" src="Marq_Msg.js">scroll_messages()</script>
Hell, i even had the function try returning a string (even hardcoded a simple "hello" to be returned) but that didnt work either with and without the 'type':
//Marq_Msg.js
function scroll_messages()
{
return "hello";
}
//index.html
<script type="text/javascript" src="Marq_Msg.js">document.write(scroll_messages())</script>
What am I missing? Any help would be greatly appreciated!! I've looked all over Google, and every site I find wants to do it using some 'form'. I just want messages to be displayed across, no form attached.
If a <script> has a src then the text content of the element will be not be executed as JS (although it will appear in the DOM).
You need to use multiple script elements.
a <script> to load the external script
a <script> to hold your inline code (with the call to the function in the external script)
scroll_messages();
In Layman terms, you need to include external js file in your HTML file & thereafter you could directly call your JS method written in an external js file from HTML page.
Follow the code snippet for insight:-
caller.html
<script type="text/javascript" src="external.js"></script>
<input type="button" onclick="letMeCallYou()" value="run external javascript">
external.js
function letMeCallYou()
{
alert("Bazinga!!! you called letMeCallYou")
}
Result :
If anyone still has the reference error is probably because you are loading your Javascript with defer, or it's in the bottom of the body so when the function gets called your function still doesn't exist.

Can you make a javascript function replace itself on the page with custom html?

I have some javascript which will create some sort of widget on a page. I will be giving this snippet to clients so I want them to have to do very little.
The most obvious solution which I have work right now looks something like this:
<div id="divContent"></div>
<script type="text/javascript">
MakeWidget('divContent');
</script>
Make widget basically looks for the divContent div and fill it with my widget's html.
Is there a better way to do this?
Can you replace a Script Tag with a Div using Javascript in that Script Tag?
I would really like it if I could reduce the code down to only the MakeWidget function and it would replace itself and the script tag with the html the function generates.
Edit - I essentially want to generate HTML exactly where the MakeWidget function is called on the page.
Can you replace a Script Tag with a Div using Javascript in that Script Tag?
Yes. When the <script> element is reached, assuming it is not a defer or async script, it will be the last script element in the page so far. So you can say, either inline or in an external script:
<script type="text/javascript">
(function() {
var scripts= document.getElementsByTagName('script');
var script= scripts[scripts.length-1];
var div= document.createElement('div');
div.innerHTML= 'Whatever content is going to be inserted';
script.parentNode.insertBefore(div, script);
})();
</script>
You have to have MakeWidget defined somewhere, right? Presumably this is going to be in an external script. Why not just have the external script source just attach itself to the divContent using the window.onload method?
This would result in this code on your client's page:
<script src="http://foo.com/makewidget.js"></script>
Your makewidget.js code could then look like this:
window.onload = function() { MakeWidget('divContent') }
There may some issues with other scripts loading and probably some cross-browser compatibility issues but that should get you pointed in the right direction.
So you want to have a script element which replaces itself with div.
Your initial code is like this:
<div id="divContent"></div>
<script>
MakeWidget('divContent');
</script>
You can rewrite it like this (I am using JQuery):
<script id="scriptContent">
$('#scriptContent').after('<div id="divContent"></div>');
MakeWidget('divContent');
$('#scriptContent').remove();
</script>
I have not tried it though!
I would think it would be possible to do it as follows:
<div id="divWidgets">
<script type="text/javascript">
MakeWidgets("divWidgets");
</script>
</div>
The end result should be (if I understand your description correctly) that MakeWidgets will replace the contents of the DIV, which, in this case, is the script itself.

Categories

Resources