/* eslint-disable */
(function (global) {
class MilestoneSelect {
constructor(currentProject) {
this.$el = null;
this.config = null;
this.state = null;
this.templates = null;
this.storeElements();
this.storeConfig();
this.initState(currentProject);
this.initTemplates();
this.initDropdown();
}
storeElements() {
const $document = $(document);
const $html = $document.find('html');
const $body = $document.find('body');
const $dropdown = $document.find('.js-milestone-select');
const $selectbox = $dropdown.closest('.selectbox');
const $block = $selectbox.closest('.block');
const $value = $block.find('.value');
const $loading = $block.find('.block-loading');
const $collapsedValue = $block.find('.sidebar-collapsed-icon');
const $form = $dropdown.closest('form');
this.$el = {
document: $document,
html: $html,
body: $body,
dropdown: $dropdown,
dropdownSelectBox: $selectbox,
containerBlock: $block,
valueDisplay: $value,
loadingDisplay: $loading,
collapsedValue: $collapsedValue,
form: $form,
};
}
storeConfig() {
const $dropdown = this.$el.dropdown;
const currentPage = this.$el.body.data('page');
const isIssue = currentPage === 'projects:issues:index';
const isMergeRequest = currentPage === 'projects:merge_requests:index';
this.config.context = {
isIssue,
isMergeRequest,
isBoardSidebar: $dropdown.hasClass('js-issue-board-sidebar'),
isSubmittableNonIndex: $dropdown.hasClass('js-filter-submit'),
isSubmittableIndex: $dropdown.hasClass('js-filter-submit') && (isIssue || isMergeRequest),
isBoard: this.$el.html.hasClass('issue-boards-page') && !$dropdown.hasClass('js-issue-board-sidebar'),
shouldPreventSubmission: $dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown'),
};
const dataset = this.config.dataset = this.$el.dropdown.get(0).dataset;
this.config.display = {
showMenuAbove: dataset.showMenuAbove,
showNo: dataset.showNo,
showAny: dataset.showAny,
showUpcoming: dataset.showUpcoming,
extraOptions: []
};
}
initState(currentProject) {
this.state = {
currentProject: currentProject ? JSON.parse(currentProject) : null,
selectedMilestone: this.config.dataset.selected,
};
}
initTemplates() {
if (this.config.dataset.issueUpdate) {
this.templates = {
milestoneLink: _.template(`
<%- title %>
`),
milestoneLinkNone: `None`,
collapsedSidebarLabel: _.template(`
<%- title %>
`
),
};
}
}
initDropdown() {
const dataset = this.config.dataset;
const selectedMilestone = dataset.selected;
const searchFields = { fields: ['title'] };
const isSelected = milestone => milestone.name === selectedMilestone;
this.$el.dropdown.glDropdown({
isSelected,
filterable: true,
selectable: true,
search: searchFields,
fieldName: dataset.fieldName,
defaultLabel: dataset.defaultLabel,
vue: this.config.context.isBoardSidebar,
showMenuAbove: this.config.display.showMenuAbove,
text: item => this.escapeText(item),
hidden: () => this.renderDisplayState(),
id: milestone => this.displaySelected(milestone),
data: (term, callback) => this.fetchMilestones(term, callback),
toggleLabel: (selected, $el, e) => this.toggleLabel(selected, $el, e),
clicked: (selected, $el, e) => this.handleDropdownClick(selected, $el, e),
});
this.renderLoadedState();
}
displaySelected(milestone) {
const useId = this.config.dataset.useId;
return (!useId && !this.$el.dropdown.is('.js-issuable-form-dropdown')) ? milestone.name : milestone.id;
}
fetchMilestones(term, callback) {
const milestonesUrl = this.config.dataset.milestones;
return $.ajax({ url: milestonesUrl })
.done((milestones, callback) => this.handleFetchSuccess(milestones, callback));
}
handleFetchSuccess(milestones, callback) {
this.prepExtraOptions();
callback(this.config.display.extraOptions.concat(milestones));
this.positionMenuAbove();
}
prepExtraOptions() {
const displayConfig = this.config.display;
if (displayConfig.showAny) this.storeExtraDropdownOptions(0, '', 'Any Milestone');
if (displayConfig.showNo) this.storeExtraDropdownOptions(-1, 'No Milestone', 'No Milestone');
if (displayConfig.showUpcoming) this.storeExtraDropdownOptions(-2, '#upcoming', 'Upcoming');
if (displayConfig.extraOptions.length) this.storeExtraDropdownOptions('divider');
}
storeExtraDropdownOptions(id, name, title) {
const divider = 'divider';
const pushable = id === divider ? divider : { id, name, title };
this.config.display.extraOptions.push(pushable);
}
handleDropdownClick(selected, $el, e) {
const pageConfig = this.config.context;
if (pageConfig.shouldPrevntSubmission) {
return e.preventDefault();
}
if (pageConfig.isBoardPage) {
return this.putIssueBoardPage(selected, $el, e);
}
if (pageConfig.isSubmittableIndex) {
return this.putSubmittableIndex(selected, $el, e);
}
if (pageConfig.isSubmittableNonIndex) {
return this.putSubmittableNonIndex(selected, $el, e);
}
if (pageConfig.isBoardSidebar) {
return this.putIssueBoardSidebar(selected, $el, e);
}
return this.putGeneric(selected, $el, e);
}
toggleLabel(selected, $el, e) {
const defaultLabel = this.config.dataset.defaultLabel;
return (selected, el, e) => (selected && selected.id && el.hasClass('is-active')) ?
selected.title : defaultLabel;
}
escapeText(milestone) {
return _.escape(milestone.title);
}
renderDisplayState() {
this.$el.dropdownSelectBox.hide();
// display:block overrides the hide-collapse rule
this.$el.valueDisplay.css('display', '');
}
updateState(issuableData) {
// TODO: Pass this to a pub/sub resource to update async
this.renderUpdatedState(issuableData);
}
renderUpdatedState(issuableData) {
const $valueDisplay = this.$el.valueDisplay;
const $collapsedValue = this.$el.collapsedValue;
const milestoneData = issuableData.milestone;
if (milestoneData != null) {
$valueDisplay.html(this.templates.milestoneLink(milestoneData));
$collapsedValue.find('span').html(this.templates.collapsedSidebarLabel(milestoneData));
} else {
$valueDisplay.html(this.templates.milestoneLinkNone);
$collapsedValue.find('span').text('No');
}
}
renderLoadingState() {
this.$el.loadingDisplay.fadeIn();
this.$el.dropdown.trigger('loading.gl.dropdown');
}
renderLoadedState() {
this.$el.loadingDisplay.fadeOut();
this.$el.dropdown.trigger('loaded.gl.dropdown');
}
positionMenuAbove() {
if (this.config.display.showMenuAbove) {
this.$el.dropdown.positionMenuAbove();
}
}
putGeneric(selected, $el, e) {
const selectedMilestone = this.$el.dropdownSelectBox.find('input[type="hidden"]').val() || selected.id;
const milestonePayload = {};
const abilityName = this.config.dataset.abilityName;
milestonePayload[abilityName] = {};
milestonePayload[abilityName].milestone_id = selectedMilestone;
const issueUpdateURL = this.config.dataset.issueUpdate;
// TODO: Use issuable pub/sub resource method to propagate changes
this.renderLoadingState();
$.ajax({ type: 'PUT', url: issueUpdateURL, data: milestonePayload })
.done(issuableData => {
this.handlePutSuccess(issuableData);
});
}
handlePutSuccess(issuableData) {
this.renderLoadedState();
issuableData.milestone = this.parsePutValue(issuableData);
this.renderUpdatedState(issuableData);
}
parsePutValue(data) {
const milestoneData = data.milestone;
if (milestoneData != null) {
const currentProject = this.state.currentProject;
milestoneData.namespace = currentProject.namespace;
milestoneData.path = currentProject.path;
milestoneData.remaining = gl.utils.timeFor(milestoneData.due_date);
}
return milestoneData;
}
putIssueBoardPage(selected, $el, e) {
gl.issueBoards.BoardsStore.state.filters[this.config.dataset.fieldName] = selected.name;
gl.issueBoards.BoardsStore.updateFiltersUrl();
e.preventDefault();
}
putIssueBoardSidebar(selected, $el, e) {
if (selected.id !== -1) {
Vue.set(gl.issueBoards.BoardsStore.detail.issue, 'milestone', new ListMilestone({
id: selected.id,
title: selected.name
}));
} else {
Vue.delete(gl.issueBoards.BoardsStore.detail.issue, 'milestone');
}
this.renderLoadingState();
gl.issueBoards.BoardsStore.detail.issue.update(this.config.dataset.issueUpdate)
.then(() => this.renderLoadedState());
}
putSubmittableIndex(selected, $el, e) {
return Issuable.filterResults(this.$el.form);
}
putSubmittableNonIndex(selected, $el, e) {
return this.$el.form.submit();
}
}
global.MilestoneSelect = MilestoneSelect;
})(window);