How to access google chrome extension from any page's javascript - google-chrome

I am trying to figure out how can I call into my extension from a normal web page.
All documentation that I find seems to be either for communication between extensions, or between content scripts and extensions.
Any pointers are much appreciated!

I think you should make a content script, that injects an object into your page that calls your extension.
Create a content script that injects YourExt.js into every page, which should contain:
var YourExt = {
doThis: function () {
chrome.extension.sendRequest('doThis');
},
doThat: function () {
chrome.extension.sendRequest({
action: 'doThat',
params: ['foo','bar']
});
}
}

While extensions can't access page variables and vice versa, you can communicate between page and extension through events. Here is a quick example of creating custom events:
function fireEvent(name, target) {
//Ready: create a generic event
var evt = document.createEvent("Events")
//Aim: initialize it to be the event we want
evt.initEvent(name, true, true); //true for can bubble, true for cancelable
//FIRE!
target.dispatchEvent(evt);
}
function foobar() {
alert("foobar");
}
function testEvents() {
window.addEventListener("foobar", foobar, false); //false to get it in bubble not capture.
fireEvent("foobar", document);
}
(taken from here)
So if you need to pass information from a page to an extension, you would need to fire a custom event on a page which you will be listening to in your content script.

Related

Polymer + page.js flash notifications with paper-toast

I'm building a mid sized app with Polymer and used the Polymer Starter Kit to kick things off which uses page.js for routing.
I want to implement flash message functionality using the paper-toast element.
In other technologies/frameworks this is implemented by checking to see if a property exists when the route is changed.. if it does, it shoes the relevant flash/toast message.
How... with Polymer & Page.js is it possible to replicate this type of functionality? Page.js doesn't seem to have any events for changed routes.
The only way I can think is to create a proxy function for the page('/route') function that I have to call every time I want to go to a new page which then calls the actual page function. Is there a better way?
I've implemented this like follows for the time being... seems to be ok but if anyone can suggest improvements let me know.
In routing.html
window.addEventListener('WebComponentsReady', function() {
// Assign page to another global object
LC.page = page;
// Define all routes through this new object
LC.page('/login', function () {
app.route = 'login';
app.scrollPageToTop();
});
....
//implement remaining routes
// page proxy... to intercept calls
page = function(path) {
// dispatch event
document.dispatchEvent(new Event('LC.pageChange', {path: path}));
// call the real page
LC.page(path);
};
});
Then where you want to listen.. in my case in a lc-paper-toast element added to the index.html file of the app I can now listen to when the page is changed...
ready: function() {
document.addEventListener('LC.pageChange', function(e){
console.log('page change' , e);
}, false);
}
Only thing to be aware of is that all page changes must be called with page('/route') otherwise it won't go through the proxy.

How do you detect that a script was loaded *and* executed in a chrome extension?

I've been tracking down a bug for days... then I realized the bug was me. :/
I had been using webRequest.onComplete, filtered for scripts. My error was that I made the incorrect association between the scripts being loaded and being executed. The get loaded in a different order than they get executed, and thus the timing of the events is not in the order I need them in. I need to inject between certain scripts so I need an event right after a file has been executed and before the next one.
The only solution I can think of at the moment is to alter the JS being loaded before it gets executed. But it makes my stomach turn. And the bfcache would wreak even more havoc, so not a great solution either.
I would use the HTML5 spec's afterscriptexecute, but that is not implemented in Chrome. Is there another API, perhaps an extension API that I can use?
Note: This method no longer works as of Chrome 36. There are no direct alternatives.
Note: The answer below only applies to external scripts, i.e. those loaded with <script src>.
In Chrome (and Safari), the "beforeload" event is triggered right before a resource is loaded. This event allows one to block the resource, so that the script is never fetched. In this event, you can determine whether the loaded resource is a script, and check whether you want to perform some action
This event can be used to emulate beforescriptexecute / afterscriptexecute:
document.addEventListener('beforeload', function(event) {
var target = event.target;
if (target.nodeName.toUpperCase() !== 'SCRIPT') return;
var dispatchEvent = function(name, bubbles, cancelable) {
var evt = new CustomEvent(name, {
bubbles: bubbles,
cancelable: cancelable
});
target.dispatchEvent(evt);
if (evt.defaultPrevented) {
event.preventDefault();
}
};
var onload = function() {
cleanup();
dispatchEvent('afterscriptexecute', true, false);
};
var cleanup = function() {
target.removeEventListener('load', onload, true);
target.removeEventListener('error', cleanup, true);
}
target.addEventListener('error', cleanup, true);
target.addEventListener('load', onload, true);
dispatchEvent('beforescriptexecute', true, true);
}, true);
The dispatch times are not 100% identical to the original ones, but it is sufficient for most cases. This is the time line for the (non-emulated) events:
beforeload Before the network request is started
beforescriptexecute Before a script executes
afterscriptexecute After a script executes
onload After the script has executed
Here's an easy way to see that the events are working as expected:
window.addEventListener('afterscriptexecute', function() {
alert(window.x);
});
document.head.appendChild(document.createElement('script')).src = 'data:,x=1';
document.head.appendChild(document.createElement('script')).src = 'data:,x=2';
The demo can be seen live at http://jsfiddle.net/sDaZt/
I'm not familiar with Chrome Extensions (only browser javascript), but I think that you will unfortunately have to edit your loaded JS so that is calls a function of your choice when it is executed, if you want to do this nicely. This it what Google does for asynchronously loading its Maps Javascript file:
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?sensor=false&callback=executed";
document.body.appendChild(script);
}
function executed() {
/* Google maps has finished loading, do awesome things ! */
}
If you really don't want to edit your loaded JS files, you could have a setInterval (or a recursive function with setTimeout) checking regularly if some functions or variables are initialized.
Have you tried script loading using Modernizr.js?
I had a similar issue, where the timing of script loading was causing conflict. I used Modernizr.js, which includes the library yepnope.js by default. Below is an example of some scripts I loaded conditionally. You can include a test clause, or simply load them in the order you prefer, with the guarantee that they will load and execute in the order you wish due to the callback.
Here is an example with a conditional clause:
Modernizr.load({
test: false, //Or whatever else you'd like. Can be conditional, or not so conditional
yep: {
'script1': 'MyJavascriptLibrary1.js'
},
nope: {
'script2': 'MyJavascriptLibrary2.js',
'script3': 'MyJavascriptLibrary3.js'
},
callback: {
'script1': function (url, result, key) {
console.log('MyJavascriptLibrary1.js loaded'); //will not load in this example
},
'script2': function (url, result, key) {
console.log('MyJavascriptLibrary2.js loaded first');
},
'script3': function (url, result, key) {
console.log('MyJavascriptLibrary3.js loaded second');
}
}
});
If triggering false, MyJavascriptLibrary2.js and MyJavascriptLibrary3.js will load in the appropriate order, no matter what elements influence how they would behave normally (file size, connection speed, etc.). In these callbacks, you may fire additional javascript as well, in the order you wish to do so. Example:
'script2': function (url, result, key) {
alert('anything in here will fire before MyJavascriptLibrary3.js executes');
},
Note this can be done without Modernizr.load({...
but using simply yepnope({...
For more documentation, check out the yepnope.js API

Chrome Extension: Insert a clickable image using a content script

I know hat it is possible, but I am not quite sure how to do it the 'right' way, as to ensure there are no conflicts.
I came across this question: Cannot call functions to content scripts by clicking on image . But it is so convoluted with random comments that it's hard to understand what the corrected way was.
Use case:
Html pages have a div on the page where they expect anyone using the Chrome extension to inject a picture. When users click on he picture, I want to somehow notify an event script. So I know I need to register a listener so the code inserted messages the event script.
Can I get some indication on what code to inject through the content script? I saw that sometimes injecting jquery directly is advised.
I am trying to avoid having the html page to post a message to itself so it can be intercepted. Thanks
With the help of Jquery something like this would capture the image onclick event and allow you to pass a message to a background page in the Chrome Extension:
$("img").click(function(){
var imageSrc = $(this).attr("src");
//Post to a background page in the Chrome Extension
chrome.extension.sendMessage({ cmd: "postImage", data: { imgSrc: imageSrc } }, function (response) {
return response;
});
});
Then in your background.js create a listener for the message:
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.cmd == "postImage") {
var imageSrc = request.data.imgSrc;
}
});

jQuery Does Not Run <script> When AJAX $.load() Method Called by Click Event

I've been struggling with this for a while and can't figure it out. Hopefully it's something obvious that I missed.
Here's the code:
$(document).ready(function() {
$('#clickbox').load('eventpage/clicks.html.php #click2', function () {
console.log('click2 loaded');
$(this).hide()
.fadeIn(3000);
$('#click2').click(function(e) {
e.preventDefault();
console.log('click2 clicked');
$('#bizdev').load('pagewithscripttags.php', function (data) {
console.log(data);
console.log('#bizdev is loaded, but scripts are not run');
$('#bizdev').hide();
console.log('bizdev hidden');
});
$('#content').hide();
$('#bizdev').show();
});
});
When I run this (from an external js file), the file 'pagewithscripttags.php' is loaded into the DOM on the click event, but the scripts are not executed and I can't figure out why. HELP!
However, when I move the load method into the callback function of the first load, the file is inserted into the DOM and the scripts are run:
$(document).ready(function() {
$('#clickbox').load('eventpage/clicks.html.php #click2', function () {
console.log('click2 loaded');
$(this).hide()
.fadeIn(3000);
$('#bizdev').load('pagewithscripttags.php', function (data) {
console.log(data);
console.log('#bizdev loaded and scripts are run');
$('#bizdev').hide();
console.log('#bizdev hidden');
});
$('#click2').click(function(e) {
e.preventDefault();
console.log('click2 clicked');
$('#content').hide();
$('#bizdev').show();
});
});
Why do the scripts run as part of the callback function, but not on the click event (which is when I need them to run)?
Here are the contents of pagewithscripts.php:
<script>console.log('this script was run');</script>
<script type="IN/MemberProfile" data-id="http://linkedin.com/publicprofileurl" data-format="inline" width='106px' data-related="false"></script>
The first script is run and appears on the console.log, but the second is just inserted into the DOM without being run, except when I place the .load() method outside of the click handler.
(I need to load the scripts on the click event because they take several seconds to run (they call the LinkedIn API) and there's freezing/lag when I run them on document ready.)
You probably need to tell the LinkedIn framework to re-scan the page.
IN.parse(domNode)
This is covered on the JavaScript API reference document on events here:
https://developer.linkedin.com/documents/inauth-inevent-and-inui
Load the script datatype
http://api.jquery.com/jQuery.getScript/
Actually jQuery 'click()' function will not handle the 'click' event of dynamic elements, so try on() or live() functions to make your code working fine, using these functions you can move the click handler code out of the first load() callback.
FYI: Try to replace your $('#click2').click(function(e) { code with this $('#click2').live("click", function(e) { code.
Note: 'live()' function is deprecated from the jQuery version 1.7 onwards.
If you are not clear to use these functions then just provide your full page source so that I can check and adjust your code accordingly.

chrome extension API for refreshing the page

Is there an API to programmatically refresh the current tab from inside a browser action button? I have background page configured, which attaches a listener via:
chrome.browserAction.onClicked.addListener(function(tab) { ... });
So the callback function retrieves a reference to the tab that it was clicked from, but I don't see an API anywhere to refresh/reload that tab.
I think what you're looking for is:
chrome.tabs.reload(integer tabId, object reloadProperties, function callback)
Check out tabs API() documentation for more information.
The API for chrome.tabs.getSelected(), which the accepted answer uses, has been deprecated. You should instead get the current tab and reload it using something like the following:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(arrayOfTabs[0].id, {code: code});
});
Or perhaps:
chrome.tabs.query({active: true, currentWindow: true}, function (arrayOfTabs) {
chrome.tabs.reload(arrayOfTabs[0].id);
});
I had no real luck with the second version, though other answers seem to suggest it should work. The API seems to suggest that, too.
I recommend using chrome.tabs.executeScript to inject javascript that calls window.location.reload() into the current tab. Something like:
chrome.tabs.getSelected(null, function(tab) {
var code = 'window.location.reload();';
chrome.tabs.executeScript(tab.id, {code: code});
});
Reference here
More specifically:
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.reload(tab.id);
});
You can also use this:
chrome.tabs.reload(function(){});
reload function params: integer tabId, object reloadProperties,
function callback
Reference: http://developer.chrome.com/extensions/tabs.html#method-reload
if you want to reload all the tabs which have loaded completely and are active in their window
chrome.tabs.query({status:'complete'}, (tabs)=>{
tabs.forEach((tab)=>{
if(tab.url){
chrome.tabs.update(tab.id,{url: tab.url});
}
});
});
you can change the parameter object to fetch only active tabs as {status:'complete', active: true} refer to query api of chrome extensions
Reason for not using chrome.tabs.reload :
If the tab properties especially the tab.url have not changed, tab does not reload. If you want to force reload every time, it is better to update the tab URL with its own tab.url which sends the event of the change in property and tab automatically reloads.