Skip to content

Commit c3e063a

Browse files
committed
add button to save a query as example
1 parent 7b25bfd commit c3e063a

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

demo/dbgi.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<body>
1515
<div>
1616
<sparql-editor endpoint="https://biosoda.unil.ch/graphdb/repositories/emi-dbgi">
17-
<h1>SPARQL editors for SIB endpoints</h1>
17+
<h4>Other SPARQL editors for SIB endpoints</h4>
1818
<ul>
1919
<li><a href="/sparql-editor/uniprot">UniProt - protein knowledgebase</a></li>
2020
<li><a href="/sparql-editor/bgee">Bgee - gene expression</a></li>

src/sparql-editor.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export class SparqlEditor extends HTMLElement {
6464
container.innerHTML = `
6565
<div id="sparql-editor">
6666
<button id="sparql-add-prefixes-btn" class="btn" style="margin-bottom: 0.3em;">Add common prefixes</button>
67+
<button id="sparql-save-example-btn" class="btn" style="margin-bottom: 0.3em;">Save query as example</button>
6768
<div id="yasgui"></div>
6869
</div>
6970
<div>
@@ -172,6 +173,61 @@ export class SparqlEditor extends HTMLElement {
172173
});
173174
});
174175

176+
// Button to pop a dialog to save the query as an example in a turtle file
177+
const addExampleBtnEl = this.shadowRoot?.getElementById("sparql-save-example-btn");
178+
const capitalize = (str: any) => str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
179+
addExampleBtnEl?.addEventListener("click", () => {
180+
const dialog = document.createElement("dialog");
181+
dialog.style.width = "400px";
182+
dialog.style.padding = "1em";
183+
dialog.style.borderRadius = "8px";
184+
dialog.style.borderColor = "#cccccc";
185+
// <textarea id="description" name="description" rows="4" style="width: 100%;"></textarea><br><br>
186+
dialog.innerHTML = `
187+
<form id="example-form" method="dialog">
188+
<h3>Save query as example</h3>
189+
<p>Save the current query as an example in a turtle file that you can then submit to the repository where all examples are stored.</p>
190+
<label for="description">Description:</label><br>
191+
<input type="text" id="description" name="description" style="width: 100%;" maxlength="200"><br><br>
192+
<label for="keywords">Keywords (optional, comma separated):</label><br>
193+
<input type="text" id="keywords" name="keywords" style="width: 100%;"><br><br>
194+
<button type="submit" class="btn">Save</button>
195+
<button type="button" class="btn" onclick="this.closest('dialog').close()">Cancel</button>
196+
</form>
197+
`;
198+
this.shadowRoot?.appendChild(dialog);
199+
dialog.showModal();
200+
dialog.querySelector("#example-form")?.addEventListener("submit", (e) => {
201+
e.preventDefault();
202+
const description = (dialog.querySelector("#description") as HTMLTextAreaElement).value;
203+
const keywordsStr = (dialog.querySelector("#keywords") as HTMLInputElement).value.split(",").map((kw: string) => `"${kw.trim()}"`).join(', ');
204+
const queryType = capitalize(this.yasgui?.getTab()?.getYasqe().getQueryType())
205+
const endpointUrlWithSlash = this.endpointUrl.endsWith('/') ? this.endpointUrl : `${this.endpointUrl}/`;
206+
const exampleNumberForId = (this.exampleQueries.length + 1).toString().padStart(3, '0');
207+
const keywordsBit = keywordsStr.length > 2 ? `schema:keyword ${keywordsStr} ;\n ` : '';
208+
209+
const shaclStr = `@prefix ex: <${endpointUrlWithSlash}.well-known/sparql-examples/> .
210+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
211+
@prefix schema: <https://schema.org/> .
212+
@prefix sh: <http://www.w3.org/ns/shacl#> .
213+
214+
ex:${exampleNumberForId} a sh:SPARQLExecutable${['Select', 'Construct', "Ask"].includes(queryType) ? `,
215+
sh:SPARQL${queryType}Executable` : ''} ;
216+
rdfs:comment "${description}"@en ;
217+
sh:prefixes _:sparql_examples_prefixes ;
218+
sh:${queryType.toLowerCase()} """${this.yasgui?.getTab()?.getYasqe().getValue()}""" ;
219+
${keywordsBit}schema:target <${this.endpointUrl}> .`
220+
221+
const dataStr = `data:text/turtle;charset=utf-8,${encodeURIComponent(shaclStr)}`;
222+
const downloadAnchor = document.createElement("a");
223+
downloadAnchor.setAttribute("href", dataStr);
224+
downloadAnchor.setAttribute("download", `${exampleNumberForId}.ttl`);
225+
downloadAnchor.click();
226+
dialog.close();
227+
});
228+
});
229+
230+
175231
// Parse query params from URL and auto run query if provided in URL
176232
// NOTE: Yasqe already automatically load query param in the editor and run the query
177233
// But it does not trigger the .on("query") event, so it does not add limit
@@ -191,6 +247,11 @@ export class SparqlEditor extends HTMLElement {
191247
}
192248
}
193249

250+
// TODO: there is a SUGGESTIONS_LIMIT of 100 on the get. So doing filtering in postProcessHints is not ideal...
251+
// Best would be to have a way to filter the results in the get method directly
252+
// (it will also reduce the amount of SPARQL request done!)
253+
// It ctreates problem with UniProt query3 up:Natural_Variant_Annotation
254+
194255
// Original autocompleters: https://github.com/zazuko/Yasgui/blob/main/packages/yasqe/src/autocompleters/classes.ts#L8
195256
// Fork examples: https://github.com/zazuko/Yasgui/blob/main/webpack/pages/yasqe.html#L61
196257
prefixesCompleter = {
@@ -553,6 +614,9 @@ export class SparqlEditor extends HTMLElement {
553614
return curie;
554615
}
555616
}
617+
618+
619+
556620
}
557621

558622
function extractAllSubjectsAndTypes(query: string): Map<string, Set<string>> {

0 commit comments

Comments
 (0)