selection and site search in chrome extension

I'm trying to write google chrome extension that accepts user-selected word and user-defined web site and searches this word on that site (via Google and contextmenu).There's a form in options page. User enters sites in form fields (there's a variable number of fields/sites- user specifies which sites and therefore how many).All sites are saved to array. array is saved to localStorage["arr"]. all of this was in options.html.

On bg.html (Background page) first of all, i get array from localStorage (all is fine by now).then i create contextmenu items in a loop. I have ONLY ONE onclick event handler for all contextmenu items. Inside of event handler, i'm trying to get the right array element (on which site to search) and selectontext(what to search), and then open a new tab with google search results.
My BIGGEST problems: 1)i can't get array element (in event handler) at all!!(on which site to search is undefined). 2)onclick event works only for one of context menu items. 3)sometimes, contextmenu items are created but clicking doesn't work at all!!

My code: manifest.json

{
  "name": "Context Site Search",
  "version" : "0.0.0.1",
  "background_page" : "bg.html",
  "options_page": "options.html",
  "permissions" : [
    "tabs",
    "contextMenus",
    "http://www.google.com"
    ]
}

bg.html:

<script type="text/javascript">

var ar = localStorage.getItem("arr").split(",");//getting array from localStorage 

for (var i=0;i<ar.length;i++){ // creating contextmenu items in a loop

chrome.contextMenus.create({
    "title": "find ' %s' ? "+ ar[i],
    "contexts": [ "selection"],
    "onclick" : clickhandler
});
}

var clickhandler = function(e,ar){
var baseUrl = "http://www.google.com/search?q=site%3A";

if (e.selectionText){
baseUrl += ar[i]+ "&q="+ encodeURI(e.selectionText);
chrome.tabs.create(
{"url": baseUrl}

);

 }

}

</script>

Please, help! what am i doing wrong?? how to fix this?? Any help is appreciated.

Thanks in advance!!

UPDATE: Thanks to serg, i'm finally getting something.. but there are new issues: 1) number of contextmenu items mysteriously doubles (and even quintuples!! )sites entered at options page. 2)clicking save button doesn't immediately replace old menuitems with new ones.(Reloading extension is obviously needed). i suspect, i incorrectly wrote save function which runs upon save button click... here's code:

var arr = [];
function save() {
localStorage.clear();

var nodes = document.querySelectorAll("input[type=text]");
for (var i=0; i<nodes.length; i++){
    if (nodes[i].value == "" ){
        alert('Enter Data!');return false;
} else {
 arr.push( nodes[i].value);


   }}

localStorage['arr'] =  JSON.stringify(arr);

}


</script>

UPDATE2:

i figured out doubling/quintupling thing. it depends on how many times user clicks save button.. 1)Is there a chance to prevent this?? e.g. multiple clicks add ONLY ONE set of values to array?? 2)Contextmenu items still don't change. they change ONLY AFTER reloading extension.. :(( What is the difference between reloading extension and changing localStorage??

Answers:

Answer

When you assign a function to onclick property it is not evaluated right away. By the time it is evaluated your loop is ended long time ago and ar[i] doesn't contain what you expect.

It is a classic javascript problem which is solved with closures:

chrome.contextMenus.create({
    "title": "find ' %s' ? "+ ar[i],
    "contexts": [ "selection"],
    "onclick" : (function(element) {
                    return function(info, tab) {
                        var baseUrl = "http://www.google.com/search?q=site%3A";

                        if (info.selectionText) {
                            baseUrl += element + "&q="+ encodeURI(info.selectionText);
                            chrome.tabs.create({"url": baseUrl});
                        }
                    }
                })(ar[i])
});

We created anonymous function which is evaluated right away and returns a real event handler. The trick is that current ar[i] value will now be always available as element variable inside the closure.

Answer
var ar = JSON.parse(localStorage.getItem("arr")); // you should also use JSON.stringify to store the array
var menuitems = []; // array to hold menu item ID's and sites

for (i in ar)
{
    menuitem = chrome.contextMenus.create({
        "title": "find ' %s' ? " + ar[i],
        "contexts": ["selection"],
        "onclick": function(e)
        {
            var baseUrl = "http://www.google.com/search?q=site%3A";

            if (e.selectionText)
            {
                baseUrl += encodeURIComponent(menuitems[e.menuItemId]) + "&q=" + encodeURIComponent(e.selectionText);
                chrome.tabs.create({ "url": baseUrl });
            }
        }
    });

    menuitems[menuitem] = ar[i]; // store the ID of the current menuitem with the site
}

Tested, this should do the trick. Notice I also added a few improvements, like using for (.. in ..) for the loop, and encodeURIComponent for the URL arguments (encodeURI is for complete URLs, encodeURIComponent is for URI components, i.e. arguments). Additionally, use JSON for storing data in localStorage.

What I think you were doing wrong is that you defined clickHandler after creating the menu item. When you create the menu item, clickHandler is null, and nothing happens when you click it. I fixed this by simply defining the function inline in the menu item creation.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.