javascript code of my firefox extension keeps reloading the page uncontrolablly - javascript

I am trying to create an Firefox add-on/extension to add a parameter to the end a URL of a particular page and reload the page with the new URL with the parameter added.
The problem with the following code is that it does add the parameter, but it keeps reloading the new page uncontrollably
initial URL
https://www.example.com/questions/foo/bar
paged reloaded with changed URL
https://www.example.com/foo/bar?abcd=1
script.js
var url = window.location.href;
if (url.indexOf('?') > -1){
window.stop()
}else{
url += '?abcd=1'
}
window.location.href = url;
manifest.json
{
"manifest_version": 2,
"name": "some name",
"version": "1.0",
"description": "some description",
"icons": {
"48": "icons/explore-48.png"
},
"content_scripts": [
{
"matches": ["*://www.example.com/*"],
"js": ["script.js"]
}
]
}
Note : I did try out few examples found for the same scenario from Stackoverflow

JavaScript doesn't wait for the whole if statement to execute before continuing to what is after it, so the value of url never changes before the page is reloaded. To fix this, simply move window.location.href = url; into your else, like this:
var url = window.location.href;
if (url.indexOf('?') > -1) {
window.stop()
} else {
url += '?abcd=1'
window.location.href = url;
}

Related

refresh page until it changes chrome extension

i'm building extension for google chrome that refresh page until it changes its link.
I tried this code but it didn't worked:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (/^https:\/\/meet.google.com\/lookup/.test(changeInfo.url)) {
var intervalId = window.setInterval(function() {
var code = 'window.location.reload(); ';
chrome.tabs.executeScript(tab.id, {code: code});
}, 30000);
}
else {
window.clearInterval(intervalId)
}
});
i want to stop refresh when meet.google.com/lookup/ changes in another link, that could be also meet.google.com or meet.google.com/abcdef/.
So it refresh the page, but when the link of google meet changes, it keeps to refresh page. How can i solve? Thanks everyone!
P.S: I added my answer on a comment for be more understandable
I am assuming your aim is to keep refreshing a tab unless its location is meet.google...(the regex you have used), every thirty seconds.
If that is your aim, the problem here, is that the intervalID is lost once the event listener is executed. So, you need to maintain the intervalID outside of the listener scope so that you can clear it when that tab changes the URL.
I have the code below, try this
var intervalMap = {};
function handleUpdated(tabId, changeInfo, tabInfo) {
if (changeInfo.url) {
console.log("Tab: " + tabId + " URL changed to " + changeInfo.url);
if (changeInfo.url.indexOf("https://meet.google.com/?authuser") > -1) {
console.log("Found URL to reload. Added interval");
var intervalId = window.setInterval(function () {
var code = "window.location.reload(); ";
chrome.tabs.executeScript(tabId, { code: code });
}, 3000);
//Save the intervalId to our map
intervalMap[tabId] = intervalId;
} else if (intervalMap[tabId]) {
//Take interval ID from map and clear it
console.log("Tab changed to differente URL. Removed interval");
window.clearInterval(intervalMap[tabId]);
}
}
}
chrome.tabs.onUpdated.addListener(handleUpdated);
Manifest (Version 2)
{
"name": "Test",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["background.js"]
},
"permissions": ["background", "tabs", "https://meet.google.com/*"]
}
Edit: Have updated the code to add relevant console logs. Added manifest to ensure that required permissions are added

Chrome extension run Javascript on X next tabs

I'm making an extension and I can't understand how to do the following -
My extensions currently open X amount of tabs, according to a specific text. Now I want it to run a specific script in every new tab it opens.
Manifest.json:
{
"name": "Asaf Feedback Opener",
"version": "1",
"manifest_version" : 2,
"description": "Opens any View Item on the current page",
"background" : {
"scripts" : ["background.js"]
},
"browser_action": {
"default_icon": "icon.png"
},
"permissions": ["activeTab", "tabs"]
}
Now it runs the following code in the current page of clicking:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "testScript.js"});
});
Javascript:
var links = document.getElementsByTagName("a");
numofview = 0;
for (i = 0; i < links.length; i++)
{
if (links[i].innerHTML.startsWith("View Item"))
{
numofview = numofview+1;
window.open(links[i].getAttribute("href"), "_blank");
}
}
Now, In the above JS It opens links in a new tab. I want the next code to run in every tab that the previous code had opened:
var soldlinks = document.getElementsByTagName("a");
for (i = 0; i < soldlinks.length; i++)
{
if (soldlinks[i].innerHTML.endsWith("sold"))
{
var soldlength = soldlinks[i].innerHTML.length
var amount = soldlinks[i].innerHTML.substring(0,soldlength-5);
if (Number(amount) >= 5)
window.open(soldlinks[i].getAttribute("href"), "_self");
else
window.close()
}
}
I actually don't know JS or the chrome extensions coding language at all, I've been improvising with google to get this far.
Both scripts work in separate, I don't how to go forward from here.
Make your injected content scripts only collect and return the URLs to the background page script by leaving the data as the last expression in the file (see the code below). It will be available in executeScript's callback parameter which is an array of results per each frame in a tab so our data is inside its element 0 (main frame is 0 = the page itself).
The background page script will open the tabs and use executeScript to inject the new content script into the opened tabs. This will require additional permissions in manifest.json for the opened sites or all URLs if you don't know which sites may be referred:
"permissions": ["<all_urls>", "tabs"]
Use an event page that's automatically unloaded when your extension is not used.
"background" : {
"scripts" : ["event.js"],
"persistent": false
},
event.js (previously background.js now renamed for clarity):
chrome.browserAction.onClicked.addListener(collectViewItems);
function collectViewItems(tab) {
chrome.tabs.executeScript(tab.id, {file: 'collect-view-items.js'}, results => {
results[0].forEach(openViewItem);
});
}
function openViewItem(url) {
chrome.tabs.create({url, pinned: true, active: false}, collectSoldItems);
}
function collectSoldItems(tab) {
chrome.tabs.executeScript(tab.id, {file: 'collect-sold-items.js'}, results => {
chrome.tabs.remove(tab.id);
results[0].forEach(openSoldItem);
});
}
function openSoldItem(url) {
chrome.tabs.create({url, active: false});
}
collect-view-items.js:
[...document.links]
.filter(a => a.textContent.trim().startsWith('View Item'))
.map(a => a.href);
collect-sold-items.js:
[...document.links]
.filter(a => a.textContent.trim().endsWith('sold') && parseInt(a.textContent) >= 5)
.map(a => a.href);
ES2015 syntax is used, available in modern browsers by default.

Chrome vs. Firefox Extensions

I wrote a simple extension for Firefox. Unfortunately, my friend uses Chrome, and I don't understand why the same code does nothing in Chrome. What's the difference between Firefox's Tabs and Chrome's Tabs? Here's the code:
Manifest.json:
{
"manifest_version": 2,
"name": "customAddon",
"description": "Unsurprisingly, this addon does things.",
"version": "1",
"background": {
"persistent": true,
"scripts": ["customAddon.js"]
},
"permissions": [
"tabs",
"http://*.com/"
]
}
customAddon.js:
chrome.tabs.onUpdated.addListener(function(tabId , info) {
if (info.status == "complete") {
if (window.location.href == 'http://ninjakiwi.com/Games/Action/Play/SAS-Zombie-Assault-4.html') {
var elem = document.getElementById('secondary');
elem.innerHTML = '';
var removeLinks = (function() {
return function(passedElems){
for (i = 0; i < passedElems.length; i++) {
passedElems[i].setAttribute('onclick','return false;');
}}})();
removeLinks(document.getElementsByClassName('group'));
removeLinks(document.getElementsByClassName('nav'));
removeLinks(document.getElementsByClassName('local-skin'));
document.getElementsByClassName('header-bar')[0].setAttribute('style','padding-left:85px; padding-right:-85px;');}}
}
});
Your customAddon.js code runs is a separate, invisible page, called the background page.
Of course, its location.href will never be that URL, and its elements will never match what you expect.
What you really need is a content script. You can set the filter that tells which page it should be loaded in, and then it will execute with access to the page's DOM, which is precisely what you need. No need to use tabs API.

How can I determine if a Chrome extension is in a popup from the content script?

Background
I have a Chrome extension with a browser action to launch index.html in a new tab.
I'd like to update the extension to open index.html in a popup first, and then include a button users can click to optionally open the app in a new tab.
I don't want this button to show when it's not a popup (since it wouldn't make sense), which means the content script needs to know whether it is a popup in order to show the button.
Questions
This is a two part question:
How does a Chrome extension popup know it's a popup?
How do I pass that information to a content script before the popup is rendered?
What I've tried
I've tried to use chrome.extension.getViews in background.js to firstly determine if a popup is open. Then, I send a message to the content script which then shows the button. However I haven't gotten it to work - views is always an empty array, and the message doesn't seem to ever be received by the content script.
Here are the relevant parts of my manifest.json file:
"background": {
"scripts": ["background.js"]
},
"browser_action": {
"default_icon": {
"19": "img/icon19.png",
"38": "img/icon38.png"
},
"default_title": "Super Simple Tasks",
"default_popup": "index.html"
}
And here's what I've been trying in my background.js:
// Get all popups
var views = chrome.extension.getViews({ type: "popup" });
// Send a message if there is a popup
if (views.length > 0){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {action: "popup_open"}, function(response) {});
});
};
And then in my content script, I listen for the message and then add a class to the body:
// Listen for the message
chrome.extension.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.action === 'popup_open') {
// My code here to show the button
}
});
After talking with a friend I discovered an elegant solution that doesn't involve messaging or even a background.js script at all.
I can specify ?popup=true in manifest.json and check for that parameter in my extension's content script. Here's the code:
manifest.json now looks like this:
"browser_action": {
"default_icon": {
"19": "img/icon19.png",
"38": "img/icon38.png"
},
"default_title": "Super Simple Tasks",
"default_popup": "index.html?popup=true"
}
The following code in my content script (taken from this answer) checks for ?popup=true. Worth noting that this function can handle multiple URL parameters split by the & character.
function getUrlParameter(sParam) {
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++) {
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == sParam) {
return sParameterName[1];
}
}
}
var isPopup;
isPopup = getUrlParameter('popup') === 'true';
Finally, add a class to the body if it's a popup:
$('body').toggleClass('popup', isPopup)
In the manifest file add a hash to the url:
"browser_action": {
"default_popup": "index.html#popup"
}
In JavaScript:
if (location.hash === '#popup')
// do something awesome!
I needed something similar as i wanted to create some cross-compatible code for all script types.
I found that this worked quite well.
const SCRIPT_TYPE = (() => {
if (chrome && chrome.extension && chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() === window) {
return 'BACKGROUND';
} else if (chrome && chrome.extension && chrome.extension.getBackgroundPage && chrome.extension.getBackgroundPage() !== window) {
return 'POPUP';
} else if (!chrome || !chrome.runtime || !chrome.runtime.onMessage) {
return 'WEB';
} else {
return 'CONTENT';
}
})();
chrome.tabs.getCurrent(function(tab) {
if(tab == undefined)
document.getElementById('mButton').style.display = 'inline-block';
});
I initially set the button's display: none; if the returned tab is undefined, means it's not a tab (so it is popup) and then I display button. You can reverse it of course.
======
Well the sending parameter also works, which in that case you won't need to add the query string in the manifest, just adding it in button's click listener would suffice.
btn.addEventListener('click', function() {
chrome.tabs.create({url: "index.html?popup=false"});
});
And then the same process (reading the query string and comparing, etc).
======
Alternatively you can make a copy of index.html say index2.html, remove the button from index.html, use index2.html in the manifest and index.html for button click. :)

how do i toggle on/off content_scripts in a google extension?

I have this simple extension, it displays icon on chrome's toolbar and shows a enable/disable button. i want to add function to the button to disable or enable the content_script.js which fires on visiting google website:
popup.js
var setLayout = function(){
var list = document.createElement('ul');
var enable = document.createElement('li');
enable.appendChild(document.createTextNode('Enable Script'));
enable.onclick = function(){toggle(0)};
var disable = document.createElement('li');
disable.appendChild(document.createTextNode('Disable Script'));
disable.onclick = function(){toggle(1)};
list.appendChild(disable);
document.body.appendChild(list);
function toggle(n){
list.removeChild( n == 0 ? enable : disable);
list.appendChild(n == 0 ? disable : enable);
}
};
document.addEventListener('DOMContentLoaded', setLayout, false);
manifest.json
{
"manifest_version": 2,
"name": "test",
"description": "test",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["https://www.google.co.uk/"],
"js": ["content_scripts.js"]
}
]
}
content_scripts.js
(function(){
alert('hello');
})();
i'm new to google extensions and have no idea how to do that, i thought about changing the manifist after clicking disable/enable buttons but couldn't find the right command to do so after reading the documentations on google website!
any help would be greately appreciated.
After some research i figured out how to solve this by using backround pages, sendMessage and localstorage.
background pages work as a communicator between popup.js and content_scripts.js, they are on two different documents and it's not possible to pass variables between them directly.
To enable background page in mamifest i added:
"background": {
"scripts": ["background.js"],
"persistent": true
},
localstorage save variables locally and remember them even when the browser is closed and opened again, so when enable/disable button is clicked it set localStorage['status'] = 1/0 which can be accessed through background.js and passed to content_scripts.js.
To set localStorage variable i added to popup.js:
if(!localStorage.status) localStorage['status'] = 1;
toggle(2);
enable.onclick = function(){toggle(0)};
disable.onclick = function(){toggle(1)};
function toggle(n){
if((n == 0) && (enable.parentNode == list)){
list.removeChild(enable);
list.appendChild(disable);
localStorage.status = 1;
}else if((n == 1) && (disable.parentNode == list)){
list.removeChild(disable);
list.appendChild(enable);
localStorage.status = 0;
}else if((n == 2) && (!list.hasChildNodes())){
list.appendChild((localStorage.status == 1) ? disable : enable);
chrome.browserAction.setIcon({path: (localStorage.status == 1) ? "icons/icon19.png" : "icons/icon19_disabled.png"});
}else{
return;
}
}
To pass localStorage.status to content_scripts.js i had to use sendMessage on content_scrips.js which on loaded send request message to background.js, and onMessage on background.js which listens to requests and send response to content_scripts.js with the localStorage.status value.
background.js:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.type == "status") sendResponse({status: localStorage.status});
});
content_scripts.js
var fn = function(){...};
chrome.runtime.sendMessage({type: "status"}, function(response) {
if(response.status == 1) fn();
return;
});
That's it, hope someone find it useful.
Try injecting the content script using code rather than the manifest file, something like this:
chrome.tabs.executeScript(null, {file: "content_script.js"});
You can then use message passing between the background page and your content script to decide whether or not to inject the content script, or perhaps an if statement in the content script itself that only runs when a flag set by the extension's action button.
You can use a browser action event to detect when the action button is pressed.

Categories