@abi-software/map-side-bar 1.3.1 → 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.
@@ -1,557 +1,557 @@
1
- <template>
2
- <div class="filters">
3
- <map-svg-sprite-color />
4
- <transition name="el-zoom-in-top">
5
- <span v-show="showFilters" class="search-filters transition-box">
6
- <custom-cascader
7
- class="cascader"
8
- ref="cascader"
9
- v-model="cascadeSelected"
10
- placeholder
11
- :collapse-tags="true"
12
- :options="options"
13
- :props="props"
14
- @change="cascadeEvent($event)"
15
- @expand-change="cascadeExpandChange"
16
- :show-all-levels="false"
17
- :append-to-body="false"
18
- @tags-changed="tagsChangedCallback"
19
- ></custom-cascader>
20
- <div v-if="showFiltersText" class="filter-default-value">
21
- Filters
22
- </div>
23
- <el-popover
24
- title="How do filters work?"
25
- width="250"
26
- trigger="hover"
27
- :append-to-body=false
28
- popper-class="popover"
29
- >
30
- <map-svg-icon slot="reference" icon="help" class="help"/>
31
- <div >
32
- <strong>Within categories:</strong> OR
33
- <br/>
34
- example: 'heart' OR 'colon'
35
- <br/>
36
- <br/>
37
- <strong>Between categories:</strong> AND
38
- <br/>
39
- example: 'rat' AND 'lung'
40
- </div>
41
- </el-popover>
42
-
43
- </span>
44
- </transition>
45
-
46
- <el-select
47
- class="number-shown-select"
48
- v-model="numberShown"
49
- placeholder="10"
50
- @change="numberShownChanged($event)"
51
- >
52
- <el-option
53
- v-for="item in numberDatasetsShown"
54
- :key="item"
55
- :label="item"
56
- :value="item"
57
- ></el-option>
58
- </el-select>
59
- <span class="dataset-results-feedback">{{ this.numberOfResultsText }}</span>
60
- </div>
61
- </template>
62
-
63
-
64
- <script>
65
- /* eslint-disable no-alert, no-console */
66
- import Vue from "vue";
67
- import { Option, Select, Popover } from "element-ui";
68
- import CustomCascader from "./Cascader";
69
- import lang from "element-ui/lib/locale/lang/en";
70
- import locale from "element-ui/lib/locale";
71
- import speciesMap from "./species-map";
72
- import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
73
-
74
- import {AlgoliaClient} from "../algolia/algolia.js";
75
- import { facetPropPathMapping } from "../algolia/utils.js";
76
-
77
- locale.use(lang);
78
- Vue.use(Option);
79
- Vue.use(Select);
80
- Vue.use(Popover)
81
-
82
- const capitalise = function (txt) {
83
- return txt.charAt(0).toUpperCase() + txt.slice(1);
84
- };
85
-
86
- const convertReadableLabel = function (original) {
87
- const name = original.toLowerCase();
88
- if (speciesMap[name]) {
89
- return capitalise(speciesMap[name]);
90
- } else {
91
- return capitalise(name);
92
- }
93
- };
94
-
95
- export default {
96
- name: "SearchFilters",
97
- components: {
98
- CustomCascader,
99
- MapSvgIcon,
100
- MapSvgSpriteColor,
101
- },
102
- props: {
103
- /**
104
- * Object containing information for
105
- * the required viewing.
106
- */
107
- entry: Object,
108
- envVars: {
109
- type: Object,
110
- default: ()=>{}
111
- },
112
- },
113
- data: function () {
114
- return {
115
- cascaderIsReady: false,
116
- previousShowAllChecked: {
117
- species: false,
118
- gender: false,
119
- organ: false,
120
- datasets: false,
121
- },
122
- showFilters: true,
123
- showFiltersText: true,
124
- cascadeSelected: [],
125
- numberShown: 10,
126
- filters: [],
127
- facets: ["Species", "Gender", "Organ", "Datasets"],
128
- numberDatasetsShown: ["10", "20", "50"],
129
- props: { multiple: true },
130
- options: [
131
- {
132
- value: "Species",
133
- label: "Species",
134
- children: [{}],
135
- },
136
- ],
137
- };
138
- },
139
- computed: {
140
- numberOfResultsText: function () {
141
- return `${this.entry.numberOfHits} results | Showing`;
142
- },
143
- },
144
- methods: {
145
- createCascaderItemValue: function (term, facet) {
146
- if (facet) return term + "/" + facet;
147
- else return term;
148
- },
149
- populateCascader: function () {
150
- return new Promise((resolve) => {
151
- // Algolia facet serach
152
- this.algoliaClient.getAlgoliaFacets(facetPropPathMapping)
153
- .then((data) => {
154
- this.facets = data;
155
- this.options = data;
156
-
157
- // create top level of options in cascader
158
- this.options.forEach((facet, i) => {
159
- this.options[i].label = convertReadableLabel(facet.label);
160
- this.options[i].value = this.createCascaderItemValue(
161
- facet.key,
162
- undefined
163
- );
164
-
165
- // put "Show all" as first option
166
- this.options[i].children.unshift({
167
- value: this.createCascaderItemValue("Show all"),
168
- label: "Show all",
169
- });
170
-
171
- // populate second level of options
172
- this.options[i].children.forEach((facetItem, j) => {
173
- this.options[i].children[j].label = convertReadableLabel(
174
- facetItem.label
175
- );
176
- this.options[i].children[j].value =
177
- this.createCascaderItemValue(facet.label, facetItem.label);
178
- });
179
- });
180
- this.createDataTypeFacet()
181
- })
182
- .finally(() => {
183
- resolve();
184
- });
185
- });
186
- },
187
- tagsChangedCallback: function (presentTags) {
188
- if (presentTags.length > 0) {
189
- this.showFiltersText = false;
190
- } else {
191
- this.showFiltersText = true;
192
- }
193
- },
194
- // cascadeEvent: initiate searches based off cascader changes
195
- cascadeEvent: function (event) {
196
- if (event) {
197
- // Check for show all in selected cascade options
198
- event = this.showAllEventModifier(event);
199
-
200
- // Create results for the filter update
201
- let filterKeys = event.filter( selection => selection !== undefined).map( fs => ({
202
- facetPropPath: fs[0],
203
- facet: fs[1].split("/")[1],
204
- term: fs[1].split("/")[0],
205
- }))
206
-
207
- // Move results from arrays to object for use on scicrunch (note that we remove 'duplicate' as that is only needed for filter keys)
208
- let filters = event.filter( selection => selection !== undefined).map( fs => {
209
- let propPath = fs[0].includes('duplicate') ? fs[0].split('duplicate')[0] : fs[0]
210
- return {
211
- facetPropPath: propPath,
212
- facet: fs[1].split("/")[1],
213
- term: fs[1].split("/")[0],
214
- }
215
- })
216
-
217
-
218
- this.$emit('loading', true) // let sidebarcontent wait for the requests
219
-
220
- this.$emit("filterResults", filters); // emit filters for apps above sidebar
221
- this.setCascader(filterKeys); //update our cascader v-model if we modified the event
222
- this.makeCascadeLabelsClickable();
223
- }
224
- },
225
- // showAllEventModifier: Modifies a cascade event to unlick all selections in category if "show all" is clicked. Also unchecks "Show all" if any secection is clicked
226
- // *NOTE* Does NOT remove 'Show all' selections from showing in 'cascadeSelected'
227
- showAllEventModifier: function (event) {
228
- // check if show all is in the cascader checked option list
229
- let hasShowAll = event
230
- .map((ev) => (ev ? ev[1].toLowerCase().includes("show all") : false))
231
- .includes(true);
232
- // remove all selected options below the show all if checked
233
- if (hasShowAll) {
234
- let modifiedEvent = [];
235
- let facetMaps = {};
236
- //catagorised different facet items
237
- for (const i in event) {
238
- if (facetMaps[event[i][0]] === undefined) facetMaps[event[i][0]] = [];
239
- facetMaps[event[i][0]].push(event[i]);
240
- }
241
- // go through each facets
242
- for (const facet in facetMaps) {
243
- let showAll = undefined;
244
- // Find the show all item if any
245
- for (let i = facetMaps[facet].length - 1; i >= 0; i--) {
246
- if (facetMaps[facet][i][1].toLowerCase().includes("show all")) {
247
- //seperate the showAll item and the rest
248
- showAll = facetMaps[facet].splice(i, 1)[0];
249
- break;
250
- }
251
- }
252
- if (showAll) {
253
- if (this.previousShowAllChecked[facet]) {
254
- //Unset the show all if it was present previously
255
- //and there are other items
256
- if (facetMaps[facet].length > 0)
257
- modifiedEvent.push(...facetMaps[facet]);
258
- else modifiedEvent.push(showAll);
259
- } else {
260
- //showAll is turned on
261
- modifiedEvent.push(showAll);
262
- }
263
- } else {
264
- modifiedEvent.push(...facetMaps[facet]);
265
- }
266
- }
267
- //Make sure the expanded item are sorted first.
268
- return modifiedEvent.sort((a, b) => {
269
- if (this.__expandItem__) {
270
- if (a[0] == this.__expandItem__) {
271
- if (b[0] == this.__expandItem__) {
272
- return 0;
273
- } else {
274
- return -1;
275
- }
276
- } else if (b[0] == this.__expandItem__) {
277
- if (a[0] == this.__expandItem__) {
278
- return 0;
279
- } else {
280
- return 1;
281
- }
282
- } else {
283
- return 0;
284
- }
285
- } else return 0;
286
- });
287
- }
288
- return event;
289
- },
290
- createDataTypeFacet: function(){
291
- let dataFacet = {...this.facets[2]} // copy the 'Experiemental approach' facet
292
- let count = this.facets.at(-1).id // get the last id count
293
-
294
- // Step through the children that are valid data types, switch thier values
295
- let newChildren = dataFacet.children.filter( el=> {
296
- if (el.label === 'Scaffold' || el.label === 'Simulation' || el.label === 'Show all'){
297
- el.key = el.label
298
- el.id = count
299
- el.value = el.value.replace('Experimental approach', 'Data type')
300
- count++
301
- return el
302
- }
303
- })
304
- dataFacet.id = count
305
- dataFacet.key = 'Data type'
306
- // Add 'duplicate' so that the key is unique. This is removed in the cascade event for filtering
307
- dataFacet.value += 'duplicate'
308
- dataFacet.children = newChildren
309
- dataFacet.label = 'Data type'
310
- this.facets.push(dataFacet)
311
- },
312
- cascadeExpandChange: function (event) {
313
- //work around as the expand item may change on modifying the cascade props
314
- this.__expandItem__ = event;
315
- this.makeCascadeLabelsClickable();
316
- },
317
- numberShownChanged: function (event) {
318
- this.$emit("numberPerPage", parseInt(event));
319
- },
320
- updatePreviousShowAllChecked: function (options) {
321
- //Reset the states
322
- for (const facet in this.previousShowAllChecked) {
323
- this.previousShowAllChecked[facet] = false;
324
- }
325
- options.forEach((element) => {
326
- if (element[1].toLowerCase().includes("show all"))
327
- this.previousShowAllChecked[element[0]] = true;
328
- });
329
- },
330
- // setCascader: Clears previous selections and takes in an array of facets to select: filterFacets
331
- // facets are in the form:
332
- // {
333
- // facetPropPath: 'anatomy.organ.name',
334
- // term: 'Sex',
335
- // facet: 'Male'
336
- // }
337
- setCascader: function (filterFacets) {
338
- //Do not set the value unless it is ready
339
- if (this.cascaderIsReady && filterFacets && filterFacets.length != 0) {
340
- this.cascadeSelected = filterFacets.map(e => {
341
- return [
342
- e.facetPropPath,
343
- this.createCascaderItemValue(capitalise(e.term), e.facet),
344
- ]
345
- });
346
- this.updatePreviousShowAllChecked(this.cascadeSelected);
347
- }
348
- },
349
- addFilter: function (filter) {
350
- //Do not set the value unless it is ready
351
- if (this.cascaderIsReady && filter) {
352
- this.cascadeSelected.filter(f=>f.term != filter.term)
353
- this.cascadeSelected.push([filter.facetPropPath, this.createCascaderItemValue(filter.term, filter.facet)])
354
- }
355
- },
356
- initiateSearch: function() {
357
- this.cascadeEvent(this.cascadeSelected)
358
- },
359
- // checkShowAllBoxes: Checks each 'Show all' cascade option by using the setCascader function
360
- checkShowAllBoxes: function(){
361
- this.setCascader(
362
- this.options.map(option => {
363
- return {
364
- facetPropPath: option.value,
365
- term: option.label,
366
- facet: 'Show all'
367
- }
368
- })
369
- )
370
- },
371
- makeCascadeLabelsClickable: function () {
372
- // Next tick allows the cascader menu to change
373
- this.$nextTick(() => {
374
- this.$refs.cascader.$el
375
- .querySelectorAll(".el-cascader-node__label")
376
- .forEach((el) => {
377
- // step through each cascade label
378
- el.onclick = function () {
379
- const checkbox = this.previousElementSibling;
380
- if (checkbox) {
381
- if (!checkbox.parentElement.attributes["aria-owns"]) {
382
- // check if we are at the lowest level of cascader
383
- this.previousElementSibling.click(); // Click the checkbox
384
- }
385
- }
386
- };
387
- });
388
- });
389
- },
390
- },
391
- mounted: function () {
392
- this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
393
- this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
394
- this.populateCascader().then(() => {
395
- this.cascaderIsReady = true;
396
- this.checkShowAllBoxes()
397
- this.setCascader(this.entry.filterFacets);
398
- this.makeCascadeLabelsClickable();
399
- });
400
- },
401
- };
402
- </script>
403
-
404
- <!-- Add "scoped" attribute to limit CSS to this component only -->
405
- <style scoped>
406
- .filter-default-value {
407
- pointer-events: none;
408
- position: absolute;
409
- top: 0;
410
- left: 0;
411
- padding-top: 10px;
412
- padding-left: 16px;
413
- }
414
-
415
- .help {
416
- width: 24px !important;
417
- height: 24px;
418
- transform: scale(1.1);
419
- color: #8300bf;
420
- cursor: pointer;
421
- }
422
-
423
- .popover {
424
- color: rgb(48, 49, 51);
425
- font-family: Asap;
426
- margin: 12px;
427
- }
428
-
429
- .filter-icon-inside {
430
- width: 12px !important;
431
- height: 12px !important;
432
- color: #292b66;
433
- transform: scale(2) !important;
434
- margin-bottom: 0px !important;
435
- }
436
-
437
- .cascader {
438
- font-family: Asap;
439
- font-size: 14px;
440
- font-weight: 500;
441
- font-stretch: normal;
442
- font-style: normal;
443
- line-height: normal;
444
- letter-spacing: normal;
445
- color: #292b66;
446
- text-align: center;
447
- padding-bottom: 6px;
448
- }
449
-
450
- .cascader >>> .el-cascder-panel {
451
- max-height: 500px;
452
- }
453
-
454
- .cascader >>> .el-scrollbar__wrap {
455
- overflow-x: hidden;
456
- margin-bottom: 2px !important;
457
- }
458
-
459
- .cascader >>> li[aria-owns*="cascader"] > .el-checkbox {
460
- display: none;
461
- }
462
-
463
- .dataset-results-feedback {
464
- float: right;
465
- text-align: right;
466
- color: rgb(48, 49, 51);
467
- font-family: Asap;
468
- font-size: 18px;
469
- font-weight: 500;
470
- padding-top: 8px;
471
- }
472
-
473
- .search-filters {
474
- position: relative;
475
- float: left;
476
- padding-right: 15px;
477
- padding-bottom: 12px;
478
- }
479
-
480
- .number-shown-select {
481
- float: right;
482
- }
483
-
484
- .number-shown-select >>> .el-input__inner {
485
- width: 68px;
486
- height: 40px;
487
- color: rgb(48, 49, 51);
488
- }
489
-
490
- .search-filters >>> .el-cascader-node.is-active {
491
- color: #8300bf;
492
- }
493
-
494
- .search-filters >>> .el-cascader-node.in-active-path {
495
- color: #8300bf;
496
- }
497
-
498
- .search-filters >>> .el-checkbox__input.is-checked > .el-checkbox__inner {
499
- background-color: #8300bf;
500
- border-color: #8300bf;
501
- }
502
-
503
- .cascader >>> .el-cascader-menu:nth-child(2) .el-cascader-node:first-child {
504
- border-bottom: 1px solid #e4e7ed;
505
- }
506
-
507
- .cascader >>> .el-cascader-node__label {
508
- text-align: left;
509
- }
510
-
511
- .filters >>> .el-popover {
512
- background: #f3ecf6 !important;
513
- border: 1px solid #8300BF;
514
- border-radius: 4px;
515
- color: #303133 !important;
516
- font-size: 12px;
517
- line-height: 18px;
518
-
519
-
520
- }
521
-
522
- .filters >>> .el-popover[x-placement^="top"] .popper__arrow {
523
- border-top-color: #8300BF;
524
- border-bottom-width: 0;
525
- }
526
- .filters >>> .el-popover[x-placement^="top"] .popper__arrow::after {
527
- border-top-color: #f3ecf6;
528
- border-bottom-width: 0;
529
- }
530
-
531
- .filters >>> .el-popover[x-placement^="bottom"] .popper__arrow {
532
- border-top-width: 0;
533
- border-bottom-color: #8300BF;
534
- }
535
- .filters >>> .el-popover[x-placement^="bottom"] .popper__arrow::after {
536
- border-top-width: 0;
537
- border-bottom-color: #f3ecf6;
538
- }
539
-
540
- .filters >>> .el-popover[x-placement^="right"] .popper__arrow {
541
- border-right-color: #8300BF;
542
- border-left-width: 0;
543
- }
544
- .filters >>> .el-popover[x-placement^="right"] .popper__arrow::after {
545
- border-right-color: #f3ecf6;
546
- border-left-width: 0;
547
- }
548
-
549
- .filters >>> .el-popover[x-placement^="left"] .popper__arrow {
550
- border-right-width: 0;
551
- border-left-color: #8300BF;
552
- }
553
- .filters >>> .el-popover[x-placement^="left"] .popper__arrow::after {
554
- border-right-width: 0;
555
- border-left-color: #f3ecf6;
556
- }
557
- </style>
1
+ <template>
2
+ <div class="filters">
3
+ <map-svg-sprite-color />
4
+ <transition name="el-zoom-in-top">
5
+ <span v-show="showFilters" class="search-filters transition-box">
6
+ <custom-cascader
7
+ class="cascader"
8
+ ref="cascader"
9
+ v-model="cascadeSelected"
10
+ placeholder
11
+ :collapse-tags="true"
12
+ :options="options"
13
+ :props="props"
14
+ @change="cascadeEvent($event)"
15
+ @expand-change="cascadeExpandChange"
16
+ :show-all-levels="false"
17
+ :append-to-body="false"
18
+ @tags-changed="tagsChangedCallback"
19
+ ></custom-cascader>
20
+ <div v-if="showFiltersText" class="filter-default-value">
21
+ Filters
22
+ </div>
23
+ <el-popover
24
+ title="How do filters work?"
25
+ width="250"
26
+ trigger="hover"
27
+ :append-to-body=false
28
+ popper-class="popover"
29
+ >
30
+ <map-svg-icon slot="reference" icon="help" class="help"/>
31
+ <div >
32
+ <strong>Within categories:</strong> OR
33
+ <br/>
34
+ example: 'heart' OR 'colon'
35
+ <br/>
36
+ <br/>
37
+ <strong>Between categories:</strong> AND
38
+ <br/>
39
+ example: 'rat' AND 'lung'
40
+ </div>
41
+ </el-popover>
42
+
43
+ </span>
44
+ </transition>
45
+
46
+ <el-select
47
+ class="number-shown-select"
48
+ v-model="numberShown"
49
+ placeholder="10"
50
+ @change="numberShownChanged($event)"
51
+ >
52
+ <el-option
53
+ v-for="item in numberDatasetsShown"
54
+ :key="item"
55
+ :label="item"
56
+ :value="item"
57
+ ></el-option>
58
+ </el-select>
59
+ <span class="dataset-results-feedback">{{ this.numberOfResultsText }}</span>
60
+ </div>
61
+ </template>
62
+
63
+
64
+ <script>
65
+ /* eslint-disable no-alert, no-console */
66
+ import Vue from "vue";
67
+ import { Option, Select, Popover } from "element-ui";
68
+ import CustomCascader from "./Cascader";
69
+ import lang from "element-ui/lib/locale/lang/en";
70
+ import locale from "element-ui/lib/locale";
71
+ import speciesMap from "./species-map";
72
+ import { MapSvgIcon, MapSvgSpriteColor } from "@abi-software/svg-sprite";
73
+
74
+ import {AlgoliaClient} from "../algolia/algolia.js";
75
+ import { facetPropPathMapping } from "../algolia/utils.js";
76
+
77
+ locale.use(lang);
78
+ Vue.use(Option);
79
+ Vue.use(Select);
80
+ Vue.use(Popover)
81
+
82
+ const capitalise = function (txt) {
83
+ return txt.charAt(0).toUpperCase() + txt.slice(1);
84
+ };
85
+
86
+ const convertReadableLabel = function (original) {
87
+ const name = original.toLowerCase();
88
+ if (speciesMap[name]) {
89
+ return capitalise(speciesMap[name]);
90
+ } else {
91
+ return capitalise(name);
92
+ }
93
+ };
94
+
95
+ export default {
96
+ name: "SearchFilters",
97
+ components: {
98
+ CustomCascader,
99
+ MapSvgIcon,
100
+ MapSvgSpriteColor,
101
+ },
102
+ props: {
103
+ /**
104
+ * Object containing information for
105
+ * the required viewing.
106
+ */
107
+ entry: Object,
108
+ envVars: {
109
+ type: Object,
110
+ default: ()=>{}
111
+ },
112
+ },
113
+ data: function () {
114
+ return {
115
+ cascaderIsReady: false,
116
+ previousShowAllChecked: {
117
+ species: false,
118
+ gender: false,
119
+ organ: false,
120
+ datasets: false,
121
+ },
122
+ showFilters: true,
123
+ showFiltersText: true,
124
+ cascadeSelected: [],
125
+ numberShown: 10,
126
+ filters: [],
127
+ facets: ["Species", "Gender", "Organ", "Datasets"],
128
+ numberDatasetsShown: ["10", "20", "50"],
129
+ props: { multiple: true },
130
+ options: [
131
+ {
132
+ value: "Species",
133
+ label: "Species",
134
+ children: [{}],
135
+ },
136
+ ],
137
+ };
138
+ },
139
+ computed: {
140
+ numberOfResultsText: function () {
141
+ return `${this.entry.numberOfHits} results | Showing`;
142
+ },
143
+ },
144
+ methods: {
145
+ createCascaderItemValue: function (term, facet) {
146
+ if (facet) return term + "/" + facet;
147
+ else return term;
148
+ },
149
+ populateCascader: function () {
150
+ return new Promise((resolve) => {
151
+ // Algolia facet serach
152
+ this.algoliaClient.getAlgoliaFacets(facetPropPathMapping)
153
+ .then((data) => {
154
+ this.facets = data;
155
+ this.options = data;
156
+
157
+ // create top level of options in cascader
158
+ this.options.forEach((facet, i) => {
159
+ this.options[i].label = convertReadableLabel(facet.label);
160
+ this.options[i].value = this.createCascaderItemValue(
161
+ facet.key,
162
+ undefined
163
+ );
164
+
165
+ // put "Show all" as first option
166
+ this.options[i].children.unshift({
167
+ value: this.createCascaderItemValue("Show all"),
168
+ label: "Show all",
169
+ });
170
+
171
+ // populate second level of options
172
+ this.options[i].children.forEach((facetItem, j) => {
173
+ this.options[i].children[j].label = convertReadableLabel(
174
+ facetItem.label
175
+ );
176
+ this.options[i].children[j].value =
177
+ this.createCascaderItemValue(facet.label, facetItem.label);
178
+ });
179
+ });
180
+ this.createDataTypeFacet()
181
+ })
182
+ .finally(() => {
183
+ resolve();
184
+ });
185
+ });
186
+ },
187
+ tagsChangedCallback: function (presentTags) {
188
+ if (presentTags.length > 0) {
189
+ this.showFiltersText = false;
190
+ } else {
191
+ this.showFiltersText = true;
192
+ }
193
+ },
194
+ // cascadeEvent: initiate searches based off cascader changes
195
+ cascadeEvent: function (event) {
196
+ if (event) {
197
+ // Check for show all in selected cascade options
198
+ event = this.showAllEventModifier(event);
199
+
200
+ // Create results for the filter update
201
+ let filterKeys = event.filter( selection => selection !== undefined).map( fs => ({
202
+ facetPropPath: fs[0],
203
+ facet: fs[1].split("/")[1],
204
+ term: fs[1].split("/")[0],
205
+ }))
206
+
207
+ // Move results from arrays to object for use on scicrunch (note that we remove 'duplicate' as that is only needed for filter keys)
208
+ let filters = event.filter( selection => selection !== undefined).map( fs => {
209
+ let propPath = fs[0].includes('duplicate') ? fs[0].split('duplicate')[0] : fs[0]
210
+ return {
211
+ facetPropPath: propPath,
212
+ facet: fs[1].split("/")[1],
213
+ term: fs[1].split("/")[0],
214
+ }
215
+ })
216
+
217
+
218
+ this.$emit('loading', true) // let sidebarcontent wait for the requests
219
+
220
+ this.$emit("filterResults", filters); // emit filters for apps above sidebar
221
+ this.setCascader(filterKeys); //update our cascader v-model if we modified the event
222
+ this.makeCascadeLabelsClickable();
223
+ }
224
+ },
225
+ // showAllEventModifier: Modifies a cascade event to unlick all selections in category if "show all" is clicked. Also unchecks "Show all" if any secection is clicked
226
+ // *NOTE* Does NOT remove 'Show all' selections from showing in 'cascadeSelected'
227
+ showAllEventModifier: function (event) {
228
+ // check if show all is in the cascader checked option list
229
+ let hasShowAll = event
230
+ .map((ev) => (ev ? ev[1].toLowerCase().includes("show all") : false))
231
+ .includes(true);
232
+ // remove all selected options below the show all if checked
233
+ if (hasShowAll) {
234
+ let modifiedEvent = [];
235
+ let facetMaps = {};
236
+ //catagorised different facet items
237
+ for (const i in event) {
238
+ if (facetMaps[event[i][0]] === undefined) facetMaps[event[i][0]] = [];
239
+ facetMaps[event[i][0]].push(event[i]);
240
+ }
241
+ // go through each facets
242
+ for (const facet in facetMaps) {
243
+ let showAll = undefined;
244
+ // Find the show all item if any
245
+ for (let i = facetMaps[facet].length - 1; i >= 0; i--) {
246
+ if (facetMaps[facet][i][1].toLowerCase().includes("show all")) {
247
+ //seperate the showAll item and the rest
248
+ showAll = facetMaps[facet].splice(i, 1)[0];
249
+ break;
250
+ }
251
+ }
252
+ if (showAll) {
253
+ if (this.previousShowAllChecked[facet]) {
254
+ //Unset the show all if it was present previously
255
+ //and there are other items
256
+ if (facetMaps[facet].length > 0)
257
+ modifiedEvent.push(...facetMaps[facet]);
258
+ else modifiedEvent.push(showAll);
259
+ } else {
260
+ //showAll is turned on
261
+ modifiedEvent.push(showAll);
262
+ }
263
+ } else {
264
+ modifiedEvent.push(...facetMaps[facet]);
265
+ }
266
+ }
267
+ //Make sure the expanded item are sorted first.
268
+ return modifiedEvent.sort((a, b) => {
269
+ if (this.__expandItem__) {
270
+ if (a[0] == this.__expandItem__) {
271
+ if (b[0] == this.__expandItem__) {
272
+ return 0;
273
+ } else {
274
+ return -1;
275
+ }
276
+ } else if (b[0] == this.__expandItem__) {
277
+ if (a[0] == this.__expandItem__) {
278
+ return 0;
279
+ } else {
280
+ return 1;
281
+ }
282
+ } else {
283
+ return 0;
284
+ }
285
+ } else return 0;
286
+ });
287
+ }
288
+ return event;
289
+ },
290
+ createDataTypeFacet: function(){
291
+ let dataFacet = {...this.facets[2]} // copy the 'Experiemental approach' facet
292
+ let count = this.facets.at(-1).id // get the last id count
293
+
294
+ // Step through the children that are valid data types, switch thier values
295
+ let newChildren = dataFacet.children.filter( el=> {
296
+ if (el.label === 'Scaffold' || el.label === 'Simulation' || el.label === 'Show all'){
297
+ el.key = el.label
298
+ el.id = count
299
+ el.value = el.value.replace('Experimental approach', 'Data type')
300
+ count++
301
+ return el
302
+ }
303
+ })
304
+ dataFacet.id = count
305
+ dataFacet.key = 'Data type'
306
+ // Add 'duplicate' so that the key is unique. This is removed in the cascade event for filtering
307
+ dataFacet.value += 'duplicate'
308
+ dataFacet.children = newChildren
309
+ dataFacet.label = 'Data type'
310
+ this.facets.push(dataFacet)
311
+ },
312
+ cascadeExpandChange: function (event) {
313
+ //work around as the expand item may change on modifying the cascade props
314
+ this.__expandItem__ = event;
315
+ this.makeCascadeLabelsClickable();
316
+ },
317
+ numberShownChanged: function (event) {
318
+ this.$emit("numberPerPage", parseInt(event));
319
+ },
320
+ updatePreviousShowAllChecked: function (options) {
321
+ //Reset the states
322
+ for (const facet in this.previousShowAllChecked) {
323
+ this.previousShowAllChecked[facet] = false;
324
+ }
325
+ options.forEach((element) => {
326
+ if (element[1].toLowerCase().includes("show all"))
327
+ this.previousShowAllChecked[element[0]] = true;
328
+ });
329
+ },
330
+ // setCascader: Clears previous selections and takes in an array of facets to select: filterFacets
331
+ // facets are in the form:
332
+ // {
333
+ // facetPropPath: 'anatomy.organ.name',
334
+ // term: 'Sex',
335
+ // facet: 'Male'
336
+ // }
337
+ setCascader: function (filterFacets) {
338
+ //Do not set the value unless it is ready
339
+ if (this.cascaderIsReady && filterFacets && filterFacets.length != 0) {
340
+ this.cascadeSelected = filterFacets.map(e => {
341
+ return [
342
+ e.facetPropPath,
343
+ this.createCascaderItemValue(capitalise(e.term), e.facet),
344
+ ]
345
+ });
346
+ this.updatePreviousShowAllChecked(this.cascadeSelected);
347
+ }
348
+ },
349
+ addFilter: function (filter) {
350
+ //Do not set the value unless it is ready
351
+ if (this.cascaderIsReady && filter) {
352
+ this.cascadeSelected.filter(f=>f.term != filter.term)
353
+ this.cascadeSelected.push([filter.facetPropPath, this.createCascaderItemValue(filter.term, filter.facet)])
354
+ }
355
+ },
356
+ initiateSearch: function() {
357
+ this.cascadeEvent(this.cascadeSelected)
358
+ },
359
+ // checkShowAllBoxes: Checks each 'Show all' cascade option by using the setCascader function
360
+ checkShowAllBoxes: function(){
361
+ this.setCascader(
362
+ this.options.map(option => {
363
+ return {
364
+ facetPropPath: option.value,
365
+ term: option.label,
366
+ facet: 'Show all'
367
+ }
368
+ })
369
+ )
370
+ },
371
+ makeCascadeLabelsClickable: function () {
372
+ // Next tick allows the cascader menu to change
373
+ this.$nextTick(() => {
374
+ this.$refs.cascader.$el
375
+ .querySelectorAll(".el-cascader-node__label")
376
+ .forEach((el) => {
377
+ // step through each cascade label
378
+ el.onclick = function () {
379
+ const checkbox = this.previousElementSibling;
380
+ if (checkbox) {
381
+ if (!checkbox.parentElement.attributes["aria-owns"]) {
382
+ // check if we are at the lowest level of cascader
383
+ this.previousElementSibling.click(); // Click the checkbox
384
+ }
385
+ }
386
+ };
387
+ });
388
+ });
389
+ },
390
+ },
391
+ mounted: function () {
392
+ this.algoliaClient = new AlgoliaClient(this.envVars.ALGOLIA_ID, this.envVars.ALGOLIA_KEY, this.envVars.PENNSIEVE_API_LOCATION);
393
+ this.algoliaClient.initIndex(this.envVars.ALGOLIA_INDEX);
394
+ this.populateCascader().then(() => {
395
+ this.cascaderIsReady = true;
396
+ this.checkShowAllBoxes()
397
+ this.setCascader(this.entry.filterFacets);
398
+ this.makeCascadeLabelsClickable();
399
+ });
400
+ },
401
+ };
402
+ </script>
403
+
404
+ <!-- Add "scoped" attribute to limit CSS to this component only -->
405
+ <style scoped>
406
+ .filter-default-value {
407
+ pointer-events: none;
408
+ position: absolute;
409
+ top: 0;
410
+ left: 0;
411
+ padding-top: 10px;
412
+ padding-left: 16px;
413
+ }
414
+
415
+ .help {
416
+ width: 24px !important;
417
+ height: 24px;
418
+ transform: scale(1.1);
419
+ color: #8300bf;
420
+ cursor: pointer;
421
+ }
422
+
423
+ .popover {
424
+ color: rgb(48, 49, 51);
425
+ font-family: Asap;
426
+ margin: 12px;
427
+ }
428
+
429
+ .filter-icon-inside {
430
+ width: 12px !important;
431
+ height: 12px !important;
432
+ color: #292b66;
433
+ transform: scale(2) !important;
434
+ margin-bottom: 0px !important;
435
+ }
436
+
437
+ .cascader {
438
+ font-family: Asap;
439
+ font-size: 14px;
440
+ font-weight: 500;
441
+ font-stretch: normal;
442
+ font-style: normal;
443
+ line-height: normal;
444
+ letter-spacing: normal;
445
+ color: #292b66;
446
+ text-align: center;
447
+ padding-bottom: 6px;
448
+ }
449
+
450
+ .cascader >>> .el-cascder-panel {
451
+ max-height: 500px;
452
+ }
453
+
454
+ .cascader >>> .el-scrollbar__wrap {
455
+ overflow-x: hidden;
456
+ margin-bottom: 2px !important;
457
+ }
458
+
459
+ .cascader >>> li[aria-owns*="cascader"] > .el-checkbox {
460
+ display: none;
461
+ }
462
+
463
+ .dataset-results-feedback {
464
+ float: right;
465
+ text-align: right;
466
+ color: rgb(48, 49, 51);
467
+ font-family: Asap;
468
+ font-size: 18px;
469
+ font-weight: 500;
470
+ padding-top: 8px;
471
+ }
472
+
473
+ .search-filters {
474
+ position: relative;
475
+ float: left;
476
+ padding-right: 15px;
477
+ padding-bottom: 12px;
478
+ }
479
+
480
+ .number-shown-select {
481
+ float: right;
482
+ }
483
+
484
+ .number-shown-select >>> .el-input__inner {
485
+ width: 68px;
486
+ height: 40px;
487
+ color: rgb(48, 49, 51);
488
+ }
489
+
490
+ .search-filters >>> .el-cascader-node.is-active {
491
+ color: #8300bf;
492
+ }
493
+
494
+ .search-filters >>> .el-cascader-node.in-active-path {
495
+ color: #8300bf;
496
+ }
497
+
498
+ .search-filters >>> .el-checkbox__input.is-checked > .el-checkbox__inner {
499
+ background-color: #8300bf;
500
+ border-color: #8300bf;
501
+ }
502
+
503
+ .cascader >>> .el-cascader-menu:nth-child(2) .el-cascader-node:first-child {
504
+ border-bottom: 1px solid #e4e7ed;
505
+ }
506
+
507
+ .cascader >>> .el-cascader-node__label {
508
+ text-align: left;
509
+ }
510
+
511
+ .filters >>> .el-popover {
512
+ background: #f3ecf6 !important;
513
+ border: 1px solid #8300BF;
514
+ border-radius: 4px;
515
+ color: #303133 !important;
516
+ font-size: 12px;
517
+ line-height: 18px;
518
+
519
+
520
+ }
521
+
522
+ .filters >>> .el-popover[x-placement^="top"] .popper__arrow {
523
+ border-top-color: #8300BF;
524
+ border-bottom-width: 0;
525
+ }
526
+ .filters >>> .el-popover[x-placement^="top"] .popper__arrow::after {
527
+ border-top-color: #f3ecf6;
528
+ border-bottom-width: 0;
529
+ }
530
+
531
+ .filters >>> .el-popover[x-placement^="bottom"] .popper__arrow {
532
+ border-top-width: 0;
533
+ border-bottom-color: #8300BF;
534
+ }
535
+ .filters >>> .el-popover[x-placement^="bottom"] .popper__arrow::after {
536
+ border-top-width: 0;
537
+ border-bottom-color: #f3ecf6;
538
+ }
539
+
540
+ .filters >>> .el-popover[x-placement^="right"] .popper__arrow {
541
+ border-right-color: #8300BF;
542
+ border-left-width: 0;
543
+ }
544
+ .filters >>> .el-popover[x-placement^="right"] .popper__arrow::after {
545
+ border-right-color: #f3ecf6;
546
+ border-left-width: 0;
547
+ }
548
+
549
+ .filters >>> .el-popover[x-placement^="left"] .popper__arrow {
550
+ border-right-width: 0;
551
+ border-left-color: #8300BF;
552
+ }
553
+ .filters >>> .el-popover[x-placement^="left"] .popper__arrow::after {
554
+ border-right-width: 0;
555
+ border-left-color: #f3ecf6;
556
+ }
557
+ </style>