Stop a Google Chrome Extensions with a On and Off Button. How? - javascript

I have by default an External JS called alerton that will run on anywebppage when the extension is enabled.
I've also set up a Popup/Menu for when you click the Chrome Extension Icon at the top right.
I want to when the user presses the button "off" to Turn off/Remove an external javascript file called "alerton"
After many many hours, I'm at a loss as to what I need to do to get this to work!
I've looked at chrome.contentSettings.javascript However it doesn't seem like I can disable just one particular Javascript file.
I'm hoping someone has an answer...

One way you could achieve this is by reading and modifying a boolean variable in a Background Page and use Message Passing to communicate to and from your content-script and popup page. You can define a Background Page in your Manifest as such:
....
"background": {
"scripts": ["background.js"]
},
....
The background.js would look something like this:
var isExtensionOn = true;
chrome.extension.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.cmd == "setOnOffState") {
isExtensionOn = request.data.value;
}
if (request.cmd == "getOnOffState") {
sendResponse(isExtensionOn);
}
});
From your PopUp.html and your content-script you could then call the background.js to read and set the isExtensionOn variable.
//SET VARIABLE
var isExtensionOn = false;
chrome.extension.sendMessage({ cmd: "setOnOffState", data: { value: isExtensionOn } });
//GET VARIABLE
chrome.extension.sendMessage({ cmd: "isAutoFeedMode" }, function (response) {
if (response == true) {
//Run the rest of your content-script in here..
}
});

Related

Hide all elements before loading chrome extension

So, I am trying to do something like parental control. When I start my extension for the first time it works fine, but when I use it again elements don't hide, whole page loads and then it redirects, I want to hide all elements on page and then redirect, I am not using onBeforeRequest I want to use it with google search too and I don't know if I can put regex inside urls option. My manifest is ok, I start content script at "document_start".
background.js
var activeTabUrl;
var regex = /http:\/\/www.youporn.com\//
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
chrome.tabs.query({
active: true,
currentWindow: true
}, function (arrayOfTabs) {
activeTabUrl = arrayOfTabs[0].url;
});
if (activeTabUrl.match(regex)) {
chrome.tabs.update({
url: "http://google.com/"
})
} else {
chrome.tabs.sendMessage(tabId, {
action: "show_my_page"
}, function (response) {});
}
});
myscript.js (content_script)
_ini();
function _ini() {
document.getElementsByTagName("html")[0].style.display = "none";
chrome.extension.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.action == 'show_my_page') {
document.getElementsByTagName("html")[0].style.display = "block";
}
});
}
That's a wrong approach, but first why it fails.
If you're executing at document_start, then the only node existing in the dom would be the document node. Not even html yet.
Yes, you could potentially wait for html node to appear, but this is very roundabout. Your goal is to prevent navigation in the first place - and for blocker-style functionality there's the webrequest API (which, IIRC, was specifically implemented for AdBlock).
Here's a minimal sample from the docs themselves:
chrome.webRequest.onBeforeRequest.addListener(
function(details) { return {cancel: true}; },
{urls: ["*://www.evil.com/*"]},
["blocking"]);
You can also redirect that with a redirectUrl instead of cancel in the blocking response. See also CatBlock for a complete sample.

Chrome Extension: Iterate over different pages and collect data

I'm currently writing an extension which injects a Content Script. This script parses data from the page, saves it in the localStorage and is able to find the link to the next page and reload via location.href = "newUrl". On this page the script should run again, parse the data, save it, go to the next page etc.
Currently I can't find a solution which lets me do the last part (go to new page, run the script again, go to next page). I can't find a way to do something like "on page loaded execute the parsing function and then execute the goToNextPage function".
Any clues would be highly appreciated!
(Added from comments)
My background.js includes the following:
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.executeScript(tab.id, {file: "jquery-2.1.3.min.js"}, function () {
chrome.tabs.executeScript(tab.id, {file: "content.js"});
});
});
And content.js includes some functions to read the "next" link, parse the current page, etc.
I would do differently with regards to how you switch pages.
I would message the background with the next URL, and let background update the page and re-inject stuff. This way it will be synchronized with navigation.
// Content script
chrome.runtime.sendMessage({action: "updateMe", url: nextUrl});
// Background
function injectScripts(tab) {
chrome.tabs.executeScript(tab.id, {file: "jquery-2.1.3.min.js"},
function () { chrome.tabs.executeScript(tab.id, {file: "content.js"}); }
);
}
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.action == "updateMe") {
chrome.tabs.update(sender.tab.id, {url: message.url}, injectScripts);
}
});
// You can use the same handler in onClicked
chrome.browserAction.onClicked.addListener(injectScripts);

Chrome Extension: Message Passing (Sending the DOM to popup.js) returns 'null'

I would like to use a Chrome Extension to download the current page's DOM. I'm not sure why, but when my download occurs, the result is just a text file with either 'null' or 'undefined', rather than the DOM. I've tried to assimilate the knowledge from here and here, but I can't seem to get the message from content.js through to popup.js.
Additionally, I'm not sure why this actually works. When I read the docs, it seems like I need to send the message from popup.js to content.js by selecting the active tab:
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {message: 'getMessageFromContent'}, function(response) {
//Code to handle response from content.js
}
});
My current code:
content.js
var page_html = DOMtoString(document);
chrome.runtime.sendMessage({method: 'downloadPageDOM', pageDOM: thisPage});
function DOMtoString(document_root) { ... }
background.js
chrome.tabs.query({currentWindow: true, active: true}, function(tab) {
var page_html;
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message == 'downloadPageDOM')
page_html = request.pageDOM;
else if (request.message == 'getPageDOM')
sendResponse(page_html);
});
});
popup.js
document.addEventListener('DOMContentLoaded', function() {
var download_button = document.getElementById('download_button');
download_button.addEventListener('click', function() {
chrome.runtime.sendMessage({message:'getPageDOM'}, function(response) {
download(response, "download.html", "text/html");
});
});
});
function download(data, fileName, mimeType) { ... }
I feel like I'm missing a crucial understanding of how message passing works. If anyone could take a second to help me understand why the file that downloads just has 'null', I would sincerely appreciate it.
You're over-complicating this, which leads to a lot of logical errors.
You've set up the background page to act like a message proxy, and the content script itself triggers updating your page_html variable. Then the popup pulls that data with another message.
Note that page_html will not contain the current tab's data in any case: you're overwriting this data with the last loaded tab.
What you can do is completely cut out the middleman (i.e. background.js). I guess you got confused by the fact that sending a message TO a popup is a generally a bad idea (no guarantee it's open), but the other way around is usually safe (and you can make it always safe).
Solution 1 (bad, but here for educational purposes)
The logic of your app is: once the user clicks the button, make the snapshot at that moment. So, instead of making your content script do its work immediately, add a message listener:
// content.js
chrome.runtime.onMessage(function(message, sender, sendResponse) {
else if (request.message == 'getPageDOM')
sendResponse(DOMtoString(document));
});
function DOMtoString(document_root) { ... }
And in your popup, request it:
// popup.js
// (Inside the click listener)
chrome.tabs.query({currentWindow: true, active: true}, function(tabs) {
// Note that sending a message to a content script is different
chrome.tabs.sendMessage(tabs[0].id, {message:'getPageDOM'}, function(response) {
download(response, "download.html", "text/html");
});
});
However, this solution is not 100% robust. It will fail if the content script is not injected into the page (and this can happen). But it's possible to fix this.
Solution 2
Let's not assume the content script is injected. In fact, most of the time you don't NEED to inject it automatically, only when the user clicks your button.
So, remove the content script from the manifest, make sure you have host permissions ("<all_urls>" works well, though consider activeTab permission), and the use programmatic injection.
There is a little-used form of programmatic injection that collects the value of the last executed statement. We're going to use that.
// content.js
DOMtoString(document); // This will be the last executed statement
function DOMtoString(document_root) { ... }
In the popup, execute script, collect results:
// popup.js
// (Inside the click listener)
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content.js"}, function(data) {
// Data is an array of values, in case it was executed in multiple tabs/frames
download(data[0], "download.html", "text/html");
});
});
NOTE: All of the above assumes that your function DOMtoString actually works.

Detect Youtube video change with injected javascript

I am building an extension (some injected js) that adds some buttons to a youtube page, which works fine. My issue is that when a user clicks on another video (say in the right hand side list), the next video is loaded without an actual page reload. Is there any way to detect this change so that I can rerun my code?
I have already tried things like binding to the hashchange event, to no avail.
The idea is simple:
Use background.js to listen for url changes to a specific youtube tab using chrome.tabs.onUpdated
Once tab change is detected, send the new URL to the content-script running in that tab
The background page listens for URL changes to other tabs also but I'm pretty sure you can figure out how to fix that.
manifest.json
{
"manifest_version": 2,
"name": "Tab url change detection",
"version": "1.0",
"background": {
"persistent":true,
"page":"bg.html"
},
"content_scripts": [{
"matches": ["http://www.youtube.com/*"],
"js": ["app.js"]
}
],
"permissions": [
"tabs",
"http://www.youtube.com/*"
]
}
background.html
<script src="background.js"></script>
background.js
//Listen for when a Tab changes state
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab){
if(changeInfo && changeInfo.status == "complete"){
console.log("Tab updated: " + tab.url);
chrome.tabs.sendMessage(tabId, {data: tab}, function(response) {
console.log(response);
});
}
});
app.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
//here we get the new
console.log("URL CHANGED: " + request.data.url);
});
I know it's an old thread but I hope someone else will be able to use this information.
I had a similar issue building a chrome extension for youtube. To be more specific I needed to detect the navigation within youtube.
TL;DR;
After going over most of the StackOverflow, I've ended with the following in the context.js file.
function run(){
// your youtube extention logic
console.log('change');
}
window.onload = run;
window.addEventListener('yt-navigate-start', run, true);
Explanation
In case you wish to see all of the window events you can run getEventListeners(window).
youtube has a costume event when changing pages, the event is yt-navigate-start.
For the first time youtube loads, I used the window.onload and after that, add the event listener window.addEventListener('yt-navigate-start', run, true);
Good luck, I hope this could help.
I was recently struggling with this and I figured out what to do. I'm not sure if this is the best way to do it, but it doesn't rely on a background.js file.
var oldURL= ""
//window.setInterval takes a function and executes it after
//a given time (defined by the second parmeter)in miliseconds
var urlChangeHandler = window.setInterval(checkUrlChange, 500)
function checkURLChange(){
newURL = document.URL;
if(newURL !== oldURL){
doSomething();
oldURL = newURL;
}
}
I hope this will be helpful for somebody.
var old_url = '';
var mutationObserver = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (location.href != old_url) {
old_url = location.href;
console.log('URL was changed');
}
});
});
mutationObserver.observe(document.documentElement, {childList: true, subtree: true});

Chrome Extension DOM Completely loaded

I have tried several attempts to make sure DOM is completely loaded before trying to work with DOM, I can never seem to get the div counts to match up.
My test is, I run the page with dev tools open and once page is done I open console up and run same code(document.getElementsByTagName('div').length) and they are off!!
Anyone have any clue? The only thing that seem sto work is when I set a timeout, and I want to try to stay away from that...unless thats the only solutions, I have already searched articles and attempted several solutions, but no luck...
Here some some attempts...
1) manifest file has content_scripts/run_at : "document_start"
document.addEventListener('DOMContentLoaded', function () {
var count = document.getElementsByTagName('div').length;
console.log(count);
}, true);
2) manifest file has content_scripts/run_at : "document_end"; I basically send a message to background.js who then send message back run function.
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response);
});
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
divCount();
});
function divCount() {
var count = document.getElementsByTagName('div').length;
console.log(count);
}
2) manifest file has content_scripts/run_at : "document_end"; I basically send a message to background.js who then
content.js
chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
console.log(response);
});
background.js
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
chrome.tabs.executeScript(null, {
code: "console.log($('div').length)"
}, function(data) {
console.log(data);
});
});
I have also tried this:
chrome.tabs.onUpdated.addListener(function( tabId , info ) {
console.log(tabId, info);
if ( info.status == "complete" ) {
chrome.tabs.executeScript(null, {
code: "console.log($('div').length)"
}, function(data) {
console.log(data);
});
}
});
DOMContentLoaded - can occur before all the scripts have processed so if you have any JS that adds in elements this might explain the issue.
However I don't see why you are having an issue, you are using document_start to do some work, however this is way to early to be doing what you are doing. I am not sure why you just don't include the logic in your DOMContentLoaded in the same script as your document_end...

Categories

Resources