110 lines
3.1 KiB
JavaScript
110 lines
3.1 KiB
JavaScript
import $ from 'jquery';
|
|
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
|
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
|
|
|
|
export default class TemplateSelector {
|
|
constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) {
|
|
this.pattern = pattern;
|
|
this.editor = editor;
|
|
this.dropdown = dropdown;
|
|
this.$dropdownContainer = wrapper;
|
|
this.$filenameInput = $input || $('#file_name');
|
|
this.dropdownIcon = dropdown[0].querySelector('.dropdown-menu-toggle-icon');
|
|
this.loadingIcon = loadingIconForLegacyJS({ classes: ['gl-display-none'] });
|
|
this.dropdownIcon.parentNode.insertBefore(this.loadingIcon, this.dropdownIcon.nextSibling);
|
|
|
|
this.initDropdown(dropdown, data);
|
|
this.listenForFilenameInput();
|
|
this.renderMatchedDropdown();
|
|
this.initAutosizeUpdateEvent();
|
|
}
|
|
|
|
initDropdown(dropdown, data) {
|
|
return initDeprecatedJQueryDropdown($(dropdown), {
|
|
data,
|
|
filterable: true,
|
|
selectable: true,
|
|
toggleLabel: (item) => item.name,
|
|
search: {
|
|
fields: ['name'],
|
|
},
|
|
clicked: (options) => this.onDropdownClicked(options),
|
|
text: (item) => item.name,
|
|
});
|
|
}
|
|
|
|
// Subclasses can override this method to conditionally prevent fetching file templates
|
|
onDropdownClicked(options) {
|
|
this.fetchFileTemplate(options);
|
|
}
|
|
|
|
initAutosizeUpdateEvent() {
|
|
this.autosizeUpdateEvent = document.createEvent('Event');
|
|
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
|
|
}
|
|
|
|
listenForFilenameInput() {
|
|
return this.$filenameInput.on('keyup blur', (e) => this.renderMatchedDropdown(e));
|
|
}
|
|
|
|
renderMatchedDropdown() {
|
|
if (!this.$filenameInput.length) {
|
|
return null;
|
|
}
|
|
|
|
const filenameMatches = this.pattern.test(this.$filenameInput.val().trim());
|
|
|
|
if (!filenameMatches) {
|
|
return this.$dropdownContainer.addClass('hidden');
|
|
}
|
|
return this.$dropdownContainer.removeClass('hidden');
|
|
}
|
|
|
|
fetchFileTemplate(options) {
|
|
const { e } = options;
|
|
const item = options.selectedObj;
|
|
|
|
e.preventDefault();
|
|
return this.requestFile(item);
|
|
}
|
|
|
|
// eslint-disable-next-line class-methods-use-this
|
|
requestFile() {
|
|
// This `requestFile` method is an abstract method that should
|
|
// be added by all subclasses.
|
|
}
|
|
|
|
setEditorContent(file, { skipFocus } = {}) {
|
|
if (!file) return;
|
|
|
|
let newValue = file.content;
|
|
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
if (urlParams.has('issue[description]')) {
|
|
newValue += `\n${urlParams.get('issue[description]')}`;
|
|
}
|
|
|
|
this.editor.setValue(newValue, 1);
|
|
|
|
if (!skipFocus) this.editor.focus();
|
|
|
|
if (this.editor instanceof $) {
|
|
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
|
|
this.editor.trigger('input');
|
|
}
|
|
}
|
|
|
|
getEditorContent() {
|
|
return this.editor.getValue();
|
|
}
|
|
|
|
startLoadingSpinner() {
|
|
this.loadingIcon.classList.remove('gl-display-none');
|
|
this.dropdownIcon.classList.add('gl-display-none');
|
|
}
|
|
|
|
stopLoadingSpinner() {
|
|
this.loadingIcon.classList.add('gl-display-none');
|
|
this.dropdownIcon.classList.remove('gl-display-none');
|
|
}
|
|
}
|