@abi-software/map-utilities 1.2.2-beta.3 → 1.2.2-beta.5
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/dist/map-utilities.js +7753 -7579
- package/dist/map-utilities.umd.cjs +25 -33
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/ConnectivityGraph/graph.js +1 -1
- package/src/components/DrawToolbar/ConnectionDialog.vue +20 -34
- package/src/components/DrawToolbar/DrawToolbar.vue +12 -13
- package/src/components/Tooltip/AnnotationPopup.vue +22 -116
- package/src/components/Tooltip/ExternalResourceCard.vue +490 -61
- package/src/components/Tooltip/ProvenancePopup.vue +1 -1
- package/src/components/index.js +2 -0
- package/src/components/utilities.js +41 -0
- package/src/components.d.ts +1 -0
|
@@ -1,27 +1,67 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="resource-container">
|
|
3
|
-
<
|
|
4
|
-
<div class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
3
|
+
<div class="attribute-title-container">
|
|
4
|
+
<div class="attribute-title">References</div>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="citation-tabs" v-if="referencesWithDOI">
|
|
7
|
+
<el-button
|
|
8
|
+
link
|
|
9
|
+
v-for="citationOption of citationOptions"
|
|
10
|
+
:key="citationOption.value"
|
|
11
|
+
:type="citationType === citationOption.value ? 'primary' : ''"
|
|
12
|
+
@click="onCitationFormatChange(citationOption.value)"
|
|
13
|
+
>
|
|
14
|
+
{{ citationOption.label }}
|
|
15
|
+
</el-button>
|
|
16
|
+
</div>
|
|
17
|
+
<ul class="citation-list">
|
|
18
|
+
<li
|
|
19
|
+
v-for="reference of pubMedReferences"
|
|
20
|
+
:key="reference.id"
|
|
21
|
+
:class="{'loading': reference.citation && reference.citation[citationType] === ''}"
|
|
22
|
+
>
|
|
23
|
+
<template v-if="reference.citation && reference.citation[citationType]">
|
|
24
|
+
<span v-html="reference.citation[citationType]"></span>
|
|
25
|
+
<CopyToClipboard :content="reference.citation[citationType]" />
|
|
26
|
+
</template>
|
|
27
|
+
</li>
|
|
28
|
+
|
|
29
|
+
<li v-for="reference of openLibReferences">
|
|
30
|
+
<div v-html="formatCopyReference(reference)"></div>
|
|
31
|
+
<CopyToClipboard :content="formatCopyReference(reference)" />
|
|
32
|
+
</li>
|
|
33
|
+
|
|
34
|
+
<li v-for="reference of isbnDBReferences">
|
|
35
|
+
<a :href="reference.url" target="_blank">{{ reference.url }}</a>
|
|
36
|
+
<CopyToClipboard :content="reference.url" />
|
|
37
|
+
</li>
|
|
38
|
+
</ul>
|
|
16
39
|
</div>
|
|
17
40
|
</template>
|
|
18
41
|
|
|
19
42
|
<script>
|
|
20
|
-
|
|
21
|
-
import { shallowRef } from "vue";
|
|
22
|
-
import { Notebook as ElIconNotebook } from "@element-plus/icons-vue";
|
|
43
|
+
import CopyToClipboard from '../CopyToClipboard/CopyToClipboard.vue';
|
|
23
44
|
|
|
24
|
-
|
|
45
|
+
const CROSSCITE_API_HOST = 'https://citation.crosscite.org';
|
|
46
|
+
const CITATION_OPTIONS = [
|
|
47
|
+
{
|
|
48
|
+
label: 'APA',
|
|
49
|
+
value: 'apa',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: 'Chicago',
|
|
53
|
+
value: 'chicago-note-bibliography',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: 'IEEE',
|
|
57
|
+
value: 'ieee',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: 'Bibtex',
|
|
61
|
+
value: 'bibtex',
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
const CITATION_DEFAULT = 'apa';
|
|
25
65
|
|
|
26
66
|
export default {
|
|
27
67
|
name: "ExternalResourceCard",
|
|
@@ -33,26 +73,373 @@ export default {
|
|
|
33
73
|
},
|
|
34
74
|
data: function () {
|
|
35
75
|
return {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
76
|
+
pubMedReferences: [],
|
|
77
|
+
openLibReferences: [],
|
|
78
|
+
isbnDBReferences: [],
|
|
79
|
+
citationOptions: CITATION_OPTIONS,
|
|
80
|
+
citationType: CITATION_DEFAULT,
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
watch: {
|
|
84
|
+
resources: function (_resources) {
|
|
85
|
+
this.formatReferences([..._resources]);
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
computed: {
|
|
89
|
+
referencesWithDOI: function () {
|
|
90
|
+
const withDOI = this.pubMedReferences.filter((reference) => reference.type === 'doi' || reference.doi);
|
|
91
|
+
return withDOI.length;
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
mounted: function () {
|
|
95
|
+
this.formatReferences([...this.resources]);
|
|
96
|
+
this.getCitationText(CITATION_DEFAULT);
|
|
40
97
|
},
|
|
41
98
|
methods: {
|
|
42
|
-
|
|
43
|
-
|
|
99
|
+
formatReferences: function (references) {
|
|
100
|
+
const nonPubMedReferences = this.extractNonPubMedReferences(references);
|
|
101
|
+
const pubMedReferences = references.filter((reference) => !nonPubMedReferences.includes(reference));
|
|
102
|
+
|
|
103
|
+
this.pubMedReferences = pubMedReferences.map((reference) =>
|
|
104
|
+
(typeof reference === 'object') ?
|
|
105
|
+
this.extractPublicationIdFromURLString(reference[0]) :
|
|
106
|
+
this.extractPublicationIdFromURLString(reference)
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// pmc to pmid
|
|
110
|
+
this.pubMedReferences.forEach((reference) => {
|
|
111
|
+
if (reference.type === 'pmc') {
|
|
112
|
+
const pmcId = reference.id;
|
|
113
|
+
this.searchPMID(pmcId).then((data) => {
|
|
114
|
+
if (data && data.esearchresult) {
|
|
115
|
+
const idList = data.esearchresult.idlist || [];
|
|
116
|
+
reference.id = idList[0];
|
|
117
|
+
reference.type = 'pmid';
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
this.formatNonPubMedReferences(nonPubMedReferences).then((responses) => {
|
|
124
|
+
this.openLibReferences = responses.filter((response) => response.type === 'openlib');
|
|
125
|
+
this.isbnDBReferences = responses.filter((response) => response.type === 'isbndb');
|
|
126
|
+
|
|
127
|
+
this.formatOpenLibReferences();
|
|
128
|
+
});
|
|
129
|
+
},
|
|
130
|
+
extractNonPubMedReferences: function (references) {
|
|
131
|
+
const extractedReferences = [];
|
|
132
|
+
const pubmedDomains = this.getPubMedDomains();
|
|
133
|
+
|
|
134
|
+
references.forEach((reference) => {
|
|
135
|
+
let count = 0;
|
|
136
|
+
pubmedDomains.forEach((name) => {
|
|
137
|
+
if (reference.includes(name)) {
|
|
138
|
+
count++;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
if (!count) {
|
|
142
|
+
extractedReferences.push(reference);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return extractedReferences;
|
|
147
|
+
},
|
|
148
|
+
formatNonPubMedReferences: async function (references) {
|
|
149
|
+
const transformedReferences = [];
|
|
150
|
+
const filteredReferences = references.filter((referenceURL) => referenceURL.indexOf('isbn') !== -1);
|
|
151
|
+
const isbnIDs = filteredReferences.map((url) => {
|
|
152
|
+
const isbnId = url.split('/').pop();
|
|
153
|
+
return 'ISBN:' + isbnId;
|
|
154
|
+
});
|
|
155
|
+
const isbnIDsKey = isbnIDs.join(',');
|
|
156
|
+
const failedIDs = isbnIDs.slice();
|
|
157
|
+
|
|
158
|
+
const openlibAPI = `https://openlibrary.org/api/books?bibkeys=${isbnIDsKey}&format=json`;
|
|
159
|
+
const data = await this.fetchData(openlibAPI);
|
|
160
|
+
|
|
161
|
+
for (const key in data) {
|
|
162
|
+
const successKeyIndex = failedIDs.indexOf(key);
|
|
163
|
+
failedIDs.splice(successKeyIndex, 1);
|
|
164
|
+
|
|
165
|
+
const url = data[key].info_url;
|
|
166
|
+
const urlSegments = url.split('/');
|
|
167
|
+
const endpointIndex = urlSegments.indexOf('books');
|
|
168
|
+
const bookId = urlSegments[endpointIndex + 1];
|
|
169
|
+
|
|
170
|
+
transformedReferences.push({
|
|
171
|
+
id: key.split(':')[1], // Key => "ISBN:1234"
|
|
172
|
+
type: 'openlib',
|
|
173
|
+
url: url,
|
|
174
|
+
bookId: bookId,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
failedIDs.forEach((failedID) => {
|
|
179
|
+
const id = failedID.split(':')[1];
|
|
180
|
+
// Data does not exist in OpenLibrary
|
|
181
|
+
// Provide ISBNDB link for reference
|
|
182
|
+
const url = `https://isbndb.com/book/${id}`;
|
|
183
|
+
transformedReferences.push({
|
|
184
|
+
id: id,
|
|
185
|
+
url: url,
|
|
186
|
+
type: 'isbndb'
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return transformedReferences;
|
|
191
|
+
},
|
|
192
|
+
extractPublicationIdFromURLString: function (urlStr) {
|
|
193
|
+
if (!urlStr) return
|
|
194
|
+
|
|
195
|
+
const str = decodeURIComponent(urlStr)
|
|
196
|
+
|
|
197
|
+
let term = {id: '', type: '', citation: {}}
|
|
198
|
+
|
|
199
|
+
const names = this.getPubMedDomains()
|
|
200
|
+
|
|
201
|
+
names.forEach((name) => {
|
|
202
|
+
const lastIndex = str.lastIndexOf(name)
|
|
203
|
+
if (lastIndex !== -1) {
|
|
204
|
+
term.id = str.slice(lastIndex + name.length)
|
|
205
|
+
if (name === 'doi.org/') {
|
|
206
|
+
term.type = "doi"
|
|
207
|
+
} else if (name === 'pmc/articles/') {
|
|
208
|
+
term.type = "pmc"
|
|
209
|
+
} else {
|
|
210
|
+
term.type = "pmid"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
//Backward compatability with doi: and PMID:
|
|
216
|
+
if (term.id === '') {
|
|
217
|
+
if (urlStr.includes("doi:")) {
|
|
218
|
+
term.id = this.stripPMIDPrefix(urlStr)
|
|
219
|
+
term.type = "doi"
|
|
220
|
+
} else if (urlStr.includes("PMID:")) {
|
|
221
|
+
term.id = this.stripPMIDPrefix(urlStr)
|
|
222
|
+
term.type = "pmid"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (term.id.endsWith('/')) {
|
|
227
|
+
term.id = term.id.slice(0, -1)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return term
|
|
44
231
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
232
|
+
getPubMedDomains: function () {
|
|
233
|
+
const names = [
|
|
234
|
+
'doi.org/',
|
|
235
|
+
'nih.gov/pubmed/',
|
|
236
|
+
'pmc/articles/',
|
|
237
|
+
'pubmed.ncbi.nlm.nih.gov/',
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
return names;
|
|
241
|
+
},
|
|
242
|
+
stripPMIDPrefix: function (pubmedId) {
|
|
243
|
+
return pubmedId.split(':')[1]
|
|
244
|
+
},
|
|
245
|
+
onCitationFormatChange: function(citationType) {
|
|
246
|
+
this.citationType = citationType;
|
|
247
|
+
this.getCitationText(citationType);
|
|
248
|
+
},
|
|
249
|
+
getCitationText: function(citationType) {
|
|
250
|
+
this.pubMedReferences.forEach((reference) => {
|
|
251
|
+
const { id, type, doi } = reference;
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
!(reference.citation && reference.citation[citationType])
|
|
255
|
+
&& id
|
|
256
|
+
) {
|
|
257
|
+
reference.citation[citationType] = ''; // loading
|
|
258
|
+
|
|
259
|
+
if (type === 'doi' || doi) {
|
|
260
|
+
const doiID = type === 'doi' ? id : doi;
|
|
261
|
+
this.getCitationTextByDOI(doiID).then((text) => {
|
|
262
|
+
const formattedText = this.replaceLinkInText(text);
|
|
263
|
+
reference.citation[citationType] = formattedText;
|
|
264
|
+
this.updateCopyContents();
|
|
265
|
+
});
|
|
266
|
+
} else if (type === 'pmid') {
|
|
267
|
+
this.getDOIFromPubMedID(id).then((data) => {
|
|
268
|
+
if (data?.result) {
|
|
269
|
+
const resultObj = data.result[id];
|
|
270
|
+
const articleIDs = resultObj?.articleids || [];
|
|
271
|
+
const doiObj = articleIDs.find((item) => item.idtype === 'doi');
|
|
272
|
+
const doiID = doiObj?.value;
|
|
273
|
+
|
|
274
|
+
if (doiID) {
|
|
275
|
+
reference['doi'] = doiID;
|
|
276
|
+
this.getCitationTextByDOI(doiID).then((text) => {
|
|
277
|
+
const formattedText = this.replaceLinkInText(text);
|
|
278
|
+
reference.citation[citationType] = formattedText;
|
|
279
|
+
this.updateCopyContents();
|
|
280
|
+
});
|
|
281
|
+
} else {
|
|
282
|
+
// If there has no doi in PubMed
|
|
283
|
+
const { title, pubdate, authors } = resultObj;
|
|
284
|
+
const authorNames = authors ? authors.map((author) => author.name) : [];
|
|
285
|
+
const formattedText = this.formatCopyReference({
|
|
286
|
+
title: title || '',
|
|
287
|
+
date: pubdate || '',
|
|
288
|
+
authors: authorNames,
|
|
289
|
+
url: `https://pubmed.ncbi.nlm.nih.gov/${id}`,
|
|
290
|
+
});
|
|
291
|
+
reference.citation[citationType] = formattedText;
|
|
292
|
+
this.updateCopyContents();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
},
|
|
300
|
+
updateCopyContents: function () {
|
|
301
|
+
const citationTypeObj = this.citationOptions.find((item) => item.value === this.citationType);
|
|
302
|
+
let citationFormatStyle = '';
|
|
303
|
+
const values = [];
|
|
304
|
+
|
|
305
|
+
if (this.referencesWithDOI) {
|
|
306
|
+
citationFormatStyle = citationTypeObj?.label;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
this.pubMedReferences.forEach((reference) => {
|
|
310
|
+
values.push(reference.citation[this.citationType]);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
this.openLibReferences.forEach((reference) => {
|
|
314
|
+
values.push(this.formatCopyReference(reference));
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
this.isbnDBReferences.forEach((reference) => {
|
|
318
|
+
values.push(reference.url);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
this.$emit('references-loaded', {
|
|
322
|
+
style: citationFormatStyle,
|
|
323
|
+
list: values
|
|
324
|
+
});
|
|
325
|
+
},
|
|
326
|
+
replaceLinkInText: function (text) {
|
|
327
|
+
const protocol = 'https://';
|
|
328
|
+
let linkBody = text.split(protocol)[1];
|
|
329
|
+
|
|
330
|
+
if (linkBody) {
|
|
331
|
+
linkBody = linkBody.split(' ')[0];
|
|
332
|
+
linkBody = linkBody.trim();
|
|
333
|
+
|
|
334
|
+
if (linkBody.endsWith('.')) {
|
|
335
|
+
linkBody = linkBody.substring(0, linkBody.length - 1);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const fullLink = protocol + linkBody;
|
|
339
|
+
const htmlLink = `<a href="${fullLink}" target="_blank">${fullLink}</a>`;
|
|
340
|
+
|
|
341
|
+
return text.replace(fullLink, htmlLink);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return text;
|
|
345
|
+
},
|
|
346
|
+
searchPMID: async function (term) {
|
|
347
|
+
const esearchAPI = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=${term}&format=json`;
|
|
348
|
+
return await this.fetchData(esearchAPI);
|
|
349
|
+
},
|
|
350
|
+
getCitationTextByDOI: async function (id) {
|
|
351
|
+
const citationAPI = `${CROSSCITE_API_HOST}/format?doi=${id}&style=${this.citationType}&lang=en-US`;
|
|
352
|
+
return await this.fetchData(citationAPI, 'text');
|
|
353
|
+
},
|
|
354
|
+
getDOIFromPubMedID: async function (pubmedId) {
|
|
355
|
+
const summaryAPI = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id=${pubmedId}&format=json`;
|
|
356
|
+
return await this.fetchData(summaryAPI);
|
|
357
|
+
},
|
|
358
|
+
formatOpenLibReferences: function () {
|
|
359
|
+
this.openLibReferences.forEach((reference) => {
|
|
360
|
+
const { bookId } = reference;
|
|
361
|
+
this.getBookData(bookId).then((data) => {
|
|
362
|
+
const { title, authors, publish_date } = data;
|
|
363
|
+
if (title) {
|
|
364
|
+
reference['title'] = title;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (publish_date) {
|
|
368
|
+
reference['date'] = publish_date;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (authors) {
|
|
372
|
+
reference['authors'] = [];
|
|
373
|
+
|
|
374
|
+
authors.forEach((author) => {
|
|
375
|
+
this.getBookAuthor(author.key).then((data) => {
|
|
376
|
+
const { name } = data;
|
|
377
|
+
if (name) {
|
|
378
|
+
reference['authors'].push(name);
|
|
379
|
+
this.updateCopyContents();
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
this.updateCopyContents();
|
|
385
|
+
});
|
|
386
|
+
});
|
|
387
|
+
},
|
|
388
|
+
getBookData: async function (bookId) {
|
|
389
|
+
const apiURL = `https://openlibrary.org/books/${bookId}.json`;
|
|
390
|
+
return await this.fetchData(apiURL);
|
|
391
|
+
},
|
|
392
|
+
getBookAuthor: async function (key) {
|
|
393
|
+
const apiURL = `https://openlibrary.org${key}.json`;
|
|
394
|
+
return await this.fetchData(apiURL);
|
|
395
|
+
},
|
|
396
|
+
formatCopyReference: function (reference) {
|
|
397
|
+
const copyContents = [];
|
|
398
|
+
const { title, date, authors, url } = reference;
|
|
399
|
+
|
|
400
|
+
if (title) {
|
|
401
|
+
copyContents.push(title);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (date) {
|
|
405
|
+
copyContents.push(`(${date})`);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (authors) {
|
|
409
|
+
copyContents.push(`- ${authors.join(', ')}`);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
copyContents.push(`<div><a href="${url}" target="_blank">${url}</a></div>`);
|
|
413
|
+
|
|
414
|
+
return copyContents.join(' ');
|
|
415
|
+
},
|
|
416
|
+
fetchData: async function (apiURL, format) {
|
|
417
|
+
try {
|
|
418
|
+
const response = await fetch(apiURL);
|
|
419
|
+
if (!response.ok) {
|
|
420
|
+
throw new Error(`Response status: ${response.status}`);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (format === 'text') {
|
|
424
|
+
return await response.text();
|
|
425
|
+
} else {
|
|
426
|
+
return await response.json();
|
|
427
|
+
}
|
|
428
|
+
} catch (error) {
|
|
429
|
+
console.error(`Fetch data error: ${error}`);
|
|
430
|
+
}
|
|
48
431
|
},
|
|
49
432
|
},
|
|
50
|
-
}
|
|
433
|
+
}
|
|
51
434
|
</script>
|
|
52
435
|
|
|
53
436
|
<style lang="scss" scoped>
|
|
54
437
|
.resource-container {
|
|
55
|
-
margin-top:
|
|
438
|
+
margin-top: 1em;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.attribute-title-container {
|
|
442
|
+
margin-bottom: 0.5rem;
|
|
56
443
|
}
|
|
57
444
|
|
|
58
445
|
.attribute-title {
|
|
@@ -62,47 +449,89 @@ export default {
|
|
|
62
449
|
text-transform: uppercase;
|
|
63
450
|
}
|
|
64
451
|
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
452
|
+
.citation-list {
|
|
453
|
+
margin: 0;
|
|
454
|
+
margin-top: 0.5rem;
|
|
455
|
+
padding: 0;
|
|
456
|
+
list-style: none;
|
|
457
|
+
line-height: 1.3;
|
|
458
|
+
|
|
459
|
+
li {
|
|
460
|
+
margin: 0;
|
|
461
|
+
padding: 0.5rem 1.5rem 0.5rem 0.75rem;
|
|
462
|
+
border-radius: var(--el-border-radius-base);
|
|
463
|
+
background-color: var(--el-bg-color-page);
|
|
464
|
+
position: relative;
|
|
465
|
+
|
|
466
|
+
:deep(a) {
|
|
467
|
+
word-wrap: break-word;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
+ li {
|
|
471
|
+
margin-top: 0.5rem;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
&.loading {
|
|
475
|
+
padding: 1rem;
|
|
69
476
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
477
|
+
&::before {
|
|
478
|
+
content: "";
|
|
479
|
+
display: block;
|
|
480
|
+
width: 100%;
|
|
481
|
+
height: 100%;
|
|
482
|
+
position: absolute;
|
|
483
|
+
top: 0;
|
|
484
|
+
left: 0;
|
|
485
|
+
animation-duration: 3s;
|
|
486
|
+
animation-fill-mode: forwards;
|
|
487
|
+
animation-iteration-count: infinite;
|
|
488
|
+
animation-name: loadingAnimation;
|
|
489
|
+
animation-timing-function: linear;
|
|
490
|
+
background: linear-gradient(to right,
|
|
491
|
+
var(--el-bg-color-page) 5%,
|
|
492
|
+
var(--el-color-info-light-8) 15%,
|
|
493
|
+
var(--el-bg-color-page) 30%
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
:deep(.copy-clipboard-button) {
|
|
499
|
+
position: absolute;
|
|
500
|
+
bottom: 0.25rem;
|
|
501
|
+
right: 0.25rem;
|
|
502
|
+
opacity: 0;
|
|
503
|
+
visibility: hidden;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
&:hover {
|
|
507
|
+
:deep(.copy-clipboard-button) {
|
|
508
|
+
opacity: 1;
|
|
509
|
+
visibility: visible;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
77
512
|
}
|
|
78
513
|
}
|
|
79
514
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
515
|
+
.citation-tabs {
|
|
516
|
+
.el-button {
|
|
517
|
+
&:hover,
|
|
518
|
+
&:focus,
|
|
519
|
+
&:active {
|
|
520
|
+
color: $app-primary-color;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
83
523
|
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/* font-weight: bold; */
|
|
88
|
-
text-transform: uppercase;
|
|
524
|
+
.el-button + .el-button {
|
|
525
|
+
margin-left: 0.25rem;
|
|
526
|
+
}
|
|
89
527
|
}
|
|
90
528
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
font-size: 14px !important;
|
|
95
|
-
background-color: $app-primary-color;
|
|
96
|
-
color: #fff;
|
|
97
|
-
&:hover {
|
|
98
|
-
color: #fff !important;
|
|
99
|
-
background: #ac76c5 !important;
|
|
100
|
-
border: 1px solid #ac76c5 !important;
|
|
529
|
+
@keyframes loadingAnimation {
|
|
530
|
+
0% {
|
|
531
|
+
background-position: -30vw 0;
|
|
101
532
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
background-color: $app-primary-color;
|
|
105
|
-
color: #fff;
|
|
533
|
+
100% {
|
|
534
|
+
background-position: 70vw 0;
|
|
106
535
|
}
|
|
107
536
|
}
|
|
108
537
|
</style>
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
Search for data on components
|
|
165
165
|
</el-button>
|
|
166
166
|
|
|
167
|
-
<external-resource-card :resources="resources"></external-resource-card>
|
|
167
|
+
<external-resource-card :resources="resources" v-if="resources.length"></external-resource-card>
|
|
168
168
|
</div>
|
|
169
169
|
</transition>
|
|
170
170
|
</div>
|
package/src/components/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import DrawToolbar from "./DrawToolbar/DrawToolbar.vue";
|
|
|
6
6
|
import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
|
|
7
7
|
import Tooltip from "./Tooltip/Tooltip.vue";
|
|
8
8
|
import TreeControls from "./TreeControls/TreeControls.vue";
|
|
9
|
+
import ExternalResourceCard from "./Tooltip/ExternalResourceCard.vue";
|
|
9
10
|
|
|
10
11
|
export {
|
|
11
12
|
AnnotationPopup,
|
|
@@ -16,4 +17,5 @@ export {
|
|
|
16
17
|
HelpModeDialog,
|
|
17
18
|
Tooltip,
|
|
18
19
|
TreeControls,
|
|
20
|
+
ExternalResourceCard,
|
|
19
21
|
};
|
|
@@ -4,6 +4,47 @@ const capitalise = term => {
|
|
|
4
4
|
return term;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
const convertNodeToObject = (node) => {
|
|
8
|
+
const obj = {};
|
|
9
|
+
|
|
10
|
+
if (node.attributes) {
|
|
11
|
+
for (let i = 0; i < node.attributes.length; i++) {
|
|
12
|
+
const attr = node.attributes[i];
|
|
13
|
+
obj[`@${attr.nodeName}`] = attr.nodeValue;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
18
|
+
const child = node.childNodes[i];
|
|
19
|
+
if (child.nodeType === Node.ELEMENT_NODE) {
|
|
20
|
+
const childResult = convertNodeToObject(child);
|
|
21
|
+
if (obj[child.nodeName]) {
|
|
22
|
+
if (!Array.isArray(obj[child.nodeName])) {
|
|
23
|
+
obj[child.nodeName] = [obj[child.nodeName]];
|
|
24
|
+
}
|
|
25
|
+
obj[child.nodeName].push(childResult);
|
|
26
|
+
} else {
|
|
27
|
+
obj[child.nodeName] = childResult;
|
|
28
|
+
}
|
|
29
|
+
} else if (child.nodeType === Node.TEXT_NODE && child.nodeValue.trim() !== '') {
|
|
30
|
+
return child.nodeValue.trim();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return obj;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const xmlToJSON = (xmlText) => {
|
|
38
|
+
const parser = new DOMParser();
|
|
39
|
+
const xmlDoc = parser.parseFromString(xmlText, "text/xml");
|
|
40
|
+
|
|
41
|
+
const result = {};
|
|
42
|
+
result[xmlDoc.documentElement.nodeName] = convertNodeToObject(xmlDoc.documentElement);
|
|
43
|
+
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
|
|
7
47
|
export {
|
|
8
48
|
capitalise,
|
|
49
|
+
xmlToJSON,
|
|
9
50
|
};
|
package/src/components.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare module 'vue' {
|
|
|
14
14
|
CreateTooltipContent: typeof import('./components/Tooltip/CreateTooltipContent.vue')['default']
|
|
15
15
|
DrawToolbar: typeof import('./components/DrawToolbar/DrawToolbar.vue')['default']
|
|
16
16
|
ElButton: typeof import('element-plus/es')['ElButton']
|
|
17
|
+
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
|
|
17
18
|
ElCard: typeof import('element-plus/es')['ElCard']
|
|
18
19
|
ElCol: typeof import('element-plus/es')['ElCol']
|
|
19
20
|
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|