summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlfredo Sumaran <alfredo@gitlab.com>2016-03-08 19:39:14 -0500
committerJacob Schatz <jacobschatz@Jacobs-MBP.fios-router.home>2016-03-18 14:06:51 -0400
commit6a7f4a0767f059a2a3e4e4a4999046cffa860561 (patch)
tree5ac5eb68351a00c984f20b5fbf8418521050da05
parentc9e202c1d7cab4918e8b3789e9e6a553c30ead2a (diff)
downloadgitlab-ce-6a7f4a0767f059a2a3e4e4a4999046cffa860561.tar.gz
Apply styling and tweaks to autocomplete dropdown
-rw-r--r--app/assets/javascripts/lib/category_autocomplete.js.coffee32
-rw-r--r--app/assets/javascripts/search_autocomplete.js.coffee35
-rw-r--r--app/assets/stylesheets/framework/forms.scss34
-rw-r--r--app/assets/stylesheets/framework/header.scss20
-rw-r--r--app/assets/stylesheets/framework/jquery.scss34
-rw-r--r--app/assets/stylesheets/pages/search.scss70
-rw-r--r--app/helpers/search_helper.rb21
-rw-r--r--app/views/layouts/_search.html.haml13
-rw-r--r--app/views/shared/_location_badge.html.haml13
9 files changed, 186 insertions, 86 deletions
diff --git a/app/assets/javascripts/lib/category_autocomplete.js.coffee b/app/assets/javascripts/lib/category_autocomplete.js.coffee
index 490032dc782..c85fabbcd5b 100644
--- a/app/assets/javascripts/lib/category_autocomplete.js.coffee
+++ b/app/assets/javascripts/lib/category_autocomplete.js.coffee
@@ -14,4 +14,36 @@ $.widget( "custom.catcomplete", $.ui.autocomplete,
if item.category?
li.attr('aria-label', item.category + " : " + item.label)
+
+ _renderItem: (ul, item) ->
+ # Highlight occurrences
+ item.label = item.label.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + $.ui.autocomplete.escapeRegex(this.term) + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+
+ return $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .append( "<a>#{item.label}</a>" )
+ .appendTo( ul );
+
+ _resizeMenu: ->
+ if (isNaN(this.options.maxShowItems))
+ return
+
+ ul = this.menu.element.css(overflowX: '', overflowY: '', width: '', maxHeight: '')
+
+ lis = ul.children('li').css('whiteSpace', 'nowrap');
+
+ if (lis.length > this.options.maxShowItems)
+ ulW = ul.prop('clientWidth')
+
+ ul.css(
+ overflowX: 'hidden'
+ overflowY: 'auto'
+ maxHeight: lis.eq(0).outerHeight() * this.options.maxShowItems + 1
+ )
+
+ barW = ulW - ul.prop('clientWidth');
+ ul.width('+=' + barW);
+
+ # Original code from jquery.ui.autocomplete.js _resizeMenu()
+ ul.outerWidth(Math.max(ul.outerWidth() + 1, this.element.outerWidth()));
)
diff --git a/app/assets/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee
index df31b07910c..a6d5ab65239 100644
--- a/app/assets/javascripts/search_autocomplete.js.coffee
+++ b/app/assets/javascripts/search_autocomplete.js.coffee
@@ -24,7 +24,10 @@ class @SearchAutocomplete
@scopeInputEl = @$('#scope')
@saveOriginalState()
- @createAutocomplete()
+
+ if @locationBadgeEl.is(':empty')
+ @createAutocomplete()
+
@bindEvents()
$: (selector) ->
@@ -66,6 +69,12 @@ class @SearchAutocomplete
appendTo: 'form.navbar-form'
source: @autocompletePath + @query
minLength: 1
+ maxShowItems: 15
+ position:
+ # { my: "left top", at: "left bottom", collision: "none" }
+ my: "left-10 top+9"
+ at: "left bottom"
+ collision: "none"
close: (e) ->
e.preventDefault()
@@ -89,7 +98,9 @@ class @SearchAutocomplete
bindEvents: ->
- @searchInput.on 'keydown', @onSearchKeyDown
+ @searchInput.on 'keydown', @onSearchInputKeyDown
+ @searchInput.on 'focus', @onSearchInputFocus
+ @searchInput.on 'blur', @onSearchInputBlur
@wrap.on 'click', '.remove-badge', @onRemoveLocationBadgeClick
onRemoveLocationBadgeClick: (e) =>
@@ -97,7 +108,7 @@ class @SearchAutocomplete
@removeLocationBadge()
@searchInput.focus()
- onSearchKeyDown: (e) =>
+ onSearchInputKeyDown: (e) =>
# Remove tag when pressing backspace and input search is empty
if e.keyCode is @keyCode.BACKSPACE and e.currentTarget.value is ''
@removeLocationBadge()
@@ -106,14 +117,24 @@ class @SearchAutocomplete
else if e.keyCode is @keyCode.ESCAPE
@restoreOriginalState()
else
- # Create new autocomplete instance if it's not created
- @createAutocomplete() unless @catcomplete?
+ # Create new autocomplete if hasn't been created yet and there's no badge
+ if !@catComplete? and @locationBadgeEl.is(':empty')
+ @createAutocomplete()
+
+ onSearchInputFocus: =>
+ @wrap.addClass('search-active')
+
+ onSearchInputBlur: =>
+ @wrap.removeClass('search-active')
+
+ # If input is blank then restore state
+ @restoreOriginalState() if @searchInput.val() is ''
addLocationBadge: (item) ->
category = if item.category? then "#{item.category}: " else ''
value = if item.value? then item.value else ''
- html = "<span class='label label-primary'>
+ html = "<span class='location-badge'>
<i class='location-text'>#{category}#{value}</i>
<a class='remove-badge' href='#'>x</a>
</span>"
@@ -160,5 +181,5 @@ class @SearchAutocomplete
location.href = result.url
destroyAutocomplete: ->
- @catComplete.destroy() if @catcomplete?
+ @catComplete.destroy() if @catComplete?
@catComplete = null
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 4cb4129b71b..91b6451e68a 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -6,40 +6,6 @@ input {
border-radius: $border-radius-base;
}
-input[type='search'] {
- background-color: white;
- padding-left: 10px;
-}
-
-input[type='search'].search-input {
- background-repeat: no-repeat;
- background-position: 10px;
- background-size: 16px;
- background-position-x: 30%;
- padding-left: 10px;
- background-color: $gray-light;
-
- &.search-input[value=""] {
- background-image: url('data:image/png;base64,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');
- }
-
- &.search-input::-webkit-input-placeholder {
- text-align: center;
- }
-
- &.search-input:-moz-placeholder { /* Firefox 18- */
- text-align: center;
- }
-
- &.search-input::-moz-placeholder { /* Firefox 19+ */
- text-align: center;
- }
-
- &.search-input:-ms-input-placeholder {
- text-align: center;
- }
-}
-
input[type='text'].danger {
background: #f2dede!important;
border-color: #d66;
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 71a7ecab8ef..a6c9fce5b89 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -112,26 +112,6 @@ header {
}
}
- .search {
- margin-right: 10px;
- margin-left: 10px;
- margin-top: ($header-height - 36) / 2;
-
- form {
- margin: 0;
- padding: 0;
- }
-
- .search-input {
- width: 220px;
-
- &:focus {
- @include box-shadow(none);
- outline: none;
- }
- }
- }
-
.impersonation i {
color: $red-normal;
}
diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
index 525ed81b059..e0d655d3054 100644
--- a/app/assets/stylesheets/framework/jquery.scss
+++ b/app/assets/stylesheets/framework/jquery.scss
@@ -23,9 +23,39 @@
padding: 0;
margin-top: 2px;
z-index: 1001;
+ width: 240px;
+ margin-bottom: 0;
+ padding: 10px 10px;
+ font-size: 14px;
+ font-weight: normal;
+ background-color: $dropdown-bg;
+ border: 1px solid $dropdown-border-color;
+ border-radius: $border-radius-base;
+ box-shadow: 0 2px 4px $dropdown-shadow-color;
- .ui-menu-item a {
- padding: 4px 10px;
+ .ui-menu-item {
+ display: block;
+ position: relative;
+ padding: 0 10px;
+ color: $dropdown-link-color;
+ line-height: 34px;
+ text-overflow: ellipsis;
+ border-radius: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ border: none;
+
+ &.ui-state-focus {
+ background-color: $dropdown-link-hover-bg;
+ text-decoration: none;
+ margin: 0;
+ }
+ }
+
+ .ui-autocomplete-category {
+ text-transform: uppercase;
+ font-size: 11px;
+ color: #7f8fa4;
}
}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index b6e45024644..57b88268c03 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -21,3 +21,73 @@
}
}
+
+.search {
+ margin-right: 10px;
+ margin-left: 10px;
+ margin-top: ($header-height - 35) / 2;
+
+ &.search-active {
+ form {
+ @extend .form-control:focus;
+ }
+
+ .location-badge {
+ @include transition(all .15s);
+ background-color: $input-border-focus;
+ color: $white-light;
+ }
+ }
+
+ form {
+ @extend .form-control;
+ margin: 0;
+ padding: 4px;
+ width: 350px;
+ line-height: 24px;
+ overflow: hidden;
+ }
+
+ .location-text {
+ font-style: normal;
+ }
+
+ .remove-badge {
+ display: none;
+ }
+
+ .search-input {
+ border: none;
+ font-size: 14px;
+ outline: none;
+ padding: 0;
+ margin-left: 2px;
+ line-height: 25px;
+ width: 100%;
+ }
+
+ .location-badge {
+ line-height: 25px;
+ padding: 0 5px;
+ border-radius: 2px;
+ font-size: 14px;
+ font-style: normal;
+ color: #AAAAAA;
+ display: inline-block;
+ background-color: #F5F5F5;
+ vertical-align: top;
+ }
+
+ .search-input-container {
+ display: flex;
+ }
+
+ .search-location-badge, .search-input-wrap {
+ // Fallback if flex is not supported
+ display: inline-block;
+ }
+
+ .search-input-wrap {
+ width: 100%;
+ }
+}
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index 9102fd6d501..cbead1b8b74 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -48,20 +48,19 @@ module SearchHelper
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
- prefix = "Project - " + search_result_sanitize(@project.name_with_namespace)
ref = @ref || @project.repository.root_ref
[
- { 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) },
+ { category: "Current Project", label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },
+ { category: "Current Project", label: "Commits", url: namespace_project_commits_path(@project.namespace, @project, ref) },
+ { category: "Current Project", label: "Network", url: namespace_project_network_path(@project.namespace, @project, ref) },
+ { category: "Current Project", label: "Graph", url: namespace_project_graph_path(@project.namespace, @project, ref) },
+ { category: "Current Project", label: "Issues", url: namespace_project_issues_path(@project.namespace, @project) },
+ { category: "Current Project", label: "Merge Requests", url: namespace_project_merge_requests_path(@project.namespace, @project) },
+ { category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
+ { category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
+ { category: "Current Project", label: "Members", url: namespace_project_project_members_path(@project.namespace, @project) },
+ { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) },
]
else
[]
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index c5002893831..843c833b4fe 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,9 +1,12 @@
-.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)
+.search.search-form
+ = form_tag search_path, method: :get, class: 'navbar-form' do |f|
+ .search-input-container
+ .search-location-badge
+ = render 'shared/location_badge'
+ .search-input-wrap
+ = search_field_tag "search", nil, placeholder: 'Search', class: "search-input", spellcheck: false, tabindex: "1", autocomplete: 'off'
+ = hidden_field_tag :group_id, @group.try(:id)
= hidden_field_tag :project_id, @project && @project.persisted? ? @project.id : ''
- if @project && @project.persisted?
diff --git a/app/views/shared/_location_badge.html.haml b/app/views/shared/_location_badge.html.haml
index dfe8bc010d6..f1ecc060cf1 100644
--- a/app/views/shared/_location_badge.html.haml
+++ b/app/views/shared/_location_badge.html.haml
@@ -3,11 +3,10 @@
- if controller.controller_path =~ /^projects/
- label = 'This project'
-.search-location-badge
- - if label.present?
- %span.label.label-primary
- %i.location-text
- = label
+- if label.present?
+ %span.location-badge
+ %i.location-text
+ = label
- %a.remove-badge{href: '#'}
- x
+ %a.remove-badge{href: '#'}
+ x