theophile
Version:
A templating module that transforms a web page into a (Powerpoint-like) presentation
161 lines (151 loc) • 5.22 kB
JavaScript
import "https://cdn.jsdelivr.net/npm/marked/marked.min.js";
// document.body.innerHTML = marked.parse('<div>ok</div># quoi \n# <span>_Marked_</span> in browser\n\nRendered by **marked**.');
import Plugin from "../Plugin.js";
export default class Reference extends Plugin {
static async init(Theophile) {
await super.init(Theophile);
this.refsDocuments = {};
}
static findReferences() {
var refs = Array.from(document.querySelectorAll(".th-references"));
var promises = refs.map(group => {
return this.processGroup(group);
});
return Promise.all(promises);
}
static async processGroup(group) {
var refs = Array.from(group.querySelectorAll("a"));
await Promise.all(
refs.map(ref => {
return this.processRef(ref);
})
);
while (group.firstChild) {
group.parentNode.insertBefore(group.firstChild, group);
}
group.parentNode.removeChild(group);
}
static async processRef(ref) {
const href = ref.getAttribute("href");
const doc = await this.getRefDocument(href);
if (!doc.querySelector("body>:first-child").matches("h1")) {
let h1 = document.createElement("h1");
h1.textContent = doc.title;
doc.body.insertBefore(h1, doc.body.firstChild);
h1.classList.add("th-slide-full");
}
var id = href.split("#")[1];
if (id) {
console.error("Todo"); //TODO
} else {
this.transferStyles(doc, ref);
this.addLink(ref);
this.transferContent(doc, ref);
ref.parentNode.removeChild(ref);
}
}
static transferStyles(doc, ref) {
Array.from(doc.querySelectorAll("style,link")).forEach(element => {
ref.ownerDocument.head.appendChild(element);
});
return this;
}
static transferContent(doc, ref) {
while (doc.body.firstChild) {
ref.parentNode.insertBefore(doc.body.firstChild, ref);
}
return this;
}
static addLink(ref) {
var link = document.createElement("a");
link.href = ref.getAttribute("href");
link.classList.add("th-reference-link");
ref.parentNode.insertBefore(link, ref);
return this;
}
static downgradeHeadings(doc) {
const headings = "h5,h4,h3,h2,h1";
Array.from(doc.querySelectorAll(headings)).forEach(heading => {
let level = parseInt(heading.tagName[1]) + 1;
var newHeading = document.createElement("h" + level);
while (heading.firstChild) {
newHeading.appendChild(heading.firstChild);
}
[...heading.attributes].forEach(attr => {
console.log(attr);
newHeading.attributes.setNamedItem(attr.cloneNode());
});
heading.parentNode.insertBefore(newHeading, heading);
heading.parentNode.removeChild(heading);
});
}
/**
* Retrieves the reference document based on the provided URL.
* @param {string} url - The URL of the reference document.
* @returns {Promise} - A promise that resolves with the reference document.
*/
static async getRefDocument(url) {
url = url.split("#")[0];
if (this.refsDocuments[url]) {
return Promise.resolve(this.refsDocuments[url]);
}
if (url.endsWith(".html") || url.endsWith(".htm")) {
this.refsDocuments[url] = await this.getRefHtml(url);
} else if (url.endsWith(".md")) {
this.refsDocuments[url] = await this.getRefMarkdown(url);
} else {
console.error("Unknown file type", url);
}
return this.refsDocuments[url];
}
/**
* Fetches HTML content from the specified URL and returns it as a parsed document.
* @param {string} url - The URL to fetch the HTML content from.
* @returns {Promise<Document>} - A promise that resolves to the parsed document.
* @throws {Error} - If there is an HTTP error or if fetching the HTML fails.
*/
static async getRefHtml(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString(html, 'text/html');
return doc;
} catch (error) {
throw new Error(`Failed to fetch HTML: ${error.message}`);
}
}
/**
* Retrieves the markdown content from the specified URL and returns it as a Promise.
* If the content has already been fetched before, it will be retrieved from cache.
*
* @param {string} url - The URL of the markdown content.
* @returns {Promise<HTMLDivElement>} A Promise that resolves to the HTMLDivElement containing the markdown content.
*/
static async getRefMarkdown(url) {
try {
// Fetch the markdown content
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
// Parse the markdown content using marked.js
const markdownText = await response.text();
const htmlContent = marked.parse(markdownText);
// Create an HTML document and set the body content
const doc = document.implementation.createHTMLDocument();
doc.body.innerHTML = htmlContent;
return doc;
} catch (error) {
throw new Error(`Failed to fetch and parse markdown: ${error.message}`);
}
}
static async prepare() {
await super.prepare();
const data = await this.findReferences();
return data;
}
}