Commit 74570336 authored by Winnie Hellmann's avatar Winnie Hellmann

Cleanup new branch/merge request form in issues

parent a6b9eb5d
Pipeline #17330245 passed with stages
in 30 minutes and 50 seconds
...@@ -180,6 +180,7 @@ export default class CreateMergeRequestDropdown { ...@@ -180,6 +180,7 @@ export default class CreateMergeRequestDropdown {
valueAttribute: 'data-text', valueAttribute: 'data-text',
}, },
], ],
hideOnClick: false,
}; };
} }
......
...@@ -3,7 +3,6 @@ const DATA_DROPDOWN = 'data-dropdown'; ...@@ -3,7 +3,6 @@ const DATA_DROPDOWN = 'data-dropdown';
const SELECTED_CLASS = 'droplab-item-selected'; const SELECTED_CLASS = 'droplab-item-selected';
const ACTIVE_CLASS = 'droplab-item-active'; const ACTIVE_CLASS = 'droplab-item-active';
const IGNORE_CLASS = 'droplab-item-ignore'; const IGNORE_CLASS = 'droplab-item-ignore';
const IGNORE_HIDING_CLASS = 'droplab-item-ignore-hiding';
// Matches `{{anything}}` and `{{ everything }}`. // Matches `{{anything}}` and `{{ everything }}`.
const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g; const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g;
...@@ -14,5 +13,4 @@ export { ...@@ -14,5 +13,4 @@ export {
ACTIVE_CLASS, ACTIVE_CLASS,
TEMPLATE_REGEX, TEMPLATE_REGEX,
IGNORE_CLASS, IGNORE_CLASS,
IGNORE_HIDING_CLASS,
}; };
import utils from './utils'; import utils from './utils';
import { SELECTED_CLASS, IGNORE_CLASS, IGNORE_HIDING_CLASS } from './constants'; import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
class DropDown { class DropDown {
constructor(list, config = {}) { constructor(list, config = { }) {
this.currentIndex = 0; this.currentIndex = 0;
this.hidden = true; this.hidden = true;
this.list = typeof list === 'string' ? document.querySelector(list) : list; this.list = typeof list === 'string' ? document.querySelector(list) : list;
this.items = []; this.items = [];
this.eventWrapper = {}; this.eventWrapper = {};
this.hideOnClick = config.hideOnClick !== false;
if (config.addActiveClassToDropdownButton) { if (config.addActiveClassToDropdownButton) {
this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle'); this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle');
...@@ -37,7 +38,6 @@ class DropDown { ...@@ -37,7 +38,6 @@ class DropDown {
clickEvent(e) { clickEvent(e) {
if (e.target.tagName === 'UL') return; if (e.target.tagName === 'UL') return;
if (e.target.classList.contains(IGNORE_CLASS)) return;
const selected = utils.closest(e.target, 'LI'); const selected = utils.closest(e.target, 'LI');
if (!selected) return; if (!selected) return;
...@@ -45,7 +45,9 @@ class DropDown { ...@@ -45,7 +45,9 @@ class DropDown {
this.addSelectedClass(selected); this.addSelectedClass(selected);
e.preventDefault(); e.preventDefault();
if (!e.target.classList.contains(IGNORE_HIDING_CLASS)) this.hide(); if (this.hideOnClick) {
this.hide();
}
const listEvent = new CustomEvent('click.dl', { const listEvent = new CustomEvent('click.dl', {
detail: { detail: {
...@@ -74,6 +76,9 @@ class DropDown { ...@@ -74,6 +76,9 @@ class DropDown {
this.list.addEventListener('click', this.eventWrapper.clickEvent); this.list.addEventListener('click', this.eventWrapper.clickEvent);
this.list.addEventListener('keyup', this.eventWrapper.closeDropdown); this.list.addEventListener('keyup', this.eventWrapper.closeDropdown);
const ignoreClick = event => event.stopPropagation();
this.list.querySelectorAll(`.${IGNORE_CLASS}`).forEach(element => element.addEventListener('click', ignoreClick));
} }
closeDropdown(event) { closeDropdown(event) {
......
...@@ -449,9 +449,11 @@ img.emoji { ...@@ -449,9 +449,11 @@ img.emoji {
.prepend-top-10 { margin-top: 10px; } .prepend-top-10 { margin-top: 10px; }
.prepend-top-15 { margin-top: 15px; } .prepend-top-15 { margin-top: 15px; }
.prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-16 { margin-top: 16px; }
.prepend-top-20 { margin-top: 20px; } .prepend-top-20 { margin-top: 20px; }
.prepend-left-4 { margin-left: 4px; } .prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; } .prepend-left-5 { margin-left: 5px; }
.prepend-left-8 { margin-left: 8px; }
.prepend-left-10 { margin-left: 10px; } .prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; } .prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px; } .prepend-left-20 { margin-left: 20px; }
......
...@@ -736,10 +736,6 @@ ...@@ -736,10 +736,6 @@
} }
} }
.droplab-item-ignore {
pointer-events: none;
}
.pika-single.animate-picker.is-bound, .pika-single.animate-picker.is-bound,
.pika-single.animate-picker.is-bound.is-hidden { .pika-single.animate-picker.is-bound.is-hidden {
/* /*
......
...@@ -182,6 +182,7 @@ label { ...@@ -182,6 +182,7 @@ label {
.help-block { .help-block {
margin-bottom: 0; margin-bottom: 0;
margin-top: #{$grid-size / 2};
} }
.gl-field-error { .gl-field-error {
......
...@@ -181,11 +181,6 @@ ul.related-merge-requests > li { ...@@ -181,11 +181,6 @@ ul.related-merge-requests > li {
} }
.create-mr-dropdown-wrap { .create-mr-dropdown-wrap {
.branch-message,
.ref-message {
display: none;
}
.ref::selection { .ref::selection {
color: $placeholder-text-color; color: $placeholder-text-color;
} }
...@@ -216,6 +211,17 @@ ul.related-merge-requests > li { ...@@ -216,6 +211,17 @@ ul.related-merge-requests > li {
transform: translateY(0); transform: translateY(0);
display: none; display: none;
margin-top: 4px; margin-top: 4px;
// override dropdown item styles
.btn.btn-success {
@include btn-default;
@include btn-green;
border-style: solid;
border-width: 1px;
line-height: $line-height-base;
width: auto;
}
} }
.create-merge-request-dropdown-toggle { .create-merge-request-dropdown-toggle {
...@@ -225,66 +231,6 @@ ul.related-merge-requests > li { ...@@ -225,66 +231,6 @@ ul.related-merge-requests > li {
margin-left: 0; margin-left: 0;
} }
} }
.droplab-item-ignore {
pointer-events: auto;
}
.create-item {
cursor: pointer;
margin: 0 1px;
&:hover,
&:focus {
background-color: $dropdown-item-hover-bg;
color: $gl-text-color;
}
}
li.divider {
margin: 8px 10px;
}
li:not(.divider) {
padding: 8px 9px;
&:last-child {
padding-bottom: 8px;
}
&.droplab-item-selected {
.icon-container {
i {
visibility: visible;
}
}
.description {
display: block;
}
}
&.droplab-item-ignore {
padding-top: 8px;
}
.icon-container {
float: left;
i {
visibility: hidden;
}
}
.description {
padding-left: 22px;
}
input,
span {
margin: 4px 0 0;
}
}
} }
.discussion-reply-holder .note-edit-form { .discussion-reply-holder .note-edit-form {
......
...@@ -21,30 +21,33 @@ ...@@ -21,30 +21,33 @@
%button.btn.create-merge-request-dropdown-toggle.dropdown-toggle.btn-success.btn-inverted.js-dropdown-toggle{ type: 'button', data: { dropdown: { trigger: '#create-merge-request-dropdown' } } } %button.btn.create-merge-request-dropdown-toggle.dropdown-toggle.btn-success.btn-inverted.js-dropdown-toggle{ type: 'button', data: { dropdown: { trigger: '#create-merge-request-dropdown' } } }
= icon('caret-down') = icon('caret-down')
%ul#create-merge-request-dropdown.create-merge-request-dropdown-menu.dropdown-menu.dropdown-menu-align-right.gl-show-field-errors{ data: { dropdown: true } } .droplab-dropdown
- if can_create_merge_request %ul#create-merge-request-dropdown.create-merge-request-dropdown-menu.dropdown-menu.dropdown-menu-align-right.gl-show-field-errors{ data: { dropdown: true } }
%li.create-item.droplab-item-selected.droplab-item-ignore-hiding{ role: 'button', data: { value: 'create-mr', text: 'Create merge request' } } - if can_create_merge_request
.menu-item.droplab-item-ignore-hiding %li.droplab-item-selected{ role: 'button', data: { value: 'create-mr', text: _('Create merge request') } }
.icon-container.droplab-item-ignore-hiding= icon('check') .menu-item
.description.droplab-item-ignore-hiding Create merge request and branch = icon('check', class: 'icon')
= _('Create merge request and branch')
%li.create-item.droplab-item-ignore-hiding{ class: [!can_create_merge_request && 'droplab-item-selected'], role: 'button', data: { value: 'create-branch', text: 'Create branch' } }
.menu-item.droplab-item-ignore-hiding %li{ class: [!can_create_merge_request && 'droplab-item-selected'], role: 'button', data: { value: 'create-branch', text: _('Create branch') } }
.icon-container.droplab-item-ignore-hiding= icon('check') .menu-item
.description.droplab-item-ignore-hiding Create branch = icon('check', class: 'icon')
%li.divider = _('Create branch')
%li.divider.droplab-item-ignore
%li.droplab-item-ignore
Branch name %li.droplab-item-ignore.prepend-left-8.append-right-8.prepend-top-16
%input.js-branch-name.form-control.droplab-item-ignore{ type: 'text', placeholder: "#{@issue.to_branch_name}", value: "#{@issue.to_branch_name}" } .form-group
%span.js-branch-message.branch-message.droplab-item-ignore %label{ for: 'new-branch-name' }
= _('Branch name')
%li.droplab-item-ignore %input#new-branch-name.js-branch-name.form-control{ type: 'text', placeholder: "#{@issue.to_branch_name}", value: "#{@issue.to_branch_name}" }
Source (branch or tag) %span.js-branch-message.help-block
%input.js-ref.ref.form-control.droplab-item-ignore{ type: 'text', placeholder: "#{@project.default_branch}", value: "#{@project.default_branch}", data: { value: "#{@project.default_branch}" } }
%span.js-ref-message.ref-message.droplab-item-ignore .form-group
%label{ for: 'source-name' }
%li.droplab-item-ignore = _('Source (branch or tag)')
%button.btn.btn-success.js-create-target.droplab-item-ignore{ type: 'button', data: { action: 'create-mr' } } %input#source-name.js-ref.ref.form-control{ type: 'text', placeholder: "#{@project.default_branch}", value: "#{@project.default_branch}", data: { value: "#{@project.default_branch}" } }
Create merge request %span.js-ref-message.help-block
.form-group
%button.btn.btn-success.js-create-target{ type: 'button', data: { action: 'create-mr' } }
= _('Create merge request')
---
title: Cleanup new branch/merge request form in issues
merge_request: 16854
author:
type: fixed
import DropDown from '~/droplab/drop_down'; import DropDown from '~/droplab/drop_down';
import utils from '~/droplab/utils'; import utils from '~/droplab/utils';
import { SELECTED_CLASS, IGNORE_CLASS } from '~/droplab/constants'; import { SELECTED_CLASS } from '~/droplab/constants';
describe('DropDown', function () { describe('DropLab DropDown', function () {
describe('class constructor', function () { describe('class constructor', function () {
beforeEach(function () { beforeEach(function () {
spyOn(DropDown.prototype, 'getItems'); spyOn(DropDown.prototype, 'getItems');
...@@ -128,7 +128,12 @@ describe('DropDown', function () { ...@@ -128,7 +128,12 @@ describe('DropDown', function () {
beforeEach(function () { beforeEach(function () {
this.classList = jasmine.createSpyObj('classList', ['contains']); this.classList = jasmine.createSpyObj('classList', ['contains']);
this.list = { dispatchEvent: () => {} }; this.list = { dispatchEvent: () => {} };
this.dropdown = { hide: () => {}, list: this.list, addSelectedClass: () => {} }; this.dropdown = {
hideOnClick: true,
hide: () => {},
list: this.list,
addSelectedClass: () => {},
};
this.event = { preventDefault: () => {}, target: { classList: this.classList } }; this.event = { preventDefault: () => {}, target: { classList: this.classList } };
this.customEvent = {}; this.customEvent = {};
this.closestElement = {}; this.closestElement = {};
...@@ -164,10 +169,6 @@ describe('DropDown', function () { ...@@ -164,10 +169,6 @@ describe('DropDown', function () {
expect(window.CustomEvent).toHaveBeenCalledWith('click.dl', jasmine.any(Object)); expect(window.CustomEvent).toHaveBeenCalledWith('click.dl', jasmine.any(Object));
}); });
it('should call .classList.contains checking for IGNORE_CLASS', function () {
expect(this.classList.contains).toHaveBeenCalledWith(IGNORE_CLASS);
});
it('should call .dispatchEvent with the customEvent', function () { it('should call .dispatchEvent with the customEvent', function () {
expect(this.list.dispatchEvent).toHaveBeenCalledWith(this.customEvent); expect(this.list.dispatchEvent).toHaveBeenCalledWith(this.customEvent);
}); });
...@@ -187,22 +188,6 @@ describe('DropDown', function () { ...@@ -187,22 +188,6 @@ describe('DropDown', function () {
}); });
}); });
describe('if the target has the IGNORE_CLASS class', function () {
beforeEach(function () {
this.event = { preventDefault: () => {}, target: { tagName: 'LI', classList: this.classList } };
spyOn(this.event, 'preventDefault');
this.classList.contains.and.returnValue(true);
utils.closest.calls.reset();
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
});
it('should return immediately', function () {
expect(utils.closest).not.toHaveBeenCalled();
});
});
describe('if no selected element exists', function () { describe('if no selected element exists', function () {
beforeEach(function () { beforeEach(function () {
this.event.preventDefault.calls.reset(); this.event.preventDefault.calls.reset();
...@@ -217,6 +202,19 @@ describe('DropDown', function () { ...@@ -217,6 +202,19 @@ describe('DropDown', function () {
expect(this.event.preventDefault).not.toHaveBeenCalled(); expect(this.event.preventDefault).not.toHaveBeenCalled();
}); });
}); });
describe('if hideOnClick is false', () => {
beforeEach(function () {
this.dropdown.hideOnClick = false;
this.dropdown.hide.calls.reset();
});
it('should not call .hide', function () {
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
expect(this.dropdown.hide).not.toHaveBeenCalled();
});
});
}); });
describe('addSelectedClass', function () { describe('addSelectedClass', function () {
...@@ -278,23 +276,38 @@ describe('DropDown', function () { ...@@ -278,23 +276,38 @@ describe('DropDown', function () {
describe('addEvents', function () { describe('addEvents', function () {
beforeEach(function () { beforeEach(function () {
this.list = { addEventListener: () => {} }; this.list = {
addEventListener: () => {},
querySelectorAll: () => [],
};
this.dropdown = { this.dropdown = {
list: this.list, list: this.list,
clickEvent: () => {}, clickEvent: () => {},
closeDropdown: () => {}, closeDropdown: () => {},
eventWrapper: {}, eventWrapper: {},
}; };
});
it('should call .addEventListener', function () {
spyOn(this.list, 'addEventListener'); spyOn(this.list, 'addEventListener');
DropDown.prototype.addEvents.call(this.dropdown); DropDown.prototype.addEvents.call(this.dropdown);
});
it('should call .addEventListener', function () {
expect(this.list.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function)); expect(this.list.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function));
expect(this.list.addEventListener).toHaveBeenCalledWith('keyup', jasmine.any(Function)); expect(this.list.addEventListener).toHaveBeenCalledWith('keyup', jasmine.any(Function));
}); });
it('should not bind clickEvent() to IGNORE_CLASS', function () {
const dummyElement = document.createElement('li');
spyOn(this.list, 'querySelectorAll').and.callFake(() => [dummyElement]);
spyOn(this.dropdown, 'clickEvent');
DropDown.prototype.addEvents.call(this.dropdown);
dummyElement.click();
expect(this.list.querySelectorAll).toHaveBeenCalledWith('.droplab-item-ignore');
expect(this.dropdown.clickEvent).not.toHaveBeenCalled();
});
}); });
describe('setData', function () { describe('setData', function () {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment