Javascript update function via change src script file - javascript

My javascript file with function:
scr.js:
function myf(){
alert('aaa');
}
myf();
After load page, I see dialog box with 'aaa'. This is right.
The next, I change script source to:
function myf(){
alert('bbb'); ///////////
}
myf();
and src file by add to him timestamp (for update file):
$('script[src^="./scr.js"]').attr('src','./scr.js?='+new Date().getTime());
The problems:
after update file, the myf() function doesn't run.
after run myf() function from browser console I see dialog with 'aaa' not with 'bbb'
when I remove script tag with src scr.js, I can call again my function
Where is problem and what do for update scritpt?

As far as I know, changing a script src attribute, doesn't force the browser to download the script; you need to create a new script tag and append it to the DOM.
Because the browser didn't downloaded and executed the new script.
When your script was first run by the browser it created a global function, which has been attached to the global object; that's why you can still call it, even though you've dinamically removed the script.
UPDATE (Possible solution):
Create a script element dinamically using something like this:
function createScript(src) {
var s = document.createElement("script");
s.src = src;
return s;
}
Update the DOM:
var oldScript = document.querySelector("script[src^='s.js']");
var newScript = createScript("s.js?t=" + (new Date()).getTime());
document.body.replaceChild(newScript, oldScript);
(you can translate that into jQuery if you want)

Related

Dynamically add javascript script to page with code not src

I am trying to figure out how to inject this script into a site using Tampermonkey. Here is what I have so far but the onBrazeSdkLoaded event is never being called so I don't think its being inserted correctly. I have tried a few iterations but no luck. To reference the exact script I am trying to include here is the link to the public docs.
https://www.braze.com/docs/developer_guide/platform_integration_guides/web/initial_sdk_setup/#install-gtm
const script = document.createElement("script");
var code = document.createTextNode(`+function(a,p,P,b,y){a.braze={};a.brazeQueue=[];for(var s="BrazeSdkMetadata DeviceProperties Card Card.prototype.dismissCard Card.prototype.removeAllSubscriptions Card.prototype.removeSubscription Card.prototype.subscribeToClickedEvent Card.prototype.subscribeToDismissedEvent Card.fromContentCardsJson Banner CaptionedImage ClassicCard ControlCard ContentCards ContentCards.prototype.getUnviewedCardCount Feed Feed.prototype.getUnreadCardCount ControlMessage InAppMessage InAppMessage.SlideFrom InAppMessage.ClickAction InAppMessage.DismissType InAppMessage.OpenTarget InAppMessage.ImageStyle InAppMessage.Orientation InAppMessage.TextAlignment InAppMessage.CropType InAppMessage.prototype.closeMessage InAppMessage.prototype.removeAllSubscriptions InAppMessage.prototype.removeSubscription InAppMessage.prototype.subscribeToClickedEvent InAppMessage.prototype.subscribeToDismissedEvent InAppMessage.fromJson FullScreenMessage ModalMessage HtmlMessage SlideUpMessage User User.Genders User.NotificationSubscriptionTypes User.prototype.addAlias User.prototype.addToCustomAttributeArray User.prototype.addToSubscriptionGroup User.prototype.getUserId User.prototype.incrementCustomUserAttribute User.prototype.removeFromCustomAttributeArray User.prototype.removeFromSubscriptionGroup User.prototype.setCountry User.prototype.setCustomLocationAttribute User.prototype.setCustomUserAttribute User.prototype.setDateOfBirth User.prototype.setEmail User.prototype.setEmailNotificationSubscriptionType User.prototype.setFirstName User.prototype.setGender User.prototype.setHomeCity User.prototype.setLanguage User.prototype.setLastKnownLocation User.prototype.setLastName User.prototype.setPhoneNumber User.prototype.setPushNotificationSubscriptionType InAppMessageButton InAppMessageButton.prototype.removeAllSubscriptions InAppMessageButton.prototype.removeSubscription InAppMessageButton.prototype.subscribeToClickedEvent automaticallyShowInAppMessages destroyFeed hideContentCards showContentCards showFeed showInAppMessage toggleContentCards toggleFeed changeUser destroy getDeviceId initialize isPushBlocked isPushPermissionGranted isPushSupported logCardClick logCardDismissal logCardImpressions logContentCardImpressions logContentCardsDisplayed logCustomEvent logFeedDisplayed logInAppMessageButtonClick logInAppMessageClick logInAppMessageHtmlClick logInAppMessageImpression logPurchase openSession requestPushPermission removeAllSubscriptions removeSubscription requestContentCardsRefresh requestFeedRefresh requestImmediateDataFlush enableSDK isDisabled setLogger setSdkAuthenticationSignature addSdkMetadata disableSDK subscribeToContentCardsUpdates subscribeToFeedUpdates subscribeToInAppMessage subscribeToSdkAuthenticationFailures toggleLogging unregisterPush wipeData handleBrazeAction".split(" "),i=0;i<s.length;i++){for(var m=s[i],k=a.braze,l=m.split("."),j=0;j<l.length-1;j++)k=k[l[j]];k[l[j]]=(new Function("return function "+m.replace(/\./g,"_")+"(){window.brazeQueue.push(arguments); return true}"))()}window.braze.getCachedContentCards=function(){return new window.braze.ContentCards};window.braze.getCachedFeed=function(){return new window.braze.Feed};window.braze.getUser=function(){return new window.braze.User};(y=p.createElement(P)).type='text/javascript';
y.src='https://js.appboycdn.com/web-sdk/4.2/braze.min.js';
y.async=1;(b=p.getElementsByTagName(P)[0]).parentNode.insertBefore(y,b)`);
script.text = code;
document.head.appendChild(script);
script.onload = onBrazeSdkLoaded;
A load event fires when a resource has been loaded from an external source.
Since your script is getting its program from a text node inside the script element, instead of from a URL assigned to the src attribute, there is no external source.
Consequently, there is no load event.
If you want onBrazeSdkLoaded to fire when the script you create on line 1 has loaded, then just include onBrazeSdkLoaded() in the string you assign to code.
If you want it to fire when https://js.appboycdn.com/web-sdk/4.2/braze.min.js loads, then you need to:
Ensure it is in the global scope
Write code that assigns it to y.onload inside the string you assign to code
Fix the syntax error(s) in the JS in that string

Set Script Source from the same file instead of a different one?

I create an iframe in a file and insert a <script> tag as its content. The Script src is loaded from a different file called test.js. Here is how it is done:
var scriptElement = document.querySelector("#your-widget");
var iframe = document.createElement("iframe");
scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);
var script = document.createElement("script");
iframe.contentWindow.document.appendChild(script);
script.src = "http://www.example.com/test.js";
Instead of loading the content of the script from http://www.example.com/test.js I want to take it from the same file where the above code is. This would like this:
var scriptElement = document.querySelector("#your-widget");
var iframe = document.createElement("iframe");
scriptElement.parentNode.insertBefore(iframe, scriptElement.nextSibling);
var script = document.createElement("script");
iframe.contentWindow.document.appendChild(script);
script.src = // ????
// the following JavaScript code should be placed inside the script
function mywidget() {
// some code
return true;
}
mywidget.succeeded = mywidget();
How can I set the Script Source from the same file instead of a different one?
If you literally just want to place that exact snippet in a script tag, you can just do so using .innerText.
script.innerText = 'function mywidget() { ...';
Then it will execute as is when it's inserted into the DOM. If you want to dynamically find and inject that code, read on.
There are exactly two ways to load a script on a page.
Add a <script> with the src attribute pointing to a file.
Create a <script> tag then set the contents to whatever you want to execute.
var script = document.createElement('script');
script.innerText = 'console.log("Hello, World!")';
document.body.appendChild(script);
If you want to extract part of a script and use those contents then the best you can do is load the contents via ajax and inject it using method 2.
Assuming you have jQuery (for easy AJAX work):
$.ajax({
url: 'path/to/script.js',
dataType: 'text', // make sure it doesn't get eval'd
success: function(contentsOfScript) {
// Refer to method 2
}
});
Now you can go about extracting the contents of that snippet in one of two ways:
Know exactly which line it begins on.
var lines = contentsOfScript.split('\n');
var snippet = lines.slice(lineNumber + 1); // adjust for 0 indexing
Generate a regular expression to identify where your code begins. This is rather tricky and very error prone if your snippet isn't easily distinguished from other code.
var snippet = contentsOfScript.match(/function mywidget.+/)[0];
Neither of these methods will work if you perform any minification on your code.

Running Javascript in new window.open

I'm running this function to open a new window.
function htmlNewWindow(id) {
var html = $(id).html();
var newWindow = window.open('');
newWindow.document.body.innerHTML = '<html><head><title>Hi</title> <script src="js/myScript.js"></script> </head>' + html;
}
This successfully creates a new window with the HTML in it. I have a bunch of HTML tags which when clicked run a function called Foo1. I've tried printing the entire function of Foo1 to the new HTML document, and tried putting Foo1 inside myScript.js. I see both Foo1 inside a script tag in the new window, and but neither are loaded since they are just written to the new page as HTML.
Scripts added with .innerHTML aren't executed. You need to create a script node and append it to the window's DOM.
$("#button").click(newWindow);
function newWindow(id) {
var html = $(id).html();
var win = window.open('');
win.document.head.innerHTML = '<title>Hi</title></head>';
win.document.body.innerHTML = '<body>' + html + '</body>';
var script = document.createElement('script');
script.src = 'js/myScript.js';
win.document.head.appendChild(script);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="button">Click me</button>
This doesn't run in Stack Snippet's sandbox, here's a working jsfiddle.
Try this:
var newWindow = window.open('');
newWindow.document.createElement('script');
script.src = 'js/myScript.js';
newWindow.document.head.appendChild(script);
Just in case someone has this to be done in a link. Do the following:
Link
This opens a new window with that URL, it set the focus to that windows, and as soon as the 'load' event is triggered, it executes the code in the function. It only works with a page in the same domain.
Hope this helps ⬆✌.
Cheers 👍
Here's how you create, and then append a script file within a new window:
var fileref = document.createElement('script');
//creates script in current document
fileref.setAttribute("type", "text/javascript")
//set it to JS by "type"
fileref.setAttribute("src", filename)
//set your "src=yourFile_href_Here.js"
//Then create your newWindow as you did above, but slightly updated
//Create your function which will consume the "fileref" argument
function htmlNewWindow(fileref) {
var newWindow = window.open('');
newWindow.document.getElementsByTagName("head")[0].appendChild(fileref);
}; //right now the function is made but you still have to execute it
//Execute your function, and pass it the variable "fileref" that you set above.
htmlNewWindow(fileref);
//Within this edit you will append the head element
//with your newly created script(or any other parameterized argument)
/* Replace your filename to pass any other script */
NOTE - Opening a page residing on a different domain, if not specifically allowed, will reject instances of this due to CORS(https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)
It's not a safe practice to be sending your scripts into other people's pages or allowing them in your own if your domain hasn't sent them. Also, depending on your server/technology stack you may need to configure your *-origin settings within your backend stack. See here: (https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)

Passing a variable before injecting a content script

I am working on a Chrome Extension that works mainly within a pop-up.
I would like the user to enter some text (a string) into an input field in the pop-up, and this string will serve as a "variable" in a script I would like to inject and run on a specific page.
I have tried achieving this by making a content script that will execute the script, using the following well documented way:
var s = document.createElement('script');
s.src = chrome.runtime.getURL('pageSearch.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
Basically, I would like to pass the user's input all the way to the code in pageScript.js before executing the script on the page.
What would be the best way to approach this? I will not be getting any information back to the extension.
Thanks.
To pass a variable from the popup to the dynamically inserted content script, see Pass a parameter to a content script injected using chrome.tabs.executeScript().
After getting a variable in the content script, there are plenty of ways to get the variable to the script in the page.
E.g. by setting attributes on the script tag, and accessing this <script> tag using document.currentScript. Note: document.currentScript only refers to the script tag right after inserting the tag in the document. If you want to refer to the original script tag later (e.g. within a timer or an event handler), you have to save a reference to the script tag in a local variable.
Content script:
var s = document.createElement('script');
s.dataset.variable = 'some string variable';
s.dataset.not_a_string = JSON.stringify({some: 'object'});
s.src = chrome.runtime.getURL('pageSearch.js');
s.onload = function() {
this.remove();
};
(document.head||document.documentElement).appendChild(s);
pageSearch.js:
(function() {
var variable = document.currentScript.dataset.variable;
var not_a_string = JSON.parse(document.currentScript.dataset.not_a_string);
// TODO: Use variable or not_a_string.
})();

An other way to load a js file in js code

I opened a javaScript file in a javaScript time....
document.write("<script src='newnote.js' type='text/javascript'></script>");
is there an other way to load the js in js code..?
(this file is for loading a popup menu js code , which is loaded after delay by clock js code ... so i want an othe way to loaded it)
When opening a JS file, its code is executed at once - functions are created, code is run, events are set. The only way to 'unload' a Javascript file is to manually undo all the code that has been run as a result of loading the unwanted file: setting all new functions, variables and prototype aditions to undefined (e.g. window.badFunction = undefined, unset all events, remove all new DOM elements..
If you wanted to unload another JS file every time when opening a page, it could in theory be done, but not very easily and if the loaded JS file should change, you would have to update your invalidating file.
What you did isn't like opening a local file in a programming language like C++ or Java. You don't need to close anything.
Is it possible that the script that you are adding to the page (in this case newnote.js) is causing the error you are experiencing?
Instead of the line you used starting with document.write use this instead:
var newnote = document.createElement('script');
newnote.src = "newnote.js";
newnote.type = "text/javascript";
document.documentElement.firstChild.appendChild( newnote );
If you still get your quotes error, then the code inside of newnote.js is messed up.
Don't think this was really what you were asking, but if you used the code I listed above you could then remove this file from your page by calling this:
document.documentElement.firstChild.removeChild( newnote );
One more thought:
If your path to newnote.js is not correct (because it is not in the same directory as the calling page) then the server would return a 404 error page instead of the file. If your browser tried to execute it like javascript, it could throw an error. Try supplying the full URL: http://yoursite.com/js/newnote.js or a root relative one: /js/newnote.js
you are not opening a javascript file, in fact you cannot open any file from local file system, so there is no question of closing. You are inserting a script tag replacing all contents of the document. This would result in fetching newnote.js using the current url with newnote.js replacing anything after last slash.
To include a script you could try this:
var s = document.createElement('script');
s.src = 'newnote.js';
s.type = 'text/javascript';
var head = document.getElementsByTagName('head')[0]
head.appendChild(s);
or like that:
document.write("<script type='text/javascript' src='newnote.js'><\/sc" + "ript>");

Categories

Resources