- vuejs solr faceted search
- with extra display for active filter items
This commit is contained in:
parent
c596a620cc
commit
a95282e49e
2
public/backend/ckeditor.js
vendored
2
public/backend/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
60
public/css/search_style.css
vendored
60
public/css/search_style.css
vendored
|
@ -21,14 +21,7 @@ section.search {
|
|||
|
||||
/* Seasrch items */
|
||||
|
||||
.left-bar .panel-title {
|
||||
text-transform: capitalize;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
color: white;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.search-items {
|
||||
|
@ -116,6 +109,15 @@ section.search {
|
|||
|
||||
/* filter items in the left bar */
|
||||
/*-------------------------------------------------- */
|
||||
.left-bar .panel-title {
|
||||
text-transform: capitalize;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 2px;
|
||||
color: white;
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.overflowing {
|
||||
color: #444444;
|
||||
list-style: none;
|
||||
|
@ -128,7 +130,7 @@ section.search {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
ul.filterItems li {
|
||||
ul.filter-items li {
|
||||
min-height: 15px;
|
||||
color: #444;
|
||||
font-size: 12px;
|
||||
|
@ -148,21 +150,21 @@ ul.filterItems li {
|
|||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.filterItems.limited li:nth-of-type(1n+6) {
|
||||
.filter-items.limited li:nth-of-type(1n+3) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
ul.filterItems .active {
|
||||
/* ul.filter-items .active {
|
||||
background-color: lightgray;
|
||||
}
|
||||
ul.filterItems li a {
|
||||
} */
|
||||
ul.filter-items li a {
|
||||
cursor: pointer;
|
||||
color: lightgray;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
/* ul.filterItems li a:hover {
|
||||
/* ul.filter-items li a:hover {
|
||||
color: #0099cc;
|
||||
cursor: pointer;
|
||||
} */
|
||||
|
@ -319,7 +321,7 @@ font-size: 16px;
|
|||
list-style: outside none none;
|
||||
padding: 0px 0px 12px;
|
||||
margin: 0px;
|
||||
max-height: 240px;
|
||||
/* max-height: 240px; */
|
||||
position: relative;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
@ -342,7 +344,6 @@ font-size: 16px;
|
|||
width: 1px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.css-w1gpbi:checked + label::before {
|
||||
animation: 0s ease 0s 1 normal none running none;
|
||||
background-color: rgb(255, 255, 255);
|
||||
|
@ -396,3 +397,30 @@ vertical-align: middle;
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active-filter-items a {
|
||||
|
||||
flex-wrap: wrap;
|
||||
margin: 2px 3px;
|
||||
padding: 5px 8px;
|
||||
font-size: 0.95rem;
|
||||
position: relative;
|
||||
}
|
||||
.filter-link {
|
||||
display: inline-flex;
|
||||
-moz-box-pack: center;
|
||||
justify-content: center;
|
||||
-moz-box-align: center;
|
||||
align-items: center;
|
||||
border-radius: 3px;
|
||||
border: 1px solid transparent;
|
||||
min-height: 30px;
|
||||
overflow-wrap: break-word;
|
||||
padding: 5px 12px;
|
||||
line-height: 1.2rem;
|
||||
background-color: rgb(238, 238, 238);
|
||||
color: rgb(66, 66, 66);
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
transition: all 0.3s ease 0s;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,35 +1,41 @@
|
|||
<template>
|
||||
<div class="search-container row">
|
||||
|
||||
<div class="search-container row">
|
||||
<div class="four columns left-bar">
|
||||
<div id="left-bar" class="sidebar left-bar">
|
||||
<h2 class="indexheader">DataXplore</h2>
|
||||
|
||||
<!-- <div class="card" v-for="item in facets.language" :key="item.id">
|
||||
<span>{{ item }}</span>
|
||||
</div> -->
|
||||
<h2 class="indexheader">DataXplore</h2>
|
||||
|
||||
<!-- <facet-list v-bind:data="facets"></facet-list> -->
|
||||
<div class="card" v-for="(valueArray, filterName, index) in facets" :key="index">
|
||||
<facet-list :data="valueArray" :filterName="filterName"></facet-list>
|
||||
</div>
|
||||
<!-- <div class="card" v-for="item in facets.language" :key="item.id">
|
||||
<span>{{ item }}</span>
|
||||
</div>-->
|
||||
|
||||
<!-- <facet-list v-bind:data="facets"></facet-list> -->
|
||||
<div class="card" v-for="(item, index) in facets" :key="index">
|
||||
<facet-list :data="item.values" :filterName="item.filterName" @filter="onFilter"></facet-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="eight columns right-bar">
|
||||
<div id="right-bar" class="sidebar right-bar">
|
||||
|
||||
<!-- Search input section -->
|
||||
|
||||
<div class="row">
|
||||
<div class="twelve columns">
|
||||
<vs-input @search="onSearch"></vs-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="active-filter-items twelve columns">
|
||||
<a class="filter-link" v-for="(value, key, index) in activeFilterItems" :key="index">
|
||||
<span>{{ key + ": " }}</span>
|
||||
<span v-if="value && value.length > 0">{{ value.join(', ') }}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Results section -->
|
||||
<vs-results v-bind:data="results"></vs-results>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,9 +3,10 @@ import VsInput from './text-search/vs-input.vue';
|
|||
import VsResults from './search-results/vs-results.vue';
|
||||
import FacetList from './search-results/facet-list.vue'
|
||||
import rdrApi from './search-results/dataservice';
|
||||
import FilterItem from './models/filter-item';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
components: {
|
||||
VsInput,
|
||||
VsResults,
|
||||
FacetList
|
||||
|
@ -15,16 +16,67 @@ export default class App extends Vue {
|
|||
|
||||
results = [];
|
||||
facets = [];
|
||||
bar = 'bar';
|
||||
searchTerm = '';
|
||||
activeFilterItems = {};
|
||||
|
||||
async onFilter(filter) {
|
||||
// console.log(filter.value);
|
||||
// if (!this.activeFilterItems.some(e => e.value === filter.value)) {
|
||||
// this.activeFilterItems.push(filter);
|
||||
if (!this.activeFilterItems.hasOwnProperty(filter.Category)) {
|
||||
this.activeFilterItems[filter.Category] = [];
|
||||
}
|
||||
if (!this.activeFilterItems[filter.Category].some(e => e === filter.value)) {
|
||||
this.activeFilterItems[filter.Category].push(filter.value);
|
||||
|
||||
var res = await rdrApi.search(this.searchTerm, this.activeFilterItems);
|
||||
this.results = res.response.docs;
|
||||
// this.facets = res.facet_counts.facet_fields;
|
||||
this.facets = [];
|
||||
var facet_fields = res.facet_counts.facet_fields;
|
||||
for (var prop in facet_fields) {
|
||||
var facetValues = facet_fields[prop].map((facet, i) => {
|
||||
if (i % 2 === 0) {
|
||||
// var rObj = { value: facet, count: facet_fields[prop][i + 1] };
|
||||
var rObj = new FilterItem(facet, facet_fields[prop][i + 1]);
|
||||
return rObj;
|
||||
}
|
||||
}).filter(function (el) {
|
||||
return el != null && el.count > 0;
|
||||
});
|
||||
this.facets.push({ filterName: prop, values: facetValues });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async onSearch(term) {
|
||||
console.log(term);
|
||||
// this.results = await rdrApi.search(term);
|
||||
var res = await rdrApi.search(term);
|
||||
// console.log(term);
|
||||
// while (this.activeFilterItems.length > 0) {
|
||||
// this.activeFilterItems.pop();
|
||||
// }
|
||||
this.activeFilterItems = {};
|
||||
while (this.facets.length > 0) {
|
||||
this.facets.pop();
|
||||
}
|
||||
this.searchTerm = term;
|
||||
var res = await rdrApi.search(this.searchTerm, this.activeFilterItems);
|
||||
this.results = res.response.docs;
|
||||
this.facets = res.facet_counts.facet_fields;
|
||||
var facet_fields = res.facet_counts.facet_fields;
|
||||
for (var prop in facet_fields) {
|
||||
var facetValues = facet_fields[prop].map((facet, i) => {
|
||||
if (i % 2 === 0) {
|
||||
//var rObj = { value: facet, count: facet_fields[prop][i + 1] };
|
||||
var rObj = new FilterItem(facet, facet_fields[prop][i + 1])
|
||||
return rObj;
|
||||
}
|
||||
}).filter(function (el) {
|
||||
return el != null && el.count > 0;
|
||||
});
|
||||
this.facets.push({ filterName: prop, values: facetValues });
|
||||
}
|
||||
// console.log(this.facets.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
mounted() {
|
||||
// console.log('Component mounted.')
|
||||
|
|
25
resources/assets/js/search/models/filter-item.js
Normal file
25
resources/assets/js/search/models/filter-item.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
export default class FilterItem {
|
||||
category;
|
||||
value;
|
||||
count;
|
||||
active;
|
||||
|
||||
constructor(value, count) {
|
||||
// this.category = category;
|
||||
this.value = value;
|
||||
this.count = count;
|
||||
this.active = false;
|
||||
this.category = "";
|
||||
}
|
||||
|
||||
get Category() {
|
||||
return this.category;
|
||||
}
|
||||
set Category(theCategory) {
|
||||
this.category = theCategory;
|
||||
}
|
||||
|
||||
set Active(isActive) {
|
||||
this.active = isActive;
|
||||
}
|
||||
}
|
|
@ -2,17 +2,31 @@ import axios from "axios";
|
|||
|
||||
export default {
|
||||
|
||||
async search(term) {
|
||||
async search(term, filterItems) {
|
||||
// solr endpoint
|
||||
// const host = 'http://voyagerdemo.com/';
|
||||
const host = 'https://repository.geologie.ac.at/';
|
||||
const path = 'solr/rdr_data/select';
|
||||
const fields = 'id,server_date_published,abstract_output,title_output,title_additional,author,subject'; // fields we want returned
|
||||
const dismaxFields = "title^3 abstract^2 subject^1";
|
||||
const facetFields = "facet.field=language&facet.field={!key=datatype}doctype";//&fq=year:(2019)";//&facet.query=year:2018";
|
||||
const facetFields = "facet.field=language&facet.field={!key=datatype}doctype&facet.field=subject";//&fq=year:(2019)";//&facet.query=year:2018";
|
||||
|
||||
var filterFields = "";
|
||||
// filterItems.forEach(function (item) {
|
||||
// console.log(item.value + " " + item.category);
|
||||
// filterFields += "&fq=" + item.category +":("+ item.value + ")";
|
||||
// });
|
||||
Object.entries(filterItems).forEach(([key, valueArray]) => {
|
||||
// console.log(`${key} ${valueArray}`);
|
||||
valueArray.forEach(function (value) {
|
||||
filterFields += "&fq=" + key +":("+ value + ")";
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
// $dismax->setQueryFields('title^3 abstract^2 subject^1');
|
||||
const api = `${host}${path}?defType=dismax&q=${term}&fl=${fields}&qf=${dismaxFields}&facet=on&${facetFields}&wt=json&rows=20&indent=on`;
|
||||
const api = `${host}${path}?defType=dismax&q=${term}&fl=${fields}&qf=${dismaxFields}&facet=on&${facetFields}&${filterFields}&wt=json&rows=20&indent=on`;
|
||||
|
||||
const res = await axios.get(api);
|
||||
return res.data;//.response;//.docs;
|
||||
|
|
|
@ -1,67 +1,79 @@
|
|||
import { Component, Vue, Prop, Provide } from 'vue-property-decorator';
|
||||
|
||||
|
||||
|
||||
|
||||
@Component
|
||||
export default class FacetList extends Vue {
|
||||
|
||||
ITEMS_PER_FILTER = 5;
|
||||
bar = 'bar';
|
||||
// filterItems = [];
|
||||
|
||||
ITEMS_PER_FILTER = 2;
|
||||
bar = '';
|
||||
collapsed = true;
|
||||
// filterItems = [];
|
||||
|
||||
@Prop()
|
||||
data;
|
||||
@Prop()
|
||||
@Prop([String])
|
||||
filterName;
|
||||
|
||||
get myLanguageFilters() {
|
||||
// console.log(this.filterName);
|
||||
// console.log(this.data);
|
||||
var facetValues = this.data.map((facet, i) => {
|
||||
if (i % 2 === 0) {
|
||||
// var rObj = {};
|
||||
// rObj['value'] = facet;
|
||||
// rObj['count'] = solrArray[i +1];
|
||||
var rObj = { value: facet, count: this.data[i + 1] };
|
||||
return rObj;
|
||||
}
|
||||
}).filter(function (el) {
|
||||
return el != null && el.count > 0;
|
||||
});
|
||||
// var facetValues = this.data.language.filter(function(facet, i) {
|
||||
// return i % 2 === 0;
|
||||
// }).map(function (facet, i) {
|
||||
// var rObj = { value: facet, count: this.data.language[i + 1] };
|
||||
// return rObj;
|
||||
// }, this);
|
||||
return facetValues;
|
||||
};
|
||||
|
||||
get facets() {
|
||||
return this.data;
|
||||
};
|
||||
@Prop([String])
|
||||
// alias;
|
||||
|
||||
get alias() {
|
||||
return this.filterName == 'datatype' ? 'doctype' : this.filterName
|
||||
}
|
||||
// get filterItems() {
|
||||
// var facetValues = this.data.map((facet, i) => {
|
||||
// if (i % 2 === 0) {
|
||||
// // var rObj = {};
|
||||
// // rObj['value'] = facet;
|
||||
// // rObj['count'] = solrArray[i +1];
|
||||
// var rObj = { value: facet, count: this.data[i + 1], category: this.alias };
|
||||
// return rObj;
|
||||
// }
|
||||
// }).filter(function (el) {
|
||||
// return el != null && el.count > 0;
|
||||
// });
|
||||
// // var facetValues = this.data.language.filter(function(facet, i) {
|
||||
// // return i % 2 === 0;
|
||||
// // }).map(function (facet, i) {
|
||||
// // var rObj = { value: facet, count: this.data.language[i + 1] };
|
||||
// // return rObj;
|
||||
// // }, this);
|
||||
// return facetValues;
|
||||
// }
|
||||
get filterItems() {
|
||||
var facetValues = this.data.map((facet, i) => {
|
||||
if (i % 2 === 0) {
|
||||
// var rObj = {};
|
||||
// rObj['value'] = facet;
|
||||
// rObj['count'] = solrArray[i +1];
|
||||
var rObj = { value: facet, count: this.data[i + 1] };
|
||||
return rObj;
|
||||
}
|
||||
}).filter(function (el) {
|
||||
return el != null && el.count > 0;
|
||||
});
|
||||
// var facetValues = this.data.language.filter(function(facet, i) {
|
||||
// return i % 2 === 0;
|
||||
// }).map(function (facet, i) {
|
||||
// var rObj = { value: facet, count: this.data.language[i + 1] };
|
||||
// return rObj;
|
||||
// }, this);
|
||||
return facetValues;
|
||||
};
|
||||
return this.data;
|
||||
}
|
||||
|
||||
mounted() {
|
||||
};
|
||||
get overflowing() {
|
||||
//ko.observable(self.filterItems().length - self.activeFilterItems().length > ITEMS_PER_FILTER);
|
||||
return (this.filterItems.length) > this.ITEMS_PER_FILTER;
|
||||
}
|
||||
|
||||
get uncollapseLabelText() {
|
||||
if (this.collapsed == true) {
|
||||
// return myLabels.viewer.sidePanel.more; //"More results";
|
||||
return "More results";
|
||||
}
|
||||
else {
|
||||
// return myLabels.viewer.sidePanel.collapse; //"Collapse";
|
||||
return "Collapse";
|
||||
}
|
||||
}
|
||||
|
||||
toggle = function () {
|
||||
if (this.collapsed == true) {
|
||||
this.collapsed = false;
|
||||
}
|
||||
else if (this.collapsed == false) {
|
||||
this.collapsed = true;
|
||||
//list.children("li:gt(4)").hide();
|
||||
}
|
||||
}
|
||||
|
||||
activateItem = function (filterItem) {
|
||||
filterItem.Category = this.alias;
|
||||
filterItem.Active = true;
|
||||
this.$emit("filter", filterItem);
|
||||
}
|
||||
|
||||
mounted() {
|
||||
}
|
||||
}
|
|
@ -5,28 +5,24 @@
|
|||
<div class="panel panel-primary">
|
||||
<h3 class="panel-title filterViewModelName">{{ filterName }}</h3>
|
||||
<!-- e.g.language -->
|
||||
<ul
|
||||
class="filter-items"
|
||||
v-for="(value, index) in myLanguageFilters"
|
||||
:key="index"
|
||||
v-bind:class="{'limited':filterItems.length > 1}"
|
||||
>
|
||||
<li class="active" role="radio">
|
||||
<input
|
||||
<ul class="filter-items" v-bind:class="{'limited':filterItems.length > 1 && collapsed }">
|
||||
<li v-for="(item, index) in filterItems" :key="index" class="list-group-item">
|
||||
<!-- <input
|
||||
class="css-w1gpbi"
|
||||
name="language"
|
||||
v-bind:id="value.value"
|
||||
v-bind:id="item.value"
|
||||
type="radio"
|
||||
v-bind:value="value.value"
|
||||
v-bind:value="item.value"
|
||||
/>
|
||||
<label :for="value.value">
|
||||
<span>{{ value.value }} ({{ value.count }})</span>
|
||||
</label>
|
||||
<label :for="item.value">
|
||||
<span click: @click="activateItem(item)">{{ item.value }} ({{ item.count }})</span>
|
||||
</label>-->
|
||||
<a :class="Active ? 'disabled' : ''" @click.prevent="activateItem(item)">{{ item.value }} ({{ item.count }})</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="overflowing">
|
||||
<ul class="overflowing" v-if="overflowing == true">
|
||||
<li>
|
||||
<span @click="toggle()"></span>
|
||||
<span @click="toggle()">{{ uncollapseLabelText }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -35,4 +31,12 @@
|
|||
<script lang="ts">
|
||||
import FacetList from "./facet-list-class";
|
||||
export default FacetList;
|
||||
</script>
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* local styles */
|
||||
.disabled {
|
||||
color: lightgrey;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue
Block a user