How to open Google search results in the sidebar

Hello,

I created an extension that amongst other things opens Google search results in the sidebar. However, the search results are truncated and do not fit (i.e. the lines don’t wrap) within the width of the sidebar.

I tried to correct this by specifying a mobile user agent in the web request, but it doesn’t do anything:

/// Add a mobile header to outgoing requests
browser.webRequest.onBeforeSendHeaders.addListener(
    rewriteUserAgentHeader,
    requestFilter,
    ["blocking", "requestHeaders"]
);

/*
Rewrite the User-Agent header to contextsearch_userAgent
*/
function rewriteUserAgentHeader(e) {
    if (!contextsearch_openSearchResultsInSidebar) {
        return {};
    }
    for (const header of e.requestHeaders) {
        if (header.name.toLowerCase() === "user-agent") {
            header.value = contextsearch_userAgent;
        }
    }
    return { requestHeaders: e.requestHeaders };
}

I also tried setting the viewport width using a solution proposed by chatGPT, but that generated an error as it seems that width was not recognised:

// Get the current active tab
browser. tabs. query({active: true,
currentWindow: true}).then(tabs => {
const activeTab = tabs[0];
// Open the Google search results in a
sidebar with modified viewport size
browser.sidebarAction.open({
url: "https://www.google.com/search?
q=${activeTab.title}',
tabId: activeTab.id
});
/ Modify the viewport size of the sidebar
browser.sidebarAction.setPanel({
width: 360,
height: 640
});
});

I would be most grateful if anyone could help fix this problem.
Thank you.

Using the mobile user agent should work.
I’ve just tested it in one of my projects using following (very old) typescript code and it works:

  browser.webRequest.onBeforeSendHeaders.addListener(function (details: browser.webRequest._OnBeforeSendHeadersDetails) {
    console.log('header', details);
    const headers = details.requestHeaders!;
    for (let i = headers.length - 1; i >= 0; --i) {
      const header = headers[i];
      const headerName = header.name.toLowerCase();
      if (headerName === 'user-agent') {
        header.value = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/12.0 Mobile/15A372 Safari/604.1';
        // header.value = 'Mozilla/5.0 (Linux; Android 7.0; SM-G892A Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/67.0.3396.87 Mobile Safari/537.36';
      }
    }
    return {requestHeaders: headers};
  }, {
    urls: ['<all_urls>'],
    tabId: targetTabId || undefined,       // block only target tab (or pop-up)
    types: ['sub_frame'],     // block only "iframe" requests
  }, ['blocking', 'requestHeaders']);

PS:
do I see that you are using “Search Result Previews” addon? That’s my addon! :smiley:

Hi Juraj,

Thank you for your quick response.

I tried changing the user agent to the one in your code. I also tried changing the type from main_frame to sub_frame, but I just can’t get it to work! What does targetTabId point to? Are you sure that you’re using the Firefox in-built sidebar? (I don’t see the “x” to close the sidebar!)

I just don’t know what is causing the problem.

P.S. Yes, you’re absolutely right, I’m using your awesome add-on! Thank you.

Could the problem lie elsewhere and maybe have to do with the html and css that I’m using for the sidebar?

search_results.html :

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=430, initial-scale=1.0">
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Raleway&display=swap">
    <link rel="stylesheet" href="../styles/search_results.css" />
</head>

<body>
    <div id="searchResultsContainer">

    </div>
</body>

</html>

search_results.css :

html,
body {
    scroll-behavior: smooth;
    overflow-y: scroll;
    height: 100%;
    width: 100%;
    max-width: 432px;
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: 'Raleway', Calibri, Helvetica, Arial, sans-serif;
    font-size: 10pt;
    color: darkslategrey;
}

I tried using another extension call Open in Sidebar. I did a Google search for “Taïwan” in a tab, then I did a right-click on “All” and selected “Open Page in Sidebar”. Again, the search results were truncated, so this isn’t just happening with my extension. Btw, I’m using Firefox Developer Edition 111.0b8 (64-bit).

Other extensions are having the same problem:

Oh, that’s a sidebar, right… that may complicate things a bit.
My example was build for page displayed in “iframe”. But don’t put your page inside iframe!

But there is almost no difference, the “sub_frame” I’m using means it will affect only iframes, so you don’t want to use that, keep it to “main_frame”.

Also, what requestFilter are you using?
Are you sure the right requests are handled? Put some console logs in the handler just to be sure it’s running.
And lastly, when do you register it? You need to register it before the page starts loading.

But I’m a bit puzzled about that requestFilter… in my case I target a targetTabId , which is ID of the tab where the iframe is, but how to target a sidebar? :slight_smile:

From what I understand, you target the sidebar by setting the tabID to -1. Here’s my request filter:

// This is a RequestFilter: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/RequestFilter
// It matches tabs that aren't attached to a normal location (like a sidebar)
// It only matches embedded iframes
const requestFilter = {
    tabId: -1,
    types: ["main_frame"],
    urls: ["http://*/*", "https://*/*"]
};

Not sure what you mean by registering? My web request handler is in the background script.

Are you sure you target it by setting tabId to negative one? Where did you see that?

But more importantly, did you put a console.log into the “rewriteUserAgentHeader” handler? Do it to see if it’s actually being executed.

I update the sidebar panel with:

browser.sidebarAction.setPanel({ panel: targetUrl });

I added some console.logs as shown here, but they’re producing no output so the web request listener isn’t catching anything!

/*
Rewrite the User-Agent header to contextsearch_userAgent
*/
function rewriteUserAgentHeader(e) {
    if (!contextsearch_openSearchResultsInSidebar) {
        return {};
    }
    console.log(`Intercepted header: ${e.requestHeaders}`);
    for (const header of e.requestHeaders) {
        if (header.name.toLowerCase() === "user-agent") {
            header.value = contextsearch_userAgent;
        }
    }
    console.log(`Modified header: ${e.requestHeaders}`);
    return { requestHeaders: e.requestHeaders };
}

From what I can see in the docs, the sidebar seems to belong to the window, so maybe you need to use windowId instead.

I’ve tried to execute these two inside a sidebar and these are the results:
image

The sidebar can be linked to tab, window or global pane. I thought I was using global pane.

Try to omit both “tabId” and “windowId” in the request filter, that should make it global.
It’s not ideal but let’s try just to be sure it works.

I tried it but it doesn’t produce any output, so maybe you’re right and I need to link to the windowID.

According to ChatGPT:

No, the browser.sidebarAction.setPanel({ panel: targetUrl }) method call does not trigger a web request.

This method is used to set the content of the sidebar panel to a specified URL, which can be a local file or a remote resource. The browser then fetches the content of the specified URL and displays it in the sidebar panel.

However, if the URL specified in panel points to a remote resource, then a web request will be made to fetch the content of that resource. This request is initiated by the browser itself and not by the browser.sidebarAction.setPanel method.

It’s also worth noting that the browser.sidebarAction.setPanel method is asynchronous, which means that it does not block the execution of other code while the browser fetches the content of the specified URL. Instead, it returns a Promise that resolves when the panel is set.

Would a genius from Mozilla please help!

I find it really sad that nobody at Mozilla appears to be wanting to help improve the experience of Firefox users. There have been many requests for search engine results displayed in the sidebar not to be truncated. Yet, there has been ZERO progress over the years. It’s very discouraging for extension developers.

I’m not from Mozilla, and I’m not a genius, but I want to give you some advice.
I hope it doesn’t sound condescending.

  1. Don’t use AI to generate your code.
    AI often makes things up, like the parameters to browser.sidebarAction.open() and browser.sidebarAction.setPanel() in your first post.
    See Hallucination_(artificial_intelligence)
    Experienced developers can spot these mistakes and correct them.
    From your posts, I gather that you’re new to programming.
    I suggest reading the documentation, and using the example programs as a basis for your own programs.
    There’s even a Github repository with complete sample extensions:
    https://github.com/mdn/webextensions-examples

  2. Write a small test extension that demonstrates your problem.
    You should have enough posts to use the “Upload” feature when replying to a post.
    (The arrow pointing up; it’s the 7th icon from the left)
    Please test your extension before uploading it.
    If Firefox loads the extension without showing any errors, you can upload it.
    Posting small fragments of code is OK for experienced developers, because they usually have a good idea where the problem is, even if they can’t find it.
    But beginners often post irrelevant sections of their programs.
    In the case of your extension, I suspect the problem is in a section you haven’t shown us yet.

  3. There are many mistakes in the following code, probably because it’s AI-generated.
    If you want, I can make a list with explanations.

  1. Maybe I’m making a mistake by responding, because your last two posts sound passive-aggressive. And I don’t want to send the message that this is how you get answers here.
    But I want to encourage extension developers who still support Firefox.

Hello Hans,

First of all, thank you for taking the time to answer.

  1. I’m aware of AI hallucinating and the cutoff date of certain AI tools. I wouldn’t say that I’m new to programming, but I have to admit that I’m a bit of a jack of all trades and master of none. I don’t master HTML, CSS or JS. Also, because they’re constantly evolving and it’s too time consuming to stay up-to-date.

  2. My extension has thousands of lines of code so it’s not easy for me to know what would be useful. Sorry, but I don’t understand what you are referring to by “Upload” feature and where to find it!

  3. I’m interested in learning about my mistakes if it may help solve the issue I’m facing.

  4. I’ve been spending a lot of time trying to find a fix for my problem. I’ve tried many different things, but none worked. At one time, I think I did come across an web extension example that seemed to work. I examined the code and just couldn’t understand how it was working. I can’t find the web extension example any more. I’ve been trying to solve this problem for years hoping that Mozilla Firefox developers would come up with something that makes it easier for us to implement, but I’m still waiting and the experience has been quite frustrating. In my post on March 7th, I was not being aggressive. I was asking for help from someone proficient from Mozilla. It’s never very pleasant to be ignored when you’re crying out for help and trying to make your users have a nice experience with your extension and with Firefox. I’ve put in hundreds of hours developing my extension and am really surprised to have some 4’500 happy users. I’m not on a payroll, Hans, and all I’m getting out of it is learning to code better hopefully (but now that you think I’m a beginner maybe I should seek a new venture) and trying to be useful to others! I would just like you to understand that, when you’re not a professional developer, it can be extremely difficult to get the help from Mozilla that you need to solve an issue. I’m not the only person having this problem: https://addons.mozilla.org/fr/firefox/addon/search-in-sidebar/reviews/

I’ve tried so many things and wasted so much time only to hit a wall! That’s why I may sound passive-aggressive to you. I’ll try to be more constructive in my next post but it’s now getting late on my end.

I was thinking of a very simple extension that opens Google in the sidebar, so we can see what isn’t working (a minimal reproducible example).
The attachment shows what I mean.

edit:
Please don’t create a minimal reproducible example.
I’ve found the problem, and the solution will be in a separate post.

Open_in_Sidebar_FF_MV2.zip (5.3 KB)

When I click reply, the forum shows me:

upload_to_mozilla_discourse

If you don’t have the red-outlined icon, you haven’t reached the required Trust Level to post attachments.

The following will not help you with your specific problem.
But it might be useful to other people who stumble upon this thread later.

In your first post, in the second code block…

  1. Some consecutive lines should be combined into one line.
    (better readability, and I’m not sure if Firefox will execute the code as-is)
  2. With indentation, the code is much easier to read.
  3. browser.sidebarAction.open
    a) In the “url” parameter, the opening quote (") doesn’t match closing quote (’).
    b) The “url” parameter is a template literal, so the enclosing quotes must be backticks (`).
    c) browser.sidebarAction.open doesn’t accept any parameters.
  4. It’s true that browser.sidebarAction.setPanel takes an object as its parameter, but this object doesn’t have “width” or “height” keys.
  5. Firefox doesn’t complain about the spaces in “browser._tabs._query” (written as underscores here), but the other parts of code don’t have spaces before object properties, so I’d remove them (style consistency).
  6. The comment “/ Modify the viewport size of the sidebar” starts with a single forward slash (/), but it must start with two.

Corrected code:

// Get the current active tab
browser.tabs.query({active: true, currentWindow: true})
.then(tabs => {
    const activeTab = tabs[0];
    // Open the sidebar
    browser.sidebarAction.open();
    // Load the Google search results in the sidebar
    browser.sidebarAction.setPanel({
        panel: `https://www.google.com/search?q=${activeTab.title}`
    });
});

Sorry, I just had to get this off my chest.
AI isn’t ready to generate code without close supervision.

According to the webRequest documentation:

To use the webRequest API for a given host, an extension must have the “webRequest” API permission and the host permission for that host.

Add “<all_urls>” to the “permissions” key in manifest.json, and Firefox will call the browser.webRequest.onBeforeSendHeaders listener for all requests made from the sidebar.
(don’t use the “host_permissions” key, it’s only valid in Manifest V3)

  • You probably don’t need the “<all_urls>” host permission.
    It’s probably enough to have host permissions for the search engines.
    But then you have the problem of country-specific search engines:
    www.google.fr
    www.google.de
    www.google.co.uk
    As far as I know, “google.*” is an invalid match pattern, so you’d need to list them all in the host permissions.
    And for search engines added by the user, optional host permissions, in the “optional_permissions” manifest key.

Hi Hans, thank you so much for your help. I really apologize for my careless mistakes in the first post. I realize that I didn’t do a very good job with the code formatting, etc.

My manifest.json file contains the following relevant code:

"sidebar_action": {
    "browser_style": false,
    "default_icon": "/icons/context-search.svg",
    "default_title": "Search results",
    "default_panel": "/sidebar/search_results.html",
    "open_at_install": false
},
...
"permissions": [
    "activeTab",
    "contextMenus",
    "storage",
    "search",
    "clipboardWrite",
    "webRequest",
    "webRequestBlocking"
],

My background script contains a searchUsing() function that opens the sidebar and sets the panel to the targetUrl corresponding to a search query for the chosen search engine:

function searchUsing(id, tabIndex) {
    const searchEngineUrl = searchEngines[id].url;
    targetUrl = getSearchEngineUrl(searchEngineUrl, selection);
    if (logToConsole) console.log(`Target url: ${targetUrl}`);
    if (contextsearch_openSearchResultsInSidebar) {
        browser.sidebarAction.setPanel({ panel: targetUrl });
        browser.sidebarAction.setTitle({ title: 'Search results' });
        return;
    }
    displaySearchResults(targetUrl, tabIndex);
}

It turns out that I was missing the “<all_urls>” permission. It’s looking much better now, although Google search results are a bit of a mixed bag with some content overflowing horizontally. I have to use the “<all_urls>” permission because I don’t know in advance which custom search engines users might want to use.

I’m most grateful to you, Hans, for spotting this silly mistake!

I found the extension created by Mozilla that works nicely to view web pages in mobile view in the sidebar: it’s called Side View and I don’t think that its listed in the web extension examples.

Do I need to keep a sidebar_action in my manifest? I’m not using the search_results.html as I’m always using the setPanel method.

Also, is it possible to style the sidebar panel with CSS rules dynamically? Currently, my search_results.css stylesheet is used for search_results.html which isn’t being used.

Thank you again. I wish you a great end of week and I’m sorry if I came across as being a bit aggressive.

P.S. I don’t seem to be formatting my code correctly in these posts. Need to look this up somewhere! Sorry!

1 Like