Is there some way to get the tab id's of only the tabs that are part of my extension?
myTabs[i].location.reload()
makes error:
Uncaught TypeError: Cannot call method 'reload' of undefined
but this code:
chrome.tabs.executeScript(myTabs[i].id, {code:"document.location.reload(true);"});
works. But better to use correct method:
chrome.tabs.reload(myTabs[i].id)
This really depends on what you mean by "part of my extension".
If you mean tabs that are displaying a page that is contained within your extension you can do the following;
chrome.tabs.query({}, function (tabs) {
var myTabs = [];
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].url.indexOf(chrome.extension.getURL('')) === 0) {
myTabs.push(tabs[i].id);
}
}
console.log(myTabs);
});
If you want to access the DOM of your tabs instead, it gets even easier;
var myTabs = chrome.extension.getViews({type: 'tab'});
With access to the DOM you can simply iterate of each view (DOMWindow) and refresh each page;
for (var i = 0; i < myTabs.length; i++) {
myTabs[i].location.reload()
}
I've tried to do the same thing and using chrome.tabs.query and chrome.tabs.get didn't work for me. This worked perfectly:
var data = chrome.extension.getViews({'type':'tab'});
$.each(data, function(k,v) {
v.window.location.reload();
});
Related
I need to get some elements on HTML from each tab in a group tabs on google chrome, i need to access HTML to apply a search like getElementById or getElementsByTagName and to get element content.
main();
function main() {
crmTestButton.onclick = () => {
alertTotalBrowsersOpenned();
};
}
function alertTotalBrowsersOpenned() {
chrome.windows.getAll({ populate: true }, listTabsinBrowsers);
}
function listTabsinBrowsers(windows) {
for (var indexWindow in windows) {
console.log('------- window')
var window = windows[indexWindow]
for (var indexTab in window.tabs) {
console.log('------- tab')
var tab = window.tabs[indexTab]
console.log(tab)
}
}
}
That's way, i can't to access on HTML, just some propetys of tab like: id, title ... But i need to get HTML.
Thanks everyone.
I'm trying to take a screenshot of a page but the cookies pages get in front of because of some scripts (My software should go on any website so I can't provide the HTML).
The things is the delete in puppeteer is not working and I need some help with that.
await this.sleep(5 * 1000);
let body = await browserPage.evaluate(() => {
document.querySelectorAll('#didomi-popup')[0].outerHTML = "";
return document.documentElement.outerHTML;
});
await browserPage.screenshot({path: "test.jpg", fullPage: true});
So Yes didomi-popup exist I even try document.querySelectorAll('#didomi-popup')[0].outerHTML = ""; on the console of chrome and it delete the element.
The waiting seem also good because the cookies's popup is in the body that page.evaluate return.
Anyone has an idea ?
Thanks a lot
Try this:
await page.goto('<url_here>');
let div_selector_to_remove= ".xj7.Kwh5n";
await page.evaluate((sel) => {
var elements = document.querySelectorAll(sel);
for(var i=0; i< elements.length; i++){
elements[i].parentNode.removeChild(elements[i]);
}
}, div_selector_to_remove)
By trying other things I constat that the popup keeps gettings back on the screenshot and so I delete also all script in Javascript to prevent it and now it works
This code delete the popup and the script and then it setup the webpage with no script and so the page is static now for the screenshot.
let body = await browserPage.evaluate(() => {
const deleteElement = function(selector) {for (let i = 0; i < selector.length; i++) {selector[i].outerHTML = "";}}
const elemToDelete = ["#didomi-popup", "script"];
for (let i = 0; i < elemToDelete.length; i++) {
deleteElement(document.querySelectorAll(elemToDelete[i]))
}
return document.documentElement.outerHTML;
});
await browserPage.setContent(body)
await browserPage.screenshot({path: path, fullPage: true});
I know for other people deleteing script can be an issue but I wait a 7 seconds before the eval and so I just want to take a picture of the webpage without doing any interraction with it so it works pretty well for me !
An alternative approach might be to use the element.screenshot({ ... }) API.
The idea here is to isolate the element you want to screenshot from the entire page, not just delete annoying elements blocking your screenshot.
browserPage.$('.my-css-class')
.then(element => {
if (element) {
return element.screenshot({});
}
// default to page
page.screenshot({});
});
For additional reading, check out Bannerbear's blog post.
I have the impression that Firefox is "clearing" the data-* attributes on custom elements.
See the script below works in Chrome with native Web Components support, but in Firefox, it seems that once my click event handler is run, the dataset is empty.
document.addEventListener('DOMContentLoaded', function() {
var popups = document.querySelectorAll('iron-image[data-popup]');
for (var i=0; i < popups.length; i++) {
var img = popups[i];
console.log(img.dataset.popup); // <--- this works
img.addEventListener('click', function(ev) {
var app = document.querySelector('sh-app');
app.showPopup(ev.target.dataset.popup); // <-- This fails, dataset is empty
});
}
});
Side Note: I have also tried the WebComponentsReady event, but it doesn't get fired at all for some reason.
Has anyone run into this issue before and understand the cause?
Is this a bug in Polymer (<iron-image> in this case), the Web Components polyfills, or Firefox's implementation thereof?
Event retargeting
Basically, you have to wrap the event using Polymer.dom to normalize it.
document.addEventListener('DOMContentLoaded', function() {
var popups = document.querySelectorAll('iron-image[data-popup]');
for (var i=0; i < popups.length; i++) {
var img = popups[i];
console.log(img.dataset.popup); // <--- this works
img.addEventListener('click', function(ev) {
var app = document.querySelector('sh-app');
var event = Polymer.dom(ev); // you wrap the event using Polymer.dom
app.showPopup(event.localTarget.dataset.popup); // instead of target you should use localTarget
});
}
});
I want to use setVolume(0.01) on SoundCloud because it's way to loud for me.
As a temporary solution, I made the whole Chrome browser quieter, but then Youtube and other websites are too quiet.
I found that SoundCloud's volume can be controlled via the "SC.Widget method", but I have no idea what that is.
Can somebody explain how I can use that to set SoundCloud's volume to 0.01?
I already tried to put that just in the Chrome console but this gives me the following: VM1394:1 Uncaught ReferenceError: setVolume is not defined(…)
To change the volume on the Soundcloud website with a script there's no real API you can use, and no official way to do so. This should work:
webpackJsonp([], {
0: function(a, b, require) {
var modules = require.c;
modules[54].exports.broadcast("volume:set", 0.1);
}
});
Because the Soundcloude code is minified and not made to be used by other scripts, it is possible that the above solution might break with an error like this:
Uncaught TypeError: modules[54].exports.broadcast is not a function(…)
A hacky solution is to iterate over all modules and execute the volume:set broadcast:
webpackJsonp([], {
0: function(a, b, require) {
var modules = require.c;
for(var x in modules){
if(modules[x].exports.broadcast){
modules[x].exports.broadcast("volume:set", 1.0);
}
}
}
});
To change volume on Soundcloud widgets:
The HTML5 widget API is explained here. What you need to do first is include Soundcloud's API script, you can use this code which I borrowed from here:
var scapi = document.createElement('script');
scapi.src = "https://w.soundcloud.com/player/api.js";
document.getElementsByTagName('head')[0].appendChild(scapi);
The next step is finding the Soundcloud widget and use the API script to get the functionality we need, i.e. setVolume():
var sciframe = document.querySelector("iframe");
var widget = SC.Widget(sciframe);
widget.setVolume(0.1); // goes from 0 to 1
This you can use as a userscript with Greasemonkey or Tampermonkey and run it automatically:
var scapi = document.createElement('script');
scapi.src = "https://w.soundcloud.com/player/api.js";
document.getElementsByTagName('head')[0].appendChild(scapi);
function waitAndRegister() {
window.setTimeout(function(){
if(typeof(SC) == 'undefined') {
waitAndRegister();
} else {
quiet();
}
}, 100);
};
waitAndRegister();
function quiet() {
var scWidgets = document.querySelectorAll('iframe[src^="https://w.soundcloud.com/player"]');
if(scWidgets.length > 0) {
for (var i = 0; i < scWidgets.length; ++i) {
var widget = SC.Widget(scWidgets[i]);
widget.bind(SC.Widget.Events.PLAY, function() {
widget.setVolume(0.1);
});
}
}
}
Chrome > ctrl+shift+i > Application Tab > Storage > Local Storage > V2::local::settings
and set volume you need (eg: volume":0.05,")
Works like a charm for me.
I'm trying to teach myself how to write Chrome extensions and ran into a snag when I realized that my jQuery was breaking because it was getting information from the extension page itself and not the tab's current page like I had expected.
Quick summary, my sample extension will refresh the page every x seconds, look at the contents/DOM, and then do some stuff with it. The first and last parts are fine, but getting the DOM from the page that I'm on has proven very difficult, and the documentation hasn't been terribly helpful for me.
You can see the code that I have so far at these links:
Current manifest
Current js script
Current popup.html
If I want to have the ability to grab the DOM on each cycle of my setInterval call, what more needs to be done? I know that, for example, I'll need to have a content script. But do I also need to specify a background page in my manifest? Where do I need to call the content script within my extension? What's the easiest/best way to have it communicate with my current js file on each reload? Will my content script also be expecting me to use jQuery?
I know that these questions are basic and will seem trivial to me in retrospect, but they've really been a headache trying to explore completely on my own. Thanks in advance.
In order to access the web-pages DOM you'll need to programmatically inject some code into it (using chrome.tabs.executeScript()).
That said, although it is possible to grab the DOM as a string, pass it back to your popup, load it into a new element and look for what ever you want, this is a really bad approach (for various reasons).
The best option (in terms of efficiency and accuracy) is to do the processing in web-page itself and then pass just the results back to the popup. Note that in order to be able to inject code into a web-page, you have to include the corresponding host match pattern in your permissions property in manifest.
What I describe above can be achieved like this:
editorMarket.js
var refresherID = 0;
var currentID = 0;
$(document).ready(function(){
$('.start-button').click(function(){
oldGroupedHTML = null;
oldIndividualHTML = null;
chrome.tabs.query({ active: true }, function(tabs) {
if (tabs.length === 0) {
return;
}
currentID = tabs[0].id;
refresherID = setInterval(function() {
chrome.tabs.reload(currentID, { bypassCache: true }, function() {
chrome.tabs.executeScript(currentID, {
file: 'content.js',
runAt: 'document_idle',
allFrames: false
}, function(results) {
if (chrome.runtime.lastError) {
alert('ERROR:\n' + chrome.runtime.lastError.message);
return;
} else if (results.length === 0) {
alert('ERROR: No results !');
return;
}
var nIndyJobs = results[0].nIndyJobs;
var nGroupJobs = results[0].nGroupJobs;
$('.lt').text('Indy: ' + nIndyJobs + '; '
+ 'Grouped: ' + nGroupJobs);
});
});
}, 5000);
});
});
$('.stop-button').click(function(){
clearInterval(refresherID);
});
});
content.js:
(function() {
function getNumberOfIndividualJobs() {...}
function getNumberOfGroupedJobs() {...}
function comparator(grouped, individual) {
var IndyJobs = getNumberOfIndividualJobs();
var GroupJobs = getNumberOfGroupedJobs();
nIndyJobs = IndyJobs[1];
nGroupJobs = GroupJobs[1];
console.log(GroupJobs);
return {
nIndyJobs: nIndyJobs,
nGroupJobs: nGroupJobs
};
}
var currentGroupedHTML = $(".grouped_jobs").html();
var currentIndividualHTML = $(".individual_jobs").html();
var result = comparator(currentGroupedHTML, currentIndividualHTML);
return result;
})();