Call a function in Javascript file from tampermonkey script - javascript

I'm trying to write a tampermonkey script and want to call a javascript function which is provided by the webpage.
The HTML of the page looks like this:
<ui-button class="action-button-spacing" id="downloadAs" variant="normal" text="Download as" click="openDownloadAsPanel()" data-disabled="actionButtonsDisabled()" initialized="true"><button class="ui-button ui-button-size-normal ui-button-variant-normal ui-hover-child-icons" type="submit"><span region-container="text">Download as</span></button></ui-button>
My script creates a button on the page, and I want it to call the openDownloadAsPanel method, whose definition is in a JS file (not part of the HTML file).
For this I tried this:
function addFunction(func, exec) {
var script = document.createElement("script");
script.textContent = "-" + func + (exec ? "()" : "");
document.body.appendChild(script);
document.body.removeChild(script); // clean up
}
function myFunction () {
return openDownloadAsPanel();
}
And then onclick of the button created by me, addFunction(myFunction, true);
I get an error: openDownloadAsPanel is not defined
Also I don't know the file of the javascript file as it is served by cloudfront and the name keeps changing if the file changes. Or probably I will have to parse all the javascript file name/path written in the HTML file.

I don't think you can call a function that is ran by the webpage. Your best bet would probably be trying to see what the code in the function is and defining your own function with that same code.

Related

Dynamically executing a <script> tag with an external src attribute using eval

I'm using the Genius API to retrieve the lyrics for a given song and embed them within an HTML <div> tag. I'm interacting with this API using PHP, via an AJAX GET request.
In the event of a successful AJAX request, I retrieve the following HTML from my PHP:
<div id='rg_embed_link_2351532' class='rg_embed_link' data-song-id='2351532'>
Read <a href='https://genius.com/The-1975-the-sound-lyrics'>“The Sound” by The 1975</a> on Genius
</div>
<script crossorigin src='//genius.com/songs/2351532/embed.js'></script>
The script tag returned by the Genius API will embed the lyrics and lyric information when executed.
I'm attempting to import this HTML into my already existing <div>. In this case, the <script> portion will not be executed. I've tried to use an eval() within the 'success' function of my AJAX to dynamically execute this script, but I'm having no success:
$.ajax({
url: 'lyrics.php',
type: 'GET',
async: true,
success: function(success){
geniusHTML = success;
//Insert geniusHTML including script tag into div
var lyricsDiv = document.getElementById("lyricsDiv");
lyricsDiv.innerHTML = geniusHTML;
//Get the script tag from the html and use eval on it
var innerScript = lyricsDiv.getElementsByTagName('script')
eval(innerScript.outerHTML);
}
});
I've tried to eval the:
.outerHTML -- The console shows this value to be: <script crossorigin="" src="//genius.com/songs/2351532/embed.js"></script>
.innerHTML -- Attribute appears to be empty.
.src -- The console shows this value to be: http://genius.com/songs/2351532/embed.js. Theeval() function errors on this with Uncaught SyntaxError: Unexpected end of input.
I feel I am potentially doing this backward. Should I execute the script from my AJAX return before I add it to the div? (The script generates quite a few embed div tags)
EDIT
With instruction from answerer Sjoerd de Wit, I attempted to create a new script tag from the source tag's src attribute, and add it via document.head.appendChild. This did not work, providing the warning:
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.
You should get the src from the script tag and dynamically create and load it in your html
var script = document.createElement("script");
var innerScript = lyricsDiv.getElementsByTagName('script')
script.src = innerScript.src;
document.head.appendChild(script);
using jQuery's .html() instead of javascript's .innerHTML() will automatically evaluate scripts inside the string
so, try to change this line
//Insert geniusHTML including script tag into div
var lyricsDiv = document.getElementById("lyricsDiv");
lyricsDiv.innerHTML = geniusHTML;
//Get the script tag from the html and use eval on it
var innerScript = lyricsDiv.getElementsByTagName('script')
eval(innerScript.outerHTML);
into
$("#lyricsDiv").html(geniusHTML);
SOLUTION
Answering my own question.
The other answers to this question are perfectly acceptable and work in most situations. However, if the external .js file contains a document.write within it, your browser will give you the following warnings:
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.
One of the ways to get around this is to use Postscribe. Postscribe will override any instances of document.write within javascript passed to it.
In the context of my code -- which, rest assured, I will refactor to make it more efficient -- I retrieve my script tag from my div by getting the outerHTML of the element, then I pass it into postscribe.
With this use case, postscribe takes two arguments; the div to pass the script to, and the script itself. Of course -- you can pass the script inline or via a variable as I have done in the below example:
var myScript = myDiv.getElementsByTagName('script')[0].outerHTML;
postscribe('#myDiv', myScript);
Please see the postscribe documentation linked above for installation instructions and further functionality.

How to access to external scripts loaded by javascript via script element

I want to create my own asset loader. To load external scripts, I used following javascript
function loadScript(src, callback) {
var script = document.createElement("script");
script.onload = function() {
document.head.appendChild(script);
callback();
};
script.src = src;
}
But I think this isn't the most elegant solution. This code snippet would make my HTML code ugly since it appends code to the head - for all of my dependencies.
So my question: is it possible to access to my external loaded code without using following line
document.head.appendChild(script);
Am I able to executes my script with pure js like
script.execute();
Or even better, is there a way to access to the data stored in my external js file? Like variable "bar", for example?
var foo = script.get("bar")
Could I even execute a function of the external file?
script.function(params)
It would be great to hear of your ideas and experiences!
Darth Moon
Edit: I forgot to exclude ajax. I know I could load code via ajax and executes it via eval(), but that won't be a good idea if you're testing code local since you need a Server (like an XAMPP Apache) to send ajax request to your local files.
You could try something like so as below.
Internal script:
function appendScript(src) {
var script = document.createElement(‘script’);
script.src = src;
document.head.appendChild(script);
}
External script:
function loadedScript() {
// run something
}
loadedScript()
The external code will just run loadedScript() once the file is loaded.

create callback API

New Restful API's like Google, OpenStreetview use a simple call back mechanism.
Basically you call the API, adding a parameter &callback=my function.
When executing a call to this API, as a result my function is called passing a JSON dataset.
I am trying to create the same mechanisme for a API I am building for my personal use.
As far as I understood my API needs to return a javascript, that calls the function that is passed in a script.
For a test I created this:
function apiCall(URL,values, keyPair,cBackPair) {
// URL specifics URL to call
// keyPair: <keyname>=<key>; leave black if unneeded
// cBacPair: <callBackParametername>=<functionname>
// called is: URL?values&keypair&cBackPair
var request = (keyPair)?'&'+keyPair:'';
request = URL + '?'+ encodeURI(values) + request + '&' + cBackPair;
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", request);
document.body.appendChild(script);
}
function callAPI() {
apiCall('http://xllent.nl/map/ajax/answer.php','q=one','','s=doit');
}
function doit(result) {
alert(result);
}
To test I call callAPI onload.
The script answer.php is very basic:
<?$s = $_GET['s'];
?>
<script type="text/javascript">
doit('jeroen');
</script>
Later the script would use $s to call the right script, and of course supply user data.
For now I am just trying to get the script doit('jeroen'); to be run. But nothing happens.
Typing javascript:doit('jeroen'); in the browser window gives the result I would expect.
Any suggestions?
Don't surround your javascript with <script> tags. You are not generating a HTML file with a javascript body.. You should think of this as if you're generating a javascript file on fly.
Javascript files also don't start and end with <script>

How to include JavaScript file into JSP?

I have the following script tag in my JSP file:
<script src="/js/CCTUtil.js"></script>
with the following function in it:
function disableButton(buttonID) {
document.getElementById(buttonID).setAttribute("disabled", "true");
return true;
}
and in my jsp I call it with:
onchange="disableButton('datasourceForm:cancel');
datasourceForm:cancel is just the ID, so don't worry about that.
This works if I hardcode the JS function in my JSP, but when exporting it to a file, it doesn't work. It recognizes the valid filepath (otherwise the server throws an exception) so it can see the file just fine, but when testing it in Internet Explorer the error is "Object expected", and points to the end of the JSP file, which of course isn't telling of anything.
Help please?
The SRC must not be correct then. Are you sure you have set the path correctly? It's not supposed to be "../js/CCTUtil.js" is it?
Instead of including script file, directly add javascript function in the jsp file.
Then try, if you are getting the same issue, might be some issue with javascript or ur id datasourceForm:cancel

problems when creating a script tag to a local file in android webview

I have an Android application that consist in a simple WebView that load a local html file in the assets folder of the project.
The HTML has a tag that calls (AJAX) an external service and expects as a response a String that represent a .js filename (say, 'test.js').
In test.js there is a simple funcion declaration, as:
var testFunction = function(){
// some code here
}
The AJAX callback then construct via javascript a tag that points to the .js file and append it to the head of the document; then call the testFunction:
$.ajax('externalService').done(function(response){
var script = // construct the script tag;
$('head').append(script);
testFunction();
});
Important: the script tag points to an external .js file, like
<script src="http://justatest.com/test.js">
... and all works fine!
Now i try to do the same thing putting the test.js inside the assets folder of the project. Obviously i changed the src of the script created in the callback with a relative path:
<script src="test.js"></script>
but when i try to invoke the function testFunction i get an error (testFunction is not defined).
The local path is correct (i put jquery.js in the same local folder of test.js and loaded it directly in the html with a with no errors).
I put all the attributes (like type="text/javascript") in the tag as well...
so, why the webview doesn't load a local .js file in this way?
thank you :)
EDIT: I tried the solution found in this thread:
jQuery getScript not working in Android WebView when using Local Assets/HTML/Resources
and it worked!!!!
I tried the solution found in this thread:
jQuery getScript not working in Android WebView when using Local Assets/HTML/Resources
and it worked!
I report the solution:
var scriptUrl = "test.js";
var head = document.getElementsByTagName("head")[0];
script = document.createElement('script');
script.type = 'text/javascript';
script.src = scriptUrl;
script.onload = function() { alert("Success"); };
script.onerror = function(e) { alert("failed: " + JSON.stringify(e)); };
head.appendChild(script);
So if i use the jquery append() method it doesn't work, but if i use the javascript appendChild method it work...

Categories