Skip to content

Commit

Permalink
Search: loading indicator, no result screen, extended search on enter
Browse files Browse the repository at this point in the history
- open extended search on enter, solves #560
- show searching indicator, requested in https://community.zammad.org/t/delay-after-querying-a-search/405
- show no result screen, solves #788
- fix bug: when on ‘#search’, ‘show search results’ in the search sidebar was highlighted as active too because it links to #search
- clear search when entering a search result
  • Loading branch information
mrflix committed Jul 28, 2018
1 parent dc884fc commit 2639df5
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 46 deletions.
63 changes: 33 additions & 30 deletions app/assets/javascripts/app/controllers/navigation.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class App.Navigation extends App.ControllerWidgetPermanent
'focus #global-search': 'searchFocus'
'blur #global-search': 'searchBlur'
'keyup #global-search': 'listNavigate'
'click .js-global-search-result': 'andClose'
'click .js-global-search-result': 'emptyAndClose'
'click .js-details-link': 'openExtendedSearch'
'change .js-menu .js-switch input': 'switch'

Expand Down Expand Up @@ -156,31 +156,31 @@ class App.Navigation extends App.ControllerWidgetPermanent
type: 'personal'
)

renderResult: (result = []) =>
renderResult: (result = [], noChange) =>
if noChange
return

# remove result if not result exists
# show no results placeholder if no result exists
if _.isEmpty(result)
@searchContainer.removeClass('open')
@globalSearch.close()
@searchResult.html('')
@searchContainer.addClass('no-match')
@searchResult.html(App.view('navigation/no_result')())
return

@searchContainer.removeClass('no-match')

# build markup
html = App.view('navigation/result')(
result: result
)
@searchResult.html(html)

# show result list
@searchContainer.addClass('open')

# start ticket popups
@ticketPopups()

# start user popups
@userPopups()

# start oorganization popups
# start organization popups
@organizationPopups()

render: ->
Expand All @@ -205,26 +205,22 @@ class App.Navigation extends App.ControllerWidgetPermanent

searchFocus: (e) =>
@query = '' # reset query cache
@searchContainer.addClass('focused')
@anyPopoversDestroy()
@search()
@searchContainer.addClass('focused')

searchBlur: (e) =>

# delay to be able to click x
update = =>
query = @searchInput.val().trim()
if !query
@emptyAndClose()
return
@searchContainer.removeClass('focused')

@delay(update, 100, 'removeFocused')

listNavigate: (e) =>
if e.keyCode is 27 # close on esc
@emptyAndClose()
@searchInput.blur()
return
else if e.keyCode is 38 # up
@nudge(e, -1)
Expand All @@ -233,14 +229,13 @@ 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
@searchInput.blur()
href = @$('.global-search-result .nav-tab.is-hover').attr('href')
return if !href
@navigate(href)
if href
@navigate(href)
else
@openExtendedSearch()
@emptyAndClose()
@searchInput.blur()
return

# on other keys, show result
Expand Down Expand Up @@ -284,25 +279,33 @@ class App.Navigation extends App.ControllerWidgetPermanent
@scrollToIfNeeded(prev, false)

emptyAndClose: =>
@query = ''
@searchInput.val('')
@searchContainer.removeClass('filled').removeClass('open').removeClass('focused')
@searchContainer.removeClass('focused filled open no-match')
@globalSearch.close()

# remove not needed popovers
@delay(@anyPopoversDestroy, 100, 'removePopovers')

andClose: =>
@query = ''
@searchInput.blur()
@searchContainer.removeClass('open')
@searchContainer.removeClass('open no-match')
@globalSearch.close()
@delay(@anyPopoversDestroy, 100, 'removePopovers')

search: =>
query = @searchInput.val().trim()
return if !query
return if query is @query
@searchContainer.toggleClass('filled', !!query)
# if we started a new search and already typed something in
if @query == '' and query != ''
@searchContainer.addClass('open no-match')
@searchResult.html(App.view('navigation/search_placeholder')())

@query = query
@searchContainer.toggleClass('filled', !!@query)

if @query == ''
@searchContainer.removeClass('open')
return

@globalSearch.search(query: @query)

filterNavbar: (values, user, parent = null) ->
Expand Down Expand Up @@ -402,11 +405,11 @@ class App.Navigation extends App.ControllerWidgetPermanent
url = params.url
type = params.type
if type is 'menu'
@$('.js-menu .is-active, .js-details-link.is-active').removeClass('is-active')
@$('.js-menu .is-active').removeClass('is-active')
else
@$('.is-active').removeClass('is-active')
return if !url || url is '#'
@$("[href=\"#{url}\"]").addClass('is-active')
@$(".js-menu [href=\"#{url}\"], .tasks [href=\"#{url}\"]").addClass('is-active')

recentViewNavbarItemsRebuild: =>

Expand Down
3 changes: 2 additions & 1 deletion app/assets/javascripts/app/controllers/search.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ class App.Search extends App.Controller

@globalSearch.search(query: @query)

renderResult: (result = []) =>
renderResult: (result = [], noChange) =>
return if noChange
@result = result
for tab in @tabs
count = 0
Expand Down
6 changes: 4 additions & 2 deletions app/assets/javascripts/app/lib/app_post/global_search.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ class App.GlobalSearch extends App.Controller
renderTry: (result, query) =>

# if result hasn't changed, do not rerender
diff = false
if @lastQuery is query && @searchResultCache[query]
diff = difference(@searchResultCache[query].result, result)
return if diff isnt false && _.isEmpty(diff)
if _.isEmpty(diff)
@render(result, true)
return

@lastQuery = query

# cache search result
Expand Down
4 changes: 4 additions & 0 deletions app/assets/javascripts/app/views/navigation/no_result.jst.eco
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<li class="global-search-detail-no-result alert alert--warning horizontal" role="alert">
<%- @Icon('mood-sad') %>
<span><%= @T('There is no match for your search.') %></span>
</li>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<li class="global-search-detail-placeholder">
<a class="nav-tab nav-tab--search">
<div class="nav-tab-icon">
<%- @Icon('task-state') %>
</div>
<span class="nav-tab-name"></span>
</a>
</li>
<li class="global-search-detail-placeholder">
<a class="nav-tab nav-tab--search">
<div class="nav-tab-icon">
<%- @Icon('task-state') %>
</div>
<span class="nav-tab-name"></span>
</a>
</li>
<li class="global-search-detail-placeholder">
<a class="nav-tab nav-tab--search">
<div class="nav-tab-icon">
<%- @Icon('task-state') %>
</div>
<span class="nav-tab-name"></span>
</a>
</li>
95 changes: 82 additions & 13 deletions app/assets/stylesheets/zammad.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1962,7 +1962,6 @@ input.has-error {
border-radius: 19px;
padding: 0 17px 0 42px;
@include rtl(padding, 0 42px 0 17px);
will-change: transform;

&.is-empty + .empty-search {
visibility: hidden;
Expand Down Expand Up @@ -3279,10 +3278,6 @@ footer {
.nav-tab.nav-tab--search.is-hover {
background: #389ed9;
color: white;

.nav-tab-icon .icon {
fill: white;
}
}

.nav-tab.ui-sortable-helper {
Expand All @@ -3306,7 +3301,7 @@ footer {
.nav-tab-icon .icon {
max-width: 18px;
max-height: 18px;
fill: #808080;
fill: currentColor;
}

.nav-tab-icon .icon-diagonal-cross {
Expand Down Expand Up @@ -3432,7 +3427,8 @@ footer {
flex: 1;
border-radius: 15px;
position: relative;
transition: 240ms;
transition: margin-right 120ms;
will-change: margin-right;
}

.empty-search {
Expand All @@ -3442,16 +3438,23 @@ footer {
height: 30px;
width: 40px;
z-index: 1;
visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
@extend %clickable;
}
visibility: hidden;
cursor: pointer;

&:hover {
.icon {
opacity: 1;
}
}

.search .empty-search .icon-diagonal-cross {
fill: white;
opacity: 0.5;
.icon {
fill: white;
opacity: 0.5;
}
}

.filled.search .empty-search {
Expand Down Expand Up @@ -3489,7 +3492,8 @@ footer {
}

.search.focused .search-holder {
@include bidi-style(margin-right, -46px, margin-left, 0);
transition: margin-right 240ms;
@include bidi-style(margin-right, -59px, margin-left, 0);
}

.search.focused .logo {
Expand Down Expand Up @@ -3555,6 +3559,10 @@ footer {
padding: 9px 15px 8px 0;
margin-bottom: 7px;
height: auto !important;

.no-match & {
display: none;
}

.nav-tab-icon {
width: 18px;
Expand Down Expand Up @@ -3582,6 +3590,62 @@ footer {
list-style: none;
}

.global-search-detail-no-result {
margin: 0 10px;

.icon {
width: 30px;
height: 29px;
}
}

.global-search-detail-placeholder {
pointer-events: none;
color: inherit;

.nav-tab {
animation: fade-in 4s forwards;
}

.nav-tab-name {
background: linear-gradient(to right, hsl(0,0%,50%) 50%, hsl(0,0%,70%));
background-size: 200% 100%;
height: 10px;
width: 77%;
animation: placeholder-background 1.4s infinite;
}

&:nth-child(2) {
.nav-tab-name {
width: 54%;
}
}

&:nth-child(3) {
.nav-tab-name {
width: 68%;
}
}
}

@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

@keyframes placeholder-background {
from {
background-position: 0% 0%;
}
to {
background-position: -200% 0%;
}
}

.user-menu {
padding: 0;
margin: 0;
Expand Down Expand Up @@ -5843,6 +5907,11 @@ footer {
border-radius: 3px;
color: white;
border: none;

.icon {
margin-right: 10px;
fill: currentColor;
}

&.alert--info {
background: hsl(203,65%,55%);
Expand Down

0 comments on commit 2639df5

Please sign in to comment.