diff options
Diffstat (limited to 'app/assets/javascripts/labels/label_manager.js')
-rw-r--r-- | app/assets/javascripts/labels/label_manager.js | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/app/assets/javascripts/labels/label_manager.js b/app/assets/javascripts/labels/label_manager.js new file mode 100644 index 00000000000..1927ac6e1ec --- /dev/null +++ b/app/assets/javascripts/labels/label_manager.js @@ -0,0 +1,146 @@ +/* eslint-disable class-methods-use-this, no-underscore-dangle, no-param-reassign, func-names */ + +import $ from 'jquery'; +import Sortable from 'sortablejs'; +import { dispose } from '~/tooltips'; +import createFlash from '~/flash'; +import axios from '~/lib/utils/axios_utils'; +import { __ } from '~/locale'; + +export default class LabelManager { + constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) { + this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority'); + this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels'); + this.otherLabels = otherLabels || $('.js-other-labels'); + this.errorMessage = __('Unable to update label prioritization at this time'); + this.emptyState = document.querySelector('#js-priority-labels-empty-state'); + this.$badgeItemTemplate = $('#js-badge-item-template'); + + if ('sortable' in this.prioritizedLabels.data()) { + Sortable.create(this.prioritizedLabels.get(0), { + filter: '.empty-message', + forceFallback: true, + fallbackClass: 'is-dragging', + dataIdAttr: 'data-id', + onUpdate: this.onPrioritySortUpdate.bind(this), + }); + } + this.bindEvents(); + } + + bindEvents() { + return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick); + } + + onTogglePriorityClick(e) { + e.preventDefault(); + const _this = e.data; + const $btn = $(e.currentTarget); + const $label = $(`#${$btn.data('domId')}`); + const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; + const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); + dispose($tooltip); + _this.toggleLabelPriority($label, action); + _this.toggleEmptyState($label, $btn, action); + } + + toggleEmptyState() { + this.emptyState.classList.toggle( + 'hidden', + Boolean(this.prioritizedLabels[0].querySelector(':scope > li')), + ); + } + + toggleLabelPriority($label, action, persistState) { + if (persistState == null) { + persistState = true; + } + const url = $label.find('.js-toggle-priority').data('url'); + let $target = this.prioritizedLabels; + let $from = this.otherLabels; + const rollbackLabelPosition = this.rollbackLabelPosition.bind(this, $label, action); + + if (action === 'remove') { + $target = this.otherLabels; + $from = this.prioritizedLabels; + } + + const $detachedLabel = $label.detach(); + this.toggleLabelPriorityBadge($detachedLabel, action); + + const $labelEls = $target.find('li.label-list-item'); + + /* + * If there is a label element in the target, we'd want to + * append the new label just right next to it. + */ + if ($labelEls.length) { + $labelEls.last().after($detachedLabel); + } else { + $detachedLabel.appendTo($target); + } + + if ($from.find('li').length) { + $from.find('.empty-message').removeClass('hidden'); + } + if ($target.find('> li:not(.empty-message)').length) { + $target.find('.empty-message').addClass('hidden'); + } + // Return if we are not persisting state + if (!persistState) { + return; + } + if (action === 'remove') { + axios.delete(url).catch(rollbackLabelPosition); + + // Restore empty message + if (!$from.find('li').length) { + $from.find('.empty-message').removeClass('hidden'); + } + } else { + this.savePrioritySort($label, action).catch(rollbackLabelPosition); + } + } + + toggleLabelPriorityBadge($label, action) { + if (action === 'remove') { + $('.js-priority-badge', $label).remove(); + } else { + $('.label-links', $label).append(this.$badgeItemTemplate.clone().html()); + } + } + + onPrioritySortUpdate() { + this.savePrioritySort().catch(() => + createFlash({ + message: this.errorMessage, + }), + ); + } + + savePrioritySort() { + return axios.post(this.prioritizedLabels.data('url'), { + label_ids: this.getSortedLabelsIds(), + }); + } + + rollbackLabelPosition($label, originalAction) { + const action = originalAction === 'remove' ? 'add' : 'remove'; + this.toggleLabelPriority($label, action, false); + createFlash({ + message: this.errorMessage, + }); + } + + getSortedLabelsIds() { + const sortedIds = []; + this.prioritizedLabels.find('> li').each(function () { + const id = $(this).data('id'); + + if (id) { + sortedIds.push(id); + } + }); + return sortedIds; + } +} |