I have created a chrome extension which does something after its button is clicked.
However I dont want it be abused so I need the its code to be executed after some time.
How can I surround this code with a timeout in order to achieve this?
Thank you for reading me!
chrome.tabs.getSelected(null,function(tab) {
var Mp=tab.url.substring(0,23);
if(Mp=='https://www.example.com')
{
onWindowLoad();
chrome.extension.onMessage.addListener(function(request, sender) {
if (request.action == "getSource")
{
...Working here
}
});
}
else
{
message.innerHTML='<span style="color: #f00">This is not a valid page</span>';
}
});
function onWindowLoad()
{
var message = document.querySelector('#message');
chrome.tabs.executeScript(null, {file: "getPagesSource.js"});
}
I had to make a compromise so just after the getSelected I added the following line:
chrome.browserAction.disable(tab.Id);
It disables the action button thus it cant be clicked while the script sends the data to the server, as with this extension I grab the tab url in order to store it in my database.
After the ajax response and adding the following
if(xhr.readyState==4)
{
message.innerHTML=xhr.responseText;
chrome.browserAction.enable(tab.Id); /////<---THAT LINE
}
the button gets ready again to be clicked.
I couldnt find the way to add a specific delay in seconds, this way seems stupid but its working, as the response's delay from my server is enough for switching the 2 states of the action button.
With this, however another problem came up, which Ill write in different question.
Related
The new manifest version 3 of Chrome extension API offers a new function setExtensionActionOptions which allows a typical content blocker to display the number of blocked HTTP requests for a particular tab. The question is: when to call this API? How do I get notified that a request was just blocked and I need to call it with "increment: 1"? I'm looking for the event "onRequestBlocked" or some workaround.
The alarm API is no good because it fires once per minute. Ideally, I'd like to have this number updated in real time, as it is possible with the old MV2.
Another potential solution is to keep the service worker always running which kind of defeats the fruit of moving to MV3 at all.
There's no way to get notification outside of debugging in unpacked mode via onRuleMatchedDebug event.
You can enable automatic display of the number of the blocked requests on the icon badge.
For example, do it when the extension is installed/updated:
chrome.runtime.onInstalled.addListener(() => {
chrome.declarativeNetRequest.setExtensionActionOptions({
displayActionCountAsBadgeText: true,
});
});
You can also provide an explicit increment using tabUpdate property at any time you want:
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
if (msg.type === 'block') {
chrome.declarativeNetRequest.setExtensionActionOptions({
tabUpdate: {
tabId: sender.tab.id,
increment: msg.count, // Negative values will decrement the count
},
});
}
});
For future seekers: I've been able to find the following solution
chrome.webRequest.onErrorOccurred.addListener(
(details) => {
chrome.declarativeNetRequest.setExtensionActionOptions({
tabUpdate: {
tabId: details.tabId,
increment: 0
}
});
},
{
urls: ["<all_urls>"]
}
);
Yes, this also counts requests that are blocked by other extensions, but in practice I believe this is not so much of a problem. Another thing that's hard for me to explain, is this increment: 0 parameter. For some reason, the action count is actually incremented by increment + 1, not increment when the tabUpdate argument is provided. So, bizarre enough but works for me quite well this far.
The code below is the JavaScript file works with popup.html from a small project.
I use it for chrome extension development learning.
The first part of this code piece is getting two variable from chrome storage, let's call it part1.
The second part is a button-click event function,Let's call it part2.
The button is on popup page and called "spend".
In part2, I can set a breakpoint2 on chrome debugger DevTools,when I click the button on popup page, it will stop at breakpoint2.
But when I place a Breakpoint1 at part1,the code will not stop at that line, even I add one more line "debugger;", the program will not stop there.
So my problem is how to make the debugger stop at places like breakpoint1?
The source code for the extension:https://drive.google.com/file/d/1odxJy9pGnovzox2yXH-6MDO03_T7QIDE/view?usp=sharing
//popup.js
$(function(){
chrome.storage.sync.get(['total','limit'],function(budget){
//Breakpoint1
$('#total').text(budget.total);
$('#limit').text(budget.limit);
});
$('#spendAmount').click(function(){
//Breakpoint2
chrome.storage.sync.get(['total', 'limit'],function(budget){
var newTotal = 0;
if (budget.total){
newTotal += parseInt(budget.total);
}
var amount = $('#amount').val();
if (amount){
newTotal += parseInt(amount);
}
chrome.storage.sync.set({'total': newTotal}, function(){
bla();
bla();
}
});
$('#total').text(newTotal);
$('#amount').val('');
});
});
});
Any assistance is highly appreciated,Thanks in advance.
When I perform an action on my page, a spinner is displayed which disappears once the action is completed. I want to wait for the spinner to disappear so as to execute the assert statements.
I read the documentation which tells me how to wait for an element to appear but does not give info on how to wait for the element to disappear
I don't know how to implement this in Cucumber, Geb, Groovy project.
I'll edit/explain this in a bit, when i have more time:
In your page object:
static content = {
loadingSpinner(wait:3, required:false) { $("mat-spinner") }
//this wait:3 is redundant (i think) if we also give the waitFor() a timeout
//required:false allows our wait !displayed to pass even if the element isnt there
}
def "Handle the loader"() {
try {
waitFor(2) { loadingSpinner.isDisplayed() }
} catch (WaitTimeoutException wte) {
//do nothing, if spinner doesnt load then thats ok
//most likely the spinner has come and gone before we finished page load
//if this is not the case, up our waitFor timeout
return true;
}
waitFor(10) { !loadingSpinner.isDisplayed() }
}
As described in the documentation, the waitFor block uses Groovy Truth to know when it waited long enough. When you put a Navigator in it and the element is currently not present, it will wait for it to appear or until the maximum waiting time it elapsed.
So if want to wait for an element to disappear, you can simply put it in a waitFor like this:
// go to the page
waitFor(2) { $(".loadingspinner").displayed }
waitFor(10) { !$(".loadingspinner").displayed }
// do your assertions
In case the loading spinner already disappeared, waitFor will return immediately. In case it never disappears, it will throw a WaitTimeoutException after 10 seconds, which will make your test fail.
I believe this is related to the asynchronous nature of chrome extensions.
This section of my code:
alert(tab.title);
chrome.tabs.executeScript(tab.id, {code:"document.title = 'test'"});
Works fine, but as soon as I remove the alert, it stops working. Is there anything I can do to remove the alert but still have the js injected?
EDIT: More Code
tabs is a global array of tab objects.
chrome.tabs.onSelectionChanged.addListener(function (tabId) {
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].id == tabId) {
var tab = tabs[i];
while (i < tabs.length) {//length-1
tabs[i] = tabs[i+1];
i++;
}
tabs.pop();
alert(tab.title);//WHY IS THIS NEEDED
chrome.tabs.executeScript(tab.id, {code:"document.title = document.title.substring(1)"});
return;
}
}
});
I am very confused. Changing it the following solves the problem:
chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});
However, as soon as I change the delay to 50, the script doesn't get executed again. I would prefer not to have to have to make this delay. Does anyone know whats going on?
I know this is an old question, but if anyone is looking - wrap the chrome.tabs.executeScript method in a timeout.
setTimeout(function(){chrome.tabs.executeScript(tab.id, {code:"setTimeout('document.title = document.title.substring(1)',100)"});},500);
It's certainly not ideal but it gets the job done.
Sounds like you have a race condition. My best guess would be to change the injected code to execute on onLoad.
I want to trigger some code when page action or browser action popup gets closed. I tried listening to onunload and onbeforeunload events on <body> or window but they never fire.
It's a bug, but a chromium developer posted a workaround.
http://crbug.com/31262#c13
As looks like there is no straight forward solution, this is what I ended up doing if anyone interested.
Periodically ping background page from the popup, and if background page is not received ping within some time period, it triggers required action. Works like a time bomb :)
In background page:
var timeoutId = 0;
function popupPing() {
if(timeoutId != 0) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
popupClosed();
timeoutId = 0;
}, 1000);
}
function popupClosed() {
//...
}
In popup:
ping();
function ping() {
chrome.extension.getBackgroundPage().popupPing();
setTimeout(ping, 500);
}
(note that popup pings 2 times faster than "trigger" time in background page)