Skip to content
Snippets Groups Projects
Commit 13fee27f authored by Alfredo Sumaran's avatar Alfredo Sumaran
Browse files

Working version of autocomplete with categorized results

parent 903aa7c9
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -148,9 +148,4 @@ class Dispatcher
new Shortcuts()
 
initSearch: ->
opts = $('.search-autocomplete-opts')
path = opts.data('autocomplete-path')
project_id = opts.data('autocomplete-project-id')
project_ref = opts.data('autocomplete-project-ref')
new SearchAutocomplete(path, project_id, project_ref)
new SearchAutocomplete()
$.widget( "custom.catcomplete", $.ui.autocomplete,
_create: ->
@_super();
@widget().menu("option", "items", "> :not(.ui-autocomplete-category)")
_renderMenu: (ul, items) ->
currentCategory = ''
$.each items, (index, item) =>
if item.category isnt currentCategory
ul.append("<li class='ui-autocomplete-category'>#{item.category}</li>")
currentCategory = item.category
li = @_renderItemData(ul, item)
if item.category?
li.attr('aria-label', item.category + " : " + item.label)
)
class @SearchAutocomplete
constructor: (search_autocomplete_path, project_id, project_ref) ->
project_id = '' unless project_id
project_ref = '' unless project_ref
query = "?project_id=" + project_id + "&project_ref=" + project_ref
constructor: (opts = {}) ->
{
@wrap = $('.search')
@optsEl = @wrap.find('.search-autocomplete-opts')
@autocompletePath = @optsEl.data('autocomplete-path')
@projectId = @optsEl.data('autocomplete-project-id') || ''
@projectRef = @optsEl.data('autocomplete-project-ref') || ''
} = opts
 
$("#search").autocomplete
source: search_autocomplete_path + query
@keyCode =
ESCAPE: 27
BACKSPACE: 8
TAB: 9
ENTER: 13
@locationBadgeEl = @$('.search-location-badge')
@locationText = @$('.location-text')
@searchInput = @$('.search-input')
@projectInputEl = @$('#project_id')
@groupInputEl = @$('#group_id')
@searchCodeInputEl = @$('#search_code')
@repositoryInputEl = @$('#repository_ref')
@scopeInputEl = @$('#scope')
@saveOriginalState()
@createAutocomplete()
@bindEvents()
$: (selector) ->
@wrap.find(selector)
saveOriginalState: ->
@originalState = @serializeState()
restoreOriginalState: ->
inputs = Object.keys @originalState
for input in inputs
@$("##{input}").val(@originalState[input])
if @originalState._location is ''
@locationBadgeEl.html('')
else
@addLocationBadge(
value: @originalState._location
)
serializeState: ->
{
# Search Criteria
project_id: @projectInputEl.val()
group_id: @groupInputEl.val()
search_code: @searchCodeInputEl.val()
repository_ref: @repositoryInputEl.val()
# Location badge
_location: $.trim(@locationText.text())
}
createAutocomplete: ->
@query = "?project_id=" + @projectId + "&project_ref=" + @projectRef
@catComplete = @searchInput.catcomplete
appendTo: 'form.navbar-form'
source: @autocompletePath + @query
minLength: 1
select: (event, ui) ->
location.href = ui.item.url
close: (e) ->
e.preventDefault()
select: (event, ui) =>
# Pressing enter choses an alternative
if event.keyCode is @keyCode.ENTER
@goToResult(ui.item)
else
# Pressing tab sets the scope
if event.keyCode is @keyCode.TAB and ui.item.scope?
@setLocationBadge(ui.item)
@searchInput
.val('') # remove selected value from input
.focus()
else
# If option is not a scope go to page
@goToResult(ui.item)
# Return false to avoid focus on the next element
return false
bindEvents: ->
@searchInput.on 'keydown', @onSearchKeyDown
@wrap.on 'click', '.remove-badge', @onRemoveLocationBadgeClick
onRemoveLocationBadgeClick: (e) =>
e.preventDefault()
@removeLocationBadge()
@searchInput.focus()
onSearchKeyDown: (e) =>
# Remove tag when pressing backspace and input search is empty
if e.keyCode is @keyCode.BACKSPACE and e.currentTarget.value is ''
@removeLocationBadge()
@destroyAutocomplete()
@searchInput.focus()
else if e.keyCode is @keyCode.ESCAPE
@restoreOriginalState()
else
# Create new autocomplete instance if it's not created
@createAutocomplete() unless @catcomplete?
addLocationBadge: (item) ->
category = if item.category? then "#{item.category}: " else ''
value = if item.value? then item.value else ''
html = "<span class='label label-primary'>
<i class='location-text'>#{category}#{value}</i>
<a class='remove-badge' href='#'>x</a>
</span>"
@locationBadgeEl.html(html)
setLocationBadge: (item) ->
@addLocationBadge(item)
# Reset input states
@resetSearchState()
switch item.scope
when 'projects'
@projectInputEl.val(item.id)
# @searchCodeInputEl.val('true') # TODO: always true for projects?
# @repositoryInputEl.val('master') # TODO: always master?
when 'groups'
@groupInputEl.val(item.id)
removeLocationBadge: ->
@locationBadgeEl.empty()
# Reset state
@resetSearchState()
resetSearchState: ->
# Remove scope
@scopeInputEl.val('')
# Remove group
@groupInputEl.val('')
# Remove project id
@projectInputEl.val('')
# Remove code search
@searchCodeInputEl.val('')
# Remove repository ref
@repositoryInputEl.val('')
goToResult: (result) ->
location.href = result.url
destroyAutocomplete: ->
@catComplete.destroy() if @catcomplete?
@catComplete = null
Loading
Loading
@@ -23,45 +23,45 @@ module SearchHelper
# Autocomplete results for various settings pages
def default_autocomplete
[
{ label: "Profile settings", url: profile_path },
{ label: "SSH Keys", url: profile_keys_path },
{ label: "Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path },
{ category: "Settings", label: "Profile settings", url: profile_path },
{ category: "Settings", label: "SSH Keys", url: profile_keys_path },
{ category: "Settings", label: "Dashboard", url: root_path },
{ category: "Settings", label: "Admin Section", url: admin_root_path },
]
end
 
# Autocomplete results for internal help pages
def help_autocomplete
[
{ label: "help: API Help", url: help_page_path("api", "README") },
{ label: "help: Markdown Help", url: help_page_path("markdown", "markdown") },
{ label: "help: Permissions Help", url: help_page_path("permissions", "permissions") },
{ label: "help: Public Access Help", url: help_page_path("public_access", "public_access") },
{ label: "help: Rake Tasks Help", url: help_page_path("raketasks", "README") },
{ label: "help: SSH Keys Help", url: help_page_path("ssh", "README") },
{ label: "help: System Hooks Help", url: help_page_path("system_hooks", "system_hooks") },
{ label: "help: Web Hooks Help", url: help_page_path("web_hooks", "web_hooks") },
{ label: "help: Workflow Help", url: help_page_path("workflow", "README") },
{ category: "Help", label: "API Help", url: help_page_path("api", "README"), },
{ category: "Help", label: "Markdown Help", url: help_page_path("markdown", "markdown") },
{ category: "Help", label: "Permissions Help", url: help_page_path("permissions", "permissions") },
{ category: "Help", label: "Public Access Help", url: help_page_path("public_access", "public_access") },
{ category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks", "README") },
{ category: "Help", label: "SSH Keys Help", url: help_page_path("ssh", "README") },
{ category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks", "system_hooks") },
{ category: "Help", label: "Web Hooks Help", url: help_page_path("web_hooks", "web_hooks") },
{ category: "Help", label: "Workflow Help", url: help_page_path("workflow", "README") },
]
end
 
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
prefix = search_result_sanitize(@project.name_with_namespace)
prefix = "Project - " + search_result_sanitize(@project.name_with_namespace)
ref = @ref || @project.repository.root_ref
 
[
{ label: "#{prefix} - Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
{ label: "#{prefix} - Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) },
{ label: "#{prefix} - Network", url: namespace_project_network_path(@project.namespace, @project, ref) },
{ label: "#{prefix} - Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) },
{ label: "#{prefix} - Issues", url: namespace_project_issues_path(@project.namespace, @project) },
{ label: "#{prefix} - Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
{ label: "#{prefix} - Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ label: "#{prefix} - Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
{ label: "#{prefix} - Members", url: namespace_project_project_members_path(@project.namespace, @project) },
{ label: "#{prefix} - Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
{ category: prefix, label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
{ category: prefix, label: "Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) },
{ category: prefix, label: "Network", url: namespace_project_network_path(@project.namespace, @project, ref) },
{ category: prefix, label: "Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) },
{ category: prefix, label: "Issues", url: namespace_project_issues_path(@project.namespace, @project) },
{ category: prefix, label: "Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
{ category: prefix, label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ category: prefix, label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
{ category: prefix, label: "Members", url: namespace_project_project_members_path(@project.namespace, @project) },
{ category: prefix, label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
]
else
[]
Loading
Loading
@@ -72,7 +72,10 @@ module SearchHelper
def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
category: "Groups",
scope: "groups",
id: group.id,
label: "#{search_result_sanitize(group.name)}",
url: group_path(group)
}
end
Loading
Loading
@@ -83,7 +86,11 @@ module SearchHelper
current_user.authorized_projects.search_by_title(term).
sorted_by_stars.non_archived.limit(limit).map do |p|
{
label: "project: #{search_result_sanitize(p.name_with_namespace)}",
category: "Projects",
scope: "projects",
id: p.id,
value: "#{search_result_sanitize(p.name)}",
label: "#{search_result_sanitize(p.name_with_namespace)}",
url: namespace_project_path(p.namespace, p)
}
end
Loading
Loading
.search
= form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f|
= render 'shared/location_badge'
= search_field_tag "search", nil, placeholder: 'Search', class: "search-input form-control", spellcheck: false, tabindex: "1"
= hidden_field_tag :group_id, @group.try(:id)
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
 
= hidden_field_tag :project_id, @project && @project.persisted? ? @project.id : ''
- if @project && @project.persisted?
- if current_controller?(:issues)
= hidden_field_tag :scope, 'issues'
- elsif current_controller?(:merge_requests)
Loading
Loading
@@ -21,10 +23,3 @@
= hidden_field_tag :repository_ref, @ref
= button_tag 'Go' if ENV['RAILS_ENV'] == 'test'
.search-autocomplete-opts.hide{:'data-autocomplete-path' => search_autocomplete_path, :'data-autocomplete-project-id' => @project.try(:id), :'data-autocomplete-project-ref' => @ref }
:javascript
$('.search-input').on('keyup', function(e) {
if (e.keyCode == 27) {
$('.search-input').blur();
}
});
- if controller.controller_path =~ /^groups/
- label = 'This group'
- if controller.controller_path =~ /^projects/
- label = 'This project'
.search-location-badge
- if label.present?
%span.label.label-primary
%i.location-text
= label
%a.remove-badge{href: '#'}
x
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment