Can't use localStorage value in my Google Chrome extension - javascript

I have written a Chrome extension that adds a char counter to some input elements. There is no UI for this, it just injects the char counting code if the user is on a specific page.
There is a limit to how many chars should appear in the inputs. I initially wrote it to just display the number of chars but then I decided it would be nice if the user could choose to see how many chars they have left instead. So I decided to create an options page.
At some point in my options page I do this:
localStorage["count"] = count; // count is the string "countUp" or "countDown"
It turns out I can't access the localStorage of options.html from the contentscript.js so I reluctantly created a background.html page which listens to requests from the contentscript and returns the localStorage values that the content script asks for.
In contentscript (simplified)
var countOption;
chrome.extension.sendRequest(
{method: "localStorage", key: "count"},
function(response){
countOption = response.data;
console.log(countOption); // returns "countUp"
}
);
console.log(countOption); // returns undefined
if(countOption === "countUp") {
doSomething();
} else {
doSomethingElse();
}
Background page
<script type="text/javascript">
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if(request.method === "localStorage") {
sendResponse({data: localStorage[request.key]});
} else {
sendResponse({});
}
}
);
</script>
The problem is I can't assign a value to countOption so that it is accessible in the scope of the rest of my script. When I assign it in the chrome.extension.sendRequest's response this is the window object so I have tried declaring countOption globally but it is still undefined in the rest of my script.
Can anyone see where I'm going wrong? Thanks.

Would something like this work?
function executeCount(countOption)
{
console.log(countOption); // returns undefined
if(countOption === "countUp") {
doSomething();
} else {
doSomethingElse();
}
}
chrome.extension.sendRequest(
{method: "localStorage", key: "count"},
function(response){
executeCount(response.data);
}
);

Related

chrome extension chrome.webNavigation (Event) fires multiple time

I'm building a chrome extension , I need to create a function to detect the URL changes for example youtube.com to youtube.com/watch?v={some video id}
I kept looking around for a way to do that on Content.js but apparently it's not possible and i need to use background.js in that particular case
First I've implanted this part
chrome.webNavigation.((EVENT)).addListener(function() {
alert("worked");
});
to test if chrome can detect the URL changes correctly , then i will need to connect that to content.js to Ajax the URL changes and return JSON object from the server
I saw on this page Chrome Extension - webNavigation multiple Events that i can use
Events
onBeforeNavigate
onCommitted
onDOMContentLoaded
onCompleted
onErrorOccurred
onCreatedNavigationTarget
onReferenceFragmentUpdated
onTabReplaced
onHistoryStateUpdated
sadly none of them works properly as they the Alert pops Multiple times ( sometimes 1-4 times ) when i visit ( reload or visit a single page )
I don't know what i should do or if there is any other way to handle a problem like this , I'm fairly new to chrome extension and JS.
background.js
chrome.storage.sync.get( "extensionSwitch", function(data){
if( data[ "extensionSwitch" ] == undefined ){
chrome.storage.sync.set( { "extensionSwitch" : "true" }, function() { } );
}
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
fetch(request.input, request.init).then(function(response) {
return response.text().then(function(text) {
sendResponse([{
body: text,
status: response.status,
statusText: response.statusText,
}, null]);
});
}, function(error) {
sendResponse([null, error]);
});
return true;
});
chrome.webNavigation.onHistoryStateUpdated.addListener(function() {
alert("worked");
});

How to run callback function from content script after loading page ? chrome extension

I want to run a callback function from content script after tab loading new page .
Here is my code :
content_script.js
chrome.runtime.onMessage.addListener(function(request, sender, callback) {
if (request.id == "content_script") {
// open google.com
chrome.runtime.sendMessage({
"id" : "openUrl",
"url" : "https://google.com"
}, function(response) {
});
// call background script
// go to the claim code page
chrome.runtime.sendMessage({
"id" : "background"
}, function() {
alert("test");
});
}
});
background.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
if (msg.id == "openUrl") {
var tabId = sender.tab.id;
var url = msg.url;
openUrl(tabId, url);
} else if (msg.id == "background") {
setTimeout(function() {
sendResponse();
}, 5000);
}
});
function openUrl(tabId, url) {
chrome.tabs.update(tabId, {
url : url,
active : false
}, function() {
console.log("open tab url callback");
});
};
I also uploaded the source code to google drive, you can download it using the bellow link :
https://drive.google.com/open?id=15zSn40z4zYkvCZ8B-gclzixvy6b0C8Zr
as you can see the alert test don't show !
However if I remove the code which open new url , then alert ("test") appear !
I am not sure why ! but it looks like javascript lost the reference to the call back function when I open new url .
How can I solve the problem ? what's the correct way ?
Thank you
The sendResponse function becomes invalid after the message callback returns, unless you return true from the event listener to indicate you wish to send a response asynchronously. (https://developer.chrome.com/extensions/runtime#event-onMessage)
Add return true; in background.js to make this handler asynchronous.
Now you get an error Attempting to use a disconnected port object in the sendResponse(); call of background.js, and yes, that's a result of the page navigating away and losing the context that the content script was running in.
There's no way to make this work: The context in which you wanted to call alert() simply doesn't exist anymore.
Try using chrome.tabs.sendMessage instead. But this means you have to set up the listener at the top level, and not inside of any callback. Message passing is hard.

Javascript - Get text from html to string

It's a php while with javascript codes. I want that this:
Check every 1 seconds that chat_status.html -text's: status = "offline"
Full code:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script type="text/javascript">
// jQuery Document
$(document).ready(function(){
function loadChatStatus(){
var status = ("http://tulyita.hu/chat/chat_status.html".text);
if(status == "offline"){
//this happens 1#
} else {
//this happens 2#
}
}
setInterval (loadChatStatus, 1); //Reload file every 1 seconds
});
</script>
but it isn't worked. :( Can someone help me?
I need the text from the "chat_status.html".
function loadChatStatus(){
$.ajax({
url: "chat_status.html",
cache: false,
success: function(html){
$("#status").html(html); //Insert status into the #status div
},
});
if($("#status") == "offline"){
//this happens #1
} else {
//this happens #2
}
}
??
You can use $.get() to load the contents from your server and do something with it in the callback. Example (not tested):
$.get('http://tulyita.hu/chat/chat_status.html', function (data) {
if (data === 'chat = off' {
// happens when offline
}
else {
// happens when online
}
}, 'text');
Note that the page's current content is chat = off and not offline. Please check the exact contents of data after implementing this in your code.
Also note that your HTML page has to be on tulyita.hu or you have to add an Access-Control-Allow-Origin header because of the same-origin policy.
First, don't declare the loadChatStatus function in .ready() but outside of it. Leave only the setInterval inside the .ready() function. And 1 second is 1000 ms. setInterval expects ms.
Second, use .load() to get the contents of the url, put it in a (hidden) div,and then check what it is. You cannot just do "string".text , as a string has no .text member.

turn on and off chrome extension

I am working on a chrome extension ,this extension have 2 icons in the browser action (On & Off) ;
basically when it is On the background execute the script.js (Inject the file:script.js)
using the chrome.tabs.executeScript(tab.id,{file:"script.js",function(){});
I had problems to turn it off !
I have tried to use messages communication between the background.js and the script.js but this does not work neither .
If I understand correctly, your extension should have two states, On and Off. Clicking the extension icon toggles it on/off.
In this case you should use storage so the extension knows what state it is in. So on a click event, use something like:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.storage.sync.get('state', function(data) {
if (data.state === 'on') {
chrome.storage.sync.set({state: 'off'});
//do something, removing the script or whatever
} else {
chrome.storage.sync.set({state: 'on'});
//inject your script
}
});
});
Note though that this is happening at the extension/browser level and will apply to all tabs, so you may need something more complex that records both the tab ID and the state.
You then have the choice to either always run a content script and check the on/off state before performing some action, or inject and remove the script. I'm not sure if you remove a script though. Depending on what the script does, you may just want to refresh the page (i.e. if your script messes with the DOM and you want to undo that when turning the extension off).
background.js
var enable=false;
chrome.browserAction.onClicked.addListener(function (tab) {
enable = enable ? false : true;
if(enable){
//turn on...
chrome.browserAction.setIcon({ path: 'icon.png' });
chrome.browserAction.setBadgeText({ text: 'ON' });
chrome.tabs.executeScript(null, { file: 'content.js' });
}else{
//turn off...
chrome.browserAction.setIcon({ path: 'disable.png'});
chrome.browserAction.setBadgeText({ text: '' });
}
});
To add onto what #david-gilbertson stated for making it active and inactive for certain tabs, I have created that functionality here. I also took added some functions for removing and adding tabs to the array. Enjoy!
function addTab(array, new_tab_id)
{
array.push(new_tab_id);
//then call the set to update with modified value
chrome.storage.sync.set({
active_tabs:array
}, function() {
console.log("added tab");
});
}
function removeTab(array, rem_tab_id)
{
const index = array.indexOf(rem_tab_id);
if (index > -1) {
array.splice(index, 1);
}
//then call the set to update with modified value
chrome.storage.sync.set({
active_tabs:array
}, function() {
console.log("removed tab");
});
}
chrome.browserAction.onClicked.addListener(function (tab) {`enter code here`
chrome.storage.sync.get({active_tabs : []}, function(data) {
if (data.active_tabs.includes(request.tab_id)) {
removeTab(data.active_tabs, request.tab_id)
console.log("Turned Off ".concat(request.tab_id))
document.removeEventListener("mousemove", highlightCurrentHover, false);
} else {
addTab(data.active_tabs, request.tab_id)
console.log("Turned On ".concat(request.tab_id))
document.addEventListener('mousemove', highlightCurrentHover, false);
}
});
);

How to make a function which returns a value after a variable is set by an EventListener?

I have an EventListener and a function generator.gettext.
Code:
var generator = {
gettext: function (mytext) {
//I send a message which is intercepted by my content script.
//Later my content script will send a reply back which will be processed by 'receiver'
window.postMessage({
type: "MESSAGE",
text: mytext
}, "*");
while (generatedtext == "") {
//WAIT until generatedtext is set by 'receiver'
}
return generator.generatedtext;
},
generatedtext: ""
};
function receiver(event) {
if (event.data.type && (event.data.type == "FROM_CONTENTSCRIPT")) {
generator.generatedtext = event.data.text;
}
}
window.addEventListener('message', receiver, false);
I want that generator.gettext returns generator.generatedtext but I can't make it wait until receiver sets it. I have the impression that the EventListener is locked while generator.gettext is called. I have to change it so it becomes asynchronous and uses a callback parameter, but I'm new into this and don't know how to make it work. Can somebody help me?
EDIT: What I want to do is to process input on a website. There is a Javascript file and I want that input is processed by my content script. I redirected the javascript-file to a modified one on my hard drive. I change a line where the javascript loads the input. When I submit text the Javascript file calls something like var message = generator.gettext(mytext.value); My code above is injected into the page and has to send mytext to my content-script and has to return the output of my content-script.
I think I understand what you're asking, though it isn't very clear.
You are posting a message and you want to store the result on generator.generatedtext. You are already doing so.
var generator = {
generatedtext:'',
gettext: function (mytext) {
window.postMessage({
type: "MESSAGE",
text: mytext
}, "*");
}
};
window.addEventListener('message', function(ev){
if (event.data.type && (event.data.type == "FROM_CONTENTSCRIPT")) {
generator.generatedtext = event.data.text;
}
},false);
Unless there is some other usage that you are trying to do but haven't made clear, this is all you need. There is no need to have generator.gettext() return anything, since the message event listener is assigning the messages being received to generator.generatedtext.
If this isn't exactly what you wanted, post a comment with more details and I'll try to help you out.

Categories