Send information about window/frame from content_script to background_script

Hi,

I’m porting legacy addon and faced with difficulties.

From context of content_script I want to send message to background_script which refer to particular ‘window’ (DOM object). This is needed in cases when in particular page there are multiple frames.
In background script I can refer window by windowID but in content script I can’t find way get get windowID.
For example I want to print particular frame.

I also want to know where I can read about concept behind different webextension JavaScript API objects like windows, tabs and so on. In which type of objects are frames for example.

Regards,

Dimitar Angelov

I also want to know where I can read about concept behind different webextension JavaScript API

Are you looking for the documentation? That’s here:

In background script I can refer window by windowID but in content script I can’t find way get get windowID

Actually, it’s windowId not windowID.
I don’t think that a content script ever needs to be aware which window it is in. If you send messages to the background, the recieving end will have a .sender, whose .tab.windowId is what you want.
There is also a .tab.frameId on the sender. To have it set correctly, you need to use browser API of that frame. To get that, something like frameElement.contentWindow.browser.runtime.sendMessage(...) should work.

Than you very much for response!
I’ve understand that right way is to sent message from right window.
But I do something wrong because frameElement.contentWindow.browser is undefined in page script and in content script.

I’m not sure what you mean by page script.

For content scripts, I was afraid this would happen (but hoped it wouldn’t). The browser API is a property of the global object (this in non-strict functions without explicit this) and can thus be used as if it were defined as a variable. Usually in browsers, the global object is the window object is the global object (so that this === window is true). In content scripts (in Firefox) that was not the case the last time I checked. Here this.__proto__ === window is true. The browser API is defined on the global this and not on the window. .contentWindow will give you a reference to the window of the frame, which is not the global this of content scripts in that frame. I think it is very arguable whether that is a good design.

Anyway, to fix that, this should work:
Add this as the first "content_script" to your manifest:

    {
      "matches": ["Pattern matching the URLs of all frames to be handled"],
      "all_frames": true,
      "match_about_blank": true,
      "run_at": "document_start",
      "js": ["define-api.js"]
    }

In define-api.js put:

Object.defineProperty(window, "brower", { value: this.browser, enumerable: true, });

That should fix the missing .browser reference on .contentWindows. (I haven’t tested it, but something like this should work.)

Thank you again!

When I send message from context of iframe there issender.frameId property which is actually ‘windowId’ which is needed for me in background script to print particular frame.
For example if I want to print desired frame I simple send message from frame to background script.
In practice I tested that sender.frameId is windowsId that I can give as parameter of activeTab.linkedBrowser.print(windowID, printSettings, null);
I can’t find any proof at documentation that frameId is windowId.

That’s because they are not. Both being integer they can have the same value, but semantically they are different things.

Yes.
But interesting behavior is when call activeTab.linkedBrowser.print(frameId, printSettings, null); Only this frame is printed.
Is it possible activeTab.linkedBrowser.print to recognize frame?

Which framework are you trying to port to? activeTab.linkedBrowser.print doesn’t look like a WebExtension API.

I’m porting jsPrintSetup.
But there is lack of functionality in WebExtensions JavascriptAPI.
It these cases is recommended to write webextension experiment with proposition for new API.
What is progress of my current work (very roughly at this time).

  1. I’m writing hypothetical printervices API attached printservices.zip
  2. jsPrintSetp WE webextension jsPrinSetup.zip.
  3. Test example HTML example.zip
    The files are here
    https://drive.google.com/drive/folders/0B-F6l6AVXQ0DZFQwUzR3bERxQW8?usp=sharing

You have this in your experiment (SDK code):

        async printWindow(windowID = null, printSettings = null) {
// ...
            if (windowID == null)
              windowID = activeTab.linkedBrowser.outerWindowID;
// ...
            activeTab.linkedBrowser.print(windowID, printSettings_, null);

From that logic, isn’t windowID a frame id? And if the function always operates on the active tab, you should reflect that in it’s name, e.g. printActiveTab(frameId, options).

If my above assumptions are true, then the WebExtension frameIds may happen to have the same value as the desired first parameter to linkedBrowser.print, but I wouldn’t rely on it.

I have changed printWindow to printTab as follow.

    async printTab(tabId = null, windowID = null, printSettings = null) {
          let error = null;
          let activeTab = null;
          try {
            if (printSettings == null)
              printSettings = {};
            // prepare print settings
            let printSettings_ = printSettingsService.globalPrintSettings;
            if ((typeof(printSettings) == 'object') && ('printerName' in printSettings))
              printSettings_.printerName = printSettings.printerName;
            // First get any defaults from the printer
            printSettingsService.initPrintSettingsFromPrinter(printSettings_.printerName, printSettings_);
            // now augment them with any values from last time
            printSettingsService.initPrintSettingsFromPrefs(printSettings_, true, printSettings_.kInitSaveAll);
            setPrintSettings(printSettings_, printSettings);
            // obtain tab and windowId if not given
            activeTab = getTabOrActive(tabId);
            if (windowID == null)
              windowID = activeTab.linkedBrowser.outerWindowID;
            activeTab.linkedBrowser.print(windowID, printSettings_, null);
          } catch (err){
            error = err;
            Cu.reportError(err);
          }
          return new Promise((resolve, reject) => {
            if (error == null)
              resolve("print submitted");
            else 
              reject(error);
          });
        },

In my tests when I send message from content script to background script from context of window, frame1 and frame2 results are following:

context    tabId  windowId  frameId
window       5        3     0
frame1       5        3     6442450958
frame2       5        3     6442450959

Are there any internal correlation between frameId and windowId?
I’ve tried to search mozilla source code but without success.
Only thing that I can find is that activeTab.linkedBroser.print is something like https://dxr.mozilla.org/comm-aurora/source/mozilla/dom/base/nsFrameLoader.cpp#3416
Where window is get from global Window table https://dxr.mozilla.org/comm-aurora/source/mozilla/dom/base/nsFrameLoader.cpp#3437
How I can find exact parameter to call activeTab.linkedBrowser.print(windowID, printSettings, null); for printing frame?
In fact if I call activeTab.linkedBrowser.print(windowID, printSettings, null); with frameId instead of windowId only this frame is printed (in case frameId > 0).
May be I’m on wrong way and have to find alternative solution. My goal is to print particular frame. (XPCOM version of jsPrintSetup has this option).

Currently I’ve found how is working context menu "Print frame …"
https://dxr.mozilla.org/comm-aurora/source/suite/common/nsContextMenu.js#864
But can’t fined how to obtain frameOuterWindowID.

Are there any internal correlation between frameId and windowId?

Possibly. But that was exactly my previous point. Aperiently, the frameId (if != 0) is currently a frameOuterWindowID and can be used the way you do it. But that is only because it happens to be a convenient implementation for the Firefox developers at this time. This correlation may change without notice.

But then, you are writing an experiment, which is explicitly not meant for production, but only for experimenting and to propose an API.
So as long as you implementation works now, that’s really all you need.
(And I would call it printTab(tabId, frameId, ...). In WebExtensions, the id’s of frames are called frameIds, not windowID (after their global window object). windowId is used to address actual OS-level browser windows.)

Thank you!
I will correct it.