template.js

/** @module template */

import { Parser, BBDocument, BBNode } from "@thoughtsunificator/bbcode-parser"
import Conversion from "./conversion.js"

class Template {

	/**
	 * @param   {Code[]} codes
	 * @param   {Document} document
	 */
	constructor(codes, document) {
		this._codes = codes
		this._document = document
	}

	/**
	 * @readonly
	 * @type {Code[]}
	 */
	get codes() {
		return this._codes
	}

	/**
	 * @readonly
	 * @type {Document}
	 */
	get document() {
		return this._document
	}

	/**
	 * Convert BBcode string to HTML string
	 * @param  {string} input
	 * @return {string}
	 */
	toHTML(input) {
		const bbDocument = Parser.parse(input)
		const conversion = new Conversion(bbDocument, this.document)
		const treeWalker = bbDocument.createTreeWalker(bbDocument.documentElement)
		while (treeWalker.nextNode()) {
			conversion.nodeList.push(treeWalker.currentNode)
		}
		const rootNode = this.document.createElement("div")
		for(const bbNode of conversion.nodeList) {
			conversion.bbNode = bbNode
			conversion.tags = null
			conversion.code = null
			conversion.node = null
			conversion.parentMatch = null
			if (conversion.ignoreNodeList.indexOf(bbNode) !== -1) {
				continue
			}
			if (bbNode.nodeType === BBNode.ELEMENT_BBNODE) {
				conversion.tags = bbNode.tags()
				const code = this.codes.find(code => code.tagName === bbNode.tagName)
				if (code) {
					conversion.code = code
					conversion.code.beforeCreateNode(conversion)
					conversion.node = conversion.code.createNode(conversion)
				} else {
					const treeWalker = bbDocument.createTreeWalker(bbNode)
					while (treeWalker.nextNode()) {
						conversion.ignoreNodeList.push(treeWalker.currentNode)
					}
					conversion.node = this.document.createTextNode(bbNode.outerHTML)
				}
			} else {
				conversion.node = this.document.createTextNode(bbNode.textContent)
			}
			const parentMatch = conversion.matches.find(matchedNode => matchedNode.bbNode === bbNode.parentNode)
			if(parentMatch) {
				conversion.parentMatch = parentMatch
				const code = this.codes.find(code => code.tagName === parentMatch.bbNode.tagName)
				if(code) {
					code.appendNode(conversion)
				} else {
					conversion.parentMatch.node.appendChild(conversion.node)
				}
			} else {
				rootNode.appendChild(conversion.node)
			}
			if (conversion.node.nodeType === this.document.ELEMENT_NODE) {
				conversion.matches.push({ bbNode, node: conversion.node })
			}
		}
		return rootNode.innerHTML
	}

	/**
	 * Convert HTML string to BBcode string
	 * @param  {string} input
	 * @return {string}
	 */
	toBBCode(input) {
		const bbDocument = new BBDocument()
		const conversion = new Conversion(bbDocument, this.document)
		const element = this.document.createElement("div")
		element.innerHTML = input
		const treeWalker = this.document.createTreeWalker(element)
		while (treeWalker.nextNode()) {
			conversion.nodeList.push(treeWalker.currentNode)
		}
		for(const node of conversion.nodeList) {
			conversion.node = node
			conversion.code = null
			conversion.bbNode = null
			conversion.tags = null
			conversion.parentMatch = null
			if (conversion.ignoreNodeList.indexOf(node) !== -1) {
				continue
			}
			if (node.nodeType === this.document.ELEMENT_NODE) {
				const code = this.codes.find(code => code.testNode(node) === true)
				if (code) {
					conversion.code = code
					conversion.code.beforeCreateBBNode(conversion)
					conversion.bbNode = conversion.code.createBBNode(conversion)
					conversion.tags = conversion.bbNode.tags()
				} else {
					const treeWalker = this.document.createTreeWalker(node)
					while (treeWalker.nextNode()) {
						conversion.ignoreNodeList.push(treeWalker.currentNode)
					}
					conversion.bbNode = bbDocument.createTextNode(node.outerHTML)
				}
			} else if (node.nodeType === this.document.TEXT_NODE) {
				conversion.bbNode = bbDocument.createTextNode(node.textContent)
			}
			const parentMatch = conversion.matches.find(match => match.node === node.parentNode)
			if(parentMatch) {
				conversion.parentMatch = parentMatch
				const code = this.codes.find(code => code.tagName === parentMatch.bbNode.tagName)
				if(code) {
					code.appendBBNode(conversion)
				} else {
					conversion.parentMatch.bbNode.appendChild(conversion.bbNode)
				}
			} else {
				bbDocument.documentElement.appendChild(conversion.bbNode)
			}
			if (conversion.bbNode.nodeType === BBNode.ELEMENT_BBNODE) {
				conversion.matches.push({ bbNode: conversion.bbNode, node })
			}
		}
		return bbDocument.documentElement.innerBBCode
	}

}

export default Template