# Design Notes

## Application State

Apart from loading up the navigation and search data, there is only one significant state in the app, which is the document being viewed.
Other state, such as highlighting the current navigation items and bread crumbs can be derived from that state.
The simplest indication of this state is the current `Location#path`, which acts as the single point of truth in the application.

* The document to display is computed from the `path`.
* Navigation to display different documents is achieved by updating the `path`.
* Whether a navigation item should be highlighted as active is computed from the `path`

Navigation between documents can be achieved through changes to the `Location`.

## Concepts

There are three main concepts in the application: documents, navigation and search.

* The document data includes the contents of the document for rendering.
* The search data includes keywords used for building the search index.
* The navigation data contains information about the visual trees that can be rendered in the app to navigate to the documents.

### Documents

Information about documents to be displayed are provided as data that can be fetched from the server.
There are two parts to the data for each document: `DocumentContents`.

* `DocumentContents` contains the actual document that will be rendered. This can be loaded (and then cached) lazily only when the document is to be viewed.

Each document is uniquely identified by the `path` that is also used to fetch its `DocumentContents`.
The `DocumentContents` are stored in JSON files on the server. They are loaded lazily on demand and then cached.

```ts
interface DocumentContents {
  title: string;
  contents: string;
}

type DocumentContentsJSONFile = Array<DocumentContents>;
```

### Navigation

Within an application there can be multiple navigational views for displaying links to documents.
For example, there might be views for the top level `Toolbar` and for the more detailed `SideBar` navigation.

Each view is represented as a tree of `NavigationNode`s. Each `NavigationNode` may, optionally, have a `url`, a `path` and `children`.

```ts
interface NavigationNode {
  title: string;
  url?: string;
  path?: string;
  tooltip?: string;
  target?: string;
  children?: NavigationNode[];
}
```

The `url` property represents a link to an external url outside of the app.
The `path` property identifies the document to display for this navigation `url`. It is used both as the URL segment in the browser and in the request to fetch the document contents.
It is not valid to have both `url` and `path` properties on a single node.
If neither `url` nor `path` properties are then the node is a pure container, in which case it ought to have

The `NavigationNode` data is stored in a JSON file that is fetched from the server at startup

```ts
interface NavigationViews {
  [name: string]: NavigationNode;
}
```

The mapping of a URL back to `NavigationNode` is computed by inverting all the `NavigationNode` structures to produce a `NavigationMap` of URL to node.

```ts
interface NavigationMap {
  [url: string]: NavigationMapItem
}
```

Each `NavigationMapItem` contains information for updating the current navigation views and also caches the `DocumentContents` once it has been loaded.

```ts
interface NavigationMapItem {
  node: NavigationNode;
  parents: NavigationNode[];
  document?: DocumentContents;
}
```



### Search

The `SearchTerms` are stored in a single JSON file that is loaded by the search WebWorker at startup and used to generate the search index.

```ts
interface SearchTerms {
  url: string;
  title: string;
  body: string;
}

type SearchTermsJSONFile = Array<SearchTerms>;
```

## LocationService

Since the core Angular `Location` service does not expose a subject, nor emits events when the location is changed programmatically,
we have our own `LocationService` that does this for us.

```
export class LocationService {
  currentUrl: Observable<string>;
  go(url: string): void
}
```

You can subscribe to the `currentUrl` to be updated when location changes occur.
You should navigate to new documents by calling `go`.

## DocumentService

The `DocumentService` is responsible for monitoring the `LocationService.currentUrl` and updating the `currentDocument`.
When the `currentUrl` changes, the `DocumentService` will fetch the `DocumentContents` from the server if necessary and cache it for the future.

```ts
export class DocumentService {
  currentDocument: Observable<DocumentContents>;
}
```

The mapping of URL path to the path to fetch the document contents is simply:

```ts
  private computePath(url) {
    url = url.startsWith('/') ? url : '/' + url;
    return 'content/docs' + url + '.json';
  }
```

## NavigationService

The `NavigationService` is responsible for:

* fetching and exposing the `NavigationViews` for use in displaying navigation UI.
* building the `NavigationMap` from the `NavigationNode` data.
* updating observables for the currently active `NavigationNode`s that can be used to render the navigation UI
  when the `LocationService.currentUrl` changes.


```ts
class NavigationService {
  navigationViews: Observable<NavigationViews>;
  currentNode: Observable<NavigationNode>;
  activeNodes: Observable<NavigationNode[]>;
}
```

