Is there a way to detect if the chrome SidePanel is open?
Asked Answered
W

3

10

I have an extension that generates content in the built-in chrome sidebar on click of an element in the current page. I also am using a content script to add some highlighting to the clicked element so that it can be kept in context. However, on closing of the sidepanel I'd like to remove this highlighting as it is no longer relevant. But I can't seem to find an onClose event for the sidepanel's 'x' button that would fire when the panel is not visible.

Searched through the documentation. I found chrome.runtime.onSuspend but that didn't seem to work in my case - I tried calling it from my contentscript but that wasn't a recognized event in chrome.runtime in that context.

Westernmost answered 8/9, 2023 at 1:59 Comment(5)
Does this answer your question? Find out whether Chrome console is openSnapper
Kind of. The hack with window size works for the sidePanel as well, though it's not ideal. The rest of that question only applies to the Chrome console, not the sidepanel.Westernmost
Following up on this - the window size works but is unreliable. It doesn't work if the user has the browser zoomed.Westernmost
for zooming there is other options with the screen pixel ratios. Just multiply everything you get with that number -> developer.mozilla.org/en-US/docs/Web/API/Window/…Snapper
Unless I'm missing something, using device pixel ratio doesn't work across different devices. The base device pixel ratio at 100% on my mac is 2, but if I then use an external monitor or an older laptop it is 1. how do I differentiate these scenarios?Westernmost
D
11

There is no close event for the side panel but with a little trick you can detect if the sidepanel was closed:

You can simulate the event by opening a permanent connection between the side panel and the background script. This connection fires an onDisconnect event if the side panel gets closed.

sidepanel.js:

chrome.runtime.connect({ name: 'mySidepanel' });

The background script can add a listener and react accordingly.

background.js:

chrome.runtime.onConnect.addListener(function (port) {
  if (port.name === 'mySidepanel') {
    port.onDisconnect.addListener(async () => {
      console.log('Sidepanel closed.');
    });
  }
});
Dupleix answered 14/9, 2023 at 16:21 Comment(3)
Thanks, this solution works for the problem as I described it in my original post. However, one additional need that I am facing now. I added a button to the main page using my content script that is hidden on opening the panel and returned when the panel is closed, but if the sidepanel is already open on page reload this event never fires (because the connect event already happened and it was not disconnected) and the button appears. Any ideas?Westernmost
Update - Doesn't actually work with manifest v3 service workers, which do not stay connected. onDisconnect fires after some period of inactivity even though the sidebar is still open.Westernmost
I thought an open port would keep the service worker alive, but that does not seem to be the case and it's terminated 30 seconds after it received the last event. The only solution (better workaround) I can think of at the moment is to send a dummy message every 25 seconds or so.Dupleix
T
0

You have window.innerWidth which tells us the effective size of our HTML page and window.outerWidth, which gives us our page size + UI elements of the browser, such as the side bar. You can get the difference and compare it to a threshold.

Note that some people have toolbars or vertical tabs and it might interfere, but in most cases it's good

You might be able to detect the changes in the window UI like this:

window.outerWidth - window.innerWidth > threshold

And you can also track it's changes which signals opening and closing of UI elements if you want more accuracy and detecting when it is opened by listening to the resize event.

Thracian answered 1/8 at 8:42 Comment(0)
F
0

This is what i do in my extension and it works perfect with me

this utility open a window and await until it's closed, you can also export the popup variable if you need it in your code, also you can change the height and width logic to be passed as params.

import { Tabs, Windows } from "webextension-polyfill";

import WindowType = Tabs.WindowType;

let popup: Windows.Window | undefined;

let popupRequestId: string | undefined;

const closePopup = async () => {
  // try to close the popup if possible
  try {
    if (popup?.id) {
      await windows.remove(popup.id);
    }
  } catch {
    // ignore
  }
};

export const openPopup = async (type: WindowType = "popup", requestId: string = "") => {
  const lastFocused = await windows.getLastFocused();
  const { top = 0, left = 0, width = 0 } = lastFocused;
  if (popupRequestId === requestId) {
    if (popup?.id) {
      await windows.update(popup.id, {
        focused: true,
        drawAttention: true,
      });
    }
  } else {
    popupRequestId = requestId;
    if (popup) {
      await closePopup();
    }
    popup = await windows.create({
      type,
      url: `./index.html?requestId=${requestId}`,
      width: 360,
      height: 628, // +28 (the toolbar height)
      focused: true,
      left: Math.max(left + width - 360 - 20, 0),
      top: top + 20,
    });
    return new Promise(resolve => {
      const onRemoved = (windowId: number) => {
        if (popup && windowId === popup.id) {
          popup = undefined;
          popupRequestId = undefined;
          windows.onRemoved.removeListener(onRemoved);
        }
        resolve(true);
      };
      windows.onRemoved.addListener(onRemoved);
    });
  }
};

here is how to use it:

const test = async () => {
  await openPopup("panel", "unique id");
  // popup is closed :)
};
Fayum answered 3/9 at 19:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.