@abi-software/flatmapvuer 1.1.4 → 1.2.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.
Files changed (41) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +120 -120
  3. package/cypress.config.js +23 -23
  4. package/dist/flatmapvuer.js +43570 -38544
  5. package/dist/flatmapvuer.umd.cjs +182 -182
  6. package/dist/index.html +17 -17
  7. package/dist/style.css +1 -1
  8. package/package.json +95 -95
  9. package/public/index.html +17 -17
  10. package/reporter-config.json +9 -9
  11. package/src/App.vue +379 -379
  12. package/src/assets/_variables.scss +43 -43
  13. package/src/assets/styles.scss +5 -5
  14. package/src/components/AnnotationTool.vue +501 -501
  15. package/src/components/ConnectionDialog.vue +134 -134
  16. package/src/components/DrawTool.vue +502 -502
  17. package/src/components/EventBus.js +3 -3
  18. package/src/components/ExternalResourceCard.vue +109 -109
  19. package/src/components/FlatmapVuer.vue +3515 -3461
  20. package/src/components/HelpModeDialog.vue +360 -360
  21. package/src/components/MultiFlatmapVuer.vue +814 -814
  22. package/src/components/ProvenancePopup.vue +530 -530
  23. package/src/components/SelectionsGroup.vue +363 -363
  24. package/src/components/Tooltip.vue +50 -50
  25. package/src/components/TreeControls.vue +236 -236
  26. package/src/components/index.js +8 -8
  27. package/src/components/legends/DynamicLegends.vue +106 -106
  28. package/src/components/legends/SvgLegends.vue +112 -112
  29. package/src/icons/flatmap-marker.js +9 -9
  30. package/src/icons/fonts/mapicon-species.svg +14 -14
  31. package/src/icons/fonts/mapicon-species.ttf +0 -0
  32. package/src/icons/fonts/mapicon-species.woff +0 -0
  33. package/src/icons/mapicon-species-style.css +42 -42
  34. package/src/icons/yellowstar.js +5 -5
  35. package/src/legends/legend.svg +25 -25
  36. package/src/main.js +19 -19
  37. package/src/services/flatmapQueries.js +475 -475
  38. package/src/store/index.js +23 -23
  39. package/vite.config.js +73 -73
  40. package/vite.static-build.js +12 -12
  41. package/vuese-generator.js +64 -64
@@ -1,501 +1,501 @@
1
- <template>
2
- <el-main class="main">
3
- <div class="block">
4
- <el-row class="info-field">
5
- <div class="title">Feature Annotations</div>
6
- </el-row>
7
- <template v-if="annotationEntry">
8
- <el-row
9
- v-for="(key, label) in displayPair"
10
- v-show="annotationEntry[key]"
11
- class="dialog-text"
12
- :key="key"
13
- >
14
- <strong>{{ label }}: </strong>&nbsp;{{ annotationEntry[key] }}
15
- </el-row>
16
- <template v-if="prevSubs.length > 0">
17
- <div
18
- v-show="showSubmissions"
19
- class="hide"
20
- @click="showSubmissions = false"
21
- >
22
- Hide previous submissions
23
- <el-icon><el-icon-arrow-up /></el-icon>
24
- </div>
25
- <div
26
- v-show="!showSubmissions"
27
- class="hide"
28
- @click="showSubmissions = true"
29
- >
30
- Show previous {{ prevSubs.length }} submission(s)
31
- <el-icon><el-icon-arrow-down /></el-icon>
32
- </div>
33
- <template v-if="showSubmissions">
34
- <el-row class="dialog-spacer"></el-row>
35
- <el-row class="dialog-text">
36
- <strong class="sub-title">Previous submissions:</strong>
37
- </el-row>
38
- <div class="entry" v-for="(sub, index) in prevSubs" :key="index">
39
- <el-row class="dialog-text">
40
- <strong>{{ formatTime(sub.created) }}</strong>
41
- {{ sub.creator.name }}
42
- </el-row>
43
- <el-row class="dialog-text">
44
- <strong>Evidence: </strong>
45
- <el-row
46
- v-for="evidence in sub.body.evidence"
47
- :key="evidence"
48
- class="dialog-text"
49
- >
50
- <a :href="evidence" target="_blank"> {{ evidence }}</a>
51
- </el-row>
52
- </el-row>
53
- <el-row class="dialog-text">
54
- <strong>Comment: </strong> {{ sub.body.comment }}
55
- </el-row>
56
- </div>
57
- </template>
58
- </template>
59
- <template v-if="authenticated">
60
- <template v-if="isEditable">
61
- <el-row class="dialog-spacer"></el-row>
62
- <el-row v-if="!editing">
63
- <el-icon class="standard-icon">
64
- <el-icon-edit @click="editing = true" />
65
- </el-icon>
66
- <el-icon
67
- class="standard-icon"
68
- v-if="isDeleted"
69
- >
70
- <el-icon-delete @click="submit"/>
71
- </el-icon>
72
- <el-icon
73
- class="standard-icon"
74
- v-else-if="isPositionUpdated"
75
- >
76
- <el-icon-finished @click="submit" />
77
- </el-icon>
78
- </el-row>
79
- <template v-else>
80
- <el-row class="dialog-text">
81
- <strong class="sub-title">Suggest changes:</strong>
82
- </el-row>
83
- <template v-if="!isDeleted">
84
- <el-row class="dialog-text">
85
- <strong>Evidence:</strong>
86
- </el-row>
87
- <el-row v-for="(value, index) in evidence" :key="value">
88
- <el-col :span="20">
89
- {{ evidence[index] }}
90
- </el-col>
91
- <el-col :span="4">
92
- <el-icon class="standard-icon">
93
- <el-icon-close @click="removeEvidence(index)" />
94
- </el-icon>
95
- </el-col>
96
- </el-row>
97
- <el-row>
98
- <el-input
99
- size="small"
100
- placeholder="Enter"
101
- v-model="newEvidence"
102
- @change="evidenceEntered($event)"
103
- >
104
- <template #prepend>
105
- <el-select
106
- :teleported="false"
107
- v-model="evidencePrefix"
108
- placeholder="Select"
109
- class="select-box"
110
- popper-class="flatmap_dropdown"
111
- >
112
- <el-option
113
- v-for="item in evidencePrefixes"
114
- :key="item"
115
- :label="item"
116
- :value="item"
117
- >
118
- <el-row>
119
- <el-col :span="12">{{ item }}</el-col>
120
- </el-row>
121
- </el-option>
122
- </el-select>
123
- </template>
124
- </el-input>
125
- </el-row>
126
- </template>
127
- <el-row>
128
- <strong>Comment:</strong>
129
- </el-row>
130
- <el-row class="dialog-text">
131
- <el-input
132
- type="textarea"
133
- :autosize="{ minRows: 2, maxRows: 4 }"
134
- placeholder="Enter"
135
- v-model="comment"
136
- />
137
- </el-row>
138
- <el-row class="dialog-text">
139
- <el-button class="button" type="primary" plain @click="submit">
140
- Submit
141
- </el-button>
142
- </el-row>
143
- </template>
144
- <el-row class="dialog-text" v-if="errorMessage">
145
- <strong class="sub-title"> {{ errorMessage }} </strong>
146
- </el-row>
147
- </template>
148
- </template>
149
- </template>
150
- </div>
151
- </el-main>
152
- </template>
153
-
154
- <script>
155
- import {
156
- ArrowUp as ElIconArrowUp,
157
- ArrowDown as ElIconArrowDown,
158
- Edit as ElIconEdit,
159
- Close as ElIconClose,
160
- Delete as ElIconDelete,
161
- Finished as ElIconFinished,
162
- } from '@element-plus/icons-vue'
163
- /* eslint-disable no-alert, no-console */
164
- import {
165
- ElButton as Button,
166
- ElCol as Col,
167
- ElInput as Input,
168
- ElMain as Main,
169
- ElRow as Row,
170
- ElSelect as Select,
171
- } from 'element-plus'
172
-
173
- export default {
174
- name: 'AnnotationTool',
175
- components: {
176
- Button,
177
- Col,
178
- Input,
179
- Main,
180
- Row,
181
- Select,
182
- ElIconArrowUp,
183
- ElIconArrowDown,
184
- ElIconEdit,
185
- ElIconClose,
186
- },
187
- props: {
188
- annotationEntry: {
189
- type: Object,
190
- },
191
- },
192
- inject: ['flatmapAPI', '$annotator', 'userApiKey'],
193
- data: function () {
194
- return {
195
- displayPair: {
196
- 'Feature ID': 'featureId',
197
- Tooltip: 'label',
198
- Models: 'models',
199
- Name: 'name',
200
- Resource: 'resourceId',
201
- },
202
- editing: false,
203
- evidencePrefixes: ['DOI:', 'PMID:'],
204
- evidencePrefix: 'DOI:',
205
- evidence: [],
206
- authenticated: false,
207
- newEvidence: '',
208
- comment: '',
209
- prevSubs: [],
210
- showSubmissions: true,
211
- errorMessage: '',
212
- creator: undefined
213
- }
214
- },
215
- computed: {
216
- isEditable: function () {
217
- return (
218
- this.annotationEntry['resourceId'] &&
219
- this.annotationEntry['featureId']
220
- )
221
- },
222
- isPositionUpdated: function () {
223
- return (
224
- this.annotationEntry['resourceId'] &&
225
- this.annotationEntry['type'] === 'updated' &&
226
- this.annotationEntry['positionUpdated']
227
- )
228
- },
229
- isDeleted: function () {
230
- return (
231
- this.annotationEntry['resourceId'] &&
232
- this.annotationEntry['type'] === 'deleted'
233
- )
234
- }
235
- },
236
- methods: {
237
- evidenceEntered: function (value) {
238
- if (value) {
239
- this.evidence.push(this.evidencePrefix + value)
240
- this.newEvidence = ''
241
- }
242
- },
243
- formatTime: function (dateString) {
244
- const options = {
245
- year: 'numeric',
246
- month: 'long',
247
- day: 'numeric',
248
- hour: 'numeric',
249
- minute: 'numeric',
250
- second: 'numeric',
251
- }
252
- return new Date(dateString).toLocaleDateString(undefined, options)
253
- },
254
- updatePrevSubmissions: function () {
255
- if (this.$annotator && this.authenticated) {
256
- if (
257
- this.annotationEntry['resourceId'] &&
258
- this.annotationEntry['featureId']
259
- ) {
260
- this.$annotator
261
- .itemAnnotations(
262
- this.userApiKey,
263
- this.annotationEntry['resourceId'],
264
- this.annotationEntry['featureId']
265
- )
266
- .then((value) => {
267
- this.prevSubs = value
268
- })
269
- .catch((reason) => {
270
- console.log(reason) // Error!
271
- })
272
- }
273
- }
274
- },
275
- submit: function () {
276
- // User can either update/delete annotation directly
277
- // or provide extra comments for update/delete action
278
- if (
279
- this.annotationEntry['type'] === 'updated' &&
280
- this.annotationEntry['positionUpdated']
281
- ) {
282
- this.comment = this.comment ?
283
- `Position Updated: ${this.comment}` :
284
- 'Position Updated'
285
- } else if (this.annotationEntry['type'] === 'deleted') {
286
- this.comment = this.comment ?
287
- `Feature Deleted: ${this.comment}` :
288
- 'Feature Deleted'
289
- }
290
-
291
- if (this.evidence.length > 0 || this.comment) {
292
- if (
293
- this.annotationEntry['resourceId'] &&
294
- this.annotationEntry['featureId']
295
- ) {
296
- const evidenceURLs = []
297
- this.evidence.forEach((evidence) => {
298
- if (evidence.includes('DOI:')) {
299
- const link = evidence.replace('DOI:', 'https://doi.org/')
300
- evidenceURLs.push(new URL(link))
301
- } else if (evidence.includes('PMID:')) {
302
- const link = evidence.replace(
303
- 'PMID:',
304
- 'https://pubmed.ncbi.nlm.nih.gov/'
305
- )
306
- evidenceURLs.push(new URL(link))
307
- }
308
- })
309
- const userAnnotation = {
310
- resource: this.annotationEntry['resourceId'],
311
- item: Object.assign({id: this.annotationEntry['featureId']},
312
- Object.fromEntries(
313
- Object.entries(this.annotationEntry)
314
- .filter(([key]) => ['label', 'models'].includes(key)))),
315
- body: {
316
- evidence: evidenceURLs,
317
- comment: this.comment,
318
- },
319
- feature: this.annotationEntry['feature']
320
- }
321
- Object.assign(userAnnotation.body, this.annotationEntry['body'])
322
- if (this.annotationEntry['type'] === 'deleted') {
323
- userAnnotation.feature = undefined
324
- }
325
- if (this.creator) userAnnotation.creator = this.creator
326
- this.$annotator
327
- .addAnnotation(this.userApiKey, userAnnotation)
328
- .then(() => {
329
- this.$emit('annotation', userAnnotation)
330
- this.errorMessage = ''
331
- this.resetSubmission()
332
- this.updatePrevSubmissions()
333
- })
334
- .catch(() => {
335
- this.errorMessage =
336
- 'There is a problem with the submission, please try again later'
337
- })
338
- }
339
- }
340
- },
341
- removeEvidence: function (index) {
342
- this.evidence.splice(index, 1)
343
- },
344
- resetSubmission: function () {
345
- this.editing = false
346
- this.evidence = []
347
- this.newFeature = ''
348
- this.comment = ''
349
- },
350
- },
351
- watch: {
352
- annotationEntry: {
353
- handler: function (newVal, oldVal) {
354
- if (newVal !== oldVal) {
355
- this.resetSubmission()
356
- this.updatePrevSubmissions()
357
- }
358
- },
359
- immediate: false,
360
- deep: false,
361
- },
362
- },
363
- mounted: function () {
364
- this.$annotator.authenticate(this.userApiKey).then((userData) => {
365
- if (userData.name && userData.email) {
366
- this.creator = userData
367
- if (!userData.orcid) this.creator.orcid = '0000-0000-0000-0000'
368
- this.authenticated = true
369
- this.updatePrevSubmissions()
370
- } else {
371
- this.errorMessage = ''
372
- }
373
- })
374
- },
375
- }
376
- </script>
377
-
378
- <style lang="scss" scoped>
379
-
380
- .info-field {
381
- display: flex;
382
- }
383
-
384
- .block {
385
- margin-bottom: 0.5em;
386
-
387
- .main > &:first-of-type {
388
- margin-right: 0.5em;
389
- }
390
- }
391
-
392
- .button {
393
- padding-top: 5px;
394
- padding-bottom: 5px;
395
- }
396
-
397
- .standard-icon {
398
- color: $app-primary-color;
399
- &:hover {
400
- cursor: pointer;
401
- }
402
- }
403
-
404
- .dialog-text {
405
- color: rgb(48, 49, 51);
406
- font-size: 14px;
407
- font-weight: normal;
408
- line-height: 20px;
409
- }
410
-
411
- .main {
412
- font-size: 14px;
413
- text-align: left;
414
- line-height: 1.5em;
415
- font-family: Asap, sans-serif, Helvetica;
416
- font-weight: 400;
417
- /* outline: thin red solid; */
418
- padding: 1em !important;
419
- overflow-x: hidden;
420
- overflow-y: auto;
421
- min-width: 300px; // .maplibregl-popup max-width
422
- max-height: 400px;
423
- scrollbar-width: thin;
424
-
425
- &::-webkit-scrollbar {
426
- width: 4px;
427
- }
428
-
429
- &::-webkit-scrollbar-thumb {
430
- border-radius: 10px;
431
- box-shadow: inset 0 0 6px #c0c4cc;
432
- }
433
- }
434
-
435
- .title {
436
- font-size: 18px;
437
- font-weight: 500;
438
- font-weight: bold;
439
- padding-bottom: 8px;
440
- color: rgb(131, 0, 191);
441
- }
442
-
443
- .sub-title {
444
- font-size: 16px;
445
- }
446
-
447
- .dialog-spacer {
448
- border-bottom: 1px solid #e4e7ed;
449
- margin-bottom: 10px;
450
- }
451
-
452
- .submit {
453
- color: $app-primary-color;
454
- &:hover {
455
- cursor: pointer;
456
- }
457
- }
458
-
459
- .entry ~ .entry {
460
- border-top: 1px solid #e4e7ed;
461
- margin-top: 10px;
462
- }
463
-
464
- .hide {
465
- color: $app-primary-color;
466
- cursor: pointer;
467
- margin-right: 6px;
468
- margin-top: 3px;
469
- }
470
-
471
- :deep(.el-input__inner),
472
- :deep(.el-textarea__inner) {
473
- font-family: Asap, sans-serif;
474
- }
475
-
476
- .select-box {
477
- width: 80px;
478
- background-color: var(--white);
479
- font-weight: 500;
480
- color: rgb(48, 49, 51);
481
- :deep(.el-input__inner) {
482
- height: 30px;
483
- color: rgb(48, 49, 51);
484
- }
485
- :deep(.el-input__icon) {
486
- line-height: 30px;
487
- }
488
- }
489
-
490
- :deep(.flatmap_dropdown) {
491
- min-width: 80px !important;
492
- .el-select-dropdown__item {
493
- white-space: nowrap;
494
- text-align: left;
495
- &.selected {
496
- color: $app-primary-color;
497
- font-weight: normal;
498
- }
499
- }
500
- }
501
- </style>
1
+ <template>
2
+ <el-main class="main">
3
+ <div class="block">
4
+ <el-row class="info-field">
5
+ <div class="title">Feature Annotations</div>
6
+ </el-row>
7
+ <template v-if="annotationEntry">
8
+ <el-row
9
+ v-for="(key, label) in displayPair"
10
+ v-show="annotationEntry[key]"
11
+ class="dialog-text"
12
+ :key="key"
13
+ >
14
+ <strong>{{ label }}: </strong>&nbsp;{{ annotationEntry[key] }}
15
+ </el-row>
16
+ <template v-if="prevSubs.length > 0">
17
+ <div
18
+ v-show="showSubmissions"
19
+ class="hide"
20
+ @click="showSubmissions = false"
21
+ >
22
+ Hide previous submissions
23
+ <el-icon><el-icon-arrow-up /></el-icon>
24
+ </div>
25
+ <div
26
+ v-show="!showSubmissions"
27
+ class="hide"
28
+ @click="showSubmissions = true"
29
+ >
30
+ Show previous {{ prevSubs.length }} submission(s)
31
+ <el-icon><el-icon-arrow-down /></el-icon>
32
+ </div>
33
+ <template v-if="showSubmissions">
34
+ <el-row class="dialog-spacer"></el-row>
35
+ <el-row class="dialog-text">
36
+ <strong class="sub-title">Previous submissions:</strong>
37
+ </el-row>
38
+ <div class="entry" v-for="(sub, index) in prevSubs" :key="index">
39
+ <el-row class="dialog-text">
40
+ <strong>{{ formatTime(sub.created) }}</strong>
41
+ {{ sub.creator.name }}
42
+ </el-row>
43
+ <el-row class="dialog-text">
44
+ <strong>Evidence: </strong>
45
+ <el-row
46
+ v-for="evidence in sub.body.evidence"
47
+ :key="evidence"
48
+ class="dialog-text"
49
+ >
50
+ <a :href="evidence" target="_blank"> {{ evidence }}</a>
51
+ </el-row>
52
+ </el-row>
53
+ <el-row class="dialog-text">
54
+ <strong>Comment: </strong> {{ sub.body.comment }}
55
+ </el-row>
56
+ </div>
57
+ </template>
58
+ </template>
59
+ <template v-if="authenticated">
60
+ <template v-if="isEditable">
61
+ <el-row class="dialog-spacer"></el-row>
62
+ <el-row v-if="!editing">
63
+ <el-icon class="standard-icon">
64
+ <el-icon-edit @click="editing = true" />
65
+ </el-icon>
66
+ <el-icon
67
+ class="standard-icon"
68
+ v-if="isDeleted"
69
+ >
70
+ <el-icon-delete @click="submit"/>
71
+ </el-icon>
72
+ <el-icon
73
+ class="standard-icon"
74
+ v-else-if="isPositionUpdated"
75
+ >
76
+ <el-icon-finished @click="submit" />
77
+ </el-icon>
78
+ </el-row>
79
+ <template v-else>
80
+ <el-row class="dialog-text">
81
+ <strong class="sub-title">Suggest changes:</strong>
82
+ </el-row>
83
+ <template v-if="!isDeleted">
84
+ <el-row class="dialog-text">
85
+ <strong>Evidence:</strong>
86
+ </el-row>
87
+ <el-row v-for="(value, index) in evidence" :key="value">
88
+ <el-col :span="20">
89
+ {{ evidence[index] }}
90
+ </el-col>
91
+ <el-col :span="4">
92
+ <el-icon class="standard-icon">
93
+ <el-icon-close @click="removeEvidence(index)" />
94
+ </el-icon>
95
+ </el-col>
96
+ </el-row>
97
+ <el-row>
98
+ <el-input
99
+ size="small"
100
+ placeholder="Enter"
101
+ v-model="newEvidence"
102
+ @change="evidenceEntered($event)"
103
+ >
104
+ <template #prepend>
105
+ <el-select
106
+ :teleported="false"
107
+ v-model="evidencePrefix"
108
+ placeholder="Select"
109
+ class="select-box"
110
+ popper-class="flatmap_dropdown"
111
+ >
112
+ <el-option
113
+ v-for="item in evidencePrefixes"
114
+ :key="item"
115
+ :label="item"
116
+ :value="item"
117
+ >
118
+ <el-row>
119
+ <el-col :span="12">{{ item }}</el-col>
120
+ </el-row>
121
+ </el-option>
122
+ </el-select>
123
+ </template>
124
+ </el-input>
125
+ </el-row>
126
+ </template>
127
+ <el-row>
128
+ <strong>Comment:</strong>
129
+ </el-row>
130
+ <el-row class="dialog-text">
131
+ <el-input
132
+ type="textarea"
133
+ :autosize="{ minRows: 2, maxRows: 4 }"
134
+ placeholder="Enter"
135
+ v-model="comment"
136
+ />
137
+ </el-row>
138
+ <el-row class="dialog-text">
139
+ <el-button class="button" type="primary" plain @click="submit">
140
+ Submit
141
+ </el-button>
142
+ </el-row>
143
+ </template>
144
+ <el-row class="dialog-text" v-if="errorMessage">
145
+ <strong class="sub-title"> {{ errorMessage }} </strong>
146
+ </el-row>
147
+ </template>
148
+ </template>
149
+ </template>
150
+ </div>
151
+ </el-main>
152
+ </template>
153
+
154
+ <script>
155
+ import {
156
+ ArrowUp as ElIconArrowUp,
157
+ ArrowDown as ElIconArrowDown,
158
+ Edit as ElIconEdit,
159
+ Close as ElIconClose,
160
+ Delete as ElIconDelete,
161
+ Finished as ElIconFinished,
162
+ } from '@element-plus/icons-vue'
163
+ /* eslint-disable no-alert, no-console */
164
+ import {
165
+ ElButton as Button,
166
+ ElCol as Col,
167
+ ElInput as Input,
168
+ ElMain as Main,
169
+ ElRow as Row,
170
+ ElSelect as Select,
171
+ } from 'element-plus'
172
+
173
+ export default {
174
+ name: 'AnnotationTool',
175
+ components: {
176
+ Button,
177
+ Col,
178
+ Input,
179
+ Main,
180
+ Row,
181
+ Select,
182
+ ElIconArrowUp,
183
+ ElIconArrowDown,
184
+ ElIconEdit,
185
+ ElIconClose,
186
+ },
187
+ props: {
188
+ annotationEntry: {
189
+ type: Object,
190
+ },
191
+ },
192
+ inject: ['flatmapAPI', '$annotator', 'userApiKey'],
193
+ data: function () {
194
+ return {
195
+ displayPair: {
196
+ 'Feature ID': 'featureId',
197
+ Tooltip: 'label',
198
+ Models: 'models',
199
+ Name: 'name',
200
+ Resource: 'resourceId',
201
+ },
202
+ editing: false,
203
+ evidencePrefixes: ['DOI:', 'PMID:'],
204
+ evidencePrefix: 'DOI:',
205
+ evidence: [],
206
+ authenticated: false,
207
+ newEvidence: '',
208
+ comment: '',
209
+ prevSubs: [],
210
+ showSubmissions: true,
211
+ errorMessage: '',
212
+ creator: undefined
213
+ }
214
+ },
215
+ computed: {
216
+ isEditable: function () {
217
+ return (
218
+ this.annotationEntry['resourceId'] &&
219
+ this.annotationEntry['featureId']
220
+ )
221
+ },
222
+ isPositionUpdated: function () {
223
+ return (
224
+ this.annotationEntry['resourceId'] &&
225
+ this.annotationEntry['type'] === 'updated' &&
226
+ this.annotationEntry['positionUpdated']
227
+ )
228
+ },
229
+ isDeleted: function () {
230
+ return (
231
+ this.annotationEntry['resourceId'] &&
232
+ this.annotationEntry['type'] === 'deleted'
233
+ )
234
+ }
235
+ },
236
+ methods: {
237
+ evidenceEntered: function (value) {
238
+ if (value) {
239
+ this.evidence.push(this.evidencePrefix + value)
240
+ this.newEvidence = ''
241
+ }
242
+ },
243
+ formatTime: function (dateString) {
244
+ const options = {
245
+ year: 'numeric',
246
+ month: 'long',
247
+ day: 'numeric',
248
+ hour: 'numeric',
249
+ minute: 'numeric',
250
+ second: 'numeric',
251
+ }
252
+ return new Date(dateString).toLocaleDateString(undefined, options)
253
+ },
254
+ updatePrevSubmissions: function () {
255
+ if (this.$annotator && this.authenticated) {
256
+ if (
257
+ this.annotationEntry['resourceId'] &&
258
+ this.annotationEntry['featureId']
259
+ ) {
260
+ this.$annotator
261
+ .itemAnnotations(
262
+ this.userApiKey,
263
+ this.annotationEntry['resourceId'],
264
+ this.annotationEntry['featureId']
265
+ )
266
+ .then((value) => {
267
+ this.prevSubs = value
268
+ })
269
+ .catch((reason) => {
270
+ console.log(reason) // Error!
271
+ })
272
+ }
273
+ }
274
+ },
275
+ submit: function () {
276
+ // User can either update/delete annotation directly
277
+ // or provide extra comments for update/delete action
278
+ if (
279
+ this.annotationEntry['type'] === 'updated' &&
280
+ this.annotationEntry['positionUpdated']
281
+ ) {
282
+ this.comment = this.comment ?
283
+ `Position Updated: ${this.comment}` :
284
+ 'Position Updated'
285
+ } else if (this.annotationEntry['type'] === 'deleted') {
286
+ this.comment = this.comment ?
287
+ `Feature Deleted: ${this.comment}` :
288
+ 'Feature Deleted'
289
+ }
290
+
291
+ if (this.evidence.length > 0 || this.comment) {
292
+ if (
293
+ this.annotationEntry['resourceId'] &&
294
+ this.annotationEntry['featureId']
295
+ ) {
296
+ const evidenceURLs = []
297
+ this.evidence.forEach((evidence) => {
298
+ if (evidence.includes('DOI:')) {
299
+ const link = evidence.replace('DOI:', 'https://doi.org/')
300
+ evidenceURLs.push(new URL(link))
301
+ } else if (evidence.includes('PMID:')) {
302
+ const link = evidence.replace(
303
+ 'PMID:',
304
+ 'https://pubmed.ncbi.nlm.nih.gov/'
305
+ )
306
+ evidenceURLs.push(new URL(link))
307
+ }
308
+ })
309
+ const userAnnotation = {
310
+ resource: this.annotationEntry['resourceId'],
311
+ item: Object.assign({id: this.annotationEntry['featureId']},
312
+ Object.fromEntries(
313
+ Object.entries(this.annotationEntry)
314
+ .filter(([key]) => ['label', 'models'].includes(key)))),
315
+ body: {
316
+ evidence: evidenceURLs,
317
+ comment: this.comment,
318
+ },
319
+ feature: this.annotationEntry['feature']
320
+ }
321
+ Object.assign(userAnnotation.body, this.annotationEntry['body'])
322
+ if (this.annotationEntry['type'] === 'deleted') {
323
+ userAnnotation.feature = undefined
324
+ }
325
+ if (this.creator) userAnnotation.creator = this.creator
326
+ this.$annotator
327
+ .addAnnotation(this.userApiKey, userAnnotation)
328
+ .then(() => {
329
+ this.$emit('annotation', userAnnotation)
330
+ this.errorMessage = ''
331
+ this.resetSubmission()
332
+ this.updatePrevSubmissions()
333
+ })
334
+ .catch(() => {
335
+ this.errorMessage =
336
+ 'There is a problem with the submission, please try again later'
337
+ })
338
+ }
339
+ }
340
+ },
341
+ removeEvidence: function (index) {
342
+ this.evidence.splice(index, 1)
343
+ },
344
+ resetSubmission: function () {
345
+ this.editing = false
346
+ this.evidence = []
347
+ this.newFeature = ''
348
+ this.comment = ''
349
+ },
350
+ },
351
+ watch: {
352
+ annotationEntry: {
353
+ handler: function (newVal, oldVal) {
354
+ if (newVal !== oldVal) {
355
+ this.resetSubmission()
356
+ this.updatePrevSubmissions()
357
+ }
358
+ },
359
+ immediate: false,
360
+ deep: false,
361
+ },
362
+ },
363
+ mounted: function () {
364
+ this.$annotator.authenticate(this.userApiKey).then((userData) => {
365
+ if (userData.name && userData.email) {
366
+ this.creator = userData
367
+ if (!userData.orcid) this.creator.orcid = '0000-0000-0000-0000'
368
+ this.authenticated = true
369
+ this.updatePrevSubmissions()
370
+ } else {
371
+ this.errorMessage = ''
372
+ }
373
+ })
374
+ },
375
+ }
376
+ </script>
377
+
378
+ <style lang="scss" scoped>
379
+
380
+ .info-field {
381
+ display: flex;
382
+ }
383
+
384
+ .block {
385
+ margin-bottom: 0.5em;
386
+
387
+ .main > &:first-of-type {
388
+ margin-right: 0.5em;
389
+ }
390
+ }
391
+
392
+ .button {
393
+ padding-top: 5px;
394
+ padding-bottom: 5px;
395
+ }
396
+
397
+ .standard-icon {
398
+ color: $app-primary-color;
399
+ &:hover {
400
+ cursor: pointer;
401
+ }
402
+ }
403
+
404
+ .dialog-text {
405
+ color: rgb(48, 49, 51);
406
+ font-size: 14px;
407
+ font-weight: normal;
408
+ line-height: 20px;
409
+ }
410
+
411
+ .main {
412
+ font-size: 14px;
413
+ text-align: left;
414
+ line-height: 1.5em;
415
+ font-family: Asap, sans-serif, Helvetica;
416
+ font-weight: 400;
417
+ /* outline: thin red solid; */
418
+ padding: 1em !important;
419
+ overflow-x: hidden;
420
+ overflow-y: auto;
421
+ min-width: 300px; // .maplibregl-popup max-width
422
+ max-height: 400px;
423
+ scrollbar-width: thin;
424
+
425
+ &::-webkit-scrollbar {
426
+ width: 4px;
427
+ }
428
+
429
+ &::-webkit-scrollbar-thumb {
430
+ border-radius: 10px;
431
+ box-shadow: inset 0 0 6px #c0c4cc;
432
+ }
433
+ }
434
+
435
+ .title {
436
+ font-size: 18px;
437
+ font-weight: 500;
438
+ font-weight: bold;
439
+ padding-bottom: 8px;
440
+ color: rgb(131, 0, 191);
441
+ }
442
+
443
+ .sub-title {
444
+ font-size: 16px;
445
+ }
446
+
447
+ .dialog-spacer {
448
+ border-bottom: 1px solid #e4e7ed;
449
+ margin-bottom: 10px;
450
+ }
451
+
452
+ .submit {
453
+ color: $app-primary-color;
454
+ &:hover {
455
+ cursor: pointer;
456
+ }
457
+ }
458
+
459
+ .entry ~ .entry {
460
+ border-top: 1px solid #e4e7ed;
461
+ margin-top: 10px;
462
+ }
463
+
464
+ .hide {
465
+ color: $app-primary-color;
466
+ cursor: pointer;
467
+ margin-right: 6px;
468
+ margin-top: 3px;
469
+ }
470
+
471
+ :deep(.el-input__inner),
472
+ :deep(.el-textarea__inner) {
473
+ font-family: Asap, sans-serif;
474
+ }
475
+
476
+ .select-box {
477
+ width: 80px;
478
+ background-color: var(--white);
479
+ font-weight: 500;
480
+ color: rgb(48, 49, 51);
481
+ :deep(.el-input__inner) {
482
+ height: 30px;
483
+ color: rgb(48, 49, 51);
484
+ }
485
+ :deep(.el-input__icon) {
486
+ line-height: 30px;
487
+ }
488
+ }
489
+
490
+ :deep(.flatmap_dropdown) {
491
+ min-width: 80px !important;
492
+ .el-select-dropdown__item {
493
+ white-space: nowrap;
494
+ text-align: left;
495
+ &.selected {
496
+ color: $app-primary-color;
497
+ font-weight: normal;
498
+ }
499
+ }
500
+ }
501
+ </style>