Merge branch 'winh-new-branch-dropdown-style' into 'master'
Cleanup new branch/merge request form in issues Closes #41938 See merge request gitlab-org/gitlab-ce!16854
This commit is contained in:
commit
8925671a06
10 changed files with 135 additions and 139 deletions
|
@ -180,6 +180,7 @@ export default class CreateMergeRequestDropdown {
|
|||
valueAttribute: 'data-text',
|
||||
},
|
||||
],
|
||||
hideOnClick: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ const DATA_DROPDOWN = 'data-dropdown';
|
|||
const SELECTED_CLASS = 'droplab-item-selected';
|
||||
const ACTIVE_CLASS = 'droplab-item-active';
|
||||
const IGNORE_CLASS = 'droplab-item-ignore';
|
||||
const IGNORE_HIDING_CLASS = 'droplab-item-ignore-hiding';
|
||||
// Matches `{{anything}}` and `{{ everything }}`.
|
||||
const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g;
|
||||
|
||||
|
@ -14,5 +13,4 @@ export {
|
|||
ACTIVE_CLASS,
|
||||
TEMPLATE_REGEX,
|
||||
IGNORE_CLASS,
|
||||
IGNORE_HIDING_CLASS,
|
||||
};
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import utils from './utils';
|
||||
import { SELECTED_CLASS, IGNORE_CLASS, IGNORE_HIDING_CLASS } from './constants';
|
||||
import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
|
||||
|
||||
class DropDown {
|
||||
constructor(list, config = {}) {
|
||||
constructor(list, config = { }) {
|
||||
this.currentIndex = 0;
|
||||
this.hidden = true;
|
||||
this.list = typeof list === 'string' ? document.querySelector(list) : list;
|
||||
this.items = [];
|
||||
this.eventWrapper = {};
|
||||
this.hideOnClick = config.hideOnClick !== false;
|
||||
|
||||
if (config.addActiveClassToDropdownButton) {
|
||||
this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle');
|
||||
|
@ -37,15 +38,17 @@ class DropDown {
|
|||
|
||||
clickEvent(e) {
|
||||
if (e.target.tagName === 'UL') return;
|
||||
if (e.target.classList.contains(IGNORE_CLASS)) return;
|
||||
if (e.target.closest(`.${IGNORE_CLASS}`)) return;
|
||||
|
||||
const selected = utils.closest(e.target, 'LI');
|
||||
const selected = e.target.closest('li');
|
||||
if (!selected) return;
|
||||
|
||||
this.addSelectedClass(selected);
|
||||
|
||||
e.preventDefault();
|
||||
if (!e.target.classList.contains(IGNORE_HIDING_CLASS)) this.hide();
|
||||
if (this.hideOnClick) {
|
||||
this.hide();
|
||||
}
|
||||
|
||||
const listEvent = new CustomEvent('click.dl', {
|
||||
detail: {
|
||||
|
|
|
@ -449,9 +449,11 @@ img.emoji {
|
|||
.prepend-top-10 { margin-top: 10px; }
|
||||
.prepend-top-15 { margin-top: 15px; }
|
||||
.prepend-top-default { margin-top: $gl-padding !important; }
|
||||
.prepend-top-16 { margin-top: 16px; }
|
||||
.prepend-top-20 { margin-top: 20px; }
|
||||
.prepend-left-4 { margin-left: 4px; }
|
||||
.prepend-left-5 { margin-left: 5px; }
|
||||
.prepend-left-8 { margin-left: 8px; }
|
||||
.prepend-left-10 { margin-left: 10px; }
|
||||
.prepend-left-default { margin-left: $gl-padding; }
|
||||
.prepend-left-20 { margin-left: 20px; }
|
||||
|
|
|
@ -736,10 +736,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.droplab-item-ignore {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.pika-single.animate-picker.is-bound,
|
||||
.pika-single.animate-picker.is-bound.is-hidden {
|
||||
/*
|
||||
|
|
|
@ -182,6 +182,7 @@ label {
|
|||
|
||||
.help-block {
|
||||
margin-bottom: 0;
|
||||
margin-top: #{$grid-size / 2};
|
||||
}
|
||||
|
||||
.gl-field-error {
|
||||
|
|
|
@ -181,11 +181,6 @@ ul.related-merge-requests > li {
|
|||
}
|
||||
|
||||
.create-mr-dropdown-wrap {
|
||||
.branch-message,
|
||||
.ref-message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ref::selection {
|
||||
color: $placeholder-text-color;
|
||||
}
|
||||
|
@ -216,6 +211,17 @@ ul.related-merge-requests > li {
|
|||
transform: translateY(0);
|
||||
display: none;
|
||||
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 {
|
||||
|
@ -225,66 +231,6 @@ ul.related-merge-requests > li {
|
|||
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 {
|
||||
|
|
|
@ -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' } } }
|
||||
= 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 } }
|
||||
- if can_create_merge_request
|
||||
%li.create-item.droplab-item-selected.droplab-item-ignore-hiding{ role: 'button', data: { value: 'create-mr', text: 'Create merge request' } }
|
||||
.menu-item.droplab-item-ignore-hiding
|
||||
.icon-container.droplab-item-ignore-hiding= icon('check')
|
||||
.description.droplab-item-ignore-hiding Create merge request and branch
|
||||
.droplab-dropdown
|
||||
%ul#create-merge-request-dropdown.create-merge-request-dropdown-menu.dropdown-menu.dropdown-menu-align-right.gl-show-field-errors{ data: { dropdown: true } }
|
||||
- if can_create_merge_request
|
||||
%li.droplab-item-selected{ role: 'button', data: { value: 'create-mr', text: _('Create merge request') } }
|
||||
.menu-item
|
||||
= 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
|
||||
.icon-container.droplab-item-ignore-hiding= icon('check')
|
||||
.description.droplab-item-ignore-hiding Create branch
|
||||
%li.divider
|
||||
%li{ class: [!can_create_merge_request && 'droplab-item-selected'], role: 'button', data: { value: 'create-branch', text: _('Create branch') } }
|
||||
.menu-item
|
||||
= icon('check', class: 'icon')
|
||||
= _('Create branch')
|
||||
%li.divider.droplab-item-ignore
|
||||
|
||||
%li.droplab-item-ignore
|
||||
Branch name
|
||||
%input.js-branch-name.form-control.droplab-item-ignore{ type: 'text', placeholder: "#{@issue.to_branch_name}", value: "#{@issue.to_branch_name}" }
|
||||
%span.js-branch-message.branch-message.droplab-item-ignore
|
||||
%li.droplab-item-ignore.prepend-left-8.append-right-8.prepend-top-16
|
||||
.form-group
|
||||
%label{ for: 'new-branch-name' }
|
||||
= _('Branch name')
|
||||
%input#new-branch-name.js-branch-name.form-control{ type: 'text', placeholder: "#{@issue.to_branch_name}", value: "#{@issue.to_branch_name}" }
|
||||
%span.js-branch-message.help-block
|
||||
|
||||
%li.droplab-item-ignore
|
||||
Source (branch or tag)
|
||||
%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
|
||||
|
||||
%li.droplab-item-ignore
|
||||
%button.btn.btn-success.js-create-target.droplab-item-ignore{ type: 'button', data: { action: 'create-mr' } }
|
||||
Create merge request
|
||||
.form-group
|
||||
%label{ for: 'source-name' }
|
||||
= _('Source (branch or tag)')
|
||||
%input#source-name.js-ref.ref.form-control{ type: 'text', placeholder: "#{@project.default_branch}", value: "#{@project.default_branch}", data: { value: "#{@project.default_branch}" } }
|
||||
%span.js-ref-message.help-block
|
||||
|
||||
.form-group
|
||||
%button.btn.btn-success.js-create-target{ type: 'button', data: { action: 'create-mr' } }
|
||||
= _('Create merge request')
|
||||
|
|
5
changelogs/unreleased/winh-new-branch-dropdown-style.yml
Normal file
5
changelogs/unreleased/winh-new-branch-dropdown-style.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Cleanup new branch/merge request form in issues
|
||||
merge_request: 16854
|
||||
author:
|
||||
type: fixed
|
|
@ -1,8 +1,8 @@
|
|||
import DropDown from '~/droplab/drop_down';
|
||||
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 () {
|
||||
beforeEach(function () {
|
||||
spyOn(DropDown.prototype, 'getItems');
|
||||
|
@ -128,93 +128,131 @@ describe('DropDown', function () {
|
|||
beforeEach(function () {
|
||||
this.classList = jasmine.createSpyObj('classList', ['contains']);
|
||||
this.list = { dispatchEvent: () => {} };
|
||||
this.dropdown = { hide: () => {}, list: this.list, addSelectedClass: () => {} };
|
||||
this.event = { preventDefault: () => {}, target: { classList: this.classList } };
|
||||
this.dropdown = {
|
||||
hideOnClick: true,
|
||||
hide: () => {},
|
||||
list: this.list,
|
||||
addSelectedClass: () => {},
|
||||
};
|
||||
this.event = {
|
||||
preventDefault: () => {},
|
||||
target: {
|
||||
classList: this.classList,
|
||||
closest: () => null,
|
||||
},
|
||||
};
|
||||
this.customEvent = {};
|
||||
this.closestElement = {};
|
||||
this.dummyListItem = document.createElement('li');
|
||||
spyOn(this.event.target, 'closest').and.callFake((selector) => {
|
||||
if (selector === 'li') {
|
||||
return this.dummyListItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
spyOn(this.dropdown, 'hide');
|
||||
spyOn(this.dropdown, 'addSelectedClass');
|
||||
spyOn(this.list, 'dispatchEvent');
|
||||
spyOn(this.event, 'preventDefault');
|
||||
spyOn(window, 'CustomEvent').and.returnValue(this.customEvent);
|
||||
spyOn(utils, 'closest').and.returnValues(this.closestElement, undefined);
|
||||
this.classList.contains.and.returnValue(false);
|
||||
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
});
|
||||
|
||||
it('should call utils.closest', function () {
|
||||
expect(utils.closest).toHaveBeenCalledWith(this.event.target, 'LI');
|
||||
it('should call event.target.closest', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.event.target.closest).toHaveBeenCalledWith('.droplab-item-ignore');
|
||||
expect(this.event.target.closest).toHaveBeenCalledWith('li');
|
||||
});
|
||||
|
||||
it('should call addSelectedClass', function () {
|
||||
expect(this.dropdown.addSelectedClass).toHaveBeenCalledWith(this.closestElement);
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.dropdown.addSelectedClass).toHaveBeenCalledWith(this.dummyListItem);
|
||||
});
|
||||
|
||||
it('should call .preventDefault', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.event.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call .hide', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.dropdown.hide).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should construct CustomEvent', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
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 () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.list.dispatchEvent).toHaveBeenCalledWith(this.customEvent);
|
||||
});
|
||||
|
||||
describe('if the target is a UL element', function () {
|
||||
beforeEach(function () {
|
||||
this.event = { preventDefault: () => {}, target: { tagName: 'UL', classList: this.classList } };
|
||||
this.event.target = document.createElement('ul');
|
||||
|
||||
spyOn(this.event, 'preventDefault');
|
||||
utils.closest.calls.reset();
|
||||
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
spyOn(this.event.target, 'closest');
|
||||
});
|
||||
|
||||
it('should return immediately', function () {
|
||||
expect(utils.closest).not.toHaveBeenCalled();
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.event.target.closest).not.toHaveBeenCalled();
|
||||
expect(this.dropdown.addSelectedClass).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('if the target has the IGNORE_CLASS class', function () {
|
||||
describe('if the target has the droplab-item-ignore class', function () {
|
||||
beforeEach(function () {
|
||||
this.event = { preventDefault: () => {}, target: { tagName: 'LI', classList: this.classList } };
|
||||
this.ignoredButton = document.createElement('button');
|
||||
this.ignoredButton.classList.add('droplab-item-ignore');
|
||||
this.event.target = this.ignoredButton;
|
||||
|
||||
spyOn(this.event, 'preventDefault');
|
||||
this.classList.contains.and.returnValue(true);
|
||||
utils.closest.calls.reset();
|
||||
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
spyOn(this.ignoredButton, 'closest').and.callThrough();
|
||||
});
|
||||
|
||||
it('should return immediately', function () {
|
||||
expect(utils.closest).not.toHaveBeenCalled();
|
||||
it('does not select element', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.ignoredButton.closest.calls.count()).toBe(1);
|
||||
expect(this.ignoredButton.closest).toHaveBeenCalledWith('.droplab-item-ignore');
|
||||
expect(this.dropdown.addSelectedClass).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('if no selected element exists', function () {
|
||||
beforeEach(function () {
|
||||
this.event.preventDefault.calls.reset();
|
||||
this.clickEvent = DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
});
|
||||
|
||||
it('should return undefined', function () {
|
||||
expect(this.clickEvent).toBe(undefined);
|
||||
this.dummyListItem = null;
|
||||
});
|
||||
|
||||
it('should return before .preventDefault is called', function () {
|
||||
DropDown.prototype.clickEvent.call(this.dropdown, this.event);
|
||||
|
||||
expect(this.event.preventDefault).not.toHaveBeenCalled();
|
||||
expect(this.dropdown.addSelectedClass).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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -278,20 +316,23 @@ describe('DropDown', function () {
|
|||
|
||||
describe('addEvents', function () {
|
||||
beforeEach(function () {
|
||||
this.list = { addEventListener: () => {} };
|
||||
this.list = {
|
||||
addEventListener: () => {},
|
||||
querySelectorAll: () => [],
|
||||
};
|
||||
this.dropdown = {
|
||||
list: this.list,
|
||||
clickEvent: () => {},
|
||||
closeDropdown: () => {},
|
||||
eventWrapper: {},
|
||||
};
|
||||
|
||||
spyOn(this.list, 'addEventListener');
|
||||
|
||||
DropDown.prototype.addEvents.call(this.dropdown);
|
||||
});
|
||||
|
||||
it('should call .addEventListener', function () {
|
||||
spyOn(this.list, 'addEventListener');
|
||||
|
||||
DropDown.prototype.addEvents.call(this.dropdown);
|
||||
|
||||
expect(this.list.addEventListener).toHaveBeenCalledWith('click', jasmine.any(Function));
|
||||
expect(this.list.addEventListener).toHaveBeenCalledWith('keyup', jasmine.any(Function));
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue