Firefox extension content script does not load and append HTML - google-chrome-extension

Everything below works in a Chrome extension but silently fails when ported to Firefox on:
loading the test.html unless I remove <style></style> from it
appending the #test_element to the body
Do styles have to go into a separate file for Firefox extension? Why does append() fail?
test.js
$(document).ready(function() {
$.get(chrome.extension.getURL('/html/test.html'), function(data) {
// not called unless style element is removed from HTML
// and never actually appended if it is removed
$(document.body).append($.parseHTML(data));
});
});
test.html
<style></style>
<div id="test_element">
<p>my name is cow</p>
</div>
manifest.json
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"icons": {
"64": "icons/icon-64.png"
},
"permissions": [
"tabs",
"storage",
"idle"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["lib/jquery.js", "src/test.js"]
}
],
"web_accessible_resources": [
"html/test.html"
]
}

It is not falling silently to me but gives me:
XML Parsing Error: junk after document element
Location: https://www.google.gr/
Line Number 2, Column 1
This is because it is not a valid XML document (one root element only should exists).
My way to make it work is the following:
test.html: (Make it valid)
<div>
<style></style>
<div id="test_element">
<p>my name is cow</p>
</div>
</div>
test.js: (Use XMLSerializer)
$(document).ready(function() {
$.get(chrome.extension.getURL('/html/test.html'), function(data) {
res = new XMLSerializer().serializeToString(data);
$(document.body).append(res);
});
});

For #1: see the solution by Christos. For #2: $.get() returns a string in Chrome but XMLDocument in Firefox (that must be serialized with serializeToString() before appending). Anyway, I removed jQuery to make the content script lighter (by the way, $(document).ready() is not required because by default content scripts are injected after DOM is ready):
var httpRequest = new XMLHttpRequest();
httpRequest.onload = function(data) {
httpRequest.onload = null;
var template = document.createElement('template');
template.innerHTML = data.target.responseText;
var element = template.content.firstChild;
document.body.appendChild(element);
}
httpRequest.open('GET', chrome.extension.getURL('/html/test.html'));
httpRequest.send();

Related

Chrome extension: Receiving error while making extension

I'm developing a chrome extension. It will make it possible to press a button, and it will capture a screenshot of your screen, then you will be able to save it to your computer.
However after attempting to load my extension at chrome://extensions/
I'm getting either of 2 messages:
"Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist."
"Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' blob: filesystem:". Either the 'unsafe-inline' keyword, a hash ('sha256-0xoq3Fm+45tEb3FQIwY9RYnpdCuDu/FcIzz/s1HPTAM='), or a nonce ('nonce-...') is required to enable inline execution."
I've been at this for a long time now and can't seem to find the problem. I have inserted the codes below, can anyone help me fix this?
Might be even the smallest oversight from my part, but would be super grateful for any help.
See code below:
manifest.json
{
"manifest_version": 2,
"name": "MySnap",
"description": "Take a screenshot of a selected portion of the screen",
"version": "1.0",
"permissions": [
"tabs",
"activeTab"
],
"browser_action": {
"default_icon": "icon.png",
"default_title": "MySnap",
"default_popup": "popup.html"
},
"content_security_policy": "script-src 'self' 'sha256-Ws4H0eytNaM/o8NllzTlOPZFeyohSxu1N5dQ7JOcjMI='"
}
popup.html
<!DOCTYPE html>
<html>
<head>
<title>MySnap</title>
</head>
<body>
<h1>MySnap</h1>
<button id="screenshot-button">Take Screenshot</button>
<div id="screenshot-container"></div>
<script src="screenshot.js"></script>
<script>
document.getElementById("screenshot-button").addEventListener("click", function() {
chrome.runtime.sendMessage({message: "take_screenshot"}, function(response) {
// Do something with the response
});
});
</script>
<script>
function takeScreenshot() {
chrome.runtime.sendMessage({message: "take_screenshot"}, function(response) {
if (response && response.screenshotUrl) {
// Create a link element and set its href to the screenshot URL
var link = document.createElement("a");
link.href = response.screenshotUrl;
// Set the download attribute of the link element
link.download = "screenshot.png";
// Append the link element to the DOM
document.body.appendChild(link);
// Click the link to initiate the download
link.click();
// Remove the link element from the DOM
document.body.removeChild(link);
}
});
}
</script>
</body>
</html>
screenshot.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "take_screenshot") {
chrome.tabs.captureVisibleTab(null, {}, function(screenshotUrl) {
sendResponse({screenshotUrl: screenshotUrl});
});
}
return true;
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message === "take_screenshot") {
chrome.tabs.captureVisibleTab(null, {}, function(screenshotUrl) {
sendResponse({screenshotUrl: screenshotUrl});
});
}
});
You can make the screenshot in the popup script, no need for messaging.
remove content_security_policy from manifest.json
remove all <script> elements from popup.html except <script src="screenshot.js">
remove background.js
// popup.html:
<!DOCTYPE html>
<h1>MySnap</h1>
<button id="screenshot-button">Take Screenshot</button>
<div id="screenshot-container"></div>
<script src="screenshot.js"></script>
// screenshot.js:
document.getElementById('screenshot-button').onclick = () => {
chrome.tabs.captureVisibleTab(url => {
const el = document.createElement('a');
el.href = url;
el.download = 'screenshot.png';
document.body.appendChild(el);
el.click();
el.remove();
});
};

Chrome extension not working after chrome update to Version 57.0.2987.133 (64-bit)

After recent update of chrome browser to Version 57.0.2987.133 (64-bit)
my extension stopped working.Following is the explanation of the working on extension:
Popup.js
document.addEventListener('DOMContentLoaded', function() {
chrome.tabs.getSelected(null, function(tab) {
d = document;
var f = d.createElement('form');
f.action = 'https://example.com/login';
f.method = 'post';
var i = d.createElement('input');
i.type = 'hidden';
i.name = 'url';
i.value = tab.url;
console.log(tab.url);
f.appendChild(i);
d.body.appendChild(f);
f.submit();
});
});
popup.html
<!doctype html>
<html>
<head>
<script type="text/javascript" src="jquery-2.1.1.js"></script>
<script src="popup.js"></script>
<style type="text/css">
.image {
display: block;
margin-left: auto;
margin-right: auto
}
</style>
</head>
<body style="width: 350px;height:340px;">
<h3>Connecting to server please wait ...</h3>
<br/>
<br/>
<br/>
<img src="/loader.gif" alt="Please Wait" class="image" align="middle">
</body>
</html>
manifest.json
{
"update_url": "https://clients2.google.com/service/update2/crx",
"manifest_version": 2,
"name": "test name",
"description": "test description",
"version": "0.1.2",
"browser_action": {
"default_icon": "128.png",
"default_popup": "popup.html"
},
"icons": {
"16": "128.png",
"32": "128.png",
"64": "128.png",
"128": "128.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"web_accessible_resources": [ "128.png" ],
"permissions": [
"tabs"
]
}
Before the chrome update, extension was working fine.
- I am submitting a form with post method.
- I am sending a key 'url' which I am checking on server site if the request is from extension and thus loading login form for extension. - Once the extension login loads into the popup, user logs in and is redirected to appropriate page within the popup.
This is the flow of extension. But after the update, Loading continues on popup. The form submit request is being cancelled by the browser. On googling about the problem, I found using ajax post method for submitting the form instead of direct form submit. This method was able to fetch the login form from but that without any css and js of the webpage as the urls were relative in the page and chrome extension id was prepended as the base url with all the links. So, I changed those urls to absolute but the submit functionality was not working again as it was again a form. Again I changed the form submit into ajax post submit request on server side. But the javascript written over the webpage is not working in chrome extension.
So question is how to make the extension work which was working earlier?
chrome.tabs.getSelected() is deprecated since Chrome 33. try using chrome.tabs.query({ active: true }) like this:
document.addEventListener('DOMContentLoaded', function() {
chrome.tabs.query({ active: true }, function(tabs) {
var tab = tabs[ 0 ];
d = document;
var f = d.createElement('form');
f.action = 'https://example.com/login';
f.method = 'post';
var i = d.createElement('input');
i.type = 'hidden';
i.name = 'url';
i.value = tab.url;
console.log(tab.url);
f.appendChild(i);
d.body.appendChild(f);
f.submit();
});
});
I've been encountering an issue where the DOMContentLoaded event appears to fire before the DOM is fully rendered. This has been an issue since my Chrome updated to 57.0.2987.133.
Perhaps you could use the window load event instead.
window.addEventListener('load', function() {

How to make a extension/script/program that will refresh a browser until a certain phrase/keyword is found or is not found?

Is there any program/extension that I can use with browser that will refresh a webpage and search for a certain phrase or text and then stop once the phrase is found or is not found.
For example say I made a site that cycles using a randomizer through the words "One," "Two," and "Three."
This program would refresh the page until the word "Three" is found, If I set it to find that word, and then stop once it is found.
OR
This program would refresh the page until the word "Three" is not found, If I set it to find that word, and then stop once it is not found.
I know that we can use curl and grep to do that, but the page is not loaded on webbrowser. This is not what I want. see if there is solution that we can load on browser as well
If there no such things exists, any idea on how to write this kind of program? use what tool to do that?
You could very easily write an extension to do this. I would suggest instead of refreshing the page every time, you poll the data until you get the desired result then refresh the page once you find it. A short example using jQuery because I am familiar with it:
Manifest.json
{
"name": "Find Text",
"version": "0.1",
"description": "Find Text",
"manifest_version": 2,
"browser_action": {
"default_icon": "on.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs","http://*/*","https://*/*"
],
"background": {
"scripts": ["bgp.js","jquery-1.8.3.min.js"],
"persistent": true
}
}
Popup.html
<!DOCTYPE html>
<html>
<head>
<style>
body { width: 300px; }
</style>
<script src="jquery-1.8.3.min.js"></script>
<script src="popup.js"></script>
</head>
<body>
<div>Desired Search Url</div>
<input type="text" id="searchUrl">
<div>Desired Search Text</div>
<input type="text" id="searchText">
<button id="searchButton">Search</button>
</body>
</html>
Popup.js
$(function(){
var tabId;
chrome.tabs.query({active:true,currentWindow:true}, function(tab) {
$('#searchUrl').val(tab[0].url);
tabId = tab[0].id;
});
$('#searchButton').click(function(){
chrome.extension.sendMessage({
url:$('#searchUrl').val(),
text:$('#searchText').val(),
tab:tabId
});
});
});
bgp.js
chrome.extension.onMessage.addListener(function(message,sender,sendResponse){
checkUrlForText(message.url,message.text,message.tab);
});
function checkUrlForText(url,text,tab){
var contains;
$.ajax({
url:url,
async:false,
success: function(data){
contains = $(':contains('+text+')',data);
while(contains.length == 0){
$.ajax({
url:url,
async:false,
success: function(dat){
contains = $(':contains('+text+')',dat);
}
});
}
}
});
chrome.tabs.reload(tab);
}
If having it refresh the tab every time is a requirement (the content would change between the time it found what you were looking for and when it refreshes the page) then you should use content scripts to test for the desired value and send a message to the background page if the desired text is not there to refresh the page and start again. Like this:
bgp.js
var contains;
chrome.extension.onMessage.addListener(function(message,sender,sendResponse){
checkTabForText(message.text,message.tab);
contains = false;
});
function checkTabForText(text,tab){
chrome.tabs.executeScript(tab,{file:"jquery-1.8.3.min.js"});
chrome.tabs.executeScript(tab,{file:"checkText.js"},function(){
chrome.tabs.sendMessage(tab, {text:text}, function(response){
contains = response.contains;
if(!contains){
chrome.tabs.reload(tab,function(){
checkTabForText(text,tab);
});
}
});
});
}
checkText.js
chrome.extension.onMessage.addListener(function(message,sender,sendResponse){
var contains = $(':contains('+message.text+')');
if(contains.length > 0)
sendResponse({contains:true});
else
sendResponse({contains:false});
});

Timer for chrome extension [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Chrome extension delay condition
Im very beginner at extensions and by collecting codes from here and there I created a simple one which collects the tab's url (works for specific website) and using ajax Im sending it to my server in order to store it in my database.
What Im trying to do is to add a timer so the browser button will be disabled (or do nothing) if the previous click occured in less than 5 seconds.
Below is the structure of the extension:
Manifest:
{
"name": "The name",
"icons": { "16": "Big.png",
"48": "Big.png",
"128": "Big.png" },
"version": "1.0",
"manifest_version": 2,
"description": "and the description",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": ["tabs", "<all_urls>"]
}
popup.js:
chrome.tabs.getSelected(null,function(tab) {
var Mp=tab.url
if(Mp=='http://www.examplesite.com')
{
var xhr=new XMLHttpRequest();
var Params;
xhr.open("POST", "http://myserver.com/post_from_extension.asp", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
Params='Url=' + tab.url;
xhr.onreadystatechange=function()
{
if(xhr.readyState==4)
{
message.innerHTML=xhr.responseText;
}
}
xhr.send(Params);
}
else
{
message.innerHTML='<span style="font-family: Segoe UI, Tahoma;color: #f00">This is not a valid url</span>';
}
});
popup.html
<!DOCTYPE html>
<html style=''>
<head>
<script src='popup.js'></script>
</head>
<body style="width:400px;">
<div id='message'><span style="font-family: Segoe UI, Tahoma;color: #00f">Sending request</span></div>
</body>
</html>
As a side question, is there any other method to post the url in my database, if not with Ajax?
Thank you for reading me.
I think you should add a background page (script) to your extension - this is a kind of application state. Add this in the manifest:
"background": {
"scripts": ["background.js"]
},
Then in the page you can define an array storing last times when browser action was performed for each tab.
var timers = [];
You can update this array's elements from your popup.js, something like that (in getSelected callback):
chrome.extension.getBackgroundPage().timers[tabId] = new Date();
chrome.browserAction.disable(tabId);
chrome.browserAction.setIcon({path: "icon-disabled.png", tabId: tabId});
Note how you can disable browser action and change its appearence to a disable/grayed one.
When a period passed since the registered time exceeds 5 seconds you should re-enable the button from the background page.
var currentTime = new Date();
if(currentTime - chrome.extension.getBackgroundPage().timers[tabId] > 5000)
{
chrome.browserAction.enable(tabId);
chrome.browserAction.setIcon({path: "icon-enabled.png", tabId: tabId});
}
You can execute this code from setInterval callback and within a cycle through all elements in the timers array.

Trivial Chrome pageAction extension not working

I'm trying to write a trivial Chrome pageAction extension to change all anchors on a page from one domain to another... but I can't quite seem to get it to work, and I'm having trouble debugging it.
Am I misunderstanding how this kind of extension needs to be built? Or am I just misusing the API?
manifest.json:
{
"name": "theirs2ours",
"version": "1.0",
"description": "Changes all 'their' URLs to 'our' URLs.",
"background_page": "background.html",
"permissions": [
"tabs"
],
"page_action": {
"default_icon": "cookie.png",
"default_title": "theirs2ours"
},
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["content.js"]
}
]
}
background.html:
<html>
<head>
<script type='text/javascript'>
chrome.tabs.onSelectionChanged.addListener(function(tabId) {
chrome.pageAction.show(tabId);
});
chrome.tabs.getSelected(null, function(tab) {
chrome.pageAction.show(tab.id);
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.sendRequest(tab.id, {}, null);
});
</script>
</head>
<body>
</body>
</html>
content.js:
var transform = function() {
var theirs = 'http://www.yourdomain.com';
var ours = 'http://sf.ourdomain.com';
var anchors = document.getElementsByTagName('a');
for (var a in anchors) {
var link = anchors[a];
var href = link.href;
if (href.indexOf('/') == 0) link.href = ours + href;
else if (href.indexOf(theirs) == 0) link.href = href.replace(theirs, ours);
}
};
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
transform();
});
I think this is not the way to do the extension you want.
First of all, I assume you want to replace the anchors when you click the page action button.
The manifest you have injects content.js on every page, no matter if you click or not the page action button.
I suggest you remove the content_scripts field from your manifest, and inject content.js manually, with
chrome.tabs.executeScript(tabId, {file:'content.js'})
You should do this in the page action's click listener.
By the way, in that listener you are sending a request to the content script, but it hasn't a listener to listen to such request message. In this extension you won't need to use senRequest.
You're not requesting permission to run content scripts on these pages. The matches for content scripts determines what pages they are executed in but you still need to request permission to inject scripts in to these pages.
"permissions": [
"tabs",
"http://*/*"
]

Resources