1
Fork 0
mirror of https://github.com/glassflame/glassflame.github.io.git synced 2024-10-16 06:27:32 +00:00

Abstract connectedCallback into onConnected

This commit is contained in:
Steffo 2023-10-24 11:04:57 +02:00
parent 1bb664b593
commit dd4ddb7620
6 changed files with 100 additions and 131 deletions

64
src/elements/base.mjs Normal file
View file

@ -0,0 +1,64 @@
export class NotImplementedError extends Error {}
export class CustomElement extends HTMLElement {
template
shadow
instance
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
// The template to duplicate.
this.template = this.constructor.getTemplate()
// The shadow root, the inner contents of the element..
this.shadow = this.attachShadow({ mode: "open" })
// The element contained inside the shadow root..
this.instance = this.template.content.cloneNode(true)
// Call the custom callback.
this.onConnected()
// Add the instance to the DOM.
this.shadow.appendChild(this.instance)
}
findFirstAncestor(constructor) {
let current = this
// Keep iterating over nodes
while(current) {
// The ancestor has been found!
if(current instanceof constructor) {
return current
}
// Use .host to access the parent of a ShadowRoot
else if(current instanceof ShadowRoot) {
current = current.host
}
// Use .parentNode to access the parent of a HTMLElement
else if(current instanceof HTMLElement) {
current = current.parentNode
}
// Something went wrong?
else {
console.warn("[findFirstAncestor] Reached unknown node:", current)
}
}
// The ancestor has NOT been found...
return null
}
constructor() {
super();
if(this.constructor === CustomElement) {
throw new NotImplementedError("CustomElement is being used as-is.")
}
}
onConnected() {}
static getTemplate() {
throw new NotImplementedError("CustomElement.getTemplate has not been overridden.")
}
}

View file

@ -1,26 +1,8 @@
import { fileDetails } from "../utils/file.mjs";
import { CustomElement, NotImplementedError } from "./base.mjs";
export class CanvasElement extends HTMLElement {
/**
* Return the closest {@link CanvasElement} ancestor in the tree.
*
* @param initial {HTMLElement} The element to start the search from.
*/
static findFirstCanvasAncestor(initial) {
let current = initial
while(current) {
if(current instanceof ShadowRoot) {
current = current.host
}
if(current instanceof CanvasElement) {
return current
}
current = current.parentNode
}
return null
}
export class CanvasElement extends CustomElement {
static getTemplate() {
return document.getElementById("template-canvas")
}
@ -32,10 +14,8 @@ export class CanvasElement extends HTMLElement {
nodeElements = {}
edgeElements = {}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = CanvasElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
onConnected() {
super.onConnected();
this.parsedJSON = JSON.parse(this.getAttribute("contents"))
@ -112,16 +92,11 @@ export class CanvasElement extends HTMLElement {
this.appendChild(this.nodesSlotted)
this.appendChild(this.edgesSlotted)
shadow.appendChild(instanceDocument)
}
}
/**
* Element representing the generic skeleton of an Obsidian Canvas item.
*/
export class CanvasItemElement extends HTMLElement {
export class CanvasItemElement extends CustomElement {
colorToHex() {
const color = this.getAttribute("color")
@ -133,7 +108,6 @@ export class CanvasItemElement extends HTMLElement {
return color
}
else {
// TODO: Check which colors correspond to what
return {
"0": "var(--color-gray)",
"1": "var(--color-red)",
@ -145,4 +119,12 @@ export class CanvasItemElement extends HTMLElement {
}[color]
}
}
constructor() {
super();
if(this.constructor === CanvasItemElement) {
throw new NotImplementedError("CanvasItemElement is being used as-is.")
}
}
}

View file

@ -2,28 +2,10 @@ import { fileDetails } from "../utils/file.mjs";
import { CanvasElement } from "./canvas.mjs";
import { MarkdownElement } from "./markdown.mjs";
import { FetchError } from "./node.mjs";
import { CustomElement } from "./base.mjs";
export class DisplayElement extends HTMLElement {
/**
* Return the closest {@link DisplayElement} ancestor in the tree.
*
* @param initial {HTMLElement} The element to start the search from.
*/
static findFirstDisplayAncestor(initial) {
let current = initial
while(current) {
if(current instanceof ShadowRoot) {
current = current.host
}
if(current instanceof DisplayElement) {
return current
}
current = current.parentNode
}
return null
}
export class DisplayElement extends CustomElement {
static getTemplate() {
return document.getElementById("template-display")
}
@ -31,11 +13,7 @@ export class DisplayElement extends HTMLElement {
containerSlotted
loadButton
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = DisplayElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
onConnected() {
this.containerSlotted = document.createElement("div")
this.containerSlotted.slot = "display-container"
this.loadButton = document.createElement("button")
@ -43,8 +21,6 @@ export class DisplayElement extends HTMLElement {
this.loadButton.addEventListener("click", this.load.bind(this))
this.containerSlotted.appendChild(this.loadButton)
this.appendChild(this.containerSlotted)
shadow.appendChild(instanceDocument)
}
data

View file

@ -9,12 +9,8 @@ export class EdgeElement extends CanvasItemElement {
svgSlotted
lineElement
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = EdgeElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
const canvas = CanvasElement.findFirstCanvasAncestor(this)
onConnected() {
const canvas = this.findFirstAncestor(CanvasElement)
const fromNode = canvas.nodeElements[this.getAttribute("node-from")]
const fromSide = this.getAttribute("node-from-side")
@ -48,7 +44,5 @@ export class EdgeElement extends CanvasItemElement {
this.svgSlotted.appendChild(this.lineElement)
this.appendChild(this.svgSlotted)
shadow.appendChild(instanceDocument)
}
}

View file

@ -1,12 +1,11 @@
import { Marked } from "https://unpkg.com/marked@9.1.2/lib/marked.esm.js";
import { fileDetails } from "../utils/file.mjs";
import { DisplayElement } from "./display.mjs";
import { CustomElement } from "./base.mjs";
/**
* Element rendering the Markdown contents of an Obsidian page.
*/
export class MarkdownElement extends HTMLElement {
export class MarkdownElement extends CustomElement {
static marked = new Marked({
extensions: [
{
@ -15,7 +14,7 @@ export class MarkdownElement extends HTMLElement {
start(src) {
return src.match(/^(-{3,})/)?.index
},
tokenizer(src, tokens) {
tokenizer(src, _) {
const match = src.match(/^(-{3,})(.+)?\n((?:.+\n)*)\1\n/)
if(match) {
return {
@ -36,7 +35,7 @@ export class MarkdownElement extends HTMLElement {
start(src) {
return src.match(/^\[\[/)?.index
},
tokenizer(src, tokens) {
tokenizer(src, _) {
const match = src.match(/^\[\[([^|\]]+)(?:\|([^\]]+))?]]/)
if(match) {
return {
@ -57,7 +56,7 @@ export class MarkdownElement extends HTMLElement {
start(src) {
return src.match(/^#/)?.index
},
tokenizer(src, tokens) {
tokenizer(src, _) {
const match = src.match(/^#([A-Za-z0-9]+)/)
if(match) {
return {
@ -80,11 +79,7 @@ export class MarkdownElement extends HTMLElement {
return document.getElementById("template-markdown")
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = MarkdownElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
onConnected() {
const markdown = this.getAttribute("contents")
this.contentsElement = document.createElement("div")
@ -92,65 +87,41 @@ export class MarkdownElement extends HTMLElement {
this.contentsElement.innerHTML = MarkdownElement.marked.parse(markdown)
this.appendChild(this.contentsElement)
shadow.appendChild(instanceDocument)
}
}
/**
* Element rendering Obsidian front matter.
*/
export class FrontMatterElement extends HTMLElement {
export class FrontMatterElement extends CustomElement {
static getTemplate() {
return document.getElementById("template-frontmatter")
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = FrontMatterElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
shadow.appendChild(instanceDocument)
}
}
/**
* Element rendering an Obsidian Hashtag.
*/
export class HashtagElement extends HTMLElement {
export class HashtagElement extends CustomElement {
static getTemplate() {
return document.getElementById("template-hashtag")
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = HashtagElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
shadow.appendChild(instanceDocument)
}
}
/**
* Element rendering an Obsidian Wikilink.
*/
export class WikilinkElement extends HTMLElement {
export class WikilinkElement extends CustomElement {
static getTemplate() {
return document.getElementById("template-wikilink")
}
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = WikilinkElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
const instanceElement = instanceDocument.querySelector(".wikilink")
onConnected() {
const instanceElement = this.instance.querySelector(".wikilink")
const destinationURL = new URL(window.location)
destinationURL.hash = this.getAttribute("wref")
instanceElement.href = destinationURL
shadow.appendChild(instanceDocument)
}
}

View file

@ -54,12 +54,8 @@ export class NodeGroupElement extends NodeElement {
instanceElement
labelSlotted
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = NodeGroupElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
this.instanceElement = instanceDocument.querySelector(".node-group")
onConnected() {
this.instanceElement = this.instance.querySelector(".node-group")
this.instanceElement.style.setProperty("left", `${this.getAttribute("x")}px`)
this.instanceElement.style.setProperty("top", `${this.getAttribute("y")}px`)
@ -71,8 +67,6 @@ export class NodeGroupElement extends NodeElement {
this.labelSlotted.slot = "node-label"
this.labelSlotted.innerText = this.getAttribute("label")
this.appendChild(this.labelSlotted)
shadow.appendChild(instanceDocument)
}
}
@ -86,12 +80,8 @@ export class NodeFileElement extends NodeElement {
nameSlotted
contentsSlotted
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = NodeFileElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
this.instanceElement = instanceDocument.querySelector(".node-file")
onConnect() {
this.instanceElement = this.instance.querySelector(".node-file")
this.instanceElement.style.setProperty("left", `${this.getAttribute("x")}px`)
this.instanceElement.style.setProperty("top", `${this.getAttribute("y")}px`)
@ -111,12 +101,10 @@ export class NodeFileElement extends NodeElement {
this.contentsSlotted = document.createElement(customElements.getName(DisplayElement))
this.contentsSlotted.slot = "node-contents"
const firstDisplayAncestor = DisplayElement.findFirstDisplayAncestor(this)
const firstDisplayAncestor = this.findFirstAncestor(DisplayElement)
this.contentsSlotted.setAttribute("vref", firstDisplayAncestor.getAttribute("vref"))
this.contentsSlotted.setAttribute("wref", this.getAttribute("file"))
this.appendChild(this.contentsSlotted)
shadow.appendChild(instanceDocument)
}
}
@ -128,12 +116,8 @@ export class NodeTextElement extends NodeElement {
instanceElement
contentsSlotted
// noinspection JSUnusedGlobalSymbols
connectedCallback() {
const instanceDocument = NodeTextElement.getTemplate().content.cloneNode(true)
const shadow = this.attachShadow({ mode: "open" })
this.instanceElement = instanceDocument.querySelector(".node-text")
onConnected() {
this.instanceElement = this.instance.querySelector(".node-text")
this.instanceElement.style.setProperty("left", `${this.getAttribute("x")}px`)
this.instanceElement.style.setProperty("top", `${this.getAttribute("y")}px`)
@ -145,7 +129,5 @@ export class NodeTextElement extends NodeElement {
this.contentsSlotted.slot = "node-contents"
this.contentsSlotted.setAttribute("contents", this.getAttribute("text"))
this.appendChild(this.contentsSlotted)
shadow.appendChild(instanceDocument)
}
}