@abi-software/map-side-bar 2.7.2-beta.2 → 2.7.2-beta.4
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/dist/map-side-bar.js +7019 -7394
- package/dist/map-side-bar.umd.cjs +62 -59
- package/dist/style.css +1 -1
- package/package.json +2 -2
- package/src/App.vue +30 -95
- package/src/components/ConnectivityInfo.vue +189 -384
- package/src/components/SearchFilters.vue +51 -66
- package/src/components/SearchHistory.vue +1 -0
- package/src/components/SideBar.vue +116 -79
- package/src/components/SidebarContent.vue +1 -2
- package/src/components/Tabs.vue +95 -56
- package/src/components/flatmapQueries.js +291 -0
- package/src/components.d.ts +23 -2
- package/src/exampleConnectivityInput.js +1 -1
- package/src/components/ConnectivityCard.vue +0 -78
- package/src/components/ConnectivityExplorer.vue +0 -518
|
@@ -213,60 +213,7 @@ export default {
|
|
|
213
213
|
)
|
|
214
214
|
return value
|
|
215
215
|
},
|
|
216
|
-
processOptions: function () {
|
|
217
|
-
// create top level of options in cascader
|
|
218
|
-
this.options.forEach((facet, i) => {
|
|
219
|
-
this.options[i].total = this.countTotalFacet(facet)
|
|
220
|
-
|
|
221
|
-
this.options[i].label = convertReadableLabel(facet.label)
|
|
222
|
-
this.options[i].value = this.createCascaderItemValue(
|
|
223
|
-
facet.key,
|
|
224
|
-
undefined
|
|
225
|
-
)
|
|
226
|
-
|
|
227
|
-
// put "Show all" as first option
|
|
228
|
-
this.options[i].children.unshift({
|
|
229
|
-
value: this.createCascaderItemValue('Show all'),
|
|
230
|
-
label: 'Show all',
|
|
231
|
-
})
|
|
232
|
-
|
|
233
|
-
// populate second level of options
|
|
234
|
-
this.options[i].children.forEach((facetItem, j) => {
|
|
235
|
-
// Format labels except funding program
|
|
236
|
-
if (this.options[i].children[j].facetPropPath !== 'pennsieve.organization.name') {
|
|
237
|
-
this.options[i].children[j].label = convertReadableLabel(
|
|
238
|
-
facetItem.label
|
|
239
|
-
)
|
|
240
|
-
}
|
|
241
|
-
this.options[i].children[j].value =
|
|
242
|
-
this.createCascaderItemValue(facet.label, facetItem.label)
|
|
243
|
-
if (
|
|
244
|
-
this.options[i].children[j].children &&
|
|
245
|
-
this.options[i].children[j].children.length > 0
|
|
246
|
-
) {
|
|
247
|
-
this.options[i].children[j].children.forEach((term, k) => {
|
|
248
|
-
this.options[i].children[j].children[k].label =
|
|
249
|
-
convertReadableLabel(term.label)
|
|
250
|
-
this.options[i].children[j].children[k].value =
|
|
251
|
-
this.createCascaderItemValue(
|
|
252
|
-
facet.label,
|
|
253
|
-
facetItem.label,
|
|
254
|
-
term.label
|
|
255
|
-
)
|
|
256
|
-
})
|
|
257
|
-
}
|
|
258
|
-
})
|
|
259
|
-
})
|
|
260
|
-
},
|
|
261
216
|
populateCascader: function () {
|
|
262
|
-
if (this.entry.options) {
|
|
263
|
-
return new Promise((resolve) => {
|
|
264
|
-
this.facets = this.entry.options
|
|
265
|
-
this.options = this.entry.options
|
|
266
|
-
this.processOptions()
|
|
267
|
-
resolve();
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
217
|
return new Promise((resolve) => {
|
|
271
218
|
// Algolia facet serach
|
|
272
219
|
this.algoliaClient
|
|
@@ -275,7 +222,50 @@ export default {
|
|
|
275
222
|
this.facets = data
|
|
276
223
|
EventBus.emit('available-facets', data)
|
|
277
224
|
this.options = data
|
|
278
|
-
|
|
225
|
+
|
|
226
|
+
// create top level of options in cascader
|
|
227
|
+
this.options.forEach((facet, i) => {
|
|
228
|
+
this.options[i].total = this.countTotalFacet(facet)
|
|
229
|
+
|
|
230
|
+
this.options[i].label = convertReadableLabel(facet.label)
|
|
231
|
+
this.options[i].value = this.createCascaderItemValue(
|
|
232
|
+
facet.key,
|
|
233
|
+
undefined
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
// put "Show all" as first option
|
|
237
|
+
this.options[i].children.unshift({
|
|
238
|
+
value: this.createCascaderItemValue('Show all'),
|
|
239
|
+
label: 'Show all',
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// populate second level of options
|
|
243
|
+
this.options[i].children.forEach((facetItem, j) => {
|
|
244
|
+
// Format labels except funding program
|
|
245
|
+
if (this.options[i].children[j].facetPropPath !== 'pennsieve.organization.name') {
|
|
246
|
+
this.options[i].children[j].label = convertReadableLabel(
|
|
247
|
+
facetItem.label
|
|
248
|
+
)
|
|
249
|
+
}
|
|
250
|
+
this.options[i].children[j].value =
|
|
251
|
+
this.createCascaderItemValue(facet.label, facetItem.label)
|
|
252
|
+
if (
|
|
253
|
+
this.options[i].children[j].children &&
|
|
254
|
+
this.options[i].children[j].children.length > 0
|
|
255
|
+
) {
|
|
256
|
+
this.options[i].children[j].children.forEach((term, k) => {
|
|
257
|
+
this.options[i].children[j].children[k].label =
|
|
258
|
+
convertReadableLabel(term.label)
|
|
259
|
+
this.options[i].children[j].children[k].value =
|
|
260
|
+
this.createCascaderItemValue(
|
|
261
|
+
facet.label,
|
|
262
|
+
facetItem.label,
|
|
263
|
+
term.label
|
|
264
|
+
)
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
})
|
|
279
269
|
})
|
|
280
270
|
.finally(() => {
|
|
281
271
|
resolve()
|
|
@@ -745,18 +735,13 @@ export default {
|
|
|
745
735
|
removeTopLevelCascaderCheckboxes: function () {
|
|
746
736
|
// Next tick allows the cascader menu to change
|
|
747
737
|
this.$nextTick(() => {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
panel.querySelectorAll('.el-checkbox__input').forEach(checkbox => {
|
|
756
|
-
checkbox.style.display = 'none';
|
|
757
|
-
});
|
|
758
|
-
}
|
|
759
|
-
});
|
|
738
|
+
let cascadePanels = document.querySelectorAll(
|
|
739
|
+
'.sidebar-cascader-popper .el-cascader-menu__list'
|
|
740
|
+
)
|
|
741
|
+
// Hide the checkboxes on the first level of the cascader
|
|
742
|
+
cascadePanels[0]
|
|
743
|
+
.querySelectorAll('.el-checkbox__input')
|
|
744
|
+
.forEach((el) => (el.style.display = 'none'))
|
|
760
745
|
})
|
|
761
746
|
},
|
|
762
747
|
/*
|
|
@@ -22,15 +22,29 @@
|
|
|
22
22
|
</div>
|
|
23
23
|
<div class="sidebar-container">
|
|
24
24
|
<Tabs
|
|
25
|
-
v-if="
|
|
26
|
-
:
|
|
25
|
+
v-if="activeTabs.length > 1"
|
|
26
|
+
:tabTitles="activeTabs"
|
|
27
27
|
:activeId="activeTabId"
|
|
28
|
-
@
|
|
29
|
-
@
|
|
28
|
+
@titleClicked="tabClicked"
|
|
29
|
+
@tab-close="tabClose"
|
|
30
30
|
/>
|
|
31
31
|
<template v-for="tab in tabs" key="tab.id">
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
<!-- Connectivity Info -->
|
|
33
|
+
<template v-if="tab.type === 'connectivity' && connectivityInfo">
|
|
34
|
+
<connectivity-info
|
|
35
|
+
:entry="connectivityInfo"
|
|
36
|
+
:availableAnatomyFacets="availableAnatomyFacets"
|
|
37
|
+
v-if="tab.id === activeTabId"
|
|
38
|
+
:envVars="envVars"
|
|
39
|
+
:ref="'connectivityTab_' + tab.id"
|
|
40
|
+
:useDOIFormatter="useDOIFormatter"
|
|
41
|
+
@show-connectivity="showConnectivity"
|
|
42
|
+
@show-reference-connectivities="onShowReferenceConnectivities"
|
|
43
|
+
@connectivity-component-click="onConnectivityComponentClick"
|
|
44
|
+
/>
|
|
45
|
+
</template>
|
|
46
|
+
<template v-else-if="tab.type === 'annotation'">
|
|
47
|
+
<annotation-tool
|
|
34
48
|
:ref="'annotationTab_' + tab.id"
|
|
35
49
|
v-show="tab.id === activeTabId"
|
|
36
50
|
:annotationEntry="annotationEntry"
|
|
@@ -41,23 +55,6 @@
|
|
|
41
55
|
@confirm-delete="$emit('confirm-delete', $event)"
|
|
42
56
|
/>
|
|
43
57
|
</template>
|
|
44
|
-
<template v-else-if="tab.type === 'connectivityExplorer'">
|
|
45
|
-
<ConnectivityExplorer
|
|
46
|
-
:ref="'connectivityExplorerTab_' + tab.id"
|
|
47
|
-
v-show="tab.id === activeTabId"
|
|
48
|
-
:connectivityKnowledge="connectivityKnowledge"
|
|
49
|
-
:envVars="envVars"
|
|
50
|
-
:connectivityEntry="connectivityEntry"
|
|
51
|
-
:availableAnatomyFacets="availableAnatomyFacets"
|
|
52
|
-
@search-changed="searchChanged(tab.id, $event)"
|
|
53
|
-
@hover-changed="hoverChanged($event)"
|
|
54
|
-
@show-connectivity="showConnectivity"
|
|
55
|
-
@show-reference-connectivities="onShowReferenceConnectivities"
|
|
56
|
-
@connectivity-clicked="onConnectivityClicked"
|
|
57
|
-
@connectivity-hovered="onConnectivityHovered"
|
|
58
|
-
@connectivity-explorer-clicked="onConnectivityExplorerClicked"
|
|
59
|
-
/>
|
|
60
|
-
</template>
|
|
61
58
|
<template v-else>
|
|
62
59
|
<SidebarContent
|
|
63
60
|
class="sidebar-content-container"
|
|
@@ -87,7 +84,7 @@ import SidebarContent from './SidebarContent.vue'
|
|
|
87
84
|
import EventBus from './EventBus.js'
|
|
88
85
|
import Tabs from './Tabs.vue'
|
|
89
86
|
import AnnotationTool from './AnnotationTool.vue'
|
|
90
|
-
import
|
|
87
|
+
import ConnectivityInfo from './ConnectivityInfo.vue'
|
|
91
88
|
|
|
92
89
|
/**
|
|
93
90
|
* Aims to provide a sidebar for searching capability for SPARC portal.
|
|
@@ -100,8 +97,8 @@ export default {
|
|
|
100
97
|
ElIconArrowRight,
|
|
101
98
|
Drawer,
|
|
102
99
|
Icon,
|
|
100
|
+
ConnectivityInfo,
|
|
103
101
|
AnnotationTool,
|
|
104
|
-
ConnectivityExplorer,
|
|
105
102
|
},
|
|
106
103
|
name: 'SideBar',
|
|
107
104
|
props: {
|
|
@@ -122,6 +119,24 @@ export default {
|
|
|
122
119
|
type: Object,
|
|
123
120
|
default: () => {},
|
|
124
121
|
},
|
|
122
|
+
/**
|
|
123
|
+
* The array of objects to show multiple sidebar contents.
|
|
124
|
+
*/
|
|
125
|
+
tabs: {
|
|
126
|
+
type: Array,
|
|
127
|
+
default: () => [
|
|
128
|
+
{ id: 1, title: 'Search', type: 'search' },
|
|
129
|
+
{ id: 2, title: 'Connectivity', type: 'connectivity' },
|
|
130
|
+
{ id: 3, title: 'Annotation', type: 'annotation' }
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
/**
|
|
134
|
+
* The active tab id for default tab.
|
|
135
|
+
*/
|
|
136
|
+
activeTabId: {
|
|
137
|
+
type: Number,
|
|
138
|
+
default: 1,
|
|
139
|
+
},
|
|
125
140
|
/**
|
|
126
141
|
* The option to show or hide sidebar on page load.
|
|
127
142
|
*/
|
|
@@ -132,16 +147,16 @@ export default {
|
|
|
132
147
|
/**
|
|
133
148
|
* The connectivity info data to show in sidebar.
|
|
134
149
|
*/
|
|
135
|
-
|
|
150
|
+
connectivityInfo: {
|
|
136
151
|
type: Object,
|
|
137
|
-
default:
|
|
152
|
+
default: null,
|
|
138
153
|
},
|
|
139
154
|
/**
|
|
140
155
|
* The annotation data to show in sidebar.
|
|
141
156
|
*/
|
|
142
157
|
annotationEntry: {
|
|
143
158
|
type: Object,
|
|
144
|
-
default:
|
|
159
|
+
default: null,
|
|
145
160
|
},
|
|
146
161
|
createData: {
|
|
147
162
|
type: Object,
|
|
@@ -153,27 +168,23 @@ export default {
|
|
|
153
168
|
y: 0,
|
|
154
169
|
},
|
|
155
170
|
},
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
171
|
+
/**
|
|
172
|
+
* The option to use DOI.org as citation formatter.
|
|
173
|
+
* If set to `false`, citation.js will be used.
|
|
174
|
+
* Default is `true`.
|
|
175
|
+
*/
|
|
176
|
+
useDOIFormatter: {
|
|
177
|
+
type: Boolean,
|
|
178
|
+
default: true,
|
|
159
179
|
},
|
|
160
180
|
},
|
|
161
181
|
data: function () {
|
|
162
182
|
return {
|
|
163
183
|
drawerOpen: false,
|
|
164
|
-
availableAnatomyFacets: []
|
|
165
|
-
activeTabId: 1,
|
|
166
|
-
tabs: [
|
|
167
|
-
{ title: 'Search', id: 1, type: 'search', closable: false },
|
|
168
|
-
{ title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
|
|
169
|
-
{ title: 'Annotation', id: 3, type: 'annotation', closable: true },
|
|
170
|
-
]
|
|
184
|
+
availableAnatomyFacets: []
|
|
171
185
|
}
|
|
172
186
|
},
|
|
173
187
|
methods: {
|
|
174
|
-
onConnectivityExplorerClicked: function (data) {
|
|
175
|
-
this.$emit('connectivity-explorer-clicked', data)
|
|
176
|
-
},
|
|
177
188
|
/**
|
|
178
189
|
* This event is emitted when the mouse hover are changed.
|
|
179
190
|
* @arg data
|
|
@@ -196,18 +207,11 @@ export default {
|
|
|
196
207
|
this.$emit('show-reference-connectivities', refSource);
|
|
197
208
|
},
|
|
198
209
|
/**
|
|
199
|
-
* This function is triggered after connectivity
|
|
200
|
-
* @arg data
|
|
201
|
-
*/
|
|
202
|
-
onConnectivityClicked: function (data) {
|
|
203
|
-
this.$emit('connectivity-clicked', data);
|
|
204
|
-
},
|
|
205
|
-
/**
|
|
206
|
-
* This function is triggered after connectivity term is hovered.
|
|
210
|
+
* This function is triggered after a connectivity component is clicked.
|
|
207
211
|
* @arg data
|
|
208
212
|
*/
|
|
209
|
-
|
|
210
|
-
this.$emit('connectivity-
|
|
213
|
+
onConnectivityComponentClick: function (data) {
|
|
214
|
+
this.$emit('connectivity-component-click', data);
|
|
211
215
|
},
|
|
212
216
|
/**
|
|
213
217
|
* This event is emitted when the search filters are changed.
|
|
@@ -230,31 +234,43 @@ export default {
|
|
|
230
234
|
toggleDrawer: function () {
|
|
231
235
|
this.drawerOpen = !this.drawerOpen
|
|
232
236
|
},
|
|
233
|
-
openConnectivitySearch: function (facets, query) {
|
|
234
|
-
this.drawerOpen = true;
|
|
235
|
-
// Because refs are in v-for, nextTick is needed here
|
|
236
|
-
this.$nextTick(() => {
|
|
237
|
-
const connectivityExplorerTabRef = this.getTabRef(2, 'connectivityExplorer', true);
|
|
238
|
-
connectivityExplorerTabRef.openSearch(facets, query);
|
|
239
|
-
})
|
|
240
|
-
},
|
|
241
237
|
openSearch: function (facets, query) {
|
|
242
238
|
this.drawerOpen = true
|
|
243
239
|
// Because refs are in v-for, nextTick is needed here
|
|
244
240
|
this.$nextTick(() => {
|
|
245
|
-
const searchTabRef = this.
|
|
241
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
246
242
|
searchTabRef.openSearch(facets, query);
|
|
247
243
|
})
|
|
248
244
|
},
|
|
245
|
+
/**
|
|
246
|
+
* Get the tab object by tab id and type.
|
|
247
|
+
* If not found, return the first available tab.
|
|
248
|
+
*/
|
|
249
|
+
getTabByIdAndType: function (id, type) {
|
|
250
|
+
const tabId = id || this.activeTabId;
|
|
251
|
+
const tabType = type || 'search'; // default to search tab
|
|
252
|
+
const tabObj = this.activeTabs.find((tab) => tab.id === tabId && tab.type === tabType);
|
|
253
|
+
const firstAvailableTab = this.activeTabs[0];
|
|
254
|
+
return tabObj || firstAvailableTab;
|
|
255
|
+
},
|
|
249
256
|
/**
|
|
250
257
|
* Get the ref id of the tab by id and type.
|
|
251
258
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
259
|
+
getTabRefId: function (id, type) {
|
|
260
|
+
let refIdPrefix = 'searchTab_'; // default to search tab
|
|
261
|
+
if (type === 'connectivity') {
|
|
262
|
+
refIdPrefix = 'connectivityTab_';
|
|
263
|
+
} else if (type === 'annotation') {
|
|
264
|
+
refIdPrefix = 'annotationTab_';
|
|
265
|
+
}
|
|
266
|
+
const tabObj = this.getTabByIdAndType(id, type);
|
|
267
|
+
const tabRefId = refIdPrefix + tabObj.id;
|
|
268
|
+
return tabRefId;
|
|
269
|
+
},
|
|
270
|
+
getSearchTabRefById: function (id) {
|
|
271
|
+
const searchTabId = id || 1; // to use id when there are multiple search tabs
|
|
272
|
+
const searchTabRefId = this.getTabRefId(searchTabId, 'search');
|
|
273
|
+
return this.$refs[searchTabRefId][0];
|
|
258
274
|
},
|
|
259
275
|
/**
|
|
260
276
|
* The function to add filters to sidebar search.
|
|
@@ -268,7 +284,7 @@ export default {
|
|
|
268
284
|
|
|
269
285
|
// Because refs are in v-for, nextTick is needed here
|
|
270
286
|
this.$nextTick(() => {
|
|
271
|
-
const searchTabRef = this.
|
|
287
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
272
288
|
searchTabRef.addFilter(filter)
|
|
273
289
|
})
|
|
274
290
|
},
|
|
@@ -276,7 +292,7 @@ export default {
|
|
|
276
292
|
this.drawerOpen = true
|
|
277
293
|
// Because refs are in v-for, nextTick is needed here
|
|
278
294
|
this.$nextTick(() => {
|
|
279
|
-
const searchTabRef = this.
|
|
295
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
280
296
|
searchTabRef.openSearch(
|
|
281
297
|
'',
|
|
282
298
|
undefined,
|
|
@@ -286,17 +302,27 @@ export default {
|
|
|
286
302
|
})
|
|
287
303
|
},
|
|
288
304
|
getAlgoliaFacets: async function () {
|
|
289
|
-
const searchTabRef = this.
|
|
305
|
+
const searchTabRef = this.getSearchTabRefById(1);
|
|
290
306
|
return await searchTabRef.getAlgoliaFacets()
|
|
291
307
|
},
|
|
292
308
|
setDrawerOpen: function (value = true) {
|
|
293
309
|
this.drawerOpen = value
|
|
294
310
|
},
|
|
295
|
-
|
|
296
|
-
|
|
311
|
+
/**
|
|
312
|
+
* The function to emit 'tabClicked' event with tab's `id` and tab's `type`
|
|
313
|
+
* when user clicks the sidebar tab.
|
|
314
|
+
* @param {Object} {id, type}
|
|
315
|
+
* @public
|
|
316
|
+
*/
|
|
317
|
+
tabClicked: function ({id, type}) {
|
|
318
|
+
/**
|
|
319
|
+
* This event is emitted when user click sidebar's tab.
|
|
320
|
+
* @arg {Object} {id, type}
|
|
321
|
+
*/
|
|
322
|
+
this.$emit('tabClicked', {id, type});
|
|
297
323
|
},
|
|
298
|
-
|
|
299
|
-
this.$emit('
|
|
324
|
+
tabClose: function (id) {
|
|
325
|
+
this.$emit('tab-close', id);
|
|
300
326
|
},
|
|
301
327
|
/**
|
|
302
328
|
* To receive error message for connectivity graph
|
|
@@ -308,12 +334,22 @@ export default {
|
|
|
308
334
|
},
|
|
309
335
|
computed: {
|
|
310
336
|
// This should respect the information provided by the property
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
tab.type === "
|
|
315
|
-
|
|
316
|
-
|
|
337
|
+
activeTabs: function() {
|
|
338
|
+
const tabs = []
|
|
339
|
+
this.tabs.forEach((tab) => {
|
|
340
|
+
if (tab.type === "search") {
|
|
341
|
+
tabs.push(tab)
|
|
342
|
+
} else if (tab.type === "connectivity") {
|
|
343
|
+
if (this.connectivityInfo) {
|
|
344
|
+
tabs.push(tab);
|
|
345
|
+
}
|
|
346
|
+
} else if (tab.type === "annotation") {
|
|
347
|
+
if (this.annotationEntry && Object.keys(this.annotationEntry).length > 0) {
|
|
348
|
+
tabs.push(tab);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
return tabs;
|
|
317
353
|
},
|
|
318
354
|
},
|
|
319
355
|
created: function () {
|
|
@@ -369,6 +405,7 @@ export default {
|
|
|
369
405
|
EventBus.on('available-facets', (payLoad) => {
|
|
370
406
|
this.availableAnatomyFacets = payLoad.find((facet) => facet.label === 'Anatomical Structure').children
|
|
371
407
|
})
|
|
408
|
+
|
|
372
409
|
},
|
|
373
410
|
}
|
|
374
411
|
</script>
|
|
@@ -164,8 +164,7 @@ export default {
|
|
|
164
164
|
},
|
|
165
165
|
methods: {
|
|
166
166
|
hoverChanged: function (data) {
|
|
167
|
-
|
|
168
|
-
this.$emit('hover-changed', payload)
|
|
167
|
+
this.$emit('hover-changed', data)
|
|
169
168
|
},
|
|
170
169
|
resetSearch: function () {
|
|
171
170
|
this.numberOfHits = 0
|
package/src/components/Tabs.vue
CHANGED
|
@@ -1,35 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="
|
|
2
|
+
<div class="tab-container">
|
|
3
3
|
<div
|
|
4
|
-
class="
|
|
5
|
-
v-for="
|
|
6
|
-
:key="
|
|
7
|
-
:class="{ 'active-tab':
|
|
8
|
-
@click="tabClicked(tab)"
|
|
4
|
+
class="title"
|
|
5
|
+
v-for="title in tabTitles"
|
|
6
|
+
:key="title.id"
|
|
7
|
+
:class="{ 'active-tab': title.id == activeId }"
|
|
9
8
|
>
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
v-
|
|
13
|
-
|
|
14
|
-
class="tab-close-icon"
|
|
9
|
+
<div
|
|
10
|
+
class="title-text-table"
|
|
11
|
+
v-bind:class="{ highlightText: title.id == activeId }"
|
|
12
|
+
v-on:click="titleClicked(title.id, title.type)"
|
|
15
13
|
>
|
|
16
|
-
<
|
|
17
|
-
|
|
14
|
+
<div class="title-text">
|
|
15
|
+
{{ title.title }}
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
<el-button
|
|
19
|
+
v-if="title.id > 1"
|
|
20
|
+
@click="tabClose(title.id)"
|
|
21
|
+
class="button-tab-close"
|
|
22
|
+
aria-label="Close"
|
|
23
|
+
>
|
|
24
|
+
×
|
|
25
|
+
<span class="visually-hidden">Close</span>
|
|
26
|
+
</el-button>
|
|
18
27
|
</div>
|
|
19
28
|
</div>
|
|
20
29
|
</template>
|
|
21
30
|
|
|
22
31
|
<script>
|
|
23
32
|
/* eslint-disable no-alert, no-console */
|
|
24
|
-
import { Close as ElIconClose } from "@element-plus/icons-vue";
|
|
25
33
|
|
|
26
34
|
export default {
|
|
27
|
-
name:
|
|
28
|
-
components: {
|
|
29
|
-
ElIconClose,
|
|
30
|
-
},
|
|
35
|
+
name: 'Tabs',
|
|
31
36
|
props: {
|
|
32
|
-
|
|
37
|
+
tabTitles: {
|
|
33
38
|
type: Array,
|
|
34
39
|
default: () => [],
|
|
35
40
|
},
|
|
@@ -37,72 +42,106 @@ export default {
|
|
|
37
42
|
type: Number,
|
|
38
43
|
default: 1,
|
|
39
44
|
},
|
|
40
|
-
contextArray: {
|
|
41
|
-
type: Array,
|
|
42
|
-
default: () => [],
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
computed: {
|
|
46
|
-
tabs: function () {
|
|
47
|
-
// permanent tabs always show in the front
|
|
48
|
-
const permanent = this.tabEntries.filter((t) => !t.closable);
|
|
49
|
-
const temporary = this.tabEntries.filter((t) => t.closable);
|
|
50
|
-
let entries = permanent.concat(temporary);
|
|
51
|
-
if (this.contextArray.length) {
|
|
52
|
-
for (let i in entries) {
|
|
53
|
-
entries[i].contextCard = this.contextArray[i];
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return entries;
|
|
57
|
-
},
|
|
58
45
|
},
|
|
59
46
|
methods: {
|
|
60
|
-
|
|
61
|
-
this.$emit(
|
|
47
|
+
titleClicked: function (id, type) {
|
|
48
|
+
this.$emit('titleClicked', {id, type})
|
|
62
49
|
},
|
|
63
|
-
|
|
64
|
-
this.$emit(
|
|
50
|
+
tabClose: function (id) {
|
|
51
|
+
this.$emit('tab-close', id);
|
|
65
52
|
},
|
|
66
53
|
},
|
|
67
|
-
}
|
|
54
|
+
}
|
|
68
55
|
</script>
|
|
69
56
|
|
|
70
57
|
<style lang="scss" scoped>
|
|
71
|
-
|
|
58
|
+
$tab-height: 30px;
|
|
59
|
+
|
|
60
|
+
.tab-container {
|
|
61
|
+
height: $tab-height + 2;
|
|
72
62
|
display: flex;
|
|
73
|
-
flex-
|
|
74
|
-
|
|
63
|
+
flex-direction: row;
|
|
64
|
+
position: relative;
|
|
65
|
+
z-index: 1;
|
|
75
66
|
}
|
|
76
67
|
|
|
77
|
-
.
|
|
78
|
-
height:
|
|
68
|
+
.title {
|
|
69
|
+
height: $tab-height;
|
|
79
70
|
border: 1px solid var(--el-border-color);
|
|
80
71
|
border-top-color: transparent;
|
|
81
|
-
|
|
72
|
+
background-color: white;
|
|
82
73
|
display: flex;
|
|
74
|
+
width: fit-content;
|
|
83
75
|
align-items: center;
|
|
76
|
+
position: relative;
|
|
84
77
|
cursor: pointer;
|
|
85
78
|
}
|
|
86
79
|
|
|
87
|
-
.
|
|
80
|
+
.title-text {
|
|
81
|
+
text-align: center;
|
|
82
|
+
display: table-cell;
|
|
83
|
+
vertical-align: middle;
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
padding: 0 1rem;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.title-text-table {
|
|
89
|
+
display: table;
|
|
90
|
+
height: 100%;
|
|
91
|
+
width: 100%;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.parent-dialog:hover .title-text {
|
|
95
|
+
color: $app-primary-color;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.title:hover,
|
|
88
99
|
.active-tab {
|
|
89
100
|
background-color: #f9f2fc;
|
|
90
|
-
border:
|
|
101
|
+
border: solid #8300bf;
|
|
102
|
+
border-width: 1px 1px .125em;
|
|
91
103
|
color: #8300bf;
|
|
92
104
|
font-weight: 500;
|
|
93
105
|
}
|
|
94
106
|
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
font-size: 14px;
|
|
98
|
-
padding: 0 1rem;
|
|
107
|
+
.highlightText {
|
|
108
|
+
color: $app-primary-color;
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
.tab-close
|
|
111
|
+
.button-tab-close {
|
|
102
112
|
width: 20px !important;
|
|
103
113
|
height: 20px !important;
|
|
104
|
-
|
|
114
|
+
line-height: 20px !important;
|
|
115
|
+
padding: 0 !important;
|
|
105
116
|
padding-right: 4px !important;
|
|
117
|
+
font-size: 24px !important;
|
|
106
118
|
color: $app-primary-color !important;
|
|
119
|
+
border: 0 none !important;
|
|
120
|
+
box-shadow: none !important;
|
|
121
|
+
outline: none !important;
|
|
122
|
+
background-color: transparent !important;
|
|
123
|
+
|
|
124
|
+
:deep(> span) {
|
|
125
|
+
height: $tab-height - 2 !important; // tab height minus border
|
|
126
|
+
font-family: Arial !important; // to fix font alignment on different browsers
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
&:hover,
|
|
130
|
+
&:focus {
|
|
131
|
+
border: 0 none !important;
|
|
132
|
+
outline: none !important;
|
|
133
|
+
box-shadow: none !important;
|
|
134
|
+
background-color: transparent !important;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.visually-hidden {
|
|
139
|
+
clip: rect(0 0 0 0);
|
|
140
|
+
clip-path: inset(50%);
|
|
141
|
+
height: 1px;
|
|
142
|
+
overflow: hidden;
|
|
143
|
+
position: absolute;
|
|
144
|
+
white-space: nowrap;
|
|
145
|
+
width: 1px;
|
|
107
146
|
}
|
|
108
147
|
</style>
|