Commit 67469995 authored by Randall Leeds's avatar Randall Leeds

Refactor page search

Refactor the page search rendering algorithm for fewer scope
variables, simpler template expressions, camel case, support
for holes in threads, less looping, conciseness and readability.
parent 5736d80b
This diff is collapsed.
......@@ -73,7 +73,7 @@ class SearchFilter
filter = term.slice 0, term.indexOf ":"
unless filter? then filter = ""
switch filter
when 'quote' then quote.push term[6..]
when 'quote' then quote.push term[6..].toLowerCase()
when 'result' then result.push term[7..]
when 'since'
# We'll turn this into seconds
......@@ -109,44 +109,36 @@ class SearchFilter
# Time given in year
t = /^(\d+)year$/.exec(time)[1]
since.push t * 60 * 60 * 24 * 365
when 'tag' then tag.push term[4..]
when 'text' then text.push term[5..]
when 'uri' then uri.push term[4..]
when 'user' then user.push term[5..]
else any.push term
when 'tag' then tag.push term[4..].toLowerCase()
when 'text' then text.push term[5..].toLowerCase()
when 'uri' then uri.push term[4..].toLowerCase()
when 'user' then user.push term[5..].toLowerCase()
else any.push term.toLowerCase()
any:
terms: any
operator: 'and'
lowercase: true
quote:
terms: quote
operator: 'and'
lowercase: true
result:
terms: result
operator: 'min'
lowercase: false
since:
terms: since
operator: 'and'
lowercase: false
tag:
terms: tag
operator: 'and'
lowercase: true
text:
terms: text
operator: 'and'
lowercase: true
uri:
terms: uri
operator: 'or'
lowercase: true
user:
terms: user
operator: 'or'
lowercase: true
# This class will process the results of search and generate the correct filter
......@@ -235,19 +227,6 @@ class QueryParser
and_or: 'and'
fields: ['quote', 'tag', 'text', 'uri', 'user']
parseModels: (models) ->
# Cluster facets together
categories = {}
for searchItem in models
category = searchItem.attributes.category
value = searchItem.attributes.value
if category of categories
categories[category].push value
else
categories[category] = [value]
categories
populateFilter: (filter, query) =>
# Populate a filter with a query object
for category, value of query
......
imports = [
'h.filters',
'h.searchfilters'
]
# The render function accepts a scope and a data object and schedule the scope
# to be updated with the provided data and digested before the next repaint
# using window.requestAnimationFrame() (or a fallback). If the resulting digest
......@@ -501,12 +495,6 @@ class ViewFilter
any:
fields: ['quote', 'text', 'tag', 'user']
this.$inject = ['searchfilter']
constructor: (searchfilter) ->
@searchfilter = searchfilter
_matches: (filter, value, match) ->
matches = true
......@@ -549,17 +537,17 @@ class ViewFilter
value = checker.value annotation
if angular.isArray value
if filter.lowercase then value = value.map (e) -> e.toLowerCase()
if typeof(value[0]) == 'string'
value = value.map (v) -> v.toLowerCase()
return @_arrayMatches filter, value, checker.match
else
value = value.toLowerCase() if filter.lowercase
value = value.toLowerCase() if typeof(value) == 'string'
return @_matches filter, value, checker.match
# Filters a set of annotations, according to a given query.
# Inputs:
# annotations is the input list of annotations (array)
# query is the query string. It will be converted to faceted filter by the SearchFilter
# filters is the query is a faceted filter generated by SearchFilter
#
# It'll handle the annotation matching by the returned facet configuration (operator, lowercase, etc.)
# and the here configured @checkers. This @checkers object contains instructions how to verify the match.
......@@ -577,84 +565,34 @@ class ViewFilter
# matched annotation IDs list,
# the faceted filters
# ]
filter: (annotations, query) =>
filters = @searchfilter.generateFacetedFilter query
results = []
# Check for given limit
# Find the minimal
limit = 0
if filters.result.terms.length
limit = filter.result.terms[0]
for term in filter.result.terms
if limit > term then limit = term
# Convert terms to lowercase if needed
for _, filter of filters
if filter.lowercase then filter.terms.map (e) -> e.toLowerCase()
# Now that this filter is called with the top level annotations, we have to add the children too
annotationsWithChildren = []
for annotation in annotations
annotationsWithChildren.push annotation
children = annotation.thread?.flattenChildren()
if children?.length > 0
for child in children
annotationsWithChildren.push child
for annotation in annotationsWithChildren
matches = true
#ToDo: What about given zero limit?
# Limit reached
if limit and results.length >= limit then break
filter: (annotations, filters) ->
limit = Math.min((filters.result?.terms or [])...)
count = 0
results = for annotation in annotations
break if count >= limit
match = true
for category, filter of filters
break unless matches
terms = filter.terms
# No condition for this category
continue unless terms.length
break unless match
continue unless filter.terms.length
switch category
when 'result'
# Handled above
continue
when 'any'
# Special case
matchterms = []
matchterms.push false for term in terms
categoryMatch = false
for field in @checkers.any.fields
conf = @checkers[field]
continue if conf.autofalse? and conf.autofalse annotation
value = conf.value annotation
if angular.isArray value
if filter.lowercase
value = value.map (e) -> e.toLowerCase()
else
value = value.toLowerCase() if filter.lowercase
matchresult = @_anyMatches filter, value, conf.match
matchterms = matchterms.map (t, i) -> t or matchresult[i]
# Now let's see what we got.
matched = 0
for _, value of matchterms
matched++ if value
if (filter.operator is 'or' and matched > 0) or (filter.operator is 'and' and matched is terms.length)
matches = true
else
matches = false
if @_checkMatch(filter, annotation, @checkers[field])
categoryMatch = true
break
match = categoryMatch
else
# For all other categories
matches = @_checkMatch filter, annotation, @checkers[category]
if matches
results.push annotation.id
[results, filters]
match = @_checkMatch filter, annotation, @checkers[category]
continue unless match
count++
annotation.id
angular.module('h.services', imports)
angular.module('h.services', [])
.factory('render', renderFactory)
.provider('drafts', DraftProvider)
.service('annotator', Hypothesis)
......
......@@ -36,7 +36,7 @@ class StreamSearch
$scope.sort.name = 'Newest'
$scope.shouldShowAnnotation = (id) -> true
$scope.shouldShowThread = (container) -> true
$scope.$watch 'updater', (updater) ->
updater?.then (sock) ->
......
Markdown is supported
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