I'm working on a chrome extension which needs to auto-save the text of a hmtl5 content editable section. My estimation is that the space need would be about 1MB. How do I approach this? Does the localStorage.setItem work in a chrome extension?
Thanks,
Arun
In a Chrome Extension, you can use the storage API. It can handle a couple MBs, make sure to add the permission to the manifest file (this one won't prompt users to accept it)
...
"permissions": [
"storage"
],
To save the user's input:
chrome.storage.local.set({
auto_saved_text: 'text entered by the user'
}, function() { ... })
Then to retrieve it later:
chrome.storage.local.get('auto_saved_text', function(values) {
if('auto_saved_text' in values) {
// values.auto_saved_text contains the value
}
else {
// The value has never been saved before
}
});
https://developer.chrome.com/extensions/storage
Related
I'm writing a simple extension and need to save user blacklisted keywords. I'm using the options_page for chrome to ask users for input, and save those words to the storage to be used later. However, when I press 'save', I get the error Uncaught TypeError: Cannot read property 'sync' of undefined, but I followed the instructions in the chrome extension documentation. I added "permissions": ["storage"]to the manifest.json file, and reloaded the extension and options page multiple times, yet I still get the same error. Here's my javascript code:
var save_options = function() {
var blacklistWords = document.getElementById('word').value;
chrome.storage.sync.set({'blacklistWords': blacklistWords}, function() {
// Update status to let user know options were saved.
alert("saved");
});
};
document.getElementById('save').addEventListener('click', save_options);
I would really appreciate it if someone could help me figure this out.
Your application needs permissions to read/write sync storage.
"permissions": [
"storage",
],
Always reload the extension whenever you update the manifest.json file.
Is there any way to fetch user’s phone number in Firefox OS?
If so, any help would be appreciated.
According to Mozilla's app permissions page, there is an permission called "phonenumberservice" but there is no information about it. Anyway, the permision is listed under the "Internal (Certified) app permissions", which means that, when available, it can only be used by "system-level apps and default apps created by Mozilla/operators/OEMs".
With Firefox 2.0 you should be able to use Mobile Identity API:
https://wiki.mozilla.org/WebAPI/MobileIdentity
https://bugzilla.mozilla.org/show_bug.cgi?id=1021594
I believe the permission is:
"permissions": {
"mobileid": {} }
And it is privileged.
So, as #Jason said, the Mobile Identity API provides this capability, and not just for certified, but for privileged applications. So it is no longer just for OEMs.
The Mozilla Wiki site shows the API:
dictionary MobileIdOptions {
boolean forceSelection = false;
};
partial interface Navigator {
Promise getMobileIdAssertion(optional MobileIdOptions options);
};
The site also provides a sample code skeleton for this:
function verifyAssertion(aAssertion) {
// Make use of the remote verification API
// and return the verified msisdn.
// NB: This is necessary to make sure that the user *really* controls this phone number!
}
// Request a mobile identity assertion and force the chrome UI to
// allow the user to change a possible previous selection.
navigator.getMobileIdAssertion({ forceSelection: true })
.then(
(assertion) => {
verifyAssertion(assertion)
.then(
(msisdn) => {
// Do stuff with the msisdn.
}
);
},
(error) {
// Process error.
};
);
For this to work, you need to add the mobileid permission in the manifest file, for example like this (I made up the description):
"permissions": {
"mobileid": {
"description": "Required for sending SMS for two factor authentication",
"access": "readonly"
}
}
PS: I made this answer, because most answers are outdated, and the one that isn't, does not contain all useful information.
References:
App Manifest Documentation
Firefox Remote Verification
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.
I am building an extension that requires access to history to provide one of the features.
After publishing a version which contained the permission as mandatory and consequently losing a part of my users because they got scared away by the big alert saying that the extension might be able to snoop into their history (I really didn't plan on doing that), I decided to publish a version with the offending part removed and the permission disabled as a temporary fix.
I'd like to implement this feature back using optional permissions.
First of all, I added the new optional permission to my manifest file:
...
"permissions": [
"https://news.ycombinator.com/",
"http://news.ycombinator.com/"
],
"optional_permissions": [ "history" ],
...
Then, I built a function to request permissions into the script which handles the extension's settings:
Settings.prototype.applyPermissions = function (permissions, map) {
Object.keys(permissions).forEach(function (key) {
if (map[key]) {
var checkbox = map[key].getElementsByTagName("input")[0];
checkbox.addEventListener("change", function (e) {
if (this.checked) {
chrome.permissions.request(permissions[key], function(granted) {
if (granted) {
// Permission has been granted
} else {
// Not granted
}
});
}
});
}
});
};
The key part here is this:
checkbox.addEventListener("change", function (e) {
if (this.checked) {
chrome.permissions.request(permissions[key], function(granted) {
if (granted) {
// Permission has been granted
} else {
// Not granted
}
});
}
});
I perform the request on an event caused by user interaction (the guide states that it won't work otherwise), and pass permissions[key], an object specified in my extension's settings which looks like this:
"permissions": {
"mark_as_read": {
"permissions": ["history"]
}
}
When accessing it as permissions[key], I get this part:
{
"permissions": ["history"]
}
Which is basically the format that the documentation shows for this kind of requests.
If I run this code and toggle the checkbox that should enable the feature, and look at the error log, I see this error:
chrome.permissions is not available: You do not have permission to
access this API. Ensure that the required permission or manifest
property is included in your manifest.json.
I also tried accessing this API from a background page, where it was actually available but I was not allowed to use because Chrome requires that you access it from a user interaction, and such interaction is lost if you send a message to the background page from your content script to request activation.
Am I missing something obvious here? Maybe I need to add something to the manifest, but I can't find any explicit documentation about it.
I assume you're trying to do this from a content script. You can't access most chrome.* APIs from content scripts, including chrome.permissions. However, you've correctly pointed out that a background page is also unsuitable, because you a permission change requires a direct user action.
Luckily, we have hardly exhausted our options. You could set the permission in:
The extension's options page
A browser action popup
A page action popup
Any page in your extension served through the chrome-extension:// scheme, provided you include the page and necessary sub-resources as web_accessible_resources in your manifest
In the last case, get the URL using chrome.extension.getURL. You could possibly use an iframe to inject it directly into the page, if you don't want the permission-requesting interface to be separate from the current page.
So, in fact, content scripts and background pages are the only two extension contexts where you can't use chrome.permissions.
I am trying to detect whether my extension was uninstalled.
I can't use chrome.management.onUninstalled because it will be fired on other extension.
As of Chrome 41, you can now open a URL when the extension is uninstalled. That could contain an exit survey or track the uninstall event as some sort of analytics.
Google Chrome, unlike Firefox, doesn’t allow to detect when the user uninstalls the extension, which is quite useful to understand user behaviour.
There is a feature request on crbug.com with a discussion of this feature but it has not been implemented yet.
You can call chrome.runtime.setUninstallURL("www.example.com/survey") and redirect user to a url. Unfortunately, as soon as the extension is removed, the background script is removed too, and you can't do anything like log event or send hit to google analytics.
What I did is to set the redirect url to my server endpoint, and do some tasks like logging event to my own db, or sending hit to google analytics (ga hit builder). Then call res.status(301).redirect("www.example.com/survey") to some survey url. Finally I can send the uninstall event to google analysis.
If you're on Manifest V3, you can add it on your onInstalled Listener. If you want to capture uninstall for existing users as well, you need to add it to 'update' as well.
Place this code in your background page:
chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == 'install') {
... can add things like sending a user to a tutorial page on your website
chrome.runtime.setUninstallURL('https://www.yourwebsite.com/uninstall');
} else if (details.reason == 'update') {
... can add things like sending user to a update page on your website
chrome.runtime.setUninstallURL('https://www.yourwebsite.com/uninstall');
}
});
Find more information here: https://developer.chrome.com/docs/extensions/reference/runtime/#method-setUninstallURL
For mv3: An easy way would be to have
// Redirect users to a form when the extension is uninstalled.
const uninstallListener = (details) => {
if (details.reason === chrome.runtime.OnInstalledReason.INSTALL) {
chrome.runtime.setUninstallURL('https://forms.gle/...');
}
if (details.reason === chrome.runtime.OnInstalledReason.UPDATE) {
// TODO: show changelog
}
};
chrome.runtime.onInstalled.addListener(uninstallListener);
Place it in your background.
Content Script can Detect an Uninstall
Simply check the value of chrome.runtime, which becomes undefined when an extension is uninstalled.
A good trigger to check this is port disconnect:
// content_script.js
const port = chrome.runtime.connect();
port.onDisconnect.addListener(onPortDisconnect);
function onPortDisconnect() {
// After the extension is disabled/uninstalled, `chrome.runtime` may take
// a few milliseconds to get cleared, so use a delay before checking.
setTimeout(() => {
if (!chrome.runtime?.id) {
console.log('Extension disabled!');
}
}, 1000);
};