2013-10-24 3 views
1

Я создаю расширение, которое нужно иметь возможность запускать скрипт контента несколько раз при нажатии на кнопку действия страницы. У меня это в моем background.js:Хром Расширение не работает каждый раз, когда нажата кнопка действия приложения.

chrome.pageAction.onClicked.addListener(function(tab) { 
    alert('calling content_script'); 
    chrome.tabs.executeScript(null, { 
     file: 'content_script.js' 
    },function(){alert("success");}); 
}); 

Это срабатывает при первом нажатии кнопки. Когда вы нажимаете второй раз, я получаю всплывающее сообщение «вызов content_script», но сценарий содержимого никогда не выполняется. Почему это?

Вот фон сценарий в полном объеме:

function checkForValidUrl(tabId, ChangeInfo, tab){ 
    if(tab.url.indexOf("tiger.armstrong")> -1){ 
     chrome.pageAction.show(tabId); 
     if(tab.url.indexOf("tiger.armstrong") == 0){ 
      chrome.pageAction.hide(tabId); 
     } 
    } 
} 

chrome.tabs.onUpdated.addListener(checkForValidUrl); 

chrome.pageAction.onClicked.addListener(function(tab) { 
    alert('calling content_script'); 
    chrome.tabs.executeScript(null, { 
     file: 'content_script.js' 
    },function(){alert("success");}); 
}); 

Вот манифест:

{ 
    "name": "LiveLab Post Grades", 
    "version": "2.0", 
    "permissions": [ 
    "activeTab","tabs","http://*/*","https://*/*" 
    ], 
    "background": { 
    "scripts": ["jquery.min.js","background3.js"], 
    "persistent": false 
    }, 
    "page_action": { 
    "default_icon": { 
     "19": "GIcon.png" 
    }, 
    "default_title": "LiveLab Tools" 
    }, 
    "content_scripts": [ { 
    "js": [ "jquery.min.js" ], 
    "matches": [ "http://*/*", "https://*/*"], 
    "run_at": "document_end" 
    }], 
    "manifest_version": 2 
} 

Вот скрипт содержания:

var livelabtools = { 
    /** 
    * this function is like window.open, but it can POST (rather than GET) from js 
    * source: http://canop.org/blog/?p=426 
    */ 
    canop_open: function (verb, url, data, target) { 
     var form = document.createElement("form"); 
     form.action = url; 
     form.method = verb; 
     form.target = target || "_self"; 

     if (data) { 
      //for (var key in data) { 
       var input = document.createElement("input"); 
       input.name = 'data'; 
       input.value = data;//typeof data[key] === "object" ? JSON.stringify(data[key]) : data[key]; 
       form.appendChild(input); 
       //console.log(form); 
      //} 
     } 
     // these two lines are only needed for ie 
     //form.style.display = 'none'; 
     //document.body.appendChild(form); 
     form.submit(); 
     console.log("form submit === " + form); 
     form.remove(); 
    }, 
    post_grades: function() { 
     alert('in post grades!!!!'); 
     var str, exercise, 
     i = 0; 
     grades = {}; 
     do { 
      ex_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc3:st3"; 
      lname_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc1:st1"; 
      grade_str = "form1:tabSet1:tabInstr:lp2:tabSet4:tabp:lpProgress:ts1:tab7:lp7:table3:rg3:" + i + ":tc7:st7_field"; 
      exercise = document.getElementById(ex_str); 
      lname = document.getElementById(lname_str); 
      grade = document.getElementById(grade_str); 
      if (exercise != null) { 
       if (grades[lname.innerHTML] === undefined) 
        grades[lname.innerHTML] = {}; 
        console.log(lname.innerHTML + ", " + exercise.innerHTML + ", " + grade.innerHTML); 
       if (grade.value != null && grade.value != '') 
        grades[lname.innerHTML][exercise.innerHTML] = grade.value; 
       else 
        grades[lname.innerHTML][exercise.innerHTML] = "0"; 
      } 
      i++; 
     } while (exercise != null); 
     // console.log(JSON.stringify(grades)); 
     // console.log(JSON.stringify(grades).length) 
     //window.open("http://aspen2.cscofc.info/jsontocsv.php?data="+JSON.stringify(grades)); 
     console.log('posting...' + "\n JSON.String... = "+ JSON.stringify(grades)); 
     livelabtools.canop_open("post", "http://aspen2.cscofc.info/jsontocsv.php", JSON.stringify(grades));   
     console.log('done'); 
     return "function end"; 
    } 
} 

console.log(livelabtools.post_grades()); 

Я не пойду в деталях об этом, если только не задано, но важными частями для заметок являются оператор return и журнал консоли. Все работает отлично в первый раз, когда нажата кнопка действия страницы, и когда закончите, я получаю «конец функции», напечатанный на консоли. Однако после начального запуска, когда я нажимаю кнопку действия с страницей, я получаю предупреждение о вызове content_script и ничего больше не происходит. Почему мой контент-скрипт не запускается более одного раза?

+0

с вашим кодом, я был в состоянии успешно выполнить сценарий содержание каждый раз, когда я нажал на действия страницы. Не могли бы вы добавить свой манифест и остальную часть вашего фонового скрипта (в частности, как вы показываете страницу действий)? –

+0

@Metoule Спасибо за ваше время, я обновил вопрос. – lampwins

+0

Он отлично работает .. что заставляет вас говорить, что нет? Возможно, ваш скрипт контента является виновником; my - это просто 'console.log (« Я здесь »);' и он регистрирует сообщение столько раз, сколько я нажимаю на действие страницы. –

ответ

2

Похоже, что когда сценарий уже был введен, он снова не вводится.
Таким образом, способ начать было бы инициировать ваше действие, передав сообщение сценарию содержимого. (Конечно, если сценарий содержание не было введено еще, вам нужно вводить его в первую очередь.)

Одно решение, которое я придумал (и после испытания подтвердили, что работает отлично) заключается в следующем:

  1. На странице pageAction.onClicked отправьте сообщение с фоновой страницы на сценарий содержимого, попросив его что-то сделать (например, вывести оценки). Кроме того, запросите ответ, который будет отправлен обратно на исходную страницу.
    [См также, chrome.tabs.sendMessage(...).]

  2. Если сценарий контент уже введен, есть он получит сообщение, отправить подтверждение обратно на фоне страницы и продолжайте делать что-то (например, размещая классы) , Этот процесс может происходить столько раз, сколько вы хотите.
    [См также, chrome.runtime.onMessage.]

  3. В первый раз, что pageAction.onClicked увольняют, не будет никакого содержания сценария прослушивания сообщений. В этом случае подтверждения сообщения не будет. Вместо этого будет установлен chrome.runtime.lastError. В этом случае исходная страница должна будет сначала ввести сценарий содержимого, а затем отправить сообщение еще раз.
    [См также, chrome.runtime.lastError.]


говоря теоретически возможный, что должен это сделать!
Practicaly, это пример кода, который работал для меня:

manifest.json: (Примечание: Если у вас есть более конкретные требования в отношении страниц, вам нужно получить доступ, вы можете включить их в манифесте и избавиться от некоторых разрешений)

{ 
    ... 
    "background": { 
     "persistent": false, 
     "scripts": ["background.js"] 
    }, 

    "page_action": { 
     "default_title": "Test Extension" 
    }, 

    "permissions": [ 
     "tabs", 
     "http://*/*", 
     "https://*/*" 
    ] 
    ... 
} 

background.js:.

function checkForValidURL(tabId, info, tab) { 
    var idx = tab.url.indexOf("tiger.armstrong"); 
    if (idx > 0) { 
     chrome.pageAction.show(tabId); 
    } else { 
     chrome.pageAction.hide(tabId); 
    } 
} 
chrome.tabs.onUpdated.addListener(checkForValidURL); 

function onPageActionClicked(tab) { 
    // Send message to content script, asking to post grades 
    alert("Calling content_script..."); 
    chrome.tabs.sendMessage(tab.id, { action: "postGrades" }, function() { 
     if (chrome.runtime.lastError) { 
      // The error indicates that the content script 
      // has not been injected yet. Inject it and... 
      chrome.tabs.executeScript(tab.id, { 
       file: "content.js" 
      }, function() { 
       if (!chrome.runtime.lastError) { 
        // ...if injected successfully, send the message anew 
        onPageActionClicked(tab); 
       } 
      }); 
     } else { 
      // The content script called our response callback, 
      // confirming that it is there and got our message 
      alert("Message got through !"); 
     } 
    }); 
}; 
chrome.pageAction.onClicked.addListener(onPageActionClicked); 

content.js:

var livelabtools = { 
    /** 
    * This function is like window.open, but it can POST (rather than GET) from 
    * JS source: http://canop.org/blog/?p=426 
    */ 
    canop_open: function (method, url, data, target) { 
     var form = document.createElement("form"); 
     form.action = url; 
     form.method = method; 
     form.target = target || "_self"; 

     // 'data' is an object with key-value pairs 
     // of fields to be sent 
     if (data) { 
      for (var key in data) { 
       var input = document.createElement("input"); 
       input.name = key; 
       input.value = (typeof(data[key]) === "object") 
         ? JSON.stringify(data[key]) : data[key]; 
       form.appendChild(input); 
      } 
     } 

     form.submit(); 
     form.remove(); 
    }, 
    post_grades: function() { 
     console.log("Posting some grades..."); 
     livelabtools.canop_open("POST", 
       "http://aspen2.cscofc.info/jsontocsv.php", 
       "{}"); 
     console.log("Grades sent !"); 
    } 
} 

// Listen for messages from the background page 
// (It actually listens for messages from anyone in the context, 
// but the background page is the one that interrests us) 
chrome.runtime.onMessage.addListener(function(msg, sender, response) { 
    // If we've been asked to post grades... 
    if (msg.action && (msg.action == "postGrades")) { 
     // ...confirm we got the message and... 
     response(); 
     // ...do what we do best: post grades ! 
     livelabtools.post_grades(); 
    } 
}); 

Будем надеяться, это покрывает его :)

+0

Что вы сказали об однократной инъекции скрипта контента, имеет смысл, но это указано в документации Google? (может быть, я просто плохо читаю). В любом случае, ваше решение работает просто отлично, спасибо! Тем не менее, я предлагаю одно для будущих читателей, мой сценарий контента называется 'content_script.js', а когда вы вызываете вызов, вы ссылаетесь на' content.js'. В любом случае спасибо за помощь! – lampwins

+0

Я не могу найти документацию об одноразовой инъекции. Мой вывод основан только на наблюдениях (вот почему я написал «* Это ** кажется ** как ... *»). Если вы присмотритесь, вы заметите, что я назвал свой контентный скрипт «content.js» (это название над соответствующим блоком кода), поэтому я ссылаюсь на него как на «контент».js "в манифесте (но это, вероятно, слишком много деталей для тех, кого интересует). Я рад, что это сработало для вас :) – gkalpak

Смежные вопросы