@abi-software/map-utilities 1.2.2-beta.5 → 1.2.2-beta.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-utilities",
3
- "version": "1.2.2-beta.5",
3
+ "version": "1.2.2-beta.7",
4
4
  "files": [
5
5
  "dist/*",
6
6
  "src/*",
@@ -21,9 +21,9 @@
21
21
  </template>
22
22
 
23
23
  <script>
24
- const labelBefore = 'Copy to clipboard';
25
- const labelAfter = 'Copied!';
26
- const appPrimaryColor = '#8300bf';
24
+ const LABEL_BEFORE = 'Copy to clipboard';
25
+ const LABEL_AFTER = 'Copied!';
26
+ const APP_PRIMARY_COLOR = '#8300bf';
27
27
 
28
28
  export default {
29
29
  name: 'CopyToClipboard',
@@ -32,6 +32,10 @@ export default {
32
32
  type: String,
33
33
  default: '',
34
34
  },
35
+ label: {
36
+ type: String,
37
+ default: LABEL_BEFORE,
38
+ },
35
39
  /**
36
40
  * `theme: light` will show white button,
37
41
  * to use when the button is over other readable text content.
@@ -44,9 +48,9 @@ export default {
44
48
  },
45
49
  data: function () {
46
50
  return {
47
- textLabel: labelBefore,
51
+ textLabel: this.label,
48
52
  autoHideTimeout: 0,
49
- iconColor: appPrimaryColor,
53
+ iconColor: APP_PRIMARY_COLOR,
50
54
  };
51
55
  },
52
56
  methods: {
@@ -78,14 +82,14 @@ export default {
78
82
  }
79
83
 
80
84
  if (copiedSuccessfully) {
81
- this.textLabel = labelAfter;
85
+ this.textLabel = LABEL_AFTER;
82
86
  } else {
83
87
  this.textLabel = 'Error trying to copy to clipboard!';
84
88
  }
85
89
  },
86
90
  resetSettings: function () {
87
91
  this.autoHideTimeout = 0;
88
- this.textLabel = labelBefore;
92
+ this.textLabel = this.label;
89
93
  },
90
94
  }
91
95
  }
@@ -3,22 +3,16 @@
3
3
  <el-row>
4
4
  <el-col>
5
5
  <el-row v-if="inDrawing">
6
- <span class="dialog-title">Finalise drawing</span>
7
- <el-button-group>
8
- <el-button
9
- type="primary"
10
- plain
11
- @click="$emit('confirmDrawn', true)"
12
- >
13
- Confirm
14
- </el-button>
15
- <el-button type="primary" plain @click="$emit('cancelDrawn', true)">
16
- Cancel
17
- </el-button>
18
- </el-button-group>
6
+ <span class="dialog-title">Finalize drawing</span>
7
+ <el-button type="primary" plain @click="$emit('confirmDrawn', true)">
8
+ Confirm
9
+ </el-button>
10
+ <el-button type="primary" plain @click="$emit('cancelDrawn', true)">
11
+ Cancel
12
+ </el-button>
19
13
  </el-row>
20
14
  <el-row v-else>
21
- <span class="dialog-title">Visualise connection</span>
15
+ <span class="dialog-title">Visualize connection</span>
22
16
  <el-button
23
17
  type="primary"
24
18
  plain
@@ -34,7 +28,18 @@
34
28
  <b><span>Related Features</span></b>
35
29
  <el-row v-for="(value, key) in connectionEntry" :key="key">
36
30
  <el-card :shadow="shadowDisplay(key)" @click="handleTooltip(key)">
37
- <span>{{ capitalise(value.label) }}</span>
31
+ <el-popover
32
+ trigger="hover"
33
+ :disabled="value.label.length < 20"
34
+ :width="200"
35
+ :content="capitalize(value.label)"
36
+ >
37
+ <template #reference>
38
+ <span class="connection-label">
39
+ {{ capitalize(value.label) }}
40
+ </span>
41
+ </template>
42
+ </el-popover>
38
43
  </el-card>
39
44
  </el-row>
40
45
  </el-col>
@@ -43,7 +48,7 @@
43
48
  </template>
44
49
 
45
50
  <script>
46
- const capitalise = function (str) {
51
+ const capitalize = function (str) {
47
52
  if (str) return str.charAt(0).toUpperCase() + str.slice(1);
48
53
  return "";
49
54
  };
@@ -73,8 +78,8 @@ export default {
73
78
  shadowDisplay: function (value) {
74
79
  return this.tooltipId === value ? "always" : "hover";
75
80
  },
76
- capitalise: function (label) {
77
- return capitalise(label);
81
+ capitalize: function (label) {
82
+ return capitalize(label);
78
83
  },
79
84
  handleTooltip: function (value) {
80
85
  this.tooltipId = this.tooltipId === value ? undefined : value;
@@ -100,13 +105,13 @@ export default {
100
105
  }
101
106
 
102
107
  .dialog-title {
103
- font-size: 18px;
108
+ font-size: 16px;
104
109
  font-weight: bold;
105
110
  color: rgb(131, 0, 191);
106
111
  }
107
112
 
108
113
  .el-button {
109
- margin: 5px 0px;
114
+ margin: 5px 5px 5px 0;
110
115
  }
111
116
 
112
117
  :deep(.el-card) {
@@ -115,4 +120,13 @@ export default {
115
120
  border: 0;
116
121
  cursor: pointer;
117
122
  }
123
+
124
+ .connection-label {
125
+ white-space: nowrap;
126
+ display: block;
127
+ width: 200px;
128
+ overflow: hidden;
129
+ text-overflow: ellipsis;
130
+ font-size: 14px;
131
+ }
118
132
  </style>
@@ -308,12 +308,12 @@ export default {
308
308
  data: function () {
309
309
  return {
310
310
  toolbarIcons: [
311
- { name: "Edit", active: false, disabled: false },
312
- { name: "Delete", active: false, disabled: false },
313
- { name: "Point", active: false, disabled: false },
314
- { name: "LineString", active: false, disabled: false },
315
- { name: "Polygon", active: false, disabled: false },
316
- { name: "Connection", active: false, disabled: true },
311
+ { name: "Edit", active: false, disabled: false, type: "mode" },
312
+ { name: "Delete", active: false, disabled: false, type: "mode" },
313
+ { name: "Point", active: false, disabled: false, type: "tool" },
314
+ { name: "LineString", active: false, disabled: false, type: "tool" },
315
+ { name: "Polygon", active: false, disabled: false, type: "tool" },
316
+ { name: "Connection", active: false, disabled: true, type: "conn" },
317
317
  ],
318
318
  connectionDisplay: false,
319
319
  dialogPosition: {
@@ -374,13 +374,13 @@ export default {
374
374
  this.disabledToolbarConnectionIcon(true);
375
375
  },
376
376
  activeDrawMode: function (value) {
377
- this.updateToolbarIcons(value);
377
+ this.updateToolbarIcons(value, "mode");
378
378
  if (value === "Delete") {
379
379
  this.connectionDisplay = false;
380
380
  }
381
381
  },
382
382
  activeDrawTool: function (value) {
383
- this.updateToolbarIcons(value);
383
+ this.updateToolbarIcons(value, "tool");
384
384
  if (!value) {
385
385
  this.connectionDisplay = false;
386
386
  }
@@ -435,7 +435,7 @@ export default {
435
435
  this.connectionDisplay = !this.connectionDisplay;
436
436
  }
437
437
  },
438
- updateToolbarIcons: function (value) {
438
+ updateToolbarIcons: function (value, type) {
439
439
  this.toolbarIcons.map((icon) => {
440
440
  if (icon.name === value) {
441
441
  icon.active = true;
@@ -444,7 +444,8 @@ export default {
444
444
  }
445
445
  });
446
446
  this.toolbarIcons
447
- .filter((icon) => icon.name !== "Connection" && icon.name !== value)
447
+ .filter((icon) => icon.type !== "conn")
448
+ .filter((icon) => icon.type !== type)
448
449
  .map((icon) => {
449
450
  if (value) {
450
451
  icon.disabled = true;
@@ -456,7 +457,7 @@ export default {
456
457
  },
457
458
  disabledToolbarConnectionIcon: function (value) {
458
459
  this.toolbarIcons
459
- .filter((icon) => icon.name === "Connection")
460
+ .filter((icon) => icon.type === "conn")
460
461
  .map((icon) => {
461
462
  if (value) {
462
463
  icon.disabled = true;
@@ -472,7 +473,7 @@ export default {
472
473
  },
473
474
  activeToolbarConnectionIcon: function (value) {
474
475
  this.toolbarIcons
475
- .filter((icon) => icon.name === "Connection")
476
+ .filter((icon) => icon.type === "conn")
476
477
  .map((icon) => {
477
478
  if (value) {
478
479
  icon.active = true;
@@ -3,6 +3,9 @@
3
3
  <div class="block">
4
4
  <el-row class="info-field">
5
5
  <div class="title">Feature Annotations</div>
6
+ <div class="title-buttons">
7
+ <copy-to-clipboard :content="updatedCopyContent" />
8
+ </div>
6
9
  </el-row>
7
10
  <template v-if="annotationEntry">
8
11
  <el-row
@@ -11,7 +14,9 @@
11
14
  class="dialog-text"
12
15
  :key="key"
13
16
  >
14
- <strong>{{ label }}: </strong>&nbsp;{{ annotationEntry[key] }}
17
+ <strong>{{ label }}: </strong>&nbsp;
18
+ <span v-if="label !== 'Ontology'">{{ annotationEntry[key] }}</span>
19
+ <a v-else :href="ontologyLink" target="_blank">{{ annotationEntry[key] }}</a>
15
20
  </el-row>
16
21
  <template v-if="prevSubs.length > 0">
17
22
  <div
@@ -43,11 +48,15 @@
43
48
  <el-row class="dialog-text">
44
49
  <strong>Evidence: </strong>
45
50
  <el-row
46
- v-for="evidence in sub.body.evidence"
51
+ v-for="(evidence, index) in processEvidences(sub)"
47
52
  :key="evidence"
48
53
  class="dialog-text"
49
- >
50
- <a :href="evidence" target="_blank"> {{ evidence }}</a>
54
+ >
55
+ <a v-if="typeof evidence === 'object' ":href="Object.values(evidence)[0]" target="_blank">
56
+ {{ Object.keys(evidence)[0] }}
57
+ </a>
58
+ <span v-else> {{ evidence }}</span>
59
+ <span v-if="index !== sub.body.evidence.length - 1">, </span>
51
60
  </el-row>
52
61
  </el-row>
53
62
  <el-row class="dialog-text">
@@ -99,18 +108,17 @@
99
108
  <el-select
100
109
  :teleported="false"
101
110
  v-model="evidencePrefix"
102
- placeholder="No Prefix"
111
+ placeholder="Other:"
103
112
  class="select-box"
104
113
  popper-class="flatmap_dropdown"
105
114
  >
106
115
  <el-option
107
116
  v-for="item in evidencePrefixes"
108
- :key="item"
109
- :label="item"
110
- :value="item"
117
+ :key="item.label"
118
+ :value="item.value"
111
119
  >
112
120
  <el-row>
113
- <el-col :span="12">{{ item }}</el-col>
121
+ <el-col :span="12">{{ item.label }}</el-col>
114
122
  </el-row>
115
123
  </el-option>
116
124
  </el-select>
@@ -158,14 +166,18 @@ export default {
158
166
  return {
159
167
  displayPair: {
160
168
  "Feature ID": "featureId",
161
- Tooltip: "label",
162
- Models: "models",
169
+ Label: "label",
170
+ Ontology: "models",
163
171
  Name: "name",
164
172
  Resource: "resourceId",
165
173
  },
166
174
  editing: false,
167
- evidencePrefixes: ["", "DOI:", "PMID:"],
168
- evidencePrefix: "",
175
+ evidencePrefixes: [
176
+ { value: "DOI:", label: "DOI:" },
177
+ { value: "PMID:", label: "PMID:" },
178
+ { value: "", label: "Other:" },
179
+ ],
180
+ evidencePrefix: "DOI:",
169
181
  evidence: [],
170
182
  authenticated: false,
171
183
  newEvidence: "",
@@ -174,6 +186,7 @@ export default {
174
186
  showSubmissions: true,
175
187
  errorMessage: "",
176
188
  creator: undefined,
189
+ copyContent: '',
177
190
  };
178
191
  },
179
192
  computed: {
@@ -195,8 +208,42 @@ export default {
195
208
  this.annotationEntry["type"] === "deleted"
196
209
  );
197
210
  },
211
+ ontologyLink: function () {
212
+ const models = this.annotationEntry['models'];
213
+ if (models && models.startsWith("UBERON")) {
214
+ return `http://purl.obolibrary.org/obo/${this.annotationEntry.models.replace(":", "_")}`;
215
+ }
216
+ },
217
+ updatedCopyContent: function () {
218
+ return this.getUpdateCopyContent();
219
+ },
198
220
  },
199
221
  methods: {
222
+ processEvidences: function(sub) {
223
+ const evidences = [];
224
+ if (sub?.body?.evidence) {
225
+ sub.body.evidence.forEach((evidence) => {
226
+ if (typeof evidence === 'object') {
227
+ evidences.push(evidence);
228
+ } else {
229
+ const eviObject = {}
230
+ if (evidence.includes("https://doi.org/")) {
231
+ const key = evidence.replace("https://doi.org/", "DOI:");
232
+ eviObject[key] = evidence;
233
+ } else if (evidence.includes("https://pubmed.ncbi.nlm.nih.gov/")) {
234
+ const key = evidence.replace("https://pubmed.ncbi.nlm.nih.gov/", "PMID:");
235
+ eviObject[key] = evidence;
236
+ }
237
+ if (Object.keys(eviObject).length > 0) {
238
+ evidences.push(eviObject);
239
+ } else {
240
+ evidences.push(evidence);
241
+ }
242
+ }
243
+ });
244
+ }
245
+ return evidences;
246
+ },
200
247
  evidenceEntered: function (value) {
201
248
  if (value) {
202
249
  this.evidence.push(this.evidencePrefix + value);
@@ -316,6 +363,57 @@ export default {
316
363
  this.newFeature = "";
317
364
  this.comment = "";
318
365
  },
366
+ getUpdateCopyContent: function () {
367
+ if (!this.annotationEntry) {
368
+ return '';
369
+ }
370
+
371
+ const contentArray = [];
372
+
373
+ // featureId
374
+ if (this.annotationEntry.featureId) {
375
+ contentArray.push(`<div><strong>Feature ID:</strong>${this.annotationEntry.featureId}</div>`);
376
+ }
377
+
378
+ // label
379
+ if (this.annotationEntry.label) {
380
+ contentArray.push(`<div><strong>Label:</strong>${this.annotationEntry.label}</div>`);
381
+ }
382
+
383
+ // models
384
+ if (this.annotationEntry.models) {
385
+ contentArray.push(`<div><strong>Ontology:</strong>${this.annotationEntry.models}</div>`);
386
+ if (this.ontologyLink) {
387
+ contentArray.push(`<div><strong>Ontology Link:</strong>${this.ontologyLink}</div>`);
388
+ }
389
+ }
390
+
391
+ // resourceId
392
+ if (this.annotationEntry.resourceId) {
393
+ contentArray.push(`<div><strong>Resource:</strong>${this.annotationEntry.resourceId}</div>`);
394
+ }
395
+
396
+ if (this.prevSubs.length) {
397
+ let annotationContent = '<div><strong>Annotations:</strong></div>\n<br>';
398
+ this.prevSubs.map((sub, index) => {
399
+ annotationContent += `<div><strong>Created:</strong>${this.formatTime(sub.created)}</div>\n<br>`;
400
+ annotationContent += `<div><strong>Creator:</strong>${sub.creator.name}</div>\n<br>`;
401
+ annotationContent += `<div><strong>Email:</strong>${sub.creator.email}</div>\n<br>`;
402
+ if (sub.body.evidence.length) {
403
+ let evidenceContent = '';
404
+ sub.body.evidence.forEach((evi, index) => {
405
+ evidenceContent += `${typeof evi === 'object' ? Object.values(evi)[0] : evi}`;
406
+ if (index !== sub.body.evidence.length - 1) evidenceContent += ', ';
407
+ })
408
+ annotationContent += `<div><strong>Evidence:</strong>${evidenceContent}</div>\n<br>`;
409
+ }
410
+ annotationContent += `<div><strong>Comment:</strong>${sub.body.comment}</div>\n<br>`;
411
+ })
412
+ contentArray.push(`<div>${annotationContent}</div>`);
413
+ }
414
+
415
+ return contentArray.join('\n\n<br>');
416
+ },
319
417
  },
320
418
  watch: {
321
419
  annotationEntry: {
@@ -346,7 +444,11 @@ export default {
346
444
 
347
445
  <style lang="scss" scoped>
348
446
  .info-field {
447
+ padding: 0;
349
448
  display: flex;
449
+ flex-direction: row;
450
+ justify-content: space-between;
451
+ gap: 1rem;
350
452
  }
351
453
 
352
454
  .block {
@@ -405,7 +507,22 @@ export default {
405
507
  font-weight: 500;
406
508
  font-weight: bold;
407
509
  padding-bottom: 8px;
408
- color: rgb(131, 0, 191);
510
+ color: $app-primary-color;
511
+ }
512
+
513
+ .title-buttons {
514
+ display: flex;
515
+ flex-direction: row;
516
+ gap: 0.5rem;
517
+
518
+ :deep(.copy-clipboard-button) {
519
+ &,
520
+ &:hover,
521
+ &:focus {
522
+ border-color: $app-primary-color !important;
523
+ border-radius: 50%;
524
+ }
525
+ }
409
526
  }
410
527
 
411
528
  .sub-title {
@@ -2,6 +2,9 @@
2
2
  <div class="resource-container">
3
3
  <div class="attribute-title-container">
4
4
  <div class="attribute-title">References</div>
5
+ <div class="copy-button">
6
+ <CopyToClipboard label="Copy list to clipboard" :content="referecesListContent" />
7
+ </div>
5
8
  </div>
6
9
  <div class="citation-tabs" v-if="referencesWithDOI">
7
10
  <el-button
@@ -76,6 +79,7 @@ export default {
76
79
  pubMedReferences: [],
77
80
  openLibReferences: [],
78
81
  isbnDBReferences: [],
82
+ referecesListContent: '',
79
83
  citationOptions: CITATION_OPTIONS,
80
84
  citationType: CITATION_DEFAULT,
81
85
  }
@@ -83,6 +87,7 @@ export default {
83
87
  watch: {
84
88
  resources: function (_resources) {
85
89
  this.formatReferences([..._resources]);
90
+ this.getCitationText(CITATION_DEFAULT);
86
91
  },
87
92
  },
88
93
  computed: {
@@ -318,6 +323,13 @@ export default {
318
323
  values.push(reference.url);
319
324
  });
320
325
 
326
+ if (values.length) {
327
+ const list = values.map((item) => `<li>${item}</li>`).join('\n');
328
+ const listContent = `<ul>${list}</ul>`;
329
+ const listTitle = `<div><strong>References</strong></div>`;
330
+ this.referecesListContent = listTitle + `\n` + listContent;
331
+ }
332
+
321
333
  this.$emit('references-loaded', {
322
334
  style: citationFormatStyle,
323
335
  list: values
@@ -436,10 +448,25 @@ export default {
436
448
  <style lang="scss" scoped>
437
449
  .resource-container {
438
450
  margin-top: 1em;
451
+
452
+ &:hover {
453
+ .attribute-title-container :deep(.copy-clipboard-button) {
454
+ opacity: 1;
455
+ visibility: visible;
456
+ }
457
+ }
439
458
  }
440
459
 
441
460
  .attribute-title-container {
442
461
  margin-bottom: 0.5rem;
462
+ display: flex;
463
+ align-items: center;
464
+ gap: 0.5rem;
465
+
466
+ :deep(.copy-clipboard-button) {
467
+ opacity: 0;
468
+ visibility: hidden;
469
+ }
443
470
  }
444
471
 
445
472
  .attribute-title {
@@ -465,6 +492,7 @@ export default {
465
492
 
466
493
  :deep(a) {
467
494
  word-wrap: break-word;
495
+ color: $app-primary-color;
468
496
  }
469
497
 
470
498
  + li {
@@ -14,7 +14,6 @@ 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']
18
17
  ElCard: typeof import('element-plus/es')['ElCard']
19
18
  ElCol: typeof import('element-plus/es')['ElCol']
20
19
  ElColorPicker: typeof import('element-plus/es')['ElColorPicker']