Commit 2e4297dd authored by Phil Hughes's avatar Phil Hughes

Merge branch 'ee-38869-templates' into 'master'

Port of 38869-templates to EE

See merge request gitlab-org/gitlab-ee!3611
parents a1f76904 6d486917
This diff is collapsed.
......@@ -34,6 +34,7 @@ import LabelManager from './label_manager';
/* global WeightSelect */
/* global AdminEmailSelect */
import IssuableTemplateSelectors from './templates/issuable_template_selectors';
import Flash from './flash';
import CommitsList from './commits';
import Issue from './issue';
......@@ -294,7 +295,7 @@ import initGroupAnalytics from './init_group_analytics';
new LabelsSelect();
new MilestoneSelect();
new WeightSelect();
new gl.IssuableTemplateSelectors();
new IssuableTemplateSelectors();
break;
case 'projects:merge_requests:creations:new':
const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
......@@ -319,7 +320,7 @@ import initGroupAnalytics from './init_group_analytics';
new IssuableForm($('.merge-request-form'));
new LabelsSelect();
new MilestoneSelect();
new gl.IssuableTemplateSelectors();
new IssuableTemplateSelectors();
new AutoWidthDropdownSelect($('.js-target-branch-select')).init();
break;
case 'projects:tags:new':
......
import ImageBadge from '../image_badge';
import ImageDiff from '../image_diff';
import ReplacedImageDiff from '../replaced_image_diff';
import '../../commit/image_file';
import ImageFile from '../../commit/image_file';
export function resizeCoordinatesToImageElement(imageEl, meta) {
const { x, y, width, height } = meta;
......@@ -81,7 +81,7 @@ export function initImageDiff(fileEl, canCreateNote, renderCommentBadge) {
// ImageFile needs to be invoked before initImageDiff so that badges
// can mount to the correct location
new gl.ImageFile(fileEl); // eslint-disable-line no-new
new ImageFile(fileEl); // eslint-disable-line no-new
if (fileEl.querySelector('.diff-file .js-single-image')) {
diff = new ImageDiff(fileEl, options);
......
<script>
import IssuableTemplateSelectors from '../../../templates/issuable_template_selectors';
export default {
props: {
formState: {
......@@ -32,7 +34,7 @@
};
editor.getValue = () => this.formState.description;
this.issuableTemplate = new gl.IssuableTemplateSelectors({
this.issuableTemplate = new IssuableTemplateSelectors({
$dropdowns: $(this.$refs.toggle),
editor,
});
......
/* eslint-disable comma-dangle, max-len, no-useless-return, no-param-reassign, max-len */
import Api from '../api';
/* eslint-disable no-useless-return, max-len */
import Api from '../api';
import TemplateSelector from '../blob/template_selector';
((global) => {
class IssuableTemplateSelector extends TemplateSelector {
constructor(...args) {
super(...args);
this.projectPath = this.dropdown.data('project-path');
this.namespacePath = this.dropdown.data('namespace-path');
this.issuableType = this.$dropdownContainer.data('issuable-type');
this.titleInput = $(`#${this.issuableType}_title`);
const initialQuery = {
name: this.dropdown.data('selected')
};
if (initialQuery.name) this.requestFile(initialQuery);
$('.reset-template', this.dropdown.parent()).on('click', () => {
this.setInputValueToTemplateContent();
});
$('.no-template', this.dropdown.parent()).on('click', () => {
this.currentTemplate.content = '';
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text('Choose a template');
});
}
export default class IssuableTemplateSelector extends TemplateSelector {
constructor(...args) {
super(...args);
this.projectPath = this.dropdown.data('project-path');
this.namespacePath = this.dropdown.data('namespace-path');
this.issuableType = this.$dropdownContainer.data('issuable-type');
this.titleInput = $(`#${this.issuableType}_title`);
const initialQuery = {
name: this.dropdown.data('selected'),
};
if (initialQuery.name) this.requestFile(initialQuery);
$('.reset-template', this.dropdown.parent()).on('click', () => {
this.setInputValueToTemplateContent();
});
$('.no-template', this.dropdown.parent()).on('click', () => {
this.currentTemplate.content = '';
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text('Choose a template');
});
}
requestFile(query) {
this.startLoadingSpinner();
Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => {
this.currentTemplate = currentTemplate;
if (err) return; // Error handled by global AJAX error handler
this.stopLoadingSpinner();
this.setInputValueToTemplateContent();
});
return;
}
requestFile(query) {
this.startLoadingSpinner();
Api.issueTemplate(this.namespacePath, this.projectPath, query.name, this.issuableType, (err, currentTemplate) => {
this.currentTemplate = currentTemplate;
if (err) return; // Error handled by global AJAX error handler
this.stopLoadingSpinner();
this.setInputValueToTemplateContent();
});
return;
}
setInputValueToTemplateContent() {
// `this.setEditorContent` sets the value of the description input field
// to the content of the template selected.
if (this.titleInput.val() === '') {
// If the title has not yet been set, focus the title input and
// skip focusing the description input by setting `true` as the
// `skipFocus` option to `setEditorContent`.
this.setEditorContent(this.currentTemplate, { skipFocus: true });
this.titleInput.focus();
} else {
this.setEditorContent(this.currentTemplate, { skipFocus: false });
}
return;
setInputValueToTemplateContent() {
// `this.setEditorContent` sets the value of the description input field
// to the content of the template selected.
if (this.titleInput.val() === '') {
// If the title has not yet been set, focus the title input and
// skip focusing the description input by setting `true` as the
// `skipFocus` option to `setEditorContent`.
this.setEditorContent(this.currentTemplate, { skipFocus: true });
this.titleInput.focus();
} else {
this.setEditorContent(this.currentTemplate, { skipFocus: false });
}
return;
}
global.IssuableTemplateSelector = IssuableTemplateSelector;
})(window.gl || (window.gl = {}));
}
/* eslint-disable no-new, comma-dangle, class-methods-use-this, no-param-reassign */
/* eslint-disable no-new, class-methods-use-this */
import IssuableTemplateSelector from './issuable_template_selector';
((global) => {
class IssuableTemplateSelectors {
constructor({ $dropdowns, editor } = {}) {
this.$dropdowns = $dropdowns || $('.js-issuable-selector');
this.editor = editor || this.initEditor();
export default class IssuableTemplateSelectors {
constructor({ $dropdowns, editor } = {}) {
this.$dropdowns = $dropdowns || $('.js-issuable-selector');
this.editor = editor || this.initEditor();
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
new gl.IssuableTemplateSelector({
pattern: /(\.md)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-issuable-selector-wrap'),
dropdown: $dropdown,
editor: this.editor
});
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
new IssuableTemplateSelector({
pattern: /(\.md)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-issuable-selector-wrap'),
dropdown: $dropdown,
editor: this.editor,
});
}
initEditor() {
const editor = $('.markdown-area');
// Proxy ace-editor's .setValue to jQuery's .val
editor.setValue = editor.val;
editor.getValue = editor.val;
return editor;
}
});
}
global.IssuableTemplateSelectors = IssuableTemplateSelectors;
})(window.gl || (window.gl = {}));
initEditor() {
const editor = $('.markdown-area');
// Proxy ace-editor's .setValue to jQuery's .val
editor.setValue = editor.val;
editor.getValue = editor.val;
return editor;
}
}
---
title: Remove template selector from global namespace
merge_request:
author:
type: performance
......@@ -157,27 +157,19 @@ describe('utilsHelper', () => {
beforeEach(() => {
window.gl = window.gl || (window.gl = {});
glCache = window.gl;
window.gl.ImageFile = () => {};
fileEl = document.createElement('div');
fileEl.innerHTML = `
<div class="diff-file"></div>
`;
spyOn(ImageDiff.prototype, 'init').and.callFake(() => {});
spyOn(ReplacedImageDiff.prototype, 'init').and.callFake(() => {});
spyOn(ImageDiff.prototype, 'init').and.callFake(() => {});
});
afterEach(() => {
window.gl = glCache;
});
it('should initialize gl.ImageFile', () => {
spyOn(window.gl, 'ImageFile');
utilsHelper.initImageDiff(fileEl, false, false);
expect(gl.ImageFile).toHaveBeenCalled();
});
it('should initialize ImageDiff if js-single-image', () => {
const diffFileEl = fileEl.querySelector('.diff-file');
diffFileEl.innerHTML = `
......
......@@ -34,7 +34,6 @@ describe('Inline edit form component', () => {
});
it('renders template selector when templates exists', (done) => {
spyOn(gl, 'IssuableTemplateSelectors');
vm.issuableTemplates = ['test'];
Vue.nextTick(() => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment