Commit 804f2f34 authored by Randall Leeds's avatar Randall Leeds

Simplify visualsearch usage in app controller

Make a directive for visualsearch that eases integration by taking
care of digest cycles and providing declarative binding for events.

Remove the state tracking with inSearch and will_search and replace
it by reflect the search directly in the query string.
parent 5bfb0834
...@@ -227,29 +227,34 @@ class App ...@@ -227,29 +227,34 @@ class App
$rootScope.applySort "Location" $rootScope.applySort "Location"
# Clean up the searchbar $scope.query = $location.search()
$scope.leaveSearch = =>
# Got back from search page $scope.search = (searchCollection) ->
$scope.show_search = false return unless annotator.discardDrafts()
# We have to call all these internal methods matched = []
# of VS, because the public API does not have query =
# a method for clearing search. tags: []
@visualSearch.searchBox.disableFacets(); quote: []
@visualSearch.searchBox.value('');
@visualSearch.searchBox.flags.allSelected = false;
$scope.$on '$routeChangeStart', (current, next) -> for item in searchCollection.models
return unless next.$$route? {category, value} = item.attributes
# Will we be in search mode after this change? # Stuff we need to collect
willSearch = next.$$route?.controller is "SearchController" switch
when category in ['text', 'user', 'time', 'group']
query[category] = value
when category == 'tag'
# Tags are specials, because we collect those into an array
query.tags.push value.toLowerCase()
when category == 'quote'
query.quote = query.quote.concat(value.split(/\s+/))
if $scope.inSearch and not willSearch $location.path('/page_search').search(query)
# We were in search mode, but we are leaving it now.
$scope.leaveSearch()
$scope.inSearch = willSearch $scope.searchClear = ->
$location.url('/viewer')
$scope.show_search = false
# Update scope with auto-filled form field values # Update scope with auto-filled form field values
$timeout -> $timeout ->
...@@ -259,86 +264,6 @@ class App ...@@ -259,86 +264,6 @@ class App
$i.triggerHandler('input') $i.triggerHandler('input')
, 200 # We hope this is long enough , 200 # We hope this is long enough
search_query = ''
@visualSearch = VS.init
container: $element.find('.visual-search')
query: search_query
callbacks:
search: (query, searchCollection) =>
unless query
if $scope.inSearch
$location.path('/viewer')
$rootScope.$digest()
return
return unless annotator.discardDrafts()
matched = []
parsedQuery =
text: ''
tags: []
quote: []
for searchItem in searchCollection.models
category = searchItem.attributes.category
value = searchItem.attributes.value
# Stuff we need to collect
if category in ['text', 'user', 'time', 'group']
parsedQuery[category] = value
# Tags are specials, because we collect those into an array
if category in ['tag']
parsedQuery[category].push value.toLowerCase()
if category in ['quote']
parsedQuery[category].push val.toLowerCase() for val in value.split ' '
annotations = $rootScope.annotations
matchingIDs = viewFilter.filter annotations, parsedQuery
# Set the path
# TODO: do we really need this data in the location?
search =
query: parsedQuery
matched : matchingIDs
in_body_text: parsedQuery.text
quote: parsedQuery.quote
$location.path('/page_search').search(search)
$rootScope.$digest()
facetMatches: (callback) =>
if $scope.show_search
return callback ['text','tag', 'quote', 'group','time','user'], {preserveOrder: true}
valueMatches: (facet, searchTerm, callback) ->
switch facet
when 'group' then callback ['Public', 'Private']
when 'time'
callback ['5 min', '30 min', '1 hour', '12 hours', '1 day', '1 week', '1 month', '1 year'], {preserveOrder: true}
clearSearch: (original) =>
# Execute clearSearch's internal method for resetting search
original()
# If we are in a search view, then the act of leaving it
# will trigger the route change watch, which will call
# leaveSearch(). However, if we have not yet started searching,
# (only opened the searcbar), no route change will happen,
# so we will have to trigger the cleanup manually.
$scope.leaveSearch() unless $scope.inSearch
# Go to viewer
$location.path('/viewer')
$rootScope.$digest()
if search_query.length > 0
$timeout =>
@visualSearch.searchBox.searchEvent('')
, 1500
$scope.reloadAnnotations = -> $scope.reloadAnnotations = ->
$rootScope.applyView "Screen" $rootScope.applyView "Screen"
return unless annotator.plugins.Store return unless annotator.plugins.Store
...@@ -812,6 +737,7 @@ class Search ...@@ -812,6 +737,7 @@ class Search
$scope.highlighter = '<span class="search-hl-active">$&</span>' $scope.highlighter = '<span class="search-hl-active">$&</span>'
$scope.filter_orderBy = $filter('orderBy') $scope.filter_orderBy = $filter('orderBy')
$scope.matches = []
$scope.render_order = {} $scope.render_order = {}
$scope.render_pos = {} $scope.render_pos = {}
$scope.ann_info = $scope.ann_info =
...@@ -833,19 +759,19 @@ class Search ...@@ -833,19 +759,19 @@ class Search
buildRenderOrder(threadid, thread.children) buildRenderOrder(threadid, thread.children)
setMoreTop = (threadid, annotation) => setMoreTop = (threadid, annotation) =>
unless annotation.id in $scope.search_filter unless annotation.id in $scope.matches
return false return false
result = false result = false
pos = $scope.render_pos[annotation.id] pos = $scope.render_pos[annotation.id]
if pos > 0 if pos > 0
prev = $scope.render_order[threadid][pos-1] prev = $scope.render_order[threadid][pos-1]
unless prev in $scope.search_filter unless prev in $scope.matches
result = true result = true
result result
setMoreBottom = (threadid, annotation) => setMoreBottom = (threadid, annotation) =>
unless annotation.id in $scope.search_filter unless annotation.id in $scope.matches
return false return false
result = false result = false
...@@ -853,7 +779,7 @@ class Search ...@@ -853,7 +779,7 @@ class Search
if pos < $scope.render_order[threadid].length-1 if pos < $scope.render_order[threadid].length-1
next = $scope.render_order[threadid][pos+1] next = $scope.render_order[threadid][pos+1]
unless next in $scope.search_filter unless next in $scope.matches
result = true result = true
result result
...@@ -880,14 +806,12 @@ class Search ...@@ -880,14 +806,12 @@ class Search
params: annotation.$$tag params: annotation.$$tag
$scope.$watchCollection 'annotations', (nVal, oVal) => $scope.$watchCollection 'annotations', (nVal, oVal) =>
$routeParams.matched = viewFilter.filter $rootScope.annotations, $routeParams.query
refresh() refresh()
refresh = => refresh = =>
$scope.search_filter = $routeParams.matched $scope.matches = viewFilter.filter $rootScope.annotations, $routeParams
# Create the regexps for highlighting the matches inside the annotations' bodies # Create the regexps for highlighting the matches inside the annotations' bodies
$scope.text_tokens = $routeParams.in_body_text.split ' ' $scope.text_tokens = $routeParams.text?.split(/\s+/) or []
$scope.text_regexp = [] $scope.text_regexp = []
$scope.quote_tokens = $routeParams.quote $scope.quote_tokens = $routeParams.quote
$scope.quote_regexp = [] $scope.quote_regexp = []
...@@ -917,7 +841,7 @@ class Search ...@@ -917,7 +841,7 @@ class Search
root_annotation = (annotator.threading.getContainer annotation_root).message root_annotation = (annotator.threading.getContainer annotation_root).message
unless root_annotation in $rootScope.annotations then continue unless root_annotation in $rootScope.annotations then continue
if annotation.id in $scope.search_filter if annotation.id in $scope.matches
# We have a winner, let's put its root annotation into our list and build the rendering # We have a winner, let's put its root annotation into our list and build the rendering
root_thread = annotator.threading.getContainer annotation_root root_thread = annotator.threading.getContainer annotation_root
threads.push root_thread threads.push root_thread
...@@ -934,7 +858,7 @@ class Search ...@@ -934,7 +858,7 @@ class Search
# - Open detail mode for quote hits # - Open detail mode for quote hits
for thread in threads for thread in threads
thread.message.highlightText = thread.message.text thread.message.highlightText = thread.message.text
if thread.message.id in $scope.search_filter if thread.message.id in $scope.matches
$scope.ann_info.shown[thread.message.id] = true $scope.ann_info.shown[thread.message.id] = true
if thread.message.text? if thread.message.text?
for regexp in $scope.text_regexp for regexp in $scope.text_regexp
...@@ -968,7 +892,7 @@ class Search ...@@ -968,7 +892,7 @@ class Search
if children? if children?
for child in children for child in children
child.highlightText = child.text child.highlightText = child.text
if child.id in $scope.search_filter if child.id in $scope.matches
$scope.ann_info.shown[child.id] = true $scope.ann_info.shown[child.id] = true
for regexp in $scope.text_regexp for regexp in $scope.text_regexp
child.highlightText = child.highlightText.replace regexp, $scope.highlighter child.highlightText = child.highlightText.replace regexp, $scope.highlighter
...@@ -986,7 +910,7 @@ class Search ...@@ -986,7 +910,7 @@ class Search
hidden = 0 hidden = 0
last_shown = null last_shown = null
for id in order for id in order
if id in $scope.search_filter if id in $scope.matches
if last_shown? then $scope.ann_info.more_bottom_num[last_shown] = hidden if last_shown? then $scope.ann_info.more_bottom_num[last_shown] = hidden
$scope.ann_info.more_top_num[id] = hidden $scope.ann_info.more_top_num[id] = hidden
last_shown = id last_shown = id
......
...@@ -394,6 +394,49 @@ streamviewer = [ -> ...@@ -394,6 +394,49 @@ streamviewer = [ ->
templateUrl: 'streamviewer.html' templateUrl: 'streamviewer.html'
] ]
visualSearch = ['$parse', ($parse) ->
link: (scope, elem, attr, ctrl) ->
_search = $parse(attr.onsearch)
_clear = $parse(attr.onclear)
_facets = $parse(attr.facets)
_values = $parse(attr.values)
_vs = VS.init
container: elem
callbacks:
search: (query, modelCollection) ->
scope.$apply ->
_search(scope, {"this": modelCollection})
clearSearch: (original) ->
_vs.searchBox.value('')
if attr.onclear
scope.$apply ->
_clear(scope)
else
original()
facetMatches: (callback) ->
facets = _facets(scope) or []
callback(facets or [], preserveOrder: true)
valueMatches: (facet, term, callback) ->
values = _values(scope)?[facet]
callback(values or [], preserveOrder: true)
scope.$watch attr.query, (query) ->
terms =
for k, v of query
continue unless v?.length
if ' ' in v
"#{k}: \"#{v}\""
else
"#{k}: #{v}"
_vs.searchBox.value(terms.join(' '))
_search(scope, {"this": _vs.searchQuery})
restrict: 'C'
]
whenscrolled = ['$window', ($window) -> whenscrolled = ['$window', ($window) ->
link: (scope, elem, attr) -> link: (scope, elem, attr) ->
$window = angular.element($window) $window = angular.element($window)
...@@ -419,4 +462,5 @@ angular.module('h.directives', ['ngSanitize']) ...@@ -419,4 +462,5 @@ angular.module('h.directives', ['ngSanitize'])
.directive('userPicker', userPicker) .directive('userPicker', userPicker)
.directive('repeatAnim', repeatAnim) .directive('repeatAnim', repeatAnim)
.directive('streamviewer', streamviewer) .directive('streamviewer', streamviewer)
.directive('visualSearch', visualSearch)
.directive('whenscrolled', whenscrolled) .directive('whenscrolled', whenscrolled)
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