Skip to content

Loading…

expose unique tab ids to the high-level tabs module #595

Merged
merged 2 commits into from

3 participants

@erikvold erikvold was assigned
@Gozala
Mozilla member

Two things to consider before going ahead with this:

  1. Do we actually have a need for a properties like id. In chrome APIs they seem to be a primary mechanism for dealing with identity not the objects themselves. In our case tab instance itself serves this purpose. In other words in chrome you pass tab id across diff APIs in our case you pass object instead.

  2. Can we guarantee that we'll be able to support this in a future ? I guess answer is yes, if things will come to worst we could make our own ID's.

@Gozala
Mozilla member

After giving this a little bit more thought, I'm convinced that exposing tab.id is a good idea, in fact having such property would have made our lives a lot easier.

@Gozala Gozala commented on an outdated diff
packages/api-utils/lib/tabs/utils.js
@@ -131,6 +131,14 @@ function getBrowserForTab(tab) {
}
exports.getBrowserForTab = getBrowserForTab;
+function getTabId(tab) {
+ if (tab.browser) // fennec
+ return tab.id
+
+ return String.split(tab.linkedPanel, 'panel').pop();
@Gozala Mozilla member
Gozala added a note

I'm not sure it's relable ?

It's reliable for desktop as the linkedPanel property always returns a string 'panel1234567' for example. There would need to be a test written to ensure that the platform continues to produce that string format as the property.

I do this string manipulation out for aesthetic reasons, it looks wrong for something like 'tab.id' to have a value 'panel1234' - panels are something completely different in the SDK and we don't want to confuse people.

I think I have three action items here:

  1. write a test that will fail if the value of tab.linkedPanel changes
  2. investigate a cleaner way to re-format the linkedPanel value
  3. do some tests on fennec to see what their tab.id looks like
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Gozala
Mozilla member

Now even though I think tab.id / window.id is a good idea, I would be more comfortable if we could check with someone on the platform side to make sure. All the APIs I could have though of tend to avoid using id's, making me wonder if there are intentional reasons. Take a look at https://developer.mozilla.org/en-US/docs/Session_store_API for example.

Also implementation does not seems to use any particular attribute as an identifier, which is concerning:
https://mxr.mozilla.org/mozilla-central/source/browser/components/sessionstore/src/SessionStore.jsm

Maybe one of the contributors @andrez47 @ttaubert @iake @MichaelKohler to session-store could tell use why ?

With this, I think we should avoid adding such attribute until we get more insights. Also if there is no particular reason for not having tab id's, I think we should just add them to the firefox similar to fennec and expose only after.

@Gozala
Mozilla member

I had some conversations with Gavin and others at jsconf.eu it looks like there is no specific reason why tab's should not have id. So I'm ok with landing as is, also we should note in the docs that this ID is not preserved across restarts. Also we should create a bug to implement actual tab.id in the platform, it would be best if we'll just adopt whatever Fennec does in a desktop FF

@canuckistani

@Gozala, @erikvold - I re-applied my patch to current master, should be good to land?

@erikvold

@canuckistani I sees no tests

@canuckistani

@erikvold @Gozala added some very basic tests, the tests pass. Okay to land? Or, advice on what more we could test here.

@erikvold

do we have some confirmation that the tab.linkedPanel is globally unique?

@erikvold

I'd like to see a test for Firefox that opens two tabs in separate windows and checks that the ids are not equal. Also another test that confirms that the id is a string that only contains numbers.

@erikvold

Also another test that opens 2 tabs in the same window and confirms that those two ids are not equal (for fennec).

@canuckistani

Ok, I'll look into filling out those tests. FWIW, while the docs alude to the possible use of multiple panels per tab, etc, this does not seem to be how Firefox uses it:

https://mxr.mozilla.org/mozilla-central/source/browser/base/content/tabbrowser.xml#1355

1352             var position = this.tabs.length - 1;
1353             var uniqueId = "panel" + Date.now() + position;
1354             notificationbox.id = uniqueId;
1355             t.linkedPanel = uniqueId;
1356             t.linkedBrowser = b;
1357             t._tPos = position;
@canuckistani

@erikvold I've added additional tests, so even if we changed the underlying implementation on Firefox these tests should be helpful.

Back to the underlying question though, based on that mxr link in my previous comment, I don't see how we could get duplicate tabs based on how they generate the linkedPanel ids ( timestamp + tab index. )

@erikvold erikvold merged commit db4f668 into mozilla:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 27, 2012
  1. @canuckistani
Commits on Dec 28, 2012
  1. @canuckistani

    added additional tests.

    canuckistani committed
This page is out of date. Refresh to see the latest.
View
6 lib/sdk/tabs/tab-fennec.js
@@ -8,7 +8,7 @@ const { Class } = require('../core/heritage');
const { tabNS } = require('./namespace');
const { EventTarget } = require('../event/target');
const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL,
- setTabURL, getOwnerWindow, getTabContentType } = require('./utils');
+ setTabURL, getOwnerWindow, getTabContentType, getTabId } = require('./utils');
const { emit } = require('../event/core');
const { when: unload } = require('../system/unload');
@@ -63,6 +63,10 @@ const Tab = Class({
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAAtCAYAAAA5reyyAAAAJElEQVRoge3BAQEAAACCIP+vbkhAAQAAAAAAAAAAAAAAAADXBjhtAAGQ0AF/AAAAAElFTkSuQmCC';
},
+ get id() {
+ return getTabId(tabNS(this).tab);
+ },
+
/**
* The index of the tab relative to other tabs in the application window.
* Changing this property will change order of the actual position of the tab.
View
7 lib/sdk/tabs/tab-firefox.js
@@ -10,7 +10,7 @@ const { EVENTS } = require("./events");
const { getThumbnailURIForWindow } = require("../content/thumbnail");
const { getFaviconURIForLocation } = require("../io/data");
const { activateTab, getOwnerWindow, getBrowserForTab, getTabTitle, setTabTitle,
- getTabURL, setTabURL, getTabContentType } = require('./utils');
+ getTabURL, setTabURL, getTabContentType, getTabId } = require('./utils');
// Array of the inner instances of all the wrapped tabs.
const TABS = [];
@@ -95,6 +95,11 @@ const TabTrait = Trait.compose(EventEmitter, {
get _contentWindow() this._browser.contentWindow,
/**
+ * Unique id for the tab, actually maps to tab.linkedPanel but with some munging.
+ */
+ get id() getTabId(this._tab),
+
+ /**
* The title of the page currently loaded in the tab.
* Changing this property changes an actual title.
* @type {String}
View
9 lib/sdk/tabs/utils.js
@@ -150,6 +150,15 @@ function getBrowserForTab(tab) {
}
exports.getBrowserForTab = getBrowserForTab;
+function getTabId(tab) {
+ if (tab.browser) // fennec
+ return tab.id
+
+ return String.split(tab.linkedPanel, 'panel').pop();
+}
+exports.getTabId = getTabId;
+
+
function getTabTitle(tab) {
return getBrowserForTab(tab).contentDocument.title || tab.label || "";
}
View
42 test/tabs/test-fennec-tabs.js
@@ -125,6 +125,7 @@ exports.testTabProperties = function(test) {
test.assertEqual(tab.style, null, "style of the new tab matches");
test.assertEqual(tab.index, tabsLen, "index of the new tab matches");
test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
+ test.assertNotEqual(tab.id, null, "a tab object always has an id property");
tab.close(function() {
loader.unload();
@@ -619,3 +620,44 @@ exports.testActiveTab_getter_alt = function(test) {
}
});
};
+
+exports.testUniqueTabIds = function(test) {
+ test.waitUntilDone();
+ var tabs = require('sdk/tabs');
+ var tabIds = {};
+ var steps = [
+ function (index) {
+ tabs.open({
+ url: "data:text/html;charset=utf-8,foo",
+ onOpen: function(tab) {
+ tabIds['tab1'] = tab.id;
+ next(index);
+ }
+ });
+ },
+ function (index) {
+ tabs.open({
+ url: "data:text/html;charset=utf-8,bar",
+ onOpen: function(tab) {
+ tabIds['tab2'] = tab.id;
+ next(index);
+ }
+ });
+ },
+ function (index) {
+ test.assertNotEqual(tabIds.tab1, tabIds.tab2, "Tab ids should be unique.");
+ test.done();
+ }
+ ];
+
+ function next(index) {
+ if (index === steps.length) {
+ return;
+ }
+ let fn = steps[index];
+ index++;
+ fn(index);
+ }
+
+ next(0);
+}
View
48 test/tabs/test-firefox-tabs.js
@@ -177,6 +177,7 @@ exports.testTabProperties = function(test) {
test.assertEqual(tab.style, null, "style of the new tab matches");
test.assertEqual(tab.index, 1, "index of the new tab matches");
test.assertNotEqual(tab.getThumbnail(), null, "thumbnail of the new tab matches");
+ test.assertNotEqual(tab.id, null, "a tab object always has an id property.");
closeBrowserWindow(window, function() test.done());
}
});
@@ -913,6 +914,53 @@ exports['test ready event on new window tab'] = function(test) {
let window = openBrowserWindow(function(){}, uri);
};
+
+exports['test unique tab ids'] = function(test) {
+ test.waitUntilDone();
+
+ var windows = require('windows').browserWindows,
+ tabIds = {}, win1, win2;
+
+ let steps = [
+ function (index) {
+ win1 = windows.open({
+ url: "data:text/html;charset=utf-8,foo",
+ onOpen: function(window) {
+ tabIds['tab1'] = window.tabs.activeTab.id;
+ next(index);
+ }
+ });
+ },
+ function (index) {
+ win2 = windows.open({
+ url: "data:text/html;charset=utf-8,foo",
+ onOpen: function(window) {
+ tabIds['tab2'] = window.tabs.activeTab.id;
+ next(index);
+ }
+ });
+ },
+ function (index) {
+ test.assertNotEqual(tabIds.tab1, tabIds.tab2, "Tab ids should be unique.");
+ win1.close();
+ win2.close();
+ test.done();
+ }
+ ];
+
+ function next(index) {
+ if (index === steps.length) {
+ return;
+ }
+ let fn = steps[index];
+ index++
+ fn(index);
+ }
+
+ // run!
+ next(0);
+}
+
/******************* helpers *********************/
// Helper for getting the active window
Something went wrong with that request. Please try again.