Sorting Tabs in Directory Opus

 ·   ·  ☕ 7 min read
🏷️
This page looks best with JavaScript enabled

One of the best features of Directory Opus is the ability to have multiple listers with numerous open tabs. However, if you’re not diligent in closing unnecessary tabs, you’ll quickly end up with a cluttered mix of relevant and irrelevant tabs.

Managing a multitude of tabs can be daunting, especially when you need to keep them organized for efficient workflow. The script in this article aims to streamline this process by automatically sorting your tabs based on their paths. It distinguishes between locked and unlocked tabs, ensuring your most important tabs remain accessible while others are neatly arranged.

Whether you’re a power user or looking to enhance your productivity, this script will save you time and reduce clutter in your tab management.

Now, let’s delve into the specifics of how the script works and the benefits it brings to your daily use of Directory Opus.

The Script

The following JavaScript code organizes tabs based on their paths, distinguishing between locked and unlocked tabs. It consists of two functions:

  1. OnClick: Handles the click event, retrieves the command object, prevents automatic deselection, clears existing files, and calls the sortTabs function for both left and right tabs.

  2. SortTabs: Sorts tabs by their paths, processes locked and unlocked tabs separately, and generates commands to reposition the tabs in the specified order.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
function OnClick(clickData) {
  var cmd = clickData.func.command;
  cmd.deselect = false; // Prevent automatic deselection
  cmd.ClearFiles();

  SortTabs(cmd, clickData.func.sourcetab.lister.tabsleft);
  SortTabs(cmd, clickData.func.sourcetab.lister.tabsright);
}

function SortTabs(cmd, tabList) {
  var setLabels = DOpus.Create.StringSet();
  var mapLabelToTabVec = DOpus.Create.Map();

  for (var eTabs = new Enumerator(tabList); !eTabs.atEnd(); eTabs.moveNext()) {
    var tab = eTabs.item();
    var label = tab.path.def_value.toLowerCase();

    setLabels.insert(label);

    if (!mapLabelToTabVec.exists(label)) {
      mapLabelToTabVec(label) = DOpus.Create.Vector();
    }
    mapLabelToTabVec(label).push_back(tab);
  }

  var vecLabels = DOpus.Create.Vector();

  for (var eLabels = new Enumerator(setLabels); !eLabels.atEnd(); eLabels.moveNext()) {
    vecLabels.push_back(eLabels.item());
  }
  vecLabels.sort();

  cmd.Clear();
  var tabPos = 0;

  // Locked Tabs
  for (var eLabels = new Enumerator(vecLabels); !eLabels.atEnd(); eLabels.moveNext()) {
    var vecTabs = mapLabelToTabVec(eLabels.item());
    for (var eTabs = new Enumerator(vecTabs); !eTabs.atEnd(); eTabs.moveNext()) {
      var tab = eTabs.item();
      if (tab.lock !== "off") {
        cmd.AddLine("Go TABPOS=" + tabPos + "," + tab);
        ++tabPos;
      }
    }
  }

  // Unlocked Tabs
  for (var eLabels = new Enumerator(vecLabels); !eLabels.atEnd(); eLabels.moveNext()) {
    var vecTabs = mapLabelToTabVec(eLabels.item());
    for (var eTabs = new Enumerator(vecTabs); !eTabs.atEnd(); eTabs.moveNext()) {
      var tab = eTabs.item();
      if (tab.lock === "off") {
        cmd.AddLine("Go TABPOS=" + tabPos + "," + tab);
        ++tabPos;
      }
    }
  }

  if (tabPos > 1) {
    cmd.Run();
  }
}

Explanation of the JavaScript Code

The provided JavaScript code sorts tabs in Directory Opus based on their paths. Let’s break down the code step by step and call out noteworthy functions and behaviors using line numbers:

  1. Function OnClick(clickData)

    • Line 1: Defines the OnClick function, which is triggered when a button is clicked.
    • Line 2: Retrieves the command object associated with the click.
    • Line 3: Prevents automatic deselection of the clicked item.
    • Line 4: Clears any existing files from the command object.
  2. Calling SortTabs Function

    • Lines 6-7: Calls the SortTabs function twice, once for the left tabs and once for the right tabs of the lister.
  3. Function SortTabs(cmd, tabList)

    • Line 10: Defines the SortTabs function.
    • Line 11: Creates a set to store unique tab labels.
    • Line 12: Creates a map to associate labels with their corresponding tabs.
  4. Looping Through Tabs

    • Lines 14-21: Loops through each tab in the provided tabList. For each tab, it converts the tab path to lowercase, inserts the label into the set, and adds the tab to the map.
    • Line 22: Converts the set of labels to a vector for sorting.
    • Lines 24-26: Sorts the labels vector alphabetically.
  5. Sorting and Positioning Tabs

    • Line 28: Clears the command object.
    • Line 29: Initializes the tab position counter.
  6. Processing Locked Tabs

    • Lines 32-40: Loops through the sorted labels and processes tabs that are locked (i.e., lock !== "off"). Adds commands to move these tabs to their new positions.
  7. Processing Unlocked Tabs

    • Lines 43-51: Loops through the sorted labels and processes tabs that are unlocked (i.e., lock === "off"). Adds commands to move these tabs to their new positions.
  8. Executing Commands

    • Line 53: Runs the commands if there are more than one tab.

Customizing the JavaScript

  1. Sort by tab label instead of path

    • Update Line 16 by replacing path.def_value with displayed_label so that you end up with:
      16
      
          var label = tab.displayed_label.toLowerCase();
      
  2. Sort locked and unlocked tabs together

    • Replace Lines 36-58 with a single for loop that simply sorts the tabs regardless of whether they’re locked or not:
      36
      37
      38
      39
      40
      41
      42
      43
      
        for (var eLabels = new Enumerator(vecLabels); !eLabels.atEnd(); eLabels.moveNext()) {
          var vecTabs = mapLabelToTabVec(eLabels.item());
          for (var eTabs = new Enumerator(vecTabs); !eTabs.atEnd(); eTabs.moveNext()) {
            var tab = eTabs.item();
            cmd.AddLine("Go TABPOS=" + tabPos + "," + tab);
            ++tabPos;
          }
        }
      

The Command File

To simplify adding this command to your Directory Opus installation, download the complete “Sort Tabs by Path” file, which includes an appropriate label, tooltip, and icon. Once downloaded, you can simply double-click the file to execute the command in Directory Opus. You can also customize your toolbar and drag the file to where you want it to appear for easier access.

If you’d prefer to create the file manually, I’ve also included the file contents below. A .dcf file is essentially an XML file associated with Directory Opus, which you can edit using any plain text editor. Simply copy the XML code into a new file and save it with the .dcf file extension.

now you know
Command Iconas it appears in Directory Opus 13
Sort Tabs by Path.dcf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<?xml version="1.0"?>
<button backcol="none" display="icon" label_pos="right" textcol="none">
  <label>Sort Tabs by Path</label>
  <tip>Sort tabs by their lock state and then by their associated file or folder path</tip>
  <icon1>#sort_alpha</icon1>
  <function type="script">
    <instruction>@script JScript</instruction>
    <instruction>function OnClick(clickData) {</instruction>
    <instruction>  var cmd = clickData.func.command;</instruction>
    <instruction>  cmd.deselect = false; // Prevent automatic deselection</instruction>
    <instruction>  cmd.ClearFiles();</instruction>
    <instruction />
    <instruction>  sortTabs(cmd, clickData.func.sourcetab.lister.tabsleft);</instruction>
    <instruction>  sortTabs(cmd, clickData.func.sourcetab.lister.tabsright);</instruction>
    <instruction>}</instruction>
    <instruction />
    <instruction>function sortTabs(cmd, tabList) {</instruction>
    <instruction>  var setLabels = DOpus.Create.StringSet();</instruction>
    <instruction>  var mapLabelToTabVec = DOpus.Create.Map();</instruction>
    <instruction />
    <instruction>  for (var eTabs = new Enumerator(tabList); !eTabs.atEnd(); eTabs.moveNext()) {</instruction>
    <instruction>    var tab = eTabs.item();</instruction>
    <instruction>    var label = tab.path.def_value.toLowerCase();</instruction>
    <instruction />
    <instruction>    setLabels.insert(label);</instruction>
    <instruction />
    <instruction>    if (!mapLabelToTabVec.exists(label)) {</instruction>
    <instruction>      mapLabelToTabVec(label) = DOpus.Create.Vector();</instruction>
    <instruction>    }</instruction>
    <instruction>    mapLabelToTabVec(label).push_back(tab);</instruction>
    <instruction>  }</instruction>
    <instruction />
    <instruction>  var vecLabels = DOpus.Create.Vector();</instruction>
    <instruction />
    <instruction>  for (var eLabels = new Enumerator(setLabels); !eLabels.atEnd(); eLabels.moveNext()) {</instruction>
    <instruction>    vecLabels.push_back(eLabels.item());</instruction>
    <instruction>  }</instruction>
    <instruction>  vecLabels.sort();</instruction>
    <instruction />
    <instruction>  cmd.Clear();</instruction>
    <instruction>  var tabPos = 0;</instruction>
    <instruction />
    <instruction>  // Locked Tabs</instruction>
    <instruction>  for (var eLabels = new Enumerator(vecLabels); !eLabels.atEnd(); eLabels.moveNext()) {</instruction>
    <instruction>    var vecTabs = mapLabelToTabVec(eLabels.item());</instruction>
    <instruction>    for (var eTabs = new Enumerator(vecTabs); !eTabs.atEnd(); eTabs.moveNext()) {</instruction>
    <instruction>      var tab = eTabs.item();</instruction>
    <instruction>      if (tab.lock !== &quot;off&quot;) {</instruction>
    <instruction>        cmd.AddLine(&quot;Go TABPOS=&quot; + tabPos + &quot;,&quot; + tab);</instruction>
    <instruction>        ++tabPos;</instruction>
    <instruction>      }</instruction>
    <instruction>    }</instruction>
    <instruction>  }</instruction>
    <instruction />
    <instruction>  // Unlocked Tabs</instruction>
    <instruction>  for (var eLabels = new Enumerator(vecLabels); !eLabels.atEnd(); eLabels.moveNext()) {</instruction>
    <instruction>    var vecTabs = mapLabelToTabVec(eLabels.item());</instruction>
    <instruction>    for (var eTabs = new Enumerator(vecTabs); !eTabs.atEnd(); eTabs.moveNext()) {</instruction>
    <instruction>      var tab = eTabs.item();</instruction>
    <instruction>      if (tab.lock === &quot;off&quot;) {</instruction>
    <instruction>        cmd.AddLine(&quot;Go TABPOS=&quot; + tabPos + &quot;,&quot; + tab);</instruction>
    <instruction>        ++tabPos;</instruction>
    <instruction>      }</instruction>
    <instruction>    }</instruction>
    <instruction>  }</instruction>
    <instruction />
    <instruction>  if (tabPos &gt; 1) {</instruction>
    <instruction>    cmd.Run();</instruction>
    <instruction>  }</instruction>
    <instruction>}</instruction>
  </function>
</button>

By using this script, you can effortlessly organize your Directory Opus tabs, ensuring a neat and efficient workspace. This approach saves time, reduces clutter, and enhances productivity.

End of Line.