Improved some small features for extended search.

This commit is contained in:
Martin Edenhofer 2016-07-05 22:05:29 +02:00
parent 613cc7ef20
commit 5ccde0c6f1
7 changed files with 113 additions and 105 deletions

View file

@ -147,6 +147,8 @@ class App.Controller extends Spine.Controller
scrollToIfNeeded: (element, position = true) -> scrollToIfNeeded: (element, position = true) ->
return if !element return if !element
return if !element.get(0) return if !element.get(0)
if position is true
return if element.visible(true)
element.get(0).scrollIntoView(position) element.get(0).scrollIntoView(position)
shake: (element) -> shake: (element) ->

View file

@ -906,7 +906,7 @@ class App.ChannelEmailNotificationWizard extends App.WizardModal
processData: true processData: true
success: (data, status, xhr) => success: (data, status, xhr) =>
if data.result is 'ok' if data.result is 'ok'
@el.remove() @el.modal('hide')
else else
@showSlide('js-outbound') @showSlide('js-outbound')
@showAlert('js-outbound', data.message_human || data.message) @showAlert('js-outbound', data.message_human || data.message)

View file

@ -3,19 +3,21 @@ class App.Navigation extends App.ControllerWidgetPermanent
elements: elements:
'#global-search': 'searchInput' '#global-search': 'searchInput'
'.js-global-search-result': 'searchResult'
'.search': 'searchContainer' '.search': 'searchContainer'
'.js-global-search-result': 'searchResult'
'.js-details-link': 'searchDetails'
events: events:
'click .js-toggleNotifications': 'toggleNotifications' 'click .js-toggleNotifications': 'toggleNotifications'
'click .js-emptySearch': 'emptyAndClose' 'click .js-emptySearch': 'emptyAndClose'
'submit form.search-holder': 'preventDefault' 'submit form.search-holder': 'preventDefault'
'dblclick form.search-holder .icon-magnifier': 'openExtendedSearch'
'focus #global-search': 'searchFocus' 'focus #global-search': 'searchFocus'
'blur #global-search': 'searchBlur' 'blur #global-search': 'searchBlur'
'keydown #global-search': 'listNavigate' 'keyup #global-search': 'listNavigate'
'click .js-global-search-result': 'andClose' 'click .js-global-search-result': 'andClose'
'change .js-menu .js-switch input': 'switch'
'click .js-details-link': 'openExtendedSearch' 'click .js-details-link': 'openExtendedSearch'
'change .js-menu .js-switch input': 'switch'
constructor: -> constructor: ->
super super
@ -214,6 +216,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
listNavigate: (e) => listNavigate: (e) =>
if e.keyCode is 27 # close on esc if e.keyCode is 27 # close on esc
@emptyAndClose() @emptyAndClose()
@searchInput.blur()
return return
else if e.keyCode is 38 # up else if e.keyCode is 38 # up
@nudge(e, -1) @nudge(e, -1)
@ -222,9 +225,12 @@ class App.Navigation extends App.ControllerWidgetPermanent
@nudge(e, 1) @nudge(e, 1)
return return
else if e.keyCode is 13 # enter 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') href = @$('.global-search-result .nav-tab.is-hover').attr('href')
return if !href return if !href
@locationExecute(href) @navigate(href)
@emptyAndClose() @emptyAndClose()
@searchInput.blur() @searchInput.blur()
return return
@ -234,10 +240,20 @@ class App.Navigation extends App.ControllerWidgetPermanent
nudge: (e, position) => nudge: (e, position) =>
return if !@searchContainer.hasClass('open')
# get current # get current
current = @searchResult.find('.nav-tab.is-hover') current = @searchResult.find('.nav-tab.is-hover')
if !current.get(0) if !current.get(0)
@searchResult.find('.nav-tab').first().addClass('is-hover')
# 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 return
if position is 1 if position is 1
@ -250,6 +266,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
if prev.get(0) if prev.get(0)
current.removeClass('is-hover').popover('hide') current.removeClass('is-hover').popover('hide')
prev.addClass('is-hover').popover('show') prev.addClass('is-hover').popover('show')
else
current.removeClass('is-hover').popover('hide')
@searchDetails.addClass('is-hover')
if next if next
@scrollToIfNeeded(next, true) @scrollToIfNeeded(next, true)
@ -275,49 +294,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
@query = query @query = query
@searchContainer.toggleClass('filled', !!@query) @searchContainer.toggleClass('filled', !!@query)
# use cache for search result App.GlobalSearch.execute(
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 query: @query
processData: true, render: @renderResult
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)
) )
getItems: (data) -> getItems: (data) ->
@ -424,7 +403,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
url = params.url url = params.url
type = params.type type = params.type
if type is 'menu' if type is 'menu'
@$('.js-menu .is-active').removeClass('is-active') @$('.js-menu .is-active, .js-details-link.is-active').removeClass('is-active')
else else
@$('.is-active').removeClass('is-active') @$('.is-active').removeClass('is-active')
return if !url || url is '#' return if !url || url is '#'
@ -478,8 +457,9 @@ class App.Navigation extends App.ControllerWidgetPermanent
e.stopPropagation() e.stopPropagation()
@notificationWidget.toggle() @notificationWidget.toggle()
openExtendedSearch: (event) -> openExtendedSearch: (e) ->
event.preventDefault() if e
e.preventDefault()
query = @searchInput.val() query = @searchInput.val()
@searchInput.val('').blur() @searchInput.val('').blur()
if query if query
@ -487,6 +467,4 @@ class App.Navigation extends App.ControllerWidgetPermanent
return return
@navigate('#search') @navigate('#search')
App.Config.set('navigation', App.Navigation, 'Navigations') App.Config.set('navigation', App.Navigation, 'Navigations')

View file

@ -6,7 +6,7 @@ class App.Search extends App.Controller
events: events:
'click .js-emptySearch': 'empty' 'click .js-emptySearch': 'empty'
'submit form.search-holder': 'preventDefault' 'submit form.search-holder': 'preventDefault'
'keydown .js-search': 'listNavigate' 'keyup .js-search': 'listNavigate'
'click .js-tab': 'showTab' 'click .js-tab': 'showTab'
'input .js-search': 'updateFilledClass' 'input .js-search': 'updateFilledClass'
@ -25,6 +25,11 @@ class App.Search extends App.Controller
@render() @render()
# rerender view, e. g. on langauge change
@bind('ui:rerender', =>
@render()
)
meta: => meta: =>
if @query if @query
title = App.Utils.htmlEscape(@query) title = App.Utils.htmlEscape(@query)
@ -95,7 +100,9 @@ class App.Search extends App.Controller
empty: => empty: =>
@searchInput.val('') @searchInput.val('')
@query = ''
@updateFilledClass() @updateFilledClass()
@updateTask()
# remove not needed popovers # remove not needed popovers
@delay(@anyPopoversDestroy, 100, 'removePopovers') @delay(@anyPopoversDestroy, 100, 'removePopovers')
@ -106,53 +113,11 @@ class App.Search extends App.Controller
return if !query return if !query
return if query is @query return if query is @query
@query = 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() @updateTask()
App.Ajax.request( App.GlobalSearch.execute(
id: 'search'
type: 'GET'
url: "#{@apiPath}/search"
data:
query: @query query: @query
limit: 200 render: @renderResult
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)
) )
renderResult: (result = []) => renderResult: (result = []) =>
@ -210,6 +175,7 @@ class App.Search extends App.Controller
updateTask: => updateTask: =>
current = App.TaskManager.get(@task_key).state current = App.TaskManager.get(@task_key).state
return if !current
current.query = @query current.query = @query
current.model = @model current.model = @model
App.TaskManager.update(@task_key, { state: current }) App.TaskManager.update(@task_key, { state: current })

View file

@ -94,9 +94,9 @@ class App.OnlineNotificationWidget extends App.Controller
prev.addClass('is-hover') prev.addClass('is-hover')
if next if next
@scrollToIfNeeded(next, false) @scrollToIfNeeded(next, true)
if prev if prev
@scrollToIfNeeded(prev, true) @scrollToIfNeeded(prev, false)
counterUpdate: (count, force = false) => counterUpdate: (count, force = false) =>
count = '' if count is 0 count = '' if count is 0

View 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)
)

View file

@ -16,7 +16,7 @@
<%- @Icon('searchdetail') %> <%- @Icon('searchdetail') %>
</div> </div>
<div class="nav-tab-name flex u-textTruncate"> <div class="nav-tab-name flex u-textTruncate">
<%= @T('Show Search Details') %> <%- @T('Show Search Details') %>
<%- @Icon('long-arrow-right') %> <%- @Icon('long-arrow-right') %>
</div> </div>
</a> </a>