@abi-software/map-side-bar 2.14.0 → 2.14.1-acupoint.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.
@@ -0,0 +1,620 @@
1
+ <template>
2
+ <div v-if="entry" class="main">
3
+ <div class="header">
4
+ <el-row>
5
+ <el-input
6
+ class="search-input"
7
+ placeholder="Search"
8
+ v-model="searchInput"
9
+ @keyup="search(searchInput)"
10
+ clearable
11
+ @clear="clearSearchClicked"
12
+ ></el-input>
13
+ <el-button
14
+ v-show="false"
15
+ type="primary"
16
+ class="button"
17
+ @click="search(searchInput)"
18
+ size="large"
19
+ >
20
+ Search
21
+ </el-button>
22
+ </el-row>
23
+ </div>
24
+ <SearchFilters
25
+ v-if="filterEntry.options"
26
+ class="filters"
27
+ ref="filtersRef"
28
+ :entry="filterEntry"
29
+ @filterResults="filterUpdate"
30
+ @numberPerPage="numberPerPageUpdate"
31
+ @cascaderReady="cascaderReady"
32
+ ></SearchFilters>
33
+ <div class="content scrollbar" ref="content">
34
+ <div v-if="paginatedResults.length > 0" v-for="result in paginatedResults" :key="result.Acupoint" class="step-item">
35
+ <AcupointsCard
36
+ class="dataset-card"
37
+ :entry="result"
38
+ @mouseenter="hoverChanged(result)"
39
+ @mouseleave="hoverChanged(undefined)"
40
+ />
41
+ </div>
42
+ <div v-else class="error-feedback">
43
+ No results found - Please change your search / filter criteria.
44
+ </div>
45
+ <el-pagination
46
+ class="pagination"
47
+ v-model:current-page="page"
48
+ hide-on-single-page
49
+ large
50
+ layout="prev, pager, next"
51
+ :page-size="numberPerPage"
52
+ :total="numberOfHits"
53
+ @current-change="pageChange"
54
+ ></el-pagination>
55
+ </div>
56
+ </div>
57
+ </template>
58
+
59
+ <script>
60
+ /* eslint-disable no-alert, no-console */
61
+ import { markRaw } from 'vue';
62
+ import {
63
+ ElButton as Button,
64
+ ElCard as Card,
65
+ ElCol as Col,
66
+ ElRadioButton as RadioButton,
67
+ ElRadioGroup as RadioGroup,
68
+ ElDrawer as Drawer,
69
+ ElIcon as Icon,
70
+ ElInput as Input,
71
+ ElPagination as Pagination,
72
+ ElRow as Row,
73
+ } from 'element-plus'
74
+ import AcupointsCard from './AcupointsCard.vue'
75
+ import SearchFilters from "./SearchFilters.vue"
76
+
77
+ export default {
78
+ components: {
79
+ AcupointsCard,
80
+ Button,
81
+ Card,
82
+ Col,
83
+ RadioButton,
84
+ RadioGroup,
85
+ SearchFilters,
86
+ Drawer,
87
+ Icon,
88
+ Input,
89
+ Pagination,
90
+ Row
91
+ },
92
+ name: 'AcupointsInfoSearch',
93
+ props: {
94
+ entry: {
95
+ type: Object,
96
+ default: () => {},
97
+ },
98
+ },
99
+ created: function() {
100
+ if (this.entry) {
101
+ let entries = Object.values(this.entry)
102
+ const meridians = []
103
+ let others = false
104
+ entries.forEach((acupoint) => {
105
+ let meridian = acupoint.Meridian
106
+ if (!meridian) {
107
+ others = true
108
+ } else if (!(meridians.includes(meridian))) {
109
+ meridians.push(meridian)
110
+ }
111
+ });
112
+ meridians.sort();
113
+ if (others) {
114
+ meridians.push("Others")
115
+ }
116
+ if (meridians.length > 1) {
117
+ const filterOption = {
118
+ "key": "acupoints.meridian",
119
+ "label": "Meridian",
120
+ "children": [
121
+ ],
122
+ }
123
+ meridians.forEach(meridian => {
124
+ const entry = {
125
+ "key": `acupoints.meridian.${meridian}`,
126
+ "label": meridian,
127
+ "value": meridian,
128
+ }
129
+ filterOption.children.push(entry)
130
+ })
131
+ this.filterOptions.unshift(filterOption)
132
+ this.filters.unshift({
133
+ "facetPropPath": "acupoints.meridian",
134
+ "facet": "Show all",
135
+ "term": "Meridian"
136
+ })
137
+ }
138
+ }
139
+ },
140
+ computed: {
141
+ // This computed property populates filter data's entry object with $data from this sidebar
142
+ filterEntry: function () {
143
+ return {
144
+ numberOfHits: this.numberOfHits,
145
+ filterFacets: this.filters,
146
+ options: this.filterOptions,
147
+ showFilters: true,
148
+ };
149
+ },
150
+ },
151
+ data: function () {
152
+ return {
153
+ filters: [
154
+ {
155
+ "facetPropPath": "acupoints.WHO",
156
+ "facet": "Show all",
157
+ "term": "WHO",
158
+ },
159
+ {
160
+ "facetPropPath": "acupoints.visualized",
161
+ "facet": "Show all",
162
+ "term": "Visualized"
163
+ },
164
+ {
165
+ "facetPropPath": "acupoints.onMRI",
166
+ "facet": "Show all",
167
+ "term": "onMRI"
168
+ },
169
+ {
170
+ "facetPropPath": "acupoints.userDefined",
171
+ "facet": "Show all",
172
+ "term": "User defined"
173
+ }
174
+ ],
175
+ filterOptions: [
176
+ {
177
+ "key": "acupoints.visualized",
178
+ "label": "Visualized",
179
+ "children": [
180
+ {
181
+ "key": "acupoints.visualized.yes",
182
+ "label": "Visualized",
183
+ "value": "Visualized>Yes"
184
+ },
185
+ {
186
+ "key": "acupoints.visualized.no",
187
+ "label": "Non visualized",
188
+ "value": "Visualized>No"
189
+ },
190
+ ],
191
+ },
192
+ {
193
+ "key": "acupoints.onMRI",
194
+ "label": "Markers",
195
+ "children": [
196
+ {
197
+ "key": "acupoints.onMRI.yes",
198
+ "label": "Marked",
199
+ "value": "onMRI>Yes"
200
+ },
201
+ {
202
+ "key": "acupoints.onMRI.no",
203
+ "label": "Unmarked",
204
+ "value": "onMRI>No"
205
+ },
206
+ ],
207
+ },
208
+ {
209
+ "key": "acupoints.WHO",
210
+ "label": "WHO",
211
+ "children": [
212
+ {
213
+ "key": "acupoints.WHO.yes",
214
+ "label": "WHO",
215
+ "value": "WHO>Yes"
216
+ },
217
+ {
218
+ "key": "acupoints.WHO.no",
219
+ "label": "Non WHO",
220
+ "value": "WHO>No"
221
+ },
222
+ ],
223
+ },
224
+ {
225
+ "key": "acupoints.userDefined",
226
+ "label": "User Defined",
227
+ "children": [
228
+ {
229
+ "key": "acupoints.userDefined.yes",
230
+ "label": "User data",
231
+ "value": "userDefined>Yes"
232
+ },
233
+ {
234
+ "key": "acupoints.userDefined.no",
235
+ "label": "Official data",
236
+ "value": "userDefined>No"
237
+ },
238
+ ],
239
+ },
240
+ ],
241
+ currentFilters: markRaw({
242
+ curated: "Both",
243
+ mri: "Both",
244
+ who: "Both",
245
+ userDefined: "Both",
246
+ meridian: {
247
+ showAll: true,
248
+ list: []
249
+ },
250
+ }),
251
+ results: [],
252
+ paginatedResults: [],
253
+ searchInput: "",
254
+ lastSearch: "",
255
+ numberOfHits: 0,
256
+ numberPerPage: 10,
257
+ page: 1,
258
+ }
259
+ },
260
+ watch: {
261
+ entry: {
262
+ handler: function () {
263
+ this.filterUpdate(this.filters)
264
+ },
265
+ immediate: true,
266
+ deep: true,
267
+ },
268
+ },
269
+ methods: {
270
+ cascaderReady: function () {
271
+ this.cascaderIsReady = true;
272
+ this.search(this.searchInput);
273
+ },
274
+ filterUpdate: function (filters) {
275
+ this.filters = [...filters]
276
+ this.currentFilters['meridian']['list'] = []
277
+ this.filters.forEach((filter) => {
278
+ if (filter.facetPropPath === "acupoints.visualized") {
279
+ if (filter.facet === "Visualized") {
280
+ this.currentFilters['curated'] = 'Curated'
281
+ } else if (filter.facet === 'Non visualized') {
282
+ this.currentFilters['curated'] = 'Uncurated'
283
+ } else {
284
+ this.currentFilters['curated'] = 'Both'
285
+ }
286
+ }
287
+ if (filter.facetPropPath === "acupoints.onMRI") {
288
+ if (filter.facet === "Marked") {
289
+ this.currentFilters['mri'] = 'On'
290
+ } else if (filter.facet === 'Unmarked') {
291
+ this.currentFilters['mri'] = 'Off'
292
+ } else {
293
+ this.currentFilters['mri'] = 'Both'
294
+ }
295
+ }
296
+ if (filter.facetPropPath === "acupoints.WHO") {
297
+ if (filter.facet === "WHO") {
298
+ this.currentFilters['who'] = 'Yes'
299
+ } else if (filter.facet === 'Non who') {
300
+ this.currentFilters['who'] = 'No'
301
+ } else {
302
+ this.currentFilters['who'] = 'Both'
303
+ }
304
+ }
305
+ if (filter.facetPropPath === "acupoints.userDefined") {
306
+ if (filter.facet === "User data") {
307
+ this.currentFilters['userDefined'] = 'Yes'
308
+ } else if (filter.facet === 'Official data') {
309
+ this.currentFilters['userDefined'] = 'No'
310
+ } else {
311
+ this.currentFilters['userDefined'] = 'Both'
312
+ }
313
+ }
314
+ if (filter.facetPropPath === "acupoints.meridian") {
315
+ if (filter.facet === "Show all") {
316
+ this.currentFilters['meridian']['showAll'] = true
317
+ } else {
318
+ this.currentFilters['meridian']['showAll'] = false
319
+ this.currentFilters['meridian']['list'].push(filter.facet.toLowerCase())
320
+ }
321
+ }
322
+ });
323
+
324
+ this.search( this.searchInput)
325
+ },
326
+ numberPerPageUpdate: function (val) {
327
+ this.numberPerPage = val;
328
+ this.pageChange(1);
329
+ },
330
+ hoverChanged: function (data) {
331
+ this.$emit('hover-changed', data)
332
+ },
333
+ resetSearch: function () {
334
+ this.numberOfHits = 0
335
+ this.search(this.searchInput)
336
+ },
337
+ clearSearchClicked: function () {
338
+ this.searchInput = '';
339
+ this.search("");
340
+ },
341
+ getFilteredList: function() {
342
+ let filteredList = Object.values(this.entry)
343
+ if (this.currentFilters['curated'] !== "Both") {
344
+ const curated = this.currentFilters['curated'] === "Curated" ? true : false
345
+ filteredList = filteredList.filter(
346
+ item => (item.Curated ? true : false) === curated)
347
+ }
348
+ if (this.currentFilters['mri'] !== "Both") {
349
+ const mri = this.currentFilters['mri'] === "On" ? true : false
350
+ filteredList = filteredList.filter(item => (item.onMRI ? true : false) === mri)
351
+ }
352
+ if (this.currentFilters['who'] !== "Both") {
353
+ const who = this.currentFilters['who'] === "Yes" ? true : false
354
+ filteredList = filteredList.filter(
355
+ item => (item["Meridian Point"] ? true : false) === who)
356
+ }
357
+ if (this.currentFilters['userDefined'] !== "Both") {
358
+ const user = this.currentFilters['userDefined'] === "Yes" ? true : false
359
+ filteredList = filteredList.filter(
360
+ item => (item["userDefined"] ? true : false) === user)
361
+ }
362
+ if (!this.currentFilters['meridian']['showAll']) {
363
+ filteredList = filteredList.filter((item) => {
364
+ let meridian = "others"
365
+ if (item.Meridian) {
366
+ meridian = item.Meridian.toLowerCase()
367
+ }
368
+ return this.currentFilters['meridian']['list'].includes(meridian)
369
+ })
370
+ }
371
+ return filteredList;
372
+ },
373
+ search: function(input) {
374
+ this.results = []
375
+ let filteredList = this.getFilteredList()
376
+ if (input === "") {
377
+ this.results = filteredList
378
+ } else {
379
+ const lowerCase = input.toLowerCase()
380
+ for (const value of filteredList) {
381
+ const searchFields = [
382
+ value["Acupoint"],
383
+ value["Synonym"],
384
+ value["Chinese Name"],
385
+ value["English Name"],
386
+ value["Reference"],
387
+ value["Indications"],
388
+ value["Acupuncture Method"],
389
+ value["Vasculature"],
390
+ value["Innervation"],
391
+ value["Note"],
392
+ ];
393
+ const allstrings = searchFields.join();
394
+ const myJSON = allstrings.toLowerCase();
395
+ if (myJSON.includes(lowerCase)) {
396
+ this.results.push(value)
397
+ }
398
+ }
399
+ }
400
+ this.results.sort((a, b) => {
401
+ if (a["Meridian Point"] == b["Meridian Point"]) {
402
+ return a['Acupoint'].localeCompare(b['Acupoint'], undefined, { numeric: true })
403
+ } else if (a["Meridian Point"]) {
404
+ return -1
405
+ } else {
406
+ return 1
407
+ }
408
+ })
409
+
410
+ const start = this.numberPerPage * (this.page - 1)
411
+ this.paginatedResults = this.results.slice(start, start + this.numberPerPage)
412
+ this.numberOfHits = this.results.length
413
+ this.searchInput = input
414
+ this.lastSearch = input
415
+ this.$emit("acupoints-result", {
416
+ list: this.results
417
+ });
418
+ },
419
+ openSearch: function (filters, searchTerm = '') {
420
+ this.searchInput = searchTerm
421
+ this.filterUpdate(filters)
422
+ this.$refs.filtersRef.setCascader(this.filters)
423
+ },
424
+ numberPerPageUpdate: function (val) {
425
+ this.numberPerPage = val
426
+ this.pageChange(1)
427
+ },
428
+ pageChange: function (page) {
429
+ this.page = page
430
+ this.search( this.searchInput)
431
+ },
432
+ scrollToTop: function () {
433
+ if (this.$refs.content) {
434
+ this.$refs.content.scroll({ top: 0, behavior: 'smooth' })
435
+ }
436
+ },
437
+ resetPageNavigation: function () {
438
+ this.page = 1
439
+ },
440
+ },
441
+ }
442
+ </script>
443
+
444
+ <style lang="scss" scoped>
445
+
446
+ .acuRadioGroup {
447
+ padding-top: 8px;
448
+ }
449
+
450
+ .dataset-card {
451
+ position: relative;
452
+
453
+ &::before {
454
+ content: "";
455
+ display: block;
456
+ width: calc(100% - 15px);
457
+ height: 100%;
458
+ position: absolute;
459
+ top: 7px;
460
+ left: 7px;
461
+ border-style: solid;
462
+ border-radius: 5px;
463
+ border-color: transparent;
464
+ }
465
+
466
+ &:hover {
467
+ &::before {
468
+ border-color: var(--el-color-primary);
469
+ }
470
+ }
471
+ }
472
+
473
+ .main {
474
+ font-size: 14px;
475
+ text-align: left;
476
+ line-height: 1.5em;
477
+ font-family: Asap, sans-serif, Helvetica;
478
+ font-weight: 400;
479
+ /* outline: thin red solid; */
480
+ overflow-y: auto;
481
+ scrollbar-width: thin;
482
+ min-width: 16rem;
483
+ background-color: #f7faff;
484
+ height: 100%;
485
+ border-left: 1px solid var(--el-border-color);
486
+ border-top: 1px solid var(--el-border-color);
487
+ display: flex;
488
+ flex-direction: column;
489
+ gap: 1rem;
490
+ padding: 1rem;
491
+ }
492
+
493
+ .step-item {
494
+ font-size: 14px;
495
+ margin-bottom: 8px;
496
+ text-align: left;
497
+ }
498
+
499
+ .search-input {
500
+ width: 298px !important;
501
+ height: 40px;
502
+ padding-right: 14px;
503
+
504
+ :deep(.el-input__inner) {
505
+ font-family: inherit;
506
+ }
507
+ }
508
+
509
+ .header {
510
+ .el-button {
511
+ font-family: inherit;
512
+
513
+ &:hover,
514
+ &:focus {
515
+ background: $app-primary-color;
516
+ box-shadow: -3px 2px 4px #00000040;
517
+ color: #fff;
518
+ }
519
+ }
520
+ }
521
+
522
+ .pagination {
523
+ padding-bottom: 16px;
524
+ background-color: white;
525
+ padding-left: 95px;
526
+ font-weight: bold;
527
+ }
528
+
529
+ .pagination :deep(button) {
530
+ background-color: white !important;
531
+ }
532
+ .pagination :deep(li) {
533
+ background-color: white !important;
534
+ }
535
+ .pagination :deep(li.is-active) {
536
+ color: $app-primary-color;
537
+ }
538
+
539
+ .error-feedback {
540
+ font-family: Asap;
541
+ font-size: 14px;
542
+ font-style: italic;
543
+ padding-top: 15px;
544
+ }
545
+
546
+ .content-card :deep(.el-card__header) {
547
+ background-color: #292b66;
548
+ padding: 1rem;
549
+ }
550
+
551
+ .content-card :deep(.el-card__body) {
552
+ background-color: #f7faff;
553
+ overflow-y: hidden;
554
+ padding: 1rem;
555
+ }
556
+
557
+ .content {
558
+ // width: 515px;
559
+ flex: 1 1 auto;
560
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
561
+ border: solid 1px #e4e7ed;
562
+ background-color: #ffffff;
563
+ overflow-y: scroll;
564
+ scrollbar-width: thin;
565
+ border-radius: var(--el-border-radius-base);
566
+ }
567
+
568
+ .content :deep(.el-loading-spinner .path) {
569
+ stroke: $app-primary-color;
570
+ }
571
+
572
+ .content :deep(.step-item:first-child .seperator-path) {
573
+ display: none;
574
+ }
575
+
576
+ .content :deep(.step-item:not(:first-child) .seperator-path) {
577
+ width: 455px;
578
+ height: 0px;
579
+ border: solid 1px #e4e7ed;
580
+ background-color: #e4e7ed;
581
+ }
582
+
583
+ .filter-text {
584
+ top:4px;
585
+ position:relative;
586
+ }
587
+
588
+ .scrollbar::-webkit-scrollbar-track {
589
+ border-radius: 10px;
590
+ background-color: #f5f5f5;
591
+ }
592
+
593
+ .scrollbar::-webkit-scrollbar {
594
+ width: 12px;
595
+ right: -12px;
596
+ background-color: #f5f5f5;
597
+ }
598
+
599
+ .scrollbar::-webkit-scrollbar-thumb {
600
+ border-radius: 4px;
601
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.06);
602
+ background-color: #979797;
603
+ }
604
+
605
+ :deep(.el-input__suffix) {
606
+ padding-right: 0px;
607
+ }
608
+
609
+ :deep(.my-drawer) {
610
+ background: rgba(0, 0, 0, 0);
611
+ box-shadow: none;
612
+ }
613
+
614
+ .error-feedback {
615
+ font-family: Asap;
616
+ font-size: 14px;
617
+ font-style: italic;
618
+ padding-top: 15px;
619
+ }
620
+ </style>
@@ -105,10 +105,10 @@
105
105
  trigger="hover"
106
106
  popper-class="filter-help-popover"
107
107
  >
108
- <template #reference>
108
+ <template v-if="entry.helper" #reference>
109
109
  <MapSvgIcon icon="help" class="help" />
110
110
  </template>
111
- <div>
111
+ <div v-if="entry.helper">
112
112
  <strong>Within categories:</strong> OR
113
113
  <br />
114
114
  example: {{ entry.helper.within }}
@@ -362,7 +362,7 @@ export default {
362
362
  })
363
363
 
364
364
  // trigger reactivity only once
365
- Object.assign(this.options, processedOptions);
365
+ Object.assign(this.options, processedOptions)
366
366
  },
367
367
  populateCascader: function () {
368
368
  if (this.entry.options) {
@@ -542,6 +542,13 @@ export default {
542
542
  })
543
543
  return count
544
544
  }
545
+ const found = facet.children.find((item) => {
546
+ return item.label === "Show all"
547
+ })
548
+ if (found) {
549
+ return facet.children.length - 1
550
+ }
551
+
545
552
  return facet.children.length
546
553
  },
547
554
  /**