Issues with injecting jQuery into host page from a Chrome Extension [duplicate] - javascript

I am having troubles loading all the scripts that I am inserting into the page context with <script> tags from a content_script script, because they are required to be executed in the correct loading order, as some depend on others. In an actual HTML file I guess there is a queue to load the files, but with inserting <script> tags it seems like if one script delays a little time, the next one starts loading and then is immediately executed notwithstanding it had to wait for its dependency library that is still loading.
Below is the network output with the error caused because of x-tag-core.min.js is loaded before primeui-all.min.js and eventPage.js which uses jquery-ui.min.js, is loaded before it:
// manifest.js
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"js/jquery-3.1.1.min.js",
"js/main.js"
]
}
]
// main.js
var s = document.createElement('script');
s.src = chrome.extension.getURL('js/jquery-3.1.1.min.js');
$(document.head).append(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/jquery-ui.min.js');
$(document.head).append(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/primeui-all.min.js');
$(document.head).append(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/x-tag-core.min.js');
$(document.head).append(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/primeelements.min.js');
$(document.head).append(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/eventPage.js');
$(document.head).append(s);

Duplicating your problem in a snippet
The following snippet duplicates your problem by sequentially inserting <script> elements. I am using network resources, because there is no method of storing such scripts on Stack Overflow. Given that you only supplied version information for jQuery, I have had to guess at appropriate versions for the other libraries which you are using.
In order to stay close to the code which you are using in your Chrome extension, chrome.extension.getURL() is faked. In these snippets, that function returns a functional network URL for the libraries which you are using. Obviously, in your Chrome extension, you will want to continue to use the library files which you ave included with your extension.
In addition, the code for eventPage.js is faked by having some code that reports if jQuery exists, if $(document).puidialog is a function, and/or if xtag is defined. The errors you are seeing are that $([something]).puidialog was not a function and xtag was not defined. This fakeEventPageJS code accurately shows if the scripts have been properly loaded.
In this duplication of your problem, an error is also produced from the various libraries as the subsequent libraries can not find prior libraries.
var s = document.createElement('script');
s.src = chrome.extension.getURL('js/jquery-3.1.1.min.js');
document.head.appendChild(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/jquery-ui.min.js');
document.head.appendChild(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/primeui-all.min.js');
document.head.appendChild(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/x-tag-core.min.js');
document.head.appendChild(s);
s = document.createElement('script');
s.src = chrome.extension.getURL('js/primeelements.min.js');
document.head.appendChild(s);
s = document.createElement('script');
//s.src = chrome.extension.getURL('js/eventPage.js');
//Fake js/eventPage.js with an actual script.
s.textContent = fakeEventPageJS;
document.head.appendChild(s);
<!-- The JavaScript code included in this HTML section is used to fake the chrome API
and part of faking the existence of a js/eventPage.js file by inserting code. -->
<!-- Using HTML <script> tags to test that loading it via these works prior to testing
using JavaScript inserts. If you want to verify that the code works when the
scripts are included in the original HTML, you can uncomment the <script>
tags here. -->
<!-- jquery-3.1.1.min.js -->
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script><!-- -->
<!-- jquery-ui.min.js -->
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script><!-- -->
<!-- primeui-all.min.js -->
<link rel="stylesheet" href="https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeui-all.min.css">
<!-- <script src="https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeui-all.min.js"></script><!-- -->
<!-- x-tag-core.min.js -->
<!-- <script src="https://cdn.rawgit.com/x-tag/core/master/dist/x-tag-core.min.js"></script>
<!-- primeelements.min.js -->
<!-- <script src="https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeelements.min.js"></script> <!-- -->
<script>
//Fake chrome.extension.getURL
var netScriptLoations = {
'js/jquery-3.1.1.min.js':'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js',
'js/jquery-ui.min.js':'https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js',
'js/primeui-all.min.js':'https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeui-all.min.js',
'js/x-tag-core.min.js':'https://cdn.rawgit.com/x-tag/core/master/dist/x-tag-core.min.js',
'js/primeelements.min.js':'https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeelements.min.js'
}
if(typeof chrome !== 'object'){
var chrome = {};
}
if(typeof chrome.extension !== 'object'){
chrome.extension = {};
}
if(typeof chrome.extension.getURL !== 'function'){
chrome.extension.getURL = function(script){
//console.log(netScriptLoations[script]);
return netScriptLoations[script];
};
}
var fakeEventPageJS =
'var testResult = "Scripts did NOT load correctly. "'
+ ' + "$(document).puidialog is NOT a function.";'
+ 'var passedChecks=0;'
+ 'if(typeof $ === "function"){'
+ ' var puidialogNot = " NOT";'
+ ' if(typeof $(document).puidialog === "function") {'
+ ' puidialogNot = "";'
+ ' }'
+ ' console.log("$(document).puidialog is" + puidialogNot + " a function");'
+ '} else {'
+ ' console.log("No jQuery");'
+ '}'
+ 'var xtagNot = " NOT";'
+ 'if(typeof xtag !== "undefined") {'
+ ' xtagNot = "";'
+ '}'
+ 'console.log("xtag is" + xtagNot + " defined.");'
+ 'if(puidialogNot + xtagNot === "") {'
+ ' testResult = "Scripts loaded CORRECTLY. "'
+ '}'
+ 'console.log(testResult);';
</script>
Insert each <script> in the onload event handler of the prior script
It is clear that the inserted <script> elements are executed asynchronously. In order to force them to be executed synchronously, we need to insert the next script after the prior one has completed execution. This can be done by utilizing the load event for each script.
The following code loads each subsequent script in the load event handler of the prior script.
The function createScriptElement creates an individual <script> element. This function can be somewhat simplified in your code due to not needing to fake the eventPage.js script.
The function createScriptSequence creates a sequence of <script> elements which each inserts the next script in its onload listener. This uses script.addEventListerner('load',...) in order to be immune to the script being loaded changing the script.onload property/attribute.
var scriptsToInsert = [
'js/jquery-3.1.1.min.js',
'js/jquery-ui.min.js',
'js/primeui-all.min.js',
'js/x-tag-core.min.js',
'js/primeelements.min.js',
'js/eventPage.js'
]
function createScriptElement(script){
let scriptEl = document.createElement('script');
let scriptElSource = chrome.extension.getURL(script);
if(scriptElSource){
scriptEl.src = scriptElSource;
} else {
//Only need this `else` because we are faking having js/eventPage.js by using
// some code to indicate if $(document).puidialog is a function.
scriptEl.textContent = fakeEventPageJS;
}
return scriptEl;
}
function createScriptSequence(scriptArray){
var scriptEls = [];
//Create all the script elements
scriptArray.forEach((script,index)=>{
//console.log(script);
scriptEls.push(createScriptElement(script));
if(index>0){
//Add an onload listener for each script (except the last) which loads
// the next one in the sequence.
scriptEls[index - 1].addEventListener('load',function oneTime(){
//Probably don't need to remove this, but better to clean things up.
scriptEls[index - 1].removeEventListener('load',oneTime,false);
document.head.appendChild(scriptEls[index]);
},false);
}
});
//Return the first script in the sequence
return scriptEls[0];
}
document.head.appendChild(createScriptSequence(scriptsToInsert));
<!-- The JavaScript code included in this HTML section is used to fake the chrome API
and part of faking the existence of a js/eventPage.js file by inserting code. -->
<!-- jquery-ui.min.js -->
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<!-- primeui-all.min.js -->
<link rel="stylesheet" href="https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeui-all.min.css">
<script>
//Fake chrome.extension.getURL
var netScriptLoations = {
'js/jquery-3.1.1.min.js':'https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js',
'js/jquery-ui.min.js':'https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js',
'js/primeui-all.min.js':'https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeui-all.min.js',
'js/x-tag-core.min.js':'https://cdn.rawgit.com/x-tag/core/master/dist/x-tag-core.min.js',
'js/primeelements.min.js':'https://cdn.rawgit.com/primefaces/primeui-distribution/master/primeelements.min.js'
}
if(typeof chrome !== 'object'){
var chrome = {};
}
if(typeof chrome.extension !== 'object'){
chrome.extension = {};
}
if(typeof chrome.extension.getURL !== 'function'){
chrome.extension.getURL = function(script){
//console.log(netScriptLoations[script]);
return netScriptLoations[script];
};
}
var fakeEventPageJS =
'var testResult = "Scripts did NOT load correctly. "'
+ ' + "$(document).puidialog is NOT a function.";'
+ 'var passedChecks=0;'
+ 'if(typeof $ === "function"){'
+ ' var puidialogNot = " NOT";'
+ ' if(typeof $(document).puidialog === "function") {'
+ ' puidialogNot = "";'
+ ' }'
+ ' console.log("$(document).puidialog is" + puidialogNot + " a function");'
+ '} else {'
+ ' console.log("No jQuery");'
+ '}'
+ 'var xtagNot = " NOT";'
+ 'if(typeof xtag !== "undefined") {'
+ ' xtagNot = "";'
+ '}'
+ 'console.log("xtag is" + xtagNot + " defined.");'
+ 'if(puidialogNot + xtagNot === "") {'
+ ' testResult = "Scripts loaded CORRECTLY. "'
+ '}'
+ 'console.log(testResult);';
</script>

Related

Looking for an alternative to document.write for gpt.js file declaration

What can I use in place of document.write in JavaScript? Is there a different way to rewrite this line of code?
document.write('<scr' + 'ipt src="' + src + '"></scr' + 'ipt>');
Assuming your document.write statement was already in an executing script tag, you could substitute it with:
var script = document.createElement('script')
script.src = src
var first = document.getElementsByTagName('script')[0]
first.parentNode.insertBefore(script, first)
Demo:
// a delayed check to see if the script loaded
setTimeout(function() {
console.log(window.jQuery ? 'jQuery loaded!' : 'Uh oh!')
}, 5000)
<script>
var script = document.createElement('script')
// example src
script.src = 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'
var first = document.getElementsByTagName('script')[0]
first.parentNode.insertBefore(script, first)
</script>

Why does '&page' in my Javascript code show up as '&amp;page' in web browser

This is my script and it's being placed in the header internally on the html document:
<script type="text/javascript">
(function l(d){
var site = '6708', page = 'blahblah', s, er = d.createElement('script');
er.type = 'text/javascript';
er.async = true;
er.src = '//randomsite.com/?site=' + site + '&page=' + page; // **
s = d.getElementsByTagName('script')[0];
s.parentNode.insertBefore(er, s);
})(document);
</script>
and for some reason in Chrome when I check the console it shows up as
+ site + '&amp;page='
instead of
+ site + '&page=' + page;
Edit
So the error disappeared after clearing up console and browser settings. But now a new error has shown up, and I'm not sure what this means
I'm at a loss as to why that is.
You should be getting Uncaught SyntaxError: Unexpected token * with the ** before site and after page. How have you embedded it in the html? this seemed to work fine for me:
<html>
<head>
</head>
<body>
<script type="text/javascript">
(function l(d){
var site = '6708', page = 'blahblah', s, er = d.createElement('script');
er.type = 'text/javascript';
er.async = true;
er.src = '//randomsite.com/?site=' + site + '&page=' + page;
s = d.getElementsByTagName('script')[0];
s.parentNode.insertBefore(er, s);
})(document);
</script>
</body>
</html>
Most likely you have an ad blocker installed in your browser. Disable it and try again. ;-)

javascript tag in innerhtml

Like the title says I'm trying to add a javascript tag into a innerHTML.
I have a combobox and depending on which value is selected it should load a script into a div
the script looks like this:
<script type="text/javascript">
_cashieProductID=292016;
document.write(unescape("%3Cscript src='" +
('https:' == document.location.protocol ? 'https://' : 'http://') +
"somelink.js'
type='text/javascript'%3E%3C/script%3E"));
</script>
when I put this into my script it shows all kind of text on my page that is part of the combobox script. So I hope someone can help me how to insert this code into my script so it will show the content that gets loaded with the code given above.
HTML
<select id="product" onchange="validate()">
function validate()
{
pName = document.getElementById('product');
var value = pName.options[pName.selectedIndex].value;
if(value == "4OFC")
loadJs(detail,"myjsSrc");
else if(/*some conditon*/)
{
// use this ladder to change the script address based on value of select box
}
else{
}
}
function loadJs(targetDiv,source)
{
var ele = document.getElementById(targetDiv);
if(ele)
{
var scr = document.createElement('script');
scr.type = 'text/javascript';
scr.src = source;
ele.appendChild(scr);
}
}
Just try the actual string in document.write, like this:
document.write("<script src='" + ('https:' == document.location.protocol ? 'https://' : 'http://') + "somelink.js' type='text/javascript'></script>");

Javascript access denied error on page partial load - why?

On thirdpartydomain.com I want to embed a simple <script> tag that pulls in a script from mydomain.com/myscript.js, which simply creates a little <div> and pulls partial page content from mydomain.com/mypage.htm.
Here's the script, adapted from: How to embed Javascript widget that depends on jQuery into an unknown environment
var myEmbedId = '12345';
var myEmbedContainerId = 'myEmbedContainer_' + myEmbedId;
document.write('<div id="' + myEmbedContainerId + '">IF ALL GOES WELL, THIS TEXT WILL BE REPLACED WITH MYPAGE.HTM CONTENTS');
document.write('</div>');
(function (window, document, version, callback) {
var j, d;
var loaded = false;
if (!(j = window.jQuery) || version > j.fn.jquery || callback(j, loaded)) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://mydomain.com/jquery-1.4.1.min.js";
script.onload = script.onreadystatechange = function () {
if (!loaded && (!(d = this.readyState) || d == "loaded" || d == "complete")) {
callback((j = window.jQuery).noConflict(1), loaded = true);
j(script).remove();
}
};
document.documentElement.childNodes[0].appendChild(script)
}
})(window, document, "1.3", function ($, jquery_loaded) {
$(document).ready(function () {
alert('jquery loaded!');
var myRefreshUrl = 'http://mydomain.com/mypage.htm';
alert('refreshing from ' + myRefreshUrl);
$.get(myRefreshUrl, function(data){
var returnData = data;
alert('return data: ' + data);
$('#' + myEmbedContainerId).html(data); });
alert('load complete v2');
});
});
In IE, I get an Access Denied error from Javascript; in Firefox I just get no data returned.
What's wrong with this?
You cannot create an AJAX request to a different domain from the one that is hosting the current window context.
To pull off what you're describing, you can do something like:
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'http://mydomain.com/dynamic.js?data=somepage.htm';
someContainer.appendChild(script);
Within that dynamic.js, you can wrap the HTML contents in a document.write(). The net effect is the same as inserting the result of the AJAX request at the same point in the DOM.

Call Chrome.extension.sendRequest from a dynamically inserted js?

I'm currently trying to insert dynamically a JS block on a webpage using jQuery but it didn't work. I tried this :
var body = $('body');
var injectJs = $('<script type=text/javascript>' +
'$(document).click(function() {' +
'dropMenu("dropMenu1", 0);' +
'});');
body.append(injectJs);
EDIT : 16:26
I've succeed to insert the code by this way :
/* Importation de Tool.js */
var scriptImport = document.createElement('script');
scriptImport.type = 'text/javascript';
scriptImport.src= chrome.extension.getURL('js/Tool.js');
head.appendChild(scriptImport);
/* Injection du script onClick */
var script = document.createElement('script');
script.type = 'text/javascript';
script.innerHTML = "document.addEventListener('click', function(){ dropMenu('slideUp', 0); alert('TRY ME AGAIN'); });";
And dropMenu :
function dropMenu(dropMenuPage, marginLeft)
{
var msg = "";
msg = msg.concat(dropMenuPage, "|", marginLeft);
chrome.extension.sendRequest({dropMenu : msg});
alert('After send');
}
The problem is that the sendRequest is impossible from this page... Someone have an idea ?
Thanks in advance.
You need a closing </script> at the end there...
I think its just your script stag isn't closed
var b= $('body');
var injectJs = $('<script type=text/javascript> $(document).click(function() {alert("yes");});</script>');
b.append(injectJs);
Use eval function, such as eg:
var body = $('body');
var injectJs = eval("$(document).click(function() {alert('hello')})");
body.append(injectJs);
Why not use content scripts for this? Injecting script directly to the page is only required if you need to access js variables from the page. For your dropMenu() a content script should be enough.
You cannot use Chrome API inside injected js. You would need to also inject a content script, and using custom DOM events you would be able to communicate with it from your injected script. Then this content script would be able to call Chrome API and communicate with a background page. Sounds like a pain to me. I would suggest you go this route only if there is no other ways possible.
// Importation of jQuery.js
var scriptImport = document.createElement('script');
scriptImport.type = 'text/javascript';
scriptImport.src= chrome.extension.getURL('js/jquery.js');
head.appendChild(scriptImport);
// Injection of onClick script
var script = document.createElement('script');
script.type = 'text/javascript';
script.innerHTML =
"document.addEventListener('click', function()" +
"{ if(document.getElementById('dropMenu')) {" +
"$('#dropMenu').slideUp(800, function() {" +
"$(this).remove();" +
"});" +
"}});";
I've finally done this, it works :)

Categories