Mercurial > code > home > repos > light9
diff web/ResourceDisplay.ts @ 2376:4556eebe5d73
topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author | drewp@bigasterisk.com |
---|---|
date | Sun, 12 May 2024 19:02:10 -0700 |
parents | light9/web/ResourceDisplay.ts@ed0db55f604c |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/ResourceDisplay.ts Sun May 12 19:02:10 2024 -0700 @@ -0,0 +1,164 @@ +import { TextField } from "@material/mwc-textfield"; +import debug from "debug"; +import { css, html, LitElement, PropertyValues } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; +import { NamedNode } from "n3"; +import { getTopGraph } from "./RdfdbSyncedGraph"; +import { SyncedGraph } from "./SyncedGraph"; +export { Button } from "@material/mwc-button"; +export { Dialog } from "@material/mwc-dialog"; +export { TextField } from "@material/mwc-textfield"; + +const log = debug("rdisplay"); + +@customElement("resource-display") +export class ResourceDisplay extends LitElement { + graph!: SyncedGraph; + static styles = [ + css` + :host { + display: inline-block; + } + + a.resource { + color: inherit; + text-decoration: none; + } + + .resource { + border: 1px solid #545454; + border-radius: 5px; + padding: 1px; + margin: 2px; + background: rgb(49, 49, 49); + display: inline-block; + text-shadow: 1px 1px 2px black; + } + .resource.minor { + background: none; + border: none; + } + .resource a { + color: rgb(150, 150, 255); + padding: 1px; + display: inline-block; + } + .resource.minor a { + text-decoration: none; + color: rgb(155, 155, 193); + padding: 0; + } + `, + ]; + + render() { + let renameDialog = html``; + if (this.renameDialogOpen) { + renameDialog = html` <mwc-dialog id="renameDialog" open @closing=${this.onRenameClosing} @closed=${this.onRenameClosed}> + <p> + New label: + <mwc-textfield id="renameField" dialogInitialFocus .value=${this.renameTo}></mwc-textfield> + </p> + <mwc-button dialogAction="cancel" slot="secondaryAction">Cancel</mwc-button> + <mwc-button dialogAction="ok" slot="primaryAction">OK</mwc-button> + </mwc-dialog>`; + } + + return html` <span class="${this.resClasses()}"> + <a href="${this.href()}" id="uri"> <!-- type icon goes here -->${this.label}</a> + ${this.rename ? html`<button @click=${this.onRename}>Rename</button>` : ""} </span + >${renameDialog}`; + // + } + @property() uri?: NamedNode; + + @state() label: string = ""; + @state() renameDialogOpen = false; + @state() renameTo = ""; + + @property({ type: Boolean }) rename: boolean = false; + @property({ type: Boolean }) noclick: boolean = false; + @property({ type: Boolean }) minor: boolean = false; + + constructor() { + super(); + getTopGraph().then((g) => { + this.graph = g; + this.onUri(); + }); + } + + updated(changedProperties: PropertyValues) { + if (changedProperties.has("uri")) { + this.onUri(); + } + } + + private onUri() { + if (!this.graph) { + return; /*too soon, but getTopGraph will call us again*/ + } + + if (this.uri === undefined) { + this.label = "(unset)"; + } else if (this.uri === null) { + throw 'use undefined please' + } else { + this.graph.runHandler(this.compile.bind(this, this.graph), `label for ${this.uri.id}`); + } + } + private compile(graph: SyncedGraph) { + if (this.uri === undefined) { + return; + } else { + this.label = this.graph.labelOrTail(this.uri); + } + } + + private href(): string { + if (!this.uri || this.noclick) { + return "javascript:;"; + } + return this.uri.value; + } + + private resClasses() { + return this.minor ? "resource minor" : "resource"; + } + + private onRename() { + this.renameTo = this.label; + this.renameDialogOpen = true; + setTimeout(() => { + // I! 👏 know! 👏 the! 👏 element! 👏 I! 👏 want! + const inputEl = this.shadowRoot!.querySelector("#renameField")!.shadowRoot!.querySelector("input")! as HTMLInputElement; + inputEl.setSelectionRange(0, -1); + }, 100); + } + + // move to SyncedGraph + private whatCtxHeldTheObj(subj: NamedNode, pred: NamedNode): NamedNode { + var ctxs = this.graph.contextsWithPattern(subj, pred, null); + if (ctxs.length != 1) { + throw new Error(`${ctxs.length} ${pred.id} stmts for ${subj.id}`); + } + return ctxs[0]; + } + + private onRenameClosing(ev: CustomEvent) { + this.renameTo = (this.shadowRoot!.querySelector("#renameField")! as TextField).value; + } + + private onRenameClosed(ev: CustomEvent) { + this.renameDialogOpen = false; + if (ev.detail.action == "ok") { + var label = this.graph.Uri("rdfs:label"); + if (this.uri === undefined) { + throw "lost uri"; + } + const ctx = this.whatCtxHeldTheObj(this.uri, label); + this.graph.patchObject(this.uri, label, this.graph.Literal(this.renameTo), ctx); + } + this.renameTo = ""; + } +}