2021-05-13 14:50:54 +08:00
|
|
|
import { Panel } from "../ui/panel"
|
|
|
|
import { Group } from "../ui/view"
|
|
|
|
import { ClassType } from "../util/types"
|
2021-05-18 11:41:18 +08:00
|
|
|
import { ViewHolder, ViewModel } from "./mvvm"
|
2021-05-14 13:14:54 +08:00
|
|
|
import { Provider } from "./provider"
|
2021-05-13 14:50:54 +08:00
|
|
|
|
2021-05-13 16:57:21 +08:00
|
|
|
export abstract class Module extends Panel {
|
|
|
|
superPanel?: ModularPanel
|
|
|
|
|
2021-05-14 13:14:54 +08:00
|
|
|
__provider?: Provider
|
|
|
|
|
|
|
|
get provider(): Provider | undefined {
|
|
|
|
return this.__provider || (this.superPanel?.provider)
|
|
|
|
}
|
|
|
|
|
|
|
|
set provider(provider: Provider | undefined) {
|
|
|
|
this.__provider = provider
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:41:18 +08:00
|
|
|
private unmounted = false
|
|
|
|
|
|
|
|
mount() {
|
|
|
|
if (this.unmounted) {
|
|
|
|
this.unmounted = false
|
|
|
|
this.superPanel?.onStructureChanged(this, true)
|
|
|
|
this.onMounted()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unmount() {
|
|
|
|
if (!this.unmounted) {
|
|
|
|
this.unmounted = true
|
|
|
|
this.superPanel?.onStructureChanged(this, false)
|
|
|
|
this.onUnmounted()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get mounted() {
|
|
|
|
return !this.unmounted
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Dispatch message to other modules.
|
|
|
|
* @param message which is sent out
|
|
|
|
*/
|
2021-05-13 16:57:21 +08:00
|
|
|
dispatchMessage(message: any) {
|
|
|
|
this.superPanel?.dispatchMessage(message)
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:41:18 +08:00
|
|
|
/**
|
|
|
|
* Dispatched messages can be received by override this method.
|
|
|
|
* @param message recevied message
|
|
|
|
*/
|
2021-05-13 16:57:21 +08:00
|
|
|
onMessage(message: any) { }
|
2021-05-18 11:41:18 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when this module is mounted
|
|
|
|
*/
|
|
|
|
onMounted() { }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when this module is unmounted
|
|
|
|
*/
|
|
|
|
onUnmounted() { }
|
|
|
|
}
|
|
|
|
|
|
|
|
export abstract class VMModule<M extends Object, V extends ViewHolder> extends Module {
|
|
|
|
private vm?: ViewModel<M, V>
|
|
|
|
private vh?: V
|
|
|
|
abstract getViewModelClass(): ClassType<ViewModel<M, V>>
|
|
|
|
|
|
|
|
abstract getState(): M
|
|
|
|
|
|
|
|
abstract getViewHolderClass(): ClassType<V>
|
|
|
|
|
|
|
|
getViewModel() {
|
|
|
|
return this.vm
|
|
|
|
}
|
|
|
|
|
|
|
|
build(root: Group): void {
|
|
|
|
this.vh = new (this.getViewHolderClass())
|
|
|
|
this.vm = new (this.getViewModelClass())(this.getState(), this.vh)
|
|
|
|
this.vm.context = this.context
|
|
|
|
this.vm.attach(root)
|
|
|
|
}
|
2021-05-13 16:57:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export abstract class ModularPanel extends Module {
|
2021-05-13 14:50:54 +08:00
|
|
|
private modules: Panel[]
|
2021-05-18 11:41:18 +08:00
|
|
|
private scheduledRebuild?: NodeJS.Timeout
|
2021-05-13 16:57:21 +08:00
|
|
|
|
2021-05-13 14:50:54 +08:00
|
|
|
constructor() {
|
|
|
|
super()
|
2021-05-13 16:57:21 +08:00
|
|
|
this.modules = this.setupModules().map(e => {
|
|
|
|
const instance = new e
|
|
|
|
if (instance instanceof Module) {
|
|
|
|
instance.superPanel = this
|
|
|
|
}
|
|
|
|
return instance
|
|
|
|
})
|
2021-05-13 14:50:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
abstract setupModules(): ClassType<Panel>[]
|
2021-05-13 16:57:21 +08:00
|
|
|
|
2021-05-13 14:50:54 +08:00
|
|
|
abstract setupShelf(root: Group): Group
|
|
|
|
|
2021-05-13 16:57:21 +08:00
|
|
|
dispatchMessage(message: any) {
|
|
|
|
if (this.superPanel) {
|
|
|
|
this.superPanel.dispatchMessage(message)
|
|
|
|
} else {
|
|
|
|
this.onMessage(message)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:41:18 +08:00
|
|
|
get mountedModules() {
|
|
|
|
return this.modules.filter(e => !(e instanceof Module) || e.mounted)
|
|
|
|
}
|
|
|
|
|
2021-05-13 16:57:21 +08:00
|
|
|
onMessage(message: any) {
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 16:57:21 +08:00
|
|
|
if (e instanceof Module) {
|
|
|
|
e.onMessage(message)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-18 11:41:18 +08:00
|
|
|
onStructureChanged(module: Module, mounted: boolean) {
|
|
|
|
if (this.superPanel) {
|
|
|
|
this.superPanel.onStructureChanged(module, mounted)
|
|
|
|
} else {
|
|
|
|
if (!!!this.scheduledRebuild) {
|
|
|
|
this.scheduledRebuild = setTimeout(() => {
|
|
|
|
this.scheduledRebuild = undefined
|
|
|
|
this.getRootView().children.length = 0
|
|
|
|
this.build(this.getRootView())
|
|
|
|
}, 0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-13 16:57:21 +08:00
|
|
|
|
2021-05-13 14:50:54 +08:00
|
|
|
build(root: Group) {
|
|
|
|
const groupView = this.setupShelf(root)
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 14:50:54 +08:00
|
|
|
Reflect.set(e, "__root__", groupView)
|
|
|
|
e.build(groupView)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
onCreate() {
|
|
|
|
super.onCreate()
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 16:26:48 +08:00
|
|
|
e.context = this.context
|
2021-05-13 14:50:54 +08:00
|
|
|
e.onCreate()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
onDestroy() {
|
|
|
|
super.onDestroy()
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 14:50:54 +08:00
|
|
|
e.onDestroy()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
onShow() {
|
|
|
|
super.onShow()
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 14:50:54 +08:00
|
|
|
e.onShow()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
onHidden() {
|
|
|
|
super.onHidden()
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 14:50:54 +08:00
|
|
|
e.onHidden()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
onRenderFinished() {
|
|
|
|
super.onRenderFinished()
|
2021-05-18 11:41:18 +08:00
|
|
|
this.mountedModules.forEach(e => {
|
2021-05-13 14:50:54 +08:00
|
|
|
e.onRenderFinished()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|