@igea/oac_frontend 1.0.48 → 1.0.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/controllers/investigation.js +14 -4
- package/src/locales/en.json +11 -0
- package/src/locales/it.json +11 -0
- package/src/public/images/search.png +0 -0
- package/src/public/js/app/vue-investigation.js +250 -0
- package/src/views/investigation/form.twig +136 -0
- package/src/views/sidebar.twig +8 -4
- package/src/views/investigation/new.twig +0 -32
package/package.json
CHANGED
|
@@ -4,15 +4,25 @@ const DataModel = require('../models/DataModel');
|
|
|
4
4
|
|
|
5
5
|
module.exports = function(serviceName) {
|
|
6
6
|
/**
|
|
7
|
-
* @route GET /
|
|
7
|
+
* @route GET /investigation/form/:uuid? redirect to the investigation form
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const renderForm = function(req, res, uuid){
|
|
10
11
|
let data = new DataModel(req, {
|
|
11
12
|
root: serviceName,
|
|
12
|
-
title: '
|
|
13
|
+
title: 'Investigation Creation',
|
|
13
14
|
currentPath: req.baseUrl +req.path,
|
|
15
|
+
uuid
|
|
14
16
|
});
|
|
15
|
-
res.render('investigation/
|
|
17
|
+
res.render('investigation/form.twig', data.toJson());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
router.get('/form', (req, res) => {
|
|
21
|
+
renderForm(req, res, null);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
router.get('/form/:uuid', (req, res) => {
|
|
25
|
+
renderForm(req, res, req.params.uuid);
|
|
16
26
|
});
|
|
17
27
|
|
|
18
28
|
return router
|
package/src/locales/en.json
CHANGED
|
@@ -86,6 +86,17 @@
|
|
|
86
86
|
"max_size": "Each file must be less than 10MB"
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
|
+
"investigation":{
|
|
90
|
+
"new": {
|
|
91
|
+
"title": "New Investigation",
|
|
92
|
+
"description": "Compila il modulo sottostante per creare una nuova indagine.",
|
|
93
|
+
"form_invalid": "The form contains errors. Please correct them before submitting.",
|
|
94
|
+
"submit": "Save",
|
|
95
|
+
"reset": "Reset",
|
|
96
|
+
"show_more": "Show more",
|
|
97
|
+
"confirm": "Confirm"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
89
100
|
"search": {
|
|
90
101
|
"fast": {
|
|
91
102
|
"title": "Fast search"
|
package/src/locales/it.json
CHANGED
|
@@ -89,6 +89,17 @@
|
|
|
89
89
|
"invalid_file": "Tipo di file non valido"
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
|
+
"investigation": {
|
|
93
|
+
"new": {
|
|
94
|
+
"title": "Nuova Indagine",
|
|
95
|
+
"description": "Compila il modulo sottostante per creare una nuova indagine.",
|
|
96
|
+
"form_invalid": "La scheda contiene errori. Correggerli per poterla salvare correttamente.",
|
|
97
|
+
"submit": "Invia",
|
|
98
|
+
"reset": "Reimposta",
|
|
99
|
+
"show_more": "Mostra di più",
|
|
100
|
+
"confirm": "Conferma"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
92
103
|
"search": {
|
|
93
104
|
"title" : "Ricerca",
|
|
94
105
|
"fast": {
|
|
Binary file
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
const {createApp} = Vue;
|
|
2
|
+
|
|
3
|
+
const appId = 'investigation-app';
|
|
4
|
+
const shaclId = 'shacl-form';
|
|
5
|
+
const templateIRIToExcludeFromSearch = [
|
|
6
|
+
"http://diagnostica/indagine/$UUID$"
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
10
|
+
const el = document.getElementById(appId);
|
|
11
|
+
|
|
12
|
+
const app = createApp({
|
|
13
|
+
delimiters: ['{@', '@}'],
|
|
14
|
+
data() {
|
|
15
|
+
return {
|
|
16
|
+
cur_role: parseInt(el.dataset.cur_role),
|
|
17
|
+
uuid: parseInt(el.dataset.uuid) || null,
|
|
18
|
+
form: null,
|
|
19
|
+
enabled: el.dataset.editing == "true",
|
|
20
|
+
serializedForm: "",
|
|
21
|
+
validForm: false,
|
|
22
|
+
labels: {
|
|
23
|
+
|
|
24
|
+
},
|
|
25
|
+
search: {
|
|
26
|
+
offset: 0,
|
|
27
|
+
limit: 10,
|
|
28
|
+
prefix: "",
|
|
29
|
+
results: [],
|
|
30
|
+
end: false,
|
|
31
|
+
input: null,
|
|
32
|
+
selected: null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
mounted() {
|
|
37
|
+
this.initShaclForm();
|
|
38
|
+
this.load();
|
|
39
|
+
},
|
|
40
|
+
computed:{
|
|
41
|
+
outputStyle(){
|
|
42
|
+
var style = {
|
|
43
|
+
"color": "red",
|
|
44
|
+
"font-weight": "bold",
|
|
45
|
+
"max-height": "400px",
|
|
46
|
+
"overflow-y": "auto",
|
|
47
|
+
"white-space": "pre-wrap"
|
|
48
|
+
}
|
|
49
|
+
if(this.validForm)
|
|
50
|
+
style["color"] = "green";
|
|
51
|
+
return style;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
methods: {
|
|
55
|
+
initShaclForm() {
|
|
56
|
+
var _this = this;
|
|
57
|
+
this.form = document.querySelector("shacl-form");
|
|
58
|
+
const output = document.getElementById("shacl-output")
|
|
59
|
+
this.form.addEventListener('change', event => {
|
|
60
|
+
// check if form data validates according to the SHACL shapes
|
|
61
|
+
_this.validForm = event.detail?.valid;
|
|
62
|
+
_this.serializedForm = _this.form.serialize();
|
|
63
|
+
});
|
|
64
|
+
this.form.addEventListener("ready", () => {
|
|
65
|
+
var intervalId = setInterval(() => {
|
|
66
|
+
if(_this.form.shadowRoot){
|
|
67
|
+
clearInterval(intervalId);
|
|
68
|
+
_this.inputIdentifizier();
|
|
69
|
+
if(!_this.enabled)
|
|
70
|
+
_this.disableInteractions(_this.form);
|
|
71
|
+
}
|
|
72
|
+
}, 100);
|
|
73
|
+
});
|
|
74
|
+
},
|
|
75
|
+
searchByPrefixStart(rokitInput, prefix){
|
|
76
|
+
this.search.offset = 0;
|
|
77
|
+
this.search.prefix = prefix;
|
|
78
|
+
this.search.results = [];
|
|
79
|
+
this.search.end = false;
|
|
80
|
+
this.search.input = rokitInput;
|
|
81
|
+
this.search.selected = null;
|
|
82
|
+
if(prefix) this.searchByPrefix();
|
|
83
|
+
},
|
|
84
|
+
confirmSelection(){
|
|
85
|
+
if(this.search.selected && this.search.selected.instance)
|
|
86
|
+
this.search.input.value = this.search.selected.instance;
|
|
87
|
+
this.searchByPrefixStart(null, null);
|
|
88
|
+
},
|
|
89
|
+
searchByPrefix(){
|
|
90
|
+
if(this.search.end) return;
|
|
91
|
+
var _this = this;
|
|
92
|
+
var request = axios.post("/backend/fuseki/search/by-prefix", {
|
|
93
|
+
limit: this.search.limit,
|
|
94
|
+
offset: this.search.offset,
|
|
95
|
+
prefix: this.search.prefix
|
|
96
|
+
});
|
|
97
|
+
request.then(response => {
|
|
98
|
+
var data = response.data;
|
|
99
|
+
if(data.success){
|
|
100
|
+
_this.search.results = _this.search.results.concat(data.data);
|
|
101
|
+
_this.search.offset += data.data.length;
|
|
102
|
+
if(data.data.length < _this.search.limit){
|
|
103
|
+
_this.search.end = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}).catch(error => {
|
|
107
|
+
console.log(error);
|
|
108
|
+
});
|
|
109
|
+
},
|
|
110
|
+
monitorChanges(root, callback) {
|
|
111
|
+
const observer = new MutationObserver(mutations => {
|
|
112
|
+
mutations.forEach(mutation => {
|
|
113
|
+
callback(mutation);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
observer.observe(root, {
|
|
117
|
+
childList: true, // nuove aggiunte / rimozioni di nodi
|
|
118
|
+
subtree: true // osserva rischiosamente tutto l’albero
|
|
119
|
+
//attributes: true, // monitora cambi di attributi
|
|
120
|
+
//characterData: true // monitora testo interno dei nodi
|
|
121
|
+
});
|
|
122
|
+
return observer;
|
|
123
|
+
},
|
|
124
|
+
inputIdentifizier(){
|
|
125
|
+
const form = this.form;
|
|
126
|
+
const _this = this;
|
|
127
|
+
|
|
128
|
+
const disableIDField = () => {
|
|
129
|
+
const shadow = form.shadowRoot;
|
|
130
|
+
if (!shadow) return false;
|
|
131
|
+
|
|
132
|
+
// Trova la label "ID"
|
|
133
|
+
const labels = Array.from(shadow.querySelectorAll("label"))
|
|
134
|
+
.filter(l => l.textContent.trim() === "ID");
|
|
135
|
+
|
|
136
|
+
if (labels.length == 0) return false;
|
|
137
|
+
for(var i=0; i<labels.length; i++){
|
|
138
|
+
const label = labels[i];
|
|
139
|
+
if (!label) continue;
|
|
140
|
+
// Container della property
|
|
141
|
+
const container = label.closest(".property-instance");
|
|
142
|
+
if (!container) return false;
|
|
143
|
+
|
|
144
|
+
// Disabilita rokit-input
|
|
145
|
+
const rokitInput = container.querySelector("rokit-input");
|
|
146
|
+
if (rokitInput) {
|
|
147
|
+
if(rokitInput.value == ""){
|
|
148
|
+
rokitInput.value = _this.generateIRI(rokitInput.placeholder);
|
|
149
|
+
}
|
|
150
|
+
rokitInput.setAttribute("disabled", "true");
|
|
151
|
+
rokitInput.style.opacity = "0.6";
|
|
152
|
+
rokitInput.style.pointerEvents = "none";
|
|
153
|
+
|
|
154
|
+
var escludeSearchButton = templateIRIToExcludeFromSearch.includes(rokitInput.placeholder);
|
|
155
|
+
|
|
156
|
+
if(_this.enabled && !escludeSearchButton){
|
|
157
|
+
// Aggiungo bottone IMG per la ricerca
|
|
158
|
+
let next = label.nextElementSibling;
|
|
159
|
+
let imgClass = "search-identifier-icon";
|
|
160
|
+
if (!(next && next.tagName === "IMG"
|
|
161
|
+
&& next.classList.contains(imgClass))) {
|
|
162
|
+
// creo immagine
|
|
163
|
+
const img = document.createElement("img");
|
|
164
|
+
img.src = "/frontend/images/search.png";
|
|
165
|
+
img.style.width = "24px"; img.style.height = "24px";
|
|
166
|
+
img.style["margin-left"] = "5px"; img.style["margin-right"] = "5px";
|
|
167
|
+
img.style.cursor = "pointer";
|
|
168
|
+
img.classList.add(imgClass);
|
|
169
|
+
img.onclick = function(){
|
|
170
|
+
var prefix = rokitInput.placeholder.replace("$uuid$", "").replace("$UUID$", "");
|
|
171
|
+
prefix = "http://diagnostica/vocabularies/quesito-diagnostico/";
|
|
172
|
+
_this.searchByPrefixStart(rokitInput, prefix);
|
|
173
|
+
}
|
|
174
|
+
// inserisco subito dopo la label
|
|
175
|
+
label.insertAdjacentElement("afterend", img);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// SHACL NODE superiore che contiene TUTTO il blocco ID
|
|
180
|
+
const shaclNode = container.closest("shacl-node");
|
|
181
|
+
// Rimuovi TUTTI i remove-button
|
|
182
|
+
if (shaclNode) {
|
|
183
|
+
shaclNode.querySelectorAll("div.remove-button-wrapper").forEach(el => {
|
|
184
|
+
el.style.display = "none";
|
|
185
|
+
});
|
|
186
|
+
shaclNode.querySelectorAll("rokit-button.remove-button").forEach(btn => {
|
|
187
|
+
btn.style.display = "none";
|
|
188
|
+
});
|
|
189
|
+
// Rimuovi TUTTI gli add-button all'interno del nodo ID
|
|
190
|
+
shaclNode.querySelectorAll("rokit-select.add-button").forEach(btn => {
|
|
191
|
+
btn.style.display = "none";
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return true;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const observer = this.monitorChanges(form.shadowRoot, (mutation) => {
|
|
199
|
+
disableIDField();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
disableIDField();
|
|
203
|
+
},
|
|
204
|
+
disableInteractions(root) {
|
|
205
|
+
root.style.pointerEvents = 'none';
|
|
206
|
+
|
|
207
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
|
|
208
|
+
|
|
209
|
+
while (walker.nextNode()) {
|
|
210
|
+
const el = walker.currentNode;
|
|
211
|
+
|
|
212
|
+
// Blocca click e interazioni mouse
|
|
213
|
+
el.style.pointerEvents = 'none';
|
|
214
|
+
|
|
215
|
+
// Blocca editing su input / textarea / select
|
|
216
|
+
if (el instanceof HTMLInputElement ||
|
|
217
|
+
el instanceof HTMLTextAreaElement ||
|
|
218
|
+
el instanceof HTMLSelectElement ||
|
|
219
|
+
el instanceof HTMLButtonElement) {
|
|
220
|
+
el.disabled = true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Blocca contenteditable
|
|
224
|
+
if (el.isContentEditable) {
|
|
225
|
+
el.contentEditable = "false";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Ricorsione dentro Shadow DOM (se presente)
|
|
229
|
+
if (el.shadowRoot) {
|
|
230
|
+
disableInteractions(el.shadowRoot);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
generateIRI(template, uuid){
|
|
235
|
+
var _uuid = uuid || crypto.randomUUID();
|
|
236
|
+
return template.replace("$uuid$", _uuid).replace("$UUID$", _uuid);
|
|
237
|
+
},
|
|
238
|
+
load() {
|
|
239
|
+
|
|
240
|
+
},
|
|
241
|
+
save() {
|
|
242
|
+
|
|
243
|
+
},
|
|
244
|
+
reset() {
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
app.mount(`#${appId}`);
|
|
250
|
+
});
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
{% set showSidebar = true %}
|
|
2
|
+
{% extends "../base.twig" %}
|
|
3
|
+
|
|
4
|
+
{% block extendHead %}
|
|
5
|
+
<script src="/{{ root }}/js/lib/shacl-form.bundle.js" type="module"></script>
|
|
6
|
+
<script src="/{{ root }}/js/app/vue-investigation.js"></script>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<style>
|
|
10
|
+
/* Sfondo fullscreen semi-trasparente */
|
|
11
|
+
.modal-overlay {
|
|
12
|
+
position: fixed;
|
|
13
|
+
top: 0;
|
|
14
|
+
left: 0;
|
|
15
|
+
width: 100%;
|
|
16
|
+
height: 100%;
|
|
17
|
+
background: rgba(0, 0, 0, 0.6); /* nero ombreggiato */
|
|
18
|
+
display: flex;
|
|
19
|
+
justify-content: center;
|
|
20
|
+
align-items: center;
|
|
21
|
+
z-index: 1000;
|
|
22
|
+
visibility: visible;
|
|
23
|
+
transition: opacity 0.3s ease;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Box centrale della modale */
|
|
27
|
+
.modal-content {
|
|
28
|
+
background: #fff;
|
|
29
|
+
padding: 20px;
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
max-width: 650px;
|
|
32
|
+
width: 90%;
|
|
33
|
+
box-shadow: 0 5px 20px rgba(0,0,0,0.3);
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Label */
|
|
39
|
+
.modal-content label {
|
|
40
|
+
font-weight: bold;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Dropdown a 2 colonne */
|
|
44
|
+
.modal-content select {
|
|
45
|
+
width: 100%;
|
|
46
|
+
display: grid;
|
|
47
|
+
grid-template-columns: 1fr 1fr; /* 2 colonne */
|
|
48
|
+
gap: 10px;
|
|
49
|
+
padding: 5px;
|
|
50
|
+
font-size: 16px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Bottone chiusura */
|
|
54
|
+
.close-btn {
|
|
55
|
+
align-self: flex-end;
|
|
56
|
+
background: transparent;
|
|
57
|
+
border: none;
|
|
58
|
+
font-size: 40px;
|
|
59
|
+
cursor: pointer;
|
|
60
|
+
float: right;
|
|
61
|
+
}
|
|
62
|
+
</style>
|
|
63
|
+
|
|
64
|
+
{% endblock %}
|
|
65
|
+
|
|
66
|
+
{% block content %}
|
|
67
|
+
|
|
68
|
+
<div>
|
|
69
|
+
<h2 style="display:flex; justify-content:space-between; align-items:center;">
|
|
70
|
+
<span>{{ t('investigation.new.title') }}:</span>
|
|
71
|
+
</h2>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div id="investigation-app"
|
|
75
|
+
data-cur_role="{{ user.role }}"
|
|
76
|
+
data-uuid="{{ uuid }}"
|
|
77
|
+
data-editing="{{ user.role != 3 }}"
|
|
78
|
+
>
|
|
79
|
+
|
|
80
|
+
<shacl-form id="shacl-form" data-collapse="open"
|
|
81
|
+
data-shapes-url="/backend/ontology/schema/ttl2">
|
|
82
|
+
</shacl-form>
|
|
83
|
+
|
|
84
|
+
{% if user.role != 3 %}
|
|
85
|
+
<!-- Buttons -->
|
|
86
|
+
<div class="col-12 text-center mt-4">
|
|
87
|
+
<button v-if="validForm" @click="save()" type="submit" class="btn btn-primary me-2">{{ t('investigation.new.submit') }}</button>
|
|
88
|
+
<button @click="reset()" type="button" class="btn btn-secondary">{{ t('investigation.new.reset') }}</button>
|
|
89
|
+
</div>
|
|
90
|
+
{% if user.role in [0, 1] %}
|
|
91
|
+
<fieldset id="shacl-output" style="margin-top:10px;
|
|
92
|
+
border: solid 1px gray;
|
|
93
|
+
border-radius: 10px;
|
|
94
|
+
padding: 10px;">
|
|
95
|
+
<legend>Generated output: [{@ validForm @}]</legend>
|
|
96
|
+
<pre :style="outputStyle">{@ serializedForm @}</pre>
|
|
97
|
+
</fieldset>
|
|
98
|
+
{% endif %}
|
|
99
|
+
{% endif %}
|
|
100
|
+
|
|
101
|
+
<div style="margin-top:200px;"></div>
|
|
102
|
+
|
|
103
|
+
<div class="modal-overlay" v-cloak v-if="search.input != null">
|
|
104
|
+
<div class="modal-content">
|
|
105
|
+
<div class="row" style="line-height:40px; margin-bottom:10px;">
|
|
106
|
+
<span style="font-weight:bold; float:left; max-width:570px;">
|
|
107
|
+
Seleziona istanza:
|
|
108
|
+
</span>
|
|
109
|
+
<span style="float:right; max-width:24px;" class="close-btn" @click="searchByPrefixStart(null, null);">×</span>
|
|
110
|
+
</div>
|
|
111
|
+
<select size="10" v-model="search.selected">
|
|
112
|
+
<option v-for="item in search.results" :value="item">{@ (item.label && item.label.trim()) ? item.label : item.instance @}</option>
|
|
113
|
+
</select>
|
|
114
|
+
<div v-if="search.selected">
|
|
115
|
+
<span style="font-size:12px; color:gray;">{@ search.selected.instance @}</span>
|
|
116
|
+
</div>
|
|
117
|
+
<div style="margin-top:10px;">
|
|
118
|
+
<span @click="searchByPrefix()" v-if="!search.end" style="float:left;
|
|
119
|
+
cursor: pointer; color: blue;
|
|
120
|
+
border: solid 1px blue;
|
|
121
|
+
border-radius: 4px; padding: 4px;">
|
|
122
|
+
{{ t('investigation.new.show_more') }}...
|
|
123
|
+
</span>
|
|
124
|
+
<span v-if="search.selected" @click="confirmSelection()" style="float:right;
|
|
125
|
+
cursor: pointer; color: green;
|
|
126
|
+
border: solid 1px green;
|
|
127
|
+
border-radius: 4px; padding: 4px;">
|
|
128
|
+
{{ t('investigation.new.confirm') }}
|
|
129
|
+
</span>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
</div>
|
|
135
|
+
|
|
136
|
+
{% endblock %}
|
package/src/views/sidebar.twig
CHANGED
|
@@ -47,12 +47,16 @@
|
|
|
47
47
|
<i class="fa-solid fa-book-bookmark"></i>
|
|
48
48
|
<span>{{ t('users.vocabolaries.title') }}</span>
|
|
49
49
|
</a>
|
|
50
|
-
<a href="/{{ root }}/investigation/new" class="{% if '/investigation/new' in currentPath %}active{% endif %}">
|
|
51
|
-
<i class="fa-solid fa-clipboard-list"></i>
|
|
52
|
-
<span>Indagine</span>
|
|
53
|
-
</a>
|
|
54
50
|
</div>
|
|
55
51
|
</div>
|
|
52
|
+
|
|
53
|
+
<div class="menu-item">
|
|
54
|
+
<a href="/{{ root }}/investigation/form" class="{% if '/investigation/form' in currentPath %}active{% endif %}">
|
|
55
|
+
<i class="fa-solid fa-clipboard-list"></i>
|
|
56
|
+
<span>{{ t('investigation.new.title') }}</span>
|
|
57
|
+
</a>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
56
60
|
{% endif %}
|
|
57
61
|
|
|
58
62
|
{# Ricerca #}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{% set showSidebar = true %}
|
|
2
|
-
{% extends "../base.twig" %}
|
|
3
|
-
|
|
4
|
-
{% block extendHead %}
|
|
5
|
-
<script src="/{{ root }}/js/lib/shacl-form.bundle.js" type="module"></script>
|
|
6
|
-
{% endblock %}
|
|
7
|
-
|
|
8
|
-
{% block content %}
|
|
9
|
-
|
|
10
|
-
<div>
|
|
11
|
-
<h2 style="display:flex; justify-content:space-between; align-items:center;">
|
|
12
|
-
<span>Nuova Indagine:</span>
|
|
13
|
-
</h2>
|
|
14
|
-
</div>
|
|
15
|
-
|
|
16
|
-
<shacl-form data-shapes-url="/backend/ontology/schema/ttl2"></shacl-form>
|
|
17
|
-
|
|
18
|
-
<script>
|
|
19
|
-
const form = document.querySelector("shacl-form")
|
|
20
|
-
form.addEventListener('change', event => {
|
|
21
|
-
// check if form data validates according to the SHACL shapes
|
|
22
|
-
if (event.detail?.valid) {
|
|
23
|
-
// get data graph as RDF triples and
|
|
24
|
-
// log them to the browser console
|
|
25
|
-
const triples = form.serialize()
|
|
26
|
-
console.log('entered form data', triples)
|
|
27
|
-
// store the data somewhere, e.g. in a triple store
|
|
28
|
-
}
|
|
29
|
-
})
|
|
30
|
-
</script>
|
|
31
|
-
|
|
32
|
-
{% endblock %}
|