Closed Bug 1384515 Opened 3 years ago Closed 3 years ago

Provide an API for hiding and showing individual tabs

Categories

(WebExtensions :: Untriaged, enhancement, P2)

enhancement

Tracking

(Not tracked)

RESOLVED DUPLICATE of bug 1423725

People

(Reporter: johannh, Assigned: mixedpuppy)

References

(Depends on 1 open bug, Blocks 2 open bugs, )

Details

(Whiteboard: [design-decision-approved])

Attachments

(1 file, 1 obsolete file)

14.14 KB, application/x-xpinstall
Details
I've heard from several people that they're looking for an API that enables the usage of tabbrowser.showTab, tabbrowser.hideTab and/or tabbrowser.showOnlyTheseTabs. The primary use case I can point to right now is TabGroups (in fact I think this is blocking TabGroups from being ported to a WebExtension).

My initial suggestion was to fix up browser.tabs.update to include a "hidden" field, but bwinton mentioned that there are plans to refactor the tabbrowser APIs to only do batch operations, and that individual WE operations on tabs probably won't have a good chance of approval right now.

A suggested alternative would be browser.tabs.hide([tab1, tab2, ...]) and browser.tabs.show([tab1, tab2, ...]). It sounds to me like all stakeholders would find this acceptable.

Firefox Engineering will not work on faster tabstrip APIs in the coming months because everyone is _quite_ busy with Photon, but if the API that I suggested above is compatible with the planned improvements, maybe we can land this feature using the old tabbrowser.showTab/hideTab methods in time for 57, and switch to the new thing once it's implemented.

Dietrich mentioned he wanted to do a WE experiment for this.

Thoughts?
Would gladly appreciate that and immediately spend some time porting my TabGroups extension to it, just to avoid having too much fallout. `browser.tabs.hide` and `.show` would perfectly suit all needs, since everything else can be worked around.

> Dietrich mentioned he wanted to do a WE experiment for this.

++ as well. If I can help somehow, ping me.
I'm +1 on the suggested alternative API, and will gladly help out in any way I can.

(Indeed, everything from that point on is a good summarization of my conversations with Dolske, Andy, and Dietrich at SF! :)

If someone wants to start a repo on GitHub for the experiment, that might be a decent way to move forward…
Experiment here: https://github.com/autonome/webext-experiment-showOnlyTheseTabs

Thanks to rpl for helping me get it working.

On the add-on side, this is enough for any interested party to be able start prototyping/migrating a TabGroups or similar type of add-on to it. Then they'd just have to migrate the API usage when it is complete.

On the API side, this just mostly mirrors the existing API. The next step would be to update it based on the show/hide API semantics y'all agreed on here.
Whiteboard: [design-decision-needed]
(In reply to Johann Hofmann [:johannh] from comment #0)
> A suggested alternative would be browser.tabs.hide([tab1, tab2, ...]) and
> browser.tabs.show([tab1, tab2, ...]). It sounds to me like all stakeholders
> would find this acceptable.

Should these be hide/show exclusive?

Eg, does show([1,2]) hide tabs 3 and 4 if they're visible? And does hide([1,2]) show tabs 3 and 4 if they're hidden?

Or non-exclusive:

Eg, show([1,2]) shows those tabs in addition to tabs 3 and 4 (if they're visible)?

Should we add a magic value for show all?

Eg: show([])

I'm going to assume "hide all" is not a supported scenario :)
What if the tab ids span multiple windows? Should we restrict per window and add window as a constraining parameter, or just leave it simple and more powerful?

Johann and I talked also about the idea of show/hide vs show/hide+suspend. One of the limitations of tab groups as a feature and add-on was that loaded tabs in inactive groups still consume resources, even though the user has shown clear intent that they're done with those tabs, in a way that is far more strong than switching tabs.

I'd love to be able to do something like: hideAndLazify([some tabs]).
(In reply to Dietrich Ayala (:dietrich) from comment #5)
> Johann and I talked also about the idea of show/hide vs show/hide+suspend.
> One of the limitations of tab groups as a feature and add-on was that loaded
> tabs in inactive groups still consume resources, even though the user has
> shown clear intent that they're done with those tabs, in a way that is far
> more strong than switching tabs.
> 
> I'd love to be able to do something like: hideAndLazify([some tabs]).

Bug 1378647 and bug 1322485
Thanks Tim! Technically we'd only need to depend on bug 1284886 for the internal support. However, we should have a cohesive story for add-on authors for how all these APIs coexist and make sure they play nice together, so is good to be aware of these.

If we didn't add a combined hide+lazify functionality, and used .discard() it'd look something like:

<pseudocode>
var tabIds = getTabIdsYouWantToHide();
browser.tabs.hide(tabIds);
tabIds.map(getTabForId).forEach(tabs.discard)
</pseudocode>

Which seems fine.

Downside is that there's no action on that bug :(
(In reply to Dietrich Ayala (:dietrich) from comment #4)
> (In reply to Johann Hofmann [:johannh] from comment #0)
> > A suggested alternative would be browser.tabs.hide([tab1, tab2, ...]) and
> > browser.tabs.show([tab1, tab2, ...]). It sounds to me like all stakeholders
> > would find this acceptable.
> 
> Should these be hide/show exclusive?
> 
> Eg, does show([1,2]) hide tabs 3 and 4 if they're visible? And does
> hide([1,2]) show tabs 3 and 4 if they're hidden?
> 
> Or non-exclusive:
> 
> Eg, show([1,2]) shows those tabs in addition to tabs 3 and 4 (if they're
> visible)?

My vote is on non-exclusive. It's a more obvious API and it allows for more granular control.

> Should we add a magic value for show all?
> 
> Eg: show([])

It sounds handy to have a show-all, but this one could easily surprise extension authors when doing something like

browser.tabs.show(tabs.filter((tab) => !tab.title.includes("secret")))

> 
> I'm going to assume "hide all" is not a supported scenario :)

> What if the tab ids span multiple windows? Should we restrict per window and add window as a constraining parameter, or just leave it simple and more powerful?

I think this API is better when it's kept simple. It's really not that hard to manually do the things you mention with basic non-exclusive tabs.show and tabs.hide.

I'm not sure about discard. I wonder if we should just discard hidden tabs by default, to restrict the way that extension authors can abuse this to waste resources.
Hi Johann, this has been added to the agenda for the August 1 WebExtensions APIs triage meeting. Would you be able to join us? 

Wiki: https://wiki.mozilla.org/Add-ons/Contribute/Triage#Next_Meeting

Agenda: https://docs.google.com/document/d/1l5zlSASqZAzzJGZhHtLWY1yaUwCKZiHXXGP1k_2W-TU/edit#
If a tab is hidden like this, would that also mean that it is disabled? Meaning that it will never get activated automatically and that if the last visible tab is closed, but there is a hidden one, a new tab will be opened instead of activating the hidden one.
(In reply to Caitlin Neiman (http://pronoun.is/she) from comment #9)
> Hi Johann, this has been added to the agenda for the August 1 WebExtensions
> APIs triage meeting. Would you be able to join us? 
> 
> Wiki: https://wiki.mozilla.org/Add-ons/Contribute/Triage#Next_Meeting
> 
> Agenda:
> https://docs.google.com/document/d/1l5zlSASqZAzzJGZhHtLWY1yaUwCKZiHXXGP1k_2W-
> TU/edit#

I'll try to make it, though other folks (like Dietrich, bwinton or denschub) probably have greater stakes in this than me and could ideally join the meeting as well. If not, I will try to represent them as good as possible.
Priority: -- → P1
Whiteboard: [design-decision-needed] → [design-decision-approved]
(In reply to Johann Hofmann [:johannh] from comment #0)
> A suggested alternative would be browser.tabs.hide([tab1, tab2, ...]) and
> browser.tabs.show([tab1, tab2, ...]). It sounds to me like all stakeholders
> would find this acceptable.

I'm not sure about having 2 methods on browser.tabs. I feel like this should just be an update property.

If we really want to support batch operations, then a new updateMultiple/updateBatch method would be the way to go IMO.

But having it be an update property is much better because you can then update the `discarded` property at the same time as the `hidden` one.


You'd have stuff like this:

browser.tabs.update(tabId, { hidden: true, discarded: false });
browser.tabs.updateBatch([tab1, tab2, tab3], { hidden: false, discarded: true });

and so on...


I feel like this much more consistent with the current APIs, and also more flexible.
(In reply to Tim Nguyen :ntim from comment #14)
> I'm not sure about having 2 methods on browser.tabs. I feel like this should
> just be an update property.

There are already a bunch of methods on browser.tabs.  `highlight`, in particular, is very similar to this in that it handle multiple tabs by default.

> If we really want to support batch operations, then a new
> updateMultiple/updateBatch method would be the way to go IMO.

It's more than that.  We _only_ want to support batch operations.  Operations on a single tab were explicitly and strongly discouraged by the Firefox Front-End Engineering team.

> But having it be an update property is much better because you can then
> update the `discarded` property at the same time as the `hidden` one.

But it's much worse because it forces us into an operation-per-tab, which we want to avoid.

> I feel like this much more consistent with the current APIs, and also more
> flexible.

`setZoom`, `setZoomSettings`, `highlight`, `move`, and `print` are all methods on the `browser.tabs` object.  Adding `show`/`hide` seems pretty consistent to me, and I'm not convinced that the flexibility is useful here.
(In reply to Blake Winton (:bwinton) (:☕️) from comment #15)
> > If we really want to support batch operations, then a new
> > updateMultiple/updateBatch method would be the way to go IMO.
> 
> It's more than that.  We _only_ want to support batch operations. 
> Operations on a single tab were explicitly and strongly discouraged by the
> Firefox Front-End Engineering team.

Then the solution is to start supporting batch operations on browser.tabs.update(). Perhaps the first argument of update() could support passing an array instead of an extra updateBatch() method. Then updating the `hidden` property would only work if you specify an array.

browser.tabs.update([tab1, tab2, tab3], { hidden: true, discard: true });

But tbh, you could also just write an array with 1 item (even with your show/hide proposal) to workaround the batch limitation

> > I feel like this much more consistent with the current APIs, and also more
> > flexible.
> 
> `setZoom`, `setZoomSettings`, `highlight`, `move`, and `print` are all
> methods on the `browser.tabs` object.
Only `highlight` uses batch operations.

print, setZoom, setZoomSettings don't update a property on a tab, they just execute an operation on the page content related to it.

`move` needs some special data associated to it, so it makes sense as a separate method.

> and I'm not convinced that the flexibility is useful here.

It is useful in this case, :jkt mentioned hiding should suspend/discard the tab by default. How would you hide a tab without suspending/discarding it ? In the case of tab groups, we do *not* want to discard/suspend tabs.
(In reply to Tim Nguyen :ntim from comment #16)
> > > If we really want to support batch operations, then a new
> > > updateMultiple/updateBatch method would be the way to go IMO.
> > It's more than that.  We _only_ want to support batch operations. 
> > Operations on a single tab were explicitly and strongly discouraged by the
> > Firefox Front-End Engineering team.
> Then the solution is to start supporting batch operations on
> browser.tabs.update(). Perhaps the first argument of update() could support
> passing an array instead of an extra updateBatch() method. Then updating the
> `hidden` property would only work if you specify an array.

You _could_, but most people won't, for compatibility with other browsers, and having some properties work some times but not others depends on what kind of arguments you pass in seems like a terrible idea to me.  If nothing else, imagine how the documentation or autocompletions for that would look!

> But tbh, you could also just write an array with 1 item (even with your
> show/hide proposal) to workaround the batch limitation

Sure, but there it's very obvious that you're doing something weird and probably shouldn't.

> > and I'm not convinced that the flexibility is useful here.
> It is useful in this case, :jkt mentioned hiding should suspend/discard the
> tab by default. How would you hide a tab without suspending/discarding it ?
> In the case of tab groups, we do *not* want to discard/suspend tabs.

Don't we?  Also, `tabs.hide([tabids]);tabs.suspend([tabids])` isn't that hard to write if that's what you want.
My issue with non suspended tabs is they could continue to consume resources and make network requests without the user really knowing where the issue was coming from. This comes at a priv/sec and performance issue.

> Only `highlight` uses batch operations.

Also move(), I don't see any issue in exposing it as an array access only.

There is also the option of something like:

browser.tabs.visibility([tabIds], {keepActive: true, hidden: true});

This exposes one method only to reduce collisions of other extension apis whilst being similar to other APIs like move. Mostly the browser tries to only keep active pinned tabs right on session restore right? It would be nice to keep that similarity with this API.
(In reply to Jonathan Kingston [:jkt] from comment #18)
> My issue with non suspended tabs is they could continue to consume resources
> and make network requests without the user really knowing where the issue
> was coming from. This comes at a priv/sec and performance issue.
> 
> > Only `highlight` uses batch operations.
> 
> Also move(), I don't see any issue in exposing it as an array access only.
> 
> There is also the option of something like:
> 
> browser.tabs.visibility([tabIds], {keepActive: true, hidden: true});
> 
> This exposes one method only to reduce collisions of other extension apis
> whilst being similar to other APIs like move. Mostly the browser tries to
> only keep active pinned tabs right on session restore right? It would be
> nice to keep that similarity with this API.

I support the option of being able to keep a tab active while hidden - this is something I loved about panorama / tab groups and that pretty much no chrome addon could offer (Being able to interact with a client sided js web app, switch groups, then come back and have the same instance of the same tab - not an attempt at restoring the state when the tab was hidden).

A simple example of this is filling out a form, then hiding and showing tabs / switching tab groups, and being able to come back with the partially entered data. This also applies to more complex examples like javascript web app state.
(In reply to Blake Winton (:bwinton) (:☕️) from comment #17)
> (In reply to Tim Nguyen :ntim from comment #16)
> > > > If we really want to support batch operations, then a new
> > > > updateMultiple/updateBatch method would be the way to go IMO.
> > > It's more than that.  We _only_ want to support batch operations. 
> > > Operations on a single tab were explicitly and strongly discouraged by the
> > > Firefox Front-End Engineering team.
> > Then the solution is to start supporting batch operations on
> > browser.tabs.update(). Perhaps the first argument of update() could support
> > passing an array instead of an extra updateBatch() method. Then updating the
> > `hidden` property would only work if you specify an array.
> 
> You _could_, but most people won't, for compatibility with other browsers,
> and having some properties work some times but not others depends on what
> kind of arguments you pass in seems like a terrible idea to me.  If nothing
> else, imagine how the documentation or autocompletions for that would look!
> Don't we?  
If you move tabs between groups, or switch groups, you don't want your tabs to unload and lose your data there.

> > > and I'm not convinced that the flexibility is useful here.
> > It is useful in this case, :jkt mentioned hiding should suspend/discard the
> > tab by default. How would you hide a tab without suspending/discarding it ?
> > In the case of tab groups, we do *not* want to discard/suspend tabs.
> 
> Also, `tabs.hide([tabids]);tabs.suspend([tabids])` isn't that
> hard to write if that's what you want.

:jkt suggests that should be the default (tabs.hide + tabs.suspend) for performance, but what about hiding without suspending the tab ? You would have to do: tabs.hide + tabs.unsuspend, which would reload the page, since tabs.hide would already unload/suspend the page. Passing a second argument with { suspended: false } would essentially be reimplementing some type of browser.tabs.update() that hides tabs. 

Which is why I'm tempted to create a new browser.tabs.updateBatch() method supporting only the properties relevant to batch actions (hiding, suspending, highlighting, ...), this also solves your concern about browser.tabs.update becoming too complicated.
(In reply to Jonathan Kingston [:jkt] from comment #18)
> My issue with non suspended tabs is they could continue to consume resources
> and make network requests without the user really knowing where the issue
> was coming from. This comes at a priv/sec and performance issue.
> 
> > Only `highlight` uses batch operations.
> 
> Also move(), I don't see any issue in exposing it as an array access only.
> 
> There is also the option of something like:
> 
> browser.tabs.visibility([tabIds], {keepActive: true, hidden: true});
> 
> This exposes one method only to reduce collisions of other extension apis
> whilst being similar to other APIs like move. Mostly the browser tries to
> only keep active pinned tabs right on session restore right? It would be
> nice to keep that similarity with this API.

Could be nice to have a more generic method for batch updates (updateBatch?) and only support hidden/discarded/highlighted/... or anything else relevant to batch updating. I think it would be ok to have some properties supported for update and different properties supported for updateBatch, because some of `update` properties don't really make sense with `updateBatch` and vice-versa (like `active` which only makes sense for `update`)
Btw, I'm using `discarded` because chrome has chrome.tabs.discard(). Also see bug 1378647
Whatever semantics you choose, the API needs to be able to support both hidden inactive and hidden active tabs.

For users with lots of tabs, active hidden tabs were the worst part of TabGroups. For users with fewer tabs and who switched groups more often, it was the best part.

I recommend to not make too many assumptions about some eventual UI usage.

The balance of cross-browser compat and API flexibility seems like far better criteria for choosing the feature set and deciding the semantics.
I was asked to chime in here. So, some considerations now that, apparently, the decision from bug 1357214 is being reversed:

- what happens if all the tabs are hidden? The tabstrip doesn't currently deal well with this (and arguably shouldn't have to). This ties into the point comment 4 makes - if the API isn't exclusive and you first hide 2 tabs and then 2 other tabs, it's not necessarily obvious to the second call why it would (presumably) fail in some way.

- what happens with beforeunload? See also discussion in bug 1284886. This ties into the suspend discussion. This could be vaguely sane if we force suspending hidden tabs. If it's an option to not suspend them, it's not clear how you would deal with navigation in those hidden tabs - do we just force-unhide them? This would quickly break any illusions of coherent grouping. As a result, I think making suspending/discarding optional when hiding tabs is problematic.

- the APIs are (presumably?) async (or can happen from more than 1 add-on), so what happens if a partially-overlapping hide and show call (ie hide [1,5,10], show [2,3,5]) race, especially if we decide these calls are exclusive?

- if you're hiding but not suspending tabs, what happens when they pop alerts that would normally focus/select the tab? What about popups?

- if you're hiding *and* suspending tabs, it would trigger unload handlers in one tab, which can, in reaction, close other tabs that they control (on the same site), which makes the first point (ensuring there's always at least 1 non-hidden tab in a given window) more complicated. If you don't also suspend tabs, the hidden tabs could still close other tabs at will later, which should force one or more of the previous tabs to become visible again. In fact, it's also possible for a single remaining visible tab in one window to be closed by one in another window, so you'll have this problem regardless.

- I don't think the current show/hide implementations on tabbrowser do any visibilitychange notifications. Given that we've just improved those on OS X ( bug 1236512 ) I guess if we support hiding tabs without suspending them, we should make sure we send the correct notifications to pages.

Given all the above, it seems in addition to whatever update/show/hide API you go with, you also need an event API so (other) extensions can know when tabs are being hidden/shown, especially if the browser is forced to intervene without explicit show/hide calls in order to deal with tabs closing / beforeunload / whatever.
If hiding would always mean suspending, what would the point of hiding be? You could just close the tab and recover it when needed?

For generating thumbnails (see https://bugzilla.mozilla.org/show_bug.cgi?id=1246693) I would need hiding without suspending...

Regarding pop alerts / popups(assuming they are not user initiated which would be hard if a tab is hidden) / tabs that control other tabs - those should just always be forbidden anyway. Just saying...
(In reply to sblask from comment #25)
> Regarding pop alerts / popups(assuming they are not user initiated which
> would be hard if a tab is hidden)

Users can and do allow them for specific pages, so we can't just assume this doesn't happen.

> / tabs that control other tabs

This is a web feature that you probably rely on without realizing it, that is:

var w = window.open("compose_my_email.html", "_blank")

is pseudo-equivalent to what gmail does when writing an email and opening that in a new 'window'. And yes, if you close the original gmail tab, gmail then closes the dependent window it opened for you (which opened in a separate tab). See e.g. bug 1377039 .

Making it impossible for script-opened windows to close themselves (or for same-origin pages to do the same) would contravene the web spec and break real webpages, so we can't just break that usecase.
(In reply to :Gijs from comment #24)
> - what happens if all the tabs are hidden? The tabstrip doesn't currently
> deal well with this (and arguably shouldn't have to). This ties into the
> point comment 4 makes - if the API isn't exclusive and you first hide 2 tabs
> and then 2 other tabs, it's not necessarily obvious to the second call why
> it would (presumably) fail in some way.

Perhaps it should have a minimum of one tab.

> - the APIs are (presumably?) async (or can happen from more than 1 add-on),
> so what happens if a partially-overlapping hide and show call (ie hide
> [1,5,10], show [2,3,5]) race, especially if we decide these calls are
> exclusive?

async. These are all the exact same race conditions that can occur right now with tabs.move, tabs.update etc. its not great, but I don't think we need to anything special here.
(In reply to Dietrich Ayala (:dietrich) from comment #23)
> For users with lots of tabs, active hidden tabs were the worst part of
> TabGroups. For users with fewer tabs and who switched groups more often, it
> was the best part.

As a user with lots of tabs I feel misrepresented here. I do *not* want my tabs discarded, even if they are in a different group. I switch groups frequently and have interactive websites (some which also use desktop notifications) open in different groups. Discarding them just because I switch groups would be unwelcome due to loss of background updates.

I also use the tabbar switch-to behavior (% tabname) which also automatically switches tab groups. In essence I just want a set of related tabs on the tab bar but still be able to have other tabs open.

Having the ability to discard invisible tabs is certainly desirable for some use-cases, but it would be quite annoying for others.

Those features should be considered orthogonal.
(In reply to :Gijs from comment #24)
> - if you're hiding but not suspending tabs, what happens when they pop
> alerts that would normally focus/select the tab? What about popups?

If necessary the browser should be allowed to unhide a tab even though an addon set it to hidden. This can be necessary for popups, alerts, when using switch-to behavior or when using desktop notifications.

Addons should be notified of this change. For example if the browser decides to switch to a hidden tab where the hidden tab belongs to a tab group, some tab-subtree or similar thing (addon-internal concepts) then they can treat this as an external trigger to switch to the previously hidden group/subtree/whatever.

The tabgroups addon already does exactly this to deal with the above-mentioned cases.

Change notifications also allow different tab-related addons to interact with each other. Some use-cases may be mutually exclusive, but others may not. For example an addon that simply counts the number of visible tabs and updates its toolbar icon to show the number can incorporate those change notifications to deal with the changes made by a tab groups addon.
(In reply to The 8472 from comment #28)
> (In reply to Dietrich Ayala (:dietrich) from comment #23)
> > For users with lots of tabs, active hidden tabs were the worst part of
> > TabGroups. For users with fewer tabs and who switched groups more often, it
> > was the best part.
> 
> As a user with lots of tabs I feel misrepresented here. I do *not* want my
> tabs discarded, even if they are in a different group. 

More concisely, I think the point is that if user opens a tab, then leave it there.. It is his own business to ultimately keep "track" of it. 
If he feels like the session's getting heavier he can always restart the browser (whenever bug 1366009 lands). 

Which at the very worst is simply _current situation_.
Yes, as a tabgroup user i have no interest that tabs will be suspended or discarded automatically in background on group switching, it is nice if the user can decide if tabs should be unloaded, suspended or whatever but this should be a tab based explicit user action. If youtube shall play in background or i get a message in background then it should also work. At the moment i have also no automatically tab/group switching on such events as notifications or popups. And this is ok! Things should made not be more complicate as needed.
(In reply to The 8472 from comment #28)
> (In reply to Dietrich Ayala (:dietrich) from comment #23)
> > For users with lots of tabs, active hidden tabs were the worst part of
> > TabGroups. For users with fewer tabs and who switched groups more often, it
> > was the best part.
> 
> As a user with lots of tabs I feel misrepresented here. I do *not* want my
> tabs discarded, even if they are in a different group.

Yep, as I said in that comment, we need *both*, so that new add-ons can be created that work in all permutations of suspend or not.

Remember - we're designing an *API*, not a feature.

Also, to all the TabGroups users - this API isn't solely to rebuild TabGroups. Actually, I'm not sure the original add-on can get working again as-is, even with this API...
(In reply to Dietrich Ayala (:dietrich) from comment #32)
> Remember - we're designing an *API*, not a feature.
>
> Also, to all the TabGroups users - this API isn't solely to rebuild
> TabGroups. Actually, I'm not sure the original add-on can get working again
> as-is, even with this API...

Nevertheless, it is a step in the right direction, IMHO. This API would allow us to begin to rebuild that functionality. Speaking as yet another TabGroups user, with several hundred tabs, thank you all for working on this.
I think it'll be possible to build something pretty similar to the current TabGroups plugin once we can hide tabs (without suspending them). UI-wise I think it'll not be possible to display the current TabGroup name next to the browser-action item, but apart from that I don't see what would be missing.
(In reply to github from comment #34)
> UI-wise I think it'll not be possible to display the current TabGroup name next to the
> browser-action item, but apart from that I don't see what would be missing.

You can use a badge to display text.
True .... only up to 4 chars though.
I am currently playing around with marrying contextual identities with tabgroups. As the identity is displayed in the location bar, the issue of not deplaying the tab name is actually not an issue anymore :)
are there any news on this? I have kind of a tabgroups successor in an okaish state but still need to be able to hide tabs somehow. Now that with nightly TabGroups is becoming less and less functional, I would really like to have a replacement on WebExtensions technology (and I think I am not alone).
I already played around with a work-around that moves tabs to a different, minimized window -- but that is not a workable solution.
Cheers
I haven't had time to get back to this.

We can probably hide active tabs and live with the same warts that TabGroups had (eg, stuff Gijs raised in comment #24).

We can probably split out the tab suspending part for now, since that's handled in a different bug for per-tab suspension, and then add it to this new API as a parameter later, for batch suspension.

From the comments above, sounds like we need agreement on semantics - eg, tabs.update vs tabs.updateBatch vs tabs.hide/tabs.show.

My preference is towards as explicit as possible (hide/show), as opposed to overloading a generic "do all the things" API.
I believe these APIs will work well with gmail/github like way of filtering I already implemented (see http://tinyurl.com/at-your-command), so I am going to put them to use as soon as they are available.
My user, lets say she is a writer, will then use them like this:
She will specify search query »b folder:chapter1« to filter bookmarks from folder chapter1. She will be able to run commands "open" as well as "open suspended" if she has many websites bookmarked in that folder.
Since she has hundreds of tabs opened, she will specify »tb folder:chapter1« to filter only tabs related to project called chapter1. She will run command "show only selected" to make selected tabs visible in tabbar and hide others.
As she will be going through chapters, she will start to noticing that firefox is getting slower. So she will specify »tb folder:[] is:hidden -is:suspended« to filter tabs which are not related to any project, are hidden and not suspended and run "suspend" or "close" command to free some resources.
Do I please understand it correctly that it will be possible to use these APIs like this?
Is suspended the state tabs are in when Firefox restarts after it crashed? (I am not sure if this is a default effect or Tab Mix Plus addon  is somehow responsible for this though.)
Status hidden means that tabs are not shown in tabbar at all... Do I understand it correctly?
I agree with explicificity vs a generic update and would implement the operation non-exclusivly (as defined in comment#4).
I am unsure about:

    tabs.hide([tabId1, tabId2, ...]) / tabs.show([tabId3, tabId4, ...])

vs.

    tabs.visibility({tabId1: true, tabId2: true, tabId3: false, tabId4: false})

the `tabs.visibility` version is probably avoiding some weird conditions, for example:

- checking, that at least one tab stays visible would be simpler
- if you only show tabs that were hidden before and hide tabs that are currently visible (more or less the standard for tabgroup'esque extensions), calling `tabs.hide()` and `tabs.show()` in this order could create the condition of no tab being visible between the two calls
- if one `tabId` is listed multiple times, the behavior of which one will "survive" is handled by js and does not need to be implemented as keys are unique.
There will be something like hidden/visibility boolean value in tabs.Tab type (https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/Tab), right?
Blocks: 1232178
If I may offer my 2 cents here...

Regarding suspending tabs, can that be left up to the addon?  It seems to me a good first step would be to set up an API only for hiding/showing tabs, and leave suspending tabs out of the mix.  IIUC, there is no complication in that.  If a tab groups addon wishes to offer that as an option then it could be dealt with from the addon.  This should be possible through bug 1322485.

If we decide that it would be good to make tab suspending part of this API, bugs could be filed against that at a later time. 

But it seems to me that starting simple would be a good way to go in this case.
/me agrees with comment#43 + would expect there to be a visibility boolean on tabs.Tab as well
Flags: needinfo?(amckay)
Flags: needinfo?(amckay)
Priority: P1 → P2
I don't want to create unnecessary noise, but is there any chance that this will land in v57? 57 Beta is only 3 weeks away and I guess if this is not started before then, the chances are not too high that this will be started before the big 57 release, right?
The P1 -> P2 change is not too encouraging either :/

Cheers
Hello there,

I use Nightly as my daily work browser, and I'd like to do so for my not-work related usage too.
I am more likely to catch "real world™" weirdness in my evening/night browsing sessions (news, shopping, …).
I already find it difficult to work without  panorama/tab group extension in my day-to-day job, where I do need proper "workspaces" in the browser. But it is also a major blocker that prevent me to do the switch to Nightly for my personal use.
Enabling this API would definitely help the 57 foxfooding we're invited to do.
@andym could you perhaps write a really short comment on what’s the rough plan for this? Pinging you since you set it from P1 -> P2: even a brief “no prio die to 57 release” would be more helpful than no comment at all.
Cheers
I'm working on implementing hide/show semantics in the experiment API today.

Regarding the requirement for always at least one tab visible:

* Could we throw an exception? This would be explicit, allows to catch the scenario when add-ons are still in development. Leads to fewer unknowns.

* If that's not cool, then we need to pick a tab to remain visible. Most intuitive would be to leave either first or last in the set of tabs the caller is asking to hide. I really vote for not going this route. Too arbitrary. Too much unforeseen behavior will show up in add-ons.

Pinned tabs:

* Pinned tabs should never be hidden, so we should be able to hide all other tabs if there are pinned tabs.

* How to handle pinned tabs in a show/hide request? Ignore? Exception? Filter out of the set and just operate on the rest?


Regarding input parameters: The input parameter for hide/show is an array of tab ids. I'm going to keep it that way, as it seems to be the way other tab APIs like remove() have done it.

Regarding return value: Like tabs.remove(), this should be a promise that resolves once the action has been taken.

Regarding event model: Should we add "hidden" "visible" events to correspond with these actions that we're allowing add-ons to take? I think it's in line with other APIs on tabs, so recommend that we do it.
For what it's worth, the prior functionality (for example with Tab Groups on < 57) if you attempted to hide ALL tabs by switching to a group with no tabs in it was to simple spawn a new tab open to the default "new tab" page.  The occurred EVEN IF you had pinned tabs.

After execution of tab.hide... or tab.visibility... you could check to see if there were 0 visible tabs and if so, spawn a new one to the "new tab" page.  I don't think you need to raise an exception or force them to keep one of their old tabs open, but I'm just looking at it as a very interested outside observer.
@dietrich: very cool! Thank you so much.
I agree with Scott that the tabgroup’s approach should be very simple to implement and simple to react on for extensions.

Regarding pinned tabs: couldn’t this be up to the caller? So: API-wise handle pinned tabs just as every other tab and let the caller decide wether it handles pinned tabs differently?

Regarding Return and events: both suggestions sound perfect to me — events will come in handy if more than one installed extension hides / shows tabs.
Thanks a lot for your work
Hey all, another quick reminder that this bug is not about Tab Groups. This bug is about designing a hide/show tabs API that can be used for extensions *like* Tab Groups.

Adding a new tab is something that can happen *in the extension*. The API needs to allow extensions to make those decisions for themselves, and not dogmatically decide for them.

For example, the Tab Groups extension can catch an exception and handle it by adding a new blank tab and then hiding everything else. In actuality, it would probably just make sure it's doing this correctly beforehand. But if the API started leaving one last tab, or generating new visible tabs, there's non-determinate behavior that now needs to be worked around by *all* extensions.

In this case, we don't want extensions doing things that shouldn't be done, so we can tell them so... and should do that explicitly.
Re some comments above, yes we should probably also have a property on tab objects for determining visibility.

In short, properly implementing things would look a bit like this:

function tabs.show
function tabs.hide

event tabs.onShow
event tabs.onHide

property tab.visible
support in tabs.query for tab.visible
(In reply to Dietrich Ayala (:dietrich) from comment #52)
> Hey all, another quick reminder that this bug is not about Tab Groups. This
> bug is about designing a hide/show tabs API that can be used for extensions
> *like* Tab Groups.
> 
> Adding a new tab is something that can happen *in the extension*. The API
> needs to allow extensions to make those decisions for themselves, and not
> dogmatically decide for them.
> 
> For example, the Tab Groups extension can catch an exception and handle it
> by adding a new blank tab and then hiding everything else. In actuality, it
> would probably just make sure it's doing this correctly beforehand. But if
> the API started leaving one last tab, or generating new visible tabs,
> there's non-determinate behavior that now needs to be worked around by *all*
> extensions.
> 
> In this case, we don't want extensions doing things that shouldn't be done,
> so we can tell them so... and should do that explicitly.

You are right, that really is the better way to do it. I would still allow to hide pinned unless I semantically missed something
(In reply to kesselborn from comment #54)
> I would still allow
> to hide pinned unless I semantically missed something

Sorry, I forgot to reply to this. I think I agree.

There are two user decisions in conflict in this scenario: "always show these special tabs" and "i installed the extension StuffWithTabs".

I believe the point of extensions is to customize the browser experience. If we allow pinned tabs to be hidden via the API, extensions have the option of showing them or not, and users can choose the behavior they like best.

However, the reality is that pinned tabs are handled specially throughout the browser. It may or may not actually be possible to implement this without large changes in the Firefox core. TBD.
Ok, that’s what I meant with thingsI probably don’t know enough about. If it means working against how pinned tabs are implemented throughout Firefox,I think it’s not worth implementing it.
Thanks again
What if this API will work only if there are no pinned tabs at all? At least for the time being? It would return some error in that case...
API still would be very useful for many people. I never use pinned tabs - for example.
(In reply to Jan Zavřel from comment #57)
> What if this API will work only if there are no pinned tabs at all? At least
> for the time being? It would return some error in that case...

What?
I meant no pinned tabs currently opened in Firefox ;-) See Comment 55: It may or may not actually be possible to implement this without large changes in the Firefox core.
If large changes (due to pinned tabs) will be the case, wouldn’t it mean we will not see this API for long time?
@Jan: that's why Dietrich suggested a solution where pinned tabs would just always stay visible -- I argued against it without knowing, that pinned tabs have a lot of extra handling in firefox, so I think the solution Dietrich is aiming for is to implement the API but make pinned tabs un-hideable :)
See Also: → 1322057
Experiment updated with working hide/show APIs:

https://github.com/autonome/webext-experiment-showOnlyTheseTabs

* I haven't figured out how to access the scope of the ext-*.js stuff, so this is using tabbrowser in the active window directly. This means the API only applies to the active window, until I figure that bit out.

* The tabbrowser.showOnlyTheseTabs() method handles the "hide all" scenario by leaving the left-most tab open when there are no pinned tabs, or leaving all pinned tabs open if there are some. For now that's what we'll be going with.
This is totally a drive-by comment (apologies), but couldn't handling the 'hiding the last tab' scenario be solved by requiring that a tab-hiding function also be passed a function to produce at least one tab in case it hides the last tab? This function could be determined by a setting respected by multiple extensions.
@dietrich: very exciting news ... will try that out with conex as soon as I have some time. Thank you so much for your work
@dietrich: tried it out at https://github.com/kesselborn/conex/commit/8830898c11f786cc6a49de83a1008a6e24223c94 and it works like a charm :) -- looking forward for further progress there.
Updated the experiment to include the ability to hide the tab bar, based on Timothy Johnson's experiment in bug 1332447.

https://github.com/autonome/webext-experiment-showOnlyTheseTabs
Depends on: 1408053
Hi Dietrich, your experiment has been added to the agenda for the October 17 WebExtensions APIs triage meeting for review and next steps. Would you be able to join us or send a representative? 

Here's a few things about the triage to keep in mind: 

* We normally spend 5 minutes per bug
* If it looks like the experiment is ready to go, we'll try to find a mentor to help uplift 

Relevant Links: 

* Wiki for the meeting: https://wiki.mozilla.org/Add-ons/Contribute/Triage
* Meeting agenda: https://docs.google.com/document/d/1oUFGD57_NGbtV5y8k_yIS3GN8pFO3M_K1SWQhzlq6Ho/edit#heading=h.hhpni8ijl0wx
* Vision doc for WebExtensions: https://wiki.mozilla.org/WebExtensions/Vision
Assignee: nobody → mixedpuppy
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

WIP.  I modified the extension from the experiment for manual testing, but still have to write tests.
Attachment #8920429 - Flags: feedback?(dietrich)
Attachment #8920429 - Flags: feedback?(aswan)
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

https://reviewboard.mozilla.org/r/191402/#review196590

There doesn't seem to be any code for handling the case where all tabs are hidden.

::: browser/components/extensions/ext-tabs.js:978
(Diff revision 1)
> +          if (!Array.isArray(tabIds)) {
> +            tabIds = [tabIds];
> +          }
> +          for (let [gBrowser, tabs] of getBrowserTabsMap(tabIds).entries()) {
> +            gBrowser.hideTabs(tabs);
> +            // We additionally discard hidden tabs.

There should be a way to configure this via the WE API, otherwise it makes this API useless IMO: you could just close the tab, as hiding and discarding the tab would essentially be the same.
(In reply to Tim Nguyen :ntim from comment #69)
> Comment on attachment 8920429 [details]
> Bug 1384515 add show/hide tabs api
> 
> https://reviewboard.mozilla.org/r/191402/#review196590
> 
> There doesn't seem to be any code for handling the case where all tabs are
> hidden.

You cannot hide all the tabs, that is handled in tabbrowser.  The current tab is not hideable, as well as in several other situations.  There are other edge cases that may seem to not be handled in the api, but they are in tabbrowser.

> ::: browser/components/extensions/ext-tabs.js:978
> (Diff revision 1)
> > +          if (!Array.isArray(tabIds)) {
> > +            tabIds = [tabIds];
> > +          }
> > +          for (let [gBrowser, tabs] of getBrowserTabsMap(tabIds).entries()) {
> > +            gBrowser.hideTabs(tabs);
> > +            // We additionally discard hidden tabs.
> 
> There should be a way to configure this via the WE API, otherwise it makes
> this API useless IMO: 

not really IMO.
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

I'm not sure exactly what level of feedback you're looking for here.  From a relatively quick look, I don't have any quibbles with the implementation strategy you've taken.  But it seems like there are a bunch of unanswered questions that need to be resolved before we even start talking about implementation.  Comment 24 is a good place to start with these questions, the discard-or-not question is the other really big one.  And overshadowing these engineering questions are the product/UX questions about whether there should be restrictions on this or some sort of safeguard for the case where a buggy (or malicious) extension breaks things so badly that the user needs a way to recover...
Attachment #8920429 - Flags: feedback?(aswan) → feedback+
(In reply to Andrew Swan [:aswan] from comment #71)
> Comment on attachment 8920429 [details]
> Bug 1384515 add show/hide tabs api
> 
> I'm not sure exactly what level of feedback you're looking for here.  From a
> relatively quick look, I don't have any quibbles with the implementation
> strategy you've taken.  

That and any gotcha's you might see.

> But it seems like there are a bunch of unanswered
> questions that need to be resolved before we even start talking about
> implementation.  Comment 24 is a good place to start with these questions,
> the discard-or-not question is the other really big one.  

It's actually meant to be suspend not discard.  I had discard in my head due to another bug.  In either case, comment 24 points out a lot of issues that would need to be solved if we didn't suspend or discard.  Those will need to be dealt with eventually so we can make it an option, but for now it's not optional so we can take a step forward.  There are a couple other issues that probably need to be addressed there as well, and some that don't.  The primary issue will be the triggering of unload allowing a parent window to close child windows.

> And overshadowing
> these engineering questions are the product/UX questions about whether there
> should be restrictions on this or some sort of safeguard for the case where
> a buggy (or malicious) extension breaks things so badly that the user needs
> a way to recover...

It will get a permission.  It needs to track what the extension hides so they can be unhidden for disable/uninstall.  I'm not concerned about malicious tab hiding extensions so long as we're suspending, but it may need further thought in the future.  I'm sure there will be a couple more items.  As far as any UX in firefox itself, that can be handled seperately if needed at all.  I don't think it's really necessary as a blocker since the user will be able to just disable the extension.
(In reply to Shane Caraveo (:mixedpuppy) from comment #72)
> (In reply to Andrew Swan [:aswan] from comment #71)
> > Comment on attachment 8920429 [details]

> > But it seems like there are a bunch of unanswered
> > questions that need to be resolved before we even start talking about
> > implementation.  Comment 24 is a good place to start with these questions,
> > the discard-or-not question is the other really big one.  
> 
> It's actually meant to be suspend not discard.

Revisiting the discard, it is actually what we want.  From what I see, that method returns the tab to a lazy state.
Attached file hidetabs.xpi
a modified version of dietrich's test extension.
So far with this patch:

- tab data (such as partially filled in forms) is preserved when hidden/discarded
- hidden/discarded tabs of course are preserved across sessions
- punting on handling tab owner issues when discarding for the first round (ie. we wont discard those tabs)
- "last tab closed" when all other tabs are hidden causes the next tab to the unhidden.  this is already handled by the platform.
- new tabHide permission restricts tab hiding, but not other parts of the api (show/onUpdated/query)
- hide api does not preclude adding options later

Pretty much, this is in good working condition.

Still have to manage hidden tabs on an extension basis, and this is where I plan to go with it.  This is based on a presumption that it is unlikely/rare a user is going to have multiple tab managing extensions installed at the same time.

- internally, the api will track the tabs by the extension that successfully hides it.
- only one extension "owns" a hidden tab.  This reduces the complexity of dealing with disable/uninstall/upgrades
- any extension may show any hidden tab (an extension could simply provide a show-all button)

So, if two extensions hide the same tab, the second will fail since it's already hidden. 
When an extension is disabled/uninstalled, any hidden tabs it "owns" will be shown.

An earlier comment about show/hide racing, we'll just let that happen and see if it is a real problem.
Blocks: 1410548
Without an option to hide tabs without discarding, the behaviour of Tab Groups can not be properly replicated here.

Tab Groups doesn't discard tabs when switching groups.
I'm not much inclined towards listening to "the way it was" or "this is useless" statements.  If you want to gain traction provide something with substance.  If you read between the lines just a bit, you'd also realize that this cant be done *right now*.  There are more issues to resolve and additional reviews to be done.  As I said, the api doesn't preclude adding options.
Do we have a list of possible use cases for this API ? I’m following this thread from the “tab groups extentions” point of view, so I’d like a wider view. It seems a good idea to me to check the features against concrete use cases from time to time, nevertheless.
(In reply to Shane Caraveo (:mixedpuppy) from comment #78)
> I'm not much inclined towards listening to "the way it was" or "this is
> useless" statements. 

Thinking logically, instead of just dirtily trying to reach an objective as fast as possible is certainly the way to go.

After reading comment 24 though, I'm still baffled over why "bells and whistles", even for the edge cases of an already messy-prone use-case, is a concern. 
Also, maybe it's just me, but using the browser is not watching a movie, I don't need any illusion of coherency in my tasks. 
If even a trashy ad wants to tell me I won a car while hidden, why not interrupting my workflow.. Like would exactly happen in the "same-tabstrip" case?
(In reply to Shane Caraveo (:mixedpuppy) from comment #78)
> As I said, the api doesn't preclude adding options.

I've suggested an API that would play well with options in comment 21.

updateBatch(tabIds, { hidden: true, discarded: false })

> "this is useless"

Tbh, I do think hiding tabs then discarding them would just be equivalent to closing them. If you unhide the tab, the tab would need to reload, just like reopening the tab would.
(In reply to Tim Nguyen :ntim from comment #81)
> (In reply to Shane Caraveo (:mixedpuppy) from comment #78)
> Tbh, I do think hiding tabs then discarding them would just be equivalent to
> closing them. If you unhide the tab, the tab would need to reload, just like
> reopening the tab would.

Technically (as mentioned in comment 76), you still get to retain old "tab data". 
It's useless with respect to the tab group use-case if any, but again, he has a point saying NOT to use that as a *starting* point to implement stuff.
(In reply to Shane Caraveo (:mixedpuppy) from comment #73)
> (In reply to Shane Caraveo (:mixedpuppy) from comment #72)
> > (In reply to Andrew Swan [:aswan] from comment #71)
> > > Comment on attachment 8920429 [details]
> 
> > > But it seems like there are a bunch of unanswered
> > > questions that need to be resolved before we even start talking about
> > > implementation.  Comment 24 is a good place to start with these questions,
> > > the discard-or-not question is the other really big one.  
> > 
> > It's actually meant to be suspend not discard.
> 
> Revisiting the discard, it is actually what we want.  From what I see, that
> method returns the tab to a lazy state.

First of all: thanks for working on this -- very much appreciated.
I agree that providing arguments with substance is the right way to go, but to be fair: the decision that discarding is "what we actually want" came without an explanation as well.
For extensions that would like to mimic the behavior of the old tab-groups extension (which was quite popular), discarding the hidden tabs would make this api mostly useless, as users potentially very quickly show and hide a huge amount of tabs and jump between some tabs. If I toggle between two tabs which are in different groups, that would mean that on each tab-change, the tab has to be reloaded (unless I misunderstand discarding).
There are already bugs for discarding tabs (bug #1322485 and several others), so I don't really understand why this suddenly should be the only way to hide tabs. 

Could we limit this bug to what it describes in the subject: hiding and showing tabs? Discarding is a different story and for _some_ use cases not desirable when hiding tabs (if an extension wants to hide and discard, this could easily be achieved with two API calls, no big deal). Dietrichs implementation worked like that and for the use case I was testing it with it works pretty great and as expected.

@tim: why do you think a tab has to be reloaded if it gets unhidden?
(In reply to mirh from comment #82)
> (In reply to Tim Nguyen :ntim from comment #81)
> > (In reply to Shane Caraveo (:mixedpuppy) from comment #78)
> > Tbh, I do think hiding tabs then discarding them would just be equivalent to
> > closing them. If you unhide the tab, the tab would need to reload, just like
> > reopening the tab would.
> 
> Technically (as mentioned in comment 76), you still get to retain old "tab
> data". 
> It's useless with respect to the tab group use-case if any, but again, he
> has a point saying NOT to use that as a *starting* point to implement stuff.

ok ... but that is one use case. Regarding starting point: the first implementation from Dietrich did not discard tabs, so the decision to discard is a change to that.
(sorry for multiple comments -- I just want to stay in context)

> 
> - internally, the api will track the tabs by the extension that successfully
> hides it.
> - only one extension "owns" a hidden tab.  This reduces the complexity of
> dealing with disable/uninstall/upgrades
> - any extension may show any hidden tab (an extension could simply provide a
> show-all button)
> 
> So, if two extensions hide the same tab, the second will fail since it's
> already hidden. 
> When an extension is disabled/uninstalled, any hidden tabs it "owns" will be
> shown.
> 
> An earlier comment about show/hide racing, we'll just let that happen and
> see if it is a real problem.

I wonder if this does introduce an unnecessary complexity. I would understand the api-call as an intent the extension wants to achieve, e.g.:

- hide tabs: 1, 3, 7, 5
- show tabs: 10, 5, 19, 60

if multiple extensions use the api, let them deal with possible inconsistencies. If in the example above tabs 3 and 7 are hidden already, hide 1 and 5 and return without an error, as the intended state was successfully achieved (all of the given tabs are hidden now).

Regarding the case where extensions are hidden/disabled: the api could just unhide all hidden tabs and send an event that extensions can listen to and restore the desired state (in the example above, the extension would need to execute the same hide and show calls again).

This way the api does not need to keep track of which extensions shows and hides tabs or owns a tab. If you want to keep track of who hides and shows which tabs, you would need to have a time based order as well for the case extension 1 hides tab 1 and extension 2 shows tab 1 afterwards -- which state would you recreate? Furthermore, you would need to remove closed tabs from the structure that keeps track of the extensions' operations, etc. I really think this will become a nightmare to implement.
Depending on the extensions that will use this API, owning a hidden tabs could be problematic as well and disallow to implement some behavior which could be desirable.

Regarding show/hide racing: yeah: I agree: just let it happen
> @tim: why do you think a tab has to be reloaded if it gets unhidden?

If it was discarded/suspended/unloaded when hidden, then yes, the tab needs to reload if it gets unhidden. That is the current implementation in the patch.
(In reply to Tim Nguyen :ntim from comment #86)
> > @tim: why do you think a tab has to be reloaded if it gets unhidden?
> 
> If it was discarded/suspended/unloaded when hidden, then yes, the tab needs
> to reload if it gets unhidden. That is the current implementation in the
> patch.

ah, ok -- in this case yes. I just hope that the decision to always discard tabs when hiding is not final (for the reasons I explained above).
(In reply to kesselborn from comment #85)
> (sorry for multiple comments -- I just want to stay in context)

> If in the example above tabs 3 and 7 are hidden already,
> hide 1 and 5 and return without an error, 

That should be how it's working already.

> Regarding the case where extensions are hidden/disabled: the api could just
> unhide all hidden tabs and send an event that extensions can listen to and
> restore the desired state (in the example above, the extension would need to
> execute the same hide and show calls again).

That's a good idea.  In several APIs we restore the prior state, whether by extension or user.  That is messy with this particular api.  When I was considering that, I already decided it wasn't important to be that detailed.  I'll think about this approach.  Thanks!
BTW, the general plan is up on a wiki now at https://wiki.mozilla.org/WebExtensions/TabHiding

Perhaps that will help explain some motivations we have.  There will likely be a couple minor differences:

- I used Tab.hidden as that matches our internal API, 
- last tab visible being closed currently shows the next (hidden) tab, which is the implementation of the browser itself I believe.  I'm reluctant to close a bunch of hidden tabs as they may have state.
@shane: thanks for the replies and the reference to the wiki page. It makes a good job explaining possible problems with hiding tabs. As one of the implementors of an extension that does a similar job as tab-groups, I am still in need of hiding tabs without discarding them.

This is a movie of Dietrichs experiment in conjuntion with my web-extension:

https://www.youtube.com/watch?v=wTwmIFSnLWY if somebody wants to see it with a real example: it hides all containers but the one that's currently used + provides a way to quickly search and find tabs.

Cheers
I'd like to address 2 things here:

[1] Some of the comments give me the impression that all tab groups users want to use groups a certain way, eg, they want their tabs to be loaded and ready to go when switching groups.

I tend to not agree with that.  Many users of my tab groups addon actually wanted to use groups to conserve resources (thinking if they couldn't see the tabs they must not be using resources).  In my addon I supported this class of users by supplying functionality that would "suspend group", which in essence closed all the tabs in that group (circumventing closed tabs history) and saved the tabs data in serial form for restoration later.

This argument gets somewhat more diluted when you consider that all tabs start out as discarded in the first place.  I found that a good many of my users have tabs in groups that are never loaded to begin with.

Further diluting the argument is that my observation of tab groups users was that they were not constantly switching back and forth between groups expecting loaded and ready tabs at their fingertips, but would tend to stay in a group for a while while working with a certain subject.  Often groups were set on the "back burner".  They used groups like some might use bookmarks, only groups were a much more convenient and optimized way of handling it.

So all in all, I am not sure that the use case of needing to switch back and forth between groups which have tabs loaded and ready to go represents an overwhelming majority, if even a majority at all.

[2] It has been stated (I'm pretty sure more than once) that discarding tabs when hiding them is a first stage of this process, and that other options can be added later, which will involve quite a bit more complexity and have several issues to overcome, one being security.

So, we could:

Roll out an API which will at least cover use cases of a good many users* which could be available at time A, then as the issues are worked out blocking the hiding of non-discarded tabs, a more comprehensive API could be made available at time B.

Wait until all the issues are worked out blocking the hiding of non-discarded tabs and not make anything available until the more comprehensive API is complete at time B.  The users who could have benefited from a preliminary roll-out would just have to wait.

Get it?

(* This may even include those users who while they would prefer not having discarded tabs in their hidden groups, would prefer that to not having tab groups at all)
(In reply to Tim Nguyen :ntim from comment #81)
> Tbh, I do think hiding tabs then discarding them would just be equivalent to
> closing them. If you unhide the tab, the tab would need to reload, just like
> reopening the tab would.

Just a nit, but closed != discarded; they each have very different implications as far as SessionStore and restore goes.

But I suspect you are just referring to the performance implications of this.
Hi. I've been following this discussion as a former user of the tab groups addon and a current user of @kesselborn's addon. However, I agree with @mixedpuppy that this API should not be specific to tab groups. At the same time, we should acknowledge that tab groups was a highly valuable extension; while we should not strive to re-create the exact implementation of tab groups, we should make sure that value is not lost.

In my opinion[1], the fundamental value of tab groups is the ability to get some tabs out of your way without [c]losing them.  If this API does not allow hiding tabs without unloading them, that value is lost. I believe this is what others were (ineffectively) trying to communicate with "this is useless" statements; I hope the this (and the linked analysis) are more convincing.

As long as unloading is not required, the presence of the option is irrelevant to this fundamental value. So, for maximum flexibility (unix philosophy and whatnot), I would suggest omitting unloading from this API entirely (even if the initial implementation is forced to break the spec and unload). If other add-ons which hide tabs prefer to unload them, too, they can use the API for loading/unloading tabs.

I have an idea I think can satisfy all parties, when it is fully fleshed out. However, I don't have the time to think through all the edge cases properly, so I'm sharing in the hope that it is a useful starting point for further discussion/iteration.

---

Whenever *any* tab is hidden, automatically create a "pseudo-tab". A pseudo-tab resembles a pinned tab whose favicon is the icon of the extension which has hidden the tab. Its title (displayed on hover) is [some variation of] "<number> tabs hidden by <extension>". Its contents are a list of tabs that have been hidden by that extension (think: Edge's shelved tabs, but in a tab instead of a sidebar).

- If a hidden tab is playing audio, the pseudo-tab which contains it has an audio indicator, which can be clicked to mute *all* of that extension's hidden tabs.
- If a hidden tab is flashing because it has an update, the pseudo-tab flashes, too.
- If a hidden tab performs an action that would normally grab focus, either directly or by spawning a pop-up window, etc, the pseudo-tab flashes *and* the extension receives an event, which it may handle as it sees fit.
    - Optionally, we could force the tab that wants focus to be shown and focused after the extension handles the event. I am not sure this is a good idea; it seems like the kind of thing that extensions would start doing hack-y things to circumvent. As long as the user wants this behavior and has an easy way to opt out (disable the extension), I think it's best to allow this.

- When an extension is disabled/uninstalled, any tabs hidden by it are shown.
- The top item of the pseudo-tab's right click menu opens the details page for the addon, where it can be disabled.
    - Alternatively, the top item could simply disable the addon directly.
- Hidden tabs remain visible to other extensions. Imagine if ublock didn't work in hidden tabs..
- When one extension shows/hides a tab, other (subscribed) extensions receive an event.
    - To prevent infinite loops, once a tab is hidden, it may not be shown by any other extension.
- I have not worked through the details of how error handling should work. If it's a bulk call, and some of the tabs were hidden by a different extension, does the operation succeed on the remaining tabs or fail for all of them?
- I have not worked through the details for how simultaneous calls from different extensions should work -- await completion or fail immediately? (run concurrently seems like a bad idea.)

Possible variation: have only one pseudo-tab, like Edge's shelved tabs, and group hidden tabs by extension within it.
- Pro: Minimal UI allow gives extensions more flexibility to define their own interface in a non-redundant way.
- Con: If each extension has its own pseudo-tab, it can receive an event on click, so it can show its UI, restore tabs, etc.

---

Thank you @mixedpuppy for writing the wiki page; It really helps to clarify this discussion, since we can evaluate ideas based on the considerations listed there:

> > Extensions changing large parts of the interface should be done when it’s clear it’s caused by an extension. Examples are: on install, blocking on user input.

It's always clear whether there are hidden tabs and, if so, why they are hidden.

> > Extensions should clean up after themselves when uninstalled.

Yes!

> > Users should have notification of what an extension does, especially to the Firefox UI.

There's now a visual representation of hidden tabs.

> > It shouldn’t be dependent upon add-on reviewers to enforce security UI requirements. 

> A tab running without the user’s knowledge presents many risks 

Since there is now a UI element that represents hidden tabs, it should not be possible to open a tab without the user's knowledge. The bigger a concern this is, the more prominent the "new hidden tab" cue should be.

> > A tab could be using something annoying or invasive 

These behaviors can now be controlled as well as they can for a pinned tab. I think that's an acceptable standard.

> What do we do when the last shown tab is hidden or closed?

Just show the pseudo-tab :)


[1]: https://github.com/kesselborn/conex/issues/24#issuecomment-335065115
(In reply to Shane Caraveo (:mixedpuppy) from comment #73)
 
> … discard … From what I see, that method returns the tab to a 
> lazy state.

In relatively simple terms, please (I'm not a developer): 

1) what are the primary benefits of transitioning to that lazy state; 

2) how is laziness distinct from suspension; and 

3) might the lazy state reduce the performance of – or make impossible – any type of end user action/expectation that is familiar to (say) the Tab Groups extension?

This, in particular, catches my eye: 

(The 8472 from comment #28)

> … switch groups frequently and have interactive websites … desktop
> notifications … Discarding them just because I switch groups 
> would be unwelcome due to loss of background updates. …


Background reading (partly for newcomers)
-----------------------------------------

From <https://bugzilla.mozilla.org/show_bug.cgi?id=1322485#c16> (2017-09-22) under 
1322485 - Implement tabs.discard method for Desktop: 

> … "discard" in Firefox refers to de-lazifying …

The New Firefox and Ridiculous Numbers of Tabs – Dietrich Ayala
<https://metafluff.com/2017/07/21/i-am-a-tab-hoarder/>

– whilst there's no mention of lazy or virtual in that post, this Mozilla bug was related: 

906076 - (lazytabs) Virtual tabs - lazily create linkedBrowser and other dependent elements for tabbrowser tabs to improve startup performance
<https://bugzilla.mozilla.org/show_bug.cgi?id=906076>

My understanding of virtual tabs in the context of Firefox is quite limited, based on the application startup performance benefits that _were_ remarkable with 55.0 (compared to 54.x), when I had around five hundred tabs. More recently I have more than a thousand, and whilst I do make fairly aggressive use of Auto Unload Tab <https://addons.mozilla.org/addon/auto-unload-tab/> I do not have a clear sense of whether _unloading_ (with Firefox 56) impacts negatively on the ability to receive desktop notifications, and so on. Difficult to gain that sense maybe because (like The 8472 and other users) I'm a _frequent_ switcher; there's the possibility/likelihood that my switching habits naturally cause unloaded tabs to load before any 'gaps in notification' might become remarkable. 

I can, at least, report that the ability of Conex to seek and find seems to be not prevented where vast majority of tabs are – I assume – either virtual (lazy), or unloaded, in 56.x. Here, for example, scores of groups and one container: 

Seeking grouped tabs in Firefox 56: with Tab Groups, with Mozilla's address bar, and with Conex - YouTube
<https://www.youtube.com/watch?v=fDbLhJJGRQU>

– that seventy-second screen recording is an extreme/edge use case; other cases will be less extreme but have equal or greater emphasis on the wish/requirement for e.g. uninterrupted desktop notifications. 

(I'm aware of the possibility of things straying off-topic, I should encourage spin-off discussions in Mozilla Discourse <https://discourse.mozilla.org/>.) 

----

PS BugZilla reports a mid-air collision with SIXTEEN comments. So, I'm sorry if there's some overlap, but <cough>bug 706970</cough>.
ok ... this is kind of escalating ... just a few additions and then I will try to shut up ;)

@kevin: I think we don't know what the general use case is nor should we try to guess what it is -- I am just saying that there is a use case for not discarding, not that this is the main use case.

From the perspective of the Firefox code base, I would try to develop the api with the following use case:

- do one job and do it well / separation of concerns: unless it's technologically _absolutely_ necessary, I would limit hiding tabs to hiding tabs and not intermix it with discarding

- keep the code base as simple and minimal as possible: keeping any form of state potentially introduces a lot of complexity which makes it hard to initially get the api right and (that's the bigger problem) maintain it over time. Unless it makes the browsers unstable, fire events instead and let extension developers handle the problem

- related to the last point: push every problem that is not the core of the api to the extension developers and let them deal with the problem. Not meant in a mean way, but as we can see from the current discussion it's kind of impossible to get it right for every user if the api does not stay to it's core. Furthermore: the Firefox code base is so huge and complex that everything that does not need to go into this code base should better not go into it. 

An example for my last point: if there is a hidden tab that is playing audio, let extensions handle the problem: the tabs.Tab object contains a property called audible, so extensions can find out if there is a tab that produces sound. So basically the "a hidden tab is producing audio" is in my opinion a non-issue. If somebody opens an issue in Firefox, close the bug and say that it's an extension problem.
Another anecdote:

Discarding tabs immediately after switching to a new group will quickly get annoying for my use case, as I tend to have a primary tab group and a few other groups which I only use for short periods of time. If I switch to one of the "other" groups, I tend to switch back to the primary group a couple of minutes later. Only one of my groups acts like "more convenient bookmarks", as described by comment #91.

Also, there is always https://addons.mozilla.org/en-GB/firefox/addon/tab-suspender-tab-unloader/ which suspends tabs which have not been used in a while. This can be used to solve the "conserve resources" use case (also described in comment #91).

What I'm saying is, that I personally use tab groups similarly to how one might use separate windows. The advantage is that I can always see my pinned tabs in any of the tab groups, which is not possible if I use multiple windows. Slow group switching will make this much less useful, although I agree that it is certainly better than nothing.
(In reply to kesselborn from comment #95)
> @kevin: I think we don't know what the general use case is nor should we try
> to guess what it is --

Yes, that was my point exactly.

> I am just saying that there is a use case for not
> discarding, not that this is the main use case.

Statements like "this is useless" imply that it is the only use case, and that is what I was addressing.

I was also addressing that there is so much (somewhat passionate) discussion here trying to convince that hiding tabs without discarding them is a needed functionality.  No one is discarding (NPI) this request and saying the API will only be one way or the other.  IIUC a path is being chosen which will at least allow an implementation of hiding tabs (as this bug is about hiding tabs, not tab groups) without a long wait for some who can use it.  The need for hiding without discarding is not being ignored, it is just that much more work is required to handle this properly, and this will come as resources allow.  Shane, correct me if I am wrong on that.

So please, I don't think we need to hear any more arguments for hiding tabs without discarding.  We are convinced already that there is a need.
(In reply to kesselborn from comment #95)
> ok ... this is kind of escalating ... just a few additions and then I will
> try to shut up ;)
> 
> @kevin: I think we don't know what the general use case is nor should we try
> to guess what it is -- I am just saying that there is a use case for not
> discarding, not that this is the main use case.
> 
> From the perspective of the Firefox code base, I would try to develop the
> api with the following use case:
> 
> - do one job and do it well / separation of concerns: unless it's
> technologically _absolutely_ necessary, I would limit hiding tabs to hiding
> tabs and not intermix it with discarding
> 
> - keep the code base as simple and minimal as possible: keeping any form of
> state potentially introduces a lot of complexity which makes it hard to
> initially get the api right and (that's the bigger problem) maintain it over
> time. Unless it makes the browsers unstable, fire events instead and let
> extension developers handle the problem
> 
> - related to the last point: push every problem that is not the core of the
> api to the extension developers and let them deal with the problem. Not
> meant in a mean way, but as we can see from the current discussion it's kind
> of impossible to get it right for every user if the api does not stay to
> it's core. Furthermore: the Firefox code base is so huge and complex that
> everything that does not need to go into this code base should better not go
> into it. 
> 
> An example for my last point: if there is a hidden tab that is playing
> audio, let extensions handle the problem: the tabs.Tab object contains a
> property called audible, so extensions can find out if there is a tab that
> produces sound. So basically the "a hidden tab is producing audio" is in my
> opinion a non-issue. If somebody opens an issue in Firefox, close the bug
> and say that it's an extension problem.

Conceptually, I tend to agree with you, keep it simple and let addons decide what to do.  That was a suggestion I made in comment 43 before I was aware of the security issues.

However the Mozilla team has been shifting into a new philosophy of browser security (enter WebExtensions) and will tend to keep APIs tighter in that regard in order to maintain control over security, rather than just leaving things up to addon devs, as in the "Old West" days.

I am just offering this as point of understanding, and please don't take this as an invitation to digress into a debate regarding Mozilla's philosophies :-).
Noted with thanks: 

https://wiki.mozilla.org/WebExtensions/TabHiding

Mozilla bug 1408053 - Show that tabs are hidden and all the implications
<https://bugzilla.mozilla.org/show_bug.cgi?id=1408053>

----

Two thoughts.

1) Multiple windows

Move groups between windows · Issue #5 · denschub/firefox-tabgroups
<https://github.com/denschub/firefox-tabgroups/issues/5>

2) Firefox containers

An existing use case: 

- multiple pages of any one _container_ span (a) two or more _groups_; (b) two or more _windows_.


A week or so ago I had some concerns about how things might pan out re: hiding and showing. 

Now (if I understand correctly) these two points have the potential to end those concerns: 

(In reply to Shane Caraveo (:mixedpuppy) from comment #76)

> …
> - only one extension "owns" a hidden tab. …
> - any extension may show any hidden tab …
> …


Safe mode
=========

(In reply to Shane Caraveo (:mixedpuppy) from comment #76)

> … When an extension is disabled/uninstalled, any hidden tabs it "owns" 
> will be shown. …

So: a start of Firefox in safe mode will cause all tabs to be shown, yes? 

If so, the show-all will be a welcome change from safe mode behaviour with 56.0.1. 


Thanks again
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

@jaws can you do an additional review on the tabbrowser changes?
Attachment #8920429 - Flags: review?(jaws)
Sorry I can't comment on the code and I admit that I don't understand everything 100% and please feel free to just ignore this.
I just had one question regarding the situation when all tabs are shown when an extension with hiding permissions gets uninstalled:

Will there be an event get fired so that every extensions that can hide tabs knows, that it'll potentially have to re-hide some tabs which got shown now?
Can't see it in the code, don't know if this is too early to ask or if it is somewhere else -- please feel free to just ignore this comment
(In reply to kesselborn from comment #103)

> Will there be an event get fired so that every extensions that can hide tabs
> knows, that it'll potentially have to re-hide some tabs which got shown now?

You get notifications via tabs.onUpdated.
This bug has gotten way too long for me to try to make sense of, so can someone please explain to me why we're going down this road again?

We discussed this at length in several advisory group meetings and I distinctly recall coming to the conclusion that we didn't want to do this. We already ran this experiment with Panorama, and the result was a disaster. It caused no end of problems to have hidden tabs with grouping logic that the browser code didn't know about. Dozens of extensions tried to reach into the Panorama UI code to get access to its grouping logic, which wasn't available via sane API. Selecting hidden tabs had strange results, especially while the Panorama UI hadn't yet loaded. There were performance issues, lag, data loss issues. It wasn't extensible, and led to conflicts, hacks, and compatibility issues.

There might be some argument for doing this if we hadn't already tried it and learned that it was a bad idea. I'm not sure what the argument is for doing it now.
> I'm not sure what the argument is for doing it now

Same as always: users want this functionality. You don't just get to decide what to implement or not based on how easy it is, or we wouldn't have modern web browsers.

> Selecting hidden tabs had strange results, especially while the Panorama UI hadn't yet loaded.

That's why people are discussing the API and its details.

> It wasn't extensible, and led to conflicts, hacks, and compatibility issues.

I seriously doubt implementing this feature in the WebExtensions API in a reliable way is anywhere near the complexity of many other parts of Firefox.

> There were performance issues, lag, data loss issues.

From poorly written Panorama code?

> Dozens of extensions tried to reach into the Panorama UI code to get access to its grouping logic, which wasn't available via sane API

Irrelevant.
(In reply to Dmitry Gutov from comment #106)
> > I'm not sure what the argument is for doing it now
> 
> Same as always: users want this functionality. You don't just get to decide
> what to implement or not based on how easy it is, or we wouldn't have modern
> web browsers.

Actually, to a large extent I do. But that's beside the point.

> > There were performance issues, lag, data loss issues.
> 
> From poorly written Panorama code?

Partly. But mostly from the fact that the tab grouping logic was completely separate from the core browser code that handled tabs, which led to no end of problems. That is a mistake that I don't want to make again.

> > Dozens of extensions tried to reach into the Panorama UI code to get access to its grouping logic, which wasn't available via sane API
> 
> Irrelevant.

Not even remotely irrelevant.
> tab grouping logic was completely separate from the core browser code that handled tabs, which led to no end of problems

Now you will have a smaller, clearer abstraction that the rest of the browser code can access and take into account.

> Not even remotely irrelevant.

First, extensions building upon extensions is a very secondary use case. As one example, I'm among many users of Panorama and TabGroups, and I'm only vaguely aware of one extension that tried to build upon either (Tab Mix Plus, right?).

And as far as the browser code is concerned, why do you need to know the grouping logic? Why not make do with just the information of which tabs are displayed at a given moment? Add some callbacks, if necessary.
I think there is a slight misunderstanding here. This bug is not about fully recreating the Panorama feature/functionalities.
The scope of this bug is merely providing an API to hide specific tabs in the tab bar.
As such there shouldn't be any problems with performance, lag, data loss or weird decoupled UI and logic.

Anyway it is all readily explained and summarized in the link provided at the top:

https://wiki.mozilla.org/WebExtensions/TabHiding
There's no misunderstanding. This is the same mechanism which was used to implement Panorama, and which caused so much trouble. And since the main use case presented for it so far has been implementing tab grouping, the situation is very much the same.
Back when Panorama was removed, the crux of the justification was about code rot and not enough people working on it. There was no claim it couldn't be made to work well at all.

With a limited API, there's only so much code the Firefox developers have to keep up and pay attention to.
Panorama was developed as an addon and his implementation was... Sadly such a solution was preferred instead to provide a solid simple API to hide/unhide tabs. Instead this, all addons which tried to implement their own way for Tabgrouping had to deal with the builtin panorama code as small additional task with all consequences. It's time that a API for tab hiding will be finally available. By the way things like tabs discarding if required should be optionally to have possibilities for every one.
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

https://reviewboard.mozilla.org/r/191402/#review199648

::: browser/base/content/tabbrowser.xml:3904
(Diff revision 4)
>            if (!aTab.hidden && !aTab.pinned && !aTab.selected &&
> -              !aTab.closing) {
> +              !aTab.closing && this.canHideTab(aTab)) {

Wouldn't it make sense to include these other preconditions in the canHideTab() function?
Attachment #8920429 - Flags: review?(jaws)
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

Redirecting review to Dao
Attachment #8920429 - Flags: review?(dao+bmo)
Any reasonable chance of having this falling in firefox 58?
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

https://reviewboard.mozilla.org/r/191402/#review200928

It seems like there's no consensus that we should actually do this. Can this be resolved first?

::: browser/base/content/tabbrowser.xml:2496
(Diff revision 4)
> +            "use strict";
> +            // TODO Bug 1384515 followup.  This is very similar to discardBrowser
> +            // logic except that if the browser is already discarded
> +            // (!browser.connected) we allow hiding the tab.
> +            let browser = aTab.linkedBrowser;
> +            return aTab && browser && !aTab.selected && !aTab.closing &&

You can drop aTab here. aTab.linkedBrowser will throw if aTab is null.

::: browser/base/content/tabbrowser.xml:2498
(Diff revision 4)
> +            // logic except that if the browser is already discarded
> +            // (!browser.connected) we allow hiding the tab.
> +            let browser = aTab.linkedBrowser;
> +            return aTab && browser && !aTab.selected && !aTab.closing &&
> +                    !this._windowIsClosing && browser.isRemoteBrowser &&
> +                    !(browser.frameLoader && browser.frameLoader.tabParent.hasBeforeUnload) &&

Why are you checking hasBeforeUnload here?

::: browser/base/content/tabbrowser.xml:3901
(Diff revision 4)
>          </body>
>        </method>
>  
>        <method name="hideTab">
>          <parameter name="aTab"/>
> +        <parameter name="aDiscard"/>

I'd rather not add this parameter. Seems ext-tabs.js should just call discardBrowser when it wants that.
Attachment #8920429 - Flags: review?(dao+bmo) → review-
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

https://reviewboard.mozilla.org/r/191402/#review200928

> Why are you checking hasBeforeUnload here?

That is already part of the discardBrowser checks.  I think I had intended discardBrowser and hideTab to both use a consistent check here.  In any case, right now, the plan is to not hide a tab that cannot be discarded.
(In reply to Shane Caraveo (:mixedpuppy) from comment #117)
> Comment on attachment 8920429 [details]
> Bug 1384515 add show/hide tabs api,
> 
> https://reviewboard.mozilla.org/r/191402/#review200928
> 
> > Why are you checking hasBeforeUnload here?
> 
> That is already part of the discardBrowser checks.  I think I had intended
> discardBrowser and hideTab to both use a consistent check here.  In any
> case, right now, the plan is to not hide a tab that cannot be discarded.

That doesn't really make sense though. Not discarding a tab is okay because the feature is fairly transparent to the user. Not hiding a tab that the user asked to hide is rather inconsistent and seems broken.
Comment on attachment 8920429 [details]
Bug 1384515 add show/hide tabs api,

https://reviewboard.mozilla.org/r/191402/#review203814

clearing r? until we figure out plans here
Attachment #8920429 - Flags: review?(aswan)
Hi guys,

First of all thanks for your work and priority. I'm a power user no developer but maybe i can offer a new idea.

I understand mixedpuppy after the troubles with Panorama Code and the security issues provided by hidden tabs.

The main problem is: the power user (which handle a huge amount of tabs at the same time) need a solution to handle this amount of tabs. I think this is the "main goal" of Tab Hiding API... (or? its my problem)

I read some really terrible things like its not possible to hide not-discardable or pinned tabs or auto discard hidden tabs.. PLEASE stop this.

IMO you could fix this security issues with not allowing to hide single tabs, why dont provide an API to hide full containers? 

Its already possible to see the existing containers and manage them in FF options. You could make a small change in the "Options" layout and add a tab counter (ex: "5 Tabs") after the container name. With this change the user always see whats running in the "background" and can easily close/delete it with removing the container. (I miss an undeleteable "Standard" container)

(Security improvements:
Only "Standard" container after install, the user realize containers he dont know.
Feature Request "allowed to hide tabs and containers !" (! security warning on mouseover)
Menu bar > View > Tab bar >
Hide tab bar true/false
Show hidden tabs true/false)

Malicious code is not able to (re)start single hidden tabs (every time). Its only possible to create new containers and track new/other (mostly unused) containers. An extra feature to disable containers (to improve security) would be an idea. This solution would fix the problems with discard check, pinned tabs, security issues with single hidden tabs and every "tab group user" will be happy.

"A tab could be using something annoying or invasive        Audio        WebRTC" - Maybe a request like "IF container1 is hidden then forbid Audio/WebRTC" could fix this same with focus requests?

There is only one topic left "auto discard hidden tabs" - security = yes / usability = omfg no (I hope there will be a way to prevent auto discard..) 

An API to change Container1.hidden true/false would be enough. 

Yes this is a new direction and single hidden tabs will improve usability (and assist more different addons) but for a very high price. Single hidden tabs are a heavy security issue for common users and most of us know this so we need to find a way between security(no such feature) and usability (single hidden tabs). Maybe we forget single hidden tabs and implement "hide tabs of containerX" and find a solution to deny "auto discard hidden tabs".

Think about and please dont kill me..^^ We need Tab Groups asap.
I believe one of the (internal) reasons that in previous years Firefox lost many users is that they forgot about power users. While Firefox was focusing on features for common users, like Firefox Hello, Chrome put all its power on its devtools, V8 and its ability to be embedded (like in electron). Not saying that this was the only reason, but one major reason. I think one tweet from a power user saying "Firefox is cool" has much more effect than 1000 from common users that nobody sees them as professionals.

I believe this is one of the features for power users that makes a lot of difference and I think it worth it if a group of people from Firefox core devs (engine stuff) and Firefox add-ons, would make a task force to implement what's needed for this feature to land, while it would also be manageable for add-on team with little effort.
(In reply to Dão Gottwald [::dao] from comment #116)

> It seems like there's no consensus that we should actually do this. Can this
> be resolved first?

Shouldn't we take the fact that the tab hiding has been mentioned on the Mozilla Blog (https://blog.mozilla.org/addons/2017/11/03/keeping-tabs-tab-api/comment-page-1/) as an indicator of the intended direction?
(In reply to Tim Nguyen :ntim from comment #77)
> Without an option to hide tabs without discarding, the behaviour of Tab
> Groups can not be properly replicated here.
> 
> Tab Groups doesn't discard tabs when switching groups.

I use Tab Groups now and the fact that it doesn't actually suspend/freeze/hibernate tabs that are not in the current group I'm viewing is a misfeature if you ask me. I'd prefer that only the tabs in the "Active" group be "alive". If the API did not support non-suspended hidden tabs for now, I would consider that an improvement. Later the other option could be added and the extension could use it optionally (preferably by group or even individual tabs).
(In reply to gerald.edward.butler from comment #123)
> (In reply to Tim Nguyen :ntim from comment #77)
> > Without an option to hide tabs without discarding, the behavior of Tab
> > Groups can not be properly replicated here.
> > 
> > Tab Groups doesn't discard tabs when switching groups.
> 
> I use Tab Groups now and the fact that it doesn't actually
> suspend/freeze/hibernate tabs that are not in the current group I'm viewing
> is a misfeature if you ask me. I'd prefer that only the tabs in the "Active"
> group be "alive". If the API did not support non-suspended hidden tabs for
> now, I would consider that an improvement. Later the other option could be
> added and the extension could use it optionally (preferably by group or even
> individual tabs).

Replying to myself:

To further clarify: In MOST cases, I would prefer background groups' tabs to all Suspend/Sleep/Hibernate/Disable (whatever is the correct terminology). What I mean by this is that they would use no resources, trigger no events, play no media, run no javascript or js timers in the background, invoke no background network traffic. To me, that should be the default.

If (at some point) a facility can be added so that an extension can simply "Hide" a tab or tabs without suspending them, I would prefer that require a special permission be granted to the extension and that the extension provide a per group and/or per tab control on such "hidden, but, not suspended" tabs.
(In reply to Stephen Michel from comment #93)
> Hi. I've been following this discussion as a former user of the tab groups
> addon and a current user of @kesselborn's addon. However, I agree with
> @mixedpuppy that this API should not be specific to tab groups. At the same
> time, we should acknowledge that tab groups was a highly valuable extension;
> while we should not strive to re-create the exact implementation of tab
> groups, we should make sure that value is not lost.
> 
> In my opinion[1], the fundamental value of tab groups is the ability to get
> some tabs out of your way without [c]losing them.  If this API does not
> allow hiding tabs without unloading them, that value is lost. I believe this
> is what others were (ineffectively) trying to communicate with "this is
> useless" statements; I hope the this (and the linked analysis) are more
> convincing.
> 
> As long as unloading is not required, the presence of the option is
> irrelevant to this fundamental value. So, for maximum flexibility (unix
> philosophy and whatnot), I would suggest omitting unloading from this API
> entirely (even if the initial implementation is forced to break the spec and
> unload). If other add-ons which hide tabs prefer to unload them, too, they
> can use the API for loading/unloading tabs.
> 
> I have an idea I think can satisfy all parties, when it is fully fleshed
> out. However, I don't have the time to think through all the edge cases
> properly, so I'm sharing in the hope that it is a useful starting point for
> further discussion/iteration.
> 
> ---
> 
> Whenever *any* tab is hidden, automatically create a "pseudo-tab". A
> pseudo-tab resembles a pinned tab whose favicon is the icon of the extension
> which has hidden the tab. Its title (displayed on hover) is [some variation
> of] "<number> tabs hidden by <extension>". Its contents are a list of tabs
> that have been hidden by that extension (think: Edge's shelved tabs, but in
> a tab instead of a sidebar).
> 
> - If a hidden tab is playing audio, the pseudo-tab which contains it has an
> audio indicator, which can be clicked to mute *all* of that extension's
> hidden tabs.
> - If a hidden tab is flashing because it has an update, the pseudo-tab
> flashes, too.
> - If a hidden tab performs an action that would normally grab focus, either
> directly or by spawning a pop-up window, etc, the pseudo-tab flashes *and*
> the extension receives an event, which it may handle as it sees fit.
>     - Optionally, we could force the tab that wants focus to be shown and
> focused after the extension handles the event. I am not sure this is a good
> idea; it seems like the kind of thing that extensions would start doing
> hack-y things to circumvent. As long as the user wants this behavior and has
> an easy way to opt out (disable the extension), I think it's best to allow
> this.
> 
> - When an extension is disabled/uninstalled, any tabs hidden by it are shown.
> - The top item of the pseudo-tab's right click menu opens the details page
> for the addon, where it can be disabled.
>     - Alternatively, the top item could simply disable the addon directly.
> - Hidden tabs remain visible to other extensions. Imagine if ublock didn't
> work in hidden tabs..
> - When one extension shows/hides a tab, other (subscribed) extensions
> receive an event.
>     - To prevent infinite loops, once a tab is hidden, it may not be shown
> by any other extension.
> - I have not worked through the details of how error handling should work.
> If it's a bulk call, and some of the tabs were hidden by a different
> extension, does the operation succeed on the remaining tabs or fail for all
> of them?
> - I have not worked through the details for how simultaneous calls from
> different extensions should work -- await completion or fail immediately?
> (run concurrently seems like a bad idea.)
> 
> Possible variation: have only one pseudo-tab, like Edge's shelved tabs, and
> group hidden tabs by extension within it.
> - Pro: Minimal UI allow gives extensions more flexibility to define their
> own interface in a non-redundant way.
> - Con: If each extension has its own pseudo-tab, it can receive an event on
> click, so it can show its UI, restore tabs, etc.
> 
> ---
> 
> Thank you @mixedpuppy for writing the wiki page; It really helps to clarify
> this discussion, since we can evaluate ideas based on the considerations
> listed there:
> 
> > > Extensions changing large parts of the interface should be done when it’s clear it’s caused by an extension. Examples are: on install, blocking on user input.
> 
> It's always clear whether there are hidden tabs and, if so, why they are
> hidden.
> 
> > > Extensions should clean up after themselves when uninstalled.
> 
> Yes!
> 
> > > Users should have notification of what an extension does, especially to the Firefox UI.
> 
> There's now a visual representation of hidden tabs.
> 
> > > It shouldn’t be dependent upon add-on reviewers to enforce security UI requirements. 
> 
> > A tab running without the user’s knowledge presents many risks 
> 
> Since there is now a UI element that represents hidden tabs, it should not
> be possible to open a tab without the user's knowledge. The bigger a concern
> this is, the more prominent the "new hidden tab" cue should be.
> 
> > > A tab could be using something annoying or invasive 
> 
> These behaviors can now be controlled as well as they can for a pinned tab.
> I think that's an acceptable standard.
> 
> > What do we do when the last shown tab is hidden or closed?
> 
> Just show the pseudo-tab :)
> 
> 
> [1]: https://github.com/kesselborn/conex/issues/24#issuecomment-335065115

These seem like really solid and useful suggestions.
Just a little question : instead of developping an API to handle tabs visibility, would it change anything to think about windows ? You can already open multiple windows, each with its own tabs : an extension could display only one window but in the background switch between multiple ones ?
@pierre nope, not feasible: I created a working version with this strategy for conex (a web-extension) ... I don't exactly remember all problems anymore, but the main blocker was the performance.
Hi every body,

Exceptionally, I speak about my extension as all the requested features here turn mostly around Tab Groups extension.
See the second part for ideas for the requested features.

I am developing a new extension Sync Tab Groups(https://addons.mozilla.org/en-US/firefox/addon/sync-tab-groups/) that tries to reproduce the behavior of Tab Groups over the new API. 
Except that, I am not hiding/showing tabs but opening/closing them.

I also prefer, like gerald.edward.butler, to close tabs rather than let them open. I struggled a lot with memory with previous Firefox version. Even, if the 57 version is definitely better, I still prefer to minimize memory usage.

On top of the previous extension behavior, I added:
 - Works in all windows open in the current session
 - Do a back up of the groups in the bookmarks

However, I lost some features as well:
 - The session history. As a tab is open/close, you lose all the history. (this is the most annoying)
 - Speed when switching groups (however, you can work in multiple windows to avoid it)
 - Privileged URLs are lost (about:...) as I can't open them again from the API
 - Work only from version 57 as I am using session window value for finding window again if you restore them

I would appreciate if you can try it and make a review. 

----- 

Although I am not sure I still need hiding/showing tabs (I haven't tried my extension enough, I just finished last weekend), I got some ideas for the hidden feature:
 - Ask specific permission to the user when hidden feature is used in extension
 - Put all hidden tabs in one hidden container (more or less like a window): hidden tabs are not every where
   - The hidden container is unique and created by Firefox core 
   - API example to hide: tabs.move function with parameter windows.WINDOW_HIDDEN
   - API example to show: tabs.move function with parameter an open window id
 - A default Firefox UI to interact (see, close, show...) all hidden tabs: the users have still control over hidden tabs
(In reply to gerald.edward.butler from comment #124)
> (In reply to gerald.edward.butler from comment #123)
> > (In reply to Tim Nguyen :ntim from comment #77)
> > > Without an option to hide tabs without discarding, the behavior of Tab
> > > Groups can not be properly replicated here.
> > > 
> > > Tab Groups doesn't discard tabs when switching groups.
> > 
> > I use Tab Groups now and the fact that it doesn't actually
> > suspend/freeze/hibernate tabs that are not in the current group I'm viewing
> > is a misfeature if you ask me. I'd prefer that only the tabs in the "Active"
> > group be "alive". If the API did not support non-suspended hidden tabs for
> > now, I would consider that an improvement. Later the other option could be
> > added and the extension could use it optionally (preferably by group or even
> > individual tabs).
> 
> Replying to myself:
> 
> To further clarify: In MOST cases, I would prefer background groups' tabs to
> all Suspend/Sleep/Hibernate/Disable (whatever is the correct terminology).
> What I mean by this is that they would use no resources, trigger no events,
> play no media, run no javascript or js timers in the background, invoke no
> background network traffic. To me, that should be the default.
> 
> If (at some point) a facility can be added so that an extension can simply
> "Hide" a tab or tabs without suspending them, I would prefer that require a
> special permission be granted to the extension and that the extension
> provide a per group and/or per tab control on such "hidden, but, not
> suspended" tabs.

Again replying to myself by way of refining and clarifying the use-cases (for me at least) around "Tab Groups/Tab Hiding/Tab Sleeping" etc:

After some additional thought and introspection about what I currently like/don't like about "Tab Groups/Panorama" I'd like to add the following:

   * Having the "Panorama" overview where you can drag/drop tabs from one group to another is not all that useful. It "looks" cool and provides a certain amount of "Spatial" orientation in keeping your tabs organized, but, beyond about 12 groups breaks down as being useful (NOTE: I currently have about 50 groups going at any one time). The ability to right-click on a tab and say, "Move to Group ????" is much more useful. Also, the drop-down menu with all the groups is useful to switching between groups.
   * I said earlier that having all backgrounded groups' tabs Slept/Hibernated/Closed is preferred as I would prefer only tabs in the foreground group to be consuming any resources. I'm going to have to walk that back. Actually, what I want/what is preferred is to have background groups' tabs to still be active, but, to have some notification/handling/ability to silence/control misbehaving background tabs. The sort of things that I would like to easily and clearly manage WRT background tabs are:
      - Overuse of CPU/Run-away JS
      - Overuse of Network Connections (e.g. OK to use one periodically, but, usage of more than one while in the background, or using more than one consistently is unacceptable and should be controlled)
      - Overuse of Memory (if memory of a background tab doesn't stabilize at a reasonable amount, it should be brought to the attention of the user with the option to kill/silence/etc)
      - Audio/Video playback (silenced/paused automatically, perhaps with option to allow to continue in the background)
      - Animations (Paused/Stopped)

Now looking at those requirements, it seems like the "Silence Background Tabs" stuff is orthogonal to Tab Grouping. That is, it can be handled by default behavior of FF as to any tab that is not the FG tab of a window (or by appropriate extensions as needed).

I seems like if the "Hide Tabs" API simply hid the tabs without doing anything different to what is done to a tab that simply isn't the currently displayed FG tab should be the "Right" thing. The only additional thing would be to provide a standard, discoverable, obvious UI indication that there are "Hidden" tabs and which extension "Hid" them and what the state of their BG behavior is WRT CPU, Memory, Network, Media Play-Back. That should handle any potential security/privacy issues and prevent WE from doing malicious things with hiding of tabs. The "Pseudo-Tab" idea proposed by @"Stephen Michel" in comment #93 seems to be the right sort of concept to explore.
(In reply to Morikko from comment #128)
> I also prefer, like gerald.edward.butler, to close tabs rather than let them open

That is unfortunate.

In addition to the drawbacks you listed, it's going to lose unsaved form inputs, video/audio playback progress and SPA states. Probably some authenticated sessions too. Which might be fine for tabs I haven't looked at for more than 24 hours, but not for a tab I just switched from.

> I struggled a lot with memory with previous Firefox version.

Even if open tabs become a memory hog once you visit enough of them in the current session, I'd really rather tab hiding and discarding were not tied together.

Rather, we should discard tabs which the user hasn't used for a period of time. Maybe keep the 20/30/50 most recently used ones (the extension can make this customizable), but discard the rest from time to time. Ideally, we should be able to discard without hiding, so that will apply to the old tabs in the current group, too.

I recall seeing an extension like this before, using the deprecated APIs. And if the "hide" and "discard" are orthogonal actions, it might be better to have separate extensions for tab grouping and "unused tab discarding", they shouldn't conflict. But of course, authors should be able to mix that functionality, if they so choose.

> Put all hidden tabs in one hidden container

Not sure if you mean Firefox Containers, but for the record, I'd really prefer if the word "container" disappeared from this discussion. IIUC, one cannot easily move tabs between containers, and that makes some important things difficult. If people want to "hide all other containers", they should be able to do it (write an extension, etc), but tying tab hiding to containers in any fashion would be unwise.

>  - A default Firefox UI to interact (see, close, show...) all hidden tabs: the users have still control over hidden tabs

Maybe some "developer tools" style panel? Or an "about:hidden-tabs" internal page.
(In reply to Morikko from comment #128)
> I also prefer, like gerald.edward.butler, to close tabs rather than let them
> open. I struggled a lot with memory with previous Firefox version. Even, if
> the 57 version is definitely better, I still prefer to minimize memory usage.

With the landing of bug 906076 and the lazy-tabs API, discarding tabs has very near the memory conservation as closing tabs.

Discarding tabs in Firefox can't really be compared to discarding tabs in Chrome (AFAIK), nor the old methods various addons used of "unloading" tabs, as far as memory conservation is concerned.

There really isn't any realistic justification for closing tabs and all the consequences involved.
In addition to what Kevin said, I think that's a very trivial detail completely up to whatever an add-on developer wants and think (not dissimilar from a lot of other dilemmas in the thread)

Now, please, for the love of god, let this CLEAN for developer to focus on reviewing actual code (not the general idea, just about anything would be acceptable to start by now)
DEXTER, mind you tone and read https://bugzilla.mozilla.org/page.cgi?id=etiquette.html .
Everyone is working as hard as they can here to provide a sustainable solution for users. 
You can still use Tabgroups with the latest ESR version and upgrade to release when this bug lands.
I want to say that I absolutely agree that tab hiding has nothing to do with discarding/media playback/etc. It is just GUI option for tab bar to show subset of all tabs, to make it useful in case of many (like 20+) tabs. Current behavior doesn't provide you opportunity to find a tab that you want in such case - the only chance is using some vertical tab sidebar solution (Tree Style Tab, Tab Center Redux etc). But such solutions make tab bar absolutely unnecessary (then why even show it?) and have a principal flaw - they either take too much horizontal space or don't provide a fast way to switch tabs because they need to be 1. opened 2. searched through 3. clicked 4. closed. Tab bar with few tabs is much better - it doesn't take too much space and it always on display which gives fast way to switch tab - you don't open/close sidebar, and because you don't open/close you usually don't need to search through tab bar for the wanted tab. That's why we need such hiding API.

About security, media etc. questions I agree with people who suggest standard easy-accessible place for hidden tabs. You can just put `...` button on tab bar (like `+` for new tab) which pops a vertical list of all hidden tabs when clicked. Also you can show media sign or notification sign on it if any of hidden tabs do the media or has a notification. You can place a counter of hidden tabs on this button and make some visible color animation when it changes - to ensure that nothing opens/closes tabs unnoticeably from user. You can even call this not `Hidden tabs` but `Other tabs` if you are so afraid of hiding concept. I don't think that such solution is dangerous or too hard to implement, but this will already enable creating of tabgroups-like extensions. This approach actually may be good for new Firefox containers too as an option: "In tab bar show tabs only from current container" (and hide other tabs in "Other tabs" list).
At this point we are running over 135 comments on the bug and the ability to focus on the code is actually being impaired. Thank you for the input so far, but so we can work on this feature without being overrun by comments we are closing comments on this bug. 

The plan for tabs is documented here https://wiki.mozilla.org/WebExtensions/TabHiding and as we figure out more stuff, we'll update the wiki.
Restrict Comments: true
Restrict Comments: false
See Also: → 1423725
One of the recent decisions we made around tab hiding was that we wanted to get an API out early, and allow UI and other issues to follow up.  To do this we're placing the api behind a pref that will need manual addition by the user.  Given this direction, we're reversing the earlier decision that we must require hidden tabs to be discarded (aka suspended).  While it was always the intention that the API would, ultimately, not require this, it was a short term solution to some of the UI problems we need to address.  Using the pref is a better solution as it allows us time to address those while providing hiding without discarding sooner than later.  

A primary requirement is that users maintain visibility and control over tabs, regardless of how a tab hiding extension may work.  Our UX team will be working on UI flows for Firefox that will help in this area.  We also need to ensure that web functionality is not broken through tab hiding, and that normal web functionality within a hidden tab does not present data loss, privacy or security concerns for our users.

When the API becomes available we are hoping that extension authors, and users of tab management extensions can help us to identify any corner cases we may not have considered and to file bugs.
Hello, Fx58 was just released and it's been a couple months since the last comment on this issue.  Is any preliminary version of the API available, and what's the chance of it being available in Fx59?
(In reply to dhulme from comment #138)
> Hello, Fx58 was just released and it's been a couple months since the last
> comment on this issue.  Is any preliminary version of the API available, and
> what's the chance of it being available in Fx59?

dhulme, see bug 1423725
Thanks, sorry for missing that link up there.  Good work!
Attachment #8920429 - Attachment is obsolete: true
I'm duping this to bug 1423725 as the base api is implemented there.  Bug 1410548 is the top level tracking bug for tab hiding.  If there is a specific item not currently in a bug linked to bug 1410548, please feel free to create a new bug and I'll triage it.
Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → DUPLICATE
Duplicate of bug: 1423725
Product: Toolkit → WebExtensions
You need to log in before you can comment on or make changes to this bug.