Skip to content

Infocatcher/Private_Tab

Repository files navigation

Works only in Gecko 20.0 and higher because used API doesn't exist in older versions!

WebExtensions and compatibility with Firefox 57+

Issue #254 + Private Tab WE repository

Known issues:

  • We just inherit private state from selected tab and tries preserve private state of dropped link-like things, this is simple to implement, but may confuse a bit…
  • If you use "New Private Tab" + "New Tab" buttons after tabs toolbar, you need to manually remove "New Private Tab" button before disabling or uninstalling Private Tab. Or you can remove "New Tab" button, press OK in Customize Toolbar dialog and then place "New Tab" directly after tabs.
  • Can't open new private tab, if installed Scriptify-based extension: please use Greasemonkey or Scriptish instead (#110).
  • In Firefox 52+ private:… URI may be opened only in new tab due to fix for bug 1318388 (#251).

Styles:

You can use .tabbrowser-tab[privateTab-isPrivate] (private tab), #main-window[privateTab-selectedTabIsPrivate] (selected tab is private) and #main-window[privateTab-isPrivate] (built-in private window) selectors in styles for userChrome.css/Stylish.
Example styles:

Options

See extensions.privateTab.* preferences in about:config page, some descriptions can be found in defaults/preferences/prefs.js.

  • extensions.privateTab.sendRefererHeader
    0 – don't send HTTP referer when URI is opened in new private tab
    1 – send only if private tab opened from another private tab
    2 – always send (as Firefox itself do for “Open Link in New Private Window”)

  • extensions.privateTab.usePrivateWindowStyle
    true – use style of private window, if current tab is private
    false – only show private state of window (regardless of current tab private state)

Keyboard shortcuts:

You can modify keyboard shortcuts through about:config page, see notes about extensions.privateTab.key.* preferences in defaults/preferences/prefs.js.

Troubleshooting:

Try new clean Firefox profile to ensure that there are no conflicts with another extensions or some specific configuration.

Debug logs:

Options in about:config:

  • extensions.privateTab.debug – enable debug logs
  • extensions.privateTab.debug.verbose – additionally enable detailed debug logs (not needed in most cases)

Then use Browser Console (formerly Error Console, Ctrl+Shift+J) to see messages like [Private Tab] ….

API for other extensions:

Events:

You can listen for following events:

event.type event.target event.detail Description
PrivateTab:PrivateChanged tab 1 – private tab
0 – not private
Changed private state of the tab
event.explicitOriginalTarget – initial tab in case of toggling using duplication (Firefox 51+, Private Tab 0.2.1.3+)
PrivateTab:OpenInNewTab tab 1 – may be opened as child tab Link was opened in new private tab
PrivateTab:OpenNewTab tab 1 – opened using middle-click
(or left-click with any modifier)
Opened new (empty) private tab
API functions:

boolean privateTab.isTabPrivate(in DOMNode tab)
void privateTab.isTabPrivateAsync(in DOMNode tab, in function callback[, in object context])
boolean privateTab.toggleTabPrivate(in DOMNode tab[, in boolean isPrivate])
DOMNode privateTab.duplicateTabAndTogglePrivate(in DOMNode tab[, in boolean isPrivate])
DOMNode privateTab.replaceTabAndTogglePrivate(in DOMNode tab[, in boolean isPrivate[, in function onSuccessCallback]])
void privateTab.readyToOpenTab(in boolean isPrivate)
void privateTab.readyToOpenTabs(in boolean isPrivate)
boolean privateTab.hasClosedTabs
void privateTab.forgetClosedTabs()
boolean privateTab.tabLabelIsEmpty(in string tabLabel[, in boolean isEmpty])

privateTab.isTabPrivate()

Investigates that the tab are private (true) or not (false), example:

// Close all (visible) private tabs:
Array.slice(gBrowser.visibleTabs || gBrowser.tabs).forEach(function(tab) {
	if(privateTab.isTabPrivate(tab))
		gBrowser.removeTab(tab);
});
privateTab.isTabPrivateAsync()

The same as privateTab.isTabPrivate, but get real state of nsILoadContext.usePrivateBrowsing in multi-process mode (Electrolysis aka e10s), Private Tab 0.2.1+.
Not needed in most cases!

// Asynchronously get privacy state of given tab.
// In most cases should be replaced with synchronous privateTab.isTabPrivate()
privateTab.isTabPrivateAsync(gBrowser.selectedTab, function(isPrivate) {
	alert("Selected tab is " + (isPrivate ? "private" : "not private"));
});
privateTab.toggleTabPrivate()

Changes tab private state:
Toggle: privateTab.toggleTabPrivate(tab)
Make private: privateTab.toggleTabPrivate(tab, true)
Make not private: privateTab.toggleTabPrivate(tab, false)

// Make all (visible) tabs private:
Array.forEach(
	gBrowser.visibleTabs || gBrowser.tabs,
	function(tab) {
		if(!privateTab.isTabPrivate(tab))
			privateTab.toggleTabPrivate(tab, true);
	}
);
privateTab.duplicateTabAndTogglePrivate()

Duplicate already opened tab in private or non-private tab.

// Duplicate selected tab and toggle private state of duplicated tab
var tab = gBrowser.selectedTab;
var pos = "_tPos" in tab
	? tab._tPos
	: Array.prototype.indexOf.call(gBrowser.tabs, tab); // SeaMonkey
var dupTab = gBrowser.selectedTab = privateTab.duplicateTabAndTogglePrivate(tab);
gBrowser.moveTabTo(dupTab, pos + 1); // Place right after initial tab
privateTab.replaceTabAndTogglePrivate()

Changes tab private state using tab duplication (for Firefox 52+):

// Duplicate selected tab, toggle private state of duplicated tab and then close initial tab
privateTab.replaceTabAndTogglePrivate(gBrowser.selectedTab);
// The same as above + also load new URL into duplicated tab (Private Tab 0.2.3+)
privateTab.replaceTabAndTogglePrivate(gBrowser.selectedTab, undefined, function onSuccess(dupTab) {
	dupTab.linkedBrowser.loadURI("https://example.com/");
});
privateTab.readyToOpenTab()

Allows to open private or not private tab (independent of any inheritance mechanism), example:

// Open in private tab:
privateTab.readyToOpenTab(true);
gBrowser.addTab("https://mozilla.org/");
// Open in not private tab:
privateTab.readyToOpenTab(false);
gBrowser.addTab("https://mozilla.org/");
privateTab.readyToOpenTabs()

Allows to open many private or not private tabs (independent of any inheritance mechanism), example:

// Open in private tabs:
privateTab.readyToOpenTabs(true);
gBrowser.addTab("https://mozilla.org/");
gBrowser.addTab("https://addons.mozilla.org/");
// ...
privateTab.stopToOpenTabs();
privateTab.hasClosedTabs

Only for extensions.privateTab.rememberClosedPrivateTabs = true, Private Tab 0.1.7.4+.
Return true, if there is at least one private tab in undo close list, example:

if(privateTab.hasClosedTabs)
	alert("We have at least one closed private tabs");
else
	alert("We don't have closed private tabs");
privateTab.forgetClosedTabs()

Only for extensions.privateTab.rememberClosedPrivateTabs = true, Private Tab 0.1.7.4+.
Forget about all closed private tabs in window, example:

// Forget about all closed private tabs in window
privateTab.forgetClosedTabs();
privateTab.tabLabelIsEmpty()

Mark tab label as empty (or non-empty), example:

// Mark tab label/URI as empty:
if("tabLabelIsEmpty" in privateTab) // Private Tab 0.1.7.2+
	privateTab.tabLabelIsEmpty("chrome://speeddial/content/speeddial.xul", true);
// Check state:
var isEmpty = privateTab.tabLabelIsEmpty("chrome://speeddial/content/speeddial.xul");
// Restore state (e.g. for restartless extensions):
privateTab.tabLabelIsEmpty("chrome://speeddial/content/speeddial.xul", false);

Note: used global storage for labels (not per-window)! So, it's enough to call this function only once.

Backward compatibility:

Check for Private Tab installed (and enabled):

if("privateTab" in window) {
	// Do something with "privateTab" object
}
Code examples:

Open link in private tab using FireGestures extension:

// Remember the active tab's position
var tab = gBrowser.selectedTab;
var pos = "_tPos" in tab
	? tab._tPos
	: Array.prototype.indexOf.call(gBrowser.tabs, tab); // SeaMonkey
// Get the DOM node at the starting point of gesture
var srcNode = FireGestures.sourceNode;
// Get the link URL inside the node
var linkURL = FireGestures.getLinkURL(srcNode);
if (!linkURL)
    throw "Not on a link";
// Check the URL is safe
FireGestures.checkURL(linkURL, srcNode.ownerDocument);
// Open link in new private tab
privateTab.readyToOpenTab(true);
var newPrivateTab = gBrowser.addTab(linkURL);
gBrowser.moveTabTo(newPrivateTab, pos + 1); // Place right after initial tab