I need my Chrome extension to take a screenshot of the whole page/tab, excluding an element that I have injected in it after the closing </body> that is overlaying everything else.
Currently, I take the screenshot from a background script with the following code:
chrome.extension.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'cheese') {
setTimeout(() => {
chrome.tabs.captureVisibleTab(null, { format: 'png' }, (src) => {
sendResponse({ src });
});
}, 10);
return true;
}
});
The only solution I've found so far to exclude that element is hiding it momentarily before taking the screenshot, but sometimes it still appears, thus the 10ms delay in the code above. That reduces the frequency of the issue, but doesn't fix it completely and, anyway, is just a workaround that I'd like to get rid of.
Before, I was using requestAnimationFrame to send the screenshot request to the background script only after the element has been hidden, but surprisingly, that didn't fix the issue, that's why I tried with that setTimeout instead.
Please, note the element I want to get rid of on the screenshot is on top of a relevant area of the page, so cropping the captured area is not an option, as I won't be able to see whatever is behind that element.
I took a look at the remote debugging protocol, where the closest I found was Page.captureScreenshot, which accepts a clip parameter that would crop the screenshot, but still capture the overlay.
Related
I am building a fairly simple Chrome extension: When "active", it should copy some source code whenever the content.js is sending the correct data:
background.js
...
// when active, listen for content.js and copy content into clipboard
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.from === "content" && active === true) {
copyTextToClipboard(request.message)
}
});
Setting the extension "active" is done by clicking the extension icon in the Chrome tab:
background.js
...
// turn the logo color and set activity status upon clicking the extension logo in the tab
chrome.browserAction.onClicked.addListener(function() {
active = !active;
localStorage.setItem("active_stored", active);
if (active) {
chrome.browserAction.setIcon({path: "icon_yellow.png"})
} else {
chrome.browserAction.setIcon({path: "icon_grey.png"})
}
});
...
It is almost running as expected (i.e. clicking the icon sets active=true or false, indicated by the extension logo changing accordingly).
However, I want to save the activity status using localStorage, so that it remains intact even after shutting down Chrome.
So I added the following code:
background.js:
...
// turn the logo color and set activity status upon starting up Chrome browser
let active = localStorage.getItem("active_stored");
chrome.runtime.onStartup.addListener(function () {
if (active) {
chrome.browserAction.setIcon({path: "icon_yellow.png"})
} else {
chrome.browserAction.setIcon({path: "icon_grey.png"})
}
});
...
However, when restarting Chrome, regardless of the state I left active in, the "active" logo is being displayed and the variable is set to true (which I find weird, but I could live with), but the source code is not being copied! Clicking the icon twice, i.e. deactivating and activating, will result in the expected behavior!
Can someone tell me where I am going wrong with this?
P.S.: I originally tried this with chrome.storage.set and chrome.storage.get, but the using the callback function really confused me. After having read multiple articles and other questions, I feel like this might be necessary in order to solve this problem. Please let me if a) it indeed is the only way to get this done and b) how to properly integrate this functionality.
Thanks!
The problem is that the values in localStorage are saved as string which means that both the "true" and "false" strings are truthy values.
To convert the values from localStorage to boolean, use something like this:
let active = JSON.parse(localStorage.getItem("active_stored"));
I am writing a Google Chrome extension. I don't know JavaScript and I'm trying to identify whether the "dislike" button is active (means blue, because it has been clicked by me at some point and therefore marks that I don't like the video) element in a YouTube video page.
I tried various ways but I am hopeless. A few of my attempts:
//result = document.querySelector("path[d]");
//var something = document.querySelector('[d=M15 3H6c-.83 0-1.54.5-1.84 1.22l-3.02 7.05c-.09.23-.14.47-.14.73v1.91l.01.01L1 14c0 1.1.9 2 2 2h6.31l-.95 4.57-.03.32c0 .41.17.79.44 1.06L9.83 23l6.59-6.59c.36-.36.58-.86.58-1.41V5c0-1.1-.9-2-2-2zm4 0v12h4V3h-4z" class="style-scope yt-icon]');
Can somebody help me? Interestingly I only find this attribute when inspecting the page, if I look at the page source it't not even present in the page (I have no web development knowledge, I suspect it's some dynamic trick?).
Edit: I use the following at the beginning of my chrome extension background script to make sure the page is loaded:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
if (tab.url.indexOf("youtube.com") != -1) {
As long as YouTube doesn't change things, you can take advantage of the aria-label attribute of button elements.
The one you are looking for starts with "dislike" ("dislike this video along with 89 other people" - the number will probably vary, the rest - probably not).
Try this:
for(var btn of document.getElementsByTagName("button"))
if(btn.getAttribute("aria-label"))
if(btn.getAttribute("aria-label").includes("dislike"))
console.log(btn);
Instead of console.log(btn) you can use btn.click().
Try this:
var dislikeButtonElement = document.querySelector("#top-level-buttons > ytd-toggle-button-renderer").nextElementSibling;
if(dislikeButtonElement.classList.contains("style-default-active")){
//Dislike button active
alert("Disliked Video");
}
Be aware that this will only work after the page has fully loaded as YouTube loads almost everything dynamically. On a slower connection, the video may be playing before these buttons have loaded
I would like to hover my mouse on a URL and copy the URL with CTRL+Alt+C. This topic pretty much describes 99% of what I'm trying to do:
https://www.autohotkey.com/board/topic/111762-mouse-hover-copy-link/?p=662644
I've taken the userscript and modified it slightly, so that it gives me the URL after the "href" part. By the way, I'm not at all proficient with Javascript, I've simply played around with it and was lucky to get it working. Here's what I have:
This works great, but this copies the URL everytime I hover my mouse on a link. I don't want this, as it just adds a bunch of URLs to my clipboard.
At the bottom of that post, there's a Autohotkey component. It gets the tab title, rather than the URL.
How can I modify both the userscript and the Autohotkey to do what I want?
As a secondary question - I would like to create an additional userscript using the Javascript above as a reference. This new userscript will take the URL that my mouse is hovering on, change it so that it is prefixed with word:ofe|u| and pastes that into the URL bar when I click on the link while holding the Alt key. So basically:
Hover mouse on a URL that I am interested in (e.g. https www.google.com)
Userscript will modify the URL and change it to word:ofe|u|https://www.google.com
Hold down Alt + left click on the URL
word:ofe|u|https://www.google.com - page is loaded, or URL is pasted into the URL bar
UPDATE:
I've managed to get something going, not sure how I did it but I just played around with the codes I found on Google. Again, I do not know anything about Javascript.
https://pastebin.com/S9znPxBU
// ...
This works well, but if you do single press of CTRL+C, it just keeps copying URLs to the clipboard whenever you hover your mouse on a link. I want it to only start copying a URL to the clipboard everytime I press CTRL+C.
AutoHotkey won't help much here, as it can't access the URL directly. Thankfully, you can use the new JavaScript Clipboard API. It only works in secure contexts (AKA HTTPS) and the page needs to be in focus. Doing this using a browser extension would be perferred, since it can workaround those restrictions.
Try it, but first click on a blank area in the preview window to focus it.
// Userscript
"use strict";
window.addEventListener("load", () => {
const evOpts = {capture: true, passive: true};
let hoveredLink = null;
for (let link of document.getElementsByTagName("a")) {
link.addEventListener("mouseenter", () => {
hoveredLink = link;
}, evOpts);
link.addEventListener("mouseleave", () => {
hoveredLink = null;
}, evOpts);
}
window.addEventListener("keydown", (ev) => {
if (hoveredLink && ev.ctrlKey && ev.altKey && ev.code === "KeyC") // Ctrl+Alt+C
// Copy *absolute* URL to the clipboard
navigator.clipboard.writeText(new URL(hoveredLink.href, location.href)).then(()=>{
console.log("URL copied to clipboard!");
}, (err)=>{
console.error("Error copying URL to clipboard: ", err);
});
}, evOpts);
});
Google Youtube
I've dug through other answers for a while now but haven't found anything that I think quite does what I'm looking for, so it's time for my first stackoverflow question! (Be gentle, I started learning js about 3 weeks ago.)
The tl;dr here is that I'm looking to take a DOM element (innerHTML mostly) from the active tab on the page and, when my popup opens, use that element to populate links in specific ways.
For instance, using Twitter as an example, I'd like to grab the top tweet's permalink and have part of my extension's dropdown offer a link to that.
The way I'm seeing it working is with messaging (as referenced here and here), but something's escaping me.
My best guess from the above example and digging through some other scripts is the following in my main page's content.js; (I've already used document.getElementById to set the var previousVariable):
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
if (msg.text === 'report_back') {
sendResponse(previousVariable.href);
}
});
And then the following in my popup.js:
console.log("This is step one!");
function doStuffWithDom(domContent) {
console.log('Did it work? ' + domContent);
}
// When the browser-action button is clicked...
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.sendMessage(tab.id, {text: 'report_back'}, doStuffWithDom);
});
I'm writing a Google Chrome extension and I want to show the first image of a webpage (for instance: a blog) in the popup.htm. So far I know how to implement the favicon so I was trying to work backwards and edit the favicon into the first image of the page. The problem is the favicon was so simple! All I had to write for a given variable was
function favicon(a)
{
return "chrome.../" +a;
}
Now, I can find the img.src of a background page. But I'm not sure how to find one of a unique page (submitted by the user). I've googled every way my vocabulary permits and so far have come up with this...
function getLavicon(a)
{
/*
find first image on page requested
get url of first image
return url
*/
return $(localStorage.getItem(a)).find('img').first().attr('src');
}
It returns a blank image. Let me know if screenshots are necessary.
Why use jQuery for this ? You can get the first image url on the page by using the following code:
var firstImage = document.getElementsByTagName("img")[0];
console.log(firstImage.src) // This will print out the source of the image on the console
Now you can use the source of the first image whenever you want just by using firstImage.src
Pretty sweet and clean huh ? :)