Working with multiple HTML files in Chrome extension - html

I have the following question:
I am writing a chrome extension that works with context menu over text selection. one of the things that I want to do is to create a new tab that is based on one of my html files that I create dynamically using the data I received at the text selection.how do I communicate between my javascript file that is connected to my background.html and my other html file in order to get to its' DOM and alternate it's contents?
my manifest.json:
{
"name": "My flickr Extension",
"version": "1.0",
"description": "The first extension that I made.",
"icons": {
"16": "icon.png"},
"background_page":"background.html",
"permissions": ["tabs",
"http://api.flickr.com/","contextMenus","http://*/*","https://*/*"
]
}
my background.html:
<script src="ext.js"></script>
my ext.js main functions:
function searchSelection(info,tab){
var updated=makeNewString(info.selectionText);
var xhReq = new XMLHttpRequest();
xhReq.open(
"GET",
"http://api.flickr.com/services/rest/?method=flickr.photos.search&text="+updated+"&api_key=a0a60c4e0ed00af8d70800b0987cae70&content_type=1&sort=relevance",
true);
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
if (xhReq.status == 200) {
var photos = xhReq.responseXML.getElementsByTagName("photo");
var urlOfNew=chrome.extension.getURL('results.html');//this is me getting the link of the other html page that i want to update
//here I want to manipulate the results.html DOM like adding images depending on the photos and other stuff
chrome.tabs.create({"selected":true,"url":urlOfNew});
}
};
};
xhReq.send(null);
}
var context="selection";
var id = chrome.contextMenus.create({"title": "search Flickr", "contexts":[context],"onclick":searchSelection});

Take a look at Message Passing, http://code.google.com/chrome/extensions/messaging.html, it has detailed examples on how to send messages from Content Script to Extension Page.
Since you are just communicating in the same page (background page), why are you having any trouble? You can just use normal JavaScript to pass variables around.

Related

how to access IndexedDB (of current opened domain/tab) from chrome extension

I currently have indexedDB on google.com domain. i want to be able to read it from google chrome extension. how can i accomplish this? do i need to add any specific permissions?
i currently have:
"permissions": [ "tabs", "bookmarks", "unlimitedStorage", "*://*/*", "identity", "https://*.google.com/*", "https://ssl.gstatic.com/", "https://www.googleapis.com/", "https://accounts.google.com/" ],
with what command i can do this? thank you!
Edit: i have readed i can access it from content script(aslong as the tab with domain is open - which is my case), but i dont know how to do that...
To access indexeddb of current tab add "activeTab" to "permissions" tag in manifest.json, Then create a content script, content script will be helpful in accessing the indexeddb as it runs in context of webpages, then add the content script created to the "content_scripts" tag in manifest.json file.
For Eg in manifest.json add the following:
"permissions": ["activeTab"],
"content_scripts": [
{
"matches": ["add the domains of the webpages where content script needs to run"],
"js": ["contentScript.js"]
}
]
For more info on matches check out here: https://developer.chrome.com/extensions/match_patterns
.
Inside content script add open the store and then perform transaction on the object store and perform queries on the object store.
For Eg in content script add following:
if (!('indexedDB' in window)) {
alert("This browser doesn't support IndexedDB");
} else {
let indexdb = window.indexedDB.open('firebaseLocalStorageDb', 1);
indexdb.onsuccess = function () {
let db = indexdb.result;
let transaction = db.transaction('firebaseLocalStorage', 'readwrite');
let storage = transaction.objectStore('firebaseLocalStorage');
console.log(storage.getAll());
};
}
Explanation of the above code:
It accesses the window object and opens the store "firebaseLocalStorageDb" with version "1", then after successfully accessing the object it looks for the result and performs transaction on the objectstore "firebaseLocalStorage" residing inside the store. Finally query the instance of objectstore "storage" to get all the key-value pairs.
For more info check: https://javascript.info/indexeddb
For anyone still interested, my solution to this problem -
this is placed in content script of extension -
chrome.extension.onConnect.addListener(function(port) {
if(port.name == "extension_request" ) {
port.onMessage.addListener(function(msg) {
if (msg.db) {
window.indexedDB.webkitGetDatabaseNames().onsuccess = function(sender,args)
{
var r = sender.target.result;
if(r.contains(msg.db)){
var openRequest = indexedDB.open(msg.db);
// your code
port.postMessage({foo: bar}); // your result which you want to send
}
}
}
}
}
and this is for background or popup script -
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var port = chrome.tabs.connect(tabs[0].id,{name: "extension_request"});
port.postMessage({db: "database_name_example"}); // send database name
port.onMessage.addListener(function(msg) {
if (msg.foo ) {
// do your stuff in extension
}
}
}

Chrome extension push notifications on signalR event

I'm working on building an chrome extension that communicates with an external SignalR HUB on server side.
I've managed to configure both to communicate with one another if I write the JS code in the pop-up page, the problem with this method is that if the extension is not opened, then it can't get updates (doesn't respond to the raised event).
In order to solve it I read that I should write my event handlers in the background.js, so even if the extension pop up is not showing - it would still respond to the event. However, I still need to support a button click on my extension to fire an event - which after reading a bit more is not possible cause I don't have access to the DOM in a background file.
So my question is how do I tackle this issue? how can I, from the client side call a function (or make ajax requests) in the server SignalR HUB? and also receive a response from the server when the popup is not opened.
By response I mean a to update values in the background.js and a simple +1 to the value in the icon badge, Something that will notify the user that something happened.
I'm very new to chrome extensions so I would appreciate the help!
This is my current code:
manifest.json
{
"manifest_version": 2,
"name": "Getting started ex1ample",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"background": {
"scripts": ["jquery-2.1.4.min.js", "jquery.signalR-2.2.0.min.js", "background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"http://localhost:61275/"
]
}
background.js
var singalR = {};
$(document).ready(function(){
singalR.connection = $.hubConnection('http://localhost:61275/signalr/hubs', {useDefaultPath: false});
singalR.connection.logging = true;
singalR.roomIndexHubProxy = singalR.connection.createHubProxy('roomIndexHub');
singalR.connection.start().done(function() {
// Wire up Send button to call RoomIndexHubProxy on the server.
console.log('Hub has started');
$("#btn-join").click(function(){
singalR.roomIndexHubProxy.invoke('test', 111);
});
});
singalR.connection.error(function (error) {
console.log('SignalR error: ' + error)
});
singalR.roomIndexHubProxy.on('test', function (val) {
chrome.browserAction.setBadgeText({ text: val } );
});
});
popup.html
<!doctype html>
<html>
<head>
<script src="popup.js"></script> //empty for now
</head>
<body>
<button id="btn-join">Join</button>
</body>
</html>
Server Side HUB
public class RoomIndexHub : Hub
{
static int val = 0;
public RoomIndexHub(){
}
public async Task test(int k)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<RoomIndexHub>();
val++;
await Task.Delay(4000);
hubContext.Clients.All.test(val.ToString());
}
}
Have you tried setting the lifetime of your background page? Set persistence to true so this hidden page in background will "live" all the time and is able to listen to incoming requests.
"background": {
"scripts": ["background.js"],
"persistent": true
},
This will give you a persistent background page.
Check this: Chrome documentation for event pages
Reards
Carsten

how to show the notification on certain websites extension page action

I'm developing an extension page action that works on certain websites I want to add a notification whenever the user visits the website specific i'm not satisfied just with the icon in the address bar, how do the notification appears when the user accesses the specific site ?
I have these codes
background, to show the icon in specific sites in the address bar
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (~tab.url.indexOf('specificsite.com.br')) {
chrome.pageAction.show(tabId);
}
});
Code for notification
createNotification();
audioNotification();
function audioNotification(){
var yourSound = new Audio('alert.mp3');
yourSound.play();
}
function createNotification(){
var opt = {type: "basic",title: "Your Title",message: "Your message",iconUrl: "128.png"}
chrome.notifications.create("notificationName",opt,function(){});
//include this line if you want to clear the notification after 5 seconds
setTimeout(function(){chrome.notifications.clear("notificationName",function(){});},10000);
}
You can use message passing to get it done by content scripts to detect the switch on certain websites, then notify the background page in order to display the notification for that page. Your content script should send a message using chrome.runtime.sendMessage, and the background page should listen using chrome.runtime.onMessage.addListener:
I created the sample code and tested it works with me:
Content script(myscript.js):
if(onCertainWebsitesNeedNotificationAppearTrue) {
// send message to background script
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
});
}
Background page:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
//alert("good");
if (request.greeting == "hello")
createNotification();
});
function createNotification(){
var opt = {type: "basic",title: "Your Title",message: "Your message",iconUrl: "128.png"}
chrome.notifications.create("notificationName",opt,function(){});
//include this line if you want to clear the notification after 5 seconds
setTimeout(function(){chrome.notifications.clear("notificationName",function(){});},10000);
}
Also keep in mind to register your content script's code and permissions in manifest like:
"permissions": ["notifications"],
"content_scripts": [
{
"matches": ["http://www.certainwebsiteone.com/*", "http://certainwebsitetwo.com/*"],
"js": ["myscript.js"]
}
]

access iframe content from a chrome's extension content script

I'm doing a plugin to do some transformations to the interface. I keep getting unsafe javascript attempt to access frame with url.... Domains, protocols and ports must match (typical cross site issue)
But being an extension it should have access to the iframe's content http://code.google.com/chrome/extensions/content_scripts.html ...
Doesn anyone know how to access it's contents so they can be capturable?
There's generally no direct way of accessing a different-origin window object. If you want to securely communicate between content scripts in different frames, you have to send a message to the background page which in turn sends the message back to the tab.
Here is an example:
Part of manifest.json:
"background": {"scripts":["bg.js"]},
"content_scripts": [
{"js": ["main.js"], "matches": ["<all_urls>"]},
{"js": ["sub.js"], "matches": ["<all_urls>"], "all_frames":true}
]
main.js:
var isTop = true;
chrome.runtime.onMessage.addListener(function(details) {
alert('Message from frame: ' + details.data);
});
sub.js:
if (!window.isTop) { // true or undefined
// do something...
var data = 'test';
// Send message to top frame, for example:
chrome.runtime.sendMessage({sendBack:true, data:data});
}
Background script 'bg.js':
chrome.runtime.onMessage.addListener(function(message, sender) {
if (message.sendBack) {
chrome.tabs.sendMessage(sender.tab.id, message.data);
}
});
An alternative method is to use chrome.tabs.executeScript in bg.js to trigger a function in the main content script.
Relevant documentation
Message passing c.runtime.sendMessage / c.tabs.sendMessage / c.runtime.onMessage
MessageSender and Tab types.
Content scripts
chrome.tabs.executeScript
I understand that this is an old question but I recently spent half a day in order to solve it.
Usually creating of a iframe looks something like that:
var iframe = document.createElement('iframe');
iframe.src = chrome.extension.getURL('iframe-content-page.html');
This frame will have different origin with a page and you will not be able to obtain its DOM. But if you create iframe just for css isolation you can do this in another way:
var iframe = document.createElement('iframe');
document.getElementById("iframe-parent").appendChild(iframe);
iframe.contentDocument.write(getFrameHtml('html/iframe-content-page.html'));
.......
function getFrameHtml(htmlFileName) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", chrome.extension.getURL(html/htmlFileName), false);
xmlhttp.send();
return xmlhttp.responseText;
}
.......
"web_accessible_resources": [
"html/htmlFileName.html",
"styles/*",
"fonts/*"
]
After that you can use iframe.contentDocument to access to iframe's DOM

Capture link a user clicks on a page

I am playing around with making an extension. If a user has the extension installed, I would like to capture the link they clicked on a web page. Not quite sure how to do this, but it seems simple. I might add, I would like this to happen as long as the plugin is installed and enabled, but DON'T want the user to have to do anything in the toolbar to 'activate' it.
Not sure how to start. And I figure I have one too many JS files, but just trying to get one of them to log to the console. Neither do. My end goal is I would like to redirect them to an intranet page if they go to certain places.
background.js
var redirectedSites = ["https://www.facebook.com/profile.php?id=<SOMEPROFILEID>"];
// when the browser tries to get to a page, check it against a list
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
console.log('is this even getting hit?');
for(var i=0; i < redirectedSites.length; ++i) {
// if the attempt is to a listed site, redirect the request
if( details.url == redirectedSites[i] )
return {redirectUrl: "http://intranet/landing?from=" + details.url };
}
},
{urls: ["*://www.facebook.com/*"]},
["blocking"]
);
manifest.json
{
"name": "Capture Click",
"version": "0.1",
"description": "Simple tool that logs clicked links.",
"permissions": [
"tabs",
"webRequest",
"webRequestBlocking",
"https://*.facebook.com/*"
],
"background": {
"scripts": ["background.js"]
},
"manifest_version": 2
}
I've given some advice in the comments, but the best way to solve your actual larger problem is with a webRequest handler:
var redirectedSites = ["http://www.google.com/foobar", ...];
// when the browser tries to get to a page, check it against a list
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
for(var i=0; i < redirectedSites.length; ++i) {
// if the attempt is to a listed site, redirect the request
if( details.url == redirectedSites[i] )
return {redirectUrl: "http://intranet/landing?from=" + details.url };
}
},
{urls: ["*://www.google.com/*"]},
["blocking"]);
This is a really simple example, but I hope you get the idea. Here, details.url is the page the user is trying to get to, and the returned object has a redirectUrl property that redirects the attempt to visit the page. My example checks details.url against a list of target sites; you could use a regex or something else that's more robust.
Note that this will affect not only clicked links and typed-in URLs, but also resources (scrips, images) and Ajax requests.