diff --git a/app/assets/javascripts/app/controllers/_application_controller.coffee b/app/assets/javascripts/app/controllers/_application_controller.coffee index 0de01a8f9..48d0243b8 100644 --- a/app/assets/javascripts/app/controllers/_application_controller.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller.coffee @@ -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) -> diff --git a/app/assets/javascripts/app/controllers/_channel/email.coffee b/app/assets/javascripts/app/controllers/_channel/email.coffee index 876f92d54..3750aad99 100644 --- a/app/assets/javascripts/app/controllers/_channel/email.coffee +++ b/app/assets/javascripts/app/controllers/_channel/email.coffee @@ -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) diff --git a/app/assets/javascripts/app/controllers/navigation.coffee b/app/assets/javascripts/app/controllers/navigation.coffee index b4a76109e..5dd035888 100644 --- a/app/assets/javascripts/app/controllers/navigation.coffee +++ b/app/assets/javascripts/app/controllers/navigation.coffee @@ -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') diff --git a/app/assets/javascripts/app/controllers/search.coffee b/app/assets/javascripts/app/controllers/search.coffee index 47a2ee434..1556bb321 100644 --- a/app/assets/javascripts/app/controllers/search.coffee +++ b/app/assets/javascripts/app/controllers/search.coffee @@ -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 }) diff --git a/app/assets/javascripts/app/controllers/widget/online_notification.coffee b/app/assets/javascripts/app/controllers/widget/online_notification.coffee index 9fc2ea98f..9c512a0f1 100644 --- a/app/assets/javascripts/app/controllers/widget/online_notification.coffee +++ b/app/assets/javascripts/app/controllers/widget/online_notification.coffee @@ -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 diff --git a/app/assets/javascripts/app/lib/app_post/global_search.coffee b/app/assets/javascripts/app/lib/app_post/global_search.coffee new file mode 100644 index 000000000..5dcfc1efa --- /dev/null +++ b/app/assets/javascripts/app/lib/app_post/global_search.coffee @@ -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) + ) diff --git a/app/assets/javascripts/app/views/navigation.jst.eco b/app/assets/javascripts/app/views/navigation.jst.eco index 09c734560..3ff4a2713 100644 --- a/app/assets/javascripts/app/views/navigation.jst.eco +++ b/app/assets/javascripts/app/views/navigation.jst.eco @@ -16,7 +16,7 @@ <%- @Icon('searchdetail') %>