mirror of
https://github.com/glassflame/glassflame.github.io.git
synced 2024-11-25 17:44:26 +00:00
Abstract connectedCallback
into onConnected
This commit is contained in:
parent
1bb664b593
commit
dd4ddb7620
6 changed files with 100 additions and 131 deletions
64
src/elements/base.mjs
Normal file
64
src/elements/base.mjs
Normal 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.")
|
||||
}
|
||||
}
|
|
@ -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.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue