diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index 960585245d797536149bb4e575903f734fc1bc32..4b78bcde77488edd0c1c8ff375ff4afbf75fc151 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -1,13 +1,29 @@ class GitLabDropdownFilter BLUR_KEYCODES = [27, 40] + HAS_VALUE_CLASS = "has-value" - constructor: (@dropdown, @options) -> - @input = @dropdown.find(".dropdown-input .dropdown-input-field") + constructor: (@input, @options) -> + $inputContainer = @input.parent() + $clearButton = $inputContainer.find('.js-dropdown-input-clear') + + # Clear click + $clearButton.on 'click', (e) => + e.preventDefault() + e.stopPropagation() + @input + .val('') + .trigger('keyup') + .focus() # Key events timeout = "" @input.on "keyup", (e) => - if e.keyCode is 13 && @input.val() isnt "" + if @input.val() isnt "" and !$inputContainer.hasClass HAS_VALUE_CLASS + $inputContainer.addClass HAS_VALUE_CLASS + else if @input.val() is "" and $inputContainer.hasClass HAS_VALUE_CLASS + $inputContainer.removeClass HAS_VALUE_CLASS + + if e.keyCode is 13 and @input.val() isnt "" if @options.enterCallback @options.enterCallback() return @@ -95,7 +111,9 @@ class GitLabDropdown # Init filiterable if @options.filterable - @filter = new GitLabDropdownFilter @dropdown, + @input = @dropdown.find('.dropdown-input .dropdown-input-field') + + @filter = new GitLabDropdownFilter @input, remote: @options.filterRemote query: @options.data keys: @options.search.fields @@ -103,6 +121,7 @@ class GitLabDropdown return @fullData callback: (data) => @parseData data + @highlightRow 1 enterCallback: => @selectFirstRow() @@ -224,11 +243,19 @@ class GitLabDropdown noResults: -> html = "
  • " - html += "" + html += "" html += "No matching results." html += "" html += "
  • " + highlightRow: (index) -> + if @input.val() isnt "" + selector = '.dropdown-content li:first-child a' + if @dropdown.find(".dropdown-toggle-page").length + selector = ".dropdown-page-one .dropdown-content li:first-child a" + + $(selector).addClass 'is-focused' + rowClicked: (el) -> fieldName = @options.fieldName field = @dropdown.parent().find("input[name='#{fieldName}']") @@ -272,7 +299,7 @@ class GitLabDropdown if @dropdown.find(".dropdown-toggle-page").length selector = ".dropdown-page-one .dropdown-content li:first-child a" - # similute a click on the first link + # simulate a click on the first link $(selector).trigger "click" $.fn.glDropdown = (opts) -> diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee index f3cb1e3bc09fe5ab6bea71432d0e5b1319147a83..e08648d583b169af9993de3c80da4284d2a46354 100644 --- a/app/assets/javascripts/labels_select.js.coffee +++ b/app/assets/javascripts/labels_select.js.coffee @@ -6,7 +6,7 @@ class @LabelsSelect labelUrl = $dropdown.data('labels') selectedLabel = $dropdown.data('selected') if selectedLabel - selectedLabel = selectedLabel.split(',') + selectedLabel = selectedLabel.toString().split(',') newLabelField = $('#new_label_name') newColorField = $('#new_label_color') showNo = $dropdown.data('show-no') @@ -14,38 +14,81 @@ class @LabelsSelect defaultLabel = $dropdown.data('default-label') if newLabelField.length + $newLabelCreateButton = $('.js-new-label-btn') + $colorPreview = $('.js-dropdown-label-color-preview') $newLabelError = $dropdown.parent().find('.js-label-error') $newLabelError.hide() + # Suggested colors in the dropdown to chose from pre-chosen colors $('.suggest-colors-dropdown a').on 'click', (e) -> e.preventDefault() e.stopPropagation() - newColorField.val $(this).data('color') - $('.js-dropdown-label-color-preview') + newColorField + .val($(this).data('color')) + .trigger('change') + $colorPreview .css 'background-color', $(this).data('color') + .parent() .addClass 'is-active' - $('.js-new-label-btn').on 'click', (e) -> + # Cancel button takes back to first page + resetForm = -> + newLabelField + .val '' + .trigger 'change' + newColorField + .val '' + .trigger 'change' + $colorPreview + .css 'background-color', '' + .parent() + .removeClass 'is-active' + + $('.dropdown-menu-back').on 'click', -> + resetForm() + + $('.js-cancel-label-btn').on 'click', (e) -> e.preventDefault() e.stopPropagation() + resetForm() + $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' + # Listen for change and keyup events on label and color field + # This allows us to enable the button when ready + enableLabelCreateButton = -> if newLabelField.val() isnt '' and newColorField.val() isnt '' - $newLabelError.hide() - $('.js-new-label-btn').disable() - - # Create new label with API - Api.newLabel projectId, { - name: newLabelField.val() - color: newColorField.val() - }, (label) -> - $('.js-new-label-btn').enable() - - if label.message? - $newLabelError - .text label.message - .show() - else - $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' + $newLabelCreateButton.enable() + else + $newLabelCreateButton.disable() + + newLabelField.on 'keyup change', enableLabelCreateButton + + newColorField.on 'keyup change', enableLabelCreateButton + + # Send the API call to create the label + $newLabelCreateButton + .disable() + .on 'click', (e) -> + e.preventDefault() + e.stopPropagation() + + if newLabelField.val() isnt '' and newColorField.val() isnt '' + $newLabelError.hide() + $('.js-new-label-btn').disable() + + # Create new label with API + Api.newLabel projectId, { + name: newLabelField.val() + color: newColorField.val() + }, (label) -> + $('.js-new-label-btn').enable() + + if label.message? + $newLabelError + .text label.message + .show() + else + $('.dropdown-menu-back', $dropdown.parent()).trigger 'click' $dropdown.glDropdown( data: (term, callback) -> @@ -78,8 +121,11 @@ class @LabelsSelect else selected = if label.title is selectedLabel then 'is-active' else '' + color = if label.color? then "" else "" + "
  • + #{color} #{label.title}
  • " diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee index 3d6452d2f4693d36691df7ff987bc257de83d761..84193400890b4f8a19f6fe67146c2101bf68b08c 100644 --- a/app/assets/javascripts/users_select.js.coffee +++ b/app/assets/javascripts/users_select.js.coffee @@ -30,6 +30,7 @@ class @UsersSelect if showNullUser showDivider += 1 users.unshift( + beforeDivider: true name: 'Unassigned', id: 0 ) @@ -39,6 +40,7 @@ class @UsersSelect name = showAnyUser name = 'Any User' if name == true anyUser = { + beforeDivider: true name: name, id: null } @@ -75,20 +77,27 @@ class @UsersSelect selected = if user.id is selectedId then "is-active" else "" img = "" - if avatar - img = "" - - "
  • - - #{img} - + if user.beforeDivider? + "
  • + #{user.name} - - - #{username} - - -
  • " + + " + else + if avatar + img = "" + + "
  • + + #{img} + + #{user.name} + + + #{username} + + +
  • " ) $('.ajax-users-select').each (i, select) => diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index d92cf6e6c44f7ca4c1eeaec30e4c01e632a20c38..2d616fc660c520afb058abe39e37f8df17e7fd8f 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -130,6 +130,12 @@ text-decoration: none; outline: 0; } + + &.dropdown-menu-empty-link { + &.is-focused { + background-color: $dropdown-empty-row-bg; + } + } } } @@ -183,7 +189,7 @@ } .dropdown-select { - width: 280px; + width: 300px; } .dropdown-menu-align-right { @@ -237,7 +243,7 @@ .dropdown-title-button { position: absolute; - top: -1px; + top: 0; padding: 0; color: $dropdown-title-btn-color; font-size: 14px; @@ -270,6 +276,22 @@ font-size: 12px; pointer-events: none; } + + .dropdown-input-clear { + display: none; + cursor: pointer; + pointer-events: all; + } + + &.has-value { + .dropdown-input-clear { + display: block; + } + + .dropdown-input-search { + display: none; + } + } } .dropdown-input-field { @@ -286,13 +308,13 @@ border-color: $dropdown-input-focus-border; box-shadow: 0 0 4px $dropdown-input-focus-shadow; - + .fa { + ~ .fa { color: $dropdown-link-color; } } &:hover { - + .fa { + ~ .fa { color: $dropdown-link-color; } } @@ -338,11 +360,12 @@ } } -.dropdown-menu-labels { - .label { - position: relative; - width: 30px; - margin-right: 5px; - text-indent: -99999px; - } +.dropdown-label-box { + position: relative; + top: 3px; + margin-right: 5px; + display: inline-block; + width: 15px; + height: 15px; + border-radius: $border-radius-base; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index be626678bd7a88e3682007c8fda9e66b9848c5a9..61e0dd4d672b1f6e95704f68df796ea6a3a6e784 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -168,13 +168,14 @@ $regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif */ $dropdown-bg: #fff; $dropdown-link-color: #555; -$dropdown-link-hover-bg: rgba(#000, .04); +$dropdown-link-hover-bg: $row-hover; +$dropdown-empty-row-bg: rgba(#000, .04); $dropdown-border-color: rgba(#000, .1); $dropdown-shadow-color: rgba(#000, .1); $dropdown-divider-color: rgba(#000, .1); $dropdown-header-color: #959494; $dropdown-title-btn-color: #bfbfbf; -$dropdown-input-color: #c7c7c7; +$dropdown-input-color: #555; $dropdown-input-focus-border: rgb(58, 171, 240); $dropdown-input-focus-shadow: rgba(#000, .2); $dropdown-loading-bg: rgba(#fff, .6); diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 3c13573c8fe93cee7d0380a0be699468f4d82d38..4e02ec4e89164475eea0bd8f50fcb0ce866a33c6 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -9,28 +9,45 @@ } &.suggest-colors-dropdown { - margin-bottom: 5px; + margin-top: 10px; + margin-bottom: 10px; + border-radius: $border-radius-base; + overflow: hidden; a { @include border-radius(0); - width: 36.7px; + width: (100% / 7); margin-right: 0; margin-bottom: -5px; } } } -.dropdown-label-color-preview { - display: none; - margin-top: 5px; - width: 100%; - height: 25px; +.dropdown-new-label { + .dropdown-content { + max-height: 260px; + } +} + +.dropdown-label-color-input { + position: relative; + margin-bottom: 10px; &.is-active { - display: block; + padding-left: 32px; } } +.dropdown-label-color-preview { + position: absolute; + left: 0; + top: 0; + width: 32px; + height: 32px; + border-top-left-radius: $border-radius-base; + border-bottom-left-radius: $border-radius-base; +} + .label-row { .label { padding: 9px; diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index ceff1fbb1618a0d16b1f658a438eabc4e0fc4da5..316a10b7da36ee52b6b349d13d9cce4505670b0d 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -70,7 +70,8 @@ def dropdown_title(title, back: false) def dropdown_filter(placeholder) content_tag :div, class: "dropdown-input" do filter_output = search_field_tag nil, nil, class: "dropdown-input-field", placeholder: placeholder - filter_output << icon('search') + filter_output << icon('search', class: "dropdown-input-search") + filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button") filter_output.html_safe end diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml index 186087e8f89381a08fa8eb20aaa3a106e7236f9c..006a34a11e3ea387f3e387ff0ef27a46c4112552 100644 --- a/app/views/shared/issuable/_label_dropdown.html.haml +++ b/app/views/shared/issuable/_label_dropdown.html.haml @@ -24,17 +24,21 @@ - else View labels - if can? current_user, :admin_label, @project and @project - .dropdown-page-two + .dropdown-page-two.dropdown-new-label = dropdown_title("Create new label", back: true) = dropdown_content do .dropdown-labels-error.js-label-error - %input#new_label_color{type: "hidden"} %input#new_label_name.dropdown-input-field{type: "text", placeholder: "Name new label"} - .dropdown-label-color-preview.js-dropdown-label-color-preview .suggest-colors.suggest-colors-dropdown - suggested_colors.each do |color| = link_to '#', style: "background-color: #{color}", data: { color: color } do   - %button.btn.btn-primary.js-new-label-btn{type: "button"} - Create + .dropdown-label-color-input + .dropdown-label-color-preview.js-dropdown-label-color-preview + %input#new_label_color.dropdown-input-field{ type: "text" } + .clearfix + %button.btn.btn-primary.pull-left.js-new-label-btn{type: "button"} + Create + %button.btn.btn-default.pull-right.js-cancel-label-btn{type: "button"} + Cancel = dropdown_loading diff --git a/features/steps/dashboard/issues.rb b/features/steps/dashboard/issues.rb index f4a56865532559da8682fce5469fc6d539a4e237..93aa77589be53982619b5a68514560dcfb67bfc8 100644 --- a/features/steps/dashboard/issues.rb +++ b/features/steps/dashboard/issues.rb @@ -43,10 +43,10 @@ class Spinach::Features::DashboardIssues < Spinach::FeatureSteps step 'I click "All" link' do find('.js-author-search').click - find('.dropdown-menu-user-full-name', match: :first).click + find('.dropdown-content a', match: :first).click find('.js-assignee-search').click - find('.dropdown-menu-user-full-name', match: :first).click + find('.dropdown-content a', match: :first).click end def should_see(issue)