-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
562 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/*! | ||
* @license | ||
* Copyright (C) 2020 Michael L Haufe | ||
* SPDX-License-Identifier: AGPL-3.0-only | ||
* @see <https://spdx.org/licenses/AGPL-3.0-only.html> | ||
*/ | ||
|
||
import Contracts from '@final-hill/decorator-contracts'; | ||
|
||
const {invariant} = new Contracts(true); | ||
|
||
/** | ||
* An Abstraction is the business domain functionality associated with an Agent | ||
*/ | ||
@invariant | ||
export default class Abstraction {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/*! | ||
* @license | ||
* Copyright (C) 2020 Michael L Haufe | ||
* SPDX-License-Identifier: AGPL-3.0-only | ||
* @see <https://spdx.org/licenses/AGPL-3.0-only.html> | ||
*/ | ||
|
||
enum LayoutOptions { | ||
VERTICAL = 'vertical', | ||
HORIZONTAL = 'horizontal' | ||
} | ||
|
||
export default LayoutOptions; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/*! | ||
* @license | ||
* Copyright (C) 2020 Michael L Haufe | ||
* SPDX-License-Identifier: AGPL-3.0-only | ||
* @see <https://spdx.org/licenses/AGPL-3.0-only.html> | ||
*/ | ||
|
||
import './style.css'; | ||
|
||
import Contracts from '@final-hill/decorator-contracts'; | ||
import LayoutOptions from './LayoutOptions'; | ||
|
||
const {invariant, demands} = new Contracts(true); | ||
|
||
export interface PresentationOptions { | ||
layout?: LayoutOptions; | ||
} | ||
|
||
/** | ||
* A Presentation is the visual representation of an Agent | ||
*/ | ||
@invariant | ||
export default class Presentation { | ||
declare rootElementType: Element; | ||
#rootElement: this['rootElementType']; | ||
|
||
declare containerType: Element; | ||
#containerElement: this['containerType']; | ||
|
||
declare childType: Presentation; | ||
#children: this['childType'][] = []; | ||
|
||
#handlers: Map<string,EventListener> = new Map(); | ||
|
||
constructor(options: PresentationOptions = { | ||
layout: LayoutOptions.VERTICAL | ||
}) { | ||
this.#rootElement = this._initRootElement(); | ||
this.#rootElement.classList.add('agent'); | ||
|
||
// TODO: reference import. dynamic class name | ||
this.#containerElement = this._initContainerElement(); | ||
this.#containerElement.classList.add('agent-content'); | ||
this.setLayout( | ||
options.layout != undefined ? options.layout : LayoutOptions.VERTICAL | ||
); | ||
} | ||
|
||
/** | ||
* Attaches the provided presentation as a child. | ||
* | ||
* @param {Presenation} presentation - The presentation to attach | ||
* @returns {Presentation} - Returns the attached presentation | ||
* @throws - Throws an exception if the provided presentation is already attached | ||
*/ | ||
@demands(function(this: Presentation, presentation: Presentation['childType']){ | ||
return !this.children().includes(presentation); | ||
}) | ||
attachChild(presentation: this['childType']): this['childType'] { | ||
this.#children.push(presentation); | ||
|
||
return presentation; | ||
} | ||
|
||
/** | ||
* Detaches the provided presentation from the container | ||
* | ||
* @param {Presentation} presentation - The presentation to detach | ||
* @returns {Presenation} - Returns the detached presentation | ||
* @throws - Throws an exception if the provided presentation is not a child of this container | ||
*/ | ||
@demands(function(this: Presentation, presentation: Presentation['childType']){ | ||
return this.children().includes(presentation); | ||
}) | ||
detachChild(presentation: this['childType']): this['childType'] { | ||
this.#children = this.#children.filter(child => child !== presentation); | ||
|
||
return presentation; | ||
} | ||
|
||
/** | ||
* Returns a list of the child presentations | ||
* @returns {Presenation[]} - | ||
*/ | ||
children(): this['childType'][] { | ||
return this.#children.slice(); | ||
} | ||
|
||
/** | ||
* Captures all DOM Events and routes them to the appropriate method name | ||
* | ||
* @param {Event} e The raised event | ||
*/ | ||
handleEvent(e: Event): void { | ||
const name = `on${e.type[0].toUpperCase()}${e.type}`; | ||
if(typeof (this as any)[name] == 'function') { | ||
(this as any)[name](e); | ||
} | ||
if(this.#handlers.has(name)) { | ||
this.#handlers.get(e.type)!(e); | ||
} | ||
} | ||
|
||
setLayout(name: LayoutOptions): void { | ||
const cls = this._rootElement.classList; | ||
cls.forEach(cl => { | ||
if (cl.startsWith('layout-')) { | ||
cls.remove(cl); | ||
} | ||
}); | ||
cls.add(`layout-${name}`); | ||
} | ||
|
||
protected _initContainerElement(): this['containerType'] { | ||
return this._rootElement; | ||
} | ||
|
||
protected _initRootElement(): this['rootElementType'] { | ||
return document.createElement('div'); | ||
} | ||
|
||
protected get _rootElement(): this['rootElementType'] { | ||
return this.#rootElement; | ||
} | ||
|
||
protected get _containerElement(): this['containerType'] { | ||
return this.#containerElement; | ||
} | ||
} |
Oops, something went wrong.