debian-mirror-gitlab/app/assets/javascripts/issuable_form.js

229 lines
7.4 KiB
JavaScript
Raw Normal View History

2018-05-09 12:01:36 +05:30
import $ from 'jquery';
2017-09-10 17:25:29 +05:30
import Pikaday from 'pikaday';
2019-07-31 22:56:46 +05:30
import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete';
2018-03-17 18:26:18 +05:30
import Autosave from './autosave';
import AutoWidthDropdownSelect from './issuable/auto_width_dropdown_select';
2021-03-11 19:13:27 +05:30
import { loadCSSFile } from './lib/utils/css_utils';
2018-12-13 13:39:08 +05:30
import { parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
2021-04-17 20:07:23 +05:30
import { select2AxiosTransport } from './lib/utils/select2_utils';
2020-01-01 13:55:28 +05:30
import { queryToObject, objectToQuery } from './lib/utils/url_utility';
2021-03-11 19:13:27 +05:30
import UsersSelect from './users_select';
import ZenMode from './zen_mode';
2020-01-01 13:55:28 +05:30
2020-03-13 15:44:24 +05:30
const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
2020-01-01 13:55:28 +05:30
function organizeQuery(obj, isFallbackKey = false) {
2020-03-13 15:44:24 +05:30
if (!obj[MR_SOURCE_BRANCH] && !obj[MR_TARGET_BRANCH]) {
return obj;
}
2020-01-01 13:55:28 +05:30
if (isFallbackKey) {
return {
2020-03-13 15:44:24 +05:30
[MR_SOURCE_BRANCH]: obj[MR_SOURCE_BRANCH],
2020-01-01 13:55:28 +05:30
};
}
return {
2020-03-13 15:44:24 +05:30
[MR_SOURCE_BRANCH]: obj[MR_SOURCE_BRANCH],
[MR_TARGET_BRANCH]: obj[MR_TARGET_BRANCH],
2020-01-01 13:55:28 +05:30
};
}
function format(searchTerm, isFallbackKey = false) {
const queryObject = queryToObject(searchTerm);
const organizeQueryObject = organizeQuery(queryObject, isFallbackKey);
const formattedQuery = objectToQuery(organizeQueryObject);
return formattedQuery;
}
function getFallbackKey() {
const searchTerm = format(document.location.search, true);
return ['autosave', document.location.pathname, searchTerm].join('/');
}
2018-03-17 18:26:18 +05:30
export default class IssuableForm {
constructor(form) {
this.form = form;
this.toggleWip = this.toggleWip.bind(this);
this.renderWipExplanation = this.renderWipExplanation.bind(this);
this.resetAutosave = this.resetAutosave.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
2020-10-24 23:57:45 +05:30
/* eslint-disable @gitlab/require-i18n-strings */
this.wipRegex = new RegExp(
'^\\s*(' + // Line start, then any amount of leading whitespace
2021-03-08 18:12:59 +05:30
'draft\\s-\\s' + // Draft_-_ where "_" are *exactly* one whitespace
'|\\[(draft|wip)\\]\\s*' + // [Draft] or [WIP] and any following whitespace
'|(draft|wip):\\s*' + // Draft: or WIP: and any following whitespace
'|(draft|wip)\\s+' + // Draft_ or WIP_ where "_" is at least one whitespace
'|\\(draft\\)\\s*' + // (Draft) and any following whitespace
')+' + // At least one repeated match of the preceding parenthetical
2020-10-24 23:57:45 +05:30
'\\s*', // Any amount of trailing whitespace
'i', // Match any case(s)
);
/* eslint-enable @gitlab/require-i18n-strings */
2018-03-17 18:26:18 +05:30
2018-12-13 13:39:08 +05:30
this.gfmAutoComplete = new GfmAutoComplete(
gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
).setup();
this.usersSelect = new UsersSelect();
2020-11-24 15:15:51 +05:30
this.reviewersSelect = new UsersSelect(undefined, '.js-reviewer-search');
2018-12-13 13:39:08 +05:30
this.zenMode = new ZenMode();
2018-03-17 18:26:18 +05:30
this.titleField = this.form.find('input[name*="[title]"]');
this.descriptionField = this.form.find('textarea[name*="[description]"]');
if (!(this.titleField.length && this.descriptionField.length)) {
return;
}
2016-09-13 17:45:13 +05:30
2018-03-17 18:26:18 +05:30
this.initAutosave();
this.form.on('submit', this.handleSubmit);
this.form.on('click', '.btn-cancel', this.resetAutosave);
this.initWip();
const $issuableDueDate = $('#issuable-due-date');
if ($issuableDueDate.length) {
const calendar = new Pikaday({
field: $issuableDueDate.get(0),
theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
container: $issuableDueDate.parent().get(0),
2021-03-08 18:12:59 +05:30
parse: (dateString) => parsePikadayDate(dateString),
toString: (date) => pikadayToString(date),
onSelect: (dateText) => $issuableDueDate.val(calendar.toString(dateText)),
2019-03-02 22:35:43 +05:30
firstDay: gon.first_day_of_week,
2018-03-17 18:26:18 +05:30
});
calendar.setDate(parsePikadayDate($issuableDueDate.val()));
2016-09-13 17:45:13 +05:30
}
2018-03-17 18:26:18 +05:30
this.$targetBranchSelect = $('.js-target-branch-select', this.form);
2016-09-13 17:45:13 +05:30
2018-03-17 18:26:18 +05:30
if (this.$targetBranchSelect.length) {
this.initTargetBranchDropdown();
}
}
initAutosave() {
2020-03-13 15:44:24 +05:30
const { search } = document.location;
const searchTerm = format(search);
2020-01-01 13:55:28 +05:30
const fallbackKey = getFallbackKey();
this.autosave = new Autosave(
this.titleField,
[document.location.pathname, searchTerm, 'title'],
`${fallbackKey}=title`,
);
return new Autosave(
this.descriptionField,
[document.location.pathname, searchTerm, 'description'],
`${fallbackKey}=description`,
);
2018-03-17 18:26:18 +05:30
}
handleSubmit() {
return this.resetAutosave();
}
resetAutosave() {
this.titleField.data('autosave').reset();
return this.descriptionField.data('autosave').reset();
}
initWip() {
this.$wipExplanation = this.form.find('.js-wip-explanation');
this.$noWipExplanation = this.form.find('.js-no-wip-explanation');
if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) {
2018-12-13 13:39:08 +05:30
return undefined;
2018-03-17 18:26:18 +05:30
}
this.form.on('click', '.js-toggle-wip', this.toggleWip);
this.titleField.on('keyup blur', this.renderWipExplanation);
return this.renderWipExplanation();
}
workInProgress() {
return this.wipRegex.test(this.titleField.val());
}
2020-10-24 23:57:45 +05:30
titlePrefixContainsDraft() {
const prefix = this.titleField.val().match(this.wipRegex);
return prefix && prefix[0].match(/draft/i);
}
2018-03-17 18:26:18 +05:30
renderWipExplanation() {
if (this.workInProgress()) {
2020-10-24 23:57:45 +05:30
// These strings are not "translatable" (the code is hard-coded to look for them)
this.$wipExplanation.find('code')[0].textContent = this.titlePrefixContainsDraft()
? 'Draft' /* eslint-disable-line @gitlab/require-i18n-strings */
: 'WIP';
2018-03-17 18:26:18 +05:30
this.$wipExplanation.show();
return this.$noWipExplanation.hide();
}
2018-12-13 13:39:08 +05:30
this.$wipExplanation.hide();
return this.$noWipExplanation.show();
2018-03-17 18:26:18 +05:30
}
toggleWip(event) {
event.preventDefault();
if (this.workInProgress()) {
this.removeWip();
} else {
this.addWip();
}
return this.renderWipExplanation();
}
removeWip() {
return this.titleField.val(this.titleField.val().replace(this.wipRegex, ''));
}
addWip() {
2020-10-24 23:57:45 +05:30
this.titleField.val(`Draft: ${this.titleField.val()}`);
2018-03-17 18:26:18 +05:30
}
initTargetBranchDropdown() {
2019-03-02 22:35:43 +05:30
import(/* webpackChunkName: 'select2' */ 'select2/select2')
.then(() => {
2021-02-22 17:27:13 +05:30
// eslint-disable-next-line promise/no-nesting
loadCSSFile(gon.select2_css_path)
.then(() => {
this.$targetBranchSelect.select2({
...AutoWidthDropdownSelect.selectOptions('js-target-branch-select'),
ajax: {
url: this.$targetBranchSelect.data('endpoint'),
dataType: 'JSON',
quietMillis: 250,
data(search) {
return {
search,
};
},
2021-04-17 20:07:23 +05:30
results({ results }) {
2021-02-22 17:27:13 +05:30
return {
// `data` keys are translated so we can't just access them with a string based key
2021-04-17 20:07:23 +05:30
results: results[Object.keys(results)[0]].map((name) => ({
2021-02-22 17:27:13 +05:30
id: name,
text: name,
})),
};
},
2021-04-17 20:07:23 +05:30
transport: select2AxiosTransport,
2021-02-22 17:27:13 +05:30
},
initSelection(el, callback) {
const val = el.val();
callback({
id: val,
text: val,
});
},
2019-03-02 22:35:43 +05:30
});
2021-02-22 17:27:13 +05:30
})
.catch(() => {});
2019-03-02 22:35:43 +05:30
})
.catch(() => {});
2018-03-17 18:26:18 +05:30
}
}