diff --git a/aio/src/NOTES.md b/aio/src/NOTES.md new file mode 100644 index 0000000000..19e1115578 --- /dev/null +++ b/aio/src/NOTES.md @@ -0,0 +1,159 @@ +# 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; +``` + +### 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; +``` + +## 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; + 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; +} +``` + +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; + currentNode: Observable; + activeNodes: Observable; +} +``` +