The Google Chrome extension Share-it now has an Options page that enables you to choose which menu items are visible. Users simply can check which menu items to use and which to hide on the options page instead of navigating a menu of irrelevant menu items that they do not use. Preferences in an add-on are stored within the localstorage object in the browser in order to persist across start ups and closings. Developing an options page for your add-on isn’t a very difficult task, however, there are a couple of coding issues to be aware of.

Share-it Context Menu

Share-it Options Page
Opera Next Is In The Loop
Something else to note is that I now also test Share-it on Opera Next where it runs superbly. I plan on eventually submitting this to the Opera store for consumption . For now, however, there is a link to download the .nex file at the bottom of this post if you want to use in now. Opera Next is based on the open source Chromium browser which Google Chrome is also based on. The context menu API is basically the same throughout as it allows for a shared code-base for context menu add-on development.

Share-it Context Menu running on Opera Next
Caveats Developing an Options page or Popup page
There are a couple of tricky issues you should keep in mind if you are developing an options page for your add-on. First relates to scripting in pages inside of your add-on. There can be no inline script in your pages. Just keep your JavaScript in a separate file and make sure you are careful with your scripting not to create any inline script. Usually this means listening for click events and handling them using the event itself (similar to the way you would do it with Actionscript and Flex if you’ve ever done any Flash coding). The second issue relates to message and object passing. The JavaScript executing in your page isn’t in global scope for security reasons. There’s a special function to call, chrome.extension.getBackgroundPage(), that you have to call in order to gain access to the background page (app.js in this add-on). If you run into problems developing your page you should inspect the running page itself. The generated background page inspector will not show errors for secondary parts of the add-on (remember, not in global scope). Check out the source code below if you’re curious.
Source Code:
manifest.json
{
"name": "Share-it",
"description": "Adds context menu items to share the current page on a number of websites",
"version": "0.4",
"permissions": ["contextMenus"],
"background": {
"scripts": ["app.js"]
},
"options_page": "options.html",
"icons" : {
"16" : "favicon.ico",
"32" : "peopleicon32.png",
"48" : "peopleicon48.png",
"128" : "peopleicon128.png"
},
"manifest_version": 2
}
app.js
/** app.js */
var defaultentries = [
{
"menu":"facebook.com",
"active":1
},{
"menu":"twitter.com",
"active":1
},{
"menu":"plus.google.com",
"active":1
},{
"menu":"linkedin.com",
"active":1
},{
"menu":"digg.com",
"active":1
},{
"menu":"stumbleupon.com",
"active":1
},{
"menu":"tumblr.com",
"active":1
},{
"menu":"friendfeed.com",
"active":1
},{
"menu":"fark.com",
"active":1
},{
"menu":"blinklist.com",
"active":1
},{
"menu":"plurk.com",
"active":1
},
];
var entries = {};
if (!localStorage.getItem("entries")) {
localStorage.setItem("entries", JSON.stringify(defaultentries));
}
entries = JSON.parse(localStorage.getItem("entries"));
function isActive(menu){
console.log("isActive");
var elen = entries.length;
console.assert(!elen == 0);
for(i=0;i<elen;i++){
if(entries[i]["menu"] == menu){
console.log(entries[i]["menu"]);
if(entries[i]["active"] == 1){
return true;
}else{
return false;
}
}
}
}
function setActive(menu){
console.log("setActive");
var elen = entries.length;
console.log(menu);
console.assert(!elen == 0);
for(i=0;i<elen;i++){
if(entries[i]["menu"] == menu){
entries[i]["active"] = 1;
}
}
localStorage.setItem("entries", JSON.stringify(entries));
}
function setInactive(menu){
console.log("setInactive");
var elen = entries.length;
console.log(menu);
console.assert(!elen == 0);
for(i=0;i<elen;i++){
if(entries[i]["menu"] == menu){
entries[i]["active"] = 0;
}
}
localStorage.setItem("entries", JSON.stringify(entries));
}
/* Create the context menu */
var hp = chrome.contextMenus.create({"title": "Share-it"});
if(isActive("facebook.com")){
chrome.contextMenus.create({"title": "facebook.com", "contexts":["page"], "parentId": hp, "onclick": facebookIt});
}
function facebookIt(i, t){
var createProperties = {url: "http://www.facebook.com/sharer.php?u="+ encodeURI(t.url) + "&src=" + encodeURIComponent("Share-it")};
chrome.tabs.create(createProperties);
}
if(isActive("twitter.com")){
chrome.contextMenus.create({"title": "twitter.com", "contexts":["page"], "parentId": hp, "onclick": twitterIt});
}
function twitterIt(i, t){
var createProperties = {url: "https://twitter.com/share?url="+ encodeURI(t.url) + "&text=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("plus.google.com")){
chrome.contextMenus.create({"title": "plus.google.com", "contexts":["page"], "parentId": hp, "onclick": googleplusIt});
}
function googleplusIt(i, t){
var createProperties = {url: "https://plusone.google.com/_/+1/confirm?hl=en&url="+ encodeURI(t.url)};
chrome.tabs.create(createProperties);
}
if(isActive("linkedin.com")){
chrome.contextMenus.create({"title": "linkedin.com", "contexts":["page"], "parentId": hp, "onclick": linkedinIt});
}
function linkedinIt(i, t){
var createProperties = {url: "http://www.linkedin.com/cws/share?url="+ encodeURI(t.url)};
chrome.tabs.create(createProperties);
}
if(isActive("digg.com")){
chrome.contextMenus.create({"title": "digg.com", "contexts":["page"], "parentId": hp, "onclick": diggIt});
}
function diggIt(i, t){
var createProperties = {url: "http://digg.com/submit?url="+ encodeURI(t.url) + "&title=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("stumbleupon.com")){
chrome.contextMenus.create({"title": "stumbleupon.com", "contexts":["page"], "parentId": hp, "onclick": stumbleuponIt});
}
function stumbleuponIt(i, t){
var createProperties = {url: "http://www.stumbleupon.com/submit?url="+ encodeURI(t.url)};
chrome.tabs.create(createProperties);
}
if(isActive("tumblr.com")){
chrome.contextMenus.create({"title": "tumblr.com", "contexts":["page"], "parentId": hp, "onclick": tumblrIt});
}
function tumblrIt(i, t){
var createProperties = {url: "http://www.tumblr.com/share?v=3&u="+ encodeURI(t.url) + "&t=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("friendfeed.com")){
chrome.contextMenus.create({"title": "friendfeed.com", "contexts":["page"], "parentId": hp, "onclick": friendfeedIt});
}
function friendfeedIt(i, t){
var createProperties = {url: "http://www.friendfeed.com/share?url="+ encodeURI(t.url) + "&title=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("fark.com")){
chrome.contextMenus.create({"title": "fark.com", "contexts":["page"], "parentId": hp, "onclick": farkIt});
}
function farkIt(i, t){
var createProperties = {url: "http://cgi.fark.com/cgi/fark/farkit.pl?u="+ encodeURI(t.url) + "&h=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("blinklist.com")){
chrome.contextMenus.create({"title": "blinklist.com", "contexts":["page"], "parentId": hp, "onclick": blinklistIt});
}
function blinklistIt(i, t){
var createProperties = {url: "http://www.blinklist.com/index.php?Action=Blink/Addblink.php&Url="+ encodeURI(t.url) + "&Title=" + encodeURIComponent(t.title)};
chrome.tabs.create(createProperties);
}
if(isActive("plurk.com")){
chrome.contextMenus.create({"title": "plurk.com", "contexts":["page"], "parentId": hp, "onclick": plurkIt});
}
function plurkIt(i, t){
var createProperties = {url: "http://plurk.com/?qualifier=shares&status=" + encodeURIComponent(t.title) + "%20%2D%20" + encodeURI(t.url)};
chrome.tabs.create(createProperties);
}
options.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Share-it Options</title>
<script type="text/javascript" src="options.js"></script>
</head>
<body>
<ul id="menu"></ul>
<div class="summary">Changes will take place the next time you start your browser.
Or if you don't want to close the browser you could uncheck and recheck the enabled box next to this extension on the Extensions tab page.</div>
</body>
</html>
options.js
window.onload = function () {
ckb = chrome.extension.getBackgroundPage().entries;
var list = document.getElementById("menu");
for(i = 0; i < ckb.length; i++){
console.log(ckb[i]["active"]);
if(ckb[i]["active"] == 1){
var li = document.createElement("li");
var temp = "<input class="\"butt\"" type="\"checkbox\"" checked="checked" value="\""" />" + ckb[i]["menu"] + "";
li.innerHTML = temp;
list.appendChild(li);
}else{
var li = document.createElement("li");
var tempp = "<input class="\"butt\"" type="\"checkbox\"" value="\""" />" + ckb[i]["menu"] + "";
li.innerHTML = tempp;
list.appendChild(li);
}
}
as = document.getElementsByClassName("butt");
for(i=0;i<as.length;i++){
as[i].addEventListener("click",function(evt){
if(evt.target.checked == true){
chrome.extension.getBackgroundPage().setActive(evt.target.value);
}else{
chrome.extension.getBackgroundPage().setInactive(evt.target.value);
}
},false)
}
}
Version 0.5 update – fixed the graphics display in newest Chrome browser
If you downloaded an extension from somewhere other than the Google Store (or the Opera Store), Chrome will not let you install it on the fly (Opera will install it, however, you’ll have to go to the extensions page to enable it). You have to go to the browser menu and choose Tools->Extensions to open up the Extensions tab. Then drag the extension from wherever it is on the file-system to the open Extensions page. This should start the install process. If you ever feel funny about a packed extension that was downloaded you can unzip them to inspect the code (if you don’t have 7zip you’ll have to change the file extension to .zip – do it on a copy).
Related:
Chrome Browser:
Opera Next Extension Development:
References From Google Developer: