Chrome Extension - Javascript loaded but function is not defined when calling it - javascript

I thought everything was well with my extension, it was loading the js libraries successfully on most of the domains I've tested my extension on, then I found a few domains where it seemed the libraries wasn't being loaded.
I am using the Google Web Font Loader library, and including it in my contentscript.js, which injects it to the page like this:
// Add Google Webfont Library
var gwebfont = document.createElement("script");
gwebfont.src = "https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js";
var callback = function (){
var s = document.createElement('script');
s.type = 'text/javascript';
var code = "WebFont.load({google: { families: ['Open Sans', 'Open Sans:light', 'Open Sans:semi-bold', 'Open Sans:bold'] } });";
try {
s.appendChild(document.createTextNode(code));
shadow.appendChild(s);
} catch (e) {
s.text = code;
shadow.appendChild(s);
}
}
gwebfont.onload = callback;
shadow.appendChild(gwebfont);
Yes, I do have the folder set in web_accessible_resources and the contentscript.js is also running..
On the few domains this doesn't work, it says WebFont is not defined, but on most of the domains I've tested this on, it works without any problem.
When I check in the Network tab in Chrome, I can see the webfont.js was loaded.
Can anyone tell me why only some domains give me the not defined error, when it appears the library was loaded?
I have also tried to run the code again in the console, and on the few domains where it doesn't work, it gives me the same not defined error.
This code doesn't work on hungry.dk, works on stylepit.dk
Here's a snippet of the event
Let me know if u want a closer look at something in here..

Related

How to find which [content] script execute the eval code

Recently In my chrome, every page loads https://s3.amazonaws.com/exthub/e/2/r/US_chrome.js?cached=true and it is really annoying. I want to find which extension added such code snippets. But in the Network panel of Chrome devtools, the Initiator just shown VM***, I could not find which script invoke it even I set some break points in the scripts.
I have a lot of chrome extension, so it was difficult to check echo extension one by one. I also tried to search some keyword like content_scripts,executeScript,amazonaws and so on in %AppData%\..\Local\Google\Chrome\User Data\Default\Extensions, but I still could not find it.
Is there any convenient methods for finding the source script.
The VM*** script is the following.
(() => {
if (document.querySelector('script[data-awssuidacr]') !== null) {
return;
}
const head = document.querySelector('head');
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = 'https://s3.amazonaws.com/exthub/e/2/r/US_chrome.js?cached=true';
script.dataset['awssuidacr'] = 'KMyretRSNnBnMx4zVMxXIXOlCwtj9scH';
head.appendChild(script);
})();
#dorian Thanks for your advice. Now I tried to disable the "YouTube Video Downloader", and the scripts did not show up again.
I did not find the extension by searching some keywords was because I forgot the unpacked extension, they are not in the %AppData%\..\Local\Google\Chrome\User Data\Default\Extensions directory. And I go through the code and find the js code was obfuscated.

Object Still Undefined Even within Script Onload

I am writing up a ContentScript for a Chrome Extension. In the script, I want to import a javascript (actually a JS and a CSS) and initiate a class from that script.
To ensure the Javascript is properly loaded, I followed the guidance from several SO posts like this, this and this.
var link = document.createElement( "link" );
document.body.appendChild(link);
link.onload = function(){
console.log("link loaded");
var script = document.createElement('script');
document.body.appendChild(script); //or something of the likes
script.onload = function () {
...
console.log("script loaded");
// somehow ContentTools is undefined even after the script is loaded
editor = ContentTools.EditorApp.get();
editor.init('*[data-editable]', 'data-name');
console.log("all finished")
};
script.src = "https://....min.js";
};
link.href = "https://....min.css";
link.type = "text/css";
link.rel = "stylesheet";
I am assuming that this way of callling ContentTools.Editor at the innermost of the nested onload is a good way of guarantee that the proper CSS and JS dependencies are properly loaded. However, when I run it as a Chrome Extension inside the contentscript, it errors out with Undefined ContentTools as referenceerror but I saw message "link loaded" and "script loaded".
Clearly, ContentTools are loaded and defined (see the screenshot). And if I execute the whole script directly in the console, everything works. Looks like the root cause is only in Chrome Extension content script, somehow the editor = ContentTools... got called before the script is fully loaded.
As it is only an error as a Chrome extension but not in the Console, I am a bit lost here. jQuery related solution is also welcome here.

Using Google API on google sites themselves (like on youtube.com for example)

What I am trying to do?
I am trying to create a small javascript snippet that would run in my browser on youtube's subscriptions page (https://www.youtube.com/feed/subscriptions) and would allow to bulk add videos I have not watched into my "Watch Later" playlist so I can binge watch them in chunks and/or on my smartTV later.
How am I trying to do it?
I am trying to use Google Youtube Data API and modify "Watch Later" playlist by calling "insert" method.
What is the issue I am getting?
In order to do everything from above one of the things is to load google api script onto the page. And that is where I am seeing issue. When I load that script (https://apis.google.com/js/api.js) on a separately hosted HTML page (or just in jsfiddle sandbox) everything works:
<script>
function handleClientLoad() {
// Load the API client and auth2 library
gapi.load('client:auth2', initClient);
}
function initClient() {
// do nothing for now
}
</script>
<script async defer src="https://apis.google.com/js/api.js" onload="handleClientLoad()"></script>
However, when I try to do the same in my userscript using tampermonkey I am getting an error.
function loadScript(url, callback)
{
console.log('load script: ' + url);
// Adding the script tag to the body
var body = document.getElementsByTagName('body')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
script.async = true;
script.defer = true;
// Then bind the event to the callback function.
script.onreadystatechange = function() {
console.log('in readyStateChange. readyState: ' + this.readyState);
callback();
};
script.onload = function() {
console.log('in onload');
this.onload = function() {};
callback();
};
// Fire the loading
body.appendChild(script);
}
function initGAPI() {
console.log('initGAPI');
gapi.load('client:auth2', initClient);
}
function initClient() {
// do nothing for now
}
loadScript('https://apis.google.com/js/api.js', initGAPI);
I can see that my user script is being successfully triggered when I navigate to https://www.youtube.com/feed/subscriptions, however when it comes to gapi.load() method I am getting this error:
Uncaught TypeError: gapi.loaded_0 is not a function
at cb=gapi.loaded_0:1
I tried to inspect what is available on youtube's page before I load my own instance of gapi and realized there is already gapi object exists there and it has only one method: load(). When I try to call that method on that existing object (without trying to load my own instance of gapi script) it:
gapi.load('client:auth2', function() {console.log('gapi loaded');})
I get error of:
GET https://apis.google.com/_/scs/abc-static/_/js/k=gapi.gapi.en.HtLvrA_npCQ.O/m=client/exm=oauth2/rt=j/sv=1/d=1/ed=1/am=AAE/rs=AHpOoo8wHQU_A1WtgGgcOpQEfGjHuD8e-g/cb=gapi.loaded_1 net::ERR_ABORTED somewhere in desktop_polymer.js (line 2661)
I see there are different callbacks engaged (gapi.loaded_0 and gapi.loaded_0). However I can't make anything of it.
I am starting to think that I can't really use Google API while on google's own site (like youtube in my case). Is that correct assumption?
Maybe there are already existing solutions that achive my goal (bulk add non-watched videos into "Watch Later" playlist) - would appreciate any pointers :)
Turned out it was just my lazy eye. I missed the fact that I load https://apis.google.com/js/api.js twice. One time through #require external dependency - feature of tampermonkey script, another time - via dynamically adding that same script to the page as per instructions I started with to onboard with Google API.
Just loading via #require doesn't really work as that doesn't trigger callback that is necessary to instantiate everything properly. So I had to remove that directive and only rely on adding script to the page dynamically. After I did that - everything started to work. So, all in all, my code I posted in question is actually valid one to use, the problem was only in how I adopted it for usage in tampermonkey userscript :)

Can jQuery.getScript show the file as a resource in Chrome Developer Tools?

My code needs to load scripts on demand.
function includeJS(uri) {
return jQuery.getScript(uri);
}
includeJS('/path/to/script.js').always(function() {
// do something after script is loaded
});
The problem, though, is that the JS file will not be available in the Chrome Developer tools like other files that were included statically on the page. Due to this I cannot easily put break points.
Is there an alternative to jQuery.getScript that will also show the script in the Chrome Developer tools with the ability to put break points?
EDIT: Adding solution based on currently accepted answer (I will still consider other solutions, but this seems to work for me)
function includeJS(uri) {
var def = $.Deferred();
var script = document.createElement('script');
script.src = uri;
script.onload = function() {
def.resolve();
}
script.onerror = function() {
def.reject();
}
document.body.appendChild(script);
return def.promise();
}
You can simply append a script tag, and use an onload handler to execute post-load actions. Example: https://jsfiddle.net/0nu2dusu/
var script = document.createElement('script');
script.src = 'my_external_script.js';
script.onload = loadHandler;
document.body.appendChild(script);
You have slightly less control over failed loads than $.getScript offers, but the script does show up in dev tools.
Actually it's always there. Just take a look at an example from the jQuery.getScript() site. Here's how it looks like: http://i.imgur.com/LMFFAag.png.
The problem with .getScript() is that it never caches files requested, so on every call it adds some random string to prevent caching (what also prevents us from debugging code). But there's workaround for that:
Set global .ajax caching (not recommended) before you call .getScript():
$.ajaxSetup({
cache: true
});
Use direct .ajax() call (recommended):
$.ajax({
dataType: "script",
cache: true,
url: url
}
If it's your own script, you can always add a debugger; command anywhere to force browser to enter the debug mode (DevTools must be opened).

Google jspai fails to load, but only for customer

My website needs to use the Google Earth plugin for just a bit longer (I know, the API is deprecated, but I'm stuck with it for several more months). I load it by including google.com/jsapi, then calling google.load like so:
...
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
</script>
</body>
</html>
This works well from multiple computers and with multiple browser inside our company's firewall. It works well from my home computer, and from my colleagues' home computers. However, when my customer tries to load it, she gets an error message that google is not defined on the line that begins google.load(.
Of course, global variable google is defined at the start of file www.google.com/jsapi, so presumably that file isn't loading. I initially assumed that her corporate firewall was blocking that file, but when I asked her to paste "https://www.google.com/jsapi" into her browser's address bar, she said that immediately loaded up a page of JavaScript.
The entire output to the browser console is:
Invalid URI. Load of media resource failed. main.html
ReferenceError: google is not defined main.html:484
And I believe the Invalid URI business is just because we don't have a favicon.ico file.
She is running Firefox 35.0.1, though she says the same error occurred with IE (she didn't mention the version of IE).
Short of asking her to install Firebug, which I don't think is going to be feasible, how can I troubleshoot this issue?
I'm really not sure with that assumption but:
Could it be, that your first script loads asynchronous? Then for slow connections (your customer) this problem would occur (i know that you are not using the async tag - but maybe the source can trigger to load async).
Best thing to do here is to make sure that the Google code you're using is the sync kind and redeploy.
Also https://bugsnag.com/ can be a really interesting tool for you. Just implement the js and you can track every error your customer gets.
Redeploy your code as follows,
<script type="text/javascript">
try {
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
} catch (e) {
$.post('http://<your-remote-debug-script-or-service>',e)
}
</script>
Then, when your customer encounters the error, the full details will be sent directly to your server and you can troubleshoot as necessary.
It could be something as simple as the clients browser is blocking javascript from being executed. Maybe specifically blocking your domain or something crazy like that.
Can you try an external script that loads the google jsapi, then put your code in the callback to ensure it is loaded?
<script type="text/javascript">
function loadScript(url, callback){
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" ||
script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others
script.onload = function(){
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
loadScript("https://www.google.com/jsapi", function(){
google.load("earth", "1", {"other_params": "sensor=false"});
google.setOnLoadCallback(function () {
// call some JavaScript to begin initializing the GE plugin
});
});
</script>
(Modified from http://www.nczonline.net/blog/2009/07/28/the-best-way-to-load-external-javascript/)
You may also want to look at jsapi Auto-Loading to minimize what is loaded, but it may get tricky with an older library. https://developers.google.com/loader/

Categories