summaryrefslogtreecommitdiff
path: root/app/assets/javascripts
diff options
context:
space:
mode:
authorFelipe Artur <felipefac@gmail.com>2016-06-24 16:43:46 -0300
committerFelipe Artur <felipefac@gmail.com>2016-08-16 15:50:17 -0300
commit28726729452ef64270534806e75a9595ea1a659d (patch)
tree7f9144f88c1fa9935f3d05d50ab9b1bcc4e7558d /app/assets/javascripts
parent7f853e2245eff92c037af5e007163d3e9631888d (diff)
downloadgitlab-ce-28726729452ef64270534806e75a9595ea1a659d.tar.gz
Load issues and merge requests templates from repository
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/api.js51
-rw-r--r--app/assets/javascripts/application.js1
-rw-r--r--app/assets/javascripts/blob/template_selector.js22
-rw-r--r--app/assets/javascripts/dispatcher.js2
-rw-r--r--app/assets/javascripts/templates/issuable_template_selector.js.es651
-rw-r--r--app/assets/javascripts/templates/issuable_template_selectors.js.es629
6 files changed, 132 insertions, 24 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 49c2ac0dac3..84b292e59c6 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -9,10 +9,11 @@
licensePath: "/api/:version/licenses/:key",
gitignorePath: "/api/:version/gitignores/:key",
gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key",
+ issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key",
+
group: function(group_id, callback) {
- var url;
- url = Api.buildUrl(Api.groupPath);
- url = url.replace(':id', group_id);
+ var url = Api.buildUrl(Api.groupPath)
+ .replace(':id', group_id);
return $.ajax({
url: url,
data: {
@@ -24,8 +25,7 @@
});
},
groups: function(query, skip_ldap, callback) {
- var url;
- url = Api.buildUrl(Api.groupsPath);
+ var url = Api.buildUrl(Api.groupsPath);
return $.ajax({
url: url,
data: {
@@ -39,8 +39,7 @@
});
},
namespaces: function(query, callback) {
- var url;
- url = Api.buildUrl(Api.namespacesPath);
+ var url = Api.buildUrl(Api.namespacesPath);
return $.ajax({
url: url,
data: {
@@ -54,8 +53,7 @@
});
},
projects: function(query, order, callback) {
- var url;
- url = Api.buildUrl(Api.projectsPath);
+ var url = Api.buildUrl(Api.projectsPath);
return $.ajax({
url: url,
data: {
@@ -70,9 +68,8 @@
});
},
newLabel: function(project_id, data, callback) {
- var url;
- url = Api.buildUrl(Api.labelsPath);
- url = url.replace(':id', project_id);
+ var url = Api.buildUrl(Api.labelsPath)
+ .replace(':id', project_id);
data.private_token = gon.api_token;
return $.ajax({
url: url,
@@ -86,9 +83,8 @@
});
},
groupProjects: function(group_id, query, callback) {
- var url;
- url = Api.buildUrl(Api.groupProjectsPath);
- url = url.replace(':id', group_id);
+ var url = Api.buildUrl(Api.groupProjectsPath)
+ .replace(':id', group_id);
return $.ajax({
url: url,
data: {
@@ -102,8 +98,8 @@
});
},
licenseText: function(key, data, callback) {
- var url;
- url = Api.buildUrl(Api.licensePath).replace(':key', key);
+ var url = Api.buildUrl(Api.licensePath)
+ .replace(':key', key);
return $.ajax({
url: url,
data: data
@@ -112,19 +108,32 @@
});
},
gitignoreText: function(key, callback) {
- var url;
- url = Api.buildUrl(Api.gitignorePath).replace(':key', key);
+ var url = Api.buildUrl(Api.gitignorePath)
+ .replace(':key', key);
return $.get(url, function(gitignore) {
return callback(gitignore);
});
},
gitlabCiYml: function(key, callback) {
- var url;
- url = Api.buildUrl(Api.gitlabCiYmlPath).replace(':key', key);
+ var url = Api.buildUrl(Api.gitlabCiYmlPath)
+ .replace(':key', key);
return $.get(url, function(file) {
return callback(file);
});
},
+ issueTemplate: function(namespacePath, projectPath, key, type, callback) {
+ var url = Api.buildUrl(Api.issuableTemplatePath)
+ .replace(':key', key)
+ .replace(':type', type)
+ .replace(':project_path', projectPath)
+ .replace(':namespace_path', namespacePath);
+ $.ajax({
+ url: url,
+ dataType: 'json'
+ }).done(function(file) {
+ callback(null, file);
+ }).error(callback);
+ },
buildUrl: function(url) {
if (gon.relative_url_root != null) {
url = gon.relative_url_root + url;
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index f1aab067351..e596b98603b 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -41,6 +41,7 @@
/*= require date.format */
/*= require_directory ./behaviors */
/*= require_directory ./blob */
+/*= require_directory ./templates */
/*= require_directory ./commit */
/*= require_directory ./extensions */
/*= require_directory ./lib/utils */
diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js
index 2cf0a6631b8..b0a37ef0e0a 100644
--- a/app/assets/javascripts/blob/template_selector.js
+++ b/app/assets/javascripts/blob/template_selector.js
@@ -9,6 +9,7 @@
}
this.onClick = bind(this.onClick, this);
this.dropdown = opts.dropdown, this.data = opts.data, this.pattern = opts.pattern, this.wrapper = opts.wrapper, this.editor = opts.editor, this.fileEndpoint = opts.fileEndpoint, this.$input = (ref = opts.$input) != null ? ref : $('#file_name');
+ this.dropdownIcon = $('.fa-chevron-down', this.dropdown);
this.buildDropdown();
this.bindEvents();
this.onFilenameUpdate();
@@ -60,11 +61,26 @@
return this.requestFile(item);
};
- TemplateSelector.prototype.requestFile = function(item) {};
+ TemplateSelector.prototype.requestFile = function(item) {
+ // This `requestFile` method is an abstract method that should
+ // be added by all subclasses.
+ };
- TemplateSelector.prototype.requestFileSuccess = function(file) {
+ TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) {
this.editor.setValue(file.content, 1);
- return this.editor.focus();
+ if (!skipFocus) this.editor.focus();
+ };
+
+ TemplateSelector.prototype.startLoadingSpinner = function() {
+ this.dropdownIcon
+ .addClass('fa-spinner fa-spin')
+ .removeClass('fa-chevron-down');
+ };
+
+ TemplateSelector.prototype.stopLoadingSpinner = function() {
+ this.dropdownIcon
+ .addClass('fa-chevron-down')
+ .removeClass('fa-spinner fa-spin');
};
return TemplateSelector;
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 3946e861976..7160fa71ce5 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -55,6 +55,7 @@
shortcut_handler = new ShortcutsNavigation();
new GLForm($('.issue-form'));
new IssuableForm($('.issue-form'));
+ new IssuableTemplateSelectors();
break;
case 'projects:merge_requests:new':
case 'projects:merge_requests:edit':
@@ -62,6 +63,7 @@
shortcut_handler = new ShortcutsNavigation();
new GLForm($('.merge-request-form'));
new IssuableForm($('.merge-request-form'));
+ new IssuableTemplateSelectors();
break;
case 'projects:tags:new':
new ZenMode();
diff --git a/app/assets/javascripts/templates/issuable_template_selector.js.es6 b/app/assets/javascripts/templates/issuable_template_selector.js.es6
new file mode 100644
index 00000000000..c32ddf80219
--- /dev/null
+++ b/app/assets/javascripts/templates/issuable_template_selector.js.es6
@@ -0,0 +1,51 @@
+/*= require ../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.wrapper.data('issuable-type');
+ this.titleInput = $(`#${this.issuableType}_title`);
+
+ let initialQuery = {
+ name: this.dropdown.data('selected')
+ };
+
+ if (initialQuery.name) this.requestFile(initialQuery);
+
+ $('.reset-template', this.dropdown.parent()).on('click', () => {
+ if (this.currentTemplate) this.setInputValueToTemplateContent();
+ });
+ }
+
+ 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.requestFileSuccess` 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 2nd
+ // argument to `requestFileSuccess`.
+ this.requestFileSuccess(this.currentTemplate, true);
+ this.titleInput.focus();
+ } else {
+ this.requestFileSuccess(this.currentTemplate);
+ }
+ return;
+ }
+ }
+
+ global.IssuableTemplateSelector = IssuableTemplateSelector;
+})(window);
diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js.es6 b/app/assets/javascripts/templates/issuable_template_selectors.js.es6
new file mode 100644
index 00000000000..bd8cdde033e
--- /dev/null
+++ b/app/assets/javascripts/templates/issuable_template_selectors.js.es6
@@ -0,0 +1,29 @@
+((global) => {
+ class IssuableTemplateSelectors {
+ constructor(opts = {}) {
+ this.$dropdowns = opts.$dropdowns || $('.js-issuable-selector');
+ this.editor = opts.editor || this.initEditor();
+
+ this.$dropdowns.each((i, dropdown) => {
+ let $dropdown = $(dropdown);
+ new IssuableTemplateSelector({
+ pattern: /(\.md)/,
+ data: $dropdown.data('data'),
+ wrapper: $dropdown.closest('.js-issuable-selector-wrap'),
+ dropdown: $dropdown,
+ editor: this.editor
+ });
+ });
+ }
+
+ initEditor() {
+ let 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);