Safari extension - Save stats to storage, then display it - javascript

Example: I have created safari extension, which, after the page loads, replaces all words "fish" with the fish emoji. I want to count how many words I replaced and store that number (total number of replaces since installing the extension). When I click on the extension icon in toolbar, I want to see that total number.
content.js handles the replacing
popup.js handles the toolbar icon menu
I only need the storing capability implemented, so I need a function in content.js called SomehowStoreThisValue() and in popup.js function SomehowRetrieveThisValue()
What I've tried: (Using the local storage)
content.js:
browser.runtime.sendMessage({
data: "Hello popup, how are you"
}, function (response) {
console.dir(response);
});
popup.js:
browser.runtime.onMessage.addListener(function (message, sender, sendResponse) {
sendResponse({
data: "I am fine, thank you. How is life in the background?"
});
let my_value = parseInt(localStorage.getItem('stored_value'));
document.getElementById("MY_ID").innerHTML = my_value;
localStorage.setItem('stored_value', my_value + 1);
});
Which does work, but only when the popup is open, when the replacement is happening, which is not ideal.

Related

How to save input data form with javascript avoid security content policy -Chrome extension

i'm newbie on developping chrome extension and i'm facing a problem.
I need to get user input data and store it in some ways. I tryed with local.storage and sync.storage but they should work only with same domain since i cannot get data while i'm trying to inject javascript by using script in content.js file. It works on same domain (i suppose that in this case, when i open tab of chrome extension, local.storage save data only for that "domain").
How can solve it?
Thank you
You can try the message passing.
// popup.js
function submit(data) {
chrome.tabs.query({active: true}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, data);
});
}
// content.js
chrome.runtime.onMessage.addListener(function (message) {
// do sth
});

Firefox extension: Open window and write dynamic content

I have developed a Chrome Extension and it's mostly compatible to firefox web-extensions API. Just one problem:
In Chrome Extension i have popup.js and background.js. User click's a button, popup.js does chrome.sendMessage to background.js where data is received and afterwards (popup.html may be closed meanwhile) i just call in background.js:
newWin = window.open("about:blank", "Document Query", "width=800,height=500");
newWin.document.open();
newWin.document.write('<html><body><pre>' + documentJson + '</pre></body></html>');
// newWin.document.close();
so that works fine in Chrome extension but not in firefox. I read here (https://javascript.info/popup-windows) that for safety reasons firefox will only open with a "button click event". And if i move above code to popup.js, inside button-click-evenListener, it will open this way (but i dont have the data prepared yet, thats really not what i want)
So i tried everything i found but i dont get the chrome.tabs.executeScript running. Here is my code with comments:
popup.js
// working in firefox and chrome (popup.js)
const newWin = window.open("about:blank", "hello", "width=200,height=200");
newWin.document.write("Hello, world!");
// not working firefox: id's match, he enters function (newWindow) but document.write doing nothing (but no error in log)
// not working chrome: doesnt even enter "function (newWindow)""
chrome.windows.create({
type: 'popup',
url: "output.html"
}, function (newWindow) {
console.log(newWindow);
console.log(newWindow.id);
chrome.tabs.executeScript(newWindow.tabs[0].id, {
code: 'document.write("hello world");'
});
});
background.js
(created local output.html and gave several permissions in Manifest.json - tabs, activeTab, output.html, , about:blank)
// opening but executeScript not working in firefox: Unchecked lastError value: Error: The operation is insecure.
// opening but executeScript not working in chrome: Unchecked runtime.lastError: Cannot access contents of url "chrome-extension://plhphckppghaijagdmghdnjpilpdidkh/output.html". Extension manifest must request permission to access this host
chrome.tabs.create({
// type: 'popup',
url: "output.html"
}, function (newWindow) {
console.log(newWindow);
console.log(newWindow.id);
chrome.tabs.executeScript(newWindow.id, {
code: 'document.write("hello world");'
});
});
How can I get the data into the new window/popup from background.js - i can open an empty page from there, so it's only about getting executeScript() running
Thanks to #wOxxOm for pointing me to a data URI to transport the json document into the browser from background.js.
While searching for a javascript method to build a data URI i found this thread, with the suggestion to create a Blob :
https://stackoverflow.com/a/57243399/13292573
So my solution is this:
background.js
var documentJson = JSON.stringify(documents, null, 2)
let a = URL.createObjectURL(new Blob([documentJson]))
chrome.windows.create({
type: 'popup',
url: a
});

How to get Chrome Extension's Options value in Extension? [duplicate]

I have an options page where the user can define certain options and it saves it in localStorage: options.html
Now, I also have a content script that needs to get the options that were defined in the options.html page, but when I try to access localStorage from the content script, it doesn't return the value from the options page.
How do I make my content script get values from localStorage, from the options page or even the background page?
Update 2016:
Google Chrome released the storage API: https://developer.chrome.com/docs/extensions/reference/storage/
It is pretty easy to use like the other Chrome APIs and you can use it from any page context within Chrome.
// Save it using the Chrome extension storage API.
chrome.storage.sync.set({'foo': 'hello', 'bar': 'hi'}, function() {
console.log('Settings saved');
});
// Read it using the storage API
chrome.storage.sync.get(['foo', 'bar'], function(items) {
message('Settings retrieved', items);
});
To use it, make sure you define it in the manifest:
"permissions": [
"storage"
],
There are methods to "remove", "clear", "getBytesInUse", and an event listener to listen for changed storage "onChanged"
Using native localStorage (old reply from 2011)
Content scripts run in the context of webpages, not extension pages. Therefore, if you're accessing localStorage from your contentscript, it will be the storage from that webpage, not the extension page storage.
Now, to let your content script to read your extension storage (where you set them from your options page), you need to use extension message passing.
The first thing you do is tell your content script to send a request to your extension to fetch some data, and that data can be your extension localStorage:
contentscript.js
chrome.runtime.sendMessage({method: "getStatus"}, function(response) {
console.log(response.status);
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.method == "getStatus")
sendResponse({status: localStorage['status']});
else
sendResponse({}); // snub them.
});
You can do an API around that to get generic localStorage data to your content script, or perhaps, get the whole localStorage array.
I hope that helped solve your problem.
To be fancy and generic ...
contentscript.js
chrome.runtime.sendMessage({method: "getLocalStorage", key: "status"}, function(response) {
console.log(response.data);
});
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.method == "getLocalStorage")
sendResponse({data: localStorage[request.key]});
else
sendResponse({}); // snub them.
});
Sometimes it may be better to use chrome.storage API. It's better then localStorage because you can:
store information from your content script without the need for
message passing between content script and extension;
store your data as JavaScript objects without serializing them to JSON (localStorage only stores strings).
Here's a simple code demonstrating the use of chrome.storage. Content script gets the url of visited page and timestamp and stores it, popup.js gets it from storage area.
content_script.js
(function () {
var visited = window.location.href;
var time = +new Date();
chrome.storage.sync.set({'visitedPages':{pageUrl:visited,time:time}}, function () {
console.log("Just visited",visited)
});
})();
popup.js
(function () {
chrome.storage.onChanged.addListener(function (changes,areaName) {
console.log("New item in storage",changes.visitedPages.newValue);
})
})();
"Changes" here is an object that contains old and new value for a given key. "AreaName" argument refers to name of storage area, either 'local', 'sync' or 'managed'.
Remember to declare storage permission in manifest.json.
manifest.json
...
"permissions": [
"storage"
],
...
Another option would be to use the chromestorage API. This allows storage of user data with optional syncing across sessions.
One downside is that it is asynchronous.
https://developer.chrome.com/extensions/storage.html
[For manifest v3]
You can execute a script that returns localstorage items from the webpage. This script can be executed from popup or background service worker.
Add this line in manifest.json:
"permissions": ["scripting"]
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true })
// Execute script in the current tab
const fromPageLocalStore = await chrome.scripting.executeScript({
target: { tabId: tabId },
func: () => {
return JSON.stringify(localStorage)
}
})
const localStorageItems = JSON.parse(fromPageLocalStore[0].result)

Chrome extension and .click() loops using values from localStorage

I have made a Chrome extension to help using a small search engine in our company's intranet. That search engine is a very old webpage really convoluted, and it doesn't take parameters in the url. No chance that the original authors will assist:
The extension popup offers an input text box to type your query. Your
query is then saved in localStorage
There is a content script inserted in
the intranet page that reads the localStorage key and does a document.getElementById("textbox").value = "your query"; and then does
document.getElementById("textbox").click();
The expected result is that your search is performed. And that's all.
The problem is that the click gets performed unlimited times in an infinite loop, and I cannot see why it's repeating.
I would be grateful if you would be able to assist. This is my first Chrome extension and all what I have been learning about how to make them has been a great experience so far.
This is the relevant code:
The extension popup where you type your query
popup.html
<input type="search" id="cotext"><br>
<input type="button" value="Name Search" id="cobutton">
The attached js of the popup
popup.js
var csearch = document.getElementById("cotext");
var co = document.getElementById("cobutton");
co.addEventListener("click", function() {
localStorage["company"] = csearch.value;
window.open('url of intranet that has content script applied');
});
And now the background file to help with communication between parts:
background.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
sendResponse({data: localStorage[request.key]});
});
And finally the content script that is configured in the manifest to be injected on the url of that search engine.
incomingsearch.js
chrome.extension.sendRequest(
{method: "getLocalStorage", key: "company"},
function(response) {
var str = response.data;
if (document.getElementById("txtQSearch").value === "") {
document.getElementById("txtQSearch").value = str;
}
document.getElementById("btnQSearch").click();
});
So as I mentioned before, the code works... not just once (as it should) but many many times. Do I really have an infinite loop somewhere? I don't see it... For the moment I have disabled .click() and I have put .focus() instead, but it's a workaround. I would really like to use .click() here.
Thanks in advance!
The loop is probably caused by clicking the button even if it has a value. Try putting it inside your if. That said, you are overcomplicating it.
You can access the extension's data inside content scripts directly by replacing localstorage with the chrome.storage extension api. Add the "storage" (silent) permission to your manifest.json, like this:
"permissions": ["storage"]
Remove the message passing code in background.js. Then replace the popup button listener contents with:
chrome.storage.local.set({ "company": csearch.value }, function() {
chrome.tabs.create({ url: "whatever url" })
})
Replace the content script with:
chrome.storage.local.get("company", function(items) {
if(document.querySelector("#txtQSearch").value == "") {
document.querySelector("#txtQSearch").value = items.company
document.querySelector("#btnQSearch").click()
}
})
document.querySelector() performs the same function here as getElementById, but it is much more robust. It also has less capital letters, which makes it easier to type in my opinion.

How to access localStorage in extension background page?

I have a chrome extension that sets a string value in JavaScript localStorage in a content script. I have tested that it is being set by grabbing it and displaying it. While on the same page after it has loaded I can still access the stored string in the javascript console. If I go to any other tabs js console or when I try to access it in my other extensions background page(After the browser action has been clicked) it is returning null.
extension 1 contentscript.js
embeded.addEventListener
(
"message",
function(message)
{
localStorage.setItem("pdf", message.data);
loadPDF(message.data);
},
false
);
extension 2 background.js
chrome.browserAction.onClicked.addListener(function(tab) {
if (tab.url.substr(tab.url.length - 4) === ".pdf")
{
if (localStorage.getItem("pdf") !== null)
{
alert("boomy");
}
}
});
localStorage is shared among extension pages (background, options, popup), but not content scripts. And most certainly not shared between 2 extensions!
You have two-and-a-half options. With 2 separate extensions, only one option.
Option one: rely on messaging.
When you need to pass some value between background and content script, you can do so with messaging. Works especially well if you only need to pass it in one direction.
contentscript.js:
embeded.addEventListener(
"message",
function(message)
{
chrome.runtime.sendMessage(extensionTwoId, {pdf: message.data});
loadPDF(message.data);
},
false
);
background.js:
chrome.runtime.onMessageExternal.addListener(
function(message, sender, sendResponse) {
if(sender.id !== extenstionOneId) return;
if(message.pdf) localStorage.setItem("pdf", message.pdf);
}
);
/* ... */
Option two: chrome.storage. Not applicable between 2 extensions.

Categories

Resources