# Script: open everything in two windows

**URL:** <https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648>\
**Category:** DEVONthink\
**Tags:** automation\
**Created:** [August 31, 2024, 2:27pm UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648 "2024-08-31T14:27:51Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![meowky](https://discourse.devontechnologies.com/letter_avatar_proxy/v4/letter/m/85e7bf/32.png) [@meowky](https://discourse.devontechnologies.com/u/meowky)\
**Post date:** [August 31, 2024, 2:27pm UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/1 "2024-08-31T14:27:51Z")

</div>

### Use case

My workflow usually involves two document windows side-by-side. The window on the right is for my notes. The left is for reading and reference materials, _i.e._ everything else. Both windows may contain many tabs. I prefer this setup because I don’t need to switch between, or rearrange windows.

My setup relies on the two following functions:

- When I open documents, they appear as tabs in the _correct_ window: notes on the right, everything else on the left.
- When I, for some reason, have many document windows open, I can reorganize them into two windows with ease.

The following script is capable of both.

### Script (JXA)

> **Click to expand**
>
> ```JavaScript
> /* This script is intended to maintain a work arrangement of 2 document windows.
> One type of documents open in window A; all other documents open in window B. You can change the criteria as you wish.
> If the front DT window is a viewer window, selected documents will be opened.
> If the front DT window is a document window, all document windows and their tabs will be rearranged.
> You might want to experiment with the script to see what it does. */
> 
> /* Meowky 2024-08-31 */
> 
> function run () {
> const app = Application('DEVONthink 3');
> app.includeStandardAdditions = true;
> 	
> const allDWs = app.documentWindows();
> 	
> // Determine which window a document should open in.
> function isNote (r) {
> // Change criteria as you wish. The example is for markdown notes.
> const criteria = r.type() === 'markdown' && r.database().name() === 'My Notes' && !r.name().startsWith('This is not a note!');
> 		
> if (criteria) return true;
> else return false;
> }
> 	
> // Designate two document windows; other documents will be (re)opened in these two.
> // Windows with the most open tabs will be prioritized.
> function autoSelectWindows (ws) {
> let readingWindow, notesWindow;
> 		
> // Loop through all document windows.
> for (let i = 0; i < ws.length; i++) {
> const w = ws[i];
> const test = w.tabs().map(x => isNote(x.contentRecord()));
> 			
> // Determine the "type" of a document window by comparing the number of open notes vs other document types.
> if (test.filter(x => x).length < test.filter(x => !x).length) {
> if (!readingWindow) readingWindow = w;
> else if (readingWindow.tabs().length < w.tabs().length) readingWindow = w;
> }
> else {
> if (!notesWindow) notesWindow = w;
> else if (notesWindow.tabs().length < w.tabs().length) notesWindow = w;
> }
> }
> 		
> // Return the two windows; values default to undefined.
> return {'reading': readingWindow, 'notes': notesWindow};
> }
> 	
> const windows = autoSelectWindows(allDWs);
> 	
> if (app.thinkWindows()[0].class() === 'viewerWindow' && app.selectedRecords()) {
> 		
> // Front window is viewer window (that is, main window). Open selected records.
> app.selectedRecords().forEach(record => {
> 		
> // Ignore selected groups.
> if (record.type() === 'group') return;
> 			
> if (isNote(record)) {
> if (windows.notes) {
> app.openTabFor({record: record, in: windows.notes});
> } else {
> // Create a new document window for notes if there is no designated window for notes.
> windows.notes = app.openTabFor({record: record}).thinkWindow();
> }
> } else {
> if (windows.reading) {
> app.openTabFor({record: record, in: windows.reading});
> } else {
> windows.reading = app.openTabFor({record: record}).thinkWindow();
> }
> }
> })
> } else {
> 		
> // Front window is document window. Reorganize document windows.
> // Garner all open tabs in all document windows. NOTE: tabs in viewer windows are untouched.
> const allTabs = allDWs.map(x => x.tabs()).flat();
> 		
> // Loop through the tabs.
> allTabs.forEach(tab => {
> const record = tab.contentRecord();
> if (isNote(record)) {
> if (!windows.notes) {
> // Create new window for notes if there is no designated window.
> app.close(tab, {saving: 'ask'});
> windows.notes = app.openTabFor({record: record}).thinkWindow();
> }
> else if (tab.thinkWindow().id() !== windows.notes.id()) {
> // Move the tab if a note is not opened in the designated window for notes.
> app.close(tab, {saving: 'ask'});
> app.openTabFor({record: record, in: windows.notes});
> }
> } else {
> if (!windows.reading) {
> // Create new window ...
> app.close(tab, {saving: 'ask'});
> windows.reading = app.openTabFor({record: record}).thinkWindow();
> }
> else if (tab.thinkWindow().id() !== windows.reading.id()) {
> // Move ...
> app.close(tab, {saving: 'ask'});
> app.openTabFor({record: record, in: windows.reading});
> }
> }
> })
> }
> 	
> }
> 
> ```

Some additional comments:

- You will need to modify the `criteria` to fit your use case. Start with changing `'My Notes'` to the name of your database.
- This script manipulates the UI only, not the data. Its exact behavior depends on the `class` of the front DT window.
- This script is quite different from the `Open In Two Windows` script shipped along with the software. More specifically, my script can handle more than two documents, and runs with or without selected documents. The other script serves an entirely different purpose.
- Want to run the script with a keyboard shortcut? In case you don’t know yet, you can specify the keyboard shortcut in the filename of the script, for example: `MyScript___Shift+Cmd+Option+Control+U.scpt`  
There are alternative means as well.

Feedback is welcome!

---

<div class="post-metadata">

**Author:** ![BLUEFROG](https://discourse.devontechnologies.com/user_avatar/discourse.devontechnologies.com/bluefrog/32/135_2.png) [@BLUEFROG](https://discourse.devontechnologies.com/u/BLUEFROG)\
**Post date:** [August 31, 2024, 5:38pm UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/2 "2024-08-31T17:38:24Z")

</div>

Have you checked out this extra script?

 ![image](https://devontech-discourse.s3.dualstack.us-east-1.amazonaws.com/uploads/original/3X/2/9/297618d45d4686f4868c8893eb4f936cb7bd815a.jpeg)

And the description is actually only one use case. Install it, select two documents, and run the script.

---

<div class="post-metadata">

**Author:** ![chrillek](https://discourse.devontechnologies.com/user_avatar/discourse.devontechnologies.com/chrillek/32/29340_2.png) [@chrillek](https://discourse.devontechnologies.com/u/chrillek)\
**Post date:** [August 31, 2024, 8:46pm UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/3 "2024-08-31T20:46:52Z")

</div>

> [@meowky](#):
>
> Feedback is welcome!

Here it comes. All, of course, my personal opinion.

- The code in `isNote()` is a bit too verbose. A simple  
`return r.type() === 'markdown' && r.database().name() === 'My Notes' && !r.name().startsWith('This is not a note!`);  
suffices.
- Instead of `for (let i = ...)`, I’d use  
`ws.forEach(w => { const test w.tabs()...}...)`
- I _think_ that `w.tabs().map(x => isNote(x.contentRecord()))` could be written simpler as `w.tabs.contentRecord().map(x => isNote(x))`
- Instead of `if (!readingWindow) ... else if (...) `, I’d use an `or` condition and a single `if`:  
`if (!readingWindow or readingWindow.tabs().length < w.tabs().length) readingWindow = w`
- Same for the next `if … else if ` condition.
- I’m still struggling with the `test.filter(x => x).length ...` condition. If I understand the code correctly, `test` is an `Array` of `Boolean`, where each array element tells us if records in the current window’s tabs are notes or not. The `test` condition seems to figure out if you have more notes than non-notes in the current window’s tabs. I’d probably use something like

```JavaScript
const noteCount = w.tabs.contentRecord().filter(x => isNote(x)).length;
if (noteCount < w.tabs.length - noteCount) {
  if (!readingWindow …) {
  }
else {
  if (!notesWindow) {
}
}

```

I may of course have gotten the idea wrong or the conditions upside down. But the current code seems to be a bit over-complicated – at least if all you want to know is _how many_ notes you have in the current window. If that’s the case, I’d use a `filter`, not a `map` on the on the `contentRecords`

- Instead of `app.selectedRecords().forEach(record => { if record.type === 'group' return; … })`, I’d use  
`app.selectedRecords().filter(r => r.type !== 'group').forEach(r => …)`  
The rest of the code is way over my head. It _looks_ as if it might be simplified, but I have no clue how.

---

<div class="post-metadata">

**Author:** ![meowky](https://discourse.devontechnologies.com/letter_avatar_proxy/v4/letter/m/85e7bf/32.png) [@meowky](https://discourse.devontechnologies.com/u/meowky)\
**Post date:** [August 31, 2024, 11:11pm UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/4 "2024-08-31T23:11:29Z")

</div>

> [@BLUEFROG](#):
>
> Have you checked out this extra script?

I actually addressed that script in my original post. It serves a different purpose and, understandably, fulfills neither of my two needs.

> [@chrillek](#):
>
> it might be simplified

Many thanks for the coding lesson! Some of the tips I’m previously unaware of.

I must admit that I’m quite new to JXA and JavaScript in general, having recently switched from AppleScript. I was focused on making this script work; making it more elegant was of secondary concern unless there is a significant speed penalty.

I will perhaps rewrite the script when I want to add new functions into it. Thanks again!

---

<div class="post-metadata">

**Author:** ![vinschger](https://discourse.devontechnologies.com/letter_avatar_proxy/v4/letter/v/e47c2d/32.png) [@vinschger](https://discourse.devontechnologies.com/u/vinschger)\
**Post date:** [September 1, 2024, 4:10am UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/5 "2024-09-01T04:10:00Z")

</div>

can you please show a screenshot of your 2-window setup, so that I can better understand how you use DTP. thanks.

---

<div class="post-metadata">

**Author:** ![meowky](https://discourse.devontechnologies.com/letter_avatar_proxy/v4/letter/m/85e7bf/32.png) [@meowky](https://discourse.devontechnologies.com/u/meowky)\
**Post date:** [September 1, 2024, 5:22am UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/6 "2024-09-01T05:22:42Z")

</div>

![Screenshot](https://devontech-discourse.s3.dualstack.us-east-1.amazonaws.com/uploads/original/3X/7/1/71b9f646dbecf6c790cc57860f4aea554edf5389.jpeg)

As described in the original post, I have two document windows open in the front. On the secondary screen there are another one or two viewer windows (not shown in screenshot) for searching and organizing.

---

<div class="post-metadata">

**Author:** ![Hens](https://discourse.devontechnologies.com/user_avatar/discourse.devontechnologies.com/hens/32/7003_2.png) [@Hens](https://discourse.devontechnologies.com/u/Hens)\
**Post date:** [September 1, 2024, 6:53am UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/7 "2024-09-01T06:53:54Z")

</div>

can you share the full scrip pls

---

<div class="post-metadata">

**Author:** ![meowky](https://discourse.devontechnologies.com/letter_avatar_proxy/v4/letter/m/85e7bf/32.png) [@meowky](https://discourse.devontechnologies.com/u/meowky)\
**Post date:** [September 1, 2024, 6:59am UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/8 "2024-09-01T06:59:00Z")

</div>

Copy the script text (available in the “Click to expand” section), then paste it into Script Editor. Be assured that it _is_ the full script 🙂

---

<div class="post-metadata">

**Author:** ![chrillek](https://discourse.devontechnologies.com/user_avatar/discourse.devontechnologies.com/chrillek/32/29340_2.png) [@chrillek](https://discourse.devontechnologies.com/u/chrillek)\
**Post date:** [September 1, 2024, 8:18am UTC](https://discourse.devontechnologies.com/t/script-open-everything-in-two-windows/80648/9 "2024-09-01T08:18:10Z")

</div>

> [@meowky](#):
>
> unless there is a significant speed penalty.

I doubt that this script would exhibit any performance problems, even if coded in a worse way. But “elegance” is also about clarity, i.e. making the code easier to understand and consequently easier to maintain. Which is important for many people – more so than performance considerations.

In particular, your approach to getting the number of notes in a window is quite winded and obscures the intention (in my opinion, of course). I’d ask myself if I will understand what I did there a week or two later. Been there, done that 😉
