How to get notified on window resize in chrome browser - javascript

I am writing an extension for the Chrome browser where I want to add an event listener for the window resize event. My method is being executed for the window load event, but not being executed for the resize event.
Below is the code for my manifest.json file
{
"name": "A browser action",
"version": "1.0",
"background": { "scripts": ["background.js"] },
"permissions": [
"tabs", "http://*/*"
],
"manifest_version": 2
}
Below is the code for my background.js file.
var myExtension =
{
init: function()
{
// The event can be DOMContentLoaded, pageshow, pagehide, load or unload.
alert("ASHSIH");
window.addEventListener("resize", this.onmyPageResize, false);
},
onmyPageResize: function(aEvent)
{
alert("RESIZED");
}
}
window.addEventListener("load", function load(event){
window.removeEventListener("load", load, false); //remove listener, no longer needed
myExtension.init();
},false);

Chrome-o-Tile is one example of an extension which listens resize in its content script.
In manifest.json:
"content_scripts": [
{
"js": ["contentscript.js"],
"run_at": "document_start",
"matches": [
"<all_urls>"
]
}
],
In contentscript.js:
'use strict';
var timeoutId = 0;
window.addEventListener('resize', function() {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
chrome.runtime.sendMessage({method: 'resize'});
timeoutId = 0;
}, 100);
}, false);
In background.js:
chrome.runtime.onMessage.addListener(function requested(request) {
if (request.method === 'resize') {
...
}
)};
There is also an open issue to implement chrome.windows.onResize event for Chrome extensions.

The background.js file cannot capture resize events in the browser. You would need to inject a content script for that.

For future readers of this question, the chrome.windows API provides an onBoundsChanged event:
onBoundsChanged (Since Chrome 86)
Fired when a window has been resized; this event is only dispatched when the new bounds are committed, and not for in-progress changes.
https://developer.chrome.com/extensions/windows#event-onBoundsChanged
This is how the event can be used: chrome.windows.onBoundsChanged.addListener( callback() )
(Make sure the manifest.json file declares the tabs permission)
{
"name": "My extension",
...
"permissions": ["tabs"],
...
}

You can use jQuery's bind() function.. http://api.jquery.com/bind/
$(window).bind('resize', function () {
//do something here
});

Related

chrome extensions: How to send a message to the newly created tab?

I need to send some data to the newly created tab. I found some answers here to implement the listener first and then send a message. My event listener isn't working and can't catch the message.
manifest:
{
"manifest_version": 2,
"name": "My Cool Extension",
"version": "0.1",
"permissions": ["tabs",
"http://*/*",
"https://*/*",
"activeTab"
],
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["background.js"]
}
}
background:
chrome.browserAction.onClicked.addListener((tab)=>{
chrome.tabs.query({active: true, currentWindow: true}, tabs => {
if(tabs.length === 1 ){
chrome.tabs.create({url:"https://www.youtube.com/", active: true}, (tab)=>{
chrome.tabs.executeScript(tab.id, {file:"content.js"},tab=>{
chrome.tabs.sendMessage(tab.id, {"Active Objects": "elo"})
})
})
}
else{
alert("wrong page")
}
});
});
content:
chrome.runtime.onUpdate.addListener(
(request, sender, sendResponse)=>{
alert("elo")
}
);
I've finally got it to work. I didn't actually tested it the first time.
In addition to replacing onUpdate with onMessage in the content script you
might want to add setTimeout functions in the background script to delay the executions of
chrome.tabs.executeScript and chrome.tabs.sendMessage. Otherwise, you might
get (as I have) a runtime.lastError: The tab was closed.
And also you should avoid having multiple function callback arguments named
tab. Otherwise, they get overriden.
I simplified the background script to get it to work. You don't actually need
to query the current tab to create a tab and execute a script inside it. So,
I've simply kept chrome.tabs.create.
background.js:
chrome.browserAction.onClicked.addListener(function (_) {
chrome.tabs.create({url: "https://www.youtube.com/", active: true},
function (yt_tab) {
setTimeout(function () {
chrome.tabs.executeScript(yt_tab.id, {file: "content.js"});
setTimeout(function () {
chrome.tabs.sendMessage(yt_tab.id, {"Active Objects":"elo"});
}, 1000);
}, 1000);
});
});
content.js:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
console.log(request);
}
);

Chrome extension - permanent alarm

I'm trying to set a periodical alarm to load data on background from time to time. When the extension is installed, the alarm is triggered after the delay correctly, no problem here. But then it goes away and no other repetition is done. I also tried to set persistent=true which prevents it from going to the inactive mode but still no difference in behavior.
manifest.json
{
...
"background": {
"scripts": ["jquery-2.2.3.min.js", "common.js", "background.js"]
"persistent": false/true // tried both
},
"permissions": [
"<all_urls>",
"alarms",
"storage"
]
}
bgscript.js
chrome.runtime.onInstalled.addListener(function () {
chrome.alarms.create({delayInMinutes: 1});
});
chrome.alarms.onAlarm.addListener(function () {
doStuff();
});
As per the description of chrome.alarms.create, you should also set periodInMinutes for repeating.
chrome.runtime.onInstalled.addListener(function () {
chrome.alarms.create({delayInMinutes: 1, periodInMinutes: 1});
});

Chrome extension: Execute only on current domain name once browser action is clicked

Here is my scenario: By clicking the browser icon, I create a sidebar (html and css) next to the whole page, thus creating two columns (one is my sidebar, the other one is the actual page).
What I to achieve is having the sidebar stay when I reload the page or navigate to another page WITHIN the same domain. What I have right now is just the creation of the sidebar, but I have to click the browser action every time I navigate or reload the web page.
Manifest:
{
"name": "apdrop",
"version": "0.1",
"manifest_version": 2,
"description": "first prototype for apdrop extension",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "icons/icon19.png",
"default_title": "apdrop"
},
"permissions": [
"background",
"tabs",
"http://*/*/",
"https://*/*/"
]
}
Background.js
function injectedScript(tab, method){
chrome.tabs.insertCSS(tab.id, {file:"style.css"});
//chrome.tabs.insertCSS(tab.id, {file:"bootstrap.css"});
chrome.tabs.executeScript(tab.id, { file: 'jquery-2.1.1.min.js'});
//chrome.tabs.executeScript(tab.id, { file: 'bootstrap.min.js'});
chrome.tabs.executeScript(tab.id, { file: 'inject.js'});
}
function click(tab){
console.log("browser action clicked");
injectedScript(tab, 'click');
//alert("action button was clicked");
}
chrome.browserAction.onClicked.addListener(click);
Inject.js
var ev = $("body > *");
if (!document.getElementById('contentxf343487d32'))
{
ev.wrapAll("<div id='insidecontent65675f526567'>");
$("#insidecontent65675f526567").wrapAll("<div id='contentxf343487d32'>");
$("<div id='sidebar343gf87897fh'><div id='insidesidebar87678bbbb'><p>this is my name</p></div></div>").insertBefore("#contentxf343487d32");
}
else
{
$("#sidebar343gf87897fh").remove();
$("#insidecontent65675f526567").unwrap();
$("#insidecontent65675f526567 > div").unwrap();
}
Hope this helps clarify a bit more.
The simplest strategy would be to save state in domain's sessionStorage and have a "detector" script that re-injects your UI.
Add setting the state in your content script:
// inject.js
if (!document.getElementById('contentxf343487d32'))
{
// ...
sessionStorage["contentxf343487d32"] = true;
}
else
{
// ...
sessionStorage["contentxf343487d32"] = false;
}
Add a "detector" script:
// detect.js
if(sessionStorage["contentxf343487d32"])
{
chrome.runtime.sendMessage({injectSidebar: true});
}
Always inject the script on page load, via the manifest (and change to a better permission):
"content_scripts" : [
{
"matches": ["<all_urls>"],
"js": ["detect.js"]
}
],
"permissions": [
"background",
"tabs",
"<all_urls>"
]
In the background, inject the script upon message:
// background.js
chrome.runtime.onMessage.addListener( function (message, sender, sendResponse){
if(message.injectSidebar)
{
click(sender.tab);
}
});
If you need more persistence than sessionStorage provides, use localStorage. If you need a different logic, you can still use this skeleton of a detector signalling the background.

Access DOM elements through chrome extension

I'm trying to access some DOM elements from a webpage:
<html>
<button id="mybutton">click me</button>
</html>
I want to access the innerHTML ("click me") through a chrome extension:
chrome.browserAction.onClicked.addListener(function(tab) {
var button = document.getElementById("mybutton");
if(button == null){
alert("null!");
}
else{
alert("found!");
}
});
When I click the extension, the popup says: "null".
My manifest.json:
{
"name": "HackExtension",
"description": "Hack all the things",
"version": "2.0",
"permissions": [
"tabs", "http://*/*"
],
"background": {
"scripts": ["contentscript.js"],
"persistent": false
},
"browser_action": {
"scripts": ["contentscript.js"],
"persistent": false
},
"manifest_version": 2
}
The solution:
You need a manifest file, a background script and a content script. This is not really clear in the documentation that you have to use it and also, how to use it. For alerting the full dom, see here. Because I have a hard time finding a complete solution that actually works and not just snippets that are useless for newbies, like me, I included a specific solution:
manifest.json
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"content_scripts": [{
"matches": ["file:///*"],
"js": ["content.js"]
}],
"browser_action": {
"default_title": "Test Extension"
},
"permissions": ["activeTab"]
}
content.js
/* Listen for messages */
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
/* If the received message has the expected format... */
if (msg.text && (msg.text == "report_back")) {
/* Call the specified callback, passing
the web-pages DOM content as argument */
sendResponse(document.getElementById("mybutton").innerHTML);
}
});
background.js
/* Regex-pattern to check URLs against.
It matches URLs like: http[s]://[...]stackoverflow.com[...] */
var urlRegex = /^file:\/\/\/:?/;
/* A function creator for callbacks */
function doStuffWithDOM(element) {
alert("I received the following DOM content:\n" + element);
}
/* When the browser-action button is clicked... */
chrome.browserAction.onClicked.addListener(function(tab) {
/*...check the URL of the active tab against our pattern and... */
if (urlRegex.test(tab.url)) {
/* ...if it matches, send a message specifying a callback too */
chrome.tabs.sendMessage(tab.id, { text: "report_back" },
doStuffWithDOM);
}
});
index.html
<html>
<button id="mybutton">click me</button>
</html>
Just save the index.html somewhere and load in the folder as an extension, containing the three other files. Open the index.html and push the extension button. It should show "click me".
Starting with Manifest V3, your content scripts won't be able to access anything generated by other loaded scripts and using a trick like inlining a your code inside <script> tag won't work due to stricter CSP rules. This caused me a lot of head ache since I couldn't figure out how to access library-generated DOM properties similar to React or Redux DevTools.
Instead, you have to now inject your script inside the service_worker with eg:
chrome.scripting.registerContentScripts([
{
id: 'inject',
matches: ['<all_urls>'],
js: ['inject.js'],
runAt: 'document_end',
world: 'MAIN'
}
])
Notice the 'MAIN' property, not the default 'ISOLATED'. Then inside my inject.js I do whatever, eg:
window.addEventListener('load', () => {
findReact()
})
Also you have to add the script to the manifest.json:
"web_accessible_resources": [
{
"resources": ["inject.js"],
"matches": ["<all_urls>"],
"extension_ids": []
}
],
"externally_connectable": {
"ids": ["*"]
},
Not sure is "externally_connectable" needed. And you need to add at least "scripting" permissions. I used the React DevTools migration as my source https://github.com/facebook/react/pull/25145

.click(function()) not being called

I'm trying to make an chrome extention with the last.fm api, and I've succesfully placed down the folliwing div in the page I want it to be shown.
<div id="showLastFMInfo" Title="More info about song" class="LastFMButtonDown">»</div>
but when I click on it, nothing happens, this is the JS used:
$(document).ready(function () {
// this get executed
$('#meta-frame').append('<div id="showLastFMInfo" Title="More info about song" class="LastFMButtonDown">»</div>');
// this won't work if I click on my button
$("#showLastFMInfo").click(function(){
console.log("Click");
});
});
so you can see the first lines get executed but the .click() doesn't react.
this is my manifest.json:
{
"content_scripts": [ {
"js": [ "jquery.js", "lastfm.api.cache.js","lastfm.api.md5.js", "lastfm.api.js","lastFMLink.js", "script.js"],
"css": [ "LastFMLink.css" ],
"run_at": "document_end"
} ],
"name": "Plug.Dj VS last.Fm",
"description": "Implement information about the artist",
"icons": { "16": "cookie.png", "48": "cookie.png", "128": "cookie.png" },
"version": "0.0.1",
"web_accessible_resources": [ "lastFMLink.js" ],
"manifest_version": 2
}
Does anyone has a idea what I'm doing wrong?
You're appending it, so it's dynamic, and you need a delegated event handler:
$('#meta-frame').on('click', '#showLastFMInfo', function(){
console.log("Click");
});
on the other hand, attaching the event handler after the element is appended should work as well?
for dinamically generated contents use on of these
$("a.offsite").live("click", function(){ alert("Goodbye!"); }); // jQuery 1.3+
$(document).delegate("a.offsite", "click", function(){ alert("Goodbye!"); }); // jQuery 1.4.3+
$(document).on("click", "a.offsite", function(){ alert("Goodbye!"); }); // jQuery 1.7+
live and delegate are deprecated, so using .on() is recommended.
Use document or the closest static element
$(document).on('click','#showLastFMInfo',function(){
});

Categories