- 'xsltfile' => "public/solr.xslt"

- search_style.css
- vuejs based solr search
- vuejs facets
This commit is contained in:
Arno Kaimbacher 2019-10-03 18:54:05 +02:00
parent eb4d35ddc1
commit dd2ad2d898
16 changed files with 316 additions and 110 deletions

View File

@ -9,5 +9,5 @@ return [
'core' => env('SOLR_CORE', 'rdr_data') 'core' => env('SOLR_CORE', 'rdr_data')
] ]
], ],
'xsltfile' => "solr.xslt" 'xsltfile' => "public/solr.xslt"
]; ];

File diff suppressed because one or more lines are too long

View File

@ -288,26 +288,23 @@ font-size: 16px;
max-height: 140px; max-height: 140px;
} }
/* overflow for abstracts */
.clamped { .clamped {
line-height: 1.5; line-height: 1.5;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
} }
.clamped-2 { .clamped-2 {
/* Clamp to 2 lines, ie line-height x 2: */ /* Clamp to 2 lines, ie line-height x 2: */
max-height: 6em; max-height: 4.5em;
} }
.ellipsis { .ellipsis {
background: #fff; background: #fff;
bottom: 0; bottom: 0;
position: absolute; position: absolute;
right: 0; right: 0;
} }
.fill { .fill {
background: #fff; background: #fff;
height: 100%; height: 100%;

File diff suppressed because one or more lines are too long

View File

@ -220,7 +220,7 @@
</xsl:for-each> </xsl:for-each>
<!-- subject (uncontrolled) --> <!-- subject (uncontrolled) -->
<xsl:for-each select="/Opus/Rdr_Dataset/Subject[@Type = 'uncontrolled']"> <xsl:for-each select="/Opus/Rdr_Dataset/Subject[@Type = 'Uncontrolled']">
<xsl:element name="field"> <xsl:element name="field">
<xsl:attribute name="name">subject</xsl:attribute> <xsl:attribute name="name">subject</xsl:attribute>
<xsl:value-of select="@Value" /> <xsl:value-of select="@Value" />

View File

@ -1,31 +1,49 @@
<template> <template>
<div> <div class="search-container row">
<!-- <div>{{ bar }}</div> -->
<!-- Search input section --> <div class="four columns left-bar">
<div class="row"> <div id="left-bar" class="sidebar left-bar">
<div class="twelve columns"> <h2 class="indexheader">DataXplore</h2>
<vs-input @search="onSearch"></vs-input>
<!-- <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> </div>
</div> </div>
<!-- Results section --> <div class="eight columns right-bar">
<div class="results"> <div id="right-bar" class="sidebar right-bar">
<div class="card" v-for="item in results" :key="item.id"> <!-- Search input section -->
<img
v-if="item.thumb" <div class="row">
class="card-img-top" <div class="twelve columns">
:src="item.thumb" <vs-input @search="onSearch"></vs-input>
:alt="item.title" </div>
@error="error(item)"
/>
<div class="card-body">
<h5 class="card-title">{{item.name}}</h5>
<!-- <p class="card-text" v-html="truncate(item.description || item.abstract, 50)"></p> -->
</div> </div>
<!-- Results section -->
<vs-results v-bind:data="results"></vs-results>
</div> </div>
</div> </div>
</div> </div>
<!-- <div class="card" v-for="item in results" :key="item.id">
<img
v-if="item.thumb"
class="card-img-top"
:src="item.thumb"
:alt="item.title"
@error="error(item)"
/>
<div class="card-body">
<h5 class="card-title">{{item.name}}</h5>
<p class="card-text" v-html="truncate(item.description || item.abstract, 50)"></p>
</div>
</div>
</div>-->
</template> </template>
<script lang="js"> <script lang="js">

View File

@ -1,20 +1,28 @@
import { Component, Vue, Prop, Provide } from 'vue-property-decorator'; import { Component, Vue, Prop, Provide } from 'vue-property-decorator';
import VsInput from './components/vs-input.vue'; import VsInput from './text-search/vs-input.vue';
import rdrApi from './search-results/search-api'; import VsResults from './search-results/vs-results.vue';
import FacetList from './search-results/facet-list.vue'
import rdrApi from './search-results/dataservice';
@Component({ @Component({
components: { components: {
VsInput VsInput,
VsResults,
FacetList
} }
}) })
export default class App extends Vue { export default class App extends Vue {
results = []; results = [];
facets = [];
bar = 'bar'; bar = 'bar';
async onSearch(term) { async onSearch(term) {
console.log(term); console.log(term);
this.results = await rdrApi.search(term); // this.results = await rdrApi.search(term);
var res = await rdrApi.search(term);
this.results = res.response.docs;
this.facets = res.facet_counts.facet_fields;
} }

View File

@ -2,6 +2,6 @@ import Vue from 'vue';
import App from './App.vue'; import App from './App.vue';
new Vue({ new Vue({
el: '#search-input', el: '#test',
render: h => h(App) render: h => h(App)
}); });

View File

@ -0,0 +1,21 @@
import axios from "axios";
export default {
async search (term) {
// solr endpoint
// const host = 'http://voyagerdemo.com/';
const host = 'http://repository.geologie.ac.at:8983/';
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";//&fq=year:(2019)";//&facet.query=year:2018";
// $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 res = await axios.get(api);
return res.data;//.response;//.docs;
}
}

View File

@ -0,0 +1,61 @@
import { Component, Vue, Prop, Provide } from 'vue-property-decorator';
@Component
export default class FacetList extends Vue {
ITEMS_PER_FILTER = 5;
bar = 'bar';
@Prop()
data;
get myLanguageFilters() {
var facetValues = this.data.language.map((facet, i) => {
if (i % 2 === 0) {
// var rObj = {};
// rObj['value'] = facet;
// rObj['count'] = solrArray[i +1];
var rObj = { value: facet, count: this.data.language[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;
};
mounted() {
};
test(solrArray) {
//this.facetValues = this.data.language.filter((facet, i) => i % 2 === 0);
// var facetValues = this.data.language.map((facet, i) => {
var facetValues = solrArray.map((facet, i) => {
if (i % 2 === 0) {
// var rObj = {};
// rObj['value'] = facet;
// rObj['count'] = solrArray[i +1];
var rObj = { value: facet, count: solrArray[i + 1] };
return rObj;
}
});
// this.facetCounts = this.data.filter((facet, i) => i % 2 === 1);
return facetValues;
}
}

View File

@ -0,0 +1,31 @@
<template>
<div>
<div class="card" v-for="(valueArray, filterName, index) in facets" :key="index">
<!-- <span>property: {{ filterName }}</span>
<span>value: {{ myLanguageFilters }}</span> -->
<div class="panel panel-primary">
<h3 class="panel-title">{{ filterName }}</h3> <!-- e.g.language -->
<ul class="filter-items" v-for="(value, index) in myLanguageFilters" :key="index">
<li class="active" role="radio">
<input
class="css-w1gpbi"
name="language"
v-bind:id="value.value"
type="radio"
v-bind:value="value.value"
/>
<label :for="value.value">
<span>{{ value.value }} ({{ value.count }})</span>
</label>
</li>
</ul>
</div>
</div>
</div>
</template>
<script lang="ts">
import FacetList from "./facet-list-class";
export default FacetList;
</script>

View File

@ -1,18 +0,0 @@
import axios from "axios";
export default {
async search (term) {
// solr endpoint
const host = 'http://voyagerdemo.com/';
const path = 'daily/solr/v0/select';
const fields = 'id,name:[name],thumb:[thumbURL],abstract,description'; // fields we want returned
const api = `${host}${path}?q=${term}&fl=${fields}&wt=json&rows=20`;
const res = await axios.get(api);
// const call = await fetch(api);
// const json = await res.json();
return res.data.response.docs;
}
}

View File

@ -0,0 +1,51 @@
import { Component, Vue, Prop, Provide } from 'vue-property-decorator';
@Component
export default class VsResults extends Vue {
@Prop()
data;
get results() {
return this.data;
};
truncate(text, limit) {
text = text === undefined ? '' : text;
const content = text.split(' ').slice(0, limit);
return content.join(' ');
};
error(item) {
delete item.thumb;
this.$forceUpdate();
};
convert(unixtimestamp) {
// Unixtimestamp
// var unixtimestamp = document.getElementById('timestamp').value;
// Months array
var months_arr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// Convert timestamp to milliseconds
var date = new Date(unixtimestamp * 1000);
// Year
var year = date.getFullYear();
// Month
var month = months_arr[date.getMonth()];
// Day
var day = date.getDate();
// Hours
var hours = date.getHours();
// Minutes
var minutes = "0" + date.getMinutes();
// Seconds
var seconds = "0" + date.getSeconds();
// Display date time in MM-dd-yyyy h:m:s format
var convdataTime = month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
// document.getElementById('datetime').innerHTML = convdataTime;
return convdataTime;
};
}

View File

@ -0,0 +1,63 @@
<template>
<!-- <div class="card-columns" >
<div class="card" v-for="item in results" :key="item.id">
<img v-if="item.thumb" class="card-img-top" :src="item.thumb" :alt="item.title" @error="error(item)">
<div class="card-body">
<h5 class="card-title">{{item.name}}</h5>
<p class="card-text" v-html="truncate(item.description || item.abstract, 50)"></p>
</div>
</div>
</div>-->
<div class="results">
<div class="result-list-info">
<div class="resultheader">
Your search yielded
<strong>{{ results.length }}</strong> results:
</div>
</div>
<section class="result-list-container">
<div class="row">
<ul class="search-items isotope js-isotope u-cf">
<li v-for="document in results" :key="document.id" class="six columns post">
<div class="search-detail">
<div>
<a
v-bind:href="'dataset/' + document.id"
>{{ document.title_output }}</a>
</div>
{{ convert(document.server_date_published) }}
<p v-if="document.title_additional && document.title_additional.length > 0">
<em>Additional Title:{{ document.title_additional.join(', ') }}</em>
</p>
<div v-if="document.author && document.author.length > 0">
<em>Author: {{ document.author.join(', ') }}</em>
</div>
<p class="clamped clamped-2">
<span class="text">
Abstract: {{ document.abstract_output }}
<span class="ellipsis">...</span>
<span class="fill"></span>
</span>
</p>
<div class="css-subject" v-if="document.subject && document.subject.length > 0">
<div v-for="(item, index) in document.subject" :key="index" class="css-keyword">#{{ item }}</div>
<!-- <div class="css-keyword">#graphql</div> -->
</div>
</div>
</li>
</ul>
</div>
</section>
</div>
</template>
<script lang="ts">
import VgResults from "./vs-results-class";
export default VgResults;
</script>

View File

@ -1,18 +1,20 @@
<template> <template>
<div class="sidebar-simplesearch"> <div class="sidebar-simplesearch">
<form method="GET" action="//repository.geologie.ac.at/search" accept-charset="UTF-8"> <!-- <form method="GET" action="//repository.geologie.ac.at/search" accept-charset="UTF-8"> -->
<div>
<input <input
class="search-input" class="search-input"
placeholder="Enter your search term..." placeholder="Enter your search term..."
name="q" name="q"
type="text" type="text"
v-model="term" v-model="term" v-on:keyup.enter="search()"
/> />
<!-- <button @click="search()" class="css-1gklxk5 ekqohx90"> --> <!-- <button @click="search()" class="css-1gklxk5 ekqohx90"> -->
<button class="css-1gklxk5 ekqohx90"> <button class="css-1gklxk5 ekqohx90">
<svg <svg
alt="Search" alt="Search"
@click="search()"
class="search-icon" class="search-icon"
height="14" height="14"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -24,7 +26,7 @@
/> />
</svg> </svg>
</button> </button>
</form> </div>
</div> </div>
</template> </template>

View File

@ -7,40 +7,18 @@
<section data-sr id="search" class="search normal u-full-width"> <section data-sr id="search" class="search normal u-full-width">
{{-- <div class="container"> --}} {{-- <div class="container"> --}}
{{-- <div class="row">
<div class="twelve columns">
<div class="content">
<div class="sidebar-simplesearch">
{{ Form::open(array('method' => 'GET')) }}
{!! Form::text('q', Input::get('q'), array('class'=>'search-input',
'placeholder'=>'Enter your search term')) !!}
<span class="input-group-btn">
<button type="submit">
<i class="fa fa-search"></i>
</button>
</span>
{{ Form::close() }}
</div>
</div>
</div>
</div> --}}
<!-- SEARCH RESULTS GO HERE, EXACTLY AS BEFORE --> <!-- SEARCH RESULTS GO HERE, EXACTLY AS BEFORE -->
<div id="test" class="search-container row">
<div class="search-container row"> {{-- <div class="four columns left-bar">
<div id="left-bar" class="sidebar left-bar">
<div class="four columns left-bar">
<div class="sidebar left-bar">
{{-- <h3 class="indexheader">Refine by</h3> --}}
<h2 class="indexheader">DataXplore</h2> <h2 class="indexheader">DataXplore</h2>
@if (isset($resultset)) @if (isset($resultset))
<?php $facet = $resultset->getFacetSet()->getFacet('language'); ?>
<div class="panel panel-primary"> <div class="panel panel-primary">
<h3 class="panel-title">Language</h3> <h3 class="panel-title">Language</h3>
<ul class="filter-items"> <ul class="filter-items">
@foreach ($facet as $value => $count) @foreach ($facet as $value => $count)
@if ($count) @if ($count)
@ -48,58 +26,51 @@
<input class="css-w1gpbi" name="language" id="{{ $value }}" type="radio" <input class="css-w1gpbi" name="language" id="{{ $value }}" type="radio"
value="{{ $value }}"> value="{{ $value }}">
<label for="{{ $value }}"><span>{{ $value }} ({{ $count }}) </span></label> <label for="{{ $value }}"><span>{{ $value }} ({{ $count }}) </span></label>
</li> </li>
{{-- <li class="list-group-item">
<a class="firstLabel"
href="?{{ http_build_query(array_merge(Input::all(), array('language' => $value))) }}">{{ $value }}</a>
<span class="badge">{{ $count }}</span>
</li> --}}
@endif @endif
@endforeach @endforeach
</ul> </ul>
</div> </div>
<?php $facet = $resultset->getFacetSet()->getFacet('datatype'); ?>
<div class="panel panel-primary"> <div class="panel panel-primary">
{{-- <h3 class="panel-title">Datatype</h3> --}}
<h3 class="panel-title">Data Type</h3> <h3 class="panel-title">Data Type</h3>
<ul class="filterItems"> <ul class="filterItems">
@foreach ($facet as $value => $count) @foreach ($facet as $value => $count)
@if ($count) @if ($count)
<li class="list-group-item"> <li class="list-group-item">
<a class="firstLabel" <a class="firstLabel"
href="?{{ http_build_query(array_merge(Input::all(), array('datatype' => $value))) }}">{{ $value }} ({{ $count }})</a> href="?{{ http_build_query(array_merge(Input::all(), array('datatype' => $value))) }}">{{ $value }} ({{ $count }})</a>
{{-- <span class="badge">{{ $count }}</span> --}}
</li> </li>
@endif @endif
@endforeach @endforeach
</ul> </ul>
</div> </div>
<?php $facet = $resultset->getFacetSet()->getFacet('year'); ?>
<div class="panel panel-primary"> <div class="panel panel-primary">
<h3 class="panel-title">Year</h3> <h3 class="panel-title">Year</h3>
<ul class="filterItems"> <ul class="filterItems">
@foreach ($facet as $value => $count) @foreach ($facet as $value => $count)
@if ($count) @if ($count)
<li class="list-group-item"> <li class="list-group-item">
<a class="firstLabel" <a class="firstLabel"
href="?{{ http_build_query(array_merge(Input::all(), array('year' => $value))) }}">{{ $value }} ({{ $count }})</a> href="?{{ http_build_query(array_merge(Input::all(), array('year' => $value))) }}">{{ $value }} ({{ $count }})</a>
{{-- <span class="badge">{{ $count }}</span> --}}
</li> </li>
@endif @endif
@endforeach @endforeach
</ul> </ul>
</div> </div>
@endif @endif
</div>
</div>
<div class="eight columns right-bar"> </div>
<div class="sidebar right-bar"> </div> --}}
<div id="search-input"></div>
{{-- <div class="row">
{{--<div class="eight columns right-bar">
<div id="right-bar" class="sidebar right-bar">
<div class="row">
<div class="twelve columns"> <div class="twelve columns">
<div class="sidebar-simplesearch"> <div class="sidebar-simplesearch">
{{ Form::open(array('method' => 'GET')) }} {{ Form::open(array('method' => 'GET')) }}
@ -122,8 +93,8 @@
</div> </div>
</div> --}} </div> --}}
@if (isset($resultset)) {{-- @if (isset($resultset))
<div class="results"> <section class="results">
<div class="result-list-info"> <div class="result-list-info">
<div class="resultheader"> <div class="resultheader">
Your search yielded <strong>{{ $resultset->getNumFound() }}</strong> results: Your search yielded <strong>{{ $resultset->getNumFound() }}</strong> results:
@ -175,10 +146,11 @@
</ul> </ul>
</div> </div>
</section> </section>
</div> </section>
@endif @endif
</div> </div>
</div> </div>--}}
</div> </div>