So, I've been back and forth with this problem. What I want is to execute som piece of code (in a injected.js file) when a button is pressed on the website. I want to run code that I've written myself.
This should be do-able? I've looked it up, and this is taken from the developer docs:
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
As can be seen in the example, also found on the same page (http://developer.chrome.com/extensions/content_scripts.html#execution-environment) I should be able to attach a click event to something and the execute code from the same .js file when that button is clicked? Right?
Anyway, here's the code I've written:
$sidebar = $('<div><div></div></div>')
.css('background', '#eee')
.css('width', '20%')
.css('position', 'fixed')
.css('right', '0px')
.css('top', '0px')
.css('height', '100%');
$form = $('<br/><center><div class="input-append">\
<input class="span2" id="add_cat_input" type="text">\
<button class="btn" type="button">Add category</button>\
</div>\
<div class="input-append"><select id="categories">\
<option>A</option>\
<option>B</option>\
<option>C</option>\
<option>D</option>\
<option>E</option>\
</select>\
<button class="btn" type="button">Edit</button><button class="btn" type="button">Delete</button>\
</div></center>');
$('body').prepend($sidebar);
$sidebar.append($form);
$(document).ready(function() {
console.log(document.getElementById("add_cat_input"));
document.getElementById("add_cat_input").addEventListener("click", function() {
console.log('hej');
}, false);
});
But nothing happends when I press 'Add category'.
Can anyone explain why? Am I doing it wrong?
The code above is from myscript.js.
Here is my manifest.json
{
"name" : "Ď€Spend",
"version" : "0.1",
"description" : "Creates a piechart of the spendings in your bankaccount.",
"permissions": [ "cookies", "tabs", "http://*/*", "contextMenus" ],
"icons": { "16": "cookie.png", "48": "cookie.png", "128": "cookie.png" },
"browser_action": {
"default_icon": "cookie.png",
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"manifest_version": 2,
"content_scripts": [
{
"matches": ["https://internetbanken.privat.nordea.se/*"],
"css": [ "bootstrap.min.css" ],
"js": ["jquery.js", "raphael-min.js", "g.raphael-min.js", "g.pie-min.js", "myscript.js"]
}
]
}
On the way I tried to use some form of message posting instead, but this line:
var port = chrome.extension.connect();
Gets me this error:
Port error: Could not establish connection. Receiving end does not exist.
The element add_cat_input which is bound to click listener - is NOT a button, but a text field. The button "Add category" does not have an id in your code.
Related
I'm working on a Google Chrome extension that stores some values in local storage when a context menu item is clicked. I'm noticing however, that the behavior of the extension is different depending on if is being inspected or not. An example plugin is as follows:
manifest.json
{
"manifest_version": 2,
"name": "contextMenuTest",
"description": "contextMenuTest",
"version": "0.1",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"storage",
"unlimitedStorage",
"contextMenus",
"notifications"
],
"icons": {
"16": "icon.png"
}
}
popup.html
<!doctype html>
<html>
<head>
<script src= "popup.js"></script>
</head>
<body>
<button id="setContextMenuButton">Set context menu</button>
<button id="showResultButton">Show Answer</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("setContextMenuButton").addEventListener("click", onsetcontextmenubuttonclick);
document.getElementById("showResultButton").addEventListener("click", onshowresultbuttonclick);
});
function onsetcontextmenubuttonclick() {
chrome.storage.local.clear(function() {
chrome.contextMenus.removeAll(function() {
chrome.contextMenus.create(
{
"title": "test",
"contexts": ["selection"],
"onclick": function(info, tab) {
chrome.storage.local.set({"test":"test"});
}
}
);
});
});
}
function onshowresultbuttonclick() {
chrome.storage.local.get("test", function(items) {
console.log(items);
});
}
The expected behavior occurs when inspecting the popup: inspect the popup, click the "Set Context Menu" button, select some text and right click it, click "test" in the context menu, then inspect the popup and click the "Show Answer" button. chrome.storage.local.set() set the value for "test", so chrome.storage.local.get() is able to retrieve it properly and display {test: "test"}.
However, when carrying out the same steps without the first step of inspecting the popup, {} is displayed instead, implying that chrome.storage.local.set() did not properly set the value for "test" when the popup was not being inspected.
There is a similar question here, but it didn't quite answer my question.
Why would the context menu behave differently depending on if the plugin is being inspected or not, and how would I fix this?
I am currently writing a Google chrome extension that needs to run on YouTube videos. I have a content script which is a JavaScript file that does all the work I need it to do.
It is working fine, the only caveat is that for some reason, whenever you click a link to go to a new video, it doesn't run the JavaScript code immediately; you need to reload the page to make it work.
manifest.json
{
"name": "Title",
"description": "description",
"version": "0.5",
"permissions": [
"webNavigation",
"activeTab",
"tabs",
"*://*.youtube.com/*"
],
"browser_action": {
"default_icon": {
"16": "image.png"
},
"default_title": "name",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["*://*.youtube.com/*"],
"js": ["blocker.js"],
"run_at": "document_end"
}
],
"manifest_version": 2
}
blocker.js
myfunction();
function myfunction(){
//manipulate the HTML DOM
}
myfunction();
function myfunction(){
//manipulate the HTML DOM
}
You can put a time interval to detect that the URL changes
var currentURL = location.href;
setInterval(function() {
if(location.href != currentURL) {
myfunction();
currentURL = location.href
}
}, 100);
but I use this
var currentURL = location.href;
window.onclick=function(){
if(currentURL!==location.href){
myfunction();
currentURL = location.href
/*some code*/
}
}
HTML5 introduces a hashchange event which allows you to register for notifications of url hash changes without polling for them with a timer.
window.onhashchange = function (event) {
console.log(location.hash, event.oldURL, event.newURL);
myfunction();
}
I am writing my First Chrome Plugin and I just want to get some text present on the current webpage and show it as a alert when i click the Extension. Lets say I am using any any webpage on www.google.com after some Search query, Google shows something like "About 1,21,00,00,000 results (0.39 seconds) " . I want to show this Text as an alert when i execute my plugin. This is what i am doing.
here is the manifest.json that i am using
{
"manifest_version": 2,
"name": "Getting started example",
"description": "This extension shows a Google Image search result for the current page",
"version": "1.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["*://*.google.com/*"],
"js": ["content.js"]
}],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
Here is my popup.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("checkPage").addEventListener("click", handler);
});`
function handler() {
var a = document.getElementById("resultStats");
alert(a.innerText); // or alert(a.innerHTML);
}
Here is my content.js
// Listen for messages
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
// If the received message has the expected format...
if (msg.text === 'report_back') {
// Call the specified callback, passing
// the web-page's DOM content as argument
sendResponse(document.all[0].outerHTML);
}
});
Here is my background.js
var urlRegex = /^https?:\/\/(?:[^./?#]+\.)?google\.com/;
// A function to use as callback
function doStuffWithDom(domContent) {
console.log('I received the following DOM content:\n' + domContent);
}
// When the browser-action button is clicked...
chrome.browserAction.onClicked.addListener(function (tab) {
// ...check the URL of the active tab against our pattern and...
if (urlRegex.test(tab.url)) {
// ...if it matches, send a message specifying a callback too
chrome.tabs.sendMessage(tab.id, {text: 'report_back'}, doStuffWithDom);
}
});
1) run content scrip after document ready ** check "run_at"
"content_scripts": [{
"run_at": "document_idle",
"matches"["*://*.google.com/*"],
"js": ["content.js"]
}],
2) on click of extension make another js to run( popup js). The popup js has access to the ( open page document)
// A function to use as callback
function doStuffWithDom() {
//console.log('I received the following DOM content:\n' + domContent);
//get tabID when browser action clicked # tabId = tab.id
chrome.tabs.executeScript(tabId, {file: "js/popup.js"});
}
3) In popup JS simple you can set alert
var a = document.getElementById("resultStats");
alert(a.innerText); // or alert(a.innerHTML);
Just remove "default_popup" part in manifest.json, as you have listened to chrome.browserAction.onClicked event in background page. They can't live at the same time.
I made an Extension for Firefox that random check all radio buttons & checkboxes on a website. Now I will make it for Chrome.
JS (inject.js):
function randomFromTo(from, to){
return Math.floor(Math.random() * (to - from + 1) + from);
}
function autoFill () {
for (i = 0; i < document.forms.length ;i++) {
for (j = 0; j < document.forms[i].length ;j++) {
if (document.forms[i].elements[j].type == "radio") {
start = j;
lastName = document.forms[i].elements[j].name;
while (j < document.forms[i].length - 1 && lastName == document.forms[i].elements[j+1].name) {
j++;
}
rand = randomFromTo(start, j);
document.forms[i].elements[rand].checked = true;
}
if (document.forms[i].elements[j].type == "checkbox") {
start = j;
lastName = document.forms[i].elements[j].name;
while (j < document.forms[i].length - 1 && lastName == document.forms[i].elements[j+1].name) {
j++;
}
rand = randomFromTo(start, j);
document.forms[i].elements[rand].checked = true;
}
}
}
}
autoFill();
So I read a lot about inject.js and Content Scripts so I tried both. And made it like this.
{
"name": "Auto Check Radio \u0026 Checkbox",
"version": "0.0.1",
"manifest_version": 2,
"description": "",
"homepage_url": "",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"default_locale": "en",
"background": {
"page": "src/bg/background.html",
"persistent": true
},
"browser_action": {
"default_icon": "icons/icon16.png",
"default_title": "Autocheck",
"default_popup": "src/browser_action/browser_action.html"
},
"permissions": [
"tabs",
"notifications",
"http://*/",
"http://*/*",
"https://*/*"
],
"content_scripts": [{
"matches": ["https://*/*", "http://*/*"],
"js": ["src/inject/inject.js"],
"run_at": "document_end"
}],
"web_accessible_resources": ["src/inject/inject.js"],
"js": ["src/inject/inject.js"]
}
]
}
But I've got no idea how I can run the code. On Firefox it is much easier.
I don't need any background.html or browser_action.html
I only want to run the script - in the current tab - by clicking the icon.
Chould anyone give me a tip where i place my script?
Please read the Overview document first. Especially the Architecture part.
Any code that interacts with the page DOM must be in a Content Script. You've already put the code in src/inject.js.
Now, you don't need any UI to pop up when you click the button, so drop the "default_popup" item from the manifest and its HTML.
You also don't want your code to randomly execute when a tab loads. That's what "content_scripts" section in the manifest is about, so simply delete it.
Finally, you don't need a background HTML file. They have been replaced by autogenerated pages that are built from a list of scripts. So:
"background": {
"scripts": ["src/bg/background.js"]
},
"browser_action": {
"default_icon": "icons/icon16.png",
"default_title": "Autocheck"
},
Now, the only job of the background script is to register a handler for the button click. This is done through browserAction API:
// src/bg/background.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {file: "src/inject/inject.js"});
});
That's it, at this point it should work.
Now, to trim down the fat.
You don't need a persistent background page, since all it does is keeping simple event listeners that don't save any kind of state information. You can safely add "persistent": false to the manifest.
Your permissions are a massive overkill. There's a handy activeTab permission that gives you access to the current page if your code is invoked by, say, browser action button press.
In fact, that is the only permission your code needs. It will take care of executeScript call.
"permissions" : ["activeTab"],
I need to execute script once user clicked my context menu item.
So for the purpose I created the context menu from my background js:
chrome.contextMenus.create({"title": title, "contexts": contexts,
"onclick": genericOnClick});
It appears as expected. Later on from the genericOnClick I try to execute my script:
chrome.tabs.executeScript(null, {code: "console.log('test 1');"}, function() {
console.log("test 2");
});
I can see that the "test 2" is printed to console but "test 1" never gets printed. What am I doing wrong?
I've tried adding the console.log sentence to a separate js file but it failed to print it as well:
chrome.tabs.executeScript(null, {"file": 'content_script.js'}, function() {
console.log("test 2");
});
Note: my content_script.js is not defined in manifest. My manifest looks like follows:
{
"name": "My First Extension",
"version": "1.0",
"manifest_version": 2,
"description": "Sample extension",
"page_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"http://*/*",
"https://*/*",
"tabs",
"contextMenus"
],
"background": {
"scripts": ["sample.js"]
},
"icons": {
"16": "icon16.png"
}
}
Thank you in advance.
The only piece of code from your extension that has access to the console is the content script that is injected into the original page.
From your code it looks like you are trying to write to the console from a background script. So, to write to the console from a background page you've to inject a content script to do the job for you.
In my extensions I use my own function to write messages to the console from a background script. The code for the same is given below:
function logMessage(msg){
chrome.tabs.executeScript({code:"console.log('"+msg+"')"});
}
Define the above as the first function in your background script and call it from anywhere in the background script to write messages to the console.
In your case you can use this from the genericOnClick function to write messages to the console.
// addListener
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.executeScript(null, {file: "content_script.js"}, function() {
console.log("test 2");
});
});
// Context Menu
chrome.contextMenus.create({
title: myTitle,
contexts: ['page'],
onclick: function (detail, tab) { fn(tab) }
});
so;
"permissions": [
"tabs", "http://*/*", "https://*/*"
]
chrome.tabs.executeScript(null,{code:"document.body.style.backgroundColor='red'"});
or:
// Functional structure
function hi() { alert("hi"); };
// hi function toString after run function (hi)()
chrome.tabs.executeScript(null, { code: "(" + hi.toString() + ")()" });