@abi-software/map-utilities 1.4.2-beta.0 → 1.4.3-beta.0

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.
@@ -6,7 +6,7 @@
6
6
  <CopyToClipboard label="Copy list to clipboard" :content="referecesListContent" />
7
7
  </div>
8
8
  </div>
9
- <div class="citation-tabs" v-if="referencesWithDOI">
9
+ <div class="citation-tabs" v-if="useDOIFormatter ? referencesWithDOI : pubMedReferences.length">
10
10
  <el-button
11
11
  link
12
12
  v-for="citationOption of citationOptions"
@@ -102,7 +102,7 @@
102
102
 
103
103
  <script>
104
104
  import CopyToClipboard from '../CopyToClipboard/CopyToClipboard.vue';
105
- import { delay } from '../utilities';
105
+ import { delay, getCitationById } from '../utilities';
106
106
 
107
107
  const CROSSCITE_API_HOST = 'https://citation.doi.org';
108
108
  const CITATION_OPTIONS = [
@@ -128,11 +128,18 @@ const LOADING_DELAY = 600;
128
128
 
129
129
  export default {
130
130
  name: "ExternalResourceCard",
131
+ components: {
132
+ CopyToClipboard,
133
+ },
131
134
  props: {
132
135
  resources: {
133
136
  type: Array,
134
137
  default: () => [],
135
138
  },
139
+ useDOIFormatter: {
140
+ type: Boolean,
141
+ default: true,
142
+ }
136
143
  },
137
144
  data: function () {
138
145
  return {
@@ -338,7 +345,14 @@ export default {
338
345
 
339
346
  if (type === 'doi' || doi) {
340
347
  const doiID = type === 'doi' ? id : doi;
341
- this.getCitationTextByDOI(doiID).then((text) => {
348
+ const fetchCitationFromAPI = this.useDOIFormatter ?
349
+ this.getCitationTextByDOI(doiID) :
350
+ getCitationById(doiID, {
351
+ type: 'doi',
352
+ format: citationType
353
+ });
354
+
355
+ fetchCitationFromAPI.then((text) => {
342
356
  const formattedText = this.replaceLinkInText(text);
343
357
  reference.citation[citationType] = formattedText;
344
358
  this.updateCopyContents();
@@ -349,45 +363,61 @@ export default {
349
363
  };
350
364
  });
351
365
  } else if (type === 'pmid') {
352
- this.getDOIFromPubMedID(id).then((data) => {
353
- if (data?.result) {
354
- const resultObj = data.result[id];
355
- const articleIDs = resultObj?.articleids || [];
356
- const doiObj = articleIDs.find((item) => item.idtype === 'doi');
357
- const doiID = doiObj?.value;
358
-
359
- if (doiID) {
360
- reference['doi'] = doiID;
361
- this.getCitationTextByDOI(doiID).then((text) => {
362
- const formattedText = this.replaceLinkInText(text);
366
+ if (this.useDOIFormatter) {
367
+ this.getDOIFromPubMedID(id).then((data) => {
368
+ if (data?.result) {
369
+ const resultObj = data.result[id];
370
+ const articleIDs = resultObj?.articleids || [];
371
+ const doiObj = articleIDs.find((item) => item.idtype === 'doi');
372
+ const doiID = doiObj?.value;
373
+
374
+ if (doiID) {
375
+ reference['doi'] = doiID;
376
+ this.getCitationTextByDOI(doiID).then((text) => {
377
+ const formattedText = this.replaceLinkInText(text);
378
+ reference.citation[citationType] = formattedText;
379
+ this.updateCopyContents();
380
+ }).catch((error) => {
381
+ reference.citation['error'] = {
382
+ type: citationType,
383
+ ref: 'doi',
384
+ };
385
+ });
386
+ } else {
387
+ // If there has no doi in PubMed
388
+ const { title, pubdate, authors } = resultObj;
389
+ const authorNames = authors ? authors.map((author) => author.name) : [];
390
+ const formattedText = this.formatCopyReference({
391
+ title: title || '',
392
+ date: pubdate || '',
393
+ authors: authorNames,
394
+ url: `https://pubmed.ncbi.nlm.nih.gov/${id}`,
395
+ });
363
396
  reference.citation[citationType] = formattedText;
364
397
  this.updateCopyContents();
365
- }).catch((error) => {
366
- reference.citation['error'] = {
367
- type: citationType,
368
- ref: 'doi',
369
- };
370
- });
371
- } else {
372
- // If there has no doi in PubMed
373
- const { title, pubdate, authors } = resultObj;
374
- const authorNames = authors ? authors.map((author) => author.name) : [];
375
- const formattedText = this.formatCopyReference({
376
- title: title || '',
377
- date: pubdate || '',
378
- authors: authorNames,
379
- url: `https://pubmed.ncbi.nlm.nih.gov/${id}`,
380
- });
381
- reference.citation[citationType] = formattedText;
382
- this.updateCopyContents();
398
+ }
383
399
  }
384
- }
385
- }).catch((error) => {
386
- reference.citation['error'] = {
387
- type: citationType,
388
- ref: 'pubmed',
389
- };
390
- });
400
+ }).catch((error) => {
401
+ reference.citation['error'] = {
402
+ type: citationType,
403
+ ref: 'pubmed',
404
+ };
405
+ });
406
+ } else {
407
+ getCitationById(id, {
408
+ type: 'pmid',
409
+ format: citationType
410
+ }).then((text) => {
411
+ const formattedText = this.replaceLinkInText(text);
412
+ reference.citation[citationType] = formattedText;
413
+ this.updateCopyContents();
414
+ }).catch((error) => {
415
+ reference.citation['error'] = {
416
+ type: citationType,
417
+ ref: 'pubmed',
418
+ };
419
+ });
420
+ }
391
421
  }
392
422
  }
393
423
  },
@@ -51,118 +51,18 @@
51
51
  </div>
52
52
  <transition name="slide-fade">
53
53
  <div v-show="showDetails" class="content-container scrollbar">
54
- {{ tooltipEntry.paths }}
55
- <div v-if="tooltipEntry.origins && tooltipEntry.origins.length > 0" class="block">
56
- <div class="attribute-title-container">
57
- <span class="attribute-title">Origin</span>
58
- <el-popover
59
- width="250"
60
- trigger="hover"
61
- :teleported="false"
62
- popper-class="popover-origin-help"
63
- >
64
- <template #reference>
65
- <el-icon class="info"><el-icon-warning /></el-icon>
66
- </template>
67
- <span style="word-break: keep-all">
68
- <i>Origin</i> {{ originDescription }}
69
- </span>
70
- </el-popover>
71
- </div>
72
- <div
73
- v-for="(origin, i) in tooltipEntry.origins"
74
- class="attribute-content"
75
- :origin-item-label="origin"
76
- :key="origin"
77
- >
78
- {{ capitalise(origin) }}
79
- <div v-if="i != tooltipEntry.origins.length - 1" class="separator"></div>
80
- </div>
81
- <el-button
82
- v-show="
83
- tooltipEntry.originsWithDatasets && tooltipEntry.originsWithDatasets.length > 0
84
- "
85
- class="button"
86
- id="open-dendrites-button"
87
- @click="openDendrites"
88
- >
89
- Explore origin data
90
- </el-button>
91
- </div>
92
- <div
93
- v-if="tooltipEntry.components && tooltipEntry.components.length > 0"
94
- class="block"
95
- >
96
- <div class="attribute-title-container">
97
- <div class="attribute-title">Components</div>
98
- </div>
99
- <div
100
- v-for="(component, i) in tooltipEntry.components"
101
- class="attribute-content"
102
- :component-item-label="component"
103
- :key="component"
104
- >
105
- {{ capitalise(component) }}
106
- <div
107
- v-if="i != tooltipEntry.components.length - 1"
108
- class="separator"
109
- ></div>
110
- </div>
111
- </div>
112
- <div
113
- v-if="tooltipEntry.destinations && tooltipEntry.destinations.length > 0"
114
- class="block"
115
- >
116
- <div class="attribute-title-container">
117
- <span class="attribute-title">Destination</span>
118
- <el-popover
119
- width="250"
120
- trigger="hover"
121
- :teleported="false"
122
- popper-class="popover-origin-help"
123
- >
124
- <template #reference>
125
- <el-icon class="info"><el-icon-warning /></el-icon>
126
- </template>
127
- <span style="word-break: keep-all">
128
- <i>Destination</i> is where the axons terminate
129
- </span>
130
- </el-popover>
131
- </div>
132
- <div
133
- v-for="(destination, i) in tooltipEntry.destinations"
134
- class="attribute-content"
135
- :destination-item-label="destination"
136
- :key="destination"
137
- >
138
- {{ capitalise(destination) }}
139
- <div
140
- v-if="i != tooltipEntry.destinations.length - 1"
141
- class="separator"
142
- ></div>
143
- </div>
144
- <el-button
145
- v-show="
146
- tooltipEntry.destinationsWithDatasets &&
147
- tooltipEntry.destinationsWithDatasets.length > 0
148
- "
149
- class="button"
150
- @click="openAxons"
151
- >
152
- Explore destination data
153
- </el-button>
154
- </div>
155
-
156
- <el-button
157
- v-show="
158
- tooltipEntry.componentsWithDatasets &&
159
- tooltipEntry.componentsWithDatasets.length > 0
160
- "
161
- class="button"
162
- @click="openAll"
163
- >
164
- Search for data on components
165
- </el-button>
54
+ <connectivity-list
55
+ :key="tooltipEntry.featureId[0]"
56
+ :entry="tooltipEntry"
57
+ :origins="origins"
58
+ :components="components"
59
+ :destinations="destinations"
60
+ :originsWithDatasets="originsWithDatasets"
61
+ :componentsWithDatasets="componentsWithDatasets"
62
+ :destinationsWithDatasets="destinationsWithDatasets"
63
+ :availableAnatomyFacets="availableAnatomyFacets"
64
+ @connectivity-action-click="onConnectivityActionClick"
65
+ ></connectivity-list>
166
66
 
167
67
  <external-resource-card :resources="resources" v-if="resources.length"></external-resource-card>
168
68
  </div>
@@ -171,21 +71,25 @@
171
71
  </template>
172
72
 
173
73
  <script>
74
+ import {
75
+ ArrowUp as ElIconArrowUp,
76
+ ArrowDown as ElIconArrowDown,
77
+ Warning as ElIconWarning,
78
+ } from '@element-plus/icons-vue'
174
79
  import EventBus from "../EventBus.js";
175
-
176
- const titleCase = (str) => {
177
- return str.replace(/\w\S*/g, (t) => {
178
- return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase();
179
- });
180
- };
181
-
182
- const capitalise = function (str) {
183
- if (str) return str.charAt(0).toUpperCase() + str.slice(1);
184
- return "";
185
- };
80
+ import ConnectivityList from '../ConnectivityList/ConnectivityList.vue';
81
+ import ExternalResourceCard from './ExternalResourceCard.vue';
82
+ import { capitalise, titleCase } from '../utilities.js';
186
83
 
187
84
  export default {
188
85
  name: "ProvenancePopup",
86
+ components: {
87
+ ElIconArrowUp,
88
+ ElIconArrowDown,
89
+ ElIconWarning,
90
+ ConnectivityList,
91
+ ExternalResourceCard,
92
+ },
189
93
  props: {
190
94
  tooltipEntry: {
191
95
  type: Object,
@@ -203,20 +107,30 @@ export default {
203
107
  inject: ["getFeaturesAlert"],
204
108
  data: function () {
205
109
  return {
206
- controller: undefined,
207
- activeSpecies: undefined,
208
- pubmedSearchUrl: "",
209
110
  loading: false,
210
- showToolip: false,
211
111
  showDetails: false,
212
112
  originDescriptions: {
213
113
  motor: "is the location of the initial cell body of the circuit",
214
114
  sensory: "is the location of the initial cell body in the PNS circuit",
215
115
  },
116
+ origins: [],
117
+ components: [],
118
+ destinations: [],
119
+ originsWithDatasets: [],
216
120
  componentsWithDatasets: [],
217
- uberons: [{ id: undefined, name: undefined }],
121
+ destinationsWithDatasets: [],
122
+ availableAnatomyFacets: [],
218
123
  };
219
124
  },
125
+ watch: {
126
+ tooltipEntry: {
127
+ handler: function (val) {
128
+ this.updateConnectionsData(val);
129
+ },
130
+ immediate: true,
131
+ deep: true,
132
+ }
133
+ },
220
134
  computed: {
221
135
  featuresAlert() {
222
136
  return this.getFeaturesAlert();
@@ -249,6 +163,10 @@ export default {
249
163
  return text;
250
164
  },
251
165
  },
166
+ mounted: function () {
167
+ this.loadAvailableAnatomyFacets();
168
+ this.updateConnectionsData(this.tooltipEntry);
169
+ },
252
170
  methods: {
253
171
  titleCase: function (title) {
254
172
  return titleCase(title);
@@ -256,29 +174,25 @@ export default {
256
174
  capitalise: function (text) {
257
175
  return capitalise(text);
258
176
  },
259
- openUrl: function (url) {
260
- window.open(url, "_blank");
177
+ onConnectivityActionClick: function (data) {
178
+ EventBus.emit('onActionClick', data);
261
179
  },
262
- openAll: function () {
263
- EventBus.emit("onActionClick", {
264
- type: "Facets",
265
- labels: this.tooltipEntry.componentsWithDatasets.map((a) => a.name),
266
- });
267
- },
268
- openAxons: function () {
269
- EventBus.emit("onActionClick", {
270
- type: "Facets",
271
- labels: this.tooltipEntry.destinationsWithDatasets.map((a) => a.name),
272
- });
273
- },
274
- openDendrites: function () {
275
- EventBus.emit("onActionClick", {
276
- type: "Facets",
277
- labels: this.tooltipEntry.originsWithDatasets.map((a) => a.name),
278
- });
180
+ // Load available anatomy facets from the local storage if available.
181
+ // The data is from Algolia in Sidebar.
182
+ loadAvailableAnatomyFacets: function () {
183
+ const availableAnatomyFacets = localStorage.getItem('available-anatomy-facets');
184
+
185
+ if (availableAnatomyFacets) {
186
+ this.availableAnatomyFacets = JSON.parse(availableAnatomyFacets);
187
+ }
279
188
  },
280
- pubmedSearchUrlUpdate: function (val) {
281
- this.pubmedSearchUrl = val;
189
+ updateConnectionsData: function (source) {
190
+ this.origins = source.origins;
191
+ this.components = source.components;
192
+ this.destinations = source.destinations;
193
+ this.originsWithDatasets = source.originsWithDatasets;
194
+ this.componentsWithDatasets = source.componentsWithDatasets;
195
+ this.destinationsWithDatasets = source.destinationsWithDatasets;
282
196
  },
283
197
  },
284
198
  };
@@ -491,6 +405,10 @@ export default {
491
405
  .block {
492
406
  padding-top: 0.5em;
493
407
  }
408
+
409
+ .connectivity-list {
410
+ padding-top: 1rem;
411
+ }
494
412
  }
495
413
 
496
414
  .scrollbar::-webkit-scrollbar-track {
@@ -1,6 +1,7 @@
1
1
  import AnnotationPopup from "./Tooltip/AnnotationPopup.vue";
2
2
  import CreateTooltipContent from "./Tooltip/CreateTooltipContent.vue";
3
3
  import ConnectivityGraph from "./ConnectivityGraph/ConnectivityGraph.vue";
4
+ import ConnectivityList from "./ConnectivityList/ConnectivityList.vue";
4
5
  import CopyToClipboard from "./CopyToClipboard/CopyToClipboard.vue";
5
6
  import DrawToolbar from "./DrawToolbar/DrawToolbar.vue";
6
7
  import HelpModeDialog from "./HelpModeDialog/HelpModeDialog.vue";
@@ -12,6 +13,7 @@ export {
12
13
  AnnotationPopup,
13
14
  CreateTooltipContent,
14
15
  ConnectivityGraph,
16
+ ConnectivityList,
15
17
  CopyToClipboard,
16
18
  DrawToolbar,
17
19
  HelpModeDialog,
@@ -1,9 +1,21 @@
1
+ import { Cite, plugins } from '@citation-js/core';
2
+ import '@citation-js/plugin-doi';
3
+ import '@citation-js/plugin-csl';
4
+ import '@citation-js/plugin-bibtex';
5
+ import '@citation-js/plugin-pubmed';
6
+
1
7
  const capitalise = term => {
2
8
  if (term)
3
9
  return term.charAt(0).toUpperCase() + term.slice(1);
4
10
  return term;
5
11
  };
6
12
 
13
+ const titleCase = (str) => {
14
+ return str.replace(/\w\S*/g, (t) => {
15
+ return t.charAt(0).toUpperCase() + t.substr(1).toLowerCase();
16
+ });
17
+ };
18
+
7
19
  const convertNodeToObject = (node) => {
8
20
  const obj = {};
9
21
 
@@ -48,8 +60,43 @@ const delay = (ms) => {
48
60
  return new Promise(resolve => setTimeout(resolve, ms));
49
61
  };
50
62
 
63
+ /**
64
+ * @param {id} id - DOI or PMID
65
+ * @param {options:type} type - type of the ID, e.g., 'pmid'
66
+ * @param {options:format} format - 'apa' (default), 'chicago', 'ieee', 'bibtex', etc.
67
+ * @returns {citation} formatted citation text
68
+ */
69
+ const getCitationById = async (id, { type, format }) => {
70
+ // because 'chicago' and 'ieee' are not in citation.js default styles
71
+ if ((format !== 'bibtex') && (format !== 'apa')) {
72
+ const xml = `https://raw.githubusercontent.com/citation-style-language/styles/refs/heads/master/${format}.csl`;
73
+ const response = await fetch(xml);
74
+ const template = await response.text();
75
+ let config = plugins.config.get('@csl');
76
+ config.templates.add(format, template);
77
+ }
78
+
79
+ const option = {};
80
+
81
+ if (type === 'pmid') {
82
+ option['forceType'] = '@pubmed/id';
83
+ }
84
+
85
+ const cite = await Cite.async(id, option);
86
+ const citation = (format === 'bibtex') ?
87
+ cite.format(format) :
88
+ cite.format('bibliography', {
89
+ format: 'html',
90
+ template: format || 'apa', // default as 'apa' style
91
+ lang: 'en-US'
92
+ })
93
+ return citation;
94
+ };
95
+
51
96
  export {
52
97
  capitalise,
98
+ titleCase,
53
99
  xmlToJSON,
54
100
  delay,
101
+ getCitationById,
55
102
  };
@@ -10,6 +10,7 @@ declare module 'vue' {
10
10
  AnnotationPopup: typeof import('./components/Tooltip/AnnotationPopup.vue')['default']
11
11
  ConnectionDialog: typeof import('./components/DrawToolbar/ConnectionDialog.vue')['default']
12
12
  ConnectivityGraph: typeof import('./components/ConnectivityGraph/ConnectivityGraph.vue')['default']
13
+ ConnectivityList: typeof import('./components/ConnectivityList/ConnectivityList.vue')['default']
13
14
  CopyToClipboard: typeof import('./components/CopyToClipboard/CopyToClipboard.vue')['default']
14
15
  CreateTooltipContent: typeof import('./components/Tooltip/CreateTooltipContent.vue')['default']
15
16
  DrawToolbar: typeof import('./components/DrawToolbar/DrawToolbar.vue')['default']