comparison 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
comparison
equal deleted inserted replaced
2375:623836db99af 2376:4556eebe5d73
1 import { TextField } from "@material/mwc-textfield";
2 import debug from "debug";
3 import { css, html, LitElement, PropertyValues } from "lit";
4 import { customElement, property, state } from "lit/decorators.js";
5 import { NamedNode } from "n3";
6 import { getTopGraph } from "./RdfdbSyncedGraph";
7 import { SyncedGraph } from "./SyncedGraph";
8 export { Button } from "@material/mwc-button";
9 export { Dialog } from "@material/mwc-dialog";
10 export { TextField } from "@material/mwc-textfield";
11
12 const log = debug("rdisplay");
13
14 @customElement("resource-display")
15 export class ResourceDisplay extends LitElement {
16 graph!: SyncedGraph;
17 static styles = [
18 css`
19 :host {
20 display: inline-block;
21 }
22
23 a.resource {
24 color: inherit;
25 text-decoration: none;
26 }
27
28 .resource {
29 border: 1px solid #545454;
30 border-radius: 5px;
31 padding: 1px;
32 margin: 2px;
33 background: rgb(49, 49, 49);
34 display: inline-block;
35 text-shadow: 1px 1px 2px black;
36 }
37 .resource.minor {
38 background: none;
39 border: none;
40 }
41 .resource a {
42 color: rgb(150, 150, 255);
43 padding: 1px;
44 display: inline-block;
45 }
46 .resource.minor a {
47 text-decoration: none;
48 color: rgb(155, 155, 193);
49 padding: 0;
50 }
51 `,
52 ];
53
54 render() {
55 let renameDialog = html``;
56 if (this.renameDialogOpen) {
57 renameDialog = html` <mwc-dialog id="renameDialog" open @closing=${this.onRenameClosing} @closed=${this.onRenameClosed}>
58 <p>
59 New label:
60 <mwc-textfield id="renameField" dialogInitialFocus .value=${this.renameTo}></mwc-textfield>
61 </p>
62 <mwc-button dialogAction="cancel" slot="secondaryAction">Cancel</mwc-button>
63 <mwc-button dialogAction="ok" slot="primaryAction">OK</mwc-button>
64 </mwc-dialog>`;
65 }
66
67 return html` <span class="${this.resClasses()}">
68 <a href="${this.href()}" id="uri"> <!-- type icon goes here -->${this.label}</a>
69 ${this.rename ? html`<button @click=${this.onRename}>Rename</button>` : ""} </span
70 >${renameDialog}`;
71 //
72 }
73 @property() uri?: NamedNode;
74
75 @state() label: string = "";
76 @state() renameDialogOpen = false;
77 @state() renameTo = "";
78
79 @property({ type: Boolean }) rename: boolean = false;
80 @property({ type: Boolean }) noclick: boolean = false;
81 @property({ type: Boolean }) minor: boolean = false;
82
83 constructor() {
84 super();
85 getTopGraph().then((g) => {
86 this.graph = g;
87 this.onUri();
88 });
89 }
90
91 updated(changedProperties: PropertyValues) {
92 if (changedProperties.has("uri")) {
93 this.onUri();
94 }
95 }
96
97 private onUri() {
98 if (!this.graph) {
99 return; /*too soon, but getTopGraph will call us again*/
100 }
101
102 if (this.uri === undefined) {
103 this.label = "(unset)";
104 } else if (this.uri === null) {
105 throw 'use undefined please'
106 } else {
107 this.graph.runHandler(this.compile.bind(this, this.graph), `label for ${this.uri.id}`);
108 }
109 }
110 private compile(graph: SyncedGraph) {
111 if (this.uri === undefined) {
112 return;
113 } else {
114 this.label = this.graph.labelOrTail(this.uri);
115 }
116 }
117
118 private href(): string {
119 if (!this.uri || this.noclick) {
120 return "javascript:;";
121 }
122 return this.uri.value;
123 }
124
125 private resClasses() {
126 return this.minor ? "resource minor" : "resource";
127 }
128
129 private onRename() {
130 this.renameTo = this.label;
131 this.renameDialogOpen = true;
132 setTimeout(() => {
133 // I! 👏 know! 👏 the! 👏 element! 👏 I! 👏 want!
134 const inputEl = this.shadowRoot!.querySelector("#renameField")!.shadowRoot!.querySelector("input")! as HTMLInputElement;
135 inputEl.setSelectionRange(0, -1);
136 }, 100);
137 }
138
139 // move to SyncedGraph
140 private whatCtxHeldTheObj(subj: NamedNode, pred: NamedNode): NamedNode {
141 var ctxs = this.graph.contextsWithPattern(subj, pred, null);
142 if (ctxs.length != 1) {
143 throw new Error(`${ctxs.length} ${pred.id} stmts for ${subj.id}`);
144 }
145 return ctxs[0];
146 }
147
148 private onRenameClosing(ev: CustomEvent) {
149 this.renameTo = (this.shadowRoot!.querySelector("#renameField")! as TextField).value;
150 }
151
152 private onRenameClosed(ev: CustomEvent) {
153 this.renameDialogOpen = false;
154 if (ev.detail.action == "ok") {
155 var label = this.graph.Uri("rdfs:label");
156 if (this.uri === undefined) {
157 throw "lost uri";
158 }
159 const ctx = this.whatCtxHeldTheObj(this.uri, label);
160 this.graph.patchObject(this.uri, label, this.graph.Literal(this.renameTo), ctx);
161 }
162 this.renameTo = "";
163 }
164 }