Tabs are an important part of the Cloud9 UI. Tabs house documents which are displayed by editors. Tabs themselves live in panes and by default Cloud9 starts up with a single pane. Users can divide the UI into multiple panes and open / move tabs between panes. Tabs are controlled by the tabManager plugin, which offers an API to control the tabs and panes in Cloud9.

The Tab Manager

Use the tabManager plugin to open tabs, look for already opened tabs and to listen for tabs being opened by other plugins. The focussed and active state of tabs is also handled by the tabManager. In addition the tabManager works closely together with other areas that house tabs such as the console plugin which is responsible for the console in the bottom of the screen.

Object structure

Besides tabs and panes there are several other objects involved in displaying content and making it editable. The following hierarchy describes the relationships between those objects.

  • Pane - Represent a single pane, housing multiple tabs
    • Editor - The editor responsible for displaying the document in the tab
    • Tab - A single tab (button) in a pane
      • Document - The representation of a file in the tab
        • Session - The session information of the editor
        • UndoManager - The object that manages the undo stack for this document

It is important to note that the Editor plugin(s) are related to the pane, not the tab. There's only one instance of a certain editor for each pane. The editor is responsible for displaying the content of a document based on the tab that is active. There can be a maximum of one tab active per pane.

Opening tabs

The most basic way to open a tab is based on a file. Simply specify the filename to open a tab.

tabManager.openFile("file.js", function(err, tab){
    if (err) return console.error(err);
    
    console.log("file.js was opened with content", tab.document.value);
});

The default editor for the extension (in this case .js) is chosen from the installed editors and used to display the content.

In the same way you can open editors that are not file based, such as the terminal. Note that these tabs still have the full object structure as described above.

tabManager.openEditor("terminal", function(err, tab){
    if (err) return console.error(err);
    
    var terminal = tab.editor;
    terminal.write("ls\n");
});

The open() method allows a more granular level of control opening tabs. It allows you to focus a newly created tab, set the pane it is created in and force a different editor than the default one.

tabManager.open({
    path: "image.png",
    editorType: "hex", // Note that this is an example. Cloud9 currently doesn't have an hex editor
    focus: true,
    pane: tabManager.getPanes()[1] // An example of getting the 2nd pane
}, function(err, tab){
    if (err) return console.error(err); 
});

Opening New Files

The easiest way to create a new file is via the newfile command, which opens a new tab with an empty unnamed file.

commands.exec("newfile");

When you want more control opening a new file then use the open() method for that.

tabs.open({
    path: "/path/to/new/filename",
    value: "The value of your file",
    active: true,
    document: {
        meta: {
            newfile: true
        }
    }
}, function(err, tab) {
    if (err)
        return console.error(err);
});

The newfile property on the meta object is used by the tabManager to not attempt to download the file from the path specified when opening the tab.

🚧

The meta object

The meta object, available on most plugins (e.g. document, tab, menu) allows you to set properties that are not directly part of the API for that plugin, but which properties can be used by other plugins. For instance the save plugin will check for meta.ignoreSave on a document and will not warn when a document with changes is closed when that property is set.

Any plugin can extend the meta object of a plugin with custom properties. Note that properties starting with $ are not saved in the object state, while all other properties are and are thus preserved between reloads of the IDE.

Loading Content from an Alternative Source

When you want to load data into a tab from another source than a file set the value property to -1. The callback will be called synchronously with a function as the third argument to be called when the contents is loaded.

tabs.open({
    value: -1,
    active: true
}, function(err, tab, done) {    
    getDataFromSomewhere(function(err, data){
        if (err) {
            tab.className.add("error");
            return console.error(err);
        }
    
        tab.document.value = data;
        done();
    });
});

It's recommended to update the progress state of the document if possible.

Active vs Focussed Tabs

There are three distinct states a tab can be in. Inactive, active and focussed. When a tab is inactive it's content is not visible. When a tab is active it's button is selected and the content of the document is displayed in the editor. When a tab is focussed, any input such as keyboard input is send to that editor. A focussed tab is always active. There can only be one focussed tab in Cloud9 at one time, while there can be multiple active tabs - one per pane.

Set a tab active either via it's path or reference:

tabManager.activateTab("/path/to/file.js");
tabManager.activateTab(myTab);

Focus a tab like this:

tabManager.focusTab("/path/to/file.js");
tabManager.focusTab(myTab);

Fetch the focussed tab via tabManager.focussedTab when you want to apply an operation to a certain tab.

var tab = tabManager.focussedTab;
if (tab.editorType == "ace") {
    performOperation(tab);
}

Events

The tabManager has over 20 events, such as tabCreate, tabAfterActivate, tabDestroy, etc. See the reference guide for a complete list.

The open and ready events are worth mentioning specifically. The open event is fired for each tab that is opened via the open() method (or openFile, openEditor) after its contents is loaded.

tabManager.on("open", function(e){
    if (e.tab.path.match(/^\/some\/path/)) {
        // Do something
    }
});

The ready event is fired after Cloud9 has started and all the tabs from the previous session have been opened (which includes loading the content).

tabManager.on("ready", function(e){
    console.log("All tabs are open");
});

👍

Sticky Event

The ready event is a so-called sticky event, which means that if it has already fired when you set the listener it will fire immediately (synchronously).

Getting a Reference to Tabs

Tabs that have a file associated to it have their path property set. To get a reference to a tab like that use the findTab() method.

var tab = tabManager.findTab("/path/to/file.js");

if a tab doesn't have a file associated, such as a terminal, then you can look them up by their name, which was automatically assigned to them when they were created.

You can retrieve a list of tabs via the getTabs() method.

var allFileTabs = tabManager.getTabs().filter(function(tab){
    return tab.path ? true : false;
});

Preview

Users of cloud9 can preview the contents of tabs. For instance, when pressing the spacebar in the tree a preview tab opens that goes away as soon as the user hits spacebar again or selects another tab. When the user edits the document in the previewed tab, the tab is opened permanently.

This behavior is provided by the tabManager via the preview() method. This method works in the same way as the the open() method with a limited set of the options.

tabManager.preview({
    path: "image.png",
}, function(err, tab){
    if (err) return console.error(err); 
});

There can only be one preview at one time. The properties tabManager.previewTab is set to the tab that is previewed or null if there is none.

Tab

For a full reference to the properties, methods and events of a tab object see the reference guide

Background Color

You can set the background color of a tab. This color is only shown when the tab is active and usually determined by the editor that is loaded.

tab.backgroundColor = "rgb(255,0,0"); // A red tab button

CSS States

Manage the css classes of a tab button via the classList property. Special classes are dark, error, loading and running which you can add to a tab to specify an appropriate state.

tab.classList.add("loading");
tab.classList.remove("loading");

Properties

The tab object has a reference to it's .pane and the .document that is attached to the tab. When the tab has been active at least once the .editor property references the editor that displays the document. It's important to realize that when a tab has not yet been active the .editor property is null. Use the .editorType property to get the name of the editor that will be used to display the document.

Closing a Tab

To close a tab call tab.close().

The Meta Object

The meta property of the tab is similar to the document's meta object. The following table lists the properties on the meta object set by the different Cloud9 plugins.

PropertyPluginDescription
$loadingMetadatametadataDuring the load phase of meta data
.$closingtabDuring the close phase of tab
$ignoreterminalThe terminal will not ask the confirm message when the tab is closed.

Switching Editors

To programmatically change the editor that is used for a certain document called switchEditor.

tab.switchEditor("imgeditor", function(){
     // Switch is complete
});