I'm loading dynamic javascript libraries and I want to do something after they are loaded. Using typescript + angular 8
ie.
const onLoaded = () => console.log('loaded')
const head = document.getElementsByTagName('head')[0];
const script = document.createElement('script');
script.src = 'https://somesite.com/my-lib.js';
script.type="text/javascript";
script.onload = onLoaded;
head.appendChild(script);
The onload Event works as expected in Chrome and Firefox.. and what a surprise, it doesn't in MS Edge.
I tried loading using jQuery*, adding addEventListener('load', onLoaded, false) adding onreadystatechange ... Nothing.
Anybody had similar issues? Anybody know how to fix this?
I need to add support for at least Microsoft Edge 44.18362.449.0 / Microsoft EdgeHTML 18.18363
Related
I'm looking to override the existing console commands via my Chrome extension - the reason for this is I wish to record the console logs for a specific site.
Unfortunately I cannot seem to update the DOM, this is what i've tried so far:
// Run functions on page change
chrome.tabs.onUpdated.addListener( function (tabId, changeInfo, tab) {
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('core/js/app/console.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
});
console.js
// Replace functionality of console log
console.defaultLog = console.log.bind(console);
console.logs = [];
console.log = function(){
console.defaultLog.apply(console, arguments);
console.logs.push(Array.from(arguments));
};
// Replace functionality of console error
console.defaultError = console.error.bind(console);
console.errors = [];
console.error = function(){
console.defaultError.apply(console, arguments);
console.errors.push(Array.from(arguments));
};
// Replace functionality of console warn
console.defaultWarn = console.warn.bind(console);
console.warns = [];
console.warn = function(){
console.defaultWarn.apply(console, arguments);
console.warns.push(Array.from(arguments));
};
// Replace functionality of console debug
console.defaultDebug = console.debug.bind(console);
console.debugs = [];
console.debug = function(){
console.defaultDebug.apply(console, arguments);
console.debugs.push(Array.from(arguments));
};
The script runs successfully with an alert().
The goal for me is to access console.logs - but its undefined which means I haven't gotten access to the DOM, despite injecting a script.
If not possible, even a third party integration would be helpful i.e. Java or C?
Any thoughts would be greatly appreciated :)
I found this post and I think Tampermonkey injects a script with the immediate function that you add in the Tampermonkey Chrome extension page, I found something similar in extensions like Wappalyzer, and looks good and safe, you could use WebRequest to inject to your website the new "polyfill" before the page is fully loaded as the post says.
Here the example of Wappalyzer that I mentioned before, this is the JS load in StackOverflow with Wappalyzer using the code injection, I didn't test it with Tampermonkey yet
EDIT
Checking Wappalyzer, how to inject the code is the easy part, you can use (Wappalyzer github example):
const script = document.createElement('script')
script.setAttribute('src', chrome.extension.getURL('js/inject.js'))
This probably will not fix your problem, this code is executed after all the content was loaded in the DOM. But, you can find how to fix that problem in this post
I'll suggest to use onCommitted event (doc1/doc2)
Using the mozilla.org example you will have something like
const filter = {
url: //website to track logs
[
{hostContains: "example.com"},
{hostPrefix: "developer"}
]
}
function logOnCommitted(details) {
//Inject Script on webpage
}
browser.webNavigation.onCommitted.addListener(logOnCommitted, filter);
It might be worth trying to redefine the entire console object:
const saved = window.console
window.console = {...saved, log: function(...args){ saved.log("Hello", ...args) }}
But it's probably impossible, because content scripts live in an isolated world:
Isolated worlds do not allow for content scripts, the extension, and the web page to access any variables or functions created by the others. This also gives content scripts the ability to enable functionality that should not be accessible to the web page.
Although in Tampermonkey this script works.
I believe Tampermonkey handles this by knowing the subtleties and tracking changes in the extensions host's protection mechanism.
BTW, for small tasks, there is a decent alternative to chrome extensions in the form of code snippets.
I am trying to add jQuery to my IE 11 extension. When I run it, it gives me the error
SCRIPT5007: Unable to get property _reference of undefined or null reference
on the line
E = jQuery.jstree._reference(o)
I dont understand why though, because the same extension works in Chrome and Firefox? please help. I'd appreciate any help on the matter.
console.log("1");
var jq = document.createElement('script');
jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
console.log("2");
var jq2 = document.createElement('script');
jq2.src = "http://code.jquery.com/jquery-1.11.3.js";
document.getElementsByTagName('head')[0].appendChild(jq2);
console.log("3");
console.log("hi");
appAPI.resources.includeJS('js/angular.min.js');
console.log("passed!");
this is my simple script,
<script>
window.onerror = err;
var script = document.createElement('script');
script.src = "192.186.1.1.1.1.1";
script.onerror = err;
document.body.appendChild(script);
function err(msg, loc, a, b) {
alert(msg + "/" + loc);
}
</script>
but when i load this i get,
[object Event]/undefined
when i run the same on "firebug" i get detailed error like,
NetworkError: 404 Not Found - http://localhost/XSS/192.186.1.1.1.1.1"
So how can i get a detailed error .
try-catch alos doesnt work
try {
var script = document.createElement('script');
script.src = "192.186.1.1.1";
document.body.appendChild(script);
} catch(e) {
alert(e.name);
}
does that method will work only in old browsers ?
img.src also doesnt provide fire error handler. why?
var img = new Image();
img.src="gifffff/asasa/ss" ;
Firebug is not code, but a browser diagnostic tool running on the agent's behalf. (JavaScript cannot read the result of the firebug console.)
Now, for the cases:
The Image.error event never says why the loading failed. There is no provision to include the "reason" in the HTML specification; problem solved by not being a feature to begin with.
The catch doesn't work because there was no Exception thrown by the code.
The Image is still an Image and can still be added to the DOM
regardless of if the resource (eventually) fails to load.
(The src is still set to a valid URI component - it would have thrown an exception on an invalid/unknown URI scheme.)
Having this general limitation (on any [Image] resource, even on the same origin) also prevents violation of the Same-Origin Policy - and the ability for malicious code to run various network scanning attacks.
I am running google custom search in browser it works fine. It runs fine even in emulator in Phonegap but it gives network error or it shows blank screen when the same is run on android phone. or gives this error "file:///google.com/cse?q=.... can not be found."
I am using google custom search v2 code.
The code you get for v2 of custom search looks something like this:
<script>
(function() {
var cx = 'ENGINE_ID';
var gcse = document.createElement('script');
gcse.type = 'text/javascript';
gcse.async = true;
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
'//www.google.com/cse/cse.js?cx=' + cx;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(gcse, s);
})();
</script>
<gcse:search></gcse:search>
What it roughly does is creating a tag like this:
<script type="text/javascript" src="http://www.google.com/cse/cse.js?cx=ENGINE_ID">
and inserts it before other scripts on your page. So you can skip this code altogether and manually insert the above tag (with your engine id) and only <gcse:search></gcse:search> to your HTML. If the connection from file:// to http:// is still not possible, download this script (http://www.google.com/cse/cse.js?cx=ENGINE_ID) and serve it as local javascript file.
I've encountered the same problem. An one-line change in JavaScript made the file:// error go away:
// This line must take place before initializing GCSE
window.IS_GOOGLE_AFS_IFRAME_ = true;
Verified on both iOS and Android Cordova environments.
For awhile now, a piece of javascript I wrote which listens to youtube actions on a certain page worked wonderfully. I am using Youtube's iframe js api: https://developers.google.com/youtube/iframe_api_reference .
But one recent content addition, a specific youtube video, the tracking wouldn't work. The events won't fire at all.
In the console, I noticed this post message error:
Unable to post message to http://youtube.com. Recipient has origin http://www.youtube.com.
So nothing with my own code helped. Some questions here on stackoverflow suggested this is an issue with initiating new YT.player too soon, so I tried a whole bunch of things like loading the yt js api file on window load and only apply the api after, but that didn't seem to do any good either.
I know this post is 3 years old, but for those who are still searching for an answer:
Add this script and everything works fine:
<script src="https://www.youtube.com/iframe_api"></script>
I've had the same problem with jwplayer and fixed it with that script.
It took me over an hour, but the answer was right in front of me. It's actually pretty self explained: You cannot use youtube's js api to track an iframe video without www. I don't know why, it certainly does not say so in their documentation.
I tested this a few times and confirmed, as of now, tracking an iframe with the source www.youtube.com/embed/0GN2kpBoFs4 would work wonderfully while tracking youtube.com/embed/0GN2kpBoFs4 will throw:
Unable to post message to http://youtube.com. Recipient has origin http://www.youtube.com.
The confusing part of course is that both the video load and play fine. It's only the API which is not working properly.
fiddle - http://jsfiddle.net/8tkgW/ (Tested on chrome / mountain lion)
Btw, while writing this answer I came across YouTube iframe API: how do I control a iframe player that's already in the HTML? - notice this guy's fiddle. He wrote his own youtube iframe implementation (wow!). If you change the iframe source address in the fiddle to one without www, it will work. This only means youtube writes bad js. Bad bad bad!
Don't forget to add it to the whitelist:
<!-- Add the whitelist plugin -->
<plugin name="cordova-plugin-whitelist" source="npm" spec="*"/>
<!-- White list https access to Youtube -->
<allow-navigation href="https://*youtube.com/*"/>
The youtube api documentation recommend to load the api like this
var tag = document.createElement('script');
tag.src = "http://youtube.com/iframe_api";
tag.id = "youtubeScript";
var firstScriptTag = document.getElementsByTagName('script')[1];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
But getting this error:
Unable to post message to http://youtube.com. Recipient has origin http://www.youtube.com
Here is the best solution I found from [a now-dead site]:
So add this first at the top before calling the Api
if (!window['YT']) {var YT = {loading: 0,loaded: 0};}
if (!window['YTConfig']) {var YTConfig = {'host': 'http://www.youtube.com'};}
if (!YT.loading) {YT.loading = 1;(function(){var l = [];YT.ready = function(f) {if (YT.loaded) {f();}
else
{l.push(f);}};
window.onYTReady = function() {YT.loaded = 1;for (var i = 0; i < l.length; i++) {try {l[i]();} catch (e) {}}};
YT.setConfig = function(c) {for (var k in c) {if (c.hasOwnProperty(k)) {YTConfig[k] = c[k];}}};
var a = document.createElement('script');
a.type = 'text/javascript';
a.id = 'www-widgetapi-script';
a.src = 'https:' + '//s.ytimg.com/yts/jsbin/www-widgetapi-vflumC9r0/www-widgetapi.js';
a.async = true;
var b = document.getElementsByTagName('script')[0];
b.parentNode.insertBefore(a, b);})();}
//===========THEN=============================
function onYouTubeIframeAPIReady () {// do stuff here}