cleanup and comments
All checks were successful
Build and Deploy Client / build-and-deploy (push) Successful in 8s

This commit is contained in:
2026-08-30 13:28:16 -05:00
parent b4142781dd
commit 99a4f5c1c8
2 changed files with 45 additions and 56 deletions

View File

@@ -1,7 +1,4 @@
<form [formGroup]="markupInput" (ngSubmit)="onSubmit()">
<textarea formControlName="inputText"></textarea>
<button>Render</button>
</form>
<textarea [(ngModel)]="liveText" (ngModelChange)="onTextUpdate($event)"></textarea>
<div #markup_container class="markup_container"></div> <div #markup_container class="markup_container"></div>

View File

@@ -1,18 +1,24 @@
import { Component, ElementRef, Renderer2, ViewChild } from '@angular/core'; import { Component, ElementRef, Renderer2, ViewChild } from '@angular/core';
import { ReactiveFormsModule, FormsModule, FormControl, FormGroup, FormBuilder } from '@angular/forms'; import { FormsModule } from '@angular/forms'
// type descriptions // type descriptions
// a formatDescriptor contains information for the renderer to apply formatting styles to a node
interface formatDescriptor { interface formatDescriptor {
className: string; className: string;
}; };
// a textNode is an element produced by the parser to link text to applied format specifiers. The renderer will
// apply each style to the text in the node according to the styles registry.
interface textNode { interface textNode {
type: string; type: string;
text: string; text: string;
styles: string[] styles: string[]
} }
// a blockNode is an element produced by the parser to structure nodes by blocks. blocks contain child nodes, either
// other blocks or text nodes at the bottom. A block node's html element type is described by kind: p, h1, h2, div, etc
// Maybe we blocks can also have styles, and then we can join textNode and blockNode into a single type.
interface blockNode { interface blockNode {
type: string; type: string;
kind: string; kind: string;
@@ -20,6 +26,7 @@ interface blockNode {
} }
// styles registry: this maps format specifiers to css classes // styles registry: this maps format specifiers to css classes
// might move this to its own file
const styles: Record<string, formatDescriptor> = { const styles: Record<string, formatDescriptor> = {
B: { B: {
className: "format-bold" className: "format-bold"
@@ -35,9 +42,10 @@ const styles: Record<string, formatDescriptor> = {
}, },
}; // i.e. %B{...} will apply "format-bold" }; // i.e. %B{...} will apply "format-bold"
// angular component class
@Component({ @Component({
selector: 'app-markleft', selector: 'app-markleft',
imports: [FormsModule, ReactiveFormsModule], imports: [FormsModule],
templateUrl: './markleft.html', templateUrl: './markleft.html',
styleUrl: './markleft.scss', styleUrl: './markleft.scss',
}) })
@@ -45,41 +53,36 @@ export class Markleft {
@ViewChild('markup_container', { static: true }) container!: ElementRef; @ViewChild('markup_container', { static: true }) container!: ElementRef;
constructor(private renderer: Renderer2, private fb: FormBuilder) { constructor(private renderer: Renderer2) {
console.log("component constructor"); // console.log("component constructor");
} }
ngOnInit() { // DOM manipulation can't occur in constructor ngOnInit() { // DOM manipulation can't occur in constructor
this.markupInput = this.fb.group({
inputText: [this.liveText],
});
this.refresh(); this.refresh();
} }
markupInput = new FormGroup({ // live update on each text input.
inputText: new FormControl("") onTextUpdate(event: Event) {
});
onSubmit() {
this.refresh(); this.refresh();
} }
// full demo right here // default text
liveText: string = ` liveText: string = `
#H{Hello World!} #H{Hello World!}
#P{ #P{
This is some markleft text. This is %I{italic} and this is %B{bold}. Some might %I{even be %B{both}}. This is some %B{PhAML} (%I{%B{Ph}ish %B{A}mazing %B{M}arkup %B{L}anguage}) text. This is %I{italic} and this is %B{bold}. Some might %I{even be %B{both}}.
} }
This should be plain and unstylized. This should be plain and unstylized.
`; // TODO: live editor `; // TODO: live editor
// parses a single string into an array of nodes
// like noted at parseStyle, maybe can return a single node which itself contains the array of children.
parsePlaintext(input: string): (textNode | blockNode)[] { parsePlaintext(input: string): (textNode | blockNode)[] {
let index: number = 0; let index: number = 0; // position in the input string
let nodes: (textNode | blockNode)[] = []; let nodes: (textNode | blockNode)[] = [];
// TODO: I might restructure the node parsing so that it starts with a generic top level node and can process all children under that node
function parseStyle(parentNode: blockNode | null = null, parentStyles: string[] | null = null) { function parseStyle(parentNode: blockNode | null = null, parentStyles: string[] | null = null) {
index++; // step onto specifier code index++; // step onto specifier code
@@ -104,19 +107,11 @@ export class Markleft {
if(input[index] === "%") { // encountered another style specifier if(input[index] === "%") { // encountered another style specifier
// commit the current node // commit the current node
const node: textNode = { addTextNode(text, styles, parentNode);
type: "text",
text: text,
styles: styles
};
if(parentNode) {
parentNode.children.push(node);
} else {
nodes.push(node);
}
text = ""; // clear the already commited text text = ""; // clear the already commited text
// and then move to the next // and then move to the next
parseStyle(parentNode ? parentNode : null, styles); // recursion parseStyle(parentNode ? parentNode : null, styles); // recursion
} else if(input[index] == "}") { // this node has closed } else if(input[index] == "}") { // this node has closed
addTextNode(text, styles, parentNode); addTextNode(text, styles, parentNode);
//index++; // step to next //index++; // step to next
@@ -127,6 +122,9 @@ export class Markleft {
text += input[index]; text += input[index];
} }
} }
if(index >= input.length) {
break;
}
} }
} }
@@ -152,15 +150,7 @@ export class Markleft {
index++; index++;
if(input[index] === "%" || input[index] === "#") { // encountered another format specifier if(input[index] === "%" || input[index] === "#") { // encountered another format specifier
// commit current plain text to the block addTextNode(text, null, node);
if(text.length !== 0) {
const textNode: textNode = {
type: "text",
text: text,
styles: [] // none
};
node.children.push(textNode);
}
text = ""; // clear the already commited text text = ""; // clear the already commited text
// and then move to the next // and then move to the next
@@ -188,6 +178,9 @@ export class Markleft {
text += input[index]; text += input[index];
} }
} }
if(index >= input.length) {
break;
}
} }
} }
@@ -297,7 +290,6 @@ export class Markleft {
} }
refresh() { refresh() {
if(this.markupInput.value.inputText) {
// clear children // clear children
const parent = this.container.nativeElement; const parent = this.container.nativeElement;
@@ -306,7 +298,7 @@ export class Markleft {
} }
// parse text // parse text
const nodes: (textNode | blockNode)[] = this.parsePlaintext(this.markupInput.value.inputText); const nodes: (textNode | blockNode)[] = this.parsePlaintext(this.liveText);
// console.log(nodes) // console.log(nodes)
@@ -314,6 +306,6 @@ export class Markleft {
nodes.forEach((node) => { nodes.forEach((node) => {
this.renderNode(node); this.renderNode(node);
}); });
}
} }
} }