Collect infos on all iframes of current page? [SOLVED]

I’m writing a WebExtension that identify fields using a given criterion in a web page.

The content script which is loaded with every page and iframe does its job well identifying and highlighting those fields.

Now I want to count the total number of said fields in a page as the user sees it, that is, including its iframes, and display this number over the browserAction icon (as adblock displays a count over its action icon).

My plan was to use setBadgeText in the action script to clear the current counter, then issue a tabs.sendMessage({req:"countFields"}), and then let every content script respond to that message by getting the current value of the badgeText and increase it with the number of fields it found on its part of the page.

Well, that does not work well. I’m getting erratic values when a page contains iFrames. I guess this is a synchronization problem, when content scripts from different parts of the page try to get the badge value and update it.

I’ve also tried navigating through window.frames from a top level content script ("all_frames":false), but that won’t work either, since cross script errors can prevent me from descending all iFrames (using the online version of tinyMce for example)

Well, at this point, I’m asking for help and advice on how to solve my problem.
Any clue or pointer would be very much welcome !

So if I understand the problem - you get too big number because of the nested iframes inside iframes, right?

What may help is this:

const frameDetails = await browser.webNavigation.getAllFrames({tabId: targetTabId});
// 1) top frame has parentFrameId === 0
// 2) top frame has frameId === 0
// 3) ==> iframe has prentFrameId === 0
const frames = frameDetails.filter(frame => frame.parentFrameId === 0)

This should help you identify only those iframes that are direct child of the main document.

This should work:

const tabId = ...;
const count = (await Promise.all(
	(await browser.webNavigation.getAllFrames({ tabId, }))
	.map(({ frameId, }) => browser.tabs.sendMessage(tabid, ..., { frameId, }))
)).reduce((a, b) => a + b, 0);

And then every content script only reports it’s own count.

2 Likes

Thanks a lot

Using frameId in sendMessage was the catch I overlooked !