diff --git a/.gitignore b/.gitignore index 316521ea0a3ad3183cecc63fc047b0044fefe152..5e667979e4f63cab8ecbd93c8ccc2418a2841645 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ yarn-debug.log* yarn-error.log* yarn.lock package-lock.json +*.tar # Windows Start scripts *.bat diff --git a/app.js b/app.js index 9b9874d2791e2743bc63652a21bc1c8bec19e3e0..5bcd35a233b1aa6b96e448d17b02348d51058228 100755 --- a/app.js +++ b/app.js @@ -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 = [] diff --git a/lib.js b/lib.js index efcf46815252401a3e8ca384f4f56c88e5233cae..76f7d70af88f5777951c1a3e9222688ef5ba5368 100755 --- a/lib.js +++ b/lib.js @@ -1,5 +1,11 @@ -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,51 +47,51 @@ 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 - } - } - // Content - if (typeof query.content !== 'undefined') { - const reCont = new RegExp(query.content) - if (!reCont.test(obj[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 + } - // Add hit to results as object - let res = {} - res[key] = obj[key] - results.push(res) - }) + for (let idx = 0; idx < elements.length; idx++) { + var matchContent = reContent.test(elements[idx]._text) + + if (matchContent) { + results.push(elements[idx]) + } + } 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 + } + + return document + +} + function searchInFeatures (features, query) { /* * Searches for a query in an array of features @@ -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 diff --git a/package.json b/package.json index c47ecc7e84a5042a79a59fc7949168fcabcb52cf..ebb0f0f072cf930cf516a4a3ea65196eede58713 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/Features.vue b/src/components/Features.vue index 0efcd2bce5974c4f79863b4cf5c1a0f0f833795a..067bbd30ce3e1b2377c67f658bbbb89ff4758a90 100644 --- a/src/components/Features.vue +++ b/src/components/Features.vue @@ -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> diff --git a/src/components/Result.vue b/src/components/Result.vue new file mode 100644 index 0000000000000000000000000000000000000000..534ebba3e4c2d025579efef68f1f4a6e7f01b441 --- /dev/null +++ b/src/components/Result.vue @@ -0,0 +1,55 @@ +<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> diff --git a/src/components/Search.vue b/src/components/Search.vue index 9515c719ec01edf1c81ea77f5372045374dfcaf7..9c7b9efb04652a050a1b3afa9c4667a3a9b48399 100644 --- a/src/components/Search.vue +++ b/src/components/Search.vue @@ -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 } } } diff --git a/src/main.js b/src/main.js index 85c5335d09bf3d2740b1c4533ad3c70e774be3a8..666f0a6d2a9f6362a685a1a87740f6bedbcc9efd 100644 --- a/src/main.js +++ b/src/main.js @@ -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({