Mercurial > code > home > repos > light9
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 } |