Improved perforamnce of global search (reduced throttle of search queries, ony start queries if query has changed).
This commit is contained in:
parent
ab6634bcfe
commit
dd54f8a787
3 changed files with 134 additions and 64 deletions
|
@ -17,6 +17,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
'dblclick form.search-holder .icon-magnifier': 'openExtendedSearch'
|
||||
'focus #global-search': 'searchFocus'
|
||||
'blur #global-search': 'searchBlur'
|
||||
'paste #global-search': 'searchPaste'
|
||||
'keyup #global-search': 'listNavigate'
|
||||
'click .js-global-search-result': 'emptyAndCloseDelayed'
|
||||
'click .js-details-link': 'openExtendedSearch'
|
||||
|
@ -27,8 +28,6 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
super
|
||||
@render()
|
||||
|
||||
@throttledSearch = _.throttle @search, 200
|
||||
|
||||
@globalSearch = new App.GlobalSearch(
|
||||
render: @renderResult
|
||||
)
|
||||
|
@ -171,20 +170,14 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
type: 'personal'
|
||||
)
|
||||
|
||||
renderResult: (result = [], noChange) =>
|
||||
if noChange
|
||||
return
|
||||
|
||||
renderResult: (result = []) =>
|
||||
@removePopovers()
|
||||
|
||||
# remove result if not result exists
|
||||
if _.isEmpty(result)
|
||||
@searchContainer.removeClass('loading').addClass('no-match')
|
||||
@searchResult.html(App.view('navigation/no_result')())
|
||||
return
|
||||
|
||||
@searchContainer.removeClass('no-match loading')
|
||||
|
||||
# build markup
|
||||
html = App.view('navigation/result')(
|
||||
result: result
|
||||
|
@ -215,11 +208,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
|
||||
searchFocus: (e) =>
|
||||
@clearDelay('emptyAndCloseDelayed')
|
||||
@throttledSearch()
|
||||
@query = undefined
|
||||
@search(10)
|
||||
App.PopoverProvidable.anyPopoversDestroy()
|
||||
@searchContainer.addClass('focused')
|
||||
@selectAll(e)
|
||||
|
||||
searchPaste: (e) =>
|
||||
update = =>
|
||||
@clearDelay('emptyAndCloseDelayed')
|
||||
@query = undefined
|
||||
@search(10)
|
||||
App.PopoverProvidable.anyPopoversDestroy()
|
||||
@searchContainer.addClass('focused')
|
||||
@delay(update, 10, 'searchFocus')
|
||||
|
||||
searchBlur: (e) =>
|
||||
|
||||
# delay to be able to "click/execute" x if query is ''
|
||||
|
@ -249,7 +252,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
return
|
||||
|
||||
# on other keys, show result
|
||||
@throttledSearch()
|
||||
@search(0)
|
||||
|
||||
nudge: (e, position) =>
|
||||
|
||||
|
@ -307,22 +310,41 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
@globalSearch.close()
|
||||
@delayedRemoveAnyPopover()
|
||||
|
||||
search: =>
|
||||
search: (delay) =>
|
||||
query = @searchInput.val().trim()
|
||||
@searchContainer.toggleClass('filled', !!query)
|
||||
|
||||
# if we started a new search and already typed something in
|
||||
if query != '' and @query == ''
|
||||
@searchContainer.addClass('open no-match loading')
|
||||
|
||||
return if @query is query
|
||||
@query = query
|
||||
|
||||
if @query == ''
|
||||
@searchContainer.removeClass('open loading')
|
||||
if delay is 0
|
||||
delay = 500
|
||||
if query.length > 2
|
||||
delay = 350
|
||||
else if query.length > 4
|
||||
delay = 200
|
||||
|
||||
# if we started a new search and already typed something in
|
||||
if query is ''
|
||||
@searchContainer.removeClass('open')
|
||||
return
|
||||
|
||||
@globalSearch.search(
|
||||
delay: delay
|
||||
query: @query
|
||||
callbackLongerAsExpected: =>
|
||||
@searchContainer.removeClass('open')
|
||||
callbackNoMatch: =>
|
||||
@searchContainer.addClass('no-match')
|
||||
@searchContainer.addClass('open')
|
||||
@globalSearch.search(query: @query)
|
||||
callbackMatch: =>
|
||||
@searchContainer.removeClass('no-match')
|
||||
@searchContainer.addClass('open')
|
||||
callbackStop: =>
|
||||
@searchContainer.removeClass('loading')
|
||||
callbackStart: =>
|
||||
@searchContainer.addClass('loading')
|
||||
)
|
||||
|
||||
filterNavbar: (values, parent = null) ->
|
||||
return _.filter values, (item) =>
|
||||
|
|
|
@ -24,8 +24,6 @@ class App.Search extends App.Controller
|
|||
# update taskbar with new meta data
|
||||
App.TaskManager.touch(@taskKey)
|
||||
|
||||
@throttledSearch = _.throttle @search, 200
|
||||
|
||||
@globalSearch = new App.GlobalSearch(
|
||||
render: @renderResult
|
||||
limit: 50
|
||||
|
@ -59,9 +57,11 @@ class App.Search extends App.Controller
|
|||
@table.show()
|
||||
@navupdate(url: '#search', type: 'menu')
|
||||
return if _.isEmpty(params.query)
|
||||
|
||||
@$('.js-search').val(params.query).trigger('change')
|
||||
return if @shown
|
||||
@throttledSearch(true)
|
||||
|
||||
@search(1000, true)
|
||||
|
||||
hide: ->
|
||||
@shown = false
|
||||
|
@ -102,7 +102,7 @@ class App.Search extends App.Controller
|
|||
)
|
||||
|
||||
if @query
|
||||
@throttledSearch(true)
|
||||
@search(500, true)
|
||||
|
||||
listNavigate: (e) =>
|
||||
if e.keyCode is 27 # close on esc
|
||||
|
@ -110,7 +110,7 @@ class App.Search extends App.Controller
|
|||
return
|
||||
|
||||
# on other keys, show result
|
||||
@throttledSearch(200)
|
||||
@search(0)
|
||||
|
||||
empty: =>
|
||||
@searchInput.val('')
|
||||
|
@ -120,7 +120,7 @@ class App.Search extends App.Controller
|
|||
|
||||
@delayedRemoveAnyPopover()
|
||||
|
||||
search: (force = false) =>
|
||||
search: (delay, force = false) =>
|
||||
query = @searchInput.val().trim()
|
||||
if !force
|
||||
return if !query
|
||||
|
@ -128,7 +128,17 @@ class App.Search extends App.Controller
|
|||
@query = query
|
||||
@updateTask()
|
||||
|
||||
@globalSearch.search(query: @query)
|
||||
if delay is 0
|
||||
delay = 500
|
||||
if query.length > 2
|
||||
delay = 350
|
||||
else if query.length > 4
|
||||
delay = 200
|
||||
|
||||
@globalSearch.search(
|
||||
delay: delay
|
||||
query: @query
|
||||
)
|
||||
|
||||
renderResult: (result = []) =>
|
||||
@result = result
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
class App.GlobalSearch extends App.Controller
|
||||
ajaxCount: 0
|
||||
constructor: ->
|
||||
super
|
||||
@searchResultCache = {}
|
||||
|
@ -12,10 +13,25 @@ class App.GlobalSearch extends App.Controller
|
|||
# use cache for search result
|
||||
currentTime = new Date
|
||||
if @searchResultCache[query] && @searchResultCache[query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
@renderTry(@searchResultCache[query].result, query)
|
||||
if @ajaxRequestId
|
||||
App.Ajax.abort(@ajaxRequestId)
|
||||
@ajaxStart(params)
|
||||
@renderTry(@searchResultCache[query].result, query, params)
|
||||
delayCallback = =>
|
||||
@ajaxStop(params)
|
||||
@delay(delayCallback, 700)
|
||||
return
|
||||
|
||||
App.Ajax.request(
|
||||
delayCallback = =>
|
||||
|
||||
@ajaxStart(params)
|
||||
|
||||
delayCallback = ->
|
||||
if params.callbackLongerAsExpected
|
||||
params.callbackLongerAsExpected()
|
||||
@delay(delayCallback, 10000, 'global-search-ajax-longer-as-expected')
|
||||
|
||||
@ajaxRequestId = App.Ajax.request(
|
||||
id: @ajaxId
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/search"
|
||||
|
@ -24,6 +40,7 @@ class App.GlobalSearch extends App.Controller
|
|||
limit: @limit || 10
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
@clearDelay('global-search-ajax-longer-as-expected')
|
||||
App.Collection.loadAssets(data.assets)
|
||||
result = {}
|
||||
for item in data.result
|
||||
|
@ -38,17 +55,38 @@ class App.GlobalSearch extends App.Controller
|
|||
App.Log.error('_globalSearchSingleton', "No such model #{item.type.toLocaleLowerCase()}.searchResultAttributes()")
|
||||
else
|
||||
App.Log.error('_globalSearchSingleton', "No such model App.#{item.type}")
|
||||
|
||||
@renderTry(result, query)
|
||||
@ajaxStop(params)
|
||||
@renderTry(result, query, params)
|
||||
error: =>
|
||||
@clearDelay('global-search-ajax-longer-as-expected')
|
||||
@ajaxStop(params)
|
||||
)
|
||||
@delay(delayCallback, params.delay || 1, 'global-search-ajax')
|
||||
|
||||
renderTry: (result, query) =>
|
||||
ajaxStart: (params) =>
|
||||
@ajaxCount++
|
||||
if params.callbackStart
|
||||
params.callbackStart()
|
||||
|
||||
ajaxStop: (params) =>
|
||||
@ajaxCount--
|
||||
if @ajaxCount == 0 && params.callbackStop
|
||||
params.callbackStop()
|
||||
|
||||
renderTry: (result, query, params) =>
|
||||
|
||||
if query
|
||||
if _.isEmpty(result)
|
||||
if params.callbackNoMatch
|
||||
params.callbackNoMatch()
|
||||
else
|
||||
if params.callbackMatch
|
||||
params.callbackMatch()
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
if @lastQuery is query && @searchResultCache[query]
|
||||
diff = difference(@searchResultCache[query].result, result)
|
||||
if _.isEmpty(diff)
|
||||
@render(result, true)
|
||||
return
|
||||
|
||||
@lastQuery = query
|
||||
|
|
Loading…
Reference in a new issue