выбор и поиск по сайту в расширении Chrome

#javascript #google-chrome-extension

#javascript #google-chrome-расширение

Вопрос:

Я пытаюсь написать расширение Google Chrome, которое принимает выбранное пользователем слово и определяемый пользователем веб-сайт и выполняет поиск по этому слову на этом сайте (через Google и contextmenu).На странице настроек есть форма. Пользователь вводит сайты в поля формы (существует переменное количество полей / сайтов — пользователь указывает, какие сайты и, следовательно, сколько).Все сайты сохраняются в массив. массив сохраняется в localStorage[«arr»]. все это было в options.html.

На bg.html (Фоновая страница) прежде всего, я получаю массив из localStorage (на данный момент все в порядке).затем я создаю элементы contextmenu в цикле. У меня есть ТОЛЬКО ОДИН обработчик события onclick для всех элементов contextmenu. Внутри обработчика событий я пытаюсь получить правильный элемент массива (на каком сайте искать) и selectontext (что искать), а затем открыть новую вкладку с результатами поиска Google.
Мои САМЫЕ БОЛЬШИЕ проблемы: 1) я вообще не могу получить элемент массива (в обработчике событий)!!(на каком сайте выполнять поиск, не определено). 2) событие onclick работает только для одного из пунктов контекстного меню. 3) иногда элементы contextmenu создаются, но нажатие на них вообще не работает!!

Мой код: 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:";

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

);

 }

}

</script>
  

Пожалуйста, помогите! что я делаю не так?? как это исправить??
Любая помощь приветствуется.

Заранее спасибо!!

ОБНОВЛЕНИЕ: Благодаря serg янаконец-то что-то получаю.. но есть новые проблемы: 1) количество элементов contextmenu таинственным образом удваивается (и даже увеличивается в пять раз!! )сайты, введенные на странице параметров. 2) нажатие кнопки сохранить не приводит к немедленной замене старых элементов меню на новые.(Очевидно, требуется перезагрузка расширения). я подозреваю, что я неправильно написал функцию сохранения, которая запускается при нажатии кнопки сохранения… вот код:

 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>
  

ОБНОВЛЕНИЕ2:

я разобрался с удвоением / удваиванием в пять раз. это зависит от того, сколько раз пользователь нажимает кнопку сохранить.. 1) Есть ли шанс предотвратить это?? например, несколько кликов добавляют ТОЛЬКО ОДИН набор значений в массив?? 2) Элементы Contextmenu по-прежнему не меняются. они меняются ТОЛЬКО ПОСЛЕ перезагрузки расширения .. :(( В чем разница между перезагрузкой расширения и изменением localStorage??

Комментарии:

1. Если вам нужно изменить пункты контекстного меню, просто удалите все, используя chrome.contextMenus.removeAll , и создайте их заново. Код в вашем обновлении выглядит нормально, проблема в чем-то другом.

2. можно ли использовать localStorage.clear() в начале функции save()??

3. Я думаю, в этом нет необходимости, вы все равно перезапишете старое значение.

Ответ №1:

Когда вы назначаете функцию onclick свойству, она вычисляется не сразу. К моменту его оценки ваш цикл давно завершен и ar[i] не содержит того, что вы ожидаете.

Это классическая проблема javascript, которая решается с помощью замыканий:

 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:";

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

Мы создали анонимную функцию, которая сразу же вычисляется и возвращает реальный обработчик событий. Хитрость в том, что текущее ar[i] значение теперь всегда будет доступно как element переменная внутри замыкания.

Ответ №2:

 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:";

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

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

Проверено, это должно сработать. Обратите внимание, что я также добавил несколько улучшений, таких как использование for (.. in ..) для цикла и encodeURIComponent для аргументов URL ( encodeURI для полных URL, encodeURIComponent для компонентов URI, то есть аргументов). Кроме того, используйте JSON для хранения данных в localStorage .

Я думаю, вы делали неправильно то, что вы определили clickHandler после создания пункта меню. При создании пункта меню clickHandler имеет значение null, и при нажатии на него ничего не происходит. Я исправил это, просто определив встроенную функцию в создание пункта меню.

Комментарии:

1. это работает, но очень плохо. нажатие на любой элемент меню выполняет поиск только на одном веб-сайте.

2. @DrStrangeLove, ты прав, видимо, я не тестировал его тщательно. Редактирование в рабочей версии.