I want to make an extension that changes the title on Chrome's built in stopwatch when i start and stop it. I am getting an error trying to retrieve the button's class. The JavaScript works when pasted in the browser console so I think the problem is with the json file.
Here is my JavaScript.
var title = document.querySelector("title");
var button = document.querySelector(".act-desktop-button");
var flip = true;
button.addEventListener("click", function(){
flip =! flip;
console.log(flip);
if(flip === true){
title.textContent = "OFF";
} else{
title.textContent = "ON";
}
});
and here is my json
{
"name": "Stopwatch Tracker",
"version": "1.0",
"description": "works with chromes built in stopwatch feature. Changes the
title of the page to 'ON' or 'OFF' depending on if the stopwatch is
running.",
"permissions":[
"tabs",
"*://*.google.com/search?q=stopwatch*"
],
"content_scripts": [
{
"matches": ["*://*.google.com/search?q=stopwatch*"],
"js": ["background.js"]
}
],
"manifest_version": 2
}
I am receiving this error:
I think, what is the most important part here is to make sure that you have checked the value of button to be not null before adding an event listener.
Just like this:
var button = document.querySelector(".act-desktop-button");
var flip = true;
if (button){
button.addEventListener("click", function(){
...
})};
Try also to check this SO post as this is related to your question.
Related
(Sorry in advance if there are any english mistake)
Hi everyone, I'm working on a simple Chrome extension to edit some graphics and texts related fields of a website (Freshdesk) that I can't modify from the website itself because the code is proprietary.
My problem is, to make the function that replace the texts be active everytime the pages are displayed, I'm using a setInterval() with 100 ms of delay, which kinda does the job but it's not optimal, because the function runs like thousands of times in a few seconds.
function main() {
console.log('main started');
setInterval(changeText, 100); //(Not optimized)
}
function changeText() {
// replace 'Group' with 'Sector'' in the ticket tab visual
$('.ember-power-select-placeholder.label-field').each(function(x){
var new_text = $(this).text().replace("Group", "Sector");
$(this).text(new_text);
console.log('function started');
})
}
main();
As you can see from the screenshots and the code above, in this simple case I wanna change the text from
Group
to
Sector
and, as you can see, the code works, but if we take a look at the console.. (this is after like 5 seconds).
I already tried some function to make the js run as soon as the page loads just once, but none of them seem to work for me.
Do you have any tip to fix this situation?
EDIT: Here is the manifest.json too
{
"name": "DAN-Patch",
"version": "1.0",
"manifest_version": 2,
"permissions": [
"webNavigation",
"activeTab",
"background",
"tabs"
],
"content_scripts": [
{
"run_at": "document_idle",
"matches": ["https://gestionaledan.freshdesk.com/*", "https://gestionaledan.freshworks.com/*"],
"js": ["jquery-3.5.1.min.js", "content.js"],
"css": ["stylesheet.css"]
}
]
}
use this to reduce the number of processes:
function main() {
console.log('main started');
let exa = setInterval(function () {
let el = $('.ember-power-select-placeholder.label-field'),
all = 0;
el.each(function () {
if ($(this).text() == "Group") {
// replace 'Group' with 'Sector'' in the ticket tab visual
var new_text = $(this).text().replace("Group", "Sector");
$(this).text(new_text);
console.log('function started');
all ++;
}
});
if (all == 0) {
clearInterval(exa);
}
}, 100); //(Not optimized)
}
main();
Hi i wanted to create extension that will trigger alert every 30mins to remind me check my posture. But i got stuck. I dont know how to make it so that alert triggers only in tab that im currently in. Now it triggers in every tab i have opened. Can someone help me please? Thanks.
As im thinking right now this way it will start new cycle every time i open new tab right? So im gonna see it in 30min only if i stay in that current tab.
setInterval(function() {
alert("Posture!");
}, 5000);
{
"name": "Posture Checker",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["posturecheck.js"]
}
]
}
You can check if a tab is in focus by checking if document.hidden.
if (document.hidden) {
// Document/tab/window is hidden
} else {
// Document/tab/window is visible
}
Alternatively, you can also check document.visibiliyState, but it does not return a boolean but a string value that you need to check against:
if (document.visibilityState === 'hidden') {
// Document/tab/window is hidden
} else if (document.visibilityState === 'visible') {
// Document/tab/window is visible
}
I'm writing a simple chrome extension which on click inserts some text in Swedish in the DOM. Works fine. So whenever a user clicks the extension, the text in inserted.
Now I want to extend this a little bit. What I want to achieve:
1) When the user clicks the extension the first time, a text in Swedish is inserted
2) When the user clicks a second time, a text in English is inserted instead
So basically I want to "toggle" the language inserted between Swedish and English.
My manifest.json:
{
"name": "TextInserter",
"version": "1",
"manifest_version" : 2,
"description": "Inserts text",
"background" : {
"scripts" : ["background.js"],
"persistent": false
},
"permissions": ["activeTab"],
"browser_action": {}
}
The code in background.js:
chrome.tabs.executeScript(tab.id, {
code: 'var toggle = true;' // How can I toggle this value?
}, function() {
chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});
The code in content.js:
var textarea = document.getElementById('description');
if (textarea && toggle) { // Is always true
textarea.value="Hej";
} else if (textarea && !toggle) {
textarea.value="Hello";
}
toggle = !toggle; // Change the value of toggle so next time text is inserted in other language
This of course doesn't work since I'm setting
var toggle = true;
in background.js.
How can I achieve this toggle effect?
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.
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.