import dom from './DOM.js'
import Router from './Router.js'
import Component from './Component.js'
import Localizer from './Localizer.js'
import EventHandler from './EventHandler.js'
/**
`App` contains the orchestration logic for the entirety of what is being displayed for a given app, including the app chrome like navigation.
App communicates these changes to {@link Component}s via events so that they may react.
The [hello-world example](https://github.com/Transmutable/bink/blob/main/examples/hello-world/site.js) has the most basic App and the [components example](https://github.com/Transmutable/bink/blob/main/examples/components/site.js) is more complex.
@example <caption>Set up a basic user administration page</caption>
* import { AdminApp } from '{some path}/App.js'
* import { UpdateBioComponent } from './UpdateBioComponent.js'
* import { ResetPasswordComponent } from './ResetPasswordComponent.js'
* import { UpdatePortraitComponent } from './UpdatePortraitComponent.js'
* import { UserModel } from './UserModel.js'
*
* class AdminApp extends App {
* constructor(){
* // Get user model (see DataObject, DataModel, and DataCollection docs)
* this.dataObject = new UserModel()
* this.dataObject.fetch().catch(err => { ... handle error ... })
*
* // Set up the masthead
* this._masthead = new MastheadComponent(
* undefined,
* {
* brand: 'Your Brand',
* brandAnchor: '/',
* menuItems: [
* { name: 'Bio', anchor: '#' },
* { name: 'Password', anchor: '#password' },
* { name: 'Portrait', anchor: '#portrait' }
* ]
* }
* ).appendTo(this)
*
* // Set up three sub-views with Components (see Component docs)
* this._bioComponent = new UpdateBioComponent(this.dataObject).appendTo(this)
* this._passwordComponent = new ResetPasswordComponent(this.dataObject).appendTo(this)
* this._portraitComponent = new UpdatePortraitComponent(this.dataObject).appendTo(this)
*
* // Set up the Router (see Router docs)
* this._router = new Router()
* this._router.addRoute(/^$/, 'default')
* this._router.addRoute(/^password$/, 'password')
* this._router.addRoute(/^portait$/, 'portrait')
* router.addListener('blog-app', (routeName) => {
* switch (routeName) {
* case 'default':
* this._bioComponent.show()
* this._passwordComponent.hide()
* this._portraitComponent.hide()
* break
* case 'password':
* this._bioComponent.hide()
* this._passwordComponent.show()
* this._portraitComponent.hide()
* break
* case 'portrait'
* this._bioComponent.hide()
* this._passwordComponent.hide()
* this._portraitComponent.show()
* break
* }
* })
* }
* }
*/
const App = class extends EventHandler {
/**
@param {Object} [options={}]
@param {HTMLElement} [options.dom=div]
*/
constructor(options = {}) {
super()
this._options = options
this._router = new Router()
this._dom = this._options.dom || dom.div()
this._dom.addClass('app')
}
/** @type {Router} */
get router() {
return this._router
}
/** @type {HTMLElement} */
get dom() {
return this._dom
}
/**
Adds the childComponent's `dom` to this Component's `dom`.
@param {Component} childComponent
@return {App} - this App, handy for chaining
*/
append(childComponent) {
this._dom.appendChild(childComponent.dom)
return this
}
/**
Removes the childComponent's `dom` from this Component's `dom`.
@param {Component} childComponent
@return {App} - this App, handy for chaining
*/
removeComponent(childComponent) {
this._dom.removeChild(childComponent.dom)
return this
}
/**
@param {boolean} shouldGather - true if the {@link Localizer} should be tracking translations
*/
set localizerGathering(shouldGather) {
Localizer.Singleton.gathering = shouldGather
}
/** @type {boolean} */
get localizerGathering() {
return Localizer.Singleton.gathering
}
/** @type {boolean} */
get localizerGatheredData() {
return Localizer.Singleton.gatheredData
}
}
export default App
export { App }