diff options
Diffstat (limited to 'app/assets/javascripts/blob')
4 files changed, 276 insertions, 1 deletions
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js index 5f14ff40eee..8f6bf162d6e 100644 --- a/app/assets/javascripts/blob/blob_file_dropzone.js +++ b/app/assets/javascripts/blob/blob_file_dropzone.js @@ -36,7 +36,7 @@ this.removeFile(file); }); return this.on('sending', function(file, xhr, formData) { - formData.append('target_branch', form.find('.js-target-branch').val()); + 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()); }); diff --git a/app/assets/javascripts/blob/blob_line_permalink_updater.js b/app/assets/javascripts/blob/blob_line_permalink_updater.js new file mode 100644 index 00000000000..c8f68860fbd --- /dev/null +++ b/app/assets/javascripts/blob/blob_line_permalink_updater.js @@ -0,0 +1,35 @@ +const lineNumberRe = /^L[0-9]+/; + +const updateLineNumbersOnBlobPermalinks = (linksToUpdate) => { + const hash = gl.utils.getLocationHash(); + if (hash && lineNumberRe.test(hash)) { + const hashUrlString = `#${hash}`; + + [].concat(Array.prototype.slice.call(linksToUpdate)).forEach((permalinkButton) => { + const baseHref = permalinkButton.getAttribute('data-original-href') || (() => { + const href = permalinkButton.getAttribute('href'); + permalinkButton.setAttribute('data-original-href', href); + return href; + })(); + permalinkButton.setAttribute('href', `${baseHref}${hashUrlString}`); + }); + } +}; + +function BlobLinePermalinkUpdater(blobContentHolder, lineNumberSelector, elementsToUpdate) { + const updateBlameAndBlobPermalinkCb = () => { + // Wait for the hash to update from the LineHighlighter callback + setTimeout(() => { + updateLineNumbersOnBlobPermalinks(elementsToUpdate); + }, 0); + }; + + blobContentHolder.addEventListener('click', (e) => { + if (e.target.matches(lineNumberSelector)) { + updateBlameAndBlobPermalinkCb(); + } + }); + updateBlameAndBlobPermalinkCb(); +} + +export default BlobLinePermalinkUpdater; diff --git a/app/assets/javascripts/blob/create_branch_dropdown.js b/app/assets/javascripts/blob/create_branch_dropdown.js new file mode 100644 index 00000000000..95517f51b1c --- /dev/null +++ b/app/assets/javascripts/blob/create_branch_dropdown.js @@ -0,0 +1,88 @@ +class CreateBranchDropdown { + constructor(el, targetBranchDropdown) { + this.targetBranchDropdown = targetBranchDropdown; + this.el = el; + this.dropdownBack = this.el.closest('.dropdown').querySelector('.dropdown-menu-back'); + this.cancelButton = this.el.querySelector('.js-cancel-branch-btn'); + this.newBranchField = this.el.querySelector('#new_branch_name'); + this.newBranchCreateButton = this.el.querySelector('.js-new-branch-btn'); + + this.newBranchCreateButton.setAttribute('disabled', ''); + + this.addBindings(); + this.cleanupWrapper = this.cleanup.bind(this); + document.addEventListener('beforeunload', this.cleanupWrapper); + } + + cleanup() { + this.cleanBindings(); + document.removeEventListener('beforeunload', this.cleanupWrapper); + } + + cleanBindings() { + this.newBranchField.removeEventListener('keyup', this.enableBranchCreateButtonWrapper); + this.newBranchField.removeEventListener('change', this.enableBranchCreateButtonWrapper); + this.newBranchField.removeEventListener('keydown', this.handleNewBranchKeydownWrapper); + this.dropdownBack.removeEventListener('click', this.resetFormWrapper); + this.cancelButton.removeEventListener('click', this.handleCancelClickWrapper); + this.newBranchCreateButton.removeEventListener('click', this.createBranchWrapper); + } + + addBindings() { + this.enableBranchCreateButtonWrapper = this.enableBranchCreateButton.bind(this); + this.handleNewBranchKeydownWrapper = this.handleNewBranchKeydown.bind(this); + this.resetFormWrapper = this.resetForm.bind(this); + this.handleCancelClickWrapper = this.handleCancelClick.bind(this); + this.createBranchWrapper = this.createBranch.bind(this); + + this.newBranchField.addEventListener('keyup', this.enableBranchCreateButtonWrapper); + this.newBranchField.addEventListener('change', this.enableBranchCreateButtonWrapper); + this.newBranchField.addEventListener('keydown', this.handleNewBranchKeydownWrapper); + this.dropdownBack.addEventListener('click', this.resetFormWrapper); + this.cancelButton.addEventListener('click', this.handleCancelClickWrapper); + this.newBranchCreateButton.addEventListener('click', this.createBranchWrapper); + } + + handleCancelClick(e) { + e.preventDefault(); + e.stopPropagation(); + + this.resetForm(); + this.dropdownBack.click(); + } + + handleNewBranchKeydown(e) { + const keyCode = e.which; + const ENTER_KEYCODE = 13; + if (keyCode === ENTER_KEYCODE) { + this.createBranch(e); + } + } + + enableBranchCreateButton() { + if (this.newBranchField.value !== '') { + this.newBranchCreateButton.removeAttribute('disabled'); + } else { + this.newBranchCreateButton.setAttribute('disabled', ''); + } + } + + resetForm() { + this.newBranchField.value = ''; + this.enableBranchCreateButtonWrapper(); + } + + createBranch(e) { + e.preventDefault(); + + if (this.newBranchCreateButton.getAttribute('disabled') === '') { + return; + } + const newBranchName = this.newBranchField.value; + this.targetBranchDropdown.setNewBranch(newBranchName); + this.resetForm(); + } +} + +window.gl = window.gl || {}; +gl.CreateBranchDropdown = CreateBranchDropdown; diff --git a/app/assets/javascripts/blob/target_branch_dropdown.js b/app/assets/javascripts/blob/target_branch_dropdown.js new file mode 100644 index 00000000000..216f069ef71 --- /dev/null +++ b/app/assets/javascripts/blob/target_branch_dropdown.js @@ -0,0 +1,152 @@ +/* eslint-disable class-methods-use-this */ +const SELECT_ITEM_MSG = 'Select'; + +class TargetBranchDropDown { + constructor(dropdown) { + this.dropdown = dropdown; + this.$dropdown = $(dropdown); + this.fieldName = this.dropdown.getAttribute('data-field-name'); + this.form = this.dropdown.closest('form'); + this.createDropdown(); + } + + static bootstrap() { + const dropdowns = document.querySelectorAll('.js-project-branches-dropdown'); + [].forEach.call(dropdowns, dropdown => new TargetBranchDropDown(dropdown)); + } + + createDropdown() { + const self = this; + this.$dropdown.glDropdown({ + selectable: true, + filterable: true, + search: { + fields: ['title'], + }, + data: (term, callback) => $.ajax({ + url: self.dropdown.getAttribute('data-refs-url'), + data: { + ref: self.dropdown.getAttribute('data-ref'), + show_all: true, + }, + dataType: 'json', + }).done(refs => callback(self.dropdownData(refs))), + toggleLabel(item, el) { + if (el.is('.is-active')) { + return item.text; + } + return SELECT_ITEM_MSG; + }, + clicked(item, el, e) { + e.preventDefault(); + self.onClick.call(self); + }, + fieldName: self.fieldName, + }); + return new gl.CreateBranchDropdown(this.form.querySelector('.dropdown-new-branch'), this); + } + + onClick() { + this.enableSubmit(); + this.$dropdown.trigger('change.branch'); + } + + enableSubmit() { + const submitBtn = this.form.querySelector('[type="submit"]'); + if (this.branchInput && this.branchInput.value) { + submitBtn.removeAttribute('disabled'); + } else { + submitBtn.setAttribute('disabled', ''); + } + } + + dropdownData(refs) { + const branchList = this.dropdownItems(refs); + this.cachedRefs = refs; + this.addDefaultBranch(branchList); + this.addNewBranch(branchList); + return { Branches: branchList }; + } + + dropdownItems(refs) { + return refs.map(this.dropdownItem); + } + + dropdownItem(ref) { + return { id: ref, text: ref, title: ref }; + } + + addDefaultBranch(branchList) { + // when no branch is selected do nothing + if (!this.branchInput) { + return; + } + + const branchInputVal = this.branchInput.value; + const currentBranchIndex = this.searchBranch(branchList, branchInputVal); + + if (currentBranchIndex === -1) { + this.unshiftBranch(branchList, this.dropdownItem(branchInputVal)); + } + } + + addNewBranch(branchList) { + if (this.newBranch) { + this.unshiftBranch(branchList, this.newBranch); + } + } + + searchBranch(branchList, branchName) { + return _.findIndex(branchList, el => branchName === el.id); + } + + unshiftBranch(branchList, branch) { + const branchIndex = this.searchBranch(branchList, branch.id); + + if (branchIndex === -1) { + branchList.unshift(branch); + } + } + + setNewBranch(newBranchName) { + this.newBranch = this.dropdownItem(newBranchName); + this.refreshData(); + this.selectBranch(this.searchBranch(this.glDropdown.fullData.Branches, newBranchName)); + } + + refreshData() { + this.glDropdown.fullData = this.dropdownData(this.cachedRefs); + this.clearFilter(); + } + + clearFilter() { + // apply an empty filter in order to refresh the data + this.glDropdown.filter.filter(''); + this.dropdown.closest('.dropdown').querySelector('.dropdown-page-one .dropdown-input-field').value = ''; + } + + selectBranch(index) { + const branch = this.dropdown.closest('.dropdown').querySelectorAll('li a')[index]; + + if (!branch.classList.contains('is-active')) { + branch.click(); + } else { + this.closeDropdown(); + } + } + + closeDropdown() { + this.dropdown.closest('.dropdown').querySelector('.dropdown-menu-close').click(); + } + + get branchInput() { + return this.form.querySelector(`input[name="${this.fieldName}"]`); + } + + get glDropdown() { + return this.$dropdown.data('glDropdown'); + } +} + +window.gl = window.gl || {}; +gl.TargetBranchDropDown = TargetBranchDropDown; |