Commit 33529b92 authored by Markus Opolka's avatar Markus Opolka
Browse files

Merge branch 'fixsearch' into 'master'

Refactor Search

See merge request bi40resu/vue-letters!1
parents 46865ec0 e5443683
......@@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log*
yarn.lock
package-lock.json
*.tar
# Windows Start scripts
*.bat
......
......@@ -143,9 +143,7 @@ app.get('/api/search', function (req, res) {
let query = {
element: req.query.element,
content: req.query.content,
attribute: req.query.attribute,
value: req.query.value
content: req.query.content
}
let data = []
......
const flat = require('flat') // Arrays
const flatten = require('flatten') // Objects
const flatten = require('flatten') // Flatten Objects
function has (object, key) {
/*
* Check if object has a key
*/
return object ? hasOwnProperty.call(object, key) : false
}
function findKeyRecursive (object, keytofind, ret = []) {
/*
......@@ -41,49 +47,49 @@ function countReferences (features) {
return count
}
function searchInObject (obj, query) {
function searchInElements (elements, query) {
/*
* Search for query in a fiven flatobject
* Searches for a query in an array of elemts
*/
let results = []
Object.keys(obj).forEach(function (key) {
// Attributes
if (typeof query.attribute !== 'undefined') {
const reAttr = new RegExp('_attributes.' + query.attribute)
if (!reAttr.test(key)) {
return
}
}
// Values
if (typeof query.value !== 'undefined') {
const reVal = new RegExp(query.value)
if (!reVal.test(obj[key])) {
return
}
}
// Elements
if (typeof query.element !== 'undefined') {
const reElem = new RegExp('[^_]' + query.element, 'g')
if (!reElem.test(key)) {
return
try {
var reContent = new RegExp(query.content)
} catch (err) {
console.log(arguments.callee) // eslint-disable-line no-caller
console.log('>> Error while searching elements')
return results
}
for (let idx = 0; idx < elements.length; idx++) {
var matchContent = reContent.test(elements[idx]._text)
if (matchContent) {
results.push(elements[idx])
}
// Content
if (typeof query.content !== 'undefined') {
const reCont = new RegExp(query.content)
if (!reCont.test(obj[key])) {
return
}
return results
}
function searchInDocument (document, query) {
/*
* Search for text in (js) document elements
*/
let elems = findKeyRecursive(document, query.element)
let results = searchInElements(elems, query)
if (results.length > 0) {
document['results'] = results
document['hits'] = undefined
} else {
return null
}
// Add hit to results as object
let res = {}
res[key] = obj[key]
results.push(res)
})
return document
return results
}
function searchInFeatures (features, query) {
......@@ -129,30 +135,7 @@ function searchFeaturesInDocument (document, query) {
let results = searchInFeatures(features, query)
if (results.length > 0) {
document['count'] = countReferences(results)
document['results'] = results
} else {
return null
}
return document
}
function searchInDocument (document, query) {
/*
* Search for query in (js) document
*/
let faltobject = {}
try {
flatobject = flat(document.object.TEI)
} catch (err) {
console.log(arguments.callee) // eslint-disable-line no-caller
console.log('>> Error while searching')
}
let results = searchInObject(flatobject, query)
if (results.length > 0) {
document['hits'] = countReferences(results)
document['results'] = results
} else {
return null
......
{
"name": "cdbp",
"version": "1.0.0",
"version": "1.0.1",
"description": "FAU CDBP",
"author": "Markus Opolka <markus@martialblog.de>",
"private": true,
......@@ -13,7 +13,6 @@
},
"dependencies": {
"express": "^4.16.2",
"flat": "^4.0.0",
"flatten": "^1.0.2",
"memory-cache": "^0.2.0",
"vue": "^2.5.2",
......
......@@ -71,32 +71,7 @@
<!-- Search Results -->
<v-flex xs12 v-if="results">
<v-card v-for="letter in results" v-bind:key="letter.url">
<v-card-title primary-title>
{{letter.name}} <v-chip label color="lime accent-4">{{letter.collection}}</v-chip>
<v-chip color="indigo" text-color="white">
<v-avatar class="indigo darken-4">{{letter.count}}</v-avatar>
Hits
</v-chip>
</v-card-title>
<v-card-text>
<ul style="list-style-type:none;">
<li v-for="hit in letter.results">
<v-chip outline small color="secondary">{{hit._text}}</v-chip>
<v-chip label small>
<span v-if="hit._attributes.category">Category: {{(hit._attributes.category)}}</span>
<span v-if="hit._attributes.type">, Type: {{(hit._attributes.type)}}</span>
<span v-if="hit._attributes.subtype">, Subtype: {{(hit._attributes.subtype)}}</span>
</v-chip>
<v-chip label small text-color="white" color="deep-orange darken-4" v-if="hit._attributes.ref">Line: {{(hit._attributes.ref)}}</v-chip>
</li>
</ul>
</v-card-text>
<v-card-actions>
<v-btn :to="letter.link" flat>View</v-btn>
</v-card-actions>
</v-card>
<result :letter="letter" v-for="letter in results" v-bind:key="letter.url" />
</v-flex>
</v-layout>
......
<template>
<v-card>
<v-card-title primary-title>
<span class="title">{{letter.name}}</span><v-chip label color="lime accent-4">{{letter.collection}}</v-chip>
<v-chip color="indigo" text-color="white" v-if="letter.hits">
<v-avatar class="indigo darken-4">{{letter.hits}}</v-avatar>
Hits
</v-chip>
</v-card-title>
<v-card-text>
<ul style="list-style-type:none;">
<li v-for="hit in letter.results">
<v-chip outline small color="secondary"> {{hit._text}} </v-chip>
<v-chip label small v-if="has(hit, '_attributes')">
<span v-if="has(hit._attributes, 'no')" >Line: {{(hit._attributes.no)}}</span>
<span v-if="has(hit._attributes, 'category')" >Category: {{(hit._attributes.category)}}</span>
<span v-if="has(hit._attributes, 'type')" >, Type: {{(hit._attributes.type)}}</span>
<span v-if="has(hit._attributes, 'subtype')" >, Subtype: {{(hit._attributes.subtype)}}</span>
</v-chip>
<v-chip label small
text-color="white"
color="deep-orange darken-4"
v-if="has(hit._attributes, 'ref')">
Line: {{(hit._attributes.ref)}}
</v-chip>
</li>
</ul>
</v-card-text>
<v-card-actions>
<v-btn :to="letter.link" flat>View</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
export default {
// Component for Results in Search
data () {
return {
data: null
}
},
methods: {
has (object, key) {
return object ? hasOwnProperty.call(object, key) : false
}
},
props: {
letter: null
}
}
</script>
......@@ -13,8 +13,9 @@
<v-card>
<v-card-text class="grey lighten-3">
<p>Content in an element: <strong>element:content</strong> (Regular Expressions are supported)</p>
<p>Attribute of an element: <strong>element@attribute=value</strong></p>
<p>Attribute and content: <strong>element@attribute=value:content</strong></p>
<p>If no element is provided, the text will be searched.</p>
<!-- <p>Attribute of an element: <strong>element@attribute=value</strong></p> -->
<!-- <p>Attribute and content: <strong>element@attribute=value:content</strong></p> -->
</v-card-text>
</v-card>
</v-expansion-panel-content>
......@@ -59,30 +60,13 @@
<v-card color="blue-grey lighten-1" class="white--text">
<v-card-text>
Results: {{results.length}} letter(s)
<v-slider v-model="cutoff" min="20" max="255" thumb-label dark></v-slider>
<v-checkbox label="Show Labels" v-model="showlabels" dark></v-checkbox>
</v-card-text>
</v-card>
</v-flex>
<!-- Search Results -->
<v-flex xs12 v-if="results">
<v-card v-for="letter in results" v-bind:key="letter.url">
<v-card-title primary-title>
{{letter.name}} <v-chip label color="lime accent-4">{{letter.collection}}</v-chip>
</v-card-title>
<v-card-text>
<ul style="list-style-type:none;">
<li v-for="hit in letter.results">
<v-chip outline small color="secondary">{{getValue(hit)}}</v-chip>
<v-chip label small v-if="showlabels">{{getKey(hit)}}</v-chip>
</li>
</ul>
</v-card-text>
<v-card-actions>
<v-btn :to="letter.link" flat>View</v-btn>
</v-card-actions>
</v-card>
<result :letter="letter" v-for="letter in results" v-bind:key="letter.url" />
</v-flex>
</v-layout>
......@@ -98,10 +82,7 @@ export default {
header: 'Search',
invalid: false,
search: '',
pattern: [
'([a-z]+)@([a-z]+=[a-z0-9]+)(:.+)?',
'^([a-z]+):(.+)'
],
pattern: '^([a-z]+):(.+)',
results: null,
searching: false,
cutoff: 100,
......@@ -109,36 +90,8 @@ export default {
}
},
methods: {
parse () {
let match = ''
let regex = ''
let params = {
element: undefined,
content: undefined,
attribute: undefined,
value: undefined
}
// Parse the input
if (this.search.indexOf('@') > 0) {
regex = new RegExp(this.pattern[0])
match = regex.exec(this.search)
params.element = match[1]
params.attribute = match[2].split('=')[0]
params.value = match[2].split('=')[1]
if (match[3]) params.content = match[3].replace(':', '')
} else {
regex = new RegExp(this.pattern[1])
match = regex.exec(this.search)
params.element = match[1]
params.content = match[2]
}
return params
},
find () {
// Parse input field and call search API
let params = this.parse()
find (params) {
// Call search API
// Remove undefined values
Object.keys(params).forEach((key) => (params[key] == null) && delete params[key])
this.searching = true
......@@ -149,32 +102,29 @@ export default {
},
validate () {
// Validate input field
this.search.toLowerCase()
let search = this.search.split(':')
const validator = new RegExp(this.pattern.join('|'))
if (validator.test(this.search)) {
this.invalid = false
this.find()
} else {
// If no element is entered we search the text <l>
if (typeof search[1] === 'undefined') {
search.unshift('l')
}
let params = {
element: search[0],
content: search[1]
}
if (!params.content) {
this.invalid = true
} else {
this.invalid = false
this.find(params)
}
},
clear () {
// Clear input field
this.invalid = false
this.search = ''
},
getValue (obj) {
// Get value of unknown key in object
let key = Object.keys(obj)[0]
return obj[key].substr(0, this.cutoff)
},
getKey (obj) {
// Get unknown first key from object
let key = Object.keys(obj)[0]
key = key.replace('teiHeader.xenoData.', '')
key = key.replace(/.[0-9]._text/, '')
return key
}
}
}
......
......@@ -6,12 +6,14 @@ import VueResource from 'vue-resource'
import App from './App'
import router from './router'
import Feature from './components/Feature'
import Result from './components/Result'
import '../node_modules/vuetify/dist/vuetify.min.css'
Vue.config.productionTip = false
Vue.use(Vuetify)
Vue.use(VueResource)
Vue.component('feature', Feature)
Vue.component('result', Result)
/* eslint-disable no-new */
new Vue({
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment