Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73171e316a | |||
| 8246bf3492 | |||
| 9397e17810 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
316
README.md
316
README.md
@ -1,2 +1,316 @@
|
|||||||
# Gefest
|
# Gefest Framework
|
||||||
|
|
||||||
|
Gefest is a lightweight, TypeScript-based framework for building and managing HTML elements programmatically. It provides a class-based approach to create reusable UI components with built-in support for attributes, classes, styles, and event handling.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Class-based Element Creation**: Define HTML elements as TypeScript classes
|
||||||
|
- **Attribute Management**: Easy setting, getting, and removing of HTML attributes
|
||||||
|
- **CSS Class Handling**: Add and remove classes dynamically
|
||||||
|
- **Style System**: Extensible styling with custom style classes
|
||||||
|
- **Event Handling**: Built-in click event management with automatic re-rendering
|
||||||
|
- **Element Registration**: Automatic ID generation and DOM integration
|
||||||
|
- **Primitive Components**: Pre-built HTML element wrappers
|
||||||
|
- **Dynamic Updates**: Re-render elements on the fly
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Gefest is included as a module in this project. To use it in your TypeScript files:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestEngine, GefestElement } from './engine';
|
||||||
|
import { GefestButton } from './primitives/button';
|
||||||
|
// ... other imports as needed
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Concepts
|
||||||
|
|
||||||
|
### GefestElement
|
||||||
|
|
||||||
|
The base abstract class for all Gefest elements. It provides:
|
||||||
|
|
||||||
|
- Content management (strings or nested elements)
|
||||||
|
- Attribute handling
|
||||||
|
- Class management
|
||||||
|
- Style application
|
||||||
|
- Event binding
|
||||||
|
- Automatic re-rendering on updates
|
||||||
|
|
||||||
|
### GefestEngine
|
||||||
|
|
||||||
|
Manages the lifecycle of Gefest elements:
|
||||||
|
|
||||||
|
- Registers elements with unique IDs
|
||||||
|
- Activates event handlers on DOM elements
|
||||||
|
- Provides the main entry point for applications
|
||||||
|
- Handles re-rendering of updated elements
|
||||||
|
|
||||||
|
### GefestStyle
|
||||||
|
|
||||||
|
Abstract base class for styling systems. Implement custom styles by extending this class.
|
||||||
|
|
||||||
|
## Basic Usage
|
||||||
|
|
||||||
|
### Creating Elements
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestButton } from './primitives/button';
|
||||||
|
|
||||||
|
// Create a simple button
|
||||||
|
const button = new GefestButton("Click me!");
|
||||||
|
console.log(button.build()); // <button data-gefest-id="gefest-abc123">Click me!</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting Attributes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Submit");
|
||||||
|
button.setAttribute('type', 'submit');
|
||||||
|
button.setAttribute('disabled', 'true');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Managing Classes
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Button");
|
||||||
|
button.addClass('btn');
|
||||||
|
button.addClass('btn-primary');
|
||||||
|
button.removeClass('btn');
|
||||||
|
console.log(button.getClassList()); // ['btn-primary']
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hiding Elements
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Hidden Button");
|
||||||
|
button.isHidden = true; // Sets the 'hidden' attribute on the element
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Handling
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Click me!");
|
||||||
|
button.onClick = () => {
|
||||||
|
console.log('Button clicked!');
|
||||||
|
// The framework automatically re-renders after click
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating Elements
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Initial");
|
||||||
|
button.update(); // Re-renders the element in the DOM
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the Application
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestEngine } from './engine';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// Create and configure your elements here
|
||||||
|
const button = new GefestButton("Hello World");
|
||||||
|
button.onClick = () => alert('Hello!');
|
||||||
|
|
||||||
|
// Insert into DOM
|
||||||
|
document.body.innerHTML = button.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
GefestEngine.main(main);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Primitives
|
||||||
|
|
||||||
|
Gefest includes several pre-built primitive elements:
|
||||||
|
|
||||||
|
### GefestButton
|
||||||
|
|
||||||
|
Wraps HTML `<button>` elements.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Click me");
|
||||||
|
button.setAttribute('type', 'submit');
|
||||||
|
```
|
||||||
|
|
||||||
|
### GefestA
|
||||||
|
|
||||||
|
Wraps HTML `<a>` elements.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const link = new GefestA("Visit site", "https://example.com");
|
||||||
|
link.setAttribute('target', '_blank');
|
||||||
|
```
|
||||||
|
|
||||||
|
### GefestImg
|
||||||
|
|
||||||
|
Wraps HTML `<img>` elements.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const image = new GefestImg("", "path/to/image.jpg");
|
||||||
|
image.setAttribute('alt', 'Description');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Other Primitives
|
||||||
|
|
||||||
|
- `GefestP`: Paragraph (`<p>`)
|
||||||
|
- `GefestSpan`: Span (`<span>`)
|
||||||
|
- `GefestHeader`: Header (`<h1>`)
|
||||||
|
- `GefestI`: Italic (`<i>`)
|
||||||
|
- `GefestSmall`: Small text (`<small>`)
|
||||||
|
- `GefestCenter`: Centered content (`<center>`)
|
||||||
|
|
||||||
|
## Advanced Features
|
||||||
|
|
||||||
|
### Nested Elements
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const link = new GefestA("Read more", "#");
|
||||||
|
const button = new GefestButton([link, " about this"]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Elements
|
||||||
|
|
||||||
|
Create your own elements by extending `GefestElement`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestElement } from './element';
|
||||||
|
|
||||||
|
export class GefestDiv extends GefestElement {
|
||||||
|
protected wrapHTML(content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<div ${attrString}>${content}</div>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Styles
|
||||||
|
|
||||||
|
Implement custom styling by extending `GefestStyle`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestStyle, GefestElement } from './style';
|
||||||
|
|
||||||
|
export class BootstrapStyle extends GefestStyle {
|
||||||
|
applyStyle(html: string, element?: GefestElement): string {
|
||||||
|
// Apply Bootstrap classes or inline styles
|
||||||
|
if (element?.getClassList().includes('btn')) {
|
||||||
|
return html.replace('<button', '<button class="btn btn-primary"');
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply styles to elements:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const button = new GefestButton("Styled Button");
|
||||||
|
button.style = new BootstrapStyle();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Parsing HTML
|
||||||
|
|
||||||
|
Convert existing HTML strings to Gefest elements:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const element = GefestElement.fromHTML('<button class="btn">Click</button>');
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
### GefestElement
|
||||||
|
|
||||||
|
#### Properties
|
||||||
|
- `gefestId: string` - Unique identifier for the element (readonly)
|
||||||
|
- `style: GefestStyle | null` - Style to apply to the element
|
||||||
|
- `onClick: (() => void) | null` - Click event handler (getter/setter)
|
||||||
|
- `isHidden: boolean` - Whether the element should be hidden (sets the 'hidden' attribute when true)
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
- `constructor(content: (GefestElement | string)[] | string)`
|
||||||
|
- `build(isFromStyle?: boolean): string`
|
||||||
|
- `update(): void` - Re-renders the element in the DOM
|
||||||
|
- `setAttribute(key: string, value: string): void`
|
||||||
|
- `getAttribute(key: string): string | undefined`
|
||||||
|
- `removeAttribute(key: string): void`
|
||||||
|
- `addClass(className: string): void`
|
||||||
|
- `removeClass(className: string): void`
|
||||||
|
- `getClassList(): string[]`
|
||||||
|
- `setPersonalStyle(style: string | null): void`
|
||||||
|
|
||||||
|
#### Static Methods
|
||||||
|
- `fromHTML(html: string): GefestElement`
|
||||||
|
|
||||||
|
### GefestEngine
|
||||||
|
|
||||||
|
#### Static Methods
|
||||||
|
- `register(element: GefestElement): string`
|
||||||
|
- `activateOnClick(): Promise<void>`
|
||||||
|
- `main(main: () => Promise<void>): Promise<void>`
|
||||||
|
- `reRenderByGI(gefestId: string): void`
|
||||||
|
|
||||||
|
### GefestStyle
|
||||||
|
|
||||||
|
#### Methods
|
||||||
|
- `applyStyle(html: string, element?: GefestElement): string`
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Complete Application
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestEngine } from './engine';
|
||||||
|
import { GefestButton, GefestP } from './primitives';
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const title = new GefestP("Welcome to Gefest!");
|
||||||
|
title.addClass('title');
|
||||||
|
|
||||||
|
const button = new GefestButton("Get Started");
|
||||||
|
button.addClass('start-btn');
|
||||||
|
button.onClick = () => {
|
||||||
|
alert('Welcome!');
|
||||||
|
};
|
||||||
|
|
||||||
|
// For custom elements, define them as shown above
|
||||||
|
const container = new (class extends GefestElement {
|
||||||
|
protected wrapHTML(content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<div ${attrString}>${content}</div>`;
|
||||||
|
}
|
||||||
|
})([title, button]);
|
||||||
|
container.addClass('container');
|
||||||
|
|
||||||
|
document.body.innerHTML = container.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
GefestEngine.main(main);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Form Creation
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { GefestButton } from './primitives/button';
|
||||||
|
|
||||||
|
const submitBtn = new GefestButton("Submit");
|
||||||
|
submitBtn.setAttribute('type', 'submit');
|
||||||
|
submitBtn.addClass('btn-submit');
|
||||||
|
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.innerHTML = submitBtn.build();
|
||||||
|
document.body.appendChild(form);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
To add new primitives or extend the framework:
|
||||||
|
|
||||||
|
1. Create new classes extending `GefestElement`
|
||||||
|
2. Implement the `wrapHTML` method to return the appropriate HTML tag
|
||||||
|
3. Add event handling if needed
|
||||||
|
4. Test with `GefestEngine.main()`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This framework is part of the AmeVox project. See project license for details.
|
||||||
|
|||||||
25
package-lock.json
generated
Normal file
25
package-lock.json
generated
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "Gefest",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^6.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
package.json
Normal file
5
package.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^6.0.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
221
src/element.ts
Normal file
221
src/element.ts
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import { GefestEngine } from './engine';
|
||||||
|
import { GefestStyle } from './style';
|
||||||
|
|
||||||
|
// The general class of Gefest
|
||||||
|
export abstract class GefestElement {
|
||||||
|
style: GefestStyle | null = null;
|
||||||
|
isHidden: boolean = false;
|
||||||
|
//onClick: (() => void) | null = null;
|
||||||
|
readonly gefestId: string;
|
||||||
|
protected content: (GefestElement | string)[] | string;
|
||||||
|
protected attributes: Record<string, string> = {};
|
||||||
|
protected classList: Set<string> = new Set();
|
||||||
|
|
||||||
|
protected clickHandler: (() => void) | null = null;
|
||||||
|
|
||||||
|
set onClick(handler: (() => void) | null) {
|
||||||
|
if (handler) {
|
||||||
|
this.clickHandler = handler;
|
||||||
|
} else {
|
||||||
|
this.clickHandler = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get onClick(): (() => void) | null {
|
||||||
|
if (this.clickHandler === null)
|
||||||
|
return null;
|
||||||
|
return () => {
|
||||||
|
this.clickHandler!();
|
||||||
|
GefestEngine.activateOnClick();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the element from an HTML string.
|
||||||
|
* @param html The HTML string to parse.
|
||||||
|
* @returns The created GefestElement.
|
||||||
|
*/
|
||||||
|
static fromHTML(html: string): GefestElement {
|
||||||
|
const htmlElement = new DOMParser().parseFromString(html, 'text/html').body.firstChild as HTMLElement;
|
||||||
|
const element = new (class extends GefestElement {
|
||||||
|
protected wrapHTML(content: string): string {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
})(htmlElement.innerHTML);
|
||||||
|
|
||||||
|
for (const attr of htmlElement.attributes) {
|
||||||
|
try {
|
||||||
|
element.setAttribute(attr.name, attr.value);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const className of htmlElement.classList) {
|
||||||
|
element.addClass(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the element.
|
||||||
|
* @param content The content for the element. Can be a string, an array of strings, an array of GefestElements or a combination of both.
|
||||||
|
*/
|
||||||
|
constructor (content : (GefestElement | string)[] | string = []) {
|
||||||
|
this.gefestId = GefestEngine.register(this);
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Call to GefestEngine for rerender element
|
||||||
|
*/
|
||||||
|
update (): void {
|
||||||
|
GefestEngine.reRenderByGI(this.gefestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the element and returns it as a string. If the element has a style, it applies the style to the rendered HTML.
|
||||||
|
* @param isFromStyle Indicates if the build is being called from a style application. This prevents infinite recursion when applying styles.
|
||||||
|
* @returns The built element as a string.
|
||||||
|
*/
|
||||||
|
build (isFromStyle: boolean = false): string {
|
||||||
|
if (this.isHidden)
|
||||||
|
this.setAttribute('hidden', '');
|
||||||
|
else
|
||||||
|
this.removeAttribute('hidden');
|
||||||
|
|
||||||
|
if (!isFromStyle)
|
||||||
|
return this.applyStyle(this.render(), this);
|
||||||
|
return this.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an attribute key is reserved.
|
||||||
|
* @param key The attribute key.
|
||||||
|
*/
|
||||||
|
checkReservedAttribute(key: string): void {
|
||||||
|
if (({ "style": true, "class": true })[key])
|
||||||
|
throw new Error(`The attribute "${
|
||||||
|
key
|
||||||
|
}" is reserved. Use the setPersonalStyle method for styles and setClass method for classes.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a personal style for the element. This will be applied on top of any style that is set for the element.
|
||||||
|
* @param style The personal style to set. If null, the personal style will be removed.
|
||||||
|
*/
|
||||||
|
setPersonalStyle(style: string | null): void {
|
||||||
|
if (style === null) {
|
||||||
|
delete this.attributes.style;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.attributes.style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a class to the element's class list and updates the "class" attribute accordingly.
|
||||||
|
* @param className The class name to add.
|
||||||
|
*/
|
||||||
|
addClass(className: string): void {
|
||||||
|
this.classList.add(className);
|
||||||
|
this.attributes.class = Array.from(this.classList).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a class from the element's class list and updates the "class" attribute accordingly.
|
||||||
|
* @param className The class name to remove.
|
||||||
|
*/
|
||||||
|
removeClass(className: string): void {
|
||||||
|
this.classList.delete(className);
|
||||||
|
this.attributes.class = Array.from(this.classList).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of classes for the element.
|
||||||
|
* @returns The array of class names.
|
||||||
|
*/
|
||||||
|
getClassList(): string[] {
|
||||||
|
return Array.from(this.classList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an attribute for the element.
|
||||||
|
* @param key The attribute key.
|
||||||
|
* @param value The attribute value.
|
||||||
|
*/
|
||||||
|
setAttribute (key: string, value: string): void {
|
||||||
|
this.checkReservedAttribute(key);
|
||||||
|
this.attributes[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an attribute value by its key.
|
||||||
|
* @param key The attribute key.
|
||||||
|
* @returns The attribute value or undefined if not found.
|
||||||
|
*/
|
||||||
|
getAttribute (key: string): string | undefined {
|
||||||
|
return this.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an attribute by its key.
|
||||||
|
* @param key The attribute key.
|
||||||
|
*/
|
||||||
|
removeAttribute (key: string): void {
|
||||||
|
this.checkReservedAttribute(key);
|
||||||
|
delete this.attributes[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the element's style to the given HTML.
|
||||||
|
* @param html The HTML to apply the style to.
|
||||||
|
* @returns The styled HTML.
|
||||||
|
*/
|
||||||
|
protected applyStyle(html: string, element?: GefestElement): string {
|
||||||
|
if (this.style)
|
||||||
|
return this.style.applyStyle(html, element);
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the element's attributes to a string.
|
||||||
|
* @returns The attributes string.
|
||||||
|
*/
|
||||||
|
protected attributesToString (): string {
|
||||||
|
return Object.entries(this.attributes)
|
||||||
|
.map(([key, value]) => `${key}="${value}"`)
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the given content in HTML tags.
|
||||||
|
* @param content The content to wrap.
|
||||||
|
* @returns The wrapped HTML.
|
||||||
|
*/
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<div ${attrString}>${content}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the element and returns it as a string.
|
||||||
|
* @returns The rendered element as a string.
|
||||||
|
*/
|
||||||
|
protected render (): string {
|
||||||
|
if (typeof this.content === 'string') {
|
||||||
|
return this.wrapHTML(this.content);
|
||||||
|
}
|
||||||
|
const rendered : string[] = [];
|
||||||
|
for (const item of this.content) {
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
rendered.push(this.applyStyle(this.wrapHTML(item)));
|
||||||
|
}
|
||||||
|
else if (item instanceof GefestElement) {
|
||||||
|
if (!item.style && this.style) {
|
||||||
|
item.style = this.style;
|
||||||
|
}
|
||||||
|
rendered.push(item.build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.wrapHTML(rendered.join(''));
|
||||||
|
}
|
||||||
|
}
|
||||||
43
src/engine.ts
Normal file
43
src/engine.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { GefestElement } from "./element";
|
||||||
|
|
||||||
|
// For protecting the set of elements from direct access
|
||||||
|
const elements: Set<GefestElement> = new Set();
|
||||||
|
const elementsMapping: Map<string, GefestElement> = new Map<string, GefestElement> ();
|
||||||
|
export class GefestEngine {
|
||||||
|
static register (element: GefestElement) : string {
|
||||||
|
elements.add(element);
|
||||||
|
// Generate GefestID for the element
|
||||||
|
const gefestId = `gefest-${Math.random().toString(36).substr(2, 9)}`;
|
||||||
|
element.setAttribute('data-gefest-id', gefestId);
|
||||||
|
elementsMapping.set(gefestId, element);
|
||||||
|
|
||||||
|
return gefestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async activateOnClick(): Promise<void> {
|
||||||
|
for (let element of elements) {
|
||||||
|
const elementHTML = document.querySelectorAll(`[data-gefest-id="${element.gefestId}"]`);
|
||||||
|
if (elementHTML.length > 0) {
|
||||||
|
const htmlElement = elementHTML[0] as HTMLElement;
|
||||||
|
htmlElement.onclick = element.onClick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async main(main : () => Promise<void>): Promise<void> {
|
||||||
|
await main();
|
||||||
|
await GefestEngine.activateOnClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
static reRenderByGI (gefestId: string) {
|
||||||
|
const gefestElement = elementsMapping.get(gefestId);
|
||||||
|
if (!gefestElement) return;
|
||||||
|
const elementHTML = document.querySelectorAll(`[data-gefest-id="${gefestId}"]`);
|
||||||
|
|
||||||
|
if (elementHTML.length > 0) {
|
||||||
|
const htmlElement = elementHTML[0] as HTMLElement;
|
||||||
|
htmlElement.outerHTML = gefestElement.build();
|
||||||
|
GefestEngine.activateOnClick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/primitives/a.ts
Normal file
14
src/primitives/a.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestA extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string, href: string | null = null) {
|
||||||
|
super(content);
|
||||||
|
if (href !== null)
|
||||||
|
this.setAttribute('href', href);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<a ${attrString}>${content}</a>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/button.ts
Normal file
12
src/primitives/button.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestButton extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<button ${attrString}>${content}</button>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/center.ts
Normal file
12
src/primitives/center.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestCenter extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<center ${attrString}>${content}</center>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/primitives/header.ts
Normal file
16
src/primitives/header.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
type HeaderLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
||||||
|
|
||||||
|
export class GefestHeader extends GefestElement {
|
||||||
|
protected level: HeaderLevel;
|
||||||
|
constructor(content : (GefestElement | string)[] | string, level : HeaderLevel = 1) {
|
||||||
|
super(content);
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<h${this.level} ${attrString}>${content}</h${this.level}>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/i.ts
Normal file
12
src/primitives/i.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestI extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<i ${attrString}>${content}</i>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/primitives/img.ts
Normal file
13
src/primitives/img.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestImg extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string, src: string) {
|
||||||
|
super(content);
|
||||||
|
this.setAttribute('src', src);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<img ${attrString}>${content}</img>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/p.ts
Normal file
12
src/primitives/p.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestP extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<p ${attrString}>${content}</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/small.ts
Normal file
12
src/primitives/small.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestSmall extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<small ${attrString}>${content}</small>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/primitives/span.ts
Normal file
12
src/primitives/span.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { GefestElement } from "../element";
|
||||||
|
|
||||||
|
export class GefestSpan extends GefestElement {
|
||||||
|
constructor(content : (GefestElement | string)[] | string) {
|
||||||
|
super(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected wrapHTML (content: string): string {
|
||||||
|
const attrString = this.attributesToString();
|
||||||
|
return `<span ${attrString}>${content}</span>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/style.ts
Normal file
7
src/style.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { GefestElement } from "./element";
|
||||||
|
|
||||||
|
export abstract class GefestStyle {
|
||||||
|
applyStyle (html: string, element ?: GefestElement): string {
|
||||||
|
throw new Error('You need to implement the applyStyle method in the child class');
|
||||||
|
}
|
||||||
|
}
|
||||||
44
tsconfig.json
Normal file
44
tsconfig.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
// Visit https://aka.ms/tsconfig to read more about this file
|
||||||
|
"compilerOptions": {
|
||||||
|
// File Layout
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
|
||||||
|
// Environment Settings
|
||||||
|
// See also https://aka.ms/tsconfig/module
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "ES2020",
|
||||||
|
"types": [],
|
||||||
|
// For nodejs:
|
||||||
|
// "lib": ["esnext"],
|
||||||
|
// "types": ["node"],
|
||||||
|
// and npm install -D @types/node
|
||||||
|
|
||||||
|
// Other Outputs
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
|
||||||
|
// Stricter Typechecking Options
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
|
||||||
|
// Style Options
|
||||||
|
// "noImplicitReturns": true,
|
||||||
|
// "noImplicitOverride": true,
|
||||||
|
// "noUnusedLocals": true,
|
||||||
|
// "noUnusedParameters": true,
|
||||||
|
// "noFallthroughCasesInSwitch": true,
|
||||||
|
// "noPropertyAccessFromIndexSignature": true,
|
||||||
|
|
||||||
|
// Recommended Options
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"verbatimModuleSyntax": false,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user