@opengeospatial/jsonld-ui-utils 0.2.0 → 0.2.7
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/README.md +96 -74
- package/dist/index.cjs.js +458 -423
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.esm.js +458 -422
- package/dist/index.esm.js.map +1 -1
- package/dist/jsonld-ui-utils-leaflet.min.js +26 -0
- package/dist/jsonld-ui-utils-leaflet.min.js.map +1 -0
- package/dist/jsonld-ui-utils.css +45 -0
- package/dist/jsonld-ui-utils.min.js +4 -49
- package/dist/jsonld-ui-utils.min.js.map +1 -1
- package/dist/jsonld.d.ts +2 -2
- package/dist/leaflet.cjs.js +549 -0
- package/dist/leaflet.cjs.js.map +1 -0
- package/dist/leaflet.d.ts +10 -0
- package/dist/leaflet.esm.js +528 -0
- package/dist/leaflet.esm.js.map +1 -0
- package/dist/resource.d.ts +1 -2
- package/package.json +30 -8
package/dist/index.esm.js
CHANGED
|
@@ -1,84 +1,84 @@
|
|
|
1
1
|
import * as N3 from 'n3';
|
|
2
|
-
import * as jsonldLib from 'jsonld';
|
|
3
2
|
import { RdfXmlParser } from 'rdfxml-streaming-parser';
|
|
4
3
|
|
|
5
|
-
const jsonFetch = async url => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
});
|
|
11
|
-
return await response.json();
|
|
4
|
+
const jsonFetch = async (url) => {
|
|
5
|
+
const response = await fetch(url, {
|
|
6
|
+
headers: { 'Accept': 'application/json' },
|
|
7
|
+
});
|
|
8
|
+
return await response.json();
|
|
12
9
|
};
|
|
13
|
-
const mergeContexts = definitions => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
const mergeContexts = (definitions) => {
|
|
11
|
+
const mergePair = (a, b) => {
|
|
12
|
+
if (!a || !Object.keys(a).length) {
|
|
13
|
+
return b;
|
|
14
|
+
}
|
|
15
|
+
const result = { ...a };
|
|
16
|
+
for (const [k, v] of Object.entries(b)) {
|
|
17
|
+
result[k] = v;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
20
|
};
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if (!definitions.length) {
|
|
22
|
+
return {};
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
let currentContext = definitions[0];
|
|
33
|
-
for (let i = 1; i < definitions.length; i++) {
|
|
34
|
-
currentContext = mergePair(currentContext, definitions[i]);
|
|
35
|
-
}
|
|
36
|
-
return currentContext;
|
|
24
|
+
if (definitions.length === 1) {
|
|
25
|
+
return definitions[0];
|
|
26
|
+
}
|
|
27
|
+
let currentContext = definitions[0];
|
|
28
|
+
for (let i = 1; i < definitions.length; i++) {
|
|
29
|
+
currentContext = mergePair(currentContext, definitions[i]);
|
|
30
|
+
}
|
|
31
|
+
return currentContext;
|
|
37
32
|
};
|
|
38
33
|
async function loadContext(context) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
34
|
+
const loadedUrls = new Map();
|
|
35
|
+
const walk = async (definition, refChain) => {
|
|
36
|
+
for (const [key, value] of Object.entries(definition)) {
|
|
37
|
+
if (key === '@context') {
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
definition[key] = await load(value, refChain);
|
|
40
|
+
}
|
|
41
|
+
else if (typeof value === 'object' && value !== null) {
|
|
42
|
+
await walk(value, refChain);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const load = async (context, refChain) => {
|
|
47
|
+
if (context === null || typeof context === 'undefined') {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
if (Array.isArray(context)) {
|
|
51
|
+
// fetch and merge
|
|
52
|
+
const contextEntries = await Promise.all(context.map(e => load(e, refChain)));
|
|
53
|
+
return mergeContexts(contextEntries);
|
|
54
|
+
}
|
|
55
|
+
else if (typeof context === 'object') {
|
|
56
|
+
await walk(context, refChain);
|
|
57
|
+
return context;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
if (refChain === null || refChain === void 0 ? void 0 : refChain.includes(context)) {
|
|
61
|
+
throw new Error('Circular dependencies found: ' + refChain.join(' -> ') + ' -> ' + context);
|
|
62
|
+
}
|
|
63
|
+
const newRefChain = Array.isArray(refChain) ? refChain === null || refChain === void 0 ? void 0 : refChain.slice() : [];
|
|
64
|
+
newRefChain.push(context);
|
|
65
|
+
let newContext;
|
|
66
|
+
if (!loadedUrls.has(context)) {
|
|
67
|
+
newContext = await jsonFetch(context);
|
|
68
|
+
loadedUrls.set(context, newContext);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
newContext = loadedUrls.get(context);
|
|
72
|
+
}
|
|
73
|
+
return load(newContext['@context'], newRefChain);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
if (typeof context === 'object' && context !== null && '@context' in context) {
|
|
77
|
+
return load(context['@context']);
|
|
53
78
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const contextEntries = await Promise.all(context.map(e => load(e, refChain)));
|
|
57
|
-
return mergeContexts(contextEntries);
|
|
58
|
-
} else if (typeof context === 'object') {
|
|
59
|
-
await walk(context, refChain);
|
|
60
|
-
return context;
|
|
61
|
-
} else {
|
|
62
|
-
if (refChain === null || refChain === void 0 ? void 0 : refChain.includes(context)) {
|
|
63
|
-
throw new Error('Circular dependencies found: ' + refChain.join(' -> ') + ' -> ' + context);
|
|
64
|
-
}
|
|
65
|
-
const newRefChain = Array.isArray(refChain) ? refChain === null || refChain === void 0 ? void 0 : refChain.slice() : [];
|
|
66
|
-
newRefChain.push(context);
|
|
67
|
-
let newContext;
|
|
68
|
-
if (!loadedUrls.has(context)) {
|
|
69
|
-
newContext = await jsonFetch(context);
|
|
70
|
-
loadedUrls.set(context, newContext);
|
|
71
|
-
} else {
|
|
72
|
-
newContext = loadedUrls.get(context);
|
|
73
|
-
}
|
|
74
|
-
return load(newContext['@context'], newRefChain);
|
|
79
|
+
else {
|
|
80
|
+
return load(context);
|
|
75
81
|
}
|
|
76
|
-
};
|
|
77
|
-
if (typeof context === 'object' && context !== null && '@context' in context) {
|
|
78
|
-
return load(context['@context']);
|
|
79
|
-
} else {
|
|
80
|
-
return load(context);
|
|
81
|
-
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
var jsonld = /*#__PURE__*/Object.freeze({
|
|
@@ -86,168 +86,206 @@ var jsonld = /*#__PURE__*/Object.freeze({
|
|
|
86
86
|
loadContext: loadContext
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
const ns = base => local => `${base}${local}`;
|
|
89
|
+
const ns = (base) => (local) => `${base}${local}`;
|
|
90
90
|
const SKOS = ns('http://www.w3.org/2004/02/skos/core#');
|
|
91
91
|
const RDFS = ns('http://www.w3.org/2000/01/rdf-schema#');
|
|
92
92
|
const DCT = ns('http://purl.org/dc/terms/');
|
|
93
93
|
const DC = ns('http://purl.org/dc/elements/1.1/');
|
|
94
94
|
const SDO = ns('https://schema.org/');
|
|
95
95
|
const FOAF = ns('http://xmlns.com/foaf/0.1/');
|
|
96
|
-
const labelPredicates = [
|
|
97
|
-
|
|
96
|
+
const labelPredicates = [
|
|
97
|
+
SKOS('prefLabel'),
|
|
98
|
+
DCT('title'),
|
|
99
|
+
DC('title'),
|
|
100
|
+
SDO('name'),
|
|
101
|
+
FOAF('name'),
|
|
102
|
+
RDFS('label'),
|
|
103
|
+
];
|
|
104
|
+
const descriptionPredicates = [
|
|
105
|
+
SKOS('definition'),
|
|
106
|
+
DCT('description'),
|
|
107
|
+
DC('description'),
|
|
108
|
+
RDFS('comment'),
|
|
109
|
+
];
|
|
98
110
|
|
|
99
111
|
const defaultFetchResourceOptions = {
|
|
100
|
-
|
|
101
|
-
|
|
112
|
+
labelPredicates,
|
|
113
|
+
descriptionPredicates,
|
|
102
114
|
};
|
|
103
115
|
const fetchResourceCache = {};
|
|
104
|
-
const
|
|
105
|
-
const
|
|
116
|
+
const requestCache = {};
|
|
117
|
+
const N3_CONTENT_TYPES = new Set([
|
|
118
|
+
'text/turtle',
|
|
119
|
+
'text/n3',
|
|
120
|
+
'application/n-triples',
|
|
121
|
+
'application/n-quads',
|
|
122
|
+
'application/trig',
|
|
123
|
+
'text/anot+turtle',
|
|
124
|
+
]);
|
|
125
|
+
const ACCEPT_HEADER = [
|
|
126
|
+
'text/turtle',
|
|
127
|
+
'application/n-triples',
|
|
128
|
+
'application/n-quads',
|
|
129
|
+
'application/trig',
|
|
130
|
+
'application/ld+json',
|
|
131
|
+
'application/rdf+xml',
|
|
132
|
+
].join(', ');
|
|
106
133
|
function findInStore(store, subjectUri, predicates) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
var _a;
|
|
135
|
+
const subj = N3.DataFactory.namedNode(subjectUri);
|
|
136
|
+
for (const predUri of predicates) {
|
|
137
|
+
const quads = store
|
|
138
|
+
.getQuads(subj, N3.DataFactory.namedNode(predUri), null, null)
|
|
139
|
+
.filter(q => q.object.termType === 'Literal');
|
|
140
|
+
if (!quads.length) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const en = quads.find(q => q.object.language === 'en');
|
|
144
|
+
const noLang = quads.find(q => !q.object.language);
|
|
145
|
+
return ((_a = en !== null && en !== void 0 ? en : noLang) !== null && _a !== void 0 ? _a : quads[0]).object.value;
|
|
146
|
+
}
|
|
147
|
+
return null;
|
|
117
148
|
}
|
|
118
149
|
function parseTurtle(text, baseIRI, contentType) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
150
|
+
const store = new N3.Store();
|
|
151
|
+
const format = contentType === 'text/anot+turtle' ? 'text/turtle' : contentType;
|
|
152
|
+
const parser = new N3.Parser({ baseIRI, format });
|
|
153
|
+
return new Promise((resolve, reject) => {
|
|
154
|
+
parser.parse(text, (err, quad) => {
|
|
155
|
+
if (err) {
|
|
156
|
+
return reject(err);
|
|
157
|
+
}
|
|
158
|
+
if (quad) {
|
|
159
|
+
store.addQuad(quad);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
resolve(store);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
129
165
|
});
|
|
130
|
-
});
|
|
131
166
|
}
|
|
132
167
|
async function parseJsonLd(text, baseIRI) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
168
|
+
const jsonldMod = await import('jsonld');
|
|
169
|
+
if (!jsonldMod) {
|
|
170
|
+
throw new Error('jsonld peer dependency is not available');
|
|
171
|
+
}
|
|
172
|
+
const doc = JSON.parse(text);
|
|
173
|
+
const nquads = await jsonldMod.toRDF(doc, { format: 'application/n-quads', base: baseIRI });
|
|
174
|
+
return parseTurtle(nquads, baseIRI, 'application/n-quads');
|
|
139
175
|
}
|
|
140
176
|
async function parseRdfXml(text, baseIRI) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
177
|
+
const store = new N3.Store();
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const parser = new RdfXmlParser({ baseIRI });
|
|
180
|
+
parser.on('data', (quad) => store.addQuad(quad));
|
|
181
|
+
parser.on('error', reject);
|
|
182
|
+
parser.on('end', () => resolve(store));
|
|
183
|
+
parser.write(text);
|
|
184
|
+
parser.end();
|
|
145
185
|
});
|
|
146
|
-
parser.on('data', quad => store.addQuad(quad));
|
|
147
|
-
parser.on('error', reject);
|
|
148
|
-
parser.on('end', () => resolve(store));
|
|
149
|
-
parser.write(text);
|
|
150
|
-
parser.end();
|
|
151
|
-
});
|
|
152
186
|
}
|
|
153
|
-
const toArray = val => !val ? [] : Array.isArray(val) ? val : [val];
|
|
154
|
-
const getSparqlQuery = uri => `DESCRIBE <${uri}>`;
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
187
|
+
const toArray = (val) => !val ? [] : Array.isArray(val) ? val : [val];
|
|
188
|
+
const getSparqlQuery = (uri) => `DESCRIBE <${uri}>`;
|
|
189
|
+
const fetchAndParse = async (fetchFn, baseIRI) => {
|
|
190
|
+
var _a;
|
|
191
|
+
let response;
|
|
192
|
+
try {
|
|
193
|
+
response = await fetchFn();
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (_b) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
const contentType = ((_a = response.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.split(';')[0].trim()) || 'text/turtle';
|
|
202
|
+
const text = await response.text();
|
|
203
|
+
try {
|
|
204
|
+
if (N3_CONTENT_TYPES.has(contentType)) {
|
|
205
|
+
return parseTurtle(text, baseIRI, contentType);
|
|
206
|
+
}
|
|
207
|
+
if (contentType === 'application/ld+json') {
|
|
208
|
+
return parseJsonLd(text, baseIRI);
|
|
209
|
+
}
|
|
210
|
+
if (contentType === 'application/rdf+xml') {
|
|
211
|
+
return parseRdfXml(text, baseIRI);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (_c) {
|
|
176
215
|
}
|
|
177
|
-
} catch (_c) {
|
|
178
216
|
return null;
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
217
|
+
};
|
|
218
|
+
const fetchAndParseDocument = (docUrl, fetchFn) => {
|
|
219
|
+
if (!(docUrl in requestCache)) {
|
|
220
|
+
requestCache[docUrl] = fetchAndParse(fetchFn, docUrl);
|
|
221
|
+
}
|
|
222
|
+
return requestCache[docUrl];
|
|
223
|
+
};
|
|
224
|
+
const findResourceInStore = async (storePromise, uri, options) => {
|
|
225
|
+
const store = await storePromise;
|
|
226
|
+
if (!store) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
const label = findInStore(store, uri, options.labelPredicates);
|
|
230
|
+
if (!label) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
return { uri, label, description: findInStore(store, uri, options.descriptionPredicates) };
|
|
187
234
|
};
|
|
188
235
|
const actualFetchResource = async (uri, options) => {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
headers: {
|
|
192
|
-
|
|
236
|
+
const docUrl = uri.includes('#') ? uri.split('#')[0] : uri;
|
|
237
|
+
// 1. Direct (cached by document URL so hash siblings share one request)
|
|
238
|
+
let result = await findResourceInStore(fetchAndParseDocument(docUrl, () => fetch(docUrl, { headers: { 'Accept': ACCEPT_HEADER } })), uri, options);
|
|
239
|
+
// 2. Rainbow proxies (in order) — not supported for hash URIs
|
|
240
|
+
const isHashUri = uri.includes('#');
|
|
241
|
+
for (const instance of [...toArray(options.fallbackRainbowInstances), ...toArray(options.fallbackRainbowInstance)]) {
|
|
242
|
+
if (result || isHashUri) {
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
const rainbowURL = new URL(instance);
|
|
246
|
+
rainbowURL.searchParams.set('uri', uri);
|
|
247
|
+
const rainbowUrlStr = rainbowURL.toString();
|
|
248
|
+
result = await findResourceInStore(fetchAndParseDocument(rainbowUrlStr, () => fetch(rainbowUrlStr, { headers: { 'Accept': ACCEPT_HEADER } })), uri, options);
|
|
193
249
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
query: getSparqlQuery(uri)
|
|
211
|
-
});
|
|
212
|
-
result = await tryFetchAndParse(() => fetch(endpoint, {
|
|
213
|
-
method: 'POST',
|
|
214
|
-
headers: {
|
|
215
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
216
|
-
'Accept': 'text/turtle, application/n-triples'
|
|
217
|
-
},
|
|
218
|
-
body: formBody.toString()
|
|
219
|
-
}), uri, options);
|
|
220
|
-
}
|
|
221
|
-
if (!result) {
|
|
222
|
-
throw new Error(`No label data found for <${uri}>`);
|
|
223
|
-
}
|
|
224
|
-
return result;
|
|
250
|
+
// 3. SPARQL endpoints (in order) — each DESCRIBE is unique per URI, no request cache
|
|
251
|
+
for (const endpoint of [...toArray(options.fallbackSparqlEndpoints), ...toArray(options.fallbackSparqlEndpoint)]) {
|
|
252
|
+
if (result) {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
const formBody = new URLSearchParams({ query: getSparqlQuery(uri) });
|
|
256
|
+
result = await findResourceInStore(fetchAndParse(() => fetch(endpoint, {
|
|
257
|
+
method: 'POST',
|
|
258
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'text/turtle, application/n-triples' },
|
|
259
|
+
body: formBody.toString(),
|
|
260
|
+
}), uri), uri, options);
|
|
261
|
+
}
|
|
262
|
+
if (!result) {
|
|
263
|
+
throw new Error(`No label data found for <${uri}>`);
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
225
266
|
};
|
|
226
267
|
async function fetchResource(uri, options = {}) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
fetchResourceCache[uri] = actualFetchResource(uri, mergedOptions);
|
|
233
|
-
}
|
|
234
|
-
return fetchResourceCache[uri];
|
|
268
|
+
const mergedOptions = { ...defaultFetchResourceOptions, ...options };
|
|
269
|
+
if (!(uri in fetchResourceCache)) {
|
|
270
|
+
fetchResourceCache[uri] = actualFetchResource(uri, mergedOptions);
|
|
271
|
+
}
|
|
272
|
+
return fetchResourceCache[uri];
|
|
235
273
|
}
|
|
236
274
|
async function loadFeature(url) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
275
|
+
const response = await fetch(url, {
|
|
276
|
+
headers: {
|
|
277
|
+
'Accept': 'application/ld+json, application/json;q=0.9, */*;q=0.1',
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
if (!response.ok) {
|
|
281
|
+
throw new Error(`Could not load feature ${url}: ${response.status} - ${response.statusText}`);
|
|
240
282
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
feature,
|
|
249
|
-
context
|
|
250
|
-
};
|
|
283
|
+
const feature = await response.json();
|
|
284
|
+
const context = await loadContext(feature);
|
|
285
|
+
return {
|
|
286
|
+
feature,
|
|
287
|
+
context,
|
|
288
|
+
};
|
|
251
289
|
}
|
|
252
290
|
|
|
253
291
|
var resource = /*#__PURE__*/Object.freeze({
|
|
@@ -258,238 +296,236 @@ var resource = /*#__PURE__*/Object.freeze({
|
|
|
258
296
|
});
|
|
259
297
|
|
|
260
298
|
const defaultAugmentOptions = {
|
|
261
|
-
|
|
262
|
-
|
|
299
|
+
replaceElements: true,
|
|
300
|
+
...defaultFetchResourceOptions,
|
|
263
301
|
};
|
|
264
302
|
function createPropertiesTable(feature, container, options = {
|
|
265
|
-
|
|
303
|
+
propertiesField: 'properties',
|
|
266
304
|
}) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
} else if (value === null || typeof value === 'undefined' || typeof value !== 'object') {
|
|
275
|
-
const span = document.createElement('span');
|
|
276
|
-
span.classList.add('literal-value');
|
|
277
|
-
span.textContent = '' + value;
|
|
278
|
-
parent.appendChild(span);
|
|
279
|
-
return span;
|
|
280
|
-
} else {
|
|
281
|
-
const table = document.createElement('table');
|
|
282
|
-
table.classList.add('object-table');
|
|
283
|
-
if (addHeaders) {
|
|
284
|
-
table.innerHTML = '<thead><tr><th>Property</th><th>Value</th></tr></thead>';
|
|
285
|
-
}
|
|
286
|
-
const tbody = document.createElement('tbody');
|
|
287
|
-
Object.entries(value).forEach(([k, v]) => {
|
|
288
|
-
const row = document.createElement('tr');
|
|
289
|
-
const keyCell = document.createElement('td');
|
|
290
|
-
keyCell.classList.add('object-property');
|
|
291
|
-
keyCell.setAttribute('data-property', k);
|
|
292
|
-
keyCell.textContent = k;
|
|
293
|
-
row.appendChild(keyCell);
|
|
294
|
-
const valueCell = document.createElement('td');
|
|
295
|
-
valueCell.classList.add('object-value');
|
|
296
|
-
createLevel(valueCell, v);
|
|
297
|
-
row.appendChild(valueCell);
|
|
298
|
-
tbody.appendChild(row);
|
|
299
|
-
});
|
|
300
|
-
table.appendChild(tbody);
|
|
301
|
-
parent.appendChild(table);
|
|
302
|
-
return table;
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
if (options.propertiesField) {
|
|
306
|
-
createLevel(container, feature[options.propertiesField], true);
|
|
307
|
-
} else {
|
|
308
|
-
createLevel(container, feature, true);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
async function augment(rootElem, context, options = {}) {
|
|
312
|
-
const mergedOptions = {
|
|
313
|
-
...defaultAugmentOptions,
|
|
314
|
-
...options
|
|
315
|
-
};
|
|
316
|
-
const resolveTerm = (term, contextStack, useVocab = true, useBase = false) => {
|
|
317
|
-
if (term.indexOf('://') !== -1) {
|
|
318
|
-
return {
|
|
319
|
-
'@id': term
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
let closestVocab = null;
|
|
323
|
-
let closestBase = null;
|
|
324
|
-
for (let i = contextStack.length - 1; i >= 0; i--) {
|
|
325
|
-
if (term in contextStack[i]) {
|
|
326
|
-
let resolvedTerm = contextStack[i][term];
|
|
327
|
-
let resolvedId;
|
|
328
|
-
if (resolvedTerm === null || typeof resolvedTerm === 'undefined' || typeof resolvedTerm === 'boolean' || Array.isArray(resolvedTerm)) {
|
|
329
|
-
continue;
|
|
305
|
+
const createLevel = (parent, value, addHeaders = false) => {
|
|
306
|
+
if (Array.isArray(value)) {
|
|
307
|
+
for (const entry of value) {
|
|
308
|
+
const newElem = createLevel(parent, entry);
|
|
309
|
+
newElem.classList.add('array-entry');
|
|
310
|
+
}
|
|
311
|
+
return parent;
|
|
330
312
|
}
|
|
331
|
-
if (typeof
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
resolvedId = resolvedTerm;
|
|
338
|
-
resolvedTerm = {
|
|
339
|
-
'@id': resolvedTerm
|
|
340
|
-
};
|
|
341
|
-
} else if (typeof resolvedTerm === 'object' && '@id' in resolvedTerm && typeof resolvedTerm['@id'] === 'string') {
|
|
342
|
-
resolvedId = resolvedTerm['@id'];
|
|
343
|
-
} else {
|
|
344
|
-
continue;
|
|
313
|
+
else if (value === null || typeof value === 'undefined' || typeof value !== 'object') {
|
|
314
|
+
const span = document.createElement('span');
|
|
315
|
+
span.classList.add('literal-value');
|
|
316
|
+
span.textContent = '' + value;
|
|
317
|
+
parent.appendChild(span);
|
|
318
|
+
return span;
|
|
345
319
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
320
|
+
else {
|
|
321
|
+
const table = document.createElement('table');
|
|
322
|
+
table.classList.add('object-table');
|
|
323
|
+
if (addHeaders) {
|
|
324
|
+
table.innerHTML = '<thead><tr><th>Property</th><th>Value</th></tr></thead>';
|
|
325
|
+
}
|
|
326
|
+
const tbody = document.createElement('tbody');
|
|
327
|
+
Object.entries(value).forEach(([k, v]) => {
|
|
328
|
+
const row = document.createElement('tr');
|
|
329
|
+
const keyCell = document.createElement('td');
|
|
330
|
+
keyCell.classList.add('object-property');
|
|
331
|
+
keyCell.setAttribute('data-property', k);
|
|
332
|
+
keyCell.textContent = k;
|
|
333
|
+
row.appendChild(keyCell);
|
|
334
|
+
const valueCell = document.createElement('td');
|
|
335
|
+
valueCell.classList.add('object-value');
|
|
336
|
+
createLevel(valueCell, v);
|
|
337
|
+
row.appendChild(valueCell);
|
|
338
|
+
tbody.appendChild(row);
|
|
339
|
+
});
|
|
340
|
+
table.appendChild(tbody);
|
|
341
|
+
parent.appendChild(table);
|
|
342
|
+
return table;
|
|
360
343
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
}
|
|
344
|
+
};
|
|
345
|
+
const wrapper = document.createElement('div');
|
|
346
|
+
wrapper.classList.add('object-properties');
|
|
347
|
+
container.appendChild(wrapper);
|
|
348
|
+
if (options.propertiesField) {
|
|
349
|
+
createLevel(wrapper, feature[options.propertiesField], true);
|
|
368
350
|
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return {
|
|
372
|
-
'@id': `${closestVocab}${term}`
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
if (useBase && closestBase) {
|
|
376
|
-
return {
|
|
377
|
-
'@id': `${closestBase}${term}`
|
|
378
|
-
};
|
|
379
|
-
}
|
|
351
|
+
else {
|
|
352
|
+
createLevel(wrapper, feature, true);
|
|
380
353
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (node !== elem && nodeElem.classList.contains('object-value')) {
|
|
388
|
-
return NodeFilter.FILTER_REJECT;
|
|
389
|
-
}
|
|
390
|
-
if (nodeElem.classList.contains('object-property')) {
|
|
391
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
354
|
+
}
|
|
355
|
+
async function augment(rootElem, context, options = {}) {
|
|
356
|
+
const mergedOptions = { ...defaultAugmentOptions, ...options };
|
|
357
|
+
const resolveTerm = (term, contextStack, useVocab = true, useBase = false) => {
|
|
358
|
+
if (term.indexOf('://') !== -1) {
|
|
359
|
+
return { '@id': term };
|
|
392
360
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
361
|
+
let closestVocab = null;
|
|
362
|
+
let closestBase = null;
|
|
363
|
+
for (let i = contextStack.length - 1; i >= 0; i--) {
|
|
364
|
+
if (term in contextStack[i]) {
|
|
365
|
+
let resolvedTerm = contextStack[i][term];
|
|
366
|
+
let resolvedId;
|
|
367
|
+
if (resolvedTerm === null || typeof resolvedTerm === 'undefined' || typeof resolvedTerm === 'boolean'
|
|
368
|
+
|| Array.isArray(resolvedTerm)) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
if (typeof resolvedTerm === 'string') {
|
|
372
|
+
if (resolvedTerm === '@type') {
|
|
373
|
+
return { '@id': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' };
|
|
374
|
+
}
|
|
375
|
+
resolvedId = resolvedTerm;
|
|
376
|
+
resolvedTerm = { '@id': resolvedTerm };
|
|
377
|
+
}
|
|
378
|
+
else if (typeof resolvedTerm === 'object' && '@id' in resolvedTerm && typeof resolvedTerm['@id'] === 'string') {
|
|
379
|
+
resolvedId = resolvedTerm['@id'];
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const idx = resolvedId.indexOf(':');
|
|
385
|
+
if (idx > -1) {
|
|
386
|
+
const prefix = resolvedId.substring(0, idx);
|
|
387
|
+
const localPart = resolvedId.substring(idx + 1);
|
|
388
|
+
if (localPart.startsWith('//')) {
|
|
389
|
+
// Full URI -> return
|
|
390
|
+
return resolvedTerm;
|
|
391
|
+
}
|
|
392
|
+
const resolvedPrefix = resolveTerm(prefix, contextStack);
|
|
393
|
+
if (resolvedPrefix !== null && '@id' in resolvedPrefix && typeof resolvedPrefix['@id'] === 'string') {
|
|
394
|
+
// Prefix found and resolved
|
|
395
|
+
resolvedTerm['@id'] = `${resolvedPrefix['@id']}${localPart}`;
|
|
396
|
+
}
|
|
397
|
+
return resolvedTerm;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (closestVocab === null && contextStack[i]['@vocab']) {
|
|
401
|
+
closestVocab = contextStack[i]['@vocab'];
|
|
402
|
+
}
|
|
403
|
+
if (closestBase === null && contextStack[i]['@base']) {
|
|
404
|
+
closestBase = contextStack[i]['@base'];
|
|
405
|
+
}
|
|
410
406
|
}
|
|
411
|
-
if (
|
|
412
|
-
|
|
413
|
-
|
|
407
|
+
if (term.indexOf(':') === -1) {
|
|
408
|
+
if (useVocab && closestVocab) {
|
|
409
|
+
return { '@id': `${closestVocab}${term}` };
|
|
410
|
+
}
|
|
411
|
+
if (useBase && closestBase) {
|
|
412
|
+
return { '@id': `${closestBase}${term}` };
|
|
413
|
+
}
|
|
414
414
|
}
|
|
415
|
-
return
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
415
|
+
return null;
|
|
416
|
+
};
|
|
417
|
+
const findPropertyChildren = (elem) => {
|
|
418
|
+
const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
|
|
419
|
+
acceptNode(node) {
|
|
420
|
+
const nodeElem = node;
|
|
421
|
+
if (node !== elem && nodeElem.classList.contains('object-value')) {
|
|
422
|
+
return NodeFilter.FILTER_REJECT;
|
|
423
|
+
}
|
|
424
|
+
if (nodeElem.classList.contains('object-property')) {
|
|
425
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
426
|
+
}
|
|
427
|
+
return NodeFilter.FILTER_SKIP;
|
|
428
|
+
},
|
|
429
|
+
});
|
|
430
|
+
const result = [];
|
|
431
|
+
let cur;
|
|
432
|
+
while ((cur = walker.nextNode())) {
|
|
433
|
+
result.push(cur);
|
|
430
434
|
}
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
435
|
+
return result;
|
|
436
|
+
};
|
|
437
|
+
const findLiteralChildren = (elem) => {
|
|
438
|
+
const result = [];
|
|
439
|
+
const walker = document.createTreeWalker(elem, NodeFilter.SHOW_ELEMENT, {
|
|
440
|
+
acceptNode(node) {
|
|
441
|
+
const nodeElem = node;
|
|
442
|
+
if (nodeElem.classList.contains('object-property') || nodeElem.classList.contains('object-value')) {
|
|
443
|
+
return NodeFilter.FILTER_REJECT;
|
|
444
|
+
}
|
|
445
|
+
if (nodeElem.classList.contains('literal-value')) {
|
|
446
|
+
result.push(nodeElem);
|
|
447
|
+
return NodeFilter.FILTER_REJECT;
|
|
448
|
+
}
|
|
449
|
+
return NodeFilter.FILTER_SKIP;
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
while (walker.nextNode()) {
|
|
436
453
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
454
|
+
return result;
|
|
455
|
+
};
|
|
456
|
+
const updateElement = (elem, resourceUri, replaceElements = true) => {
|
|
457
|
+
elem.setAttribute('data-uri', resourceUri);
|
|
458
|
+
elem.classList.add('resource-loading');
|
|
459
|
+
fetchResource(resourceUri, mergedOptions)
|
|
460
|
+
.then(resourceData => {
|
|
461
|
+
let elemToUpdate = elem.querySelector('.resource-link') || elem;
|
|
462
|
+
if (resourceData.label) {
|
|
463
|
+
elem.setAttribute('data-label', resourceData.label);
|
|
464
|
+
if (mergedOptions.replaceElements) {
|
|
465
|
+
elemToUpdate.textContent = resourceData.label;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (resourceData.description) {
|
|
469
|
+
elem.setAttribute('data-description', resourceData.description);
|
|
470
|
+
if (mergedOptions.replaceElements) {
|
|
471
|
+
elemToUpdate.title = resourceData.description;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
elem.classList.add('resource-resolved');
|
|
475
|
+
})
|
|
476
|
+
.catch(e => {
|
|
477
|
+
console.error(`Error resolving URI ${resourceUri}: ${e}`, { cause: e });
|
|
478
|
+
elem.classList.add('resource-error');
|
|
479
|
+
})
|
|
480
|
+
.finally(() => {
|
|
481
|
+
elem.classList.remove('resource-loading');
|
|
482
|
+
});
|
|
483
|
+
if (replaceElements) {
|
|
484
|
+
const link = document.createElement("a");
|
|
485
|
+
link.href = resourceUri;
|
|
486
|
+
link.target = '_blank';
|
|
487
|
+
link.classList.add('resource-link');
|
|
488
|
+
while (elem.firstChild) {
|
|
489
|
+
link.appendChild(elem.firstChild);
|
|
490
|
+
}
|
|
491
|
+
elem.appendChild(link);
|
|
475
492
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
493
|
+
};
|
|
494
|
+
const augmentInner = (elem, contextStack) => {
|
|
495
|
+
var _a;
|
|
496
|
+
const propElems = findPropertyChildren(elem);
|
|
497
|
+
for (const propElem of propElems) {
|
|
498
|
+
let propertyName = null;
|
|
499
|
+
propertyName = propElem.getAttribute('data-property');
|
|
500
|
+
if (!propertyName) {
|
|
501
|
+
propertyName = propElem.textContent.trim();
|
|
502
|
+
}
|
|
503
|
+
const resolvedProperty = resolveTerm(propertyName, contextStack);
|
|
504
|
+
let newContextStack = contextStack;
|
|
505
|
+
const valueElem = (_a = propElem.parentElement) === null || _a === void 0 ? void 0 : _a.querySelector('.object-value');
|
|
506
|
+
if (resolvedProperty && '@id' in resolvedProperty && typeof resolvedProperty['@id'] === 'string') {
|
|
507
|
+
const propertyUri = resolvedProperty['@id'];
|
|
508
|
+
updateElement(propElem, propertyUri, mergedOptions.replaceElements);
|
|
509
|
+
if ('@context' in resolvedProperty) {
|
|
510
|
+
newContextStack = [...contextStack, resolvedProperty['@context']];
|
|
511
|
+
}
|
|
512
|
+
if (resolvedProperty['@type'] === '@id' && valueElem) {
|
|
513
|
+
const literalElems = findLiteralChildren(valueElem);
|
|
514
|
+
literalElems.forEach(literalElem => {
|
|
515
|
+
const resolvedLiteral = resolveTerm(literalElem.textContent.trim(), newContextStack, false, true);
|
|
516
|
+
if (resolvedLiteral && '@id' in resolvedLiteral && typeof resolvedLiteral['@id'] === 'string') {
|
|
517
|
+
const resourceUri = resolvedLiteral['@id'];
|
|
518
|
+
updateElement(literalElem, resourceUri, mergedOptions.replaceElements);
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
if (valueElem) {
|
|
524
|
+
augmentInner(valueElem, newContextStack);
|
|
483
525
|
}
|
|
484
|
-
});
|
|
485
526
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
augmentInner(valueElem, newContextStack);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
augmentInner(rootElem, [context]);
|
|
527
|
+
};
|
|
528
|
+
augmentInner(rootElem, [context]);
|
|
493
529
|
}
|
|
494
530
|
|
|
495
531
|
var augment$1 = /*#__PURE__*/Object.freeze({
|
|
@@ -499,9 +535,9 @@ var augment$1 = /*#__PURE__*/Object.freeze({
|
|
|
499
535
|
});
|
|
500
536
|
|
|
501
537
|
var index = {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
538
|
+
...resource,
|
|
539
|
+
...jsonld,
|
|
540
|
+
...augment$1,
|
|
505
541
|
};
|
|
506
542
|
|
|
507
543
|
export { augment, createPropertiesTable, index as default, defaultFetchResourceOptions, fetchResource, loadContext, loadFeature };
|