monitoring history.pushstate from a chrome extension - javascript

I am developing a Chrome extension to tweak Facebook. However, catching browsing actions within HTML5-enabled sites such as Facebook requires an override of window.history.pushState as explained in this SO question.
Unfortunately, it seems that Chrome's isolated worlds prevent this sort of override. Is there any other method of catching history changes (other than polling document.location.href)?

Not sure whether you trying to do this in background.js or content.js, but if it is the former, you can do so using webNavigation events:
You need to set permissions for webNavigation in manifest.json:
"permissions": [
"webNavigation"
],
Then in background.js:
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details) {
console.log('Page uses History API and we heard a pushSate/replaceState.');
// do your thing
});
Source: Chrome Extension docs for webNavigation

Yes,
One way is to create a script tag and put your code there:
html = "window.history.pushState = function(a,b,c) { alert('Change !'); };";
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.innerHTML = html;
headID.appendChild(newScript);

Building on #Boris's answer: to continue with the default action, save a reference to the original pushState function, and then call it:
var headID = document.getElementsByTagName("head")[0];
var newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = chrome.extension.getURL('script.js');
headID.appendChild(newScript);
script.js:
window.history.pushState = (function(nativePushState) {
return function(a,b,c) {
// Do something
nativePushState.apply(this, arguments); //Continue by calling native history.pushState
};
})(window.history.pushState)

Related

Inject script programatically results in error 500 (LinkedIn follower plugin)

I want to insert the LinkedIn Follow Company Plugin, but only inject it, if the user has given consent.
So instead of putting in the script tags directly, I have a banner, asking for consent and if the checkbox is checked the following function runs:
function injectLinkedin() {
var linkedin_container = document.querySelector('#linkedin-follow-plugin');
var script = document.createElement("script");
script.setAttribute("src", "https://platform.linkedin.com/in.js");
script.setAttribute("type", "text/javascript");
script.setAttribute("async", "false");
script.textContent = 'lang: de_DE';
script.onload = function(){
console.log('li');
};
linkedin_container.appendChild(script);
var script2 = document.createElement("script");
script2.type = "IN/FollowCompany";
script2.setAttribute('data-id' , '1234');
script2.setAttribute('data-counter' , 'bottom');
script2.onload = function(){
console.log('li2');
};
linkedin_container.appendChild(script2);
}
But that way LinkedIn responds with an error 500 for https://platform.linkedin.com/in.js
Don't see why/how linkedin can see how the code gets loaded. Putting in the script tags directly it works fine. And, strangely, this error is not on my local machine but only on the live server.

Load external javascript after click a button

I want to load a javascript from an external source on my site, after clicking on a button.
I tried the following solution. Java script code, which is executed after clicking on the button:
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "scrSource";
document.getElementsByTagName("head")[0].appendChild(script);
So now I can see the javaScript in my head, but it was not executed.
So when I load my external script with the normal way (when the page is loading) in the header, it loads a few other java script sources.
But with my solution (load file after clicking a button), I only put it in the head and no further action is happening.
Do someone have any ideas how I can solve this problem? (and I´m not allowed to use jQuery, only java script)
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://cdnjs.cloudflare.com/ajax/libs/Faker/3.1.0/faker.min.js", function(){
//initialization code
alert('loaded: ' + faker.name.findName());
});
A simple Google search of "Load external javascript" returns this link. The function you see it is from there. It's and old one but it works.
I use Faker.js to generate random data as confirmation that the library loaded is ready to be used.
It handles onreadystatechange/onload so you can define a callback to start using the library you've just downloaded.

Javascript: best way to wait for script loaded synchonously before executing function?

I have the following problem:
I load a page inside a modal dialog. This page uses jQuery as dependency. Since I already use jQuery on the main page, for me, it is always available. Now we have the usecase, that also different pages (hosted on different domains) need to load that page if necessary.
So, I check if the jQuery variable exists on this page and if yes, just go on with my code.
If it does not exist, on top of the template, I dynamically create a script element like this:
<script>
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.src = "path/to/jQuery";
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>
And at the end of the template, I use a IIFE (to scope the jquery variable)
(function ($) {
.... code ....
})(jQuery);
However, since with this method, the script gets loaded asynchronously, sometimes I get the error: jQuery is undefined.
Now I came up by loading it synchronously, like this:
var xhrObj = new XMLHttpRequest();
// open and send a synchronous request
xhrObj.open('GET', "jquery.min.js", false);
xhrObj.send('');
// add the returned content to a newly created script tag
var se = document.createElement('script');
se.type = "text/javascript";
se.text = xhrObj.responseText;
document.getElementById('placeholder').appendChild(se);
This works fine, but the warning "Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. to the end user's experience." made me think.
However, now I changed my code and just said
if (!window.jQuery) {
document.write('<scr' + 'ipt src="jquery.js"' + '>' + '</scr' + 'ipt>');
}
on top of my Template.
Dear javascript gurus, is this a reliable solution?
Use the onload attribute in async javascript
<script async src="siteScript.js" onload="window.MyInitialisation()"></script>
In javascript it would look like this:
<script>
if(!window.jQuery)
{
var script = document.createElement('script');
script.type = "text/javascript";
script.async = "async";
script.defer = "defer";
script.onload = function() {window.MyInitialisation()}
script.src = "path/to/jQuery";
document.getElementsByTagName('head')[0].appendChild(script);
}
</script>

phonegap - dynamically adding javascript

Developing phonegap application which loads google map. Using below two javascript for google map. One javascript is loaded from locally while other javascript loaded from server.
var script = document.createElement('script');
script.src = 'http://maps.google.com/maps/api/js?sensor=true';
script.type = 'text/javascript';
document.head.appendChild(script);
script.onload = function () {
var script1 = document.createElement('script');
script1.src = 'js/jquery.ui.map.js';
script1.type = 'text/javascript';
document.head.appendChild(script1);
script1.onload = function () {
alert(google.maps.LatLng);
}
};
Both javascripts should be loaded after html page is loaded. Tried below code and referred various blogs, but its not working.
If same scripts written in header tag of html page, then it working perfectly. but in my application i need it to be loaded dynamically.
Please help....
Solved:
var doc_write = document.write; // Remember original method;
document.write = function(s) {$(s).appendTo('body')};
$.getScript('http://maps.google.com/maps/api/js?sensor=true').done(function()
{
$.getScript('js/jquery.ui.map.js').done(function()
{
document.write = doc_write; // Restore method
setTimeout(function()
{
alert(google.maps.LatLng);
},1000);
})
.fail(function(jqxhr, settings, exception)
{
alert(exception); // this gets shown
document.write = doc_write; // Restore method
});
}).fail(function()
{
alert('failed to load google maps');
});
Problem:
It takes some time to initialise.
Call your javascript function after device get ready function. Because if you are using phone gap through Xcode, the device get ready function take some time to load and your script is called before it.
Don't do it in this way
Load it in footer section of your application

Redirect from Js file depending on document location

I am using code below for for my js file for redirecting.. but i want my redirection based on top location. for example if someone visit xyz.com so it redirect to mydomain.com so what code i needed to add? i think it could be like indexOf('xyz.com')
loadScript("http://j.maxmind.com/app/geoip.js", function() {
var country = geoip_country_code();
if (country === "US") {
window.location = "http://mydomain.com/";
}
});
function loadScript(url, callback) {
// adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
// then bind the event to the callback function
// there are several events for cross browser compatibility
script.onreadystatechange = callback;
script.onload = callback;
// fire the loading
head.appendChild(script);
}
I am not totally sure I understand your question,
window.location is an object which refers to the currently displayed web page at all times. As you already know you can change window.location and cause a page change in the browser.
window.location also has several properties which help in analyzing its contents, see the referenced link for more details. window.location.host is the one you need I think.
So if I understand your question correctly, you could replace
var country = geoip_country_code();
if (country === "US") {
window.location = "http://mydomain.com/";
}
with
if (window.location.host === 'xyz.com') {
window.location = "http://mydomain.com/";
}

Categories