191 lines
5.6 KiB
JavaScript
191 lines
5.6 KiB
JavaScript
import $ from 'jquery';
|
|
import Pikaday from 'pikaday';
|
|
import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete';
|
|
import Autosave from '~/autosave';
|
|
import { parsePikadayDate, pikadayToString } from '~/lib/utils/datetime_utility';
|
|
import { queryToObject, objectToQuery } from '~/lib/utils/url_utility';
|
|
import UsersSelect from '~/users_select';
|
|
import ZenMode from '~/zen_mode';
|
|
|
|
const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
|
|
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
|
|
const DATA_ISSUES_NEW_PATH = 'data-new-issue-path';
|
|
|
|
function organizeQuery(obj, isFallbackKey = false) {
|
|
if (!obj[MR_SOURCE_BRANCH] && !obj[MR_TARGET_BRANCH]) {
|
|
return obj;
|
|
}
|
|
|
|
if (isFallbackKey) {
|
|
return {
|
|
[MR_SOURCE_BRANCH]: obj[MR_SOURCE_BRANCH],
|
|
};
|
|
}
|
|
|
|
return {
|
|
[MR_SOURCE_BRANCH]: obj[MR_SOURCE_BRANCH],
|
|
[MR_TARGET_BRANCH]: obj[MR_TARGET_BRANCH],
|
|
};
|
|
}
|
|
|
|
function format(searchTerm, isFallbackKey = false) {
|
|
const queryObject = queryToObject(searchTerm, { legacySpacesDecode: true });
|
|
const organizeQueryObject = organizeQuery(queryObject, isFallbackKey);
|
|
const formattedQuery = objectToQuery(organizeQueryObject);
|
|
|
|
return formattedQuery;
|
|
}
|
|
|
|
function getSearchTerm(newIssuePath) {
|
|
const { search, pathname } = document.location;
|
|
return newIssuePath === pathname ? '' : format(search);
|
|
}
|
|
|
|
function getFallbackKey() {
|
|
const searchTerm = format(document.location.search, true);
|
|
return ['autosave', document.location.pathname, searchTerm].join('/');
|
|
}
|
|
|
|
export default class IssuableForm {
|
|
static addAutosave(map, id, element, searchTerm, fallbackKey) {
|
|
if (!element) return;
|
|
map.set(
|
|
id,
|
|
new Autosave(element, [document.location.pathname, searchTerm, id], `${fallbackKey}=${id}`),
|
|
);
|
|
}
|
|
|
|
constructor(form) {
|
|
if (form.length === 0) {
|
|
return;
|
|
}
|
|
this.form = form;
|
|
this.resetAutosave = this.resetAutosave.bind(this);
|
|
this.handleSubmit = this.handleSubmit.bind(this);
|
|
// prettier-ignore
|
|
this.draftRegex = new RegExp(
|
|
'^\\s*(' + // Line start, then any amount of leading whitespace
|
|
'\\[draft\\]\\s*' + // [Draft] and any following whitespace
|
|
'|draft:\\s*' + // Draft: and any following whitespace
|
|
'|\\(draft\\)\\s*' + // (Draft) and any following whitespace
|
|
')+' + // At least one repeated match of the preceding parenthetical
|
|
'\\s*', // Any amount of trailing whitespace
|
|
'i', // Match any case(s)
|
|
);
|
|
|
|
this.gfmAutoComplete = new GfmAutoComplete(
|
|
gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
|
|
).setup();
|
|
this.usersSelect = new UsersSelect();
|
|
this.reviewersSelect = new UsersSelect(undefined, '.js-reviewer-search');
|
|
this.zenMode = new ZenMode();
|
|
|
|
this.searchTerm = getSearchTerm(form[0].getAttribute(DATA_ISSUES_NEW_PATH));
|
|
this.fallbackKey = getFallbackKey();
|
|
this.titleField = this.form.find('input[name*="[title]"]');
|
|
this.descriptionField = this.form.find('textarea[name*="[description]"]');
|
|
this.draftCheck = document.querySelector('input.js-toggle-draft');
|
|
if (!(this.titleField.length && this.descriptionField.length)) {
|
|
return;
|
|
}
|
|
|
|
this.autosaves = this.initAutosave();
|
|
this.form.on('submit', this.handleSubmit);
|
|
this.form.on('click', '.btn-cancel, .js-reset-autosave', this.resetAutosave);
|
|
this.initDraft();
|
|
|
|
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),
|
|
parse: (dateString) => parsePikadayDate(dateString),
|
|
toString: (date) => pikadayToString(date),
|
|
onSelect: (dateText) => {
|
|
$issuableDueDate.val(calendar.toString(dateText));
|
|
if (this.autosaves.has('due_date')) this.autosaves.get('due_date').save();
|
|
},
|
|
firstDay: gon.first_day_of_week,
|
|
});
|
|
calendar.setDate(parsePikadayDate($issuableDueDate.val()));
|
|
}
|
|
}
|
|
|
|
initAutosave() {
|
|
const autosaveMap = new Map();
|
|
IssuableForm.addAutosave(
|
|
autosaveMap,
|
|
'title',
|
|
this.form.find('input[name*="[title]"]').get(0),
|
|
this.searchTerm,
|
|
this.fallbackKey,
|
|
);
|
|
IssuableForm.addAutosave(
|
|
autosaveMap,
|
|
'description',
|
|
this.form.find('textarea[name*="[description]"]').get(0),
|
|
this.searchTerm,
|
|
this.fallbackKey,
|
|
);
|
|
IssuableForm.addAutosave(
|
|
autosaveMap,
|
|
'confidential',
|
|
this.form.find('input:checkbox[name*="[confidential]"]').get(0),
|
|
this.searchTerm,
|
|
this.fallbackKey,
|
|
);
|
|
IssuableForm.addAutosave(
|
|
autosaveMap,
|
|
'due_date',
|
|
this.form.find('input[name*="[due_date]"]').get(0),
|
|
this.searchTerm,
|
|
this.fallbackKey,
|
|
);
|
|
|
|
return autosaveMap;
|
|
}
|
|
|
|
handleSubmit() {
|
|
return this.resetAutosave();
|
|
}
|
|
|
|
resetAutosave() {
|
|
this.autosaves.forEach((autosaveItem) => {
|
|
autosaveItem?.reset();
|
|
});
|
|
}
|
|
|
|
initDraft() {
|
|
if (this.draftCheck) {
|
|
this.draftCheck.addEventListener('click', () => this.writeDraftStatus());
|
|
this.titleField.on('keyup blur', () => this.readDraftStatus());
|
|
|
|
this.readDraftStatus();
|
|
}
|
|
}
|
|
|
|
isMarkedDraft() {
|
|
return this.draftRegex.test(this.titleField.val());
|
|
}
|
|
readDraftStatus() {
|
|
this.draftCheck.checked = this.isMarkedDraft();
|
|
}
|
|
writeDraftStatus() {
|
|
if (this.draftCheck.checked) {
|
|
this.addDraft();
|
|
} else {
|
|
this.removeDraft();
|
|
}
|
|
}
|
|
|
|
removeDraft() {
|
|
return this.titleField.val(this.titleField.val().replace(this.draftRegex, ''));
|
|
}
|
|
|
|
addDraft() {
|
|
this.titleField.val(`Draft: ${this.titleField.val()}`);
|
|
}
|
|
}
|