#Introduction

In this lab you'll have the table and map open in their own windows.

#Steps

??Create a second app that provides the second window viewport

Use a terminal window, navigate to your workspace, and run `npm run create-app`. 

Name it **EarthquakesTableWindow**, 
and **answer Yes** when asked "Do you want to use SharedWorkers?"

??Inspect the app's `neo-config.json`

Open `apps/earthquakestablewindow/neo-config.json` and note the `useSharedWorkers` entry 

<pre style="color:lightgray">
{
    "appPath": "../../apps/earthquakestablewindow/app.mjs",
    "basePath": "../../",
    "environment": "development",
    "mainPath": "../node_modules/neo.mjs/src/Main.mjs",
    <span style="color:blue">"useSharedWorkers": true,</span>
    "workerBasePath": "../../node_modules/neo.mjs/src/worker/"
}
</pre>

??Clean up the new app

The only thing we need the new app for is its viewport. 

Edit `apps/earthquakestablewindow/MainContainer.mjs` and remove everything except the `className` and the `layout`, and
change the layout to `layout:{ntype:'fit'}`. When you're finished it should look like this.

<pre style="border:thin solid gray; color:gray; font-size:0.8em; padding:1em">
import Viewport from '../../../node_modules/neo.mjs/src/container/Viewport.mjs';

/**
 * @class EarthquakesTableWindow.view.MainContainer
 * @extends Neo.container.Viewport
 */
class MainContainer extends Viewport {
    static config = {
        /**
         * @member {String} className='EarthquakesTableWindow.view.MainContainer'
         * @protected
         */
        className: 'EarthquakesTableWindow.view.MainContainer',
        /*
         * @member {Object} layout={ntype:'fit'}
         */
        layout: {ntype: 'fit'}
    }
}

Neo.setupClass(MainContainer);

export default MainContainer;
</pre>

You're completly finished with EarthquakesTableWindow. 
To avoid confusion, you might want to close any EarthquakesTableWindow 
files you have open in your code editor.



??Have our Earthquakes app use a shared worker too

Both apps need to use a shared worker. To enable that in Earthquakes, edit `apps/earthquakes/neo-config.json` and add the entry for _useSharedWorkers_.

<pre style="color:lightgray">
{
    "appPath": "../../apps/earthquakes/app.mjs",
    "basePath": "../../",
    "environment": "development",
    "mainPath": "../node_modules/neo.mjs/src/Main.mjs",
    <span style="color:blue">"useSharedWorkers": true,</span>
    "workerBasePath": "../../node_modules/neo.mjs/src/worker/"
}
</pre>

??Note a change in how you debug

Chrome Devtools lets you inspect shared workers via the special url `chrome://inspect`. To use it, 
open a new browser window and enter (or copy-and-paste) that exact URL.

Then select the "Shared workers" option on the left, then click on `inspect` by the entry for _neomjs-app-worker_.

<img src="https://s3.amazonaws.com/mjs.neo.learning.images/debugging/ChromeDevToolsInspectWorkers.png"/>

Clicking `inspect` opens a standard debug window, but with a single execution context.

<img src="https://s3.amazonaws.com/mjs.neo.learning.images/debugging/ChromeDevToolsSharedWorkerContext.png"/>

If you run the app and click on a map item, or a table row, you should see the 
console logs being run from your event handlers.

??Add a button used to launch the window

Edit `MainContainer` and add a second item to the items array. This will be after
the map config and before the table config.

    {
        module: Button,
        reference: 'openWindowButton',
        style: {flex: 'none'},
        text: 'Open table in window',
        handler: 'onOpenWindowClick'
    }, 

Save and refresh and you should see the new button between the map and table.
It occupies the full width because the main container is using `align:'stretch'` for
its vbox layout.

??Create the event handler

Now edit `MainContainerController` and add a new member function `onOpenWindowClick`.

The code needs to add a new window using the URL for the EarthquakesTableWindow app.
Neo has a method that runs `window.open()` in the main thread. Here's the code.

    onOpenWindowClick() {
        Neo.Main.windowOpen({
            url: `../earthquakestablewindow`,
            windowName: 'earthquakestablewindow' // This could be _blank or whatever you want
        });
    }

Save and refresh, then click the button &mdash; a browser tab will open running the 
empty EarthquakesTableWindow app.

Close the EarthquakesTableWindow tab.

(Note that we're not bothering adding logic to see if EarthquakesTableWindow is 
already open when launching the Earthquakes app. Therefore, before refreshing
Earthquakes make sure you've closed EarthquakesTableWindow first.)

??Detect when the new window launches

Neo fires an event when applications are connected to the appworker. We need to add a listener
to that event. We'll do that in the main controller's `construct` method. Add this as a 
member method to `MainContainerController`. As you can see, the code adds two listeners
to the appworker: `onAppConnect` and `onAppDisconnect`.

    construct(config) {
        super.construct(config);

        let me = this;
        Neo.currentWorker.on({
            connect: me.onAppConnect,
            disconnect: me.onAppDisconnect,
            scope: me
        });
    }

The disconnect method will run if the user closes the EarthquakesTableWindow window.
We'll use that to move the table back to the main app.

The connect method runs if the EarthquakesTableWindow launches. In other words, 
when `onOpenWindowClick` is run, it opens the EarthquakesTableWindow, which in 
turn triggers the _connect_ event.

??Code `onAppConnect`

This is the code you've been waiting for! And it's pretty simple.

If the newly opened window is EarthquakesTableWindow, then simply remove
the table from the Earthquakes main view, and add it to the EarthquakesTableWindow
main view. Add this instance method to MainContainerController.

    onAppConnect(data) {
        let me = this;
        NeoArray.add(me.connectedApps, data.appName);
        if (data.appName === 'EarthquakesTableWindow'){
            let table = me.getReference('table');
            me.component.remove(table, false) // Params: component, destroy, silent
            Neo.apps.EarthquakesTableWindow.mainView.add(table);
            me.getReference('openWindowButton').hidden = true;
        }
    }

Save your changes, and verify that the EarthquakesTableWindow is _not_ open.
Then click on the _Open table in window_ button. A new tab should appear, holding
the table. The Earthquakes window will just hold the map.

Click on a table row, then look on the map: the corresponding marker highlights!

??Contemplate the moment

This is pretty cool. Seriously.

There's no special code. We're just moving a component from one container to another.
Events are preserved. 

(Note that the map would _not_ have moved in the same way, because the Google map and 
markers are maintained via Google Maps APIs. In contrast, the Earthquakes table is a 
normal Neo component &mdash; Neo components know their own view structure, so can 
easily be mounted in any container, including the new window's viewport. To move the 
map we'd have to write code to fully delete the map in the main view, then add it as 
a new component in EarthquakesTableWindow. It would only be a few lines of code, but 
the difference between the map and table provides some insight into how Neo works.)


??Move the table back when the EarthquakesTableWindow closes
