Improved some small features for extended search.
This commit is contained in:
parent
613cc7ef20
commit
5ccde0c6f1
7 changed files with 113 additions and 105 deletions
|
@ -147,6 +147,8 @@ class App.Controller extends Spine.Controller
|
|||
scrollToIfNeeded: (element, position = true) ->
|
||||
return if !element
|
||||
return if !element.get(0)
|
||||
if position is true
|
||||
return if element.visible(true)
|
||||
element.get(0).scrollIntoView(position)
|
||||
|
||||
shake: (element) ->
|
||||
|
|
|
@ -906,7 +906,7 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
|
|||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
if data.result is 'ok'
|
||||
@el.remove()
|
||||
@el.modal('hide')
|
||||
else
|
||||
@showSlide('js-outbound')
|
||||
@showAlert('js-outbound', data.message_human || data.message)
|
||||
|
|
|
@ -3,19 +3,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
|
||||
elements:
|
||||
'#global-search': 'searchInput'
|
||||
'.js-global-search-result': 'searchResult'
|
||||
'.search': 'searchContainer'
|
||||
'.js-global-search-result': 'searchResult'
|
||||
'.js-details-link': 'searchDetails'
|
||||
|
||||
events:
|
||||
'click .js-toggleNotifications': 'toggleNotifications'
|
||||
'click .js-emptySearch': 'emptyAndClose'
|
||||
'submit form.search-holder': 'preventDefault'
|
||||
'dblclick form.search-holder .icon-magnifier': 'openExtendedSearch'
|
||||
'focus #global-search': 'searchFocus'
|
||||
'blur #global-search': 'searchBlur'
|
||||
'keydown #global-search': 'listNavigate'
|
||||
'keyup #global-search': 'listNavigate'
|
||||
'click .js-global-search-result': 'andClose'
|
||||
'change .js-menu .js-switch input': 'switch'
|
||||
'click .js-details-link': 'openExtendedSearch'
|
||||
'change .js-menu .js-switch input': 'switch'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
@ -58,7 +60,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
@$('.bell').addClass('show')
|
||||
App.Audio.play( 'https://www.sounddogs.com/previews/2193/mp3/219024_SOUNDDOGS__be.mp3' )
|
||||
@delay(
|
||||
-> App.Event.trigger('bell', 'off' )
|
||||
-> App.Event.trigger('bell', 'off')
|
||||
3000
|
||||
)
|
||||
else
|
||||
|
@ -214,6 +216,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
listNavigate: (e) =>
|
||||
if e.keyCode is 27 # close on esc
|
||||
@emptyAndClose()
|
||||
@searchInput.blur()
|
||||
return
|
||||
else if e.keyCode is 38 # up
|
||||
@nudge(e, -1)
|
||||
|
@ -222,9 +225,12 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
@nudge(e, 1)
|
||||
return
|
||||
else if e.keyCode is 13 # enter
|
||||
if @$('.global-search-menu .js-details-link.is-hover').get(0)
|
||||
@openExtendedSearch()
|
||||
return
|
||||
href = @$('.global-search-result .nav-tab.is-hover').attr('href')
|
||||
return if !href
|
||||
@locationExecute(href)
|
||||
@navigate(href)
|
||||
@emptyAndClose()
|
||||
@searchInput.blur()
|
||||
return
|
||||
|
@ -234,11 +240,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
|
||||
nudge: (e, position) =>
|
||||
|
||||
return if !@searchContainer.hasClass('open')
|
||||
|
||||
# get current
|
||||
current = @searchResult.find('.nav-tab.is-hover')
|
||||
if !current.get(0)
|
||||
@searchResult.find('.nav-tab').first().addClass('is-hover')
|
||||
return
|
||||
|
||||
# if down, select detail search of first result
|
||||
if position is 1
|
||||
if !@searchDetails.hasClass('is-hover')
|
||||
@searchDetails.addClass('is-hover')
|
||||
return
|
||||
|
||||
@searchDetails.removeClass('is-hover')
|
||||
@searchResult.find('.nav-tab').first().addClass('is-hover').popover('show')
|
||||
return
|
||||
|
||||
if position is 1
|
||||
next = current.closest('li').nextAll('li').not('.divider').first().find('.nav-tab')
|
||||
|
@ -250,6 +266,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
if prev.get(0)
|
||||
current.removeClass('is-hover').popover('hide')
|
||||
prev.addClass('is-hover').popover('show')
|
||||
else
|
||||
current.removeClass('is-hover').popover('hide')
|
||||
@searchDetails.addClass('is-hover')
|
||||
|
||||
if next
|
||||
@scrollToIfNeeded(next, true)
|
||||
|
@ -275,49 +294,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
@query = query
|
||||
@searchContainer.toggleClass('filled', !!@query)
|
||||
|
||||
# use cache for search result
|
||||
if @searchResultCache[@query]
|
||||
@renderResult(@searchResultCache[@query].result)
|
||||
currentTime = new Date
|
||||
return if @searchResultCache[@query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
|
||||
App.Ajax.request(
|
||||
id: 'search'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/search"
|
||||
data:
|
||||
query: @query
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
App.Collection.loadAssets(data.assets)
|
||||
result = {}
|
||||
for item in data.result
|
||||
if App[item.type] && App[item.type].find
|
||||
if !result[item.type]
|
||||
result[item.type] = []
|
||||
item_object = App[item.type].find(item.id)
|
||||
if item_object.searchResultAttributes
|
||||
item_object_search_attributes = item_object.searchResultAttributes()
|
||||
result[item.type].push item_object_search_attributes
|
||||
else
|
||||
@log 'error', "No such model #{item.type.toLocaleLowerCase()}.searchResultAttributes()"
|
||||
else
|
||||
@log 'error', "No such model App.#{item.type}"
|
||||
|
||||
diff = false
|
||||
if @searchResultCache[@query]
|
||||
diff = difference(@searchResultCache[@query].resultRaw, data.result)
|
||||
|
||||
# cache search result
|
||||
@searchResultCache[@query] =
|
||||
result: result
|
||||
resultRaw: data.result
|
||||
time: new Date
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
return if diff isnt false && _.isEmpty(diff)
|
||||
|
||||
@renderResult(result)
|
||||
App.GlobalSearch.execute(
|
||||
query: @query
|
||||
render: @renderResult
|
||||
)
|
||||
|
||||
getItems: (data) ->
|
||||
|
@ -424,7 +403,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
url = params.url
|
||||
type = params.type
|
||||
if type is 'menu'
|
||||
@$('.js-menu .is-active').removeClass('is-active')
|
||||
@$('.js-menu .is-active, .js-details-link.is-active').removeClass('is-active')
|
||||
else
|
||||
@$('.is-active').removeClass('is-active')
|
||||
return if !url || url is '#'
|
||||
|
@ -478,8 +457,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
e.stopPropagation()
|
||||
@notificationWidget.toggle()
|
||||
|
||||
openExtendedSearch: (event) ->
|
||||
event.preventDefault()
|
||||
openExtendedSearch: (e) ->
|
||||
if e
|
||||
e.preventDefault()
|
||||
query = @searchInput.val()
|
||||
@searchInput.val('').blur()
|
||||
if query
|
||||
|
@ -487,6 +467,4 @@ class App.Navigation extends App.ControllerWidgetPermanent
|
|||
return
|
||||
@navigate('#search')
|
||||
|
||||
|
||||
|
||||
App.Config.set('navigation', App.Navigation, 'Navigations')
|
||||
|
|
|
@ -6,7 +6,7 @@ class App.Search extends App.Controller
|
|||
events:
|
||||
'click .js-emptySearch': 'empty'
|
||||
'submit form.search-holder': 'preventDefault'
|
||||
'keydown .js-search': 'listNavigate'
|
||||
'keyup .js-search': 'listNavigate'
|
||||
'click .js-tab': 'showTab'
|
||||
'input .js-search': 'updateFilledClass'
|
||||
|
||||
|
@ -25,6 +25,11 @@ class App.Search extends App.Controller
|
|||
|
||||
@render()
|
||||
|
||||
# rerender view, e. g. on langauge change
|
||||
@bind('ui:rerender', =>
|
||||
@render()
|
||||
)
|
||||
|
||||
meta: =>
|
||||
if @query
|
||||
title = App.Utils.htmlEscape(@query)
|
||||
|
@ -95,7 +100,9 @@ class App.Search extends App.Controller
|
|||
|
||||
empty: =>
|
||||
@searchInput.val('')
|
||||
@query = ''
|
||||
@updateFilledClass()
|
||||
@updateTask()
|
||||
|
||||
# remove not needed popovers
|
||||
@delay(@anyPopoversDestroy, 100, 'removePopovers')
|
||||
|
@ -106,53 +113,11 @@ class App.Search extends App.Controller
|
|||
return if !query
|
||||
return if query is @query
|
||||
@query = query
|
||||
|
||||
# use cache for search result
|
||||
if @searchResultCache[@query]
|
||||
@renderResult(@searchResultCache[@query].result)
|
||||
currentTime = new Date
|
||||
return if @searchResultCache[@query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
|
||||
@updateTask()
|
||||
|
||||
App.Ajax.request(
|
||||
id: 'search'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/search"
|
||||
data:
|
||||
query: @query
|
||||
limit: 200
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
App.Collection.loadAssets(data.assets)
|
||||
result = {}
|
||||
for item in data.result
|
||||
if App[item.type] && App[item.type].find
|
||||
if !result[item.type]
|
||||
result[item.type] = []
|
||||
item_object = App[item.type].find(item.id)
|
||||
if item_object.searchResultAttributes
|
||||
item_object_search_attributes = item_object.searchResultAttributes()
|
||||
result[item.type].push item_object_search_attributes
|
||||
else
|
||||
@log 'error', "No such model #{item.type.toLocaleLowerCase()}.searchResultAttributes()"
|
||||
else
|
||||
@log 'error', "No such model App.#{item.type}"
|
||||
|
||||
diff = false
|
||||
if @searchResultCache[@query]
|
||||
diff = difference(@searchResultCache[@query].resultRaw, data.result)
|
||||
|
||||
# cache search result
|
||||
@searchResultCache[@query] =
|
||||
result: result
|
||||
resultRaw: data.result
|
||||
time: new Date
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
return if diff isnt false && _.isEmpty(diff)
|
||||
|
||||
@renderResult(result)
|
||||
App.GlobalSearch.execute(
|
||||
query: @query
|
||||
render: @renderResult
|
||||
)
|
||||
|
||||
renderResult: (result = []) =>
|
||||
|
@ -210,6 +175,7 @@ class App.Search extends App.Controller
|
|||
|
||||
updateTask: =>
|
||||
current = App.TaskManager.get(@task_key).state
|
||||
return if !current
|
||||
current.query = @query
|
||||
current.model = @model
|
||||
App.TaskManager.update(@task_key, { state: current })
|
||||
|
|
|
@ -94,9 +94,9 @@ class App.OnlineNotificationWidget extends App.Controller
|
|||
prev.addClass('is-hover')
|
||||
|
||||
if next
|
||||
@scrollToIfNeeded(next, false)
|
||||
@scrollToIfNeeded(next, true)
|
||||
if prev
|
||||
@scrollToIfNeeded(prev, true)
|
||||
@scrollToIfNeeded(prev, false)
|
||||
|
||||
counterUpdate: (count, force = false) =>
|
||||
count = '' if count is 0
|
||||
|
|
62
app/assets/javascripts/app/lib/app_post/global_search.coffee
Normal file
62
app/assets/javascripts/app/lib/app_post/global_search.coffee
Normal file
|
@ -0,0 +1,62 @@
|
|||
class App.GlobalSearch
|
||||
_instance = undefined
|
||||
|
||||
@execute: (args) ->
|
||||
if _instance == undefined
|
||||
_instance ?= new _globalSearchSingleton
|
||||
_instance.execute(args)
|
||||
|
||||
class _globalSearchSingleton extends Spine.Module
|
||||
|
||||
constructor: ->
|
||||
@searchResultCache = {}
|
||||
@apiPath = App.Config.get('api_path')
|
||||
|
||||
execute: (params) ->
|
||||
query = params.query
|
||||
render = params.render
|
||||
|
||||
# use cache for search result
|
||||
if @searchResultCache[query]
|
||||
render(@searchResultCache[query].result)
|
||||
currentTime = new Date
|
||||
return if @searchResultCache[query].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
|
||||
App.Ajax.request(
|
||||
id: 'search'
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/search"
|
||||
data:
|
||||
query: query
|
||||
processData: true,
|
||||
success: (data, status, xhr) =>
|
||||
App.Collection.loadAssets(data.assets)
|
||||
result = {}
|
||||
for item in data.result
|
||||
if App[item.type] && App[item.type].find
|
||||
if !result[item.type]
|
||||
result[item.type] = []
|
||||
item_object = App[item.type].find(item.id)
|
||||
if item_object.searchResultAttributes
|
||||
item_object_search_attributes = item_object.searchResultAttributes()
|
||||
result[item.type].push item_object_search_attributes
|
||||
else
|
||||
App.Log.error('_globalSearchSingleton', "No such model #{item.type.toLocaleLowerCase()}.searchResultAttributes()")
|
||||
else
|
||||
App.Log.error('_globalSearchSingleton', "No such model App.#{item.type}")
|
||||
|
||||
diff = false
|
||||
if @searchResultCache[query]
|
||||
diff = difference(@searchResultCache[query].resultRaw, data.result)
|
||||
|
||||
# cache search result
|
||||
@searchResultCache[query] =
|
||||
result: result
|
||||
resultRaw: data.result
|
||||
time: new Date
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
return if diff isnt false && _.isEmpty(diff)
|
||||
|
||||
render(result)
|
||||
)
|
|
@ -16,7 +16,7 @@
|
|||
<%- @Icon('searchdetail') %>
|
||||
</div>
|
||||
<div class="nav-tab-name flex u-textTruncate">
|
||||
<%= @T('Show Search Details') %>
|
||||
<%- @T('Show Search Details') %>
|
||||
<%- @Icon('long-arrow-right') %>
|
||||
</div>
|
||||
</a>
|
||||
|
|
Loading…
Reference in a new issue