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

Continue refactoring

This commit is contained in:
Steffo 2023-10-25 19:57:12 +02:00
parent a1a8b89a2b
commit 8b45e78f4c
Signed by: steffo
GPG key ID: 2A24051445686895
14 changed files with 594 additions and 249 deletions

View file

@ -42,17 +42,10 @@
<template id="template-node-group">
<style>
.node-group {
position: absolute;
box-sizing: border-box;
--color-node: var(--color-gray);
outline: var(--node-group-border-width) solid var(--color-node);
background-color: color-mix(in srgb, var(--color-node) 20%, var(--color-background));
border-radius: 0 8px 8px 8px;
padding: 12px;
overflow-x: visible;
overflow-y: visible;
}
.node-group-label {
@ -73,11 +66,9 @@
margin: 0;
}
</style>
<section class="node-group">
<aside class="node-group-label">
<h1><slot name="node-label">{Group label}</slot></h1>
</aside>
</section>
<aside class="canvas-item node node-group">
<h1><slot name="node-group-label">{Group label}</slot></h1>
</aside>
</template>
<template id="template-node-file">
<style>

View file

@ -30,7 +30,7 @@ export class CustomElement extends HTMLElement {
/**
* The local cloned instance of the template node.
* @returns {Node}
* @returns {DocumentFragment}
*/
get instance() {
return this.#instance

View file

@ -42,7 +42,7 @@ export class CanvasElement extends CustomElement {
* Update the values of {@link contents} and {@link parsedContents} from the `contents` attribute of the element.
* @throws SyntaxError If `contents` is not valid JSON.
*/
updateContents() {
recalculateContents() {
this.#contents = this.getAttribute("contents")
this.#parsedContents = JSON.parse(this.#contents)
}
@ -50,7 +50,7 @@ export class CanvasElement extends CustomElement {
/**
* The minimum X node found in the items of this Canvas.
* Used to compute this element's rect.
* Can be computed from {@link contents} with {@link computeMinMax}.
* Can be computed from {@link contents} with {@link recalculateMinMax}.
* @type {{x: number, width: number}}
*/
minX
@ -58,7 +58,7 @@ export class CanvasElement extends CustomElement {
/**
* The minimum Y node found in the items of this Canvas.
* Used to compute this element's rect.
* Can be computed from {@link contents} with {@link computeMinMax}.
* Can be computed from {@link contents} with {@link recalculateMinMax}.
* @type {{y: number, height: number}}
*/
minY
@ -66,7 +66,7 @@ export class CanvasElement extends CustomElement {
/**
* The maximum X node found in the items of this Canvas.
* Used to compute this element's rect.
* Can be computed from {@link contents} with {@link computeMinMax}.
* Can be computed from {@link contents} with {@link recalculateMinMax}.
* @type {{x: number, width: number}}
*/
maxX
@ -74,7 +74,7 @@ export class CanvasElement extends CustomElement {
/**
* The maximum Y node found in the items of this Canvas.
* Used to compute this element's rect.
* Can be computed from {@link contents} with {@link computeMinMax}.
* Can be computed from {@link contents} with {@link recalculateMinMax}.
* @type {{y: number, height: number}}
*/
maxY
@ -83,7 +83,7 @@ export class CanvasElement extends CustomElement {
* Compute {@link minX}, {@link minY}, {@link maxX}, {@link maxY} from {@link contents}.
* @returns {void}
*/
computeMinMax() {
recalculateMinMax() {
// Define initial values.
this.minX = { x: Infinity, width: 0 }
this.minY = { y: Infinity, height: 0 }
@ -196,7 +196,11 @@ export class CanvasElement extends CustomElement {
this.nodesContainer.appendChild(element)
}
// TODO: You were here last time!
this.nodesContainer.style["width"] = `${this.maxX.x + this.maxX.width - this.minX.x}px`
this.nodesContainer.style["height"] = `${this.maxY.y + this.maxY.height - this.minY.y}px`
this.appendChild(this.nodesContainer)
}
/**
@ -211,20 +215,35 @@ export class CanvasElement extends CustomElement {
*/
edgeElementsById = {}
/**
* Name of the slot where the edge container should be placed.
* @type {string}
*/
static EDGES_SLOT_NAME = "canvas-nodes"
onConnect() {
this.updateContents()
this.computeMinMax()
this.recreateNodes()
/**
* Prefix to the name of the element to create for each edge.
* @type {string}
*/
static EDGE_ELEMENT_NAME = "x-edge"
/**
* Destroy and recreate the {@link edgesContainer} with the current {@link parsedContents}, {@link minX}, {@link minY}, {@link maxX}, {@link maxY}.
* @returns {void}
*/
recreateEdges() {
if(this.edgesContainer) {
this.edgesContainer.remove()
this.edgesContainer = null
}
this.edgesContainer = document.createElement("div")
this.edgesContainer.slot = "canvas-edges"
this.edgesContainer.slot = this.constructor.EDGES_SLOT_NAME
for(const edge of this.parsedContents["edges"]) {
let {id, fromNode, fromSide, toNode, toSide, color, toEnd: arrows} = edge
const element = document.createElement("x-edge")
const element = document.createElement(this.constructor.EDGE_ELEMENT_NAME)
element.setAttribute("id", `edge-${id}`)
element.setAttribute("node-from", fromNode)
element.setAttribute("node-from-side", fromSide)
@ -237,54 +256,16 @@ export class CanvasElement extends CustomElement {
this.edgesContainer.appendChild(element)
}
this.nodesContainer.style["width"] = `${maxX.x + maxX.width - minX.x}px`
this.nodesContainer.style["height"] = `${maxY.y + maxY.height - minY.y}px`
this.edgesContainer.style["width"] = `${this.maxX.x + this.maxX.width - this.minX.x}px`
this.edgesContainer.style["height"] = `${this.maxY.y + this.maxY.height - this.minY.y}px`
this.edgesContainer.style["width"] = `${maxX.x + maxX.width - minX.x}px`
this.edgesContainer.style["height"] = `${maxY.y + maxY.height - minY.y}px`
this.appendChild(this.nodesContainer)
this.appendChild(this.edgesContainer)
}
}
/**
* Abstract base class for elements drawn on a {@link CanvasElement}.
* @abstract
*/
export class CanvasItemElement extends CustomElement {
/**
* Given an Obsidian Canvas color, return its corresponding CSS color.
* @param color {string} The color, as serialized on an Obsidian Canvas.
* @returns {string} The corresponding CSS color.
*/
static colorToCSS(color) {
if(color === undefined || color === null || color === "") {
return "var(--color-gray)"
}
else if(color.startsWith("#")) {
// This is an hex color
return color
}
else {
return {
"0": "var(--color-gray)",
"1": "var(--color-red)",
"2": "var(--color-orange)",
"3": "var(--color-yellow)",
"4": "var(--color-green)",
"5": "var(--color-blue)",
"6": "var(--color-purple)",
}[color]
}
}
constructor() {
super();
if(this.constructor === CanvasItemElement) {
throw new NotImplementedError("CanvasItemElement is being used as-is.")
}
onConnect() {
this.recalculateContents()
this.recalculateMinMax()
this.recreateNodes()
this.recreateEdges()
}
}

View file

@ -0,0 +1,123 @@
import { CustomElement } from "src/elements/base.mjs";
/**
* Abstract base class for elements drawn on a {@link CanvasElement}.
* @abstract
*/
export class CanvasItemElement extends CustomElement {
/**
* @returns {number} The X coordinate of the top left vertex of this element.
*/
get x() {
return Number(this.getAttribute("x"))
}
/**
* @returns {number} The Y coordinate of the top left vertex of this element.
*/
get y() {
return Number(this.getAttribute("y"))
}
/**
* @returns {number} The horizontal width of this element.
*/
get width() {
return Number(this.getAttribute("width"))
}
/**
* @returns {number} The vertical height of this element.
*/
get height() {
return Number(this.getAttribute("height"))
}
/**
* The color of this element, as stored in Obsidian Canvas files.
* Can be either `null`, a `number`, or a `string`.
* @returns {null|number|string} The value in question.
*/
get obsidianColor() {
const color = this.getAttribute("color")
if(color === null) return null // No color specified
const maybeNumber = Number(color)
if(!isNaN(maybeNumber)) return maybeNumber // Numeric color specified
return color // Hex color specified
}
/**
* Given an Obsidian Canvas color, return its corresponding CSS color.
* @param color {null|number|string} The color, as serialized in Obsidian Canvas files, or as returned by {@link obsidianColor}.
* @returns {string} The corresponding CSS color.
*/
static obsidianColorToCssColor(color) {
if(color === null || color === "") {
return "var(--color-gray)"
}
else if(color.match(/^#[0-9A-F]{3}$|^#[0-9A-F]{6}$/i)) {
return color
}
else {
return {
"0": "var(--color-gray)",
"1": "var(--color-red)",
"2": "var(--color-orange)",
"3": "var(--color-yellow)",
"4": "var(--color-green)",
"5": "var(--color-blue)",
"6": "var(--color-purple)",
}[color]
}
}
/**
* The CSS color of this element, converted from {@link obsidianColor} with {@link obsidianColorToCssColor}.
*/
get cssColor() {
return this.constructor.obsidianColorToCssColor(this.obsidianColor)
}
/**
* The CSS selector of the element in the template representing the canvas item.
* @type {string}
*/
static CANVAS_ITEM_SELECTOR = ".canvas-item"
/**
* The element in the instance representing the canvas item.
* Can be set via {@link recalculateCanvasItemElement}.
* @type {HTMLElement}
*/
canvasItemElement
/**
* Update the value of the {@link canvasItemElement} by querying the current {@link instance} with {@link CANVAS_ITEM_SELECTOR}.
*/
recalculateCanvasItemElement() {
this.canvasItemElement = this.instance.querySelector(this.constructor.CANVAS_ITEM_SELECTOR)
}
/**
* Set the CSS properties of {@link canvasItemElement}, making sure it gets rendered properly.
* @returns {void}
*/
resetCanvasItemCssProperties() {
this.canvasItemElement.style.setProperty("box-sizing", "border-box")
this.canvasItemElement.style.setProperty("position", "absolute")
this.canvasItemElement.style.setProperty("left", `${this.getAttribute("x")}px`)
this.canvasItemElement.style.setProperty("top", `${this.getAttribute("y")}px`)
this.canvasItemElement.style.setProperty("width", `${this.getAttribute("width")}px`)
this.canvasItemElement.style.setProperty("height", `${this.getAttribute("height")}px`)
this.canvasItemElement.style.setProperty("--color-node", this.constructor.obsidianColorToCssColor(this.getAttribute("color")))
}
onConnect() {
super.onConnect()
this.recalculateCanvasItemElement()
this.resetCanvasItemCssProperties()
}
}

View file

@ -0,0 +1,140 @@
import { CanvasElement } from "src/elements/canvas/canvas.mjs";
import { CanvasItemElement } from "src/elements/canvas/canvasitem.mjs";
import { findFirstAncestor } from "src/utils/trasversal.mjs";
/**
* An edge of a {@link CanvasElement}.
*/
export class EdgeElement extends CanvasItemElement {
static getTemplate() {
return document.getElementById("template-edge")
}
/**
* The canvas this element is contained in.
* Can be recalculated with {@link recalculateCanvas}.
* @type {CanvasElement}
*/
canvas
/**
* Recalculate the value of {@link canvas}.
*/
recalculateCanvas() {
findFirstAncestor(this, CanvasElement)
}
/**
* The id of the node this edge starts at, obtained from the `node-from` attribute.
* @returns {string}
*/
get fromNodeId() {
return this.getAttribute("node-from")
}
/**
* The id of the node this edge ends at, obtained from the `node-to` attribute.
* @returns {string}
*/
get toNodeId() {
return this.getAttribute("node-to")
}
/**
* The node this edge starts at.
* Can be recalculated with {@link recalculateFromTo}.
* @type {NodeElement}
*/
fromNode
/**
* The node this edge ends at.
* Can be recalculated with {@link recalculateFromTo}.
* @type {NodeElement}
*/
toNode
/**
* Recalculate the values of {@link fromNode} and {@link toNode} using the current values of {@link fromNodeId}, {@link toNodeId}, and {@link canvas}.
* @returns {void}
*/
recalculateFromTo() {
this.fromNode = this.canvas.nodeElementsById[this.fromNodeId]
this.toNode = this.canvas.nodeElementsById[this.toNodeId]
}
/**
* The side of the node this edge starts at, obtained from the `node-from-side` attribute.
* @returns {"top"|"bottom"|"left"|"right"}
*/
get nodeFromSide() {
return this.getAttribute("node-from-side")
}
/**
* The side of the node this edge ends at, obtained from the `node-to-side` attribute.
* @returns {"top"|"bottom"|"left"|"right"}
*/
get nodeToSide() {
return this.getAttribute("node-to-side")
}
/**
* The SVG element rendering the edge.
* Can be recreated with {@link recreateSvgElement}.
* @type {SVGElement}
*/
svgElement
/**
* The line element rendering the edge.
* Can be recreated with {@link recreateSvgElement}.
* @type {SVGLineElement}
*/
lineElement
// TODO: Last time, you were here!
/**
* Recreate {@link svgElement} and {@link lineElement} with the current values of the element.
* @returns {void}
*/
recreateSvgElement() {
const [x1, y1] = this.fromNode.edgeHandle(this.nodeFromSide)
const [x2, y2] = this.toNode.edgeHandle(this.nodeToSide)
}
onConnect() {
super.onConnect()
this.recalculateCanvas()
this.recalculateFromTo()
this.recreateSvgElement()
const fromNode = canvas.nodeElements[this.getAttribute("node-from")]
const fromSide = this.getAttribute("node-from-side")
const [x1, y1] = fromNode.getCenterCoordinatesOfSide(fromSide)
const toNode = canvas.nodeElements[this.getAttribute("node-to")]
const toSide = this.getAttribute("node-to-side")
const [x2, y2] = toNode.getCenterCoordinatesOfSide(toSide)
this.svgSlotted = document.createElementNS("http://www.w3.org/2000/svg", "svg")
this.svgSlotted.slot = "edge-svg"
this.svgSlotted.style.setProperty("position", "absolute")
this.svgSlotted.style.setProperty("left", "0")
this.svgSlotted.style.setProperty("top", "0")
this.svgSlotted.style.setProperty("overflow", "visible")
this.lineElement = document.createElementNS("http://www.w3.org/2000/svg", "line")
this.lineElement.setAttribute("x1", x1)
this.lineElement.setAttribute("y1", y1)
this.lineElement.setAttribute("x2", x2)
this.lineElement.setAttribute("y2", y2)
this.lineElement.style.setProperty("stroke", this.constructor.colorToCSS(this.getAttribute("color")))
this.lineElement.style.setProperty("stroke-width", "var(--edge-width)")
this.svgSlotted.appendChild(this.lineElement)
this.appendChild(this.svgSlotted)
}
}

View file

@ -0,0 +1,77 @@
import { CanvasItemElement } from "src/elements/canvas/canvasitem.mjs";
/**
* Abstract base class for nodes of a {@link CanvasElement}.
* @abstract
*/
export class NodeElement extends CanvasItemElement {
/**
* Coordinates of the point where edges connected to the top of this node should attach to.
* @type {[number, number]}
*/
edgeHandleTop
/**
* Coordinates of the point where edges connected to the bottom of this node should attach to.
* @type {[number, number]}
*/
edgeHandleBottom
/**
* Coordinates of the point where edges connected to the left of this node should attach to.
* @type {[number, number]}
*/
edgeHandleLeft
/**
* Coordinates of the point where edges connected to the right of this node should attach to.
* @type {[number, number]}
*/
edgeHandleRight
/**
* Recalculate the values of {@link edgeHandleTop}, {@link edgeHandleBottom}, {@link edgeHandleLeft}, {@link edgeHandleRight} using the current values of {@link x}, {@link y}, {@link height}, {@link width}.
*/
recalculateEdgeHandles() {
this.edgeHandleTop = [
this.x + this.width / 2,
this.y,
]
this.edgeHandleBottom = [
this.x + this.width / 2,
this.y + this.height,
]
this.edgeHandleLeft = [
this.x,
this.y + this.height / 2,
]
this.edgeHandleRight = [
this.x + this.width,
this.y + this.height / 2,
]
}
/**
* Get the edge handle at the given side, selecting one of {@link edgeHandleTop}, {@link edgeHandleBottom}, {@link edgeHandleLeft}, or {@link edgeHandleRight}.
* @param side {"top"|"bottom"|"left"|"right"} The side whose edge handle to get.
* @returns {[number,number]} Coordinates of the edge handle.
*/
edgeHandle(side) {
switch(side) {
case "top":
return this.edgeHandleTop
case "bottom":
return this.edgeHandleBottom
case "left":
return this.edgeHandleLeft
case "right":
return this.edgeHandleRight
}
}
onConnect() {
super.onConnect()
this.recalculateEdgeHandles()
}
}

View file

@ -0,0 +1,89 @@
import { NodeElement } from "src/elements/canvas/node/base.mjs";
import { DisplayElement } from "src/elements/display.mjs";
import { fileDetails } from "src/utils/file.mjs";
import { findFirstAncestor } from "src/utils/trasversal.mjs";
export class NodeFileElement extends NodeElement {
static getTemplate() {
return document.getElementById("template-node-file")
}
/**
* Get the path of the file displayed by this node, relative to the root of the vault, from the `path` attribute.
* @returns {string} The path.
*/
get pathRelativeToVault() {
return this.getAttribute("path")
}
/**
* Get the name of the file displayed by this node, with no extension.
* @returns {string} The file name.
*/
get fileName() {
const {name} = fileDetails(this.pathRelativeToVault)
return name
}
/**
* The element displaying the name of the file.
* @type {HTMLSpanElement}
*/
labelElement
/**
* The name of the slot where {@link labelElement} should be placed in.
* @type {string}
*/
static LABEL_ELEMENT_SLOT = "node-file-label"
/**
* Recreate {@link labelElement} with the current value of {@link fileName}.
*/
recreateLabelElement() {
if(this.labelElement) {
this.labelElement.remove()
this.labelElement = null
}
this.labelSlotted = document.createElement("span")
this.labelSlotted.slot = this.constructor.LABEL_ELEMENT_SLOT
this.labelSlotted.innerText = this.fileName
this.appendChild(this.labelSlotted)
}
/**
* The element displaying the contents of the file.
* @type {DisplayElement}
*/
contentsElement
/**
* The name of the slot where {@link contentsElement} should be placed in.
* @type {string}
*/
static CONTENTS_ELEMENT_SLOT = "node-file-contents"
/**
* Recreate {@link labelElement} with the current value of {@link fileName}.
*/
recreateContentsElement() {
if(this.contentsElement) {
this.contentsElement.remove()
this.contentsElement = null
}
this.contentsElement = document.createElement("x-display")
this.contentsElement.slot = this.constructor.CONTENTS_ELEMENT_SLOT
this.contentsElement.setAttribute("vault", findFirstAncestor(this, DisplayElement).vault) // TODO: Add a vault attribute to DisplayElement
this.contentsElement.setAttribute("path", this.pathRelativeToVault) // TODO: Add a path attribute to DisplayElement
this.appendChild(this.contentsElement)
}
onConnect() {
super.onConnect()
this.recreateLabelElement()
this.recreateContentsElement()
}
}

View file

@ -0,0 +1,52 @@
import { NodeElement } from "src/elements/canvas/node/base.mjs";
/**
* A {@link NodeElement} representing a group of nodes.
* Visual only, does not actually contain any other nodes.
*/
export class NodeGroupElement extends NodeElement {
/**
* The label text of the group.
* Obtained from the `label` attribute of the element.
*/
get label() {
return this.getAttribute("label")
}
/**
* The element displaying the name of the group.
* @type {HTMLSpanElement}
*/
labelElement
/**
* The name of the slot where {@link labelElement} should be placed in.
* @type {string}
*/
static LABEL_ELEMENT_SLOT = "node-group-label"
/**
* Recreate {@link labelElement} with the current value of {@link label}.
*/
recreateLabelElement() {
if(this.labelElement) {
this.labelElement.remove()
this.labelElement = null
}
this.labelSlotted = document.createElement("span")
this.labelSlotted.slot = this.constructor.LABEL_ELEMENT_SLOT
this.labelSlotted.innerText = this.label
this.appendChild(this.labelSlotted)
}
static getTemplate() {
return document.getElementById("template-node-group")
}
onConnect() {
super.onConnect()
this.recreateLabelElement()
}
}

View file

@ -0,0 +1,51 @@
import { NodeElement } from "src/elements/canvas/node/base.mjs";
import { DisplayElement } from "src/elements/display.mjs";
/**
* A {@link NodeElement} directly rendering a Markdown document.
*/
export class NodeTextElement extends NodeElement {
static getTemplate() {
return document.getElementById("template-node-text")
}
/**
* Get the Markdown source of this node from the `document` attribute.
*/
get markdownDocument() {
return this.getAttribute("text")
}
/**
* The element displaying the contents of the node.
* @type {MarkdownElement}
*/
contentsElement
/**
* The name of the slot where {@link contentsElement} should be placed in.
* @type {string}
*/
static CONTENTS_ELEMENT_SLOT = "node-file-contents"
/**
* Recreate {@link labelElement} with the current value of {@link fileName}.
*/
recreateContentsElement() {
if(this.contentsElement) {
this.contentsElement.remove()
this.contentsElement = null
}
this.contentsElement = document.createElement("x-markdown")
this.contentsElement.slot = this.constructor.CONTENTS_ELEMENT_SLOT
this.contentsElement.setAttribute("document", this.markdownDocument) // TODO: Rename the property of x-markdown to "document"
this.appendChild(this.contentsElement)
}
onConnect() {
super.onConnect()
this.recreateContentsElement()
}
}

View file

@ -1,7 +1,7 @@
import { fileDetails } from "../utils/file.mjs";
import { CanvasElement } from "./canvas/canvas.mjs";
import { MarkdownElement } from "./markdown.mjs";
import { FetchError } from "./node.mjs";
import { FetchError } from "src/elements/canvas/node/base.mjs";
import { CustomElement } from "./base.mjs";

View file

@ -1,41 +0,0 @@
import { CanvasElement, CanvasItemElement } from "./canvas/canvas.mjs";
export class EdgeElement extends CanvasItemElement {
static getTemplate() {
return document.getElementById("template-edge")
}
svgSlotted
lineElement
onConnect() {
const canvas = this.findFirstAncestor(CanvasElement)
const fromNode = canvas.nodeElements[this.getAttribute("node-from")]
const fromSide = this.getAttribute("node-from-side")
const [x1, y1] = fromNode.getCenterCoordinatesOfSide(fromSide)
const toNode = canvas.nodeElements[this.getAttribute("node-to")]
const toSide = this.getAttribute("node-to-side")
const [x2, y2] = toNode.getCenterCoordinatesOfSide(toSide)
this.svgSlotted = document.createElementNS("http://www.w3.org/2000/svg", "svg")
this.svgSlotted.slot = "edge-svg"
this.svgSlotted.style.setProperty("position", "absolute")
this.svgSlotted.style.setProperty("left", "0")
this.svgSlotted.style.setProperty("top", "0")
this.svgSlotted.style.setProperty("overflow", "visible")
this.lineElement = document.createElementNS("http://www.w3.org/2000/svg", "line")
this.lineElement.setAttribute("x1", x1)
this.lineElement.setAttribute("y1", y1)
this.lineElement.setAttribute("x2", x2)
this.lineElement.setAttribute("y2", y2)
this.lineElement.style.setProperty("stroke", this.constructor.colorToCSS(this.getAttribute("color")))
this.lineElement.style.setProperty("stroke-width", "var(--edge-width)")
this.svgSlotted.appendChild(this.lineElement)
this.appendChild(this.svgSlotted)
}
}

View file

@ -1,5 +1,5 @@
export {NodeFileElement, NodeGroupElement, NodeTextElement} from "./node.mjs"
export {NodeFileElement, NodeGroupElement, NodeTextElement} from "src/elements/canvas/node/base.mjs"
export {MarkdownElement, HashtagElement, WikilinkElement, FrontMatterElement} from "./markdown.mjs"
export {CanvasElement} from "./canvas/canvas.mjs"
export {DisplayElement} from "./display.mjs"
export {EdgeElement} from "./edge.mjs"
export {EdgeElement} from "src/elements/canvas/edge/base.mjs"

View file

@ -1,133 +0,0 @@
import { CanvasItemElement } from "./canvas/canvas.mjs";
import { DisplayElement } from "./display.mjs";
/**
* Error in the fetching of a file.
*/
export class FetchError extends Error {
/**
* The {@link Response} object of the failed request.
*/
response
constructor(response, message) {
super(message)
this.response = response
}
}
export class NodeElement extends CanvasItemElement {
getCenterCoordinatesOfSide(side) {
switch(side) {
case "top":
return [
Number(this.getAttribute("x")) + Number(this.getAttribute("width")) / 2,
Number(this.getAttribute("y")),
]
case "bottom":
return [
Number(this.getAttribute("x")) + Number(this.getAttribute("width")) / 2,
Number(this.getAttribute("y")) + Number(this.getAttribute("height")),
]
case "left":
return [
Number(this.getAttribute("x")),
Number(this.getAttribute("y")) + Number(this.getAttribute("height")) / 2,
]
case "right":
return [
Number(this.getAttribute("x")) + Number(this.getAttribute("width")),
Number(this.getAttribute("y")) + Number(this.getAttribute("height")) / 2,
]
}
}
}
export class NodeGroupElement extends NodeElement {
static getTemplate() {
return document.getElementById("template-node-group")
}
instanceElement
labelSlotted
onConnect() {
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`)
this.instanceElement.style.setProperty("width", `${this.getAttribute("width")}px`)
this.instanceElement.style.setProperty("height", `${this.getAttribute("height")}px`)
this.instanceElement.style.setProperty("--color-node", this.constructor.colorToCSS(this.getAttribute("color")))
this.labelSlotted = document.createElement("span")
this.labelSlotted.slot = "node-label"
this.labelSlotted.innerText = this.getAttribute("label")
this.appendChild(this.labelSlotted)
}
}
export class NodeFileElement extends NodeElement {
static getTemplate() {
return document.getElementById("template-node-file")
}
instanceElement
nameSlotted
contentsSlotted
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`)
this.instanceElement.style.setProperty("width", `${this.getAttribute("width")}px`)
this.instanceElement.style.setProperty("height", `${this.getAttribute("height")}px`)
this.instanceElement.style.setProperty("--color-node", this.constructor.colorToCSS(this.getAttribute("color")))
this.nameSlotted = document.createElement("x-wikilink")
this.nameSlotted.slot = "node-title"
this.nameSlotted.setAttribute("wref", this.getAttribute("file"))
const nameSlottedText = document.createElement("span")
nameSlottedText.slot = "wikilink-text"
nameSlottedText.innerText = this.getAttribute("file-name")
this.nameSlotted.appendChild(nameSlottedText)
this.appendChild(this.nameSlotted)
this.contentsSlotted = document.createElement(customElements.getName(DisplayElement))
this.contentsSlotted.slot = "node-contents"
const firstDisplayAncestor = this.findFirstAncestor(DisplayElement)
this.contentsSlotted.setAttribute("vref", firstDisplayAncestor.getAttribute("vref"))
this.contentsSlotted.setAttribute("wref", this.getAttribute("file"))
this.appendChild(this.contentsSlotted)
}
}
export class NodeTextElement extends NodeElement {
static getTemplate() {
return document.getElementById("template-node-text")
}
instanceElement
contentsSlotted
onConnect() {
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`)
this.instanceElement.style.setProperty("width", `${this.getAttribute("width")}px`)
this.instanceElement.style.setProperty("height", `${this.getAttribute("height")}px`)
this.instanceElement.style.setProperty("--color-node", this.constructor.colorToCSS(this.getAttribute("color")))
this.contentsSlotted = document.createElement("x-markdown")
this.contentsSlotted.slot = "node-contents"
this.contentsSlotted.setAttribute("contents", this.getAttribute("text"))
this.appendChild(this.contentsSlotted)
}
}

View file

@ -6,3 +6,18 @@
* The called method is abstract, but has not been overridden by the child class.
*/
export class NotImplementedError extends Error {}
/**
* Error in a {@link fetch} request.
*/
export class FetchError extends Error {
/**
* The {@link Response} object of the failed request.
*/
response
constructor(response, message) {
super(message)
this.response = response
}
}