import { PageContent } from "../page/pageModel" ; import { StackItem , createElement , getLastStartItem , LastStartNode , StackItemBase , } from "./render" ; import { getHtmlContentElementsFromPage } from "../page/compiler/compiler" ; import { TagType , StructureNode } from "../page/structureTree/structureModel" ; import { isTagItem , CompilerElement , TagItem , } from "../page/compiler/renderers" ; import { store } from ".." ; declare global { namespace JSX { interface IntrinsicElements { "html-editor" : { } ; } } } interface HTMLStackItem extends StackItemBase { children : CompilerElement [ ] ; } interface ChildStackItem { node : TagItem ; } type Stack = Array < StackItem < HTMLStackItem > > ; type ChildStack = Array < ChildStackItem | Element | Text | string > ; export class HtmlEditor extends HTMLElement { public constructor ( ) { super ( ) ; const parent = document . createElement ( "div" ) ; const state = store . getState ( ) ; const page = state . pages [ state . selectedPage ] ; for ( const item of this . render ( page ) ) { parent . appendChild ( item ) ; } const shadow = this . attachShadow ( { mode : "open" } ) ; shadow . appendChild ( parent ) ; } private render ( page ) { let stack = [ ] ; let contentOffset = 0 ; for ( const { children , node , index } of getHtmlContentElementsFromPage ( page ) ) { switch ( node . tagType ) { case TagType . StartTag : { stack . push ( { children , contentOffset , index , node } ) ; contentOffset += node . length ; break ; } case TagType . EndTag : { stack = this . updateStack ( stack ) ; if ( node . tag === "cite" ) { stack . push ( createElement ( "br" , undefined , { contentoffset : contentOffset , ignoreinsync : "true" , isbreak : "true" , } ) ) ; } break ; } case TagType . StartEndTag : { this . addStartEndTag ( stack , node , contentOffset ) ; break ; } default : break ; } } return stack as Element [ ] ; } /**
     * Adds a element for a `StartEnd` tag.
     */ private addStartEndTag ( stack , node , contentOffset ) { switch ( node . tag ) { case "br" : { const props = { contentoffset : contentOffset , isbreak : "true" , key : node . id , } ; stack . push ( createElement ( "br" , props ) ) ; break ; } default : break ; } } /**
     * Returns the updated stack. The last `StructureStackItem` which has a
     * `tagType === TagType.StartTag` is compiled, with all the elements on the
     * stack after the last start tag being children.
     */ private updateStack ( stack ) { const lastStartStackItem = getLastStartItem ( stack as HTMLStackItem [ ] ) ; if ( lastStartStackItem ) { return this . updateItem ( stack , lastStartStackItem ) ; } else { throw new Error ( "There's a mismatch between the number of start and end tags" ) ; } } param stack param lastStartNode private updateItem ( stack , { children , contentOffset , node , stackIndex , } ) { const newStack = stack . slice ( 0 , stackIndex ) ; const childElements = this . createChildElements ( children ) ; const element = createElement ( node . tag , { margin : "0" , padding : "0" , ... node . style } , { ... node . attributes , contentoffset : contentOffset , key : node . id , } , childElements as Array < Element | Text > ) ; newStack . push ( element ) ; return newStack ; } param children private createChildElements ( children ) { let stack = [ ] ; for ( const child of children ) { if ( isTagItem ( child ) ) { switch ( child . tagType ) { case TagType . StartTag : { stack . push ( { node : child } ) ; break ; } case TagType . EndTag : { stack = this . updateChildStack ( stack ) ; break ; } case TagType . StartEndTag : { break ; } default : break ; } } else { stack . push ( document . createTextNode ( child ) ) ; } } return stack as Array < Element | string > ; } param stack private updateChildStack ( stack ) { const lastStart = getLastStartItem ( stack ) ; if ( lastStart ) { return this . updateChildItem ( stack , lastStart ) ; } else { throw new Error ( "There's a mismatch between the number of start and end tags" ) ; } } param stack param lastStartNode private updateChildItem ( stack , { stackIndex , node } ) { const newStack = stack . slice ( 0 , stackIndex ) ; const children = stack . slice ( stackIndex + 1 ) as Element [ ] ; const element = createElement ( node . tag , node . style , undefined , children ) ; newStack . push ( element ) ; return newStack ; } } customElements . define ( "html-editor" , HtmlEditor ) ;