@abi-software/map-utilities 1.3.2-beta.0 → 1.3.2

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