Skip to content

Commit

Permalink
feat: Markup parser
Browse files Browse the repository at this point in the history
  • Loading branch information
renoirb committed Jun 18, 2023
1 parent 1faca00 commit e27fc48
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
128 changes: 128 additions & 0 deletions js/bt-un-markup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { ContextRequestEvent } from './context.mjs'
import { ContextRequest_TransformMakup } from './context-markup.js'

const SVG_SKELETON_SPINNER = `
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<style>
.spinner_ajPY {
transform-origin: center;
animation: spinner_AtaB .75s infinite linear;
}
@keyframes spinner_AtaB {
100% {
transform: rotate(360deg);
}
}
</style>
<path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
/>
<path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
/>
</svg>
`

/**
* Take markup language (e.g. Markdown, Rst), and get it transformed into HTML.
*/
class UnMarkupElement extends HTMLElement {
constructor() {
super()
const shadowRoot = this.attachShadow({ mode: 'open' })
const template = document.createElement('template')

template.innerHTML = `
<style>
:host {
display: block;
}
#markup-source {
display: none;
}
.is-not-transformed #markup-loading {
display: block;
}
.is-not-transformed #markup-transformed {
display: none;
}
.is-transformed #markup-loading {
display: none;
}
.is-transformed #markup-transformed {
display: block;
}
</style>
<div class="disposition-parent">
<div
id="markup-viewer"
part="markup-viewer"
class="disposition-item is-not-transformed"
>
<div id="markup-loading">
<slot name="skeleton">
${SVG_SKELETON_SPINNER}
</slot>
</div>
<div id="markup-transformed"></div>
</div>
<div
id="markup-source"
part="markup-source"
class="disposition-item"
>
<pre>
<slot></slot>
</pre>
</div>
</div>
`
const innerHtml = template.content.cloneNode(true)
shadowRoot.appendChild(innerHtml)
let slot = this.shadowRoot.querySelector('slot:not([name])')
slot.addEventListener('slotchange', this._onSlotChange)
}

_applyTransformedMarkup = (html = '') => {
const transformed = html !== ''
const elMarkupViewer = this.shadowRoot.querySelector('#markup-viewer')
const elTransformed = this.shadowRoot.querySelector(
'#markup-transformed',
)
if (transformed) {
elTransformed.innerHTML = html
elMarkupViewer.classList.remove('is-not-transformed')
elMarkupViewer.classList.add('is-transformed')
} else {
elTransformed.innerHTML = ''
elMarkupViewer.classList.add('is-not-transformed')
elMarkupViewer.classList.remove('is-transformed')
}
}

/**
* Listen on changes only on default slot, that's the trigger to ask for HTML.
*/
_onSlotChange = (_event /*: HTMLElementEventMap['slotchange'] */) => {
this.dispatchEvent(
new ContextRequestEvent(
ContextRequest_TransformMakup,
this._onContextResponse_UnMarkup,
),
)
}

_onContextResponse_UnMarkup = ({ html = '' }) => {
this._applyTransformedMarkup(html)
}
}


export default UnMarkupElement
41 changes: 41 additions & 0 deletions js/context-markup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Context Request event for signaling Markdown needing to be parsed.
*/
export const ContextRequest_TransformMakup = 'transform-markup-context'


export const isContextRequest_TransformMakup = (event) =>
event.context === ContextRequest_TransformMakup


export const assertContextRequest_TransformMakup = (event) => {
if (!isContextRequest_TransformMakup(event)) {
const message = `Unexpected error, we expected a "ContextRequest_TransformMakup" context event`
throw new Error(message)
}
}

export const getFromContext_TransformMakup = (event) => {
assertContextRequest_TransformMakup(event)

const innerHTML = event.originalTarget.innerHTML
const lines = innerHTML.split('\n')
const isThreeDashesLine = line => /^---$/.test(line)
// Line numbers of frontMatter.
const [ fmBeginLn, fmEndLn ] = lines.map((ln, lnNbr) => isThreeDashesLine(ln) ? lnNbr : false).filter(i => i)
// Probably bogus
const frontMatter = lines.slice(fmBeginLn + 1, fmEndLn)
const markup = lines.slice(fmEndLn + 1)

return Object.freeze([
fm,
markup,
])
}


export const isValidContextResponse_TransformMakup = (payload) => {
const isAnArray = Array.isArray(payload)
const isOfTwo = payload.length === 2
return isAnArray && isOfTwo
}
40 changes: 40 additions & 0 deletions js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@ import {
isContextRequest_DateConveresion,
isValidContextResponse_DateConversion,
} from './context-date-conversion.js'
import {
getFromContext_TransformMakup,
isContextRequest_TransformMakup
} from './context-markup.js'

const DEP_SHOWDOWN_VERSION = '2.1.0'
const IMPORT_DEP_SHOWDOWN = `https://ga.jspm.io/npm:showdown@${DEP_SHOWDOWN_VERSION}/dist/showdown.js`

/**
* Our own components, but not loading them just yet.
*/
const OUR_COMPONENTS = [
['bt-time', './bt-date-time.js'],
['bt-un-markup', './bt-un-markup.js'],
]


const handleContextRequest_DateConversion = (event) => {
const test = isContextRequest_DateConveresion(event)
if (isContextRequest_DateConveresion(event)) {
Expand All @@ -30,6 +39,22 @@ const handleContextRequest_DateConversion = (event) => {
}


/**
* By default, markup is in Markdown, but could be in another.
*/
const markupParser = async (opts = {}) => {
const imported = await import(IMPORT_DEP_SHOWDOWN)
const showdown = imported?.default
const converter = new showdown.Converter({ metadata: true, ...opts })
converter.setOption('openLinksInNewWindow', true)

return converter
}





const main = async (realm, { components = [] }) => {
// TODO Allow providing our ^ components and utils

Expand All @@ -45,10 +70,25 @@ const main = async (realm, { components = [] }) => {
}
}


// Make this dynamic, based on configured markup parser
const contentParser = await markupParser()

const handleContextRequest_TransformMarkup = (event) => {
if (isContextRequest_TransformMakup(event)) {
event.stopPropagation()
const [ _fm, markup ] = getFromContext_TransformMakup(event)
// ^ TODO import and use YAML parser library
const html = contentParser.makeHtml(markup)
event.callback({ html })
}
}

// TODO Make this configurable(?)
realm.document.addEventListener('context-request', (event) => {
// ... and others.
handleContextRequest_DateConversion(event)
handleContextRequest_TransformMarkup(event)
})
}

Expand Down

0 comments on commit e27fc48

Please sign in to comment.