From faf7865c269044ea49f64858f60a8bd33a715727 Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Tue, 7 Mar 2017 19:04:20 -0500 Subject: Lightly refactor js files related to file template selectors. --- app/assets/javascripts/blob/blob_ci_yaml.js | 42 ----- .../javascripts/blob/blob_dockerfile_selector.js | 19 --- .../javascripts/blob/blob_dockerfile_selectors.js | 27 ---- app/assets/javascripts/blob/blob_file_dropzone.js | 121 +++++++------- .../javascripts/blob/blob_gitignore_selector.js | 23 --- .../javascripts/blob/blob_gitignore_selectors.js | 26 --- .../javascripts/blob/blob_license_selector.js | 28 ---- .../javascripts/blob/blob_license_selectors.js | 23 --- app/assets/javascripts/blob/template_selector.js | 101 ------------ .../template_selectors/blob_ci_yaml_selector.js | 9 ++ .../template_selectors/blob_ci_yaml_selectors.js | 23 +++ .../template_selectors/blob_dockerfile_selector.js | 9 ++ .../blob_dockerfile_selectors.js | 23 +++ .../template_selectors/blob_gitignore_selector.js | 9 ++ .../template_selectors/blob_gitignore_selectors.js | 23 +++ .../template_selectors/blob_license_selector.js | 13 ++ .../template_selectors/blob_license_selectors.js | 24 +++ .../blob/template_selectors/template_selector.js | 92 +++++++++++ app/assets/javascripts/blob_edit/blob_bundle.js | 32 ++++ .../javascripts/blob_edit/blob_edit_bundle.js | 15 -- app/assets/javascripts/blob_edit/edit_blob.js | 177 +++++++++++---------- app/assets/javascripts/main.js | 9 -- .../templates/issuable_template_selector.js | 14 +- app/views/projects/blob/_upload.html.haml | 9 +- app/views/projects/blob/edit.html.haml | 2 +- app/views/projects/blob/new.html.haml | 2 +- config/webpack.config.js | 2 +- spec/javascripts/test_bundle.js | 3 +- 28 files changed, 425 insertions(+), 475 deletions(-) delete mode 100644 app/assets/javascripts/blob/blob_ci_yaml.js delete mode 100644 app/assets/javascripts/blob/blob_dockerfile_selector.js delete mode 100644 app/assets/javascripts/blob/blob_dockerfile_selectors.js delete mode 100644 app/assets/javascripts/blob/blob_gitignore_selector.js delete mode 100644 app/assets/javascripts/blob/blob_gitignore_selectors.js delete mode 100644 app/assets/javascripts/blob/blob_license_selector.js delete mode 100644 app/assets/javascripts/blob/blob_license_selectors.js delete mode 100644 app/assets/javascripts/blob/template_selector.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selector.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selectors.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_dockerfile_selector.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_dockerfile_selectors.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_gitignore_selector.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_gitignore_selectors.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_license_selector.js create mode 100644 app/assets/javascripts/blob/template_selectors/blob_license_selectors.js create mode 100644 app/assets/javascripts/blob/template_selectors/template_selector.js create mode 100644 app/assets/javascripts/blob_edit/blob_bundle.js delete mode 100644 app/assets/javascripts/blob_edit/blob_edit_bundle.js diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js b/app/assets/javascripts/blob/blob_ci_yaml.js deleted file mode 100644 index ec1c018424d..00000000000 --- a/app/assets/javascripts/blob/blob_ci_yaml.js +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable no-param-reassign, comma-dangle */ -/* global Api */ - -require('./template_selector'); - -((global) => { - class BlobCiYamlSelector extends gl.TemplateSelector { - requestFile(query) { - return Api.gitlabCiYml(query.name, this.requestFileSuccess.bind(this)); - } - - requestFileSuccess(file) { - return super.requestFileSuccess(file); - } - } - - global.BlobCiYamlSelector = BlobCiYamlSelector; - - class BlobCiYamlSelectors { - constructor({ editor, $dropdowns } = {}) { - this.editor = editor; - this.$dropdowns = $dropdowns || $('.js-gitlab-ci-yml-selector'); - this.initSelectors(); - } - - initSelectors() { - const editor = this.editor; - this.$dropdowns.each((i, dropdown) => { - const $dropdown = $(dropdown); - return new BlobCiYamlSelector({ - editor, - pattern: /(.gitlab-ci.yml)/, - data: $dropdown.data('data'), - wrapper: $dropdown.closest('.js-gitlab-ci-yml-selector-wrap'), - dropdown: $dropdown - }); - }); - } - } - - global.BlobCiYamlSelectors = BlobCiYamlSelectors; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/blob/blob_dockerfile_selector.js b/app/assets/javascripts/blob/blob_dockerfile_selector.js deleted file mode 100644 index d4f60cc6ecd..00000000000 --- a/app/assets/javascripts/blob/blob_dockerfile_selector.js +++ /dev/null @@ -1,19 +0,0 @@ -/* global Api */ - -require('./template_selector'); - -(() => { - const global = window.gl || (window.gl = {}); - - class BlobDockerfileSelector extends gl.TemplateSelector { - requestFile(query) { - return Api.dockerfileYml(query.name, this.requestFileSuccess.bind(this)); - } - - requestFileSuccess(file) { - return super.requestFileSuccess(file); - } - } - - global.BlobDockerfileSelector = BlobDockerfileSelector; -})(); diff --git a/app/assets/javascripts/blob/blob_dockerfile_selectors.js b/app/assets/javascripts/blob/blob_dockerfile_selectors.js deleted file mode 100644 index 9cee79fa5d5..00000000000 --- a/app/assets/javascripts/blob/blob_dockerfile_selectors.js +++ /dev/null @@ -1,27 +0,0 @@ -(() => { - const global = window.gl || (window.gl = {}); - - class BlobDockerfileSelectors { - constructor({ editor, $dropdowns } = {}) { - this.editor = editor; - this.$dropdowns = $dropdowns || $('.js-dockerfile-selector'); - this.initSelectors(); - } - - initSelectors() { - const editor = this.editor; - this.$dropdowns.each((i, dropdown) => { - const $dropdown = $(dropdown); - return new gl.BlobDockerfileSelector({ - editor, - pattern: /(Dockerfile)/, - data: $dropdown.data('data'), - wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'), - dropdown: $dropdown, - }); - }); - } - } - - global.BlobDockerfileSelectors = BlobDockerfileSelectors; -})(); diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js index 8f6bf162d6e..c9fe23aec75 100644 --- a/app/assets/javascripts/blob/blob_file_dropzone.js +++ b/app/assets/javascripts/blob/blob_file_dropzone.js @@ -1,66 +1,63 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, camelcase, object-shorthand, quotes, comma-dangle, prefer-arrow-callback, no-unused-vars, prefer-template, no-useless-escape, no-alert, max-len */ +/* eslint-disable func-names, object-shorthand, prefer-arrow-callback */ /* global Dropzone */ -(function() { - this.BlobFileDropzone = (function() { - function BlobFileDropzone(form, method) { - var dropzone, form_dropzone, submitButton; - form_dropzone = form.find('.dropzone'); - Dropzone.autoDiscover = false; - dropzone = form_dropzone.dropzone({ - autoDiscover: false, - autoProcessQueue: false, - url: form.attr('action'), - // Rails uses a hidden input field for PUT - // http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails - method: method, - clickable: true, - uploadMultiple: false, - paramName: "file", - maxFilesize: gon.max_file_size || 10, - parallelUploads: 1, - maxFiles: 1, - addRemoveLinks: true, - previewsContainer: '.dropzone-previews', - headers: { - "X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content") - }, - init: function() { - this.on('addedfile', function(file) { - $('.dropzone-alerts').html('').hide(); - }); - this.on('success', function(header, response) { - window.location.href = response.filePath; - }); - this.on('maxfilesexceeded', function(file) { - this.removeFile(file); - }); - return this.on('sending', function(file, xhr, formData) { - formData.append('target_branch', form.find('input[name="target_branch"]').val()); - formData.append('create_merge_request', form.find('.js-create-merge-request').val()); - formData.append('commit_message', form.find('.js-commit-message').val()); - }); - }, - // Override behavior of adding error underneath preview - error: function(file, errorMessage) { - var stripped; - stripped = $("
").html(errorMessage).text(); - $('.dropzone-alerts').html('Error uploading file: \"' + stripped + '\"').show(); +export default class BlobFileDropzone { + constructor(form, method) { + const formDropzone = form.find('.dropzone'); + Dropzone.autoDiscover = false; + + const dropzone = formDropzone.dropzone({ + autoDiscover: false, + autoProcessQueue: false, + url: form.attr('action'), + // Rails uses a hidden input field for PUT + // http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails + method: method, + clickable: true, + uploadMultiple: false, + paramName: 'file', + maxFilesize: gon.max_file_size || 10, + parallelUploads: 1, + maxFiles: 1, + addRemoveLinks: true, + previewsContainer: '.dropzone-previews', + headers: { + 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'), + }, + init: function () { + this.on('addedfile', function () { + $('.dropzone-alerts').html('').hide(); + }); + this.on('success', function (header, response) { + window.location.href = response.filePath; + }); + this.on('maxfilesexceeded', function (file) { this.removeFile(file); - } - }); - submitButton = form.find('#submit-all')[0]; - submitButton.addEventListener('click', function(e) { - e.preventDefault(); - e.stopPropagation(); - if (dropzone[0].dropzone.getQueuedFiles().length === 0) { - alert("Please select a file"); - } - dropzone[0].dropzone.processQueue(); - return false; - }); - } + }); + this.on('sending', function (file, xhr, formData) { + formData.append('target_branch', form.find('input[name="target_branch"]').val()); + formData.append('create_merge_request', form.find('.js-create-merge-request').val()); + formData.append('commit_message', form.find('.js-commit-message').val()); + }); + }, + // Override behavior of adding error underneath preview + error: function (file, errorMessage) { + const stripped = $('
').html(errorMessage).text(); + $('.dropzone-alerts').html(`Error uploading file: "${stripped}"`).show(); + this.removeFile(file); + }, + }); - return BlobFileDropzone; - })(); -}).call(window); + const submitButton = form.find('#submit-all')[0]; + submitButton.addEventListener('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + if (dropzone[0].dropzone.getQueuedFiles().length === 0) { + // eslint-disable-next-line no-alert + alert('Please select a file'); + } + dropzone[0].dropzone.processQueue(); + return false; + }); + } +} diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js b/app/assets/javascripts/blob/blob_gitignore_selector.js deleted file mode 100644 index de20eab9cd1..00000000000 --- a/app/assets/javascripts/blob/blob_gitignore_selector.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params */ -/* global Api */ - -require('./template_selector'); - -(function() { - var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - this.BlobGitignoreSelector = (function(superClass) { - extend(BlobGitignoreSelector, superClass); - - function BlobGitignoreSelector() { - return BlobGitignoreSelector.__super__.constructor.apply(this, arguments); - } - - BlobGitignoreSelector.prototype.requestFile = function(query) { - return Api.gitignoreText(query.name, this.requestFileSuccess.bind(this)); - }; - - return BlobGitignoreSelector; - })(gl.TemplateSelector); -}).call(window); diff --git a/app/assets/javascripts/blob/blob_gitignore_selectors.js b/app/assets/javascripts/blob/blob_gitignore_selectors.js deleted file mode 100644 index 43e5c0a5641..00000000000 --- a/app/assets/javascripts/blob/blob_gitignore_selectors.js +++ /dev/null @@ -1,26 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-cond-assign, no-sequences, comma-dangle, max-len */ -/* global BlobGitignoreSelector */ - -(function() { - this.BlobGitignoreSelectors = (function() { - function BlobGitignoreSelectors(opts) { - var ref; - this.$dropdowns = (ref = opts.$dropdowns) != null ? ref : $('.js-gitignore-selector'), this.editor = opts.editor; - this.$dropdowns.each((function(_this) { - return function(i, dropdown) { - var $dropdown; - $dropdown = $(dropdown); - return new BlobGitignoreSelector({ - pattern: /(.gitignore)/, - data: $dropdown.data('data'), - wrapper: $dropdown.closest('.js-gitignore-selector-wrap'), - dropdown: $dropdown, - editor: _this.editor - }); - }; - })(this)); - } - - return BlobGitignoreSelectors; - })(); -}).call(window); diff --git a/app/assets/javascripts/blob/blob_license_selector.js b/app/assets/javascripts/blob/blob_license_selector.js deleted file mode 100644 index b582052a76e..00000000000 --- a/app/assets/javascripts/blob/blob_license_selector.js +++ /dev/null @@ -1,28 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle */ -/* global Api */ - -require('./template_selector'); - -(function() { - var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, - hasProp = {}.hasOwnProperty; - - this.BlobLicenseSelector = (function(superClass) { - extend(BlobLicenseSelector, superClass); - - function BlobLicenseSelector() { - return BlobLicenseSelector.__super__.constructor.apply(this, arguments); - } - - BlobLicenseSelector.prototype.requestFile = function(query) { - var data; - data = { - project: this.dropdown.data('project'), - fullname: this.dropdown.data('fullname') - }; - return Api.licenseText(query.id, data, this.requestFileSuccess.bind(this)); - }; - - return BlobLicenseSelector; - })(gl.TemplateSelector); -}).call(window); diff --git a/app/assets/javascripts/blob/blob_license_selectors.js b/app/assets/javascripts/blob/blob_license_selectors.js deleted file mode 100644 index c5067b0feae..00000000000 --- a/app/assets/javascripts/blob/blob_license_selectors.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable no-unused-vars, no-param-reassign */ -/* global BlobLicenseSelector */ - -((global) => { - class BlobLicenseSelectors { - constructor({ $dropdowns, editor }) { - this.$dropdowns = $('.js-license-selector'); - this.editor = editor; - this.$dropdowns.each((i, dropdown) => { - const $dropdown = $(dropdown); - return new BlobLicenseSelector({ - editor, - pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i, - data: $dropdown.data('data'), - wrapper: $dropdown.closest('.js-license-selector-wrap'), - dropdown: $dropdown, - }); - }); - } - } - - global.BlobLicenseSelectors = BlobLicenseSelectors; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js deleted file mode 100644 index 7e03ec3b391..00000000000 --- a/app/assets/javascripts/blob/template_selector.js +++ /dev/null @@ -1,101 +0,0 @@ -/* eslint-disable comma-dangle, object-shorthand, func-names, space-before-function-paren, arrow-parens, no-unused-vars, class-methods-use-this, no-var, consistent-return, no-param-reassign, max-len */ - -((global) => { - class TemplateSelector { - constructor({ dropdown, data, pattern, wrapper, editor, fileEndpoint, $input } = {}) { - this.onClick = this.onClick.bind(this); - this.dropdown = dropdown; - this.data = data; - this.pattern = pattern; - this.wrapper = wrapper; - this.editor = editor; - this.fileEndpoint = fileEndpoint; - this.$input = $input || $('#file_name'); - this.dropdownIcon = $('.fa-chevron-down', this.dropdown); - this.buildDropdown(); - this.bindEvents(); - this.onFilenameUpdate(); - - this.autosizeUpdateEvent = document.createEvent('Event'); - this.autosizeUpdateEvent.initEvent('autosize:update', true, false); - } - - buildDropdown() { - return this.dropdown.glDropdown({ - data: this.data, - filterable: true, - selectable: true, - toggleLabel: this.toggleLabel, - search: { - fields: ['name'] - }, - clicked: this.onClick, - text: function(item) { - return item.name; - } - }); - } - - bindEvents() { - return this.$input.on('keyup blur', (e) => this.onFilenameUpdate()); - } - - toggleLabel(item) { - return item.name; - } - - onFilenameUpdate() { - var filenameMatches; - if (!this.$input.length) { - return; - } - filenameMatches = this.pattern.test(this.$input.val().trim()); - if (!filenameMatches) { - this.wrapper.addClass('hidden'); - return; - } - return this.wrapper.removeClass('hidden'); - } - - onClick(item, el, e) { - e.preventDefault(); - return this.requestFile(item); - } - - requestFile(item) { - // This `requestFile` method is an abstract method that should - // be added by all subclasses. - } - - // To be implemented on the extending class - // e.g. - // Api.gitignoreText item.name, @requestFileSuccess.bind(@) - requestFileSuccess(file, { skipFocus } = {}) { - if (!file) return; - - const oldValue = this.editor.getValue(); - const newValue = file.content; - - this.editor.setValue(newValue, 1); - if (!skipFocus) this.editor.focus(); - - if (this.editor instanceof jQuery) { - this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent); - } - } - - startLoadingSpinner() { - this.dropdownIcon - .addClass('fa-spinner fa-spin') - .removeClass('fa-chevron-down'); - } - - stopLoadingSpinner() { - this.dropdownIcon - .addClass('fa-chevron-down') - .removeClass('fa-spinner fa-spin'); - } - } - - global.TemplateSelector = TemplateSelector; -})(window.gl || (window.gl = {})); diff --git a/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selector.js b/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selector.js new file mode 100644 index 00000000000..5a5954e7751 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selector.js @@ -0,0 +1,9 @@ +/* global Api */ + +import TemplateSelector from './template_selector'; + +export default class BlobCiYamlSelector extends TemplateSelector { + requestFile(query) { + return Api.gitlabCiYml(query.name, (file, config) => this.setEditorContent(file, config)); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selectors.js b/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selectors.js new file mode 100644 index 00000000000..7a4d6a42a03 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_ci_yaml_selectors.js @@ -0,0 +1,23 @@ +/* global Api */ + +import BlobCiYamlSelector from './blob_ci_yaml_selector'; + +export default class BlobCiYamlSelectors { + constructor({ editor, $dropdowns }) { + this.$dropdowns = $dropdowns || $('.js-gitlab-ci-yml-selector'); + this.initSelectors(editor); + } + + initSelectors(editor) { + this.$dropdowns.each((i, dropdown) => { + const $dropdown = $(dropdown); + return new BlobCiYamlSelector({ + editor, + pattern: /(.gitlab-ci.yml)/, + data: $dropdown.data('data'), + wrapper: $dropdown.closest('.js-gitlab-ci-yml-selector-wrap'), + dropdown: $dropdown, + }); + }); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selector.js b/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selector.js new file mode 100644 index 00000000000..19f8820a0cb --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selector.js @@ -0,0 +1,9 @@ +/* global Api */ + +import TemplateSelector from './template_selector'; + +export default class BlobDockerfileSelector extends TemplateSelector { + requestFile(query) { + return Api.dockerfileYml(query.name, (file, config) => this.setEditorContent(file, config)); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selectors.js b/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selectors.js new file mode 100644 index 00000000000..da067035b43 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_dockerfile_selectors.js @@ -0,0 +1,23 @@ +import BlobDockerfileSelector from './blob_dockerfile_selector'; + +export default class BlobDockerfileSelectors { + constructor({ editor, $dropdowns }) { + this.editor = editor; + this.$dropdowns = $dropdowns || $('.js-dockerfile-selector'); + this.initSelectors(); + } + + initSelectors() { + const editor = this.editor; + this.$dropdowns.each((i, dropdown) => { + const $dropdown = $(dropdown); + return new BlobDockerfileSelector({ + editor, + pattern: /(Dockerfile)/, + data: $dropdown.data('data'), + wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'), + dropdown: $dropdown, + }); + }); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_gitignore_selector.js b/app/assets/javascripts/blob/template_selectors/blob_gitignore_selector.js new file mode 100644 index 00000000000..0b6b02fc2b3 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_gitignore_selector.js @@ -0,0 +1,9 @@ +/* global Api */ + +import TemplateSelector from './template_selector'; + +export default class BlobGitignoreSelector extends TemplateSelector { + requestFile(query) { + return Api.gitignoreText(query.name, (file, config) => this.setEditorContent(file, config)); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_gitignore_selectors.js b/app/assets/javascripts/blob/template_selectors/blob_gitignore_selectors.js new file mode 100644 index 00000000000..dc485d97677 --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_gitignore_selectors.js @@ -0,0 +1,23 @@ +import BlobGitignoreSelector from './blob_gitignore_selector'; + +export default class BlobGitignoreSelectors { + constructor({ editor, $dropdowns }) { + this.$dropdowns = $dropdowns || $('.js-gitignore-selector'); + this.editor = editor; + this.initSelectors(); + } + + initSelectors() { + this.$dropdowns.each((i, dropdown) => { + const $dropdown = $(dropdown); + + return new BlobGitignoreSelector({ + pattern: /(.gitignore)/, + data: $dropdown.data('data'), + wrapper: $dropdown.closest('.js-gitignore-selector-wrap'), + dropdown: $dropdown, + editor: this.editor, + }); + }); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_license_selector.js b/app/assets/javascripts/blob/template_selectors/blob_license_selector.js new file mode 100644 index 00000000000..e9cb31cc2dc --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_license_selector.js @@ -0,0 +1,13 @@ +/* global Api */ + +import TemplateSelector from './template_selector'; + +export default class BlobLicenseSelector extends TemplateSelector { + requestFile(query) { + const data = { + project: this.dropdown.data('project'), + fullname: this.dropdown.data('fullname'), + }; + return Api.licenseText(query.id, data, (file, config) => this.setEditorContent(file, config)); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/blob_license_selectors.js b/app/assets/javascripts/blob/template_selectors/blob_license_selectors.js new file mode 100644 index 00000000000..a44f4f78b2d --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/blob_license_selectors.js @@ -0,0 +1,24 @@ +/* eslint-disable no-unused-vars, no-param-reassign */ + +import BlobLicenseSelector from './blob_license_selector'; + +export default class BlobLicenseSelectors { + constructor({ $dropdowns, editor }) { + this.$dropdowns = $dropdowns || $('.js-license-selector'); + this.initSelectors(editor); + } + + initSelectors(editor) { + this.$dropdowns.each((i, dropdown) => { + const $dropdown = $(dropdown); + + return new BlobLicenseSelector({ + editor, + pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i, + data: $dropdown.data('data'), + wrapper: $dropdown.closest('.js-license-selector-wrap'), + dropdown: $dropdown, + }); + }); + } +} diff --git a/app/assets/javascripts/blob/template_selectors/template_selector.js b/app/assets/javascripts/blob/template_selectors/template_selector.js new file mode 100644 index 00000000000..d7c1c32efbd --- /dev/null +++ b/app/assets/javascripts/blob/template_selectors/template_selector.js @@ -0,0 +1,92 @@ +/* eslint-disable class-methods-use-this, no-unused-vars */ + +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 = $('.fa-chevron-down', dropdown); + + this.initDropdown(dropdown, data); + this.listenForFilenameInput(); + this.renderMatchedDropdown(); + this.initAutosizeUpdateEvent(); + } + + initDropdown(dropdown, data) { + return $(dropdown).glDropdown({ + data, + filterable: true, + selectable: true, + toggleLabel: item => item.name, + search: { + fields: ['name'], + }, + clicked: (item, el, e) => this.fetchFileTemplate(item, el, e), + text: item => item.name, + }); + } + + 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(item, el, e) { + e.preventDefault(); + return this.requestFile(item); + } + + requestFile(item) { + // This `requestFile` method is an abstract method that should + // be added by all subclasses. + } + + // To be implemented on the extending class + // e.g. Api.gitlabCiYml(query.name, file => this.setEditorContent(file)); + + setEditorContent(file, { skipFocus } = {}) { + if (!file) return; + + const newValue = file.content; + + this.editor.setValue(newValue, 1); + + if (!skipFocus) this.editor.focus(); + + if (this.editor instanceof jQuery) { + this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent); + } + } + + startLoadingSpinner() { + this.$dropdownIcon + .addClass('fa-spinner fa-spin') + .removeClass('fa-chevron-down'); + } + + stopLoadingSpinner() { + this.$dropdownIcon + .addClass('fa-chevron-down') + .removeClass('fa-spinner fa-spin'); + } +} diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js new file mode 100644 index 00000000000..c5deccf631e --- /dev/null +++ b/app/assets/javascripts/blob_edit/blob_bundle.js @@ -0,0 +1,32 @@ +/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */ +/* global EditBlob */ +/* global NewCommitForm */ + +import EditBlob from './edit_blob'; +import BlobFileDropzone from '../blob/blob_file_dropzone'; + +$(() => { + const editBlobForm = $('.js-edit-blob-form'); + const uploadBlobForm = $('.js-upload-blob-form'); + + if (editBlobForm.length) { + const urlRoot = editBlobForm.data('relative-url-root'); + const assetsPath = editBlobForm.data('assets-prefix'); + const blobLanguage = editBlobForm.data('blob-language'); + + new EditBlob(`${urlRoot}${assetsPath}`, blobLanguage); + new NewCommitForm(editBlobForm); + } + + if (uploadBlobForm.length) { + const method = uploadBlobForm.data('method'); + + new BlobFileDropzone(uploadBlobForm, method); + new NewCommitForm(uploadBlobForm); + + window.gl.utils.disableButtonIfEmptyField( + uploadBlobForm.find('.js-commit-message'), + '.btn-upload-file', + ); + } +}); diff --git a/app/assets/javascripts/blob_edit/blob_edit_bundle.js b/app/assets/javascripts/blob_edit/blob_edit_bundle.js deleted file mode 100644 index 0436bbb0eaf..00000000000 --- a/app/assets/javascripts/blob_edit/blob_edit_bundle.js +++ /dev/null @@ -1,15 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */ -/* global EditBlob */ -/* global NewCommitForm */ - -require('./edit_blob'); - -(function() { - $(function() { - var url = $(".js-edit-blob-form").data("relative-url-root"); - url += $(".js-edit-blob-form").data("assets-prefix"); - - var blob = new EditBlob(url, $('.js-edit-blob-form').data('blob-language')); - new NewCommitForm($('.js-edit-blob-form')); - }); -}).call(window); diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js index a1127b9e30e..d3560d5df3b 100644 --- a/app/assets/javascripts/blob_edit/edit_blob.js +++ b/app/assets/javascripts/blob_edit/edit_blob.js @@ -1,88 +1,99 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, camelcase, no-param-reassign, quotes, prefer-template, no-new, comma-dangle, one-var, one-var-declaration-per-line, prefer-arrow-callback, no-else-return, no-unused-vars, max-len */ /* global ace */ -/* global BlobGitignoreSelectors */ - -(function() { - var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; }; - - this.EditBlob = (function() { - function EditBlob(assets_path, ace_mode) { - if (ace_mode == null) { - ace_mode = null; - } - this.editModeLinkClickHandler = bind(this.editModeLinkClickHandler, this); - ace.config.set("modePath", assets_path + "/ace"); - ace.config.loadModule("ace/ext/searchbox"); - this.editor = ace.edit("editor"); - this.editor.focus(); - if (ace_mode) { - this.editor.getSession().setMode("ace/mode/" + ace_mode); - } - $('form').submit((function(_this) { - return function() { - return $("#file-content").val(_this.editor.getValue()); - }; - // Before a form submission, move the content from the Ace editor into the - // submitted textarea - })(this)); - this.initModePanesAndLinks(); - this.initSoftWrap(); - new gl.BlobLicenseSelectors({ - editor: this.editor - }); + +import BlobLicenseSelectors from '../blob/template_selectors/blob_license_selectors'; +import BlobGitignoreSelectors from '../blob/template_selectors/blob_gitignore_selectors'; +import BlobCiYamlSelectors from '../blob/template_selectors/blob_ci_yaml_selectors'; +import BlobDockerfileSelectors from '../blob/template_selectors/blob_dockerfile_selectors'; + +export default class EditBlob { + constructor(assetsPath, aceMode) { + this.configureAceEditor(aceMode, assetsPath); + this.prepFileContentForSubmit(); + this.initModePanesAndLinks(); + this.initSoftWrap(); + this.initFileSelectors(); + } + + configureAceEditor(aceMode, assetsPath) { + ace.config.set('modePath', `${assetsPath}/ace`); + ace.config.loadModule('ace/ext/searchbox'); + + this.editor = ace.edit('editor'); + this.editor.focus(); + + if (aceMode) { + this.editor.getSession().setMode(`ace/mode/${aceMode}`); + } + } + + prepFileContentForSubmit() { + $('form').submit(() => { + $('#file-content').val(this.editor.getValue()); + }); + } + + initFileSelectors() { + this.blobTemplateSelectors = [ + new BlobLicenseSelectors({ + editor: this.editor, + }), new BlobGitignoreSelectors({ - editor: this.editor - }); - new gl.BlobCiYamlSelectors({ - editor: this.editor - }); - new gl.BlobDockerfileSelectors({ - editor: this.editor + editor: this.editor, + }), + new BlobCiYamlSelectors({ + editor: this.editor, + }), + new BlobDockerfileSelectors({ + editor: this.editor, + }), + ]; + } + + initModePanesAndLinks() { + this.$editModePanes = $('.js-edit-mode-pane'); + this.$editModeLinks = $('.js-edit-mode a'); + this.$editModeLinks.on('click', e => this.editModeLinkClickHandler(e)); + } + + editModeLinkClickHandler(e) { + e.preventDefault(); + + const currentLink = $(e.target); + const paneId = currentLink.attr('href'); + const currentPane = this.$editModePanes.filter(paneId); + + this.$editModeLinks.parent().removeClass('active hover'); + + currentLink.parent().addClass('active hover'); + + this.$editModePanes.hide(); + + currentPane.fadeIn(200); + + if (paneId === '#preview') { + this.$toggleButton.hide(); + return $.post(currentLink.data('preview-url'), { + content: this.editor.getValue(), + }, (response) => { + currentPane.empty().append(response); + return currentPane.renderGFM(); }); } - EditBlob.prototype.initModePanesAndLinks = function() { - this.$editModePanes = $(".js-edit-mode-pane"); - this.$editModeLinks = $(".js-edit-mode a"); - return this.$editModeLinks.click(this.editModeLinkClickHandler); - }; - - EditBlob.prototype.editModeLinkClickHandler = function(event) { - var currentLink, currentPane, paneId; - event.preventDefault(); - currentLink = $(event.target); - paneId = currentLink.attr("href"); - currentPane = this.$editModePanes.filter(paneId); - this.$editModeLinks.parent().removeClass("active hover"); - currentLink.parent().addClass("active hover"); - this.$editModePanes.hide(); - currentPane.fadeIn(200); - if (paneId === "#preview") { - this.$toggleButton.hide(); - return $.post(currentLink.data("preview-url"), { - content: this.editor.getValue() - }, function(response) { - currentPane.empty().append(response); - return currentPane.renderGFM(); - }); - } else { - this.$toggleButton.show(); - return this.editor.focus(); - } - }; - - EditBlob.prototype.initSoftWrap = function() { - this.isSoftWrapped = false; - this.$toggleButton = $('.soft-wrap-toggle'); - this.$toggleButton.on('click', this.toggleSoftWrap.bind(this)); - }; - - EditBlob.prototype.toggleSoftWrap = function(e) { - this.isSoftWrapped = !this.isSoftWrapped; - this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped); - this.editor.getSession().setUseWrapMode(this.isSoftWrapped); - }; - - return EditBlob; - })(); -}).call(window); + this.$toggleButton.show(); + + return this.editor.focus(); + } + + initSoftWrap() { + this.isSoftWrapped = false; + this.$toggleButton = $('.soft-wrap-toggle'); + this.$toggleButton.on('click', () => this.toggleSoftWrap()); + } + + toggleSoftWrap() { + this.isSoftWrapped = !this.isSoftWrapped; + this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped); + this.editor.getSession().setUseWrapMode(this.isSoftWrapped); + } +} diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 81d5748191d..8abff3d78f7 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -49,15 +49,6 @@ import { installGlEmojiElement } from './behaviors/gl_emoji'; installGlEmojiElement(); // blob -import './blob/blob_ci_yaml'; -import './blob/blob_dockerfile_selector'; -import './blob/blob_dockerfile_selectors'; -import './blob/blob_file_dropzone'; -import './blob/blob_gitignore_selector'; -import './blob/blob_gitignore_selectors'; -import './blob/blob_license_selector'; -import './blob/blob_license_selectors'; -import './blob/template_selector'; import './blob/create_branch_dropdown'; import './blob/target_branch_dropdown'; diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index e9e9aafd71a..32067ed1fee 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -1,15 +1,15 @@ /* eslint-disable comma-dangle, max-len, no-useless-return, no-param-reassign, max-len */ /* global Api */ -require('../blob/template_selector'); +import TemplateSelector from '../blob/template_selectors/template_selector'; ((global) => { - class IssuableTemplateSelector extends gl.TemplateSelector { + 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.issuableType = this.$dropdownContainer.data('issuable-type'); this.titleInput = $(`#${this.issuableType}_title`); const initialQuery = { @@ -41,16 +41,16 @@ require('../blob/template_selector'); } setInputValueToTemplateContent() { - // `this.requestFileSuccess` sets the value of the description input field + // `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 `requestFileSuccess`. - this.requestFileSuccess(this.currentTemplate, { skipFocus: true }); + // `skipFocus` option to `setEditorContent`. + this.setEditorContent(this.currentTemplate, { skipFocus: true }); this.titleInput.focus(); } else { - this.requestFileSuccess(this.currentTemplate, { skipFocus: false }); + this.setEditorContent(this.currentTemplate, { skipFocus: false }); } return; } diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml index 4924c73cf8e..e14885f264b 100644 --- a/app/views/projects/blob/_upload.html.haml +++ b/app/views/projects/blob/_upload.html.haml @@ -5,7 +5,7 @@ %a.close{ href: "#", "data-dismiss" => "modal" } × %h3.page-title= title .modal-body - = form_tag form_path, method: method, class: 'js-quick-submit js-upload-blob-form form-horizontal' do + = form_tag form_path, method: method, class: 'js-quick-submit js-upload-blob-form form-horizontal', data: { method: method } do .dropzone .dropzone-previews.blob-upload-dropzone-previews %p.dz-message.light @@ -24,8 +24,5 @@ .inline.prepend-left-10 = commit_in_fork_help - -:javascript - gl.utils.disableButtonIfEmptyField($('.js-upload-blob-form').find('.js-commit-message'), '.btn-upload-file'); - new BlobFileDropzone($('.js-upload-blob-form'), '#{method}'); - new NewCommitForm($('.js-upload-blob-form')) +- content_for :page_specific_javascripts do + = page_specific_javascript_bundle_tag('blob') diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index 3bcddcb37f1..afe0b5dba45 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -2,7 +2,7 @@ - page_title "Edit", @blob.path, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_bundle_tag('blob_edit') + = page_specific_javascript_bundle_tag('blob') = render "projects/commits/head" %div{ class: container_class } diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index e0ce8cc9601..4c449e040ee 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -1,7 +1,7 @@ - page_title "New File", @path.presence, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_bundle_tag('blob_edit') + = page_specific_javascript_bundle_tag('blob') %h3.page-title New File diff --git a/config/webpack.config.js b/config/webpack.config.js index 3cf94b9b435..0859c8416c8 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -21,7 +21,7 @@ var config = { common_vue: ['vue', './vue_shared/common_vue.js'], common_d3: ['d3'], main: './main.js', - blob_edit: './blob_edit/blob_edit_bundle.js', + blob: './blob_edit/blob_bundle.js', boards: './boards/boards_bundle.js', simulate_drag: './test_utils/simulate_drag.js', cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js', diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js index 16df1ad4f28..03532a46a95 100644 --- a/spec/javascripts/test_bundle.js +++ b/spec/javascripts/test_bundle.js @@ -36,7 +36,8 @@ testsContext.keys().forEach(function (path) { if (process.env.BABEL_ENV === 'coverage') { // exempt these files from the coverage report const troubleMakers = [ - './blob_edit/blob_edit_bundle.js', + './blob_edit/blob_bundle.js', + './boards/boards_bundle.js', './cycle_analytics/components/stage_plan_component.js', './cycle_analytics/components/stage_staging_component.js', './cycle_analytics/components/stage_test_component.js', -- cgit v1.2.1