import XNode from "@web-atoms/core/dist/core/XNode"; import { AtomControl } from "@web-atoms/core/dist/web/controls/AtomControl"; import { ContentPage, isMobileView } from "@web-atoms/web-controls/dist/mobile-app/MobileApp"; import { UMD } from "@web-atoms/core/dist/core/types"; import WebApp from "@web-atoms/core/dist/web/WebApp"; import styled from "@web-atoms/core/dist/style/styled"; import AnimatedLoader from "../../controls/AnimatedLoader"; import Action from "@web-atoms/core/dist/view-model/Action"; (UMD as any).map("showdown", "https://cdn.jsdelivr.net/npm/showdown@1.9.0/"); const css = styled.css ` display: grid; grid-template-columns: 1fr auto; gap: 5px; overflow: hidden; & > .md { overflow: auto; align-self: stretch; justify-self: stretch; & pre { border: solid 1px lightgray; } } & > .index { width: 200px; align-self: stretch; overflow: auto; & > * { margin: 5px; cursor: pointer; color: var(--link-color, blue); &:hover { text-decoration: underline; } } } `.installLocal(); let nextHeaderId = 1; declare let System: any; export default class MDPage extends ContentPage<{url: string; label: string;}> { public index: HTMLDivElement; public async init() { this.title = this.parameters.label; this.renderer = ; const rs = await fetch( System.resolve(this.parameters.url)); const code = await rs.text(); if (rs.status > 300) { this.renderer =

Failed to load {this.parameters.url}

{code}

; return; } this.renderer =
{!isMobileView &&
}
; this.index = this.element.querySelector(".index"); await this.loadCode(code); } @Action({ onEvent: "show-header"}) showHeader({ headerId }) { const e = this.element.querySelector(`#${headerId}`); e.scrollIntoView(); } async loadCode(code: string) { const app = this.app as WebApp; app.installStyleSheet("https://cdn.jsdelivr.net/npm/highlight.js@11.7.0/styles/github.min.css"); const showdown = await UMD.import("showdown/dist/showdown.js"); const text = code; const converter = new showdown.Converter(); converter.setOption("openLinksInNewWindow",true); converter.setOption("simplifiedAutoLink", true); const element = this.element; const mdRoot = element.querySelector(".md"); const md = document.createElement("div"); md.innerHTML = converter.makeHtml(text); md.style.width = "100%"; md.style.height = "100%"; md.className = "page"; mdRoot.appendChild(md); setTimeout(() => { this.findHeader(md); }, 100); await UMD.import("https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.7.0/build/highlight.min.js"); const highlight = (window as any).hljs; const all = document.querySelectorAll("pre > code"); // tslint:disable-next-line:prefer-for-of for (let index = 0; index < all.length; index++) { const e = all[index]; highlight.highlightBlock(e); } for(const iterator of Array.from(this.element.querySelectorAll("a"))) { if(/^(http|https)\:\/\//) { iterator.target = "_blank"; } } } private findHeader(e: HTMLElement): void { if (!e) { return; } const all = Array.from(e.querySelectorAll("h1,h2,h3,h4,h5,h6")); const index = this.index; for (const iterator of all) { const id = iterator.id ||= `nh-${nextHeaderId++}`; const link = document.createElement("div"); link.className = "header" link.textContent = iterator.textContent; link.style.paddingLeft = `${parseFloat(iterator.tagName.substring(1)) * 5}px`; link.setAttribute("data-click-event", "show-header"); link.setAttribute("data-header-id", id); index.appendChild(link); } } }