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* ...@@ -6,6 +6,7 @@ yarn-debug.log*
yarn-error.log* yarn-error.log*
yarn.lock yarn.lock
package-lock.json package-lock.json
*.tar
# Windows Start scripts # Windows Start scripts
*.bat *.bat
......
...@@ -143,9 +143,7 @@ app.get('/api/search', function (req, res) { ...@@ -143,9 +143,7 @@ app.get('/api/search', function (req, res) {
let query = { let query = {
element: req.query.element, element: req.query.element,
content: req.query.content, content: req.query.content
attribute: req.query.attribute,
value: req.query.value
} }
let data = [] let data = []
......
const flat = require('flat') // Arrays const flatten = require('flatten') // Flatten Objects
const flatten = require('flatten') // Objects
function has (object, key) {
/*
* Check if object has a key
*/
return object ? hasOwnProperty.call(object, key) : false
}
function findKeyRecursive (object, keytofind, ret = []) { function findKeyRecursive (object, keytofind, ret = []) {
/* /*
...@@ -41,49 +47,49 @@ function countReferences (features) { ...@@ -41,49 +47,49 @@ function countReferences (features) {
return count 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 = [] let results = []
Object.keys(obj).forEach(function (key) { try {
// Attributes var reContent = new RegExp(query.content)
if (typeof query.attribute !== 'undefined') { } catch (err) {
const reAttr = new RegExp('_attributes.' + query.attribute) console.log(arguments.callee) // eslint-disable-line no-caller
if (!reAttr.test(key)) { console.log('>> Error while searching elements')
return return results
}
}
// 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
} }
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 return document
let res = {}
res[key] = obj[key]
results.push(res)
})
return results
} }
function searchInFeatures (features, query) { function searchInFeatures (features, query) {
...@@ -129,30 +135,7 @@ function searchFeaturesInDocument (document, query) { ...@@ -129,30 +135,7 @@ function searchFeaturesInDocument (document, query) {
let results = searchInFeatures(features, query) let results = searchInFeatures(features, query)
if (results.length > 0) { if (results.length > 0) {
document['count'] = countReferences(results) document['hits'] = 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['results'] = results document['results'] = results
} else { } else {
return null return null
......
{ {
"name": "cdbp", "name": "cdbp",
"version": "1.0.0", "version": "1.0.1",
"description": "FAU CDBP", "description": "FAU CDBP",
"author": "Markus Opolka <markus@martialblog.de>", "author": "Markus Opolka <markus@martialblog.de>",
"private": true, "private": true,
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
}, },
"dependencies": { "dependencies": {
"express": "^4.16.2", "express": "^4.16.2",
"flat": "^4.0.0",
"flatten": "^1.0.2", "flatten": "^1.0.2",
"memory-cache": "^0.2.0", "memory-cache": "^0.2.0",
"vue": "^2.5.2", "vue": "^2.5.2",
......
...@@ -71,32 +71,7 @@ ...@@ -71,32 +71,7 @@
<!-- Search Results --> <!-- Search Results -->
<v-flex xs12 v-if="results"> <v-flex xs12 v-if="results">
<v-card v-for="letter in results" v-bind:key="letter.url"> <result :letter="letter" 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>
</v-flex> </v-flex>
</v-layout> </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 @@ ...@@ -13,8 +13,9 @@
<v-card> <v-card>
<v-card-text class="grey lighten-3"> <v-card-text class="grey lighten-3">
<p>Content in an element: <strong>element:content</strong> (Regular Expressions are supported)</p> <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>If no element is provided, the text will be searched.</p>
<p>Attribute and content: <strong>element@attribute=value:content</strong></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-text>
</v-card> </v-card>
</v-expansion-panel-content> </v-expansion-panel-content>
...@@ -59,30 +60,13 @@ ...@@ -59,30 +60,13 @@
<v-card color="blue-grey lighten-1" class="white--text"> <v-card color="blue-grey lighten-1" class="white--text">
<v-card-text> <v-card-text>
Results: {{results.length}} letter(s) 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-text>
</v-card> </v-card>
</v-flex> </v-flex>
<!-- Search Results --> <!-- Search Results -->
<v-flex xs12 v-if="results"> <v-flex xs12 v-if="results">
<v-card v-for="letter in results" v-bind:key="letter.url"> <result :letter="letter" 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>
</v-flex> </v-flex>
</v-layout> </v-layout>
...@@ -98,10 +82,7 @@ export default { ...@@ -98,10 +82,7 @@ export default {
header: 'Search', header: 'Search',
invalid: false, invalid: false,
search: '', search: '',
pattern: [ pattern: '^([a-z]+):(.+)',
'([a-z]+)@([a-z]+=[a-z0-9]+)(:.+)?',
'^([a-z]+):(.+)'
],
results: null, results: null,
searching: false, searching: false,
cutoff: 100, cutoff: 100,
...@@ -109,36 +90,8 @@ export default { ...@@ -109,36 +90,8 @@ export default {
} }
}, },
methods: { methods: {
parse () { find (params) {
let match = '' // Call search API
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()
// Remove undefined values // Remove undefined values
Object.keys(params).forEach((key) => (params[key] == null) && delete params[key]) Object.keys(params).forEach((key) => (params[key] == null) && delete params[key])
this.searching = true this.searching = true
...@@ -149,32 +102,29 @@ export default { ...@@ -149,32 +102,29 @@ export default {
}, },
validate () { validate () {
// Validate input field // Validate input field
this.search.toLowerCase() let search = this.search.split(':')
const validator = new RegExp(this.pattern.join('|')) // If no element is entered we search the text <l>
if (validator.test(this.search)) { if (typeof search[1] === 'undefined') {
this.invalid = false search.unshift('l')
this.find() }
} else {
let params = {
element: search[0],
content: search[1]
}
if (!params.content) {
this.invalid = true this.invalid = true
} else {
this.invalid = false
this.find(params)
} }
}, },
clear () { clear () {
// Clear input field // Clear input field
this.invalid = false this.invalid = false
this.search = '' 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' ...@@ -6,12 +6,14 @@ import VueResource from 'vue-resource'
import App from './App' import App from './App'
import router from './router' import router from './router'
import Feature from './components/Feature' import Feature from './components/Feature'
import Result from './components/Result'
import '../node_modules/vuetify/dist/vuetify.min.css' import '../node_modules/vuetify/dist/vuetify.min.css'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(Vuetify) Vue.use(Vuetify)
Vue.use(VueResource) Vue.use(VueResource)
Vue.component('feature', Feature) Vue.component('feature', Feature)
Vue.component('result', Result)
/* eslint-disable no-new */ /* eslint-disable no-new */
new Vue({ 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