Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
iv
gitlab-ce
Commits
4b3d3446
Commit
4b3d3446
authored
Mar 08, 2016
by
Alfredo Sumaran
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Working version of autocomplete with categorized results
parent
bc590ce6
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
229 additions
and
49 deletions
+229
-49
app/assets/javascripts/dispatcher.js.coffee
app/assets/javascripts/dispatcher.js.coffee
+1
-6
app/assets/javascripts/lib/category_autocomplete.js.coffee
app/assets/javascripts/lib/category_autocomplete.js.coffee
+17
-0
app/assets/javascripts/search_autocomplete.js.coffee
app/assets/javascripts/search_autocomplete.js.coffee
+161
-8
app/helpers/search_helper.rb
app/helpers/search_helper.rb
+33
-26
app/views/layouts/_search.html.haml
app/views/layouts/_search.html.haml
+4
-9
app/views/shared/_location_badge.html.haml
app/views/shared/_location_badge.html.haml
+13
-0
No files found.
app/assets/javascripts/dispatcher.js.coffee
View file @
4b3d3446
...
...
@@ -151,9 +151,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
()
app/assets/javascripts/lib/category_autocomplete.js.coffee
0 → 100644
View file @
4b3d3446
$
.
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
)
)
app/assets/javascripts/search_autocomplete.js.coffee
View file @
4b3d3446
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
app/helpers/search_helper.rb
View file @
4b3d3446
...
...
@@ -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:
Webhooks 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:
"
Webhooks 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
[]
...
...
@@ -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
...
...
@@ -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
...
...
app/views/layouts/_search.html.haml
View file @
4b3d3446
.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
)
...
...
@@ -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
();
}
});
app/views/shared/_location_badge.html.haml
0 → 100644
View file @
4b3d3446
-
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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment