diff options
Diffstat (limited to 'app/assets/javascripts')
70 files changed, 6086 insertions, 6325 deletions
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 34669dd13d6..a564643199c 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -1,62 +1,60 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, max-len */ -window.Admin = (function() { - function Admin() { - var modal, showBlacklistType; - $('input#user_force_random_password').on('change', function(elem) { - var elems; - elems = $('#user_password, #user_password_confirmation'); - if ($(this).attr('checked')) { - return elems.val('').attr('disabled', true); - } else { - return elems.removeAttr('disabled'); - } - }); - $('body').on('click', '.js-toggle-colors-link', function(e) { - e.preventDefault(); - return $('.js-toggle-colors-container').toggle(); - }); - $('.log-tabs a').click(function(e) { - e.preventDefault(); - return $(this).tab('show'); - }); - $('.log-bottom').click(function(e) { - var visible_log; - e.preventDefault(); - visible_log = $(".file-content:visible"); - return visible_log.animate({ - scrollTop: visible_log.find('ol').height() - }, "fast"); - }); - modal = $('.change-owner-holder'); - $('.change-owner-link').bind("click", function(e) { - e.preventDefault(); - $(this).hide(); - return modal.show(); - }); - $('.change-owner-cancel-link').bind("click", function(e) { - e.preventDefault(); - modal.hide(); - return $('.change-owner-link').show(); - }); - $('li.project_member').bind('ajax:success', function() { - return gl.utils.refreshCurrentPage(); - }); - $('li.group_member').bind('ajax:success', function() { - return gl.utils.refreshCurrentPage(); - }); - showBlacklistType = function() { - if ($("input[name='blacklist_type']:checked").val() === 'file') { - $('.blacklist-file').show(); - return $('.blacklist-raw').hide(); - } else { - $('.blacklist-file').hide(); - return $('.blacklist-raw').show(); - } - }; - $("input[name='blacklist_type']").click(showBlacklistType); - showBlacklistType(); - } +function Admin() { + var modal, showBlacklistType; + $('input#user_force_random_password').on('change', function(elem) { + var elems; + elems = $('#user_password, #user_password_confirmation'); + if ($(this).attr('checked')) { + return elems.val('').attr('disabled', true); + } else { + return elems.removeAttr('disabled'); + } + }); + $('body').on('click', '.js-toggle-colors-link', function(e) { + e.preventDefault(); + return $('.js-toggle-colors-container').toggle(); + }); + $('.log-tabs a').click(function(e) { + e.preventDefault(); + return $(this).tab('show'); + }); + $('.log-bottom').click(function(e) { + var visible_log; + e.preventDefault(); + visible_log = $(".file-content:visible"); + return visible_log.animate({ + scrollTop: visible_log.find('ol').height() + }, "fast"); + }); + modal = $('.change-owner-holder'); + $('.change-owner-link').bind("click", function(e) { + e.preventDefault(); + $(this).hide(); + return modal.show(); + }); + $('.change-owner-cancel-link').bind("click", function(e) { + e.preventDefault(); + modal.hide(); + return $('.change-owner-link').show(); + }); + $('li.project_member').bind('ajax:success', function() { + return gl.utils.refreshCurrentPage(); + }); + $('li.group_member').bind('ajax:success', function() { + return gl.utils.refreshCurrentPage(); + }); + showBlacklistType = function() { + if ($("input[name='blacklist_type']:checked").val() === 'file') { + $('.blacklist-file').show(); + return $('.blacklist-raw').hide(); + } else { + $('.blacklist-file').hide(); + return $('.blacklist-raw').show(); + } + }; + $("input[name='blacklist_type']").click(showBlacklistType); + showBlacklistType(); +} - return Admin; -})(); +window.Admin = Admin; diff --git a/app/assets/javascripts/aside.js b/app/assets/javascripts/aside.js index 88756884d16..bb45aa04ef8 100644 --- a/app/assets/javascripts/aside.js +++ b/app/assets/javascripts/aside.js @@ -1,24 +1,22 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, prefer-arrow-callback, no-var, one-var, one-var-declaration-per-line, no-else-return, max-len */ -window.Aside = (function() { - function Aside() { - $(document).off("click", "a.show-aside"); - $(document).on("click", 'a.show-aside', function(e) { - var btn, icon; - e.preventDefault(); - btn = $(e.currentTarget); - icon = btn.find('i'); - if (icon.hasClass('fa-angle-left')) { - btn.parent().find('section').hide(); - btn.parent().find('aside').fadeIn(); - return icon.removeClass('fa-angle-left').addClass('fa-angle-right'); - } else { - btn.parent().find('aside').hide(); - btn.parent().find('section').fadeIn(); - return icon.removeClass('fa-angle-right').addClass('fa-angle-left'); - } - }); - } +function Aside() { + $(document).off("click", "a.show-aside"); + $(document).on("click", 'a.show-aside', function(e) { + var btn, icon; + e.preventDefault(); + btn = $(e.currentTarget); + icon = btn.find('i'); + if (icon.hasClass('fa-angle-left')) { + btn.parent().find('section').hide(); + btn.parent().find('aside').fadeIn(); + return icon.removeClass('fa-angle-left').addClass('fa-angle-right'); + } else { + btn.parent().find('aside').hide(); + btn.parent().find('section').fadeIn(); + return icon.removeClass('fa-angle-right').addClass('fa-angle-left'); + } + }); +} - return Aside; -})(); +window.Aside = Aside; diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js index cfab6c40b34..a9fad9c64b0 100644 --- a/app/assets/javascripts/autosave.js +++ b/app/assets/javascripts/autosave.js @@ -1,55 +1,49 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */ import AccessorUtilities from './lib/utils/accessor'; -window.Autosave = (function() { - function Autosave(field, key) { - this.field = field; - this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); - - if (key.join != null) { - key = key.join("/"); - } - this.key = "autosave/" + key; - this.field.data("autosave", this); - this.restore(); - this.field.on("input", (function(_this) { - return function() { - return _this.save(); - }; - })(this)); +function Autosave(field, key) { + this.field = field; + this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); + + if (key.join != null) { + key = key.join("/"); } + this.key = "autosave/" + key; + this.field.data("autosave", this); + this.restore(); + this.field.on("input", () => this.save()); +} - Autosave.prototype.restore = function() { - var text; +Autosave.prototype.restore = function() { + var text; - if (!this.isLocalStorageAvailable) return; + if (!this.isLocalStorageAvailable) return; - text = window.localStorage.getItem(this.key); + text = window.localStorage.getItem(this.key); - if ((text != null ? text.length : void 0) > 0) { - this.field.val(text); - } - return this.field.trigger("input"); - }; + if ((text != null ? text.length : void 0) > 0) { + this.field.val(text); + } + return this.field.trigger("input"); +}; - Autosave.prototype.save = function() { - var text; - text = this.field.val(); +Autosave.prototype.save = function() { + var text; + text = this.field.val(); - if (this.isLocalStorageAvailable && (text != null ? text.length : void 0) > 0) { - return window.localStorage.setItem(this.key, text); - } + if (this.isLocalStorageAvailable && (text != null ? text.length : void 0) > 0) { + return window.localStorage.setItem(this.key, text); + } - return this.reset(); - }; + return this.reset(); +}; - Autosave.prototype.reset = function() { - if (!this.isLocalStorageAvailable) return; +Autosave.prototype.reset = function() { + if (!this.isLocalStorageAvailable) return; - return window.localStorage.removeItem(this.key); - }; + return window.localStorage.removeItem(this.key); +}; - return Autosave; -})(); +window.Autosave = Autosave; export default window.Autosave; diff --git a/app/assets/javascripts/breakpoints.js b/app/assets/javascripts/breakpoints.js index 2c1f988d987..8b28462e851 100644 --- a/app/assets/javascripts/breakpoints.js +++ b/app/assets/javascripts/breakpoints.js @@ -1,65 +1,56 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, quotes, no-shadow, prefer-arrow-callback, prefer-template, consistent-return, no-return-assign, new-parens, no-param-reassign, max-len */ -var Breakpoints = (function() { - var BreakpointInstance, instance; - - function Breakpoints() {} - - instance = null; - - BreakpointInstance = (function() { - var BREAKPOINTS; - - BREAKPOINTS = ["xs", "sm", "md", "lg"]; - - function BreakpointInstance() { - this.setup(); - } - - BreakpointInstance.prototype.setup = function() { - var allDeviceSelector, els; - allDeviceSelector = BREAKPOINTS.map(function(breakpoint) { - return ".device-" + breakpoint; - }); - if ($(allDeviceSelector.join(",")).length) { - return; - } - // Create all the elements - els = $.map(BREAKPOINTS, function(breakpoint) { - return "<div class='device-" + breakpoint + " visible-" + breakpoint + "'></div>"; - }); - return $("body").append(els.join('')); - }; - - BreakpointInstance.prototype.visibleDevice = function() { - var allDeviceSelector; - allDeviceSelector = BREAKPOINTS.map(function(breakpoint) { - return ".device-" + breakpoint; - }); - return $(allDeviceSelector.join(",")).filter(":visible"); - }; - - BreakpointInstance.prototype.getBreakpointSize = function() { - var $visibleDevice; - $visibleDevice = this.visibleDevice; - // TODO: Consider refactoring in light of turbolinks removal. - // the page refreshed via turbolinks - if (!$visibleDevice().length) { - this.setup(); - } - $visibleDevice = this.visibleDevice(); - return $visibleDevice.attr("class").split("visible-")[1]; - }; - - return BreakpointInstance; - })(); - - Breakpoints.get = function() { - return instance != null ? instance : instance = new BreakpointInstance; - }; - - return Breakpoints; -})(); +var instance, BREAKPOINTS; + +instance = null; +BREAKPOINTS = ["xs", "sm", "md", "lg"]; + +// BreakpointInstance +function BreakpointInstance() { + this.setup(); +} + +BreakpointInstance.prototype.setup = function() { + var allDeviceSelector, els; + allDeviceSelector = BREAKPOINTS.map(function(breakpoint) { + return ".device-" + breakpoint; + }); + if ($(allDeviceSelector.join(",")).length) { + return; + } + // Create all the elements + els = $.map(BREAKPOINTS, function(breakpoint) { + return "<div class='device-" + breakpoint + " visible-" + breakpoint + "'></div>"; + }); + return $("body").append(els.join('')); +}; + +BreakpointInstance.prototype.visibleDevice = function() { + var allDeviceSelector; + allDeviceSelector = BREAKPOINTS.map(function(breakpoint) { + return ".device-" + breakpoint; + }); + return $(allDeviceSelector.join(",")).filter(":visible"); +}; + +BreakpointInstance.prototype.getBreakpointSize = function() { + var $visibleDevice; + $visibleDevice = this.visibleDevice; + // TODO: Consider refactoring in light of turbolinks removal. + // the page refreshed via turbolinks + if (!$visibleDevice().length) { + this.setup(); + } + $visibleDevice = this.visibleDevice(); + return $visibleDevice.attr("class").split("visible-")[1]; +}; + +// Breakpoints +function Breakpoints() {} + +Breakpoints.get = function() { + return instance != null ? instance : instance = new BreakpointInstance; +}; $(() => { window.bp = Breakpoints.get(); }); diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 1dfa064acfd..85a967180e1 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -5,287 +5,285 @@ consistent-return, prefer-rest-params */ import _ from 'underscore'; import { bytesToKiB } from './lib/utils/number_utils'; -window.Build = (function () { - Build.timeout = null; - Build.state = null; - - function Build(options) { - this.options = options || $('.js-build-options').data(); - - this.pageUrl = this.options.pageUrl; - this.buildStatus = this.options.buildStatus; - this.state = this.options.logState; - this.buildStage = this.options.buildStage; - this.$document = $(document); - this.logBytes = 0; - this.hasBeenScrolled = false; - - this.updateDropdown = this.updateDropdown.bind(this); - this.getBuildTrace = this.getBuildTrace.bind(this); - - this.$buildTrace = $('#build-trace'); - this.$buildRefreshAnimation = $('.js-build-refresh'); - this.$truncatedInfo = $('.js-truncated-info'); - this.$buildTraceOutput = $('.js-build-output'); - this.$topBar = $('.js-top-bar'); - - // Scroll controllers - this.$scrollTopBtn = $('.js-scroll-up'); - this.$scrollBottomBtn = $('.js-scroll-down'); - - clearTimeout(Build.timeout); - // Init breakpoint checker - this.bp = Breakpoints.get(); - - this.initSidebar(); - this.populateJobs(this.buildStage); - this.updateStageDropdownText(this.buildStage); - this.sidebarOnResize(); - - this.$document - .off('click', '.js-sidebar-build-toggle') - .on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this)); - - this.$document - .off('click', '.stage-item') - .on('click', '.stage-item', this.updateDropdown); - - // add event listeners to the scroll buttons - this.$scrollTopBtn - .off('click') - .on('click', this.scrollToTop.bind(this)); - - this.$scrollBottomBtn - .off('click') - .on('click', this.scrollToBottom.bind(this)); - - this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); - - $(window) - .off('scroll') - .on('scroll', () => { - const contentHeight = this.$buildTraceOutput.prop('scrollHeight'); - if (contentHeight > this.windowSize) { - // means the user did not scroll, the content was updated. - this.windowSize = contentHeight; - } else { - // User scrolled - this.hasBeenScrolled = true; - this.toggleScrollAnimation(false); - } +function Build(options) { + this.options = options || $('.js-build-options').data(); + + this.pageUrl = this.options.pageUrl; + this.buildStatus = this.options.buildStatus; + this.state = this.options.logState; + this.buildStage = this.options.buildStage; + this.$document = $(document); + this.logBytes = 0; + this.hasBeenScrolled = false; + + this.updateDropdown = this.updateDropdown.bind(this); + this.getBuildTrace = this.getBuildTrace.bind(this); + + this.$buildTrace = $('#build-trace'); + this.$buildRefreshAnimation = $('.js-build-refresh'); + this.$truncatedInfo = $('.js-truncated-info'); + this.$buildTraceOutput = $('.js-build-output'); + this.$topBar = $('.js-top-bar'); + + // Scroll controllers + this.$scrollTopBtn = $('.js-scroll-up'); + this.$scrollBottomBtn = $('.js-scroll-down'); + + clearTimeout(Build.timeout); + // Init breakpoint checker + this.bp = Breakpoints.get(); + + this.initSidebar(); + this.populateJobs(this.buildStage); + this.updateStageDropdownText(this.buildStage); + this.sidebarOnResize(); + + this.$document + .off('click', '.js-sidebar-build-toggle') + .on('click', '.js-sidebar-build-toggle', this.sidebarOnClick.bind(this)); + + this.$document + .off('click', '.stage-item') + .on('click', '.stage-item', this.updateDropdown); + + // add event listeners to the scroll buttons + this.$scrollTopBtn + .off('click') + .on('click', this.scrollToTop.bind(this)); + + this.$scrollBottomBtn + .off('click') + .on('click', this.scrollToBottom.bind(this)); + + this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100); + + $(window) + .off('scroll') + .on('scroll', () => { + const contentHeight = this.$buildTraceOutput.prop('scrollHeight'); + if (contentHeight > this.windowSize) { + // means the user did not scroll, the content was updated. + this.windowSize = contentHeight; + } else { + // User scrolled + this.hasBeenScrolled = true; + this.toggleScrollAnimation(false); + } - this.scrollThrottled(); - }); + this.scrollThrottled(); + }); - $(window) - .off('resize.build') - .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); + $(window) + .off('resize.build') + .on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100)); - this.updateArtifactRemoveDate(); - this.initAffixTopArea(); + this.updateArtifactRemoveDate(); + this.initAffixTopArea(); - this.getBuildTrace(); - } + this.getBuildTrace(); +} - Build.prototype.initAffixTopArea = function () { - /** - If the browser does not support position sticky, it returns the position as static. - If the browser does support sticky, then we allow the browser to handle it, if not - then we default back to Bootstraps affix - **/ - if (this.$topBar.css('position') !== 'static') return; +Build.timeout = null; +Build.state = null; - const offsetTop = this.$buildTrace.offset().top; +Build.prototype.initAffixTopArea = function () { + /** + If the browser does not support position sticky, it returns the position as static. + If the browser does support sticky, then we allow the browser to handle it, if not + then we default back to Bootstraps affix + **/ + if (this.$topBar.css('position') !== 'static') return; - this.$topBar.affix({ - offset: { - top: offsetTop, - }, - }); - }; + const offsetTop = this.$buildTrace.offset().top; - Build.prototype.canScroll = function () { - return document.body.scrollHeight > window.innerHeight; - }; + this.$topBar.affix({ + offset: { + top: offsetTop, + }, + }); +}; - Build.prototype.toggleScroll = function () { - const currentPosition = document.body.scrollTop; - const windowHeight = window.innerHeight; +Build.prototype.canScroll = function () { + return document.body.scrollHeight > window.innerHeight; +}; - if (this.canScroll()) { - if (currentPosition > 0 && - (document.body.scrollHeight - currentPosition !== windowHeight)) { - // User is in the middle of the log +Build.prototype.toggleScroll = function () { + const currentPosition = document.body.scrollTop; + const windowHeight = window.innerHeight; - this.toggleDisableButton(this.$scrollTopBtn, false); - this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (currentPosition === 0) { - // User is at Top of Build Log + if (this.canScroll()) { + if (currentPosition > 0 && + (document.body.scrollHeight - currentPosition !== windowHeight)) { + // User is in the middle of the log - this.toggleDisableButton(this.$scrollTopBtn, true); - this.toggleDisableButton(this.$scrollBottomBtn, false); - } else if (document.body.scrollHeight - currentPosition === windowHeight) { - // User is at the bottom of the build log. + this.toggleDisableButton(this.$scrollTopBtn, false); + this.toggleDisableButton(this.$scrollBottomBtn, false); + } else if (currentPosition === 0) { + // User is at Top of Build Log - this.toggleDisableButton(this.$scrollTopBtn, false); - this.toggleDisableButton(this.$scrollBottomBtn, true); - } - } else { this.toggleDisableButton(this.$scrollTopBtn, true); + this.toggleDisableButton(this.$scrollBottomBtn, false); + } else if (document.body.scrollHeight - currentPosition === windowHeight) { + // User is at the bottom of the build log. + + this.toggleDisableButton(this.$scrollTopBtn, false); this.toggleDisableButton(this.$scrollBottomBtn, true); } - }; - - Build.prototype.scrollDown = function () { - document.body.scrollTop = document.body.scrollHeight; - }; - - Build.prototype.scrollToBottom = function () { - this.scrollDown(); - this.hasBeenScrolled = true; - this.toggleScroll(); - }; - - Build.prototype.scrollToTop = function () { - document.body.scrollTop = 0; - this.hasBeenScrolled = true; - this.toggleScroll(); - }; - - Build.prototype.toggleDisableButton = function ($button, disable) { - if (disable && $button.prop('disabled')) return; - $button.prop('disabled', disable); - }; - - Build.prototype.toggleScrollAnimation = function (toggle) { - this.$scrollBottomBtn.toggleClass('animate', toggle); - }; - - Build.prototype.initSidebar = function () { - this.$sidebar = $('.js-build-sidebar'); - this.$sidebar.niceScroll(); - }; - - Build.prototype.getBuildTrace = function () { - return $.ajax({ - url: `${this.pageUrl}/trace.json`, - data: this.state, - }) - .done((log) => { - gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`); - - if (log.state) { - this.state = log.state; - } - - this.windowSize = this.$buildTraceOutput.prop('scrollHeight'); + } else { + this.toggleDisableButton(this.$scrollTopBtn, true); + this.toggleDisableButton(this.$scrollBottomBtn, true); + } +}; + +Build.prototype.scrollDown = function () { + document.body.scrollTop = document.body.scrollHeight; +}; + +Build.prototype.scrollToBottom = function () { + this.scrollDown(); + this.hasBeenScrolled = true; + this.toggleScroll(); +}; + +Build.prototype.scrollToTop = function () { + document.body.scrollTop = 0; + this.hasBeenScrolled = true; + this.toggleScroll(); +}; + +Build.prototype.toggleDisableButton = function ($button, disable) { + if (disable && $button.prop('disabled')) return; + $button.prop('disabled', disable); +}; + +Build.prototype.toggleScrollAnimation = function (toggle) { + this.$scrollBottomBtn.toggleClass('animate', toggle); +}; + +Build.prototype.initSidebar = function () { + this.$sidebar = $('.js-build-sidebar'); + this.$sidebar.niceScroll(); +}; + +Build.prototype.getBuildTrace = function () { + return $.ajax({ + url: `${this.pageUrl}/trace.json`, + data: this.state, + }) + .done((log) => { + gl.utils.setCiStatusFavicon(`${this.pageUrl}/status.json`); + + if (log.state) { + this.state = log.state; + } - if (log.append) { - this.$buildTraceOutput.append(log.html); - this.logBytes += log.size; - } else { - this.$buildTraceOutput.html(log.html); - this.logBytes = log.size; - } + this.windowSize = this.$buildTraceOutput.prop('scrollHeight'); - // if the incremental sum of logBytes we received is less than the total - // we need to show a message warning the user about that. - if (this.logBytes < log.total) { - // size is in bytes, we need to calculate KiB - const size = bytesToKiB(this.logBytes); - $('.js-truncated-info-size').html(`${size}`); - this.$truncatedInfo.removeClass('hidden'); - } else { - this.$truncatedInfo.addClass('hidden'); - } + if (log.append) { + this.$buildTraceOutput.append(log.html); + this.logBytes += log.size; + } else { + this.$buildTraceOutput.html(log.html); + this.logBytes = log.size; + } - if (!log.complete) { - if (!this.hasBeenScrolled) { - this.toggleScrollAnimation(true); - } else { - this.toggleScrollAnimation(false); - } + // if the incremental sum of logBytes we received is less than the total + // we need to show a message warning the user about that. + if (this.logBytes < log.total) { + // size is in bytes, we need to calculate KiB + const size = bytesToKiB(this.logBytes); + $('.js-truncated-info-size').html(`${size}`); + this.$truncatedInfo.removeClass('hidden'); + } else { + this.$truncatedInfo.addClass('hidden'); + } - Build.timeout = setTimeout(() => { - this.getBuildTrace(); - }, 4000); + if (!log.complete) { + if (!this.hasBeenScrolled) { + this.toggleScrollAnimation(true); } else { - this.$buildRefreshAnimation.remove(); this.toggleScrollAnimation(false); } - if (log.status !== this.buildStatus) { - gl.utils.visitUrl(this.pageUrl); - } - }) - .fail(() => { + Build.timeout = setTimeout(() => { + this.getBuildTrace(); + }, 4000); + } else { this.$buildRefreshAnimation.remove(); - }) - .then(() => { - if (!this.hasBeenScrolled) { - this.scrollDown(); - } - }) - .then(() => this.toggleScroll()); - }; - - Build.prototype.shouldHideSidebarForViewport = function () { - const bootstrapBreakpoint = this.bp.getBreakpointSize(); - return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; - }; - - Build.prototype.toggleSidebar = function (shouldHide) { - const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; - const $toggleButton = $('.js-sidebar-build-toggle-header'); - - this.$sidebar - .toggleClass('right-sidebar-expanded', shouldShow) - .toggleClass('right-sidebar-collapsed', shouldHide); - - this.$topBar - .toggleClass('sidebar-expanded', shouldShow) - .toggleClass('sidebar-collapsed', shouldHide); - - if (this.$sidebar.hasClass('right-sidebar-expanded')) { - $toggleButton.addClass('hidden'); - } else { - $toggleButton.removeClass('hidden'); - } - }; - - Build.prototype.sidebarOnResize = function () { - this.toggleSidebar(this.shouldHideSidebarForViewport()); - }; - - Build.prototype.sidebarOnClick = function () { - if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); - }; - - Build.prototype.updateArtifactRemoveDate = function () { - const $date = $('.js-artifacts-remove'); - if ($date.length) { - const date = $date.text(); - return $date.text( - gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '), - ); - } - }; - - Build.prototype.populateJobs = function (stage) { - $('.build-job').hide(); - $(`.build-job[data-stage="${stage}"]`).show(); - }; - - Build.prototype.updateStageDropdownText = function (stage) { - $('.stage-selection').text(stage); - }; - - Build.prototype.updateDropdown = function (e) { - e.preventDefault(); - const stage = e.currentTarget.text; - this.updateStageDropdownText(stage); - this.populateJobs(stage); - }; - - return Build; -})(); + this.toggleScrollAnimation(false); + } + + if (log.status !== this.buildStatus) { + gl.utils.visitUrl(this.pageUrl); + } + }) + .fail(() => { + this.$buildRefreshAnimation.remove(); + }) + .then(() => { + if (!this.hasBeenScrolled) { + this.scrollDown(); + } + }) + .then(() => this.toggleScroll()); +}; + +Build.prototype.shouldHideSidebarForViewport = function () { + const bootstrapBreakpoint = this.bp.getBreakpointSize(); + return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; +}; + +Build.prototype.toggleSidebar = function (shouldHide) { + const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; + const $toggleButton = $('.js-sidebar-build-toggle-header'); + + this.$sidebar + .toggleClass('right-sidebar-expanded', shouldShow) + .toggleClass('right-sidebar-collapsed', shouldHide); + + this.$topBar + .toggleClass('sidebar-expanded', shouldShow) + .toggleClass('sidebar-collapsed', shouldHide); + + if (this.$sidebar.hasClass('right-sidebar-expanded')) { + $toggleButton.addClass('hidden'); + } else { + $toggleButton.removeClass('hidden'); + } +}; + +Build.prototype.sidebarOnResize = function () { + this.toggleSidebar(this.shouldHideSidebarForViewport()); +}; + +Build.prototype.sidebarOnClick = function () { + if (this.shouldHideSidebarForViewport()) this.toggleSidebar(); +}; + +Build.prototype.updateArtifactRemoveDate = function () { + const $date = $('.js-artifacts-remove'); + if ($date.length) { + const date = $date.text(); + return $date.text( + gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '), + ); + } +}; + +Build.prototype.populateJobs = function (stage) { + $('.build-job').hide(); + $(`.build-job[data-stage="${stage}"]`).show(); +}; + +Build.prototype.updateStageDropdownText = function (stage) { + $('.stage-selection').text(stage); +}; + +Build.prototype.updateDropdown = function (e) { + e.preventDefault(); + const stage = e.currentTarget.text; + this.updateStageDropdownText(stage); + this.populateJobs(stage); +}; + +window.Build = Build; diff --git a/app/assets/javascripts/build_artifacts.js b/app/assets/javascripts/build_artifacts.js index bd479700fd3..ed9ad3c6c57 100644 --- a/app/assets/javascripts/build_artifacts.js +++ b/app/assets/javascripts/build_artifacts.js @@ -1,25 +1,23 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, no-return-assign, max-len */ -window.BuildArtifacts = (function() { - function BuildArtifacts() { - this.disablePropagation(); - this.setupEntryClick(); - } +function BuildArtifacts() { + this.disablePropagation(); + this.setupEntryClick(); +} - BuildArtifacts.prototype.disablePropagation = function() { - $('.top-block').on('click', '.download', function(e) { - return e.stopPropagation(); - }); - return $('.tree-holder').on('click', 'tr[data-link] a', function(e) { - return e.stopImmediatePropagation(); - }); - }; +BuildArtifacts.prototype.disablePropagation = function() { + $('.top-block').on('click', '.download', function(e) { + return e.stopPropagation(); + }); + return $('.tree-holder').on('click', 'tr[data-link] a', function(e) { + return e.stopImmediatePropagation(); + }); +}; - BuildArtifacts.prototype.setupEntryClick = function() { - return $('.tree-holder').on('click', 'tr[data-link]', function(e) { - return window.location = this.dataset.link; - }); - }; +BuildArtifacts.prototype.setupEntryClick = function() { + return $('.tree-holder').on('click', 'tr[data-link]', function(e) { + return window.location = this.dataset.link; + }); +}; - return BuildArtifacts; -})(); +window.BuildArtifacts = BuildArtifacts; diff --git a/app/assets/javascripts/commit.js b/app/assets/javascripts/commit.js index 5f637524e30..e3f8355915a 100644 --- a/app/assets/javascripts/commit.js +++ b/app/assets/javascripts/commit.js @@ -1,12 +1,10 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife */ /* global CommitFile */ -window.Commit = (function() { - function Commit() { - $('.files .diff-file').each(function() { - return new CommitFile(this); - }); - } +function Commit() { + $('.files .diff-file').each(function() { + return new CommitFile(this); + }); +} - return Commit; -})(); +window.Commit = Commit; diff --git a/app/assets/javascripts/commit/file.js b/app/assets/javascripts/commit/file.js index ee087c978dd..28e5e06b155 100644 --- a/app/assets/javascripts/commit/file.js +++ b/app/assets/javascripts/commit/file.js @@ -1,14 +1,10 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new */ /* global ImageFile */ -(function() { - this.CommitFile = (function() { - function CommitFile(file) { - if ($('.image', file).length) { - new gl.ImageFile(file); - } - } +function CommitFile(file) { + if ($('.image', file).length) { + new gl.ImageFile(file); + } +} - return CommitFile; - })(); -}).call(window); +window.CommitFile = CommitFile; diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js index 17d14dc1e79..b768ba5b17b 100644 --- a/app/assets/javascripts/commit/image_file.js +++ b/app/assets/javascripts/commit/image_file.js @@ -1,211 +1,209 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-use-before-define, prefer-arrow-callback, no-else-return, consistent-return, prefer-template, quotes, one-var, one-var-declaration-per-line, no-unused-vars, no-return-assign, comma-dangle, quote-props, no-unused-expressions, no-sequences, object-shorthand, max-len */ -(function() { - gl.ImageFile = (function() { - var prepareFrames; - - // Width where images must fits in, for 2-up this gets divided by 2 - ImageFile.availWidth = 900; - - ImageFile.viewModes = ['two-up', 'swipe']; - - function ImageFile(file) { - this.file = file; - this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { - // Determine if old and new file has same dimensions, if not show 'two-up' view - return function(deletedWidth, deletedHeight) { - return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { - if (width === deletedWidth && height === deletedHeight) { - return _this.initViewModes(); - } else { - return _this.initView('two-up'); - } - }); - }; - })(this)); - } - - ImageFile.prototype.initViewModes = function() { - var viewMode; - viewMode = ImageFile.viewModes[0]; - $('.view-modes', this.file).removeClass('hide'); - $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { - return function(event) { - if (!$(event.currentTarget).hasClass('active')) { - return _this.activateViewMode(event.currentTarget.className); - } - }; - })(this)); - return this.activateViewMode(viewMode); - }; - - ImageFile.prototype.activateViewMode = function(viewMode) { - $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); - return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { - return function() { - $(".view." + viewMode, _this.file).fadeIn(200); - return _this.initView(viewMode); - }; - })(this)); - }; - - ImageFile.prototype.initView = function(viewMode) { - return this.views[viewMode].call(this); - }; - - ImageFile.prototype.initDraggable = function($el, padding, callback) { - var dragging = false; - var $body = $('body'); - var $offsetEl = $el.parent(); - - $el.off('mousedown').on('mousedown', function() { - dragging = true; - $body.css('user-select', 'none'); - }); - - $body.off('mouseup').off('mousemove').on('mouseup', function() { - dragging = false; - $body.css('user-select', ''); - }) - .on('mousemove', function(e) { - var left; - if (!dragging) return; - - left = e.pageX - ($offsetEl.offset().left + padding); - - callback(e, left); - }); - }; - - prepareFrames = function(view) { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - $('.frame', view).each((function(_this) { - return function(index, frame) { - var height, width; - width = $(frame).width(); - height = $(frame).height(); - maxWidth = width > maxWidth ? width : maxWidth; - return maxHeight = height > maxHeight ? height : maxHeight; - }; - })(this)).css({ - width: maxWidth, - height: maxHeight +var prepareFrames; + +const global = window.gl || (window.gl = {}); + +function ImageFile(file) { + this.file = file; + this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { + // Determine if old and new file has same dimensions, if not show 'two-up' view + return function(deletedWidth, deletedHeight) { + return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { + if (width === deletedWidth && height === deletedHeight) { + return _this.initViewModes(); + } else { + return _this.initView('two-up'); + } }); - return [maxWidth, maxHeight]; }; - - ImageFile.prototype.views = { - 'two-up': function() { - return $('.two-up.view .wrap', this.file).each((function(_this) { - return function(index, wrap) { - $('img', wrap).each(function() { - var currentWidth; - currentWidth = $(this).width(); - if (currentWidth > ImageFile.availWidth / 2) { - return $(this).width(ImageFile.availWidth / 2); - } - }); - return _this.requestImageInfo($('img', wrap), function(width, height) { - $('.image-info .meta-width', wrap).text(width + "px"); - $('.image-info .meta-height', wrap).text(height + "px"); - return $('.image-info', wrap).removeClass('hide'); - }); - }; - })(this)); - }, - 'swipe': function() { - var maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - return $('.swipe.view', this.file).each((function(_this) { - return function(index, view) { - var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $swipeFrame = $('.swipe-frame', view); - $swipeWrap = $('.swipe-wrap', view); - $swipeBar = $('.swipe-bar', view); - - $swipeFrame.css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $swipeWrap.css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - $swipeBar.css({ - left: 0 - }); - - wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10); - - _this.initDraggable($swipeBar, wrapPadding, function(e, left) { - if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) { - $swipeWrap.width((maxWidth + 1) - left); - $swipeBar.css('left', left); - } - }); - }; - })(this)); - }, - 'onion-skin': function() { - var dragTrackWidth, maxHeight, maxWidth; - maxWidth = 0; - maxHeight = 0; - dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); - return $('.onion-skin.view', this.file).each((function(_this) { - return function(index, view) { - var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false; - ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; - $frame = $('.onion-skin-frame', view); - $frameAdded = $('.frame.added', view); - $track = $('.drag-track', view); - $dragger = $('.dragger', $track); - - $frame.css({ - width: maxWidth + 16, - height: maxHeight + 28 - }); - $('.swipe-wrap', view).css({ - width: maxWidth + 1, - height: maxHeight + 2 - }); - $dragger.css({ - left: dragTrackWidth - }); - - framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); - - _this.initDraggable($dragger, framePadding, function(e, left) { - var opacity = left / dragTrackWidth; - - if (opacity >= 0 && opacity <= 1) { - $dragger.css('left', left); - $frameAdded.css('opacity', opacity); - } - }); - }; - })(this)); + })(this)); +} + +// Width where images must fits in, for 2-up this gets divided by 2 +ImageFile.availWidth = 900; + +ImageFile.viewModes = ['two-up', 'swipe']; + +ImageFile.prototype.initViewModes = function() { + var viewMode; + viewMode = ImageFile.viewModes[0]; + $('.view-modes', this.file).removeClass('hide'); + $('.view-modes-menu', this.file).on('click', 'li', (function(_this) { + return function(event) { + if (!$(event.currentTarget).hasClass('active')) { + return _this.activateViewMode(event.currentTarget.className); } }; - - ImageFile.prototype.requestImageInfo = function(img, callback) { - var domImg; - domImg = img.get(0); - if (domImg) { - if (domImg.complete) { - return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); - } else { - return img.on('load', (function(_this) { - return function() { - return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); - }; - })(this)); - } - } + })(this)); + return this.activateViewMode(viewMode); +}; + +ImageFile.prototype.activateViewMode = function(viewMode) { + $('.view-modes-menu li', this.file).removeClass('active').filter("." + viewMode).addClass('active'); + return $(".view:visible:not(." + viewMode + ")", this.file).fadeOut(200, (function(_this) { + return function() { + $(".view." + viewMode, _this.file).fadeIn(200); + return _this.initView(viewMode); + }; + })(this)); +}; + +ImageFile.prototype.initView = function(viewMode) { + return this.views[viewMode].call(this); +}; + +ImageFile.prototype.initDraggable = function($el, padding, callback) { + var dragging = false; + var $body = $('body'); + var $offsetEl = $el.parent(); + + $el.off('mousedown').on('mousedown', function() { + dragging = true; + $body.css('user-select', 'none'); + }); + + $body.off('mouseup').off('mousemove').on('mouseup', function() { + dragging = false; + $body.css('user-select', ''); + }) + .on('mousemove', function(e) { + var left; + if (!dragging) return; + + left = e.pageX - ($offsetEl.offset().left + padding); + + callback(e, left); + }); +}; + +prepareFrames = function(view) { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + $('.frame', view).each((function(_this) { + return function(index, frame) { + var height, width; + width = $(frame).width(); + height = $(frame).height(); + maxWidth = width > maxWidth ? width : maxWidth; + return maxHeight = height > maxHeight ? height : maxHeight; }; + })(this)).css({ + width: maxWidth, + height: maxHeight + }); + return [maxWidth, maxHeight]; +}; + +ImageFile.prototype.views = { + 'two-up': function() { + return $('.two-up.view .wrap', this.file).each((function(_this) { + return function(index, wrap) { + $('img', wrap).each(function() { + var currentWidth; + currentWidth = $(this).width(); + if (currentWidth > ImageFile.availWidth / 2) { + return $(this).width(ImageFile.availWidth / 2); + } + }); + return _this.requestImageInfo($('img', wrap), function(width, height) { + $('.image-info .meta-width', wrap).text(width + "px"); + $('.image-info .meta-height', wrap).text(height + "px"); + return $('.image-info', wrap).removeClass('hide'); + }); + }; + })(this)); + }, + 'swipe': function() { + var maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + return $('.swipe.view', this.file).each((function(_this) { + return function(index, view) { + var $swipeWrap, $swipeBar, $swipeFrame, wrapPadding, ref; + ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $swipeFrame = $('.swipe-frame', view); + $swipeWrap = $('.swipe-wrap', view); + $swipeBar = $('.swipe-bar', view); + + $swipeFrame.css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $swipeWrap.css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + $swipeBar.css({ + left: 0 + }); + + wrapPadding = parseInt($swipeWrap.css('right').replace('px', ''), 10); + + _this.initDraggable($swipeBar, wrapPadding, function(e, left) { + if (left > 0 && left < $swipeFrame.width() - (wrapPadding * 2)) { + $swipeWrap.width((maxWidth + 1) - left); + $swipeBar.css('left', left); + } + }); + }; + })(this)); + }, + 'onion-skin': function() { + var dragTrackWidth, maxHeight, maxWidth; + maxWidth = 0; + maxHeight = 0; + dragTrackWidth = $('.drag-track', this.file).width() - $('.dragger', this.file).width(); + return $('.onion-skin.view', this.file).each((function(_this) { + return function(index, view) { + var $frame, $track, $dragger, $frameAdded, framePadding, ref, dragging = false; + ref = prepareFrames(view), maxWidth = ref[0], maxHeight = ref[1]; + $frame = $('.onion-skin-frame', view); + $frameAdded = $('.frame.added', view); + $track = $('.drag-track', view); + $dragger = $('.dragger', $track); + + $frame.css({ + width: maxWidth + 16, + height: maxHeight + 28 + }); + $('.swipe-wrap', view).css({ + width: maxWidth + 1, + height: maxHeight + 2 + }); + $dragger.css({ + left: dragTrackWidth + }); + + framePadding = parseInt($frameAdded.css('right').replace('px', ''), 10); + + _this.initDraggable($dragger, framePadding, function(e, left) { + var opacity = left / dragTrackWidth; + + if (opacity >= 0 && opacity <= 1) { + $dragger.css('left', left); + $frameAdded.css('opacity', opacity); + } + }); + }; + })(this)); + } +}; + +ImageFile.prototype.requestImageInfo = function(img, callback) { + var domImg; + domImg = img.get(0); + if (domImg) { + if (domImg.complete) { + return callback.call(this, domImg.naturalWidth, domImg.naturalHeight); + } else { + return img.on('load', (function(_this) { + return function() { + return callback.call(_this, domImg.naturalWidth, domImg.naturalHeight); + }; + })(this)); + } + } +}; - return ImageFile; - })(); -}).call(window); +global.ImageFile = ImageFile; diff --git a/app/assets/javascripts/commits.js b/app/assets/javascripts/commits.js index 2b0bf49cf92..b7db5ded846 100644 --- a/app/assets/javascripts/commits.js +++ b/app/assets/javascripts/commits.js @@ -1,97 +1,93 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, consistent-return, no-return-assign, no-param-reassign, one-var, no-var, one-var-declaration-per-line, no-unused-vars, prefer-template, object-shorthand, comma-dangle, max-len, prefer-arrow-callback */ /* global Pager */ -window.CommitsList = (function() { - var CommitsList = {}; +var CommitsList = {}; - CommitsList.timer = null; +CommitsList.timer = null; - CommitsList.init = function(limit) { - this.$contentList = $('.content_list'); +CommitsList.init = function(limit) { + this.$contentList = $('.content_list'); - $("body").on("click", ".day-commits-table li.commit", function(e) { - if (e.target.nodeName !== "A") { - location.href = $(this).attr("url"); - e.stopPropagation(); - return false; - } - }); + $("body").on("click", ".day-commits-table li.commit", function(e) { + if (e.target.nodeName !== "A") { + location.href = $(this).attr("url"); + e.stopPropagation(); + return false; + } + }); - Pager.init(limit, false, false, this.processCommits); + Pager.init(limit, false, false, this.processCommits); - this.content = $("#commits-list"); - this.searchField = $("#commits-search"); - this.lastSearch = this.searchField.val(); - return this.initSearch(); - }; + this.content = $("#commits-list"); + this.searchField = $("#commits-search"); + this.lastSearch = this.searchField.val(); + return this.initSearch(); +}; - CommitsList.initSearch = function() { - this.timer = null; - return this.searchField.keyup((function(_this) { - return function() { - clearTimeout(_this.timer); - return _this.timer = setTimeout(_this.filterResults, 500); - }; - })(this)); - }; +CommitsList.initSearch = function() { + this.timer = null; + return this.searchField.keyup(() => { + clearTimeout(this.timer); + return this.timer = setTimeout(this.filterResults, 500); + }); +}; - CommitsList.filterResults = function() { - var commitsUrl, form, search; - form = $(".commits-search-form"); - search = CommitsList.searchField.val(); - if (search === CommitsList.lastSearch) return; - commitsUrl = form.attr("action") + '?' + form.serialize(); - CommitsList.content.fadeTo('fast', 0.5); - return $.ajax({ - type: "GET", - url: form.attr("action"), - data: form.serialize(), - complete: function() { - return CommitsList.content.fadeTo('fast', 1.0); - }, - success: function(data) { - CommitsList.lastSearch = search; - CommitsList.content.html(data.html); - return history.replaceState({ - page: commitsUrl - // Change url so if user reload a page - search results are saved - }, document.title, commitsUrl); - }, - error: function() { - CommitsList.lastSearch = null; - }, - dataType: "json" - }); - }; +CommitsList.filterResults = function() { + var commitsUrl, form, search; + form = $(".commits-search-form"); + search = CommitsList.searchField.val(); + if (search === CommitsList.lastSearch) return; + commitsUrl = form.attr("action") + '?' + form.serialize(); + CommitsList.content.fadeTo('fast', 0.5); + return $.ajax({ + type: "GET", + url: form.attr("action"), + data: form.serialize(), + complete: function() { + return CommitsList.content.fadeTo('fast', 1.0); + }, + success: function(data) { + CommitsList.lastSearch = search; + CommitsList.content.html(data.html); + return history.replaceState({ + page: commitsUrl + // Change url so if user reload a page - search results are saved + }, document.title, commitsUrl); + }, + error: function() { + CommitsList.lastSearch = null; + }, + dataType: "json" + }); +}; - // Prepare loaded data. - CommitsList.processCommits = (data) => { - let processedData = data; - const $processedData = $(processedData); - const $commitsHeadersLast = CommitsList.$contentList.find('li.js-commit-header').last(); - const lastShownDay = $commitsHeadersLast.data('day'); - const $loadedCommitsHeadersFirst = $processedData.filter('li.js-commit-header').first(); - const loadedShownDayFirst = $loadedCommitsHeadersFirst.data('day'); - let commitsCount; +// Prepare loaded data. +CommitsList.processCommits = (data) => { + let processedData = data; + const $processedData = $(processedData); + const $commitsHeadersLast = CommitsList.$contentList.find('li.js-commit-header').last(); + const lastShownDay = $commitsHeadersLast.data('day'); + const $loadedCommitsHeadersFirst = $processedData.filter('li.js-commit-header').first(); + const loadedShownDayFirst = $loadedCommitsHeadersFirst.data('day'); + let commitsCount; - // If commits headers show the same date, - // remove the last header and change the previous one. - if (lastShownDay === loadedShownDayFirst) { - // Last shown commits count under the last commits header. - commitsCount = $commitsHeadersLast.nextUntil('li.js-commit-header').find('li.commit').length; + // If commits headers show the same date, + // remove the last header and change the previous one. + if (lastShownDay === loadedShownDayFirst) { + // Last shown commits count under the last commits header. + commitsCount = $commitsHeadersLast.nextUntil('li.js-commit-header').find('li.commit').length; - // Remove duplicate of commits header. - processedData = $processedData.not(`li.js-commit-header[data-day="${loadedShownDayFirst}"]`); + // Remove duplicate of commits header. + processedData = $processedData.not(`li.js-commit-header[data-day="${loadedShownDayFirst}"]`); - // Update commits count in the previous commits header. - commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length); - $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${gl.text.pluralize('commit', commitsCount)}`); - } + // Update commits count in the previous commits header. + commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length); + $commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${gl.text.pluralize('commit', commitsCount)}`); + } - gl.utils.localTimeAgo($processedData.find('.js-timeago')); + gl.utils.localTimeAgo($processedData.find('.js-timeago')); - return processedData; - }; + return processedData; +}; - return CommitsList; -})(); +window.CommitsList = CommitsList; diff --git a/app/assets/javascripts/compare.js b/app/assets/javascripts/compare.js index 9e5dbd64a7e..e5321ef9cc6 100644 --- a/app/assets/javascripts/compare.js +++ b/app/assets/javascripts/compare.js @@ -1,90 +1,86 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, object-shorthand, consistent-return, no-unused-vars, comma-dangle, vars-on-top, prefer-template, max-len */ -window.Compare = (function() { - function Compare(opts) { - this.opts = opts; - this.source_loading = $(".js-source-loading"); - this.target_loading = $(".js-target-loading"); - $('.js-compare-dropdown').each((function(_this) { - return function(i, dropdown) { - var $dropdown; - $dropdown = $(dropdown); - return $dropdown.glDropdown({ - selectable: true, - fieldName: $dropdown.data('field-name'), - filterable: true, - id: function(obj, $el) { - return $el.data('id'); - }, - toggleLabel: function(obj, $el) { - return $el.text().trim(); - }, - clicked: function(e, el) { - if ($dropdown.is('.js-target-branch')) { - return _this.getTargetHtml(); - } else if ($dropdown.is('.js-source-branch')) { - return _this.getSourceHtml(); - } else if ($dropdown.is('.js-target-project')) { - return _this.getTargetProject(); - } - } - }); - }; - })(this)); - this.initialState(); - } - - Compare.prototype.initialState = function() { - this.getSourceHtml(); - return this.getTargetHtml(); - }; - - Compare.prototype.getTargetProject = function() { - return $.ajax({ - url: this.opts.targetProjectUrl, - data: { - target_project_id: $("input[name='merge_request[target_project_id]']").val() +function Compare(opts) { + this.opts = opts; + this.source_loading = $(".js-source-loading"); + this.target_loading = $(".js-target-loading"); + $('.js-compare-dropdown').each((i, dropdown) => { + var $dropdown; + $dropdown = $(dropdown); + return $dropdown.glDropdown({ + selectable: true, + fieldName: $dropdown.data('field-name'), + filterable: true, + id: function(obj, $el) { + return $el.data('id'); }, - beforeSend: function() { - return $('.mr_target_commit').empty(); + toggleLabel: function(obj, $el) { + return $el.text().trim(); }, - success: function(html) { - return $('.js-target-branch-dropdown .dropdown-content').html(html); + clicked: function(e, el) { + if ($dropdown.is('.js-target-branch')) { + return this.getTargetHtml(); + } else if ($dropdown.is('.js-source-branch')) { + return this.getSourceHtml(); + } else if ($dropdown.is('.js-target-project')) { + return this.getTargetProject(); + } } }); - }; + }); + this.initialState(); +} - Compare.prototype.getSourceHtml = function() { - return this.sendAjax(this.opts.sourceBranchUrl, this.source_loading, '.mr_source_commit', { - ref: $("input[name='merge_request[source_branch]']").val() - }); - }; +Compare.prototype.initialState = function() { + this.getSourceHtml(); + return this.getTargetHtml(); +}; - Compare.prototype.getTargetHtml = function() { - return this.sendAjax(this.opts.targetBranchUrl, this.target_loading, '.mr_target_commit', { - target_project_id: $("input[name='merge_request[target_project_id]']").val(), - ref: $("input[name='merge_request[target_branch]']").val() - }); - }; +Compare.prototype.getTargetProject = function() { + return $.ajax({ + url: this.opts.targetProjectUrl, + data: { + target_project_id: $("input[name='merge_request[target_project_id]']").val() + }, + beforeSend: function() { + return $('.mr_target_commit').empty(); + }, + success: function(html) { + return $('.js-target-branch-dropdown .dropdown-content').html(html); + } + }); +}; - Compare.prototype.sendAjax = function(url, loading, target, data) { - var $target; - $target = $(target); - return $.ajax({ - url: url, - data: data, - beforeSend: function() { - loading.show(); - return $target.empty(); - }, - success: function(html) { - loading.hide(); - $target.html(html); - var className = '.' + $target[0].className.replace(' ', '.'); - gl.utils.localTimeAgo($('.js-timeago', className)); - } - }); - }; +Compare.prototype.getSourceHtml = function() { + return this.sendAjax(this.opts.sourceBranchUrl, this.source_loading, '.mr_source_commit', { + ref: $("input[name='merge_request[source_branch]']").val() + }); +}; + +Compare.prototype.getTargetHtml = function() { + return this.sendAjax(this.opts.targetBranchUrl, this.target_loading, '.mr_target_commit', { + target_project_id: $("input[name='merge_request[target_project_id]']").val(), + ref: $("input[name='merge_request[target_branch]']").val() + }); +}; + +Compare.prototype.sendAjax = function(url, loading, target, data) { + var $target; + $target = $(target); + return $.ajax({ + url: url, + data: data, + beforeSend: function() { + loading.show(); + return $target.empty(); + }, + success: function(html) { + loading.hide(); + $target.html(html); + var className = '.' + $target[0].className.replace(' ', '.'); + gl.utils.localTimeAgo($('.js-timeago', className)); + } + }); +}; - return Compare; -})(); +window.Compare = Compare; diff --git a/app/assets/javascripts/compare_autocomplete.js b/app/assets/javascripts/compare_autocomplete.js index 72c0d98d47c..e70f78d16a8 100644 --- a/app/assets/javascripts/compare_autocomplete.js +++ b/app/assets/javascripts/compare_autocomplete.js @@ -1,68 +1,66 @@ /* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, object-shorthand, comma-dangle, prefer-arrow-callback, no-else-return, newline-per-chained-call, wrap-iife, max-len */ -window.CompareAutocomplete = (function() { - function CompareAutocomplete() { - this.initDropdown(); - } +function CompareAutocomplete() { + this.initDropdown(); +} - CompareAutocomplete.prototype.initDropdown = function() { - return $('.js-compare-dropdown').each(function() { - var $dropdown, selected; - $dropdown = $(this); - selected = $dropdown.data('selected'); - const $dropdownContainer = $dropdown.closest('.dropdown'); - const $fieldInput = $(`input[name="${$dropdown.data('field-name')}"]`, $dropdownContainer); - const $filterInput = $('input[type="search"]', $dropdownContainer); - $dropdown.glDropdown({ - data: function(term, callback) { - return $.ajax({ - url: $dropdown.data('refs-url'), - data: { - ref: $dropdown.data('ref'), - search: term, - } - }).done(function(refs) { - return callback(refs); - }); - }, - selectable: true, - filterable: true, - filterRemote: true, - fieldName: $dropdown.data('field-name'), - filterInput: 'input[type="search"]', - renderRow: function(ref) { - var link; - if (ref.header != null) { - return $('<li />').addClass('dropdown-header').text(ref.header); - } else { - link = $('<a />').attr('href', '#').addClass(ref === selected ? 'is-active' : '').text(ref).attr('data-ref', escape(ref)); - return $('<li />').append(link); +CompareAutocomplete.prototype.initDropdown = function() { + return $('.js-compare-dropdown').each(function() { + var $dropdown, selected; + $dropdown = $(this); + selected = $dropdown.data('selected'); + const $dropdownContainer = $dropdown.closest('.dropdown'); + const $fieldInput = $(`input[name="${$dropdown.data('field-name')}"]`, $dropdownContainer); + const $filterInput = $('input[type="search"]', $dropdownContainer); + $dropdown.glDropdown({ + data: function(term, callback) { + return $.ajax({ + url: $dropdown.data('refs-url'), + data: { + ref: $dropdown.data('ref'), + search: term, } - }, - id: function(obj, $el) { - return $el.attr('data-ref'); - }, - toggleLabel: function(obj, $el) { - return $el.text().trim(); + }).done(function(refs) { + return callback(refs); + }); + }, + selectable: true, + filterable: true, + filterRemote: true, + fieldName: $dropdown.data('field-name'), + filterInput: 'input[type="search"]', + renderRow: function(ref) { + var link; + if (ref.header != null) { + return $('<li />').addClass('dropdown-header').text(ref.header); + } else { + link = $('<a />').attr('href', '#').addClass(ref === selected ? 'is-active' : '').text(ref).attr('data-ref', escape(ref)); + return $('<li />').append(link); } - }); - $filterInput.on('keyup', (e) => { - const keyCode = e.keyCode || e.which; - if (keyCode !== 13) return; - const text = $filterInput.val(); - $fieldInput.val(text); - $('.dropdown-toggle-text', $dropdown).text(text); - $dropdownContainer.removeClass('open'); - }); + }, + id: function(obj, $el) { + return $el.attr('data-ref'); + }, + toggleLabel: function(obj, $el) { + return $el.text().trim(); + } + }); + $filterInput.on('keyup', (e) => { + const keyCode = e.keyCode || e.which; + if (keyCode !== 13) return; + const text = $filterInput.val(); + $fieldInput.val(text); + $('.dropdown-toggle-text', $dropdown).text(text); + $dropdownContainer.removeClass('open'); + }); - $dropdownContainer.on('click', '.dropdown-content a', (e) => { - $dropdown.prop('title', e.target.text.replace(/_+?/g, '-')); - if ($dropdown.hasClass('has-tooltip')) { - $dropdown.tooltip('fixTitle'); - } - }); + $dropdownContainer.on('click', '.dropdown-content a', (e) => { + $dropdown.prop('title', e.target.text.replace(/_+?/g, '-')); + if ($dropdown.hasClass('has-tooltip')) { + $dropdown.tooltip('fixTitle'); + } }); - }; + }); +}; - return CompareAutocomplete; -})(); +window.CompareAutocomplete = CompareAutocomplete; diff --git a/app/assets/javascripts/confirm_danger_modal.js b/app/assets/javascripts/confirm_danger_modal.js index b375b61202e..14bbc170699 100644 --- a/app/assets/javascripts/confirm_danger_modal.js +++ b/app/assets/javascripts/confirm_danger_modal.js @@ -1,30 +1,24 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, camelcase, one-var-declaration-per-line, no-else-return, max-len */ -window.ConfirmDangerModal = (function() { - function ConfirmDangerModal(form, text) { - var project_path, submit; - this.form = form; - $('.js-confirm-text').text(text || ''); - $('.js-confirm-danger-input').val(''); - $('#modal-confirm-danger').modal('show'); - project_path = $('.js-confirm-danger-match').text(); - submit = $('.js-confirm-danger-submit'); - submit.disable(); - $('.js-confirm-danger-input').off('input'); - $('.js-confirm-danger-input').on('input', function() { - if (gl.utils.rstrip($(this).val()) === project_path) { - return submit.enable(); - } else { - return submit.disable(); - } - }); - $('.js-confirm-danger-submit').off('click'); - $('.js-confirm-danger-submit').on('click', (function(_this) { - return function() { - return _this.form.submit(); - }; - })(this)); - } +function ConfirmDangerModal(form, text) { + var project_path, submit; + this.form = form; + $('.js-confirm-text').text(text || ''); + $('.js-confirm-danger-input').val(''); + $('#modal-confirm-danger').modal('show'); + project_path = $('.js-confirm-danger-match').text(); + submit = $('.js-confirm-danger-submit'); + submit.disable(); + $('.js-confirm-danger-input').off('input'); + $('.js-confirm-danger-input').on('input', function() { + if (gl.utils.rstrip($(this).val()) === project_path) { + return submit.enable(); + } else { + return submit.disable(); + } + }); + $('.js-confirm-danger-submit').off('click'); + $('.js-confirm-danger-submit').on('click', () => this.form.submit()); +} - return ConfirmDangerModal; -})(); +window.ConfirmDangerModal = ConfirmDangerModal; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index 73675d300be..6fd567c76bb 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -3,300 +3,298 @@ import './preview_markdown'; -window.DropzoneInput = (function() { - function DropzoneInput(form) { - var updateAttachingMessage, $attachingFileMessage, $mdArea, $attachButton, $cancelButton, $retryLink, $uploadingErrorContainer, $uploadingErrorMessage, $uploadProgress, $uploadingProgressContainer, appendToTextArea, btnAlert, child, closeAlertMessage, closeSpinner, divHover, divSpinner, dropzone, $formDropzone, formTextarea, getFilename, handlePaste, iconPaperclip, iconSpinner, insertToTextArea, isImage, maxFileSize, pasteText, uploadsPath, showError, showSpinner, uploadFile, addFileToForm; - Dropzone.autoDiscover = false; - divHover = '<div class="div-dropzone-hover"></div>'; - iconPaperclip = '<i class="fa fa-paperclip div-dropzone-icon"></i>'; - $attachButton = form.find('.button-attach-file'); - $attachingFileMessage = form.find('.attaching-file-message'); - $cancelButton = form.find('.button-cancel-uploading-files'); - $retryLink = form.find('.retry-uploading-link'); - $uploadProgress = form.find('.uploading-progress'); - $uploadingErrorContainer = form.find('.uploading-error-container'); - $uploadingErrorMessage = form.find('.uploading-error-message'); - $uploadingProgressContainer = form.find('.uploading-progress-container'); - uploadsPath = window.uploads_path || null; - maxFileSize = gon.max_file_size || 10; - formTextarea = form.find('.js-gfm-input'); - formTextarea.wrap('<div class="div-dropzone"></div>'); - formTextarea.on('paste', (function(_this) { - return function(event) { - return handlePaste(event); - }; - })(this)); - - // Add dropzone area to the form. - $mdArea = formTextarea.closest('.md-area'); - form.setupMarkdownPreview(); - $formDropzone = form.find('.div-dropzone'); - $formDropzone.parent().addClass('div-dropzone-wrapper'); - $formDropzone.append(divHover); - $formDropzone.find('.div-dropzone-hover').append(iconPaperclip); - - if (!uploadsPath) return; - - dropzone = $formDropzone.dropzone({ +function DropzoneInput(form) { + var updateAttachingMessage, $attachingFileMessage, $mdArea, $attachButton, $cancelButton, $retryLink, $uploadingErrorContainer, $uploadingErrorMessage, $uploadProgress, $uploadingProgressContainer, appendToTextArea, btnAlert, child, closeAlertMessage, closeSpinner, divHover, divSpinner, dropzone, $formDropzone, formTextarea, getFilename, handlePaste, iconPaperclip, iconSpinner, insertToTextArea, isImage, maxFileSize, pasteText, uploadsPath, showError, showSpinner, uploadFile, addFileToForm; + Dropzone.autoDiscover = false; + divHover = '<div class="div-dropzone-hover"></div>'; + iconPaperclip = '<i class="fa fa-paperclip div-dropzone-icon"></i>'; + $attachButton = form.find('.button-attach-file'); + $attachingFileMessage = form.find('.attaching-file-message'); + $cancelButton = form.find('.button-cancel-uploading-files'); + $retryLink = form.find('.retry-uploading-link'); + $uploadProgress = form.find('.uploading-progress'); + $uploadingErrorContainer = form.find('.uploading-error-container'); + $uploadingErrorMessage = form.find('.uploading-error-message'); + $uploadingProgressContainer = form.find('.uploading-progress-container'); + uploadsPath = window.uploads_path || null; + maxFileSize = gon.max_file_size || 10; + formTextarea = form.find('.js-gfm-input'); + formTextarea.wrap('<div class="div-dropzone"></div>'); + formTextarea.on('paste', (function(_this) { + return function(event) { + return handlePaste(event); + }; + })(this)); + + // Add dropzone area to the form. + $mdArea = formTextarea.closest('.md-area'); + form.setupMarkdownPreview(); + $formDropzone = form.find('.div-dropzone'); + $formDropzone.parent().addClass('div-dropzone-wrapper'); + $formDropzone.append(divHover); + $formDropzone.find('.div-dropzone-hover').append(iconPaperclip); + + if (!uploadsPath) return; + + dropzone = $formDropzone.dropzone({ + url: uploadsPath, + dictDefaultMessage: '', + clickable: true, + paramName: 'file', + maxFilesize: maxFileSize, + uploadMultiple: false, + headers: { + 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') + }, + previewContainer: false, + processing: function() { + return $('.div-dropzone-alert').alert('close'); + }, + dragover: function() { + $mdArea.addClass('is-dropzone-hover'); + form.find('.div-dropzone-hover').css('opacity', 0.7); + }, + dragleave: function() { + $mdArea.removeClass('is-dropzone-hover'); + form.find('.div-dropzone-hover').css('opacity', 0); + }, + drop: function() { + $mdArea.removeClass('is-dropzone-hover'); + form.find('.div-dropzone-hover').css('opacity', 0); + formTextarea.focus(); + }, + success: function(header, response) { + const processingFileCount = this.getQueuedFiles().length + this.getUploadingFiles().length; + const shouldPad = processingFileCount >= 1; + + pasteText(response.link.markdown, shouldPad); + // Show 'Attach a file' link only when all files have been uploaded. + if (!processingFileCount) $attachButton.removeClass('hide'); + addFileToForm(response.link.url); + }, + error: function(file, errorMessage = 'Attaching the file failed.', xhr) { + // If 'error' event is fired by dropzone, the second parameter is error message. + // If the 'errorMessage' parameter is empty, the default error message is set. + // If the 'error' event is fired by backend (xhr) error response, the third parameter is + // xhr object (xhr.responseText is error message). + // On error we hide the 'Attach' and 'Cancel' buttons + // and show an error. + + // If there's xhr error message, let's show it instead of dropzone's one. + const message = xhr ? xhr.responseText : errorMessage; + + $uploadingErrorContainer.removeClass('hide'); + $uploadingErrorMessage.html(message); + $attachButton.addClass('hide'); + $cancelButton.addClass('hide'); + }, + totaluploadprogress: function(totalUploadProgress) { + updateAttachingMessage(this.files, $attachingFileMessage); + $uploadProgress.text(Math.round(totalUploadProgress) + '%'); + }, + sending: function(file) { + // DOM elements already exist. + // Instead of dynamically generating them, + // we just either hide or show them. + $attachButton.addClass('hide'); + $uploadingErrorContainer.addClass('hide'); + $uploadingProgressContainer.removeClass('hide'); + $cancelButton.removeClass('hide'); + }, + removedfile: function() { + $attachButton.removeClass('hide'); + $cancelButton.addClass('hide'); + $uploadingProgressContainer.addClass('hide'); + $uploadingErrorContainer.addClass('hide'); + }, + queuecomplete: function() { + $('.dz-preview').remove(); + $('.markdown-area').trigger('input'); + + $uploadingProgressContainer.addClass('hide'); + $cancelButton.addClass('hide'); + } + }); + + child = $(dropzone[0]).children('textarea'); + + // removeAllFiles(true) stops uploading files (if any) + // and remove them from dropzone files queue. + $cancelButton.on('click', (e) => { + const target = e.target.closest('form').querySelector('.div-dropzone'); + + e.preventDefault(); + e.stopPropagation(); + Dropzone.forElement(target).removeAllFiles(true); + }); + + // If 'error' event is fired, we store a failed files, + // clear dropzone files queue, change status of failed files to undefined, + // and add that files to the dropzone files queue again. + // addFile() adds file to dropzone files queue and upload it. + $retryLink.on('click', (e) => { + const dropzoneInstance = Dropzone.forElement(e.target.closest('form').querySelector('.div-dropzone')); + const failedFiles = dropzoneInstance.files; + + e.preventDefault(); + + // 'true' parameter of removeAllFiles() cancels uploading of files that are being uploaded at the moment. + dropzoneInstance.removeAllFiles(true); + + failedFiles.map((failedFile, i) => { + const file = failedFile; + + if (file.status === Dropzone.ERROR) { + file.status = undefined; + file.accepted = undefined; + } + + return dropzoneInstance.addFile(file); + }); + }); + + handlePaste = function(event) { + var filename, image, pasteEvent, text; + pasteEvent = event.originalEvent; + if (pasteEvent.clipboardData && pasteEvent.clipboardData.items) { + image = isImage(pasteEvent); + if (image) { + event.preventDefault(); + filename = getFilename(pasteEvent) || 'image.png'; + text = `{{${filename}}}`; + pasteText(text); + return uploadFile(image.getAsFile(), filename); + } + } + }; + + isImage = function(data) { + var i, item; + i = 0; + while (i < data.clipboardData.items.length) { + item = data.clipboardData.items[i]; + if (item.type.indexOf('image') !== -1) { + return item; + } + i += 1; + } + return false; + }; + + pasteText = function(text, shouldPad) { + var afterSelection, beforeSelection, caretEnd, caretStart, textEnd; + var formattedText = text; + if (shouldPad) formattedText += "\n\n"; + const textarea = child.get(0); + caretStart = textarea.selectionStart; + caretEnd = textarea.selectionEnd; + textEnd = $(child).val().length; + beforeSelection = $(child).val().substring(0, caretStart); + afterSelection = $(child).val().substring(caretEnd, textEnd); + $(child).val(beforeSelection + formattedText + afterSelection); + textarea.setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length); + textarea.style.height = `${textarea.scrollHeight}px`; + formTextarea.get(0).dispatchEvent(new Event('input')); + return formTextarea.trigger('input'); + }; + + addFileToForm = function(path) { + $(form).append('<input type="hidden" name="files[]" value="' + _.escape(path) + '">'); + }; + + getFilename = function(e) { + var value; + if (window.clipboardData && window.clipboardData.getData) { + value = window.clipboardData.getData('Text'); + } else if (e.clipboardData && e.clipboardData.getData) { + value = e.clipboardData.getData('text/plain'); + } + value = value.split("\r"); + return value.first(); + }; + + uploadFile = function(item, filename) { + var formData; + formData = new FormData(); + formData.append('file', item, filename); + return $.ajax({ url: uploadsPath, - dictDefaultMessage: '', - clickable: true, - paramName: 'file', - maxFilesize: maxFileSize, - uploadMultiple: false, + type: 'POST', + data: formData, + dataType: 'json', + processData: false, + contentType: false, headers: { 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') }, - previewContainer: false, - processing: function() { - return $('.div-dropzone-alert').alert('close'); - }, - dragover: function() { - $mdArea.addClass('is-dropzone-hover'); - form.find('.div-dropzone-hover').css('opacity', 0.7); - }, - dragleave: function() { - $mdArea.removeClass('is-dropzone-hover'); - form.find('.div-dropzone-hover').css('opacity', 0); - }, - drop: function() { - $mdArea.removeClass('is-dropzone-hover'); - form.find('.div-dropzone-hover').css('opacity', 0); - formTextarea.focus(); - }, - success: function(header, response) { - const processingFileCount = this.getQueuedFiles().length + this.getUploadingFiles().length; - const shouldPad = processingFileCount >= 1; - - pasteText(response.link.markdown, shouldPad); - // Show 'Attach a file' link only when all files have been uploaded. - if (!processingFileCount) $attachButton.removeClass('hide'); - addFileToForm(response.link.url); + beforeSend: function() { + showSpinner(); + return closeAlertMessage(); }, - error: function(file, errorMessage = 'Attaching the file failed.', xhr) { - // If 'error' event is fired by dropzone, the second parameter is error message. - // If the 'errorMessage' parameter is empty, the default error message is set. - // If the 'error' event is fired by backend (xhr) error response, the third parameter is - // xhr object (xhr.responseText is error message). - // On error we hide the 'Attach' and 'Cancel' buttons - // and show an error. - - // If there's xhr error message, let's show it instead of dropzone's one. - const message = xhr ? xhr.responseText : errorMessage; - - $uploadingErrorContainer.removeClass('hide'); - $uploadingErrorMessage.html(message); - $attachButton.addClass('hide'); - $cancelButton.addClass('hide'); + success: function(e, textStatus, response) { + return insertToTextArea(filename, response.responseJSON.link.markdown); }, - totaluploadprogress: function(totalUploadProgress) { - updateAttachingMessage(this.files, $attachingFileMessage); - $uploadProgress.text(Math.round(totalUploadProgress) + '%'); + error: function(response) { + return showError(response.responseJSON.message); }, - sending: function(file) { - // DOM elements already exist. - // Instead of dynamically generating them, - // we just either hide or show them. - $attachButton.addClass('hide'); - $uploadingErrorContainer.addClass('hide'); - $uploadingProgressContainer.removeClass('hide'); - $cancelButton.removeClass('hide'); - }, - removedfile: function() { - $attachButton.removeClass('hide'); - $cancelButton.addClass('hide'); - $uploadingProgressContainer.addClass('hide'); - $uploadingErrorContainer.addClass('hide'); - }, - queuecomplete: function() { - $('.dz-preview').remove(); - $('.markdown-area').trigger('input'); - - $uploadingProgressContainer.addClass('hide'); - $cancelButton.addClass('hide'); + complete: function() { + return closeSpinner(); } }); - - child = $(dropzone[0]).children('textarea'); - - // removeAllFiles(true) stops uploading files (if any) - // and remove them from dropzone files queue. - $cancelButton.on('click', (e) => { - const target = e.target.closest('form').querySelector('.div-dropzone'); - - e.preventDefault(); - e.stopPropagation(); - Dropzone.forElement(target).removeAllFiles(true); + }; + + updateAttachingMessage = (files, messageContainer) => { + let attachingMessage; + const filesCount = files.filter(function(file) { + return file.status === 'uploading' || + file.status === 'queued'; + }).length; + + // Dinamycally change uploading files text depending on files number in + // dropzone files queue. + if (filesCount > 1) { + attachingMessage = 'Attaching ' + filesCount + ' files -'; + } else { + attachingMessage = 'Attaching a file -'; + } + + messageContainer.text(attachingMessage); + }; + + insertToTextArea = function(filename, url) { + return $(child).val(function(index, val) { + return val.replace(`{{${filename}}}`, url); }); + }; - // If 'error' event is fired, we store a failed files, - // clear dropzone files queue, change status of failed files to undefined, - // and add that files to the dropzone files queue again. - // addFile() adds file to dropzone files queue and upload it. - $retryLink.on('click', (e) => { - const dropzoneInstance = Dropzone.forElement(e.target.closest('form').querySelector('.div-dropzone')); - const failedFiles = dropzoneInstance.files; - - e.preventDefault(); - - // 'true' parameter of removeAllFiles() cancels uploading of files that are being uploaded at the moment. - dropzoneInstance.removeAllFiles(true); - - failedFiles.map((failedFile, i) => { - const file = failedFile; - - if (file.status === Dropzone.ERROR) { - file.status = undefined; - file.accepted = undefined; - } - - return dropzoneInstance.addFile(file); - }); + appendToTextArea = function(url) { + return $(child).val(function(index, val) { + return val + url + "\n"; }); + }; - handlePaste = function(event) { - var filename, image, pasteEvent, text; - pasteEvent = event.originalEvent; - if (pasteEvent.clipboardData && pasteEvent.clipboardData.items) { - image = isImage(pasteEvent); - if (image) { - event.preventDefault(); - filename = getFilename(pasteEvent) || 'image.png'; - text = `{{${filename}}}`; - pasteText(text); - return uploadFile(image.getAsFile(), filename); - } - } - }; - - isImage = function(data) { - var i, item; - i = 0; - while (i < data.clipboardData.items.length) { - item = data.clipboardData.items[i]; - if (item.type.indexOf('image') !== -1) { - return item; - } - i += 1; - } - return false; - }; - - pasteText = function(text, shouldPad) { - var afterSelection, beforeSelection, caretEnd, caretStart, textEnd; - var formattedText = text; - if (shouldPad) formattedText += "\n\n"; - const textarea = child.get(0); - caretStart = textarea.selectionStart; - caretEnd = textarea.selectionEnd; - textEnd = $(child).val().length; - beforeSelection = $(child).val().substring(0, caretStart); - afterSelection = $(child).val().substring(caretEnd, textEnd); - $(child).val(beforeSelection + formattedText + afterSelection); - textarea.setSelectionRange(caretStart + formattedText.length, caretEnd + formattedText.length); - textarea.style.height = `${textarea.scrollHeight}px`; - formTextarea.get(0).dispatchEvent(new Event('input')); - return formTextarea.trigger('input'); - }; - - addFileToForm = function(path) { - $(form).append('<input type="hidden" name="files[]" value="' + _.escape(path) + '">'); - }; - - getFilename = function(e) { - var value; - if (window.clipboardData && window.clipboardData.getData) { - value = window.clipboardData.getData('Text'); - } else if (e.clipboardData && e.clipboardData.getData) { - value = e.clipboardData.getData('text/plain'); - } - value = value.split("\r"); - return value.first(); - }; - - uploadFile = function(item, filename) { - var formData; - formData = new FormData(); - formData.append('file', item, filename); - return $.ajax({ - url: uploadsPath, - type: 'POST', - data: formData, - dataType: 'json', - processData: false, - contentType: false, - headers: { - 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') - }, - beforeSend: function() { - showSpinner(); - return closeAlertMessage(); - }, - success: function(e, textStatus, response) { - return insertToTextArea(filename, response.responseJSON.link.markdown); - }, - error: function(response) { - return showError(response.responseJSON.message); - }, - complete: function() { - return closeSpinner(); - } - }); - }; - - updateAttachingMessage = (files, messageContainer) => { - let attachingMessage; - const filesCount = files.filter(function(file) { - return file.status === 'uploading' || - file.status === 'queued'; - }).length; - - // Dinamycally change uploading files text depending on files number in - // dropzone files queue. - if (filesCount > 1) { - attachingMessage = 'Attaching ' + filesCount + ' files -'; - } else { - attachingMessage = 'Attaching a file -'; - } - - messageContainer.text(attachingMessage); - }; - - insertToTextArea = function(filename, url) { - return $(child).val(function(index, val) { - return val.replace(`{{${filename}}}`, url); - }); - }; - - appendToTextArea = function(url) { - return $(child).val(function(index, val) { - return val + url + "\n"; - }); - }; - - showSpinner = function(e) { - return $uploadingProgressContainer.removeClass('hide'); - }; + showSpinner = function(e) { + return $uploadingProgressContainer.removeClass('hide'); + }; - closeSpinner = function() { - return $uploadingProgressContainer.addClass('hide'); - }; + closeSpinner = function() { + return $uploadingProgressContainer.addClass('hide'); + }; - showError = function(message) { - $uploadingErrorContainer.removeClass('hide'); - $uploadingErrorMessage.html(message); - }; + showError = function(message) { + $uploadingErrorContainer.removeClass('hide'); + $uploadingErrorMessage.html(message); + }; - closeAlertMessage = function() { - return form.find('.div-dropzone-alert').alert('close'); - }; + closeAlertMessage = function() { + return form.find('.div-dropzone-alert').alert('close'); + }; - form.find('.markdown-selector').click(function(e) { - e.preventDefault(); - $(this).closest('.gfm-form').find('.div-dropzone').click(); - formTextarea.focus(); - }); - } + form.find('.markdown-selector').click(function(e) { + e.preventDefault(); + $(this).closest('.gfm-form').find('.div-dropzone').click(); + formTextarea.focus(); + }); +} - return DropzoneInput; -})(); +window.DropzoneInput = DropzoneInput; diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index ccff8f0ace7..5152b0f27a3 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -1,71 +1,69 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-param-reassign, quotes, quote-props, prefer-template, comma-dangle, max-len */ -window.Flash = (function() { - var hideFlash; +var hideFlash; - hideFlash = function() { - return $(this).fadeOut(); - }; +hideFlash = function() { + return $(this).fadeOut(); +}; - /** - * Flash banner supports different types of Flash configurations - * along with ability to provide actionConfig which can be used to show - * additional action or link on banner next to message - * - * @param {String} message Flash message - * @param {String} type Type of Flash, it can be `notice` or `alert` (default) - * @param {Object} parent Reference to Parent element under which Flash needs to appear - * @param {Object} actionConfig Map of config to show action on banner - * @param {String} href URL to which action link should point (default '#') - * @param {String} title Title of action - * @param {Function} clickHandler Method to call when action is clicked on - */ - function Flash(message, type, parent, actionConfig) { - var flash, textDiv, actionLink; - if (type == null) { - type = 'alert'; - } - if (parent == null) { - parent = null; - } - if (parent) { - this.flashContainer = parent.find('.flash-container'); - } else { - this.flashContainer = $('.flash-container-page'); - } - this.flashContainer.html(''); - flash = $('<div/>', { - "class": "flash-" + type - }); - flash.on('click', hideFlash); - textDiv = $('<div/>', { - "class": 'flash-text', - text: message - }); - textDiv.appendTo(flash); +/** + * Flash banner supports different types of Flash configurations + * along with ability to provide actionConfig which can be used to show + * additional action or link on banner next to message + * + * @param {String} message Flash message + * @param {String} type Type of Flash, it can be `notice` or `alert` (default) + * @param {Object} parent Reference to Parent element under which Flash needs to appear + * @param {Object} actionConfig Map of config to show action on banner + * @param {String} href URL to which action link should point (default '#') + * @param {String} title Title of action + * @param {Function} clickHandler Method to call when action is clicked on + */ +function Flash(message, type, parent, actionConfig) { + var flash, textDiv, actionLink; + if (type == null) { + type = 'alert'; + } + if (parent == null) { + parent = null; + } + if (parent) { + this.flashContainer = parent.find('.flash-container'); + } else { + this.flashContainer = $('.flash-container-page'); + } + this.flashContainer.html(''); + flash = $('<div/>', { + "class": "flash-" + type + }); + flash.on('click', hideFlash); + textDiv = $('<div/>', { + "class": 'flash-text', + text: message + }); + textDiv.appendTo(flash); - if (actionConfig) { - const actionLinkConfig = { - class: 'flash-action', - href: actionConfig.href || '#', - text: actionConfig.title - }; + if (actionConfig) { + const actionLinkConfig = { + class: 'flash-action', + href: actionConfig.href || '#', + text: actionConfig.title + }; - if (!actionConfig.href) { - actionLinkConfig.role = 'button'; - } + if (!actionConfig.href) { + actionLinkConfig.role = 'button'; + } - actionLink = $('<a/>', actionLinkConfig); + actionLink = $('<a/>', actionLinkConfig); - actionLink.appendTo(flash); - this.flashContainer.on('click', '.flash-action', actionConfig.clickHandler); - } - if (this.flashContainer.parent().hasClass('content-wrapper')) { - textDiv.addClass('container-fluid container-limited'); - } - flash.appendTo(this.flashContainer); - this.flashContainer.show(); + actionLink.appendTo(flash); + this.flashContainer.on('click', '.flash-action', actionConfig.clickHandler); + } + if (this.flashContainer.parent().hasClass('content-wrapper')) { + textDiv.addClass('container-fluid container-limited'); } + flash.appendTo(this.flashContainer); + this.flashContainer.show(); +} - return Flash; -})(); +window.Flash = Flash; diff --git a/app/assets/javascripts/group_avatar.js b/app/assets/javascripts/group_avatar.js index f03b47b1c1d..e60a33fbf4a 100644 --- a/app/assets/javascripts/group_avatar.js +++ b/app/assets/javascripts/group_avatar.js @@ -1,19 +1,17 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, quotes, no-var, one-var, one-var-declaration-per-line, no-useless-escape, max-len */ -window.GroupAvatar = (function() { - function GroupAvatar() { - $('.js-choose-group-avatar-button').on("click", function() { - var form; - form = $(this).closest("form"); - return form.find(".js-group-avatar-input").click(); - }); - $('.js-group-avatar-input').on("change", function() { - var filename, form; - form = $(this).closest("form"); - filename = $(this).val().replace(/^.*[\\\/]/, ''); - return form.find(".js-avatar-filename").text(filename); - }); - } +function GroupAvatar() { + $('.js-choose-group-avatar-button').on("click", function() { + var form; + form = $(this).closest("form"); + return form.find(".js-group-avatar-input").click(); + }); + $('.js-group-avatar-input').on("change", function() { + var filename, form; + form = $(this).closest("form"); + filename = $(this).val().replace(/^.*[\\\/]/, ''); + return form.find(".js-avatar-filename").text(filename); + }); +} - return GroupAvatar; -})(); +window.GroupAvatar = GroupAvatar; diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index b5975295329..d7d8e403542 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -7,115 +7,113 @@ import Api from './api'; var slice = [].slice; -window.GroupsSelect = (function() { - function GroupsSelect() { - $('.ajax-groups-select').each((function(_this) { - const self = _this; +function GroupsSelect() { + $('.ajax-groups-select').each((function(_this) { + const self = _this; - return function(i, select) { - var all_available, skip_groups; - const $select = $(select); - all_available = $select.data('all-available'); - skip_groups = $select.data('skip-groups') || []; + return function(i, select) { + var all_available, skip_groups; + const $select = $(select); + all_available = $select.data('all-available'); + skip_groups = $select.data('skip-groups') || []; - $select.select2({ - placeholder: "Search for a group", - multiple: $select.hasClass('multiselect'), - minimumInputLength: 0, - ajax: { - url: Api.buildUrl(Api.groupsPath), - dataType: 'json', - quietMillis: 250, - transport: function (params) { - $.ajax(params).then((data, status, xhr) => { - const results = data || []; + $select.select2({ + placeholder: "Search for a group", + multiple: $select.hasClass('multiselect'), + minimumInputLength: 0, + ajax: { + url: Api.buildUrl(Api.groupsPath), + dataType: 'json', + quietMillis: 250, + transport: function (params) { + $.ajax(params).then((data, status, xhr) => { + const results = data || []; - const headers = gl.utils.normalizeCRLFHeaders(xhr.getAllResponseHeaders()); - const currentPage = parseInt(headers['X-PAGE'], 10) || 0; - const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0; - const more = currentPage < totalPages; - - return { - results, - pagination: { - more, - }, - }; - }).then(params.success).fail(params.error); - }, - data: function (search, page) { - return { - search, - page, - per_page: GroupsSelect.PER_PAGE, - all_available, - }; - }, - results: function (data, page) { - if (data.length) return { results: [] }; - - const groups = data.length ? data : data.results || []; - const more = data.pagination ? data.pagination.more : false; - const results = groups.filter(group => skip_groups.indexOf(group.id) === -1); + const headers = gl.utils.normalizeCRLFHeaders(xhr.getAllResponseHeaders()); + const currentPage = parseInt(headers['X-PAGE'], 10) || 0; + const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0; + const more = currentPage < totalPages; return { results, - page, - more, + pagination: { + more, + }, }; - }, - }, - initSelection: function(element, callback) { - var id; - id = $(element).val(); - if (id !== "") { - return Api.group(id, callback); - } + }).then(params.success).fail(params.error); }, - formatResult: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return self.formatResult.apply(self, args); + data: function (search, page) { + return { + search, + page, + per_page: GroupsSelect.PER_PAGE, + all_available, + }; }, - formatSelection: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return self.formatSelection.apply(self, args); + results: function (data, page) { + if (data.length) return { results: [] }; + + const groups = data.length ? data : data.results || []; + const more = data.pagination ? data.pagination.more : false; + const results = groups.filter(group => skip_groups.indexOf(group.id) === -1); + + return { + results, + page, + more, + }; }, - dropdownCssClass: "ajax-groups-dropdown select2-infinite", - // we do not want to escape markup since we are displaying html in results - escapeMarkup: function(m) { - return m; + }, + initSelection: function(element, callback) { + var id; + id = $(element).val(); + if (id !== "") { + return Api.group(id, callback); } - }); + }, + formatResult: function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return self.formatResult.apply(self, args); + }, + formatSelection: function() { + var args; + args = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return self.formatSelection.apply(self, args); + }, + dropdownCssClass: "ajax-groups-dropdown select2-infinite", + // we do not want to escape markup since we are displaying html in results + escapeMarkup: function(m) { + return m; + } + }); - self.dropdown = document.querySelector('.select2-infinite .select2-results'); + self.dropdown = document.querySelector('.select2-infinite .select2-results'); - $select.on('select2-loaded', self.forceOverflow.bind(self)); - }; - })(this)); - } + $select.on('select2-loaded', self.forceOverflow.bind(self)); + }; + })(this)); +} - GroupsSelect.prototype.formatResult = function(group) { - var avatar; - if (group.avatar_url) { - avatar = group.avatar_url; - } else { - avatar = gon.default_avatar_url; - } - return "<div class='group-result'> <div class='group-name'>" + group.full_name + "</div> <div class='group-path'>" + group.full_path + "</div> </div>"; - }; +GroupsSelect.prototype.formatResult = function(group) { + var avatar; + if (group.avatar_url) { + avatar = group.avatar_url; + } else { + avatar = gon.default_avatar_url; + } + return "<div class='group-result'> <div class='group-name'>" + group.full_name + "</div> <div class='group-path'>" + group.full_path + "</div> </div>"; +}; - GroupsSelect.prototype.formatSelection = function(group) { - return group.full_name; - }; +GroupsSelect.prototype.formatSelection = function(group) { + return group.full_name; +}; - GroupsSelect.prototype.forceOverflow = function (e) { - const itemHeight = this.dropdown.querySelector('.select2-result:first-child').clientHeight; - this.dropdown.style.height = `${Math.floor(this.dropdown.scrollHeight - (itemHeight * 0.9))}px`; - }; +GroupsSelect.prototype.forceOverflow = function (e) { + const itemHeight = this.dropdown.querySelector('.select2-result:first-child').clientHeight; + this.dropdown.style.height = `${Math.floor(this.dropdown.scrollHeight - (itemHeight * 0.9))}px`; +}; - GroupsSelect.PER_PAGE = 20; +GroupsSelect.PER_PAGE = 20; - return GroupsSelect; -})(); +window.GroupsSelect = GroupsSelect; diff --git a/app/assets/javascripts/importer_status.js b/app/assets/javascripts/importer_status.js index 5b4ca94ed30..3d97938c0f3 100644 --- a/app/assets/javascripts/importer_status.js +++ b/app/assets/javascripts/importer_status.js @@ -1,83 +1,79 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, camelcase, no-var, one-var, one-var-declaration-per-line, prefer-template, quotes, object-shorthand, comma-dangle, no-unused-vars, prefer-arrow-callback, no-else-return, vars-on-top, no-new, max-len */ -(function() { - window.ImporterStatus = (function() { - function ImporterStatus(jobs_url, import_url) { - this.jobs_url = jobs_url; - this.import_url = import_url; - this.initStatusPage(); - this.setAutoUpdate(); - } +function ImporterStatus(jobs_url, import_url) { + this.jobs_url = jobs_url; + this.import_url = import_url; + this.initStatusPage(); + this.setAutoUpdate(); +} - ImporterStatus.prototype.initStatusPage = function() { - $('.js-add-to-import').off('click').on('click', (function(_this) { - return function(e) { - var $btn, $namespace_input, $target_field, $tr, id, target_namespace, newName; - $btn = $(e.currentTarget); - $tr = $btn.closest('tr'); - $target_field = $tr.find('.import-target'); - $namespace_input = $target_field.find('.js-select-namespace option:selected'); - id = $tr.attr('id').replace('repo_', ''); - target_namespace = null; - newName = null; - if ($namespace_input.length > 0) { - target_namespace = $namespace_input[0].innerHTML; - newName = $target_field.find('#path').prop('value'); - $target_field.empty().append(target_namespace + "/" + newName); - } - $btn.disable().addClass('is-loading'); - return $.post(_this.import_url, { - repo_id: id, - target_namespace: target_namespace, - new_name: newName - }, { - dataType: 'script' - }); - }; - })(this)); - return $('.js-import-all').off('click').on('click', function(e) { - var $btn; - $btn = $(this); - $btn.disable().addClass('is-loading'); - return $('.js-add-to-import').each(function() { - return $(this).trigger('click'); - }); +ImporterStatus.prototype.initStatusPage = function() { + $('.js-add-to-import').off('click').on('click', (function(_this) { + return function(e) { + var $btn, $namespace_input, $target_field, $tr, id, target_namespace, newName; + $btn = $(e.currentTarget); + $tr = $btn.closest('tr'); + $target_field = $tr.find('.import-target'); + $namespace_input = $target_field.find('.js-select-namespace option:selected'); + id = $tr.attr('id').replace('repo_', ''); + target_namespace = null; + newName = null; + if ($namespace_input.length > 0) { + target_namespace = $namespace_input[0].innerHTML; + newName = $target_field.find('#path').prop('value'); + $target_field.empty().append(target_namespace + "/" + newName); + } + $btn.disable().addClass('is-loading'); + return $.post(_this.import_url, { + repo_id: id, + target_namespace: target_namespace, + new_name: newName + }, { + dataType: 'script' }); }; + })(this)); + return $('.js-import-all').off('click').on('click', function(e) { + var $btn; + $btn = $(this); + $btn.disable().addClass('is-loading'); + return $('.js-add-to-import').each(function() { + return $(this).trigger('click'); + }); + }); +}; - ImporterStatus.prototype.setAutoUpdate = function() { - return setInterval(((function(_this) { - return function() { - return $.get(_this.jobs_url, function(data) { - return $.each(data, function(i, job) { - var job_item, status_field; - job_item = $("#project_" + job.id); - status_field = job_item.find(".job-status"); - if (job.import_status === 'finished') { - job_item.removeClass("active").addClass("success"); - return status_field.html('<span><i class="fa fa-check"></i> done</span>'); - } else if (job.import_status === 'scheduled') { - return status_field.html("<i class='fa fa-spinner fa-spin'></i> scheduled"); - } else if (job.import_status === 'started') { - return status_field.html("<i class='fa fa-spinner fa-spin'></i> started"); - } else { - return status_field.html(job.import_status); - } - }); - }); - }; - })(this)), 4000); +ImporterStatus.prototype.setAutoUpdate = function() { + return setInterval(((function(_this) { + return function() { + return $.get(_this.jobs_url, function(data) { + return $.each(data, function(i, job) { + var job_item, status_field; + job_item = $("#project_" + job.id); + status_field = job_item.find(".job-status"); + if (job.import_status === 'finished') { + job_item.removeClass("active").addClass("success"); + return status_field.html('<span><i class="fa fa-check"></i> done</span>'); + } else if (job.import_status === 'scheduled') { + return status_field.html("<i class='fa fa-spinner fa-spin'></i> scheduled"); + } else if (job.import_status === 'started') { + return status_field.html("<i class='fa fa-spinner fa-spin'></i> started"); + } else { + return status_field.html(job.import_status); + } + }); + }); }; + })(this)), 4000); +}; - return ImporterStatus; - })(); +window.ImporterStatus = ImporterStatus; - $(function() { - if ($('.js-importer-status').length) { - var jobsImportPath = $('.js-importer-status').data('jobs-import-path'); - var importPath = $('.js-importer-status').data('import-path'); +$(function() { + if ($('.js-importer-status').length) { + var jobsImportPath = $('.js-importer-status').data('jobs-import-path'); + var importPath = $('.js-importer-status').data('import-path'); - new window.ImporterStatus(jobsImportPath, importPath); - } - }); -}).call(window); + new window.ImporterStatus(jobsImportPath, importPath); + } +}); diff --git a/app/assets/javascripts/issuable_context.js b/app/assets/javascripts/issuable_context.js index a4d7bf096ef..e8cfc0241fe 100644 --- a/app/assets/javascripts/issuable_context.js +++ b/app/assets/javascripts/issuable_context.js @@ -4,76 +4,72 @@ import Cookies from 'js-cookie'; import UsersSelect from './users_select'; -(function() { - this.IssuableContext = (function() { - function IssuableContext(currentUser) { - this.initParticipants(); - new UsersSelect(currentUser); - $('select.select2').select2({ - width: 'resolve', - dropdownAutoWidth: true - }); - $(".issuable-sidebar .inline-update").on("change", "select", function() { - return $(this).submit(); - }); - $(".issuable-sidebar .inline-update").on("change", ".js-assignee", function() { - return $(this).submit(); - }); - $(document).off('click', '.issuable-sidebar .dropdown-content a').on('click', '.issuable-sidebar .dropdown-content a', function(e) { - return e.preventDefault(); - }); - $(document).off('click', '.edit-link').on('click', '.edit-link', function(e) { - var $block, $selectbox; - e.preventDefault(); - $block = $(this).parents('.block'); - $selectbox = $block.find('.selectbox'); - if ($selectbox.is(':visible')) { - $selectbox.hide(); - $block.find('.value').show(); - } else { - $selectbox.show(); - $block.find('.value').hide(); - } - if ($selectbox.is(':visible')) { - return setTimeout(function() { - return $block.find('.dropdown-menu-toggle').trigger('click'); - }, 0); - } - }); - window.addEventListener('beforeunload', function() { - // collapsed_gutter cookie hides the sidebar - var bpBreakpoint = bp.getBreakpointSize(); - if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') { - Cookies.set('collapsed_gutter', true); - } - }); +function IssuableContext(currentUser) { + this.initParticipants(); + new UsersSelect(currentUser); + $('select.select2').select2({ + width: 'resolve', + dropdownAutoWidth: true + }); + $(".issuable-sidebar .inline-update").on("change", "select", function() { + return $(this).submit(); + }); + $(".issuable-sidebar .inline-update").on("change", ".js-assignee", function() { + return $(this).submit(); + }); + $(document).off('click', '.issuable-sidebar .dropdown-content a').on('click', '.issuable-sidebar .dropdown-content a', function(e) { + return e.preventDefault(); + }); + $(document).off('click', '.edit-link').on('click', '.edit-link', function(e) { + var $block, $selectbox; + e.preventDefault(); + $block = $(this).parents('.block'); + $selectbox = $block.find('.selectbox'); + if ($selectbox.is(':visible')) { + $selectbox.hide(); + $block.find('.value').show(); + } else { + $selectbox.show(); + $block.find('.value').hide(); } + if ($selectbox.is(':visible')) { + return setTimeout(function() { + return $block.find('.dropdown-menu-toggle').trigger('click'); + }, 0); + } + }); + window.addEventListener('beforeunload', function() { + // collapsed_gutter cookie hides the sidebar + var bpBreakpoint = bp.getBreakpointSize(); + if (bpBreakpoint === 'xs' || bpBreakpoint === 'sm') { + Cookies.set('collapsed_gutter', true); + } + }); +} - IssuableContext.prototype.initParticipants = function() { - var _this; - _this = this; - $(document).on("click", ".js-participants-more", this.toggleHiddenParticipants); - return $(".js-participants-author").each(function(i) { - if (i >= _this.PARTICIPANTS_ROW_COUNT) { - return $(this).addClass("js-participants-hidden").hide(); - } - }); - }; +IssuableContext.prototype.initParticipants = function() { + var _this; + _this = this; + $(document).on("click", ".js-participants-more", this.toggleHiddenParticipants); + return $(".js-participants-author").each(function(i) { + if (i >= _this.PARTICIPANTS_ROW_COUNT) { + return $(this).addClass("js-participants-hidden").hide(); + } + }); +}; - IssuableContext.prototype.toggleHiddenParticipants = function(e) { - var currentText, lessText, originalText; - e.preventDefault(); - currentText = $(this).text().trim(); - lessText = $(this).data("less-text"); - originalText = $(this).data("original-text"); - if (currentText === originalText) { - $(this).text(lessText); - } else { - $(this).text(originalText); - } - return $(".js-participants-hidden").toggle(); - }; +IssuableContext.prototype.toggleHiddenParticipants = function(e) { + var currentText, lessText, originalText; + e.preventDefault(); + currentText = $(this).text().trim(); + lessText = $(this).data("less-text"); + originalText = $(this).data("original-text"); + if (currentText === originalText) { + $(this).text(lessText); + } else { + $(this).text(originalText); + } + return $(".js-participants-hidden").toggle(); +}; - return IssuableContext; - })(); -}).call(window); +window.IssuableContext = IssuableContext; diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 9ac1325fc95..b43e60e1de8 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -8,153 +8,149 @@ import UsersSelect from './users_select'; import GfmAutoComplete from './gfm_auto_complete'; import ZenMode from './zen_mode'; -(function() { - this.IssuableForm = (function() { - IssuableForm.prototype.issueMoveConfirmMsg = 'Are you sure you want to move this issue to another project?'; - - IssuableForm.prototype.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i; - - function IssuableForm(form) { - var $issuableDueDate, calendar; - this.form = form; - this.toggleWip = this.toggleWip.bind(this); - this.renderWipExplanation = this.renderWipExplanation.bind(this); - this.resetAutosave = this.resetAutosave.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup(); - new UsersSelect(); - new ZenMode(); - this.titleField = this.form.find("input[name*='[title]']"); - this.descriptionField = this.form.find("textarea[name*='[description]']"); - this.issueMoveField = this.form.find("#move_to_project_id"); - if (!(this.titleField.length && this.descriptionField.length)) { - return; +function IssuableForm(form) { + var $issuableDueDate, calendar; + this.form = form; + this.toggleWip = this.toggleWip.bind(this); + this.renderWipExplanation = this.renderWipExplanation.bind(this); + this.resetAutosave = this.resetAutosave.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources).setup(); + new UsersSelect(); + new ZenMode(); + this.titleField = this.form.find("input[name*='[title]']"); + this.descriptionField = this.form.find("textarea[name*='[description]']"); + this.issueMoveField = this.form.find("#move_to_project_id"); + if (!(this.titleField.length && this.descriptionField.length)) { + return; + } + this.initAutosave(); + this.form.on("submit", this.handleSubmit); + this.form.on("click", ".btn-cancel", this.resetAutosave); + this.initWip(); + this.initMoveDropdown(); + $issuableDueDate = $('#issuable-due-date'); + if ($issuableDueDate.length) { + calendar = new Pikaday({ + field: $issuableDueDate.get(0), + theme: 'gitlab-theme animate-picker', + format: 'yyyy-mm-dd', + container: $issuableDueDate.parent().get(0), + onSelect: function(dateText) { + $issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); } - this.initAutosave(); - this.form.on("submit", this.handleSubmit); - this.form.on("click", ".btn-cancel", this.resetAutosave); - this.initWip(); - this.initMoveDropdown(); - $issuableDueDate = $('#issuable-due-date'); - if ($issuableDueDate.length) { - calendar = new Pikaday({ - field: $issuableDueDate.get(0), - theme: 'gitlab-theme animate-picker', - format: 'yyyy-mm-dd', - container: $issuableDueDate.parent().get(0), - onSelect: function(dateText) { - $issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); - } - }); - calendar.setDate(new Date($issuableDueDate.val())); - } - } + }); + calendar.setDate(new Date($issuableDueDate.val())); + } +} + +IssuableForm.prototype.issueMoveConfirmMsg = 'Are you sure you want to move this issue to another project?'; - IssuableForm.prototype.initAutosave = function() { - new Autosave(this.titleField, [document.location.pathname, document.location.search, "title"]); - return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, "description"]); - }; +IssuableForm.prototype.wipRegex = /^\s*(\[WIP\]\s*|WIP:\s*|WIP\s+)+\s*/i; - IssuableForm.prototype.handleSubmit = function() { - var fieldId = (this.issueMoveField != null) ? this.issueMoveField.val() : null; - if ((parseInt(fieldId, 10) || 0) > 0) { - if (!confirm(this.issueMoveConfirmMsg)) { - return false; +IssuableForm.prototype.initAutosave = function() { + new Autosave(this.titleField, [document.location.pathname, document.location.search, "title"]); + return new Autosave(this.descriptionField, [document.location.pathname, document.location.search, "description"]); +}; + +IssuableForm.prototype.handleSubmit = function() { + var fieldId = (this.issueMoveField != null) ? this.issueMoveField.val() : null; + if ((parseInt(fieldId, 10) || 0) > 0) { + if (!confirm(this.issueMoveConfirmMsg)) { + return false; + } + } + return this.resetAutosave(); +}; + +IssuableForm.prototype.resetAutosave = function() { + this.titleField.data("autosave").reset(); + return this.descriptionField.data("autosave").reset(); +}; + +IssuableForm.prototype.initWip = function() { + this.$wipExplanation = this.form.find(".js-wip-explanation"); + this.$noWipExplanation = this.form.find(".js-no-wip-explanation"); + if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) { + return; + } + this.form.on("click", ".js-toggle-wip", this.toggleWip); + this.titleField.on("keyup blur", this.renderWipExplanation); + return this.renderWipExplanation(); +}; + +IssuableForm.prototype.workInProgress = function() { + return this.wipRegex.test(this.titleField.val()); +}; + +IssuableForm.prototype.renderWipExplanation = function() { + if (this.workInProgress()) { + this.$wipExplanation.show(); + return this.$noWipExplanation.hide(); + } else { + this.$wipExplanation.hide(); + return this.$noWipExplanation.show(); + } +}; + +IssuableForm.prototype.toggleWip = function(event) { + event.preventDefault(); + if (this.workInProgress()) { + this.removeWip(); + } else { + this.addWip(); + } + return this.renderWipExplanation(); +}; + +IssuableForm.prototype.removeWip = function() { + return this.titleField.val(this.titleField.val().replace(this.wipRegex, "")); +}; + +IssuableForm.prototype.addWip = function() { + return this.titleField.val("WIP: " + (this.titleField.val())); +}; + +IssuableForm.prototype.initMoveDropdown = function() { + var $moveDropdown, pageSize; + $moveDropdown = $('.js-move-dropdown'); + if ($moveDropdown.length) { + pageSize = $moveDropdown.data('page-size'); + return $('.js-move-dropdown').select2({ + ajax: { + url: $moveDropdown.data('projects-url'), + quietMillis: 125, + data: function(term, page, context) { + return { + search: term, + offset_id: context + }; + }, + results: function(data) { + var context, + more; + + if (data.length >= pageSize) + more = true; + + if (data[data.length - 1]) + context = data[data.length - 1].id; + + return { + results: data, + more: more, + context: context + }; } + }, + formatResult: function(project) { + return project.name_with_namespace; + }, + formatSelection: function(project) { + return project.name_with_namespace; } - return this.resetAutosave(); - }; - - IssuableForm.prototype.resetAutosave = function() { - this.titleField.data("autosave").reset(); - return this.descriptionField.data("autosave").reset(); - }; - - IssuableForm.prototype.initWip = function() { - this.$wipExplanation = this.form.find(".js-wip-explanation"); - this.$noWipExplanation = this.form.find(".js-no-wip-explanation"); - if (!(this.$wipExplanation.length && this.$noWipExplanation.length)) { - return; - } - this.form.on("click", ".js-toggle-wip", this.toggleWip); - this.titleField.on("keyup blur", this.renderWipExplanation); - return this.renderWipExplanation(); - }; - - IssuableForm.prototype.workInProgress = function() { - return this.wipRegex.test(this.titleField.val()); - }; - - IssuableForm.prototype.renderWipExplanation = function() { - if (this.workInProgress()) { - this.$wipExplanation.show(); - return this.$noWipExplanation.hide(); - } else { - this.$wipExplanation.hide(); - return this.$noWipExplanation.show(); - } - }; - - IssuableForm.prototype.toggleWip = function(event) { - event.preventDefault(); - if (this.workInProgress()) { - this.removeWip(); - } else { - this.addWip(); - } - return this.renderWipExplanation(); - }; - - IssuableForm.prototype.removeWip = function() { - return this.titleField.val(this.titleField.val().replace(this.wipRegex, "")); - }; - - IssuableForm.prototype.addWip = function() { - return this.titleField.val("WIP: " + (this.titleField.val())); - }; - - IssuableForm.prototype.initMoveDropdown = function() { - var $moveDropdown, pageSize; - $moveDropdown = $('.js-move-dropdown'); - if ($moveDropdown.length) { - pageSize = $moveDropdown.data('page-size'); - return $('.js-move-dropdown').select2({ - ajax: { - url: $moveDropdown.data('projects-url'), - quietMillis: 125, - data: function(term, page, context) { - return { - search: term, - offset_id: context - }; - }, - results: function(data) { - var context, - more; - - if (data.length >= pageSize) - more = true; - - if (data[data.length - 1]) - context = data[data.length - 1].id; - - return { - results: data, - more: more, - context: context - }; - } - }, - formatResult: function(project) { - return project.name_with_namespace; - }, - formatSelection: function(project) { - return project.name_with_namespace; - } - }); - } - }; + }); + } +}; - return IssuableForm; - })(); -}).call(window); +window.IssuableForm = IssuableForm; diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index 5c96646def8..4f3f5e0527c 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -4,168 +4,166 @@ import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar'; import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; -((global) => { - var issuable_created; - - issuable_created = false; - - global.IssuableIndex = { - init: function(pagePrefix) { - IssuableIndex.initTemplates(); - IssuableIndex.initSearch(); - IssuableIndex.initBulkUpdate(pagePrefix); - IssuableIndex.initResetFilters(); - IssuableIndex.resetIncomingEmailToken(); - IssuableIndex.initLabelFilterRemove(); - }, - initTemplates: function() { - return IssuableIndex.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>'); - }, - initSearch: function() { - const $searchInput = $('#issuable_search'); - - IssuableIndex.initSearchState($searchInput); - - // `immediate` param set to false debounces on the `trailing` edge, lets user finish typing - const debouncedExecSearch = _.debounce(IssuableIndex.executeSearch, 1000, false); - - $searchInput.off('keyup').on('keyup', debouncedExecSearch); - - // ensures existing filters are preserved when manually submitted - $('#issuable_search_form').on('submit', (e) => { - e.preventDefault(); - debouncedExecSearch(e); - }); - }, - initSearchState: function($searchInput) { - const currentSearchVal = $searchInput.val(); - - IssuableIndex.searchState = { - elem: $searchInput, - current: currentSearchVal - }; - - IssuableIndex.maybeFocusOnSearch(); - }, - accessSearchPristine: function(set) { - // store reference to previous value to prevent search on non-mutating keyup - const state = IssuableIndex.searchState; - const currentSearchVal = state.elem.val(); - - if (set) { - state.current = currentSearchVal; +var issuable_created; + +issuable_created = false; + +window.IssuableIndex = { + init: function(pagePrefix) { + IssuableIndex.initTemplates(); + IssuableIndex.initSearch(); + IssuableIndex.initBulkUpdate(pagePrefix); + IssuableIndex.initResetFilters(); + IssuableIndex.resetIncomingEmailToken(); + IssuableIndex.initLabelFilterRemove(); + }, + initTemplates: function() { + return IssuableIndex.labelRow = _.template('<% _.each(labels, function(label){ %> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body"> <%- label.title %> </a> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>"> <i class="fa fa-times"></i> </button> </span> <% }); %>'); + }, + initSearch: function() { + const $searchInput = $('#issuable_search'); + + IssuableIndex.initSearchState($searchInput); + + // `immediate` param set to false debounces on the `trailing` edge, lets user finish typing + const debouncedExecSearch = _.debounce(IssuableIndex.executeSearch, 1000, false); + + $searchInput.off('keyup').on('keyup', debouncedExecSearch); + + // ensures existing filters are preserved when manually submitted + $('#issuable_search_form').on('submit', (e) => { + e.preventDefault(); + debouncedExecSearch(e); + }); + }, + initSearchState: function($searchInput) { + const currentSearchVal = $searchInput.val(); + + IssuableIndex.searchState = { + elem: $searchInput, + current: currentSearchVal + }; + + IssuableIndex.maybeFocusOnSearch(); + }, + accessSearchPristine: function(set) { + // store reference to previous value to prevent search on non-mutating keyup + const state = IssuableIndex.searchState; + const currentSearchVal = state.elem.val(); + + if (set) { + state.current = currentSearchVal; + } else { + return state.current === currentSearchVal; + } + }, + maybeFocusOnSearch: function() { + const currentSearchVal = IssuableIndex.searchState.current; + if (currentSearchVal && currentSearchVal !== '') { + const queryLength = currentSearchVal.length; + const $searchInput = IssuableIndex.searchState.elem; + + /* The following ensures that the cursor is initially placed at + * the end of search input when focus is applied. It accounts + * for differences in browser implementations of `setSelectionRange` + * and cursor placement for elements in focus. + */ + $searchInput.focus(); + if ($searchInput.setSelectionRange) { + $searchInput.setSelectionRange(queryLength, queryLength); } else { - return state.current === currentSearchVal; - } - }, - maybeFocusOnSearch: function() { - const currentSearchVal = IssuableIndex.searchState.current; - if (currentSearchVal && currentSearchVal !== '') { - const queryLength = currentSearchVal.length; - const $searchInput = IssuableIndex.searchState.elem; - - /* The following ensures that the cursor is initially placed at - * the end of search input when focus is applied. It accounts - * for differences in browser implementations of `setSelectionRange` - * and cursor placement for elements in focus. - */ - $searchInput.focus(); - if ($searchInput.setSelectionRange) { - $searchInput.setSelectionRange(queryLength, queryLength); - } else { - $searchInput.val(currentSearchVal); - } - } - }, - executeSearch: function(e) { - const $search = $('#issuable_search'); - const $searchName = $search.attr('name'); - const $searchValue = $search.val(); - const $filtersForm = $('.js-filter-form'); - const $input = $(`input[name='${$searchName}']`, $filtersForm); - const isPristine = IssuableIndex.accessSearchPristine(); - - if (isPristine) { - return; + $searchInput.val(currentSearchVal); } + } + }, + executeSearch: function(e) { + const $search = $('#issuable_search'); + const $searchName = $search.attr('name'); + const $searchValue = $search.val(); + const $filtersForm = $('.js-filter-form'); + const $input = $(`input[name='${$searchName}']`, $filtersForm); + const isPristine = IssuableIndex.accessSearchPristine(); + + if (isPristine) { + return; + } - if (!$input.length) { - $filtersForm.append(`<input type='hidden' name='${$searchName}' value='${_.escape($searchValue)}'/>`); - } else { - $input.val($searchValue); - } + if (!$input.length) { + $filtersForm.append(`<input type='hidden' name='${$searchName}' value='${_.escape($searchValue)}'/>`); + } else { + $input.val($searchValue); + } - IssuableIndex.filterResults($filtersForm); - }, - initLabelFilterRemove: function() { - return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) { - var $button; - $button = $(this); - // Remove the label input box - $('input[name="label_name[]"]').filter(function() { - return this.value === $button.data('label'); - }).remove(); - // Submit the form to get new data - IssuableIndex.filterResults($('.filter-form')); + IssuableIndex.filterResults($filtersForm); + }, + initLabelFilterRemove: function() { + return $(document).off('click', '.js-label-filter-remove').on('click', '.js-label-filter-remove', function(e) { + var $button; + $button = $(this); + // Remove the label input box + $('input[name="label_name[]"]').filter(function() { + return this.value === $button.data('label'); + }).remove(); + // Submit the form to get new data + IssuableIndex.filterResults($('.filter-form')); + }); + }, + filterResults: (function(_this) { + return function(form) { + var formAction, formData, issuesUrl; + formData = form.serializeArray(); + formData = formData.filter(function(data) { + return data.value !== ''; }); - }, - filterResults: (function(_this) { - return function(form) { - var formAction, formData, issuesUrl; - formData = form.serializeArray(); - formData = formData.filter(function(data) { - return data.value !== ''; - }); - formData = $.param(formData); - formAction = form.attr('action'); - issuesUrl = formAction; - issuesUrl += "" + (formAction.indexOf('?') === -1 ? '?' : '&'); - issuesUrl += formData; - return gl.utils.visitUrl(issuesUrl); - }; - })(this), - initResetFilters: function() { - $('.reset-filters').on('click', function(e) { - e.preventDefault(); - const target = e.target; - const $form = $(target).parents('.js-filter-form'); - const baseIssuesUrl = target.href; - - $form.attr('action', baseIssuesUrl); - gl.utils.visitUrl(baseIssuesUrl); + formData = $.param(formData); + formAction = form.attr('action'); + issuesUrl = formAction; + issuesUrl += "" + (formAction.indexOf('?') === -1 ? '?' : '&'); + issuesUrl += formData; + return gl.utils.visitUrl(issuesUrl); + }; + })(this), + initResetFilters: function() { + $('.reset-filters').on('click', function(e) { + e.preventDefault(); + const target = e.target; + const $form = $(target).parents('.js-filter-form'); + const baseIssuesUrl = target.href; + + $form.attr('action', baseIssuesUrl); + gl.utils.visitUrl(baseIssuesUrl); + }); + }, + initBulkUpdate: function(pagePrefix) { + const userCanBulkUpdate = $('.issues-bulk-update').length > 0; + const alreadyInitialized = !!this.bulkUpdateSidebar; + + if (userCanBulkUpdate && !alreadyInitialized) { + IssuableBulkUpdateActions.init({ + prefixId: pagePrefix, }); - }, - initBulkUpdate: function(pagePrefix) { - const userCanBulkUpdate = $('.issues-bulk-update').length > 0; - const alreadyInitialized = !!this.bulkUpdateSidebar; - if (userCanBulkUpdate && !alreadyInitialized) { - IssuableBulkUpdateActions.init({ - prefixId: pagePrefix, - }); - - this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar(); - } - }, - resetIncomingEmailToken: function() { - $('.incoming-email-token-reset').on('click', function(e) { - e.preventDefault(); - - $.ajax({ - type: 'PUT', - url: $('.incoming-email-token-reset').attr('href'), - dataType: 'json', - success: function(response) { - $('#issue_email').val(response.new_issue_address).focus(); - }, - beforeSend: function() { - $('.incoming-email-token-reset').text('resetting...'); - }, - complete: function() { - $('.incoming-email-token-reset').text('reset it'); - } - }); - }); + this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar(); } - }; -})(window); + }, + resetIncomingEmailToken: function() { + $('.incoming-email-token-reset').on('click', function(e) { + e.preventDefault(); + + $.ajax({ + type: 'PUT', + url: $('.incoming-email-token-reset').attr('href'), + dataType: 'json', + success: function(response) { + $('#issue_email').val(response.new_issue_address).focus(); + }, + beforeSend: function() { + $('.incoming-email-token-reset').text('resetting...'); + }, + complete: function() { + $('.incoming-email-token-reset').text('reset it'); + } + }); + }); + } +}; diff --git a/app/assets/javascripts/issue_status_select.js b/app/assets/javascripts/issue_status_select.js index 56cb536dcde..097939097cf 100644 --- a/app/assets/javascripts/issue_status_select.js +++ b/app/assets/javascripts/issue_status_select.js @@ -1,34 +1,31 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */ -(function() { - this.IssueStatusSelect = (function() { - function IssueStatusSelect() { - $('.js-issue-status').each(function(i, el) { - var fieldName; - fieldName = $(el).data("field-name"); - return $(el).glDropdown({ - selectable: true, - fieldName: fieldName, - toggleLabel: (function(_this) { - return function(selected, el, instance) { - var $item, label; - label = 'Author'; - $item = instance.dropdown.find('.is-active'); - if ($item.length) { - label = $item.text(); - } - return label; - }; - })(this), - clicked: function(options) { - return options.e.preventDefault(); - }, - id: function(obj, el) { - return $(el).data("id"); + +function IssueStatusSelect() { + $('.js-issue-status').each(function(i, el) { + var fieldName; + fieldName = $(el).data("field-name"); + return $(el).glDropdown({ + selectable: true, + fieldName: fieldName, + toggleLabel: (function(_this) { + return function(selected, el, instance) { + var $item, label; + label = 'Author'; + $item = instance.dropdown.find('.is-active'); + if ($item.length) { + label = $item.text(); } - }); - }); - } + return label; + }; + })(this), + clicked: function(options) { + return options.e.preventDefault(); + }, + id: function(obj, el) { + return $(el).data("id"); + } + }); + }); +} - return IssueStatusSelect; - })(); -}).call(window); +window.IssueStatusSelect = IssueStatusSelect; diff --git a/app/assets/javascripts/label_manager.js b/app/assets/javascripts/label_manager.js index d8814802d9e..4927abac4c1 100644 --- a/app/assets/javascripts/label_manager.js +++ b/app/assets/javascripts/label_manager.js @@ -1,124 +1,123 @@ /* eslint-disable comma-dangle, class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, consistent-return, func-names, space-before-function-paren, max-len */ /* global Flash */ /* global Sortable */ +const gl = window.gl || (window.gl = {}); -((global) => { - class LabelManager { - constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) { - this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority'); - this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels'); - this.otherLabels = otherLabels || $('.js-other-labels'); - this.errorMessage = 'Unable to update label prioritization at this time'; - this.emptyState = document.querySelector('#js-priority-labels-empty-state'); - this.sortable = Sortable.create(this.prioritizedLabels.get(0), { - filter: '.empty-message', - forceFallback: true, - fallbackClass: 'is-dragging', - dataIdAttr: 'data-id', - onUpdate: this.onPrioritySortUpdate.bind(this), - }); - this.bindEvents(); - } +class LabelManager { + constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) { + this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority'); + this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels'); + this.otherLabels = otherLabels || $('.js-other-labels'); + this.errorMessage = 'Unable to update label prioritization at this time'; + this.emptyState = document.querySelector('#js-priority-labels-empty-state'); + this.sortable = Sortable.create(this.prioritizedLabels.get(0), { + filter: '.empty-message', + forceFallback: true, + fallbackClass: 'is-dragging', + dataIdAttr: 'data-id', + onUpdate: this.onPrioritySortUpdate.bind(this), + }); + this.bindEvents(); + } - bindEvents() { - this.prioritizedLabels.find('.btn-action').on('mousedown', this, this.onButtonActionClick); - return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick); - } + bindEvents() { + this.prioritizedLabels.find('.btn-action').on('mousedown', this, this.onButtonActionClick); + return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick); + } - onTogglePriorityClick(e) { - e.preventDefault(); - const _this = e.data; - const $btn = $(e.currentTarget); - const $label = $(`#${$btn.data('domId')}`); - const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; - const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); - $tooltip.tooltip('destroy'); - _this.toggleLabelPriority($label, action); - _this.toggleEmptyState($label, $btn, action); - } + onTogglePriorityClick(e) { + e.preventDefault(); + const _this = e.data; + const $btn = $(e.currentTarget); + const $label = $(`#${$btn.data('domId')}`); + const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add'; + const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`); + $tooltip.tooltip('destroy'); + _this.toggleLabelPriority($label, action); + _this.toggleEmptyState($label, $btn, action); + } - onButtonActionClick(e) { - e.stopPropagation(); - $(e.currentTarget).tooltip('hide'); - } + onButtonActionClick(e) { + e.stopPropagation(); + $(e.currentTarget).tooltip('hide'); + } - toggleEmptyState($label, $btn, action) { - this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li')); - } + toggleEmptyState($label, $btn, action) { + this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li')); + } - toggleLabelPriority($label, action, persistState) { - if (persistState == null) { - persistState = true; - } - let xhr; - const _this = this; - const url = $label.find('.js-toggle-priority').data('url'); - let $target = this.prioritizedLabels; - let $from = this.otherLabels; - if (action === 'remove') { - $target = this.otherLabels; - $from = this.prioritizedLabels; - } - $label.detach().appendTo($target); - if ($from.find('li').length) { - $from.find('.empty-message').removeClass('hidden'); - } - if ($target.find('> li:not(.empty-message)').length) { - $target.find('.empty-message').addClass('hidden'); - } - // Return if we are not persisting state - if (!persistState) { - return; - } - if (action === 'remove') { - xhr = $.ajax({ - url, - type: 'DELETE' - }); - // Restore empty message - if (!$from.find('li').length) { - $from.find('.empty-message').removeClass('hidden'); - } - } else { - xhr = this.savePrioritySort($label, action); - } - return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action)); + toggleLabelPriority($label, action, persistState) { + if (persistState == null) { + persistState = true; } - - onPrioritySortUpdate() { - const xhr = this.savePrioritySort(); - return xhr.fail(function() { - return new Flash(this.errorMessage, 'alert'); - }); + let xhr; + const _this = this; + const url = $label.find('.js-toggle-priority').data('url'); + let $target = this.prioritizedLabels; + let $from = this.otherLabels; + if (action === 'remove') { + $target = this.otherLabels; + $from = this.prioritizedLabels; } - - savePrioritySort() { - return $.post({ - url: this.prioritizedLabels.data('url'), - data: { - label_ids: this.getSortedLabelsIds() - } + $label.detach().appendTo($target); + if ($from.find('li').length) { + $from.find('.empty-message').removeClass('hidden'); + } + if ($target.find('> li:not(.empty-message)').length) { + $target.find('.empty-message').addClass('hidden'); + } + // Return if we are not persisting state + if (!persistState) { + return; + } + if (action === 'remove') { + xhr = $.ajax({ + url, + type: 'DELETE' }); + // Restore empty message + if (!$from.find('li').length) { + $from.find('.empty-message').removeClass('hidden'); + } + } else { + xhr = this.savePrioritySort($label, action); } + return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action)); + } - rollbackLabelPosition($label, originalAction) { - const action = originalAction === 'remove' ? 'add' : 'remove'; - this.toggleLabelPriority($label, action, false); + onPrioritySortUpdate() { + const xhr = this.savePrioritySort(); + return xhr.fail(function() { return new Flash(this.errorMessage, 'alert'); - } + }); + } - getSortedLabelsIds() { - const sortedIds = []; - this.prioritizedLabels.find('> li').each(function() { - const id = $(this).data('id'); + savePrioritySort() { + return $.post({ + url: this.prioritizedLabels.data('url'), + data: { + label_ids: this.getSortedLabelsIds() + } + }); + } - if (id) { - sortedIds.push(id); - } - }); - return sortedIds; - } + rollbackLabelPosition($label, originalAction) { + const action = originalAction === 'remove' ? 'add' : 'remove'; + this.toggleLabelPriority($label, action, false); + return new Flash(this.errorMessage, 'alert'); + } + + getSortedLabelsIds() { + const sortedIds = []; + this.prioritizedLabels.find('> li').each(function() { + const id = $(this).data('id'); + + if (id) { + sortedIds.push(id); + } + }); + return sortedIds; } +} - gl.LabelManager = LabelManager; -})(window.gl || (window.gl = {})); +gl.LabelManager = LabelManager; diff --git a/app/assets/javascripts/labels.js b/app/assets/javascripts/labels.js index 03dd61b4263..5e87f26afba 100644 --- a/app/assets/javascripts/labels.js +++ b/app/assets/javascripts/labels.js @@ -1,44 +1,41 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, vars-on-top, no-unused-vars, max-len */ -(function() { - this.Labels = (function() { - function Labels() { - this.setSuggestedColor = this.setSuggestedColor.bind(this); - this.updateColorPreview = this.updateColorPreview.bind(this); - var form; - form = $('.label-form'); - this.cleanBinding(); - this.addBinding(); - this.updateColorPreview(); - } - Labels.prototype.addBinding = function() { - $(document).on('click', '.suggest-colors a', this.setSuggestedColor); - return $(document).on('input', 'input#label_color', this.updateColorPreview); - }; +function Labels() { + this.setSuggestedColor = this.setSuggestedColor.bind(this); + this.updateColorPreview = this.updateColorPreview.bind(this); + var form; + form = $('.label-form'); + this.cleanBinding(); + this.addBinding(); + this.updateColorPreview(); +} - Labels.prototype.cleanBinding = function() { - $(document).off('click', '.suggest-colors a'); - return $(document).off('input', 'input#label_color'); - }; +Labels.prototype.addBinding = function() { + $(document).on('click', '.suggest-colors a', this.setSuggestedColor); + return $(document).on('input', 'input#label_color', this.updateColorPreview); +}; - Labels.prototype.updateColorPreview = function() { - var previewColor; - previewColor = $('input#label_color').val(); - return $('div.label-color-preview').css('background-color', previewColor); - // Updates the the preview color with the hex-color input - }; +Labels.prototype.cleanBinding = function() { + $(document).off('click', '.suggest-colors a'); + return $(document).off('input', 'input#label_color'); +}; - // Updates the preview color with a click on a suggested color - Labels.prototype.setSuggestedColor = function(e) { - var color; - color = $(e.currentTarget).data('color'); - $('input#label_color').val(color); - this.updateColorPreview(); - // Notify the form, that color has changed - $('.label-form').trigger('keyup'); - return e.preventDefault(); - }; +Labels.prototype.updateColorPreview = function() { + var previewColor; + previewColor = $('input#label_color').val(); + return $('div.label-color-preview').css('background-color', previewColor); +// Updates the the preview color with the hex-color input +}; - return Labels; - })(); -}).call(window); +// Updates the preview color with a click on a suggested color +Labels.prototype.setSuggestedColor = function(e) { + var color; + color = $(e.currentTarget).data('color'); + $('input#label_color').val(color); + this.updateColorPreview(); + // Notify the form, that color has changed + $('.label-form').trigger('keyup'); + return e.preventDefault(); +}; + +window.Labels = Labels; diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 8d7d3d73571..1b0de126bff 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -4,492 +4,488 @@ import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; -(function() { - this.LabelsSelect = (function() { - function LabelsSelect(els) { - var _this, $els; - _this = this; +function LabelsSelect(els) { + var _this, $els; + _this = this; + + $els = $(els); + + if (!els) { + $els = $('.js-label-select'); + } + + $els.each(function(i, dropdown) { + var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, namespacePath, projectPath, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove, $container, $dropdownContainer; + $dropdown = $(dropdown); + $dropdownContainer = $dropdown.closest('.labels-filter'); + $toggleText = $dropdown.find('.dropdown-toggle-text'); + namespacePath = $dropdown.data('namespace-path'); + projectPath = $dropdown.data('project-path'); + labelUrl = $dropdown.data('labels'); + issueUpdateURL = $dropdown.data('issueUpdate'); + selectedLabel = $dropdown.data('selected'); + if ((selectedLabel != null) && !$dropdown.hasClass('js-multiselect')) { + selectedLabel = selectedLabel.split(','); + } + showNo = $dropdown.data('show-no'); + showAny = $dropdown.data('show-any'); + showMenuAbove = $dropdown.data('showMenuAbove'); + defaultLabel = $dropdown.data('default-label'); + abilityName = $dropdown.data('ability-name'); + $selectbox = $dropdown.closest('.selectbox'); + $block = $selectbox.closest('.block'); + $form = $dropdown.closest('form, .js-issuable-update'); + $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span'); + $sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip'); + $value = $block.find('.value'); + $loading = $block.find('.block-loading').fadeOut(); + fieldName = $dropdown.data('field-name'); + useId = $dropdown.is('.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown'); + propertyName = useId ? 'id' : 'title'; + initialSelected = $selectbox + .find('input[name="' + $dropdown.data('field-name') + '"]') + .map(function () { + return this.value; + }).get(); + if (issueUpdateURL != null) { + issueURLSplit = issueUpdateURL.split('/'); + } + if (issueUpdateURL) { + labelHTMLTemplate = _.template('<% _.each(labels, function(label){ %> <a href="<%- ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%- encodeURIComponent(label.title) %>"> <span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;"> <%- label.title %> </span> </a> <% }); %>'); + labelNoneHTMLTemplate = '<span class="no-value">None</span>'; + } - $els = $(els); + $sidebarLabelTooltip.tooltip(); - if (!els) { - $els = $('.js-label-select'); - } + if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) { + new gl.CreateLabelDropdown($dropdown.closest('.dropdown').find('.dropdown-new-label'), namespacePath, projectPath); + } - $els.each(function(i, dropdown) { - var $block, $colorPreview, $dropdown, $form, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, defaultLabel, enableLabelCreateButton, issueURLSplit, issueUpdateURL, labelHTMLTemplate, labelNoneHTMLTemplate, labelUrl, namespacePath, projectPath, saveLabelData, selectedLabel, showAny, showNo, $sidebarLabelTooltip, initialSelected, $toggleText, fieldName, useId, propertyName, showMenuAbove, $container, $dropdownContainer; - $dropdown = $(dropdown); - $dropdownContainer = $dropdown.closest('.labels-filter'); - $toggleText = $dropdown.find('.dropdown-toggle-text'); - namespacePath = $dropdown.data('namespace-path'); - projectPath = $dropdown.data('project-path'); - labelUrl = $dropdown.data('labels'); - issueUpdateURL = $dropdown.data('issueUpdate'); - selectedLabel = $dropdown.data('selected'); - if ((selectedLabel != null) && !$dropdown.hasClass('js-multiselect')) { - selectedLabel = selectedLabel.split(','); - } - showNo = $dropdown.data('show-no'); - showAny = $dropdown.data('show-any'); - showMenuAbove = $dropdown.data('showMenuAbove'); - defaultLabel = $dropdown.data('default-label'); - abilityName = $dropdown.data('ability-name'); - $selectbox = $dropdown.closest('.selectbox'); - $block = $selectbox.closest('.block'); - $form = $dropdown.closest('form, .js-issuable-update'); - $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span'); - $sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip'); - $value = $block.find('.value'); - $loading = $block.find('.block-loading').fadeOut(); - fieldName = $dropdown.data('field-name'); - useId = $dropdown.is('.js-issuable-form-dropdown, .js-filter-bulk-update, .js-label-sidebar-dropdown'); - propertyName = useId ? 'id' : 'title'; - initialSelected = $selectbox - .find('input[name="' + $dropdown.data('field-name') + '"]') - .map(function () { - return this.value; - }).get(); - if (issueUpdateURL != null) { - issueURLSplit = issueUpdateURL.split('/'); - } - if (issueUpdateURL) { - labelHTMLTemplate = _.template('<% _.each(labels, function(label){ %> <a href="<%- ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%- encodeURIComponent(label.title) %>"> <span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;"> <%- label.title %> </span> </a> <% }); %>'); - labelNoneHTMLTemplate = '<span class="no-value">None</span>'; - } + saveLabelData = function() { + var data, selected; + selected = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "']").map(function() { + return this.value; + }).get(); - $sidebarLabelTooltip.tooltip(); + if (_.isEqual(initialSelected, selected)) return; + initialSelected = selected; - if ($dropdown.closest('.dropdown').find('.dropdown-new-label').length) { - new gl.CreateLabelDropdown($dropdown.closest('.dropdown').find('.dropdown-new-label'), namespacePath, projectPath); + data = {}; + data[abilityName] = {}; + data[abilityName].label_ids = selected; + if (!selected.length) { + data[abilityName].label_ids = ['']; + } + $loading.removeClass('hidden').fadeIn(); + $dropdown.trigger('loading.gl.dropdown'); + return $.ajax({ + type: 'PUT', + url: issueUpdateURL, + dataType: 'JSON', + data: data + }).done(function(data) { + var labelCount, template, labelTooltipTitle, labelTitles; + $loading.fadeOut(); + $dropdown.trigger('loaded.gl.dropdown'); + $selectbox.hide(); + data.issueURLSplit = issueURLSplit; + labelCount = 0; + if (data.labels.length) { + template = labelHTMLTemplate(data); + labelCount = data.labels.length; } + else { + template = labelNoneHTMLTemplate; + } + $value.removeAttr('style').html(template); + $sidebarCollapsedValue.text(labelCount); - saveLabelData = function() { - var data, selected; - selected = $dropdown.closest('.selectbox').find("input[name='" + fieldName + "']").map(function() { - return this.value; - }).get(); - - if (_.isEqual(initialSelected, selected)) return; - initialSelected = selected; + if (data.labels.length) { + labelTitles = data.labels.map(function(label) { + return label.title; + }); - data = {}; - data[abilityName] = {}; - data[abilityName].label_ids = selected; - if (!selected.length) { - data[abilityName].label_ids = ['']; + if (labelTitles.length > 5) { + labelTitles = labelTitles.slice(0, 5); + labelTitles.push('and ' + (data.labels.length - 5) + ' more'); } - $loading.removeClass('hidden').fadeIn(); - $dropdown.trigger('loading.gl.dropdown'); - return $.ajax({ - type: 'PUT', - url: issueUpdateURL, - dataType: 'JSON', - data: data - }).done(function(data) { - var labelCount, template, labelTooltipTitle, labelTitles; - $loading.fadeOut(); - $dropdown.trigger('loaded.gl.dropdown'); - $selectbox.hide(); - data.issueURLSplit = issueURLSplit; - labelCount = 0; - if (data.labels.length) { - template = labelHTMLTemplate(data); - labelCount = data.labels.length; - } - else { - template = labelNoneHTMLTemplate; - } - $value.removeAttr('style').html(template); - $sidebarCollapsedValue.text(labelCount); - - if (data.labels.length) { - labelTitles = data.labels.map(function(label) { - return label.title; - }); - - if (labelTitles.length > 5) { - labelTitles = labelTitles.slice(0, 5); - labelTitles.push('and ' + (data.labels.length - 5) + ' more'); - } - labelTooltipTitle = labelTitles.join(', '); - } - else { - labelTooltipTitle = ''; - $sidebarLabelTooltip.tooltip('destroy'); - } + labelTooltipTitle = labelTitles.join(', '); + } + else { + labelTooltipTitle = ''; + $sidebarLabelTooltip.tooltip('destroy'); + } - $sidebarLabelTooltip - .attr('title', labelTooltipTitle) - .tooltip('fixTitle'); + $sidebarLabelTooltip + .attr('title', labelTooltipTitle) + .tooltip('fixTitle'); - $('.has-tooltip', $value).tooltip({ - container: 'body' - }); - return $value.find('a').each(function(i) { - return setTimeout((function(_this) { - return function() { - return gl.animate.animate($(_this), 'pulse'); - }; - })(this), 200 * i); - }); - }); - }; - $dropdown.glDropdown({ - showMenuAbove: showMenuAbove, - data: function(term, callback) { - return $.ajax({ - url: labelUrl - }).done(function(data) { - data = _.chain(data).groupBy(function(label) { - return label.title; - }).map(function(label) { - var color; - color = _.map(label, function(dup) { - return dup.color; - }); - return { - id: label[0].id, - title: label[0].title, - color: color, - duplicate: color.length > 1 - }; - }).value(); - if ($dropdown.hasClass('js-extra-options')) { - var extraData = []; - if (showNo) { - extraData.unshift({ - id: 0, - title: 'No Label' - }); - } - if (showAny) { - extraData.unshift({ - isAny: true, - title: 'Any Label' - }); - } - if (extraData.length) { - extraData.push('divider'); - data = extraData.concat(data); - } - } - - callback(data); - if (showMenuAbove) { - $dropdown.data('glDropdown').positionMenuAbove(); - } + $('.has-tooltip', $value).tooltip({ + container: 'body' + }); + return $value.find('a').each(function(i) { + return setTimeout((function(_this) { + return function() { + return gl.animate.animate($(_this), 'pulse'); + }; + })(this), 200 * i); + }); + }); + }; + $dropdown.glDropdown({ + showMenuAbove: showMenuAbove, + data: function(term, callback) { + return $.ajax({ + url: labelUrl + }).done(function(data) { + data = _.chain(data).groupBy(function(label) { + return label.title; + }).map(function(label) { + var color; + color = _.map(label, function(dup) { + return dup.color; }); - }, - renderRow: function(label, instance) { - var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue; - $li = $('<li>'); - $a = $('<a href="#">'); - selectedClass = []; - removesAll = label.id <= 0 || (label.id == null); - if ($dropdown.hasClass('js-filter-bulk-update')) { - indeterminate = $dropdown.data('indeterminate') || []; - marked = $dropdown.data('marked') || []; - - if (indeterminate.indexOf(label.id) !== -1) { - selectedClass.push('is-indeterminate'); - } - - if (marked.indexOf(label.id) !== -1) { - // Remove is-indeterminate class if the item will be marked as active - i = selectedClass.indexOf('is-indeterminate'); - if (i !== -1) { - selectedClass.splice(i, 1); - } - selectedClass.push('is-active'); - } - } else { - if (this.id(label)) { - dropdownName = $dropdown.data('fieldName'); - dropdownValue = this.id(label).toString().replace(/'/g, '\\\''); - - if ($form.find("input[type='hidden'][name='" + dropdownName + "'][value='" + dropdownValue + "']").length) { - selectedClass.push('is-active'); - } - } - - if ($dropdown.hasClass('js-multiselect') && removesAll) { - selectedClass.push('dropdown-clear-active'); - } - } - if (label.duplicate) { - spacing = 100 / label.color.length; - // Reduce the colors to 4 - label.color = label.color.filter(function(color, i) { - return i < 4; + return { + id: label[0].id, + title: label[0].title, + color: color, + duplicate: color.length > 1 + }; + }).value(); + if ($dropdown.hasClass('js-extra-options')) { + var extraData = []; + if (showNo) { + extraData.unshift({ + id: 0, + title: 'No Label' }); - color = _.map(label.color, function(color, i) { - var percentFirst, percentSecond; - percentFirst = Math.floor(spacing * i); - percentSecond = Math.floor(spacing * (i + 1)); - return color + " " + percentFirst + "%," + color + " " + percentSecond + "% "; - }).join(','); - color = "linear-gradient(" + color + ")"; - } - else { - if (label.color != null) { - color = label.color[0]; - } - } - if (color) { - colorEl = "<span class='dropdown-label-box' style='background: " + color + "'></span>"; - } - else { - colorEl = ''; - } - // We need to identify which items are actually labels - if (label.id) { - selectedClass.push('label-item'); - $a.attr('data-label-id', label.id); - } - $a.addClass(selectedClass.join(' ')).html(colorEl + " " + label.title); - // Return generated html - return $li.html($a).prop('outerHTML'); - }, - search: { - fields: ['title'] - }, - selectable: true, - filterable: true, - selected: $dropdown.data('selected') || [], - toggleLabel: function(selected, el) { - var isSelected = el !== null ? el.hasClass('is-active') : false; - var title = selected.title; - var selectedLabels = this.selected; - - if (selected.id === 0) { - this.selected = []; - return 'No Label'; - } - else if (isSelected) { - this.selected.push(title); - } - else { - var index = this.selected.indexOf(title); - this.selected.splice(index, 1); - } - - if (selectedLabels.length === 1) { - return selectedLabels; - } - else if (selectedLabels.length) { - return selectedLabels[0] + " +" + (selectedLabels.length - 1) + " more"; - } - else { - return defaultLabel; - } - }, - fieldName: $dropdown.data('field-name'), - id: function(label) { - if (label.id <= 0) return label.title; - - if ($dropdown.hasClass('js-issuable-form-dropdown')) { - return label.id; } - - if ($dropdown.hasClass("js-filter-submit") && (label.isAny == null)) { - return label.title; - } - else { - return label.id; - } - }, - hidden: function() { - var isIssueIndex, isMRIndex, page, selectedLabels; - page = $('body').data('page'); - isIssueIndex = page === 'projects:issues:index'; - isMRIndex = page === 'projects:merge_requests:index'; - $selectbox.hide(); - // display:block overrides the hide-collapse rule - $value.removeAttr('style'); - - if ($dropdown.hasClass('js-issuable-form-dropdown')) { - return; - } - - if ($('html').hasClass('issue-boards-page')) { - return; + if (showAny) { + extraData.unshift({ + isAny: true, + title: 'Any Label' + }); } - if ($dropdown.hasClass('js-multiselect')) { - if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { - selectedLabels = $dropdown.closest('form').find("input:hidden[name='" + ($dropdown.data('fieldName')) + "']"); - Issuable.filterResults($dropdown.closest('form')); - } - else if ($dropdown.hasClass('js-filter-submit')) { - $dropdown.closest('form').submit(); - } - else { - if (!$dropdown.hasClass('js-filter-bulk-update')) { - saveLabelData(); - } - } + if (extraData.length) { + extraData.push('divider'); + data = extraData.concat(data); } - }, - multiSelect: $dropdown.hasClass('js-multiselect'), - vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(options) { - const { $el, e, isMarking } = options; - const label = options.selectedObj; - - var isIssueIndex, isMRIndex, page, boardsModel; - var fadeOutLoader = () => { - $loading.fadeOut(); - }; + } - page = $('body').data('page'); - isIssueIndex = page === 'projects:issues:index'; - isMRIndex = page === 'projects:merge_requests:index'; + callback(data); + if (showMenuAbove) { + $dropdown.data('glDropdown').positionMenuAbove(); + } + }); + }, + renderRow: function(label, instance) { + var $a, $li, color, colorEl, indeterminate, removesAll, selectedClass, spacing, i, marked, dropdownName, dropdownValue; + $li = $('<li>'); + $a = $('<a href="#">'); + selectedClass = []; + removesAll = label.id <= 0 || (label.id == null); + if ($dropdown.hasClass('js-filter-bulk-update')) { + indeterminate = $dropdown.data('indeterminate') || []; + marked = $dropdown.data('marked') || []; + + if (indeterminate.indexOf(label.id) !== -1) { + selectedClass.push('is-indeterminate'); + } - if ($dropdown.parent().find('.is-active:not(.dropdown-clear-active)').length) { - $dropdown.parent() - .find('.dropdown-clear-active') - .removeClass('is-active'); + if (marked.indexOf(label.id) !== -1) { + // Remove is-indeterminate class if the item will be marked as active + i = selectedClass.indexOf('is-indeterminate'); + if (i !== -1) { + selectedClass.splice(i, 1); } + selectedClass.push('is-active'); + } + } else { + if (this.id(label)) { + dropdownName = $dropdown.data('fieldName'); + dropdownValue = this.id(label).toString().replace(/'/g, '\\\''); - if ($dropdown.hasClass('js-issuable-form-dropdown')) { - return; + if ($form.find("input[type='hidden'][name='" + dropdownName + "'][value='" + dropdownValue + "']").length) { + selectedClass.push('is-active'); } + } - if ($dropdown.hasClass('js-filter-bulk-update')) { - _this.enableBulkLabelDropdown(); - _this.setDropdownData($dropdown, isMarking, label.id); - return; - } + if ($dropdown.hasClass('js-multiselect') && removesAll) { + selectedClass.push('dropdown-clear-active'); + } + } + if (label.duplicate) { + spacing = 100 / label.color.length; + // Reduce the colors to 4 + label.color = label.color.filter(function(color, i) { + return i < 4; + }); + color = _.map(label.color, function(color, i) { + var percentFirst, percentSecond; + percentFirst = Math.floor(spacing * i); + percentSecond = Math.floor(spacing * (i + 1)); + return color + " " + percentFirst + "%," + color + " " + percentSecond + "% "; + }).join(','); + color = "linear-gradient(" + color + ")"; + } + else { + if (label.color != null) { + color = label.color[0]; + } + } + if (color) { + colorEl = "<span class='dropdown-label-box' style='background: " + color + "'></span>"; + } + else { + colorEl = ''; + } + // We need to identify which items are actually labels + if (label.id) { + selectedClass.push('label-item'); + $a.attr('data-label-id', label.id); + } + $a.addClass(selectedClass.join(' ')).html(colorEl + " " + label.title); + // Return generated html + return $li.html($a).prop('outerHTML'); + }, + search: { + fields: ['title'] + }, + selectable: true, + filterable: true, + selected: $dropdown.data('selected') || [], + toggleLabel: function(selected, el) { + var isSelected = el !== null ? el.hasClass('is-active') : false; + var title = selected.title; + var selectedLabels = this.selected; + + if (selected.id === 0) { + this.selected = []; + return 'No Label'; + } + else if (isSelected) { + this.selected.push(title); + } + else { + var index = this.selected.indexOf(title); + this.selected.splice(index, 1); + } - if ($dropdown.closest('.add-issues-modal').length) { - boardsModel = gl.issueBoards.ModalStore.store.filter; - } + if (selectedLabels.length === 1) { + return selectedLabels; + } + else if (selectedLabels.length) { + return selectedLabels[0] + " +" + (selectedLabels.length - 1) + " more"; + } + else { + return defaultLabel; + } + }, + fieldName: $dropdown.data('field-name'), + id: function(label) { + if (label.id <= 0) return label.title; - if (boardsModel) { - if (label.isAny) { - boardsModel['label_name'] = []; - } else if ($el.hasClass('is-active')) { - boardsModel['label_name'].push(label.title); - } + if ($dropdown.hasClass('js-issuable-form-dropdown')) { + return label.id; + } - e.preventDefault(); - return; - } - else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { - if (!$dropdown.hasClass('js-multiselect')) { - selectedLabel = label.title; - return Issuable.filterResults($dropdown.closest('form')); - } - } - else if ($dropdown.hasClass('js-filter-submit')) { - return $dropdown.closest('form').submit(); - } - else if ($dropdown.hasClass('js-issue-board-sidebar')) { - if ($el.hasClass('is-active')) { - gl.issueBoards.BoardsStore.detail.issue.labels.push(new ListLabel({ - id: label.id, - title: label.title, - color: label.color[0], - textColor: '#fff' - })); - } - else { - var labels = gl.issueBoards.BoardsStore.detail.issue.labels; - labels = labels.filter(function (selectedLabel) { - return selectedLabel.id !== label.id; - }); - gl.issueBoards.BoardsStore.detail.issue.labels = labels; - } - - $loading.fadeIn(); - - gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) - .then(fadeOutLoader) - .catch(fadeOutLoader); - } - else { - if ($dropdown.hasClass('js-multiselect')) { + if ($dropdown.hasClass("js-filter-submit") && (label.isAny == null)) { + return label.title; + } + else { + return label.id; + } + }, + hidden: function() { + var isIssueIndex, isMRIndex, page, selectedLabels; + page = $('body').data('page'); + isIssueIndex = page === 'projects:issues:index'; + isMRIndex = page === 'projects:merge_requests:index'; + $selectbox.hide(); + // display:block overrides the hide-collapse rule + $value.removeAttr('style'); + + if ($dropdown.hasClass('js-issuable-form-dropdown')) { + return; + } - } - else { - return saveLabelData(); - } + if ($('html').hasClass('issue-boards-page')) { + return; + } + if ($dropdown.hasClass('js-multiselect')) { + if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { + selectedLabels = $dropdown.closest('form').find("input:hidden[name='" + ($dropdown.data('fieldName')) + "']"); + Issuable.filterResults($dropdown.closest('form')); + } + else if ($dropdown.hasClass('js-filter-submit')) { + $dropdown.closest('form').submit(); + } + else { + if (!$dropdown.hasClass('js-filter-bulk-update')) { + saveLabelData(); } - }, - }); - - // Set dropdown data - _this.setOriginalDropdownData($dropdownContainer, $dropdown); - }); - this.bindEvents(); - } + } + } + }, + multiSelect: $dropdown.hasClass('js-multiselect'), + vue: $dropdown.hasClass('js-issue-board-sidebar'), + clicked: function(options) { + const { $el, e, isMarking } = options; + const label = options.selectedObj; + + var isIssueIndex, isMRIndex, page, boardsModel; + var fadeOutLoader = () => { + $loading.fadeOut(); + }; - LabelsSelect.prototype.bindEvents = function() { - return $('body').on('change', '.selected_issue', this.onSelectCheckboxIssue); - }; + page = $('body').data('page'); + isIssueIndex = page === 'projects:issues:index'; + isMRIndex = page === 'projects:merge_requests:index'; - LabelsSelect.prototype.onSelectCheckboxIssue = function() { - if ($('.selected_issue:checked').length) { - return; - } - return $('.issues-bulk-update .labels-filter .dropdown-toggle-text').text('Label'); - }; + if ($dropdown.parent().find('.is-active:not(.dropdown-clear-active)').length) { + $dropdown.parent() + .find('.dropdown-clear-active') + .removeClass('is-active'); + } - LabelsSelect.prototype.enableBulkLabelDropdown = function() { - IssuableBulkUpdateActions.willUpdateLabels = true; - }; + if ($dropdown.hasClass('js-issuable-form-dropdown')) { + return; + } - LabelsSelect.prototype.setDropdownData = function($dropdown, isMarking, value) { - var i, markedIds, unmarkedIds, indeterminateIds; + if ($dropdown.hasClass('js-filter-bulk-update')) { + _this.enableBulkLabelDropdown(); + _this.setDropdownData($dropdown, isMarking, label.id); + return; + } - markedIds = $dropdown.data('marked') || []; - unmarkedIds = $dropdown.data('unmarked') || []; - indeterminateIds = $dropdown.data('indeterminate') || []; + if ($dropdown.closest('.add-issues-modal').length) { + boardsModel = gl.issueBoards.ModalStore.store.filter; + } - if (isMarking) { - markedIds.push(value); + if (boardsModel) { + if (label.isAny) { + boardsModel['label_name'] = []; + } else if ($el.hasClass('is-active')) { + boardsModel['label_name'].push(label.title); + } - i = indeterminateIds.indexOf(value); - if (i > -1) { - indeterminateIds.splice(i, 1); + e.preventDefault(); + return; } - - i = unmarkedIds.indexOf(value); - if (i > -1) { - unmarkedIds.splice(i, 1); + else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { + if (!$dropdown.hasClass('js-multiselect')) { + selectedLabel = label.title; + return Issuable.filterResults($dropdown.closest('form')); + } } - } else { - // If marked item (not common) is unmarked - i = markedIds.indexOf(value); - if (i > -1) { - markedIds.splice(i, 1); + else if ($dropdown.hasClass('js-filter-submit')) { + return $dropdown.closest('form').submit(); } + else if ($dropdown.hasClass('js-issue-board-sidebar')) { + if ($el.hasClass('is-active')) { + gl.issueBoards.BoardsStore.detail.issue.labels.push(new ListLabel({ + id: label.id, + title: label.title, + color: label.color[0], + textColor: '#fff' + })); + } + else { + var labels = gl.issueBoards.BoardsStore.detail.issue.labels; + labels = labels.filter(function (selectedLabel) { + return selectedLabel.id !== label.id; + }); + gl.issueBoards.BoardsStore.detail.issue.labels = labels; + } - // If an indeterminate item is being unmarked - if (IssuableBulkUpdateActions.getOriginalIndeterminateIds().indexOf(value) > -1) { - unmarkedIds.push(value); + $loading.fadeIn(); + + gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) + .then(fadeOutLoader) + .catch(fadeOutLoader); } + else { + if ($dropdown.hasClass('js-multiselect')) { - // If a marked item is being unmarked - // (a marked item could also be a label that is present in all selection) - if (IssuableBulkUpdateActions.getOriginalCommonIds().indexOf(value) > -1) { - unmarkedIds.push(value); + } + else { + return saveLabelData(); + } } - } + }, + }); + + // Set dropdown data + _this.setOriginalDropdownData($dropdownContainer, $dropdown); + }); + this.bindEvents(); +} + +LabelsSelect.prototype.bindEvents = function() { + return $('body').on('change', '.selected_issue', this.onSelectCheckboxIssue); +}; + +LabelsSelect.prototype.onSelectCheckboxIssue = function() { + if ($('.selected_issue:checked').length) { + return; + } + return $('.issues-bulk-update .labels-filter .dropdown-toggle-text').text('Label'); +}; + +LabelsSelect.prototype.enableBulkLabelDropdown = function() { + IssuableBulkUpdateActions.willUpdateLabels = true; +}; + +LabelsSelect.prototype.setDropdownData = function($dropdown, isMarking, value) { + var i, markedIds, unmarkedIds, indeterminateIds; + + markedIds = $dropdown.data('marked') || []; + unmarkedIds = $dropdown.data('unmarked') || []; + indeterminateIds = $dropdown.data('indeterminate') || []; + + if (isMarking) { + markedIds.push(value); + + i = indeterminateIds.indexOf(value); + if (i > -1) { + indeterminateIds.splice(i, 1); + } - $dropdown.data('marked', markedIds); - $dropdown.data('unmarked', unmarkedIds); - $dropdown.data('indeterminate', indeterminateIds); - }; + i = unmarkedIds.indexOf(value); + if (i > -1) { + unmarkedIds.splice(i, 1); + } + } else { + // If marked item (not common) is unmarked + i = markedIds.indexOf(value); + if (i > -1) { + markedIds.splice(i, 1); + } - LabelsSelect.prototype.setOriginalDropdownData = function($container, $dropdown) { - var labels = []; - $container.find('[name="label_name[]"]').map(function() { - return labels.push(this.value); - }); - $dropdown.data('marked', labels); - }; + // If an indeterminate item is being unmarked + if (IssuableBulkUpdateActions.getOriginalIndeterminateIds().indexOf(value) > -1) { + unmarkedIds.push(value); + } - return LabelsSelect; - })(); -}).call(window); + // If a marked item is being unmarked + // (a marked item could also be a label that is present in all selection) + if (IssuableBulkUpdateActions.getOriginalCommonIds().indexOf(value) > -1) { + unmarkedIds.push(value); + } + } + + $dropdown.data('marked', markedIds); + $dropdown.data('unmarked', unmarkedIds); + $dropdown.data('indeterminate', indeterminateIds); +}; + +LabelsSelect.prototype.setOriginalDropdownData = function($container, $dropdown) { + var labels = []; + $container.find('[name="label_name[]"]').map(function() { + return labels.push(this.value); + }); + $dropdown.data('marked', labels); +}; + +window.LabelsSelect = LabelsSelect; diff --git a/app/assets/javascripts/layout_nav.js b/app/assets/javascripts/layout_nav.js index 71064ccc539..db6ab6f83b6 100644 --- a/app/assets/javascripts/layout_nav.js +++ b/app/assets/javascripts/layout_nav.js @@ -1,58 +1,56 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, no-unused-vars, one-var, one-var-declaration-per-line, vars-on-top, max-len */ import _ from 'underscore'; -(function() { - var hideEndFade; - - hideEndFade = function($scrollingTabs) { - return $scrollingTabs.each(function() { - var $this; - $this = $(this); - return $this.siblings('.fade-right').toggleClass('scrolling', $this.width() < $this.prop('scrollWidth')); - }); - }; - - $(document).on('init.scrolling-tabs', () => { - const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized'); - $scrollingTabs.addClass('is-initialized'); - - hideEndFade($scrollingTabs); - $(window).off('resize.nav').on('resize.nav', function() { - return hideEndFade($scrollingTabs); - }); - $scrollingTabs.off('scroll').on('scroll', function(event) { - var $this, currentPosition, maxPosition; - $this = $(this); - currentPosition = $this.scrollLeft(); - maxPosition = $this.prop('scrollWidth') - $this.outerWidth(); - $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0); - return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1); - }); - - $scrollingTabs.each(function () { - var $this = $(this); - var scrollingTabWidth = $this.width(); - var $active = $this.find('.active'); - var activeWidth = $active.width(); - - if ($active.length) { - var offset = $active.offset().left + activeWidth; - - if (offset > scrollingTabWidth - 30) { - var scrollLeft = scrollingTabWidth / 2; - scrollLeft = (offset - scrollLeft) - (activeWidth / 2); - $this.scrollLeft(scrollLeft); - } - } - }); +var hideEndFade; + +hideEndFade = function($scrollingTabs) { + return $scrollingTabs.each(function() { + var $this; + $this = $(this); + return $this.siblings('.fade-right').toggleClass('scrolling', $this.width() < $this.prop('scrollWidth')); + }); +}; + +$(document).on('init.scrolling-tabs', () => { + const $scrollingTabs = $('.scrolling-tabs').not('.is-initialized'); + $scrollingTabs.addClass('is-initialized'); + + hideEndFade($scrollingTabs); + $(window).off('resize.nav').on('resize.nav', function() { + return hideEndFade($scrollingTabs); }); + $scrollingTabs.off('scroll').on('scroll', function(event) { + var $this, currentPosition, maxPosition; + $this = $(this); + currentPosition = $this.scrollLeft(); + maxPosition = $this.prop('scrollWidth') - $this.outerWidth(); + $this.siblings('.fade-left').toggleClass('scrolling', currentPosition > 0); + return $this.siblings('.fade-right').toggleClass('scrolling', currentPosition < maxPosition - 1); + }); + + $scrollingTabs.each(function () { + var $this = $(this); + var scrollingTabWidth = $this.width(); + var $active = $this.find('.active'); + var activeWidth = $active.width(); - function applyScrollNavClass() { - const scrollOpacityHeight = 40; - $('.navbar-border').css('opacity', Math.min($(window).scrollTop() / scrollOpacityHeight, 1)); - } + if ($active.length) { + var offset = $active.offset().left + activeWidth; - $(() => { - $(window).on('scroll', _.throttle(applyScrollNavClass, 100)); + if (offset > scrollingTabWidth - 30) { + var scrollLeft = scrollingTabWidth / 2; + scrollLeft = (offset - scrollLeft) - (activeWidth / 2); + $this.scrollLeft(scrollLeft); + } + } }); -}).call(window); +}); + +function applyScrollNavClass() { + const scrollOpacityHeight = 40; + $('.navbar-border').css('opacity', Math.min($(window).scrollTop() / scrollOpacityHeight, 1)); +} + +$(() => { + $(window).on('scroll', _.throttle(applyScrollNavClass, 100)); +}); diff --git a/app/assets/javascripts/lib/utils/animate.js b/app/assets/javascripts/lib/utils/animate.js index d93c1d0da59..a081e003891 100644 --- a/app/assets/javascripts/lib/utils/animate.js +++ b/app/assets/javascripts/lib/utils/animate.js @@ -1,49 +1,45 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, no-void, prefer-template, no-var, new-cap, prefer-arrow-callback, consistent-return, max-len */ -(function() { - (function(w) { - if (w.gl == null) { - w.gl = {}; +const w = window; + +if (w.gl == null) { + w.gl = {}; +} +if (gl.animate == null) { + gl.animate = {}; +} +gl.animate.animate = function($el, animation, options, done) { + if ((options != null ? options.cssStart : void 0) != null) { + $el.css(options.cssStart); + } + $el.removeClass(animation + ' animated').addClass(animation + ' animated').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() { + $(this).removeClass(animation + ' animated'); + if (done != null) { + done(); } - if (gl.animate == null) { - gl.animate = {}; + if ((options != null ? options.cssEnd : void 0) != null) { + $el.css(options.cssEnd); } - gl.animate.animate = function($el, animation, options, done) { - if ((options != null ? options.cssStart : void 0) != null) { - $el.css(options.cssStart); - } - $el.removeClass(animation + ' animated').addClass(animation + ' animated').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() { - $(this).removeClass(animation + ' animated'); - if (done != null) { - done(); + }); +}; +gl.animate.animateEach = function($els, animation, time, options, done) { + var dfd; + dfd = $.Deferred(); + if (!$els.length) { + dfd.resolve(); + } + $els.each(function(i) { + setTimeout(function() { + var $this; + $this = $(this); + return gl.animate.animate($this, animation, options, function() { + if (i === $els.length - 1) { + dfd.resolve(); + if (done != null) { + return done(); + } } - if ((options != null ? options.cssEnd : void 0) != null) { - $el.css(options.cssEnd); - } - }); - }; - gl.animate.animateEach = function($els, animation, time, options, done) { - var dfd; - dfd = $.Deferred(); - if (!$els.length) { - dfd.resolve(); - } - $els.each(function(i) { - setTimeout((function(_this) { - return function() { - var $this; - $this = $(_this); - return gl.animate.animate($this, animation, options, function() { - if (i === $els.length - 1) { - dfd.resolve(); - if (done != null) { - return done(); - } - } - }); - }; - })(this), time * i); }); - return dfd.promise(); - }; - })(window); -}).call(window); + }.bind(this), time * i); + }); + return dfd.promise(); +}; diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 122ec138c59..1c8efcb245c 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -1,423 +1,420 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-param-reassign, no-else-return, quotes, object-shorthand, comma-dangle, camelcase, one-var, vars-on-top, one-var-declaration-per-line, no-return-assign, consistent-return, max-len, prefer-template */ -(function() { - (function(w) { - var base; - const faviconEl = document.getElementById('favicon'); - const originalFavicon = faviconEl ? faviconEl.getAttribute('href') : null; - w.gl || (w.gl = {}); - (base = w.gl).utils || (base.utils = {}); - w.gl.utils.isInGroupsPage = function() { - return gl.utils.getPagePath() === 'groups'; - }; - w.gl.utils.isInProjectPage = function() { - return gl.utils.getPagePath() === 'projects'; - }; - w.gl.utils.getProjectSlug = function() { - if (this.isInProjectPage()) { - return $('body').data('project'); - } else { - return null; - } - }; - w.gl.utils.getGroupSlug = function() { - if (this.isInGroupsPage()) { - return $('body').data('group'); - } else { - return null; - } - }; - - w.gl.utils.ajaxGet = function(url) { - return $.ajax({ - type: "GET", - url: url, - dataType: "script" - }); - }; - - w.gl.utils.ajaxPost = function(url, data) { - return $.ajax({ - type: 'POST', - url: url, - data: data, - }); - }; - - w.gl.utils.extractLast = function(term) { - return this.split(term).pop(); - }; - - w.gl.utils.rstrip = function rstrip(val) { - if (val) { - return val.replace(/\s+$/, ''); +var base; +const w = window; +const faviconEl = document.getElementById('favicon'); +const originalFavicon = faviconEl ? faviconEl.getAttribute('href') : null; +w.gl || (w.gl = {}); +(base = w.gl).utils || (base.utils = {}); +w.gl.utils.isInGroupsPage = function() { + return gl.utils.getPagePath() === 'groups'; +}; +w.gl.utils.isInProjectPage = function() { + return gl.utils.getPagePath() === 'projects'; +}; +w.gl.utils.getProjectSlug = function() { + if (this.isInProjectPage()) { + return $('body').data('project'); + } else { + return null; + } +}; +w.gl.utils.getGroupSlug = function() { + if (this.isInGroupsPage()) { + return $('body').data('group'); + } else { + return null; + } +}; + +w.gl.utils.ajaxGet = function(url) { + return $.ajax({ + type: "GET", + url: url, + dataType: "script" + }); +}; + +w.gl.utils.ajaxPost = function(url, data) { + return $.ajax({ + type: 'POST', + url: url, + data: data, + }); +}; + +w.gl.utils.extractLast = function(term) { + return this.split(term).pop(); +}; + +w.gl.utils.rstrip = function rstrip(val) { + if (val) { + return val.replace(/\s+$/, ''); + } else { + return val; + } +}; + +gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) { + return $tooltipEl.attr('title', newTitle).tooltip('fixTitle'); +}; + +w.gl.utils.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) { + event_name = event_name || 'input'; + var closest_submit, field, that; + that = this; + field = $(field_selector); + closest_submit = field.closest('form').find(button_selector); + if (this.rstrip(field.val()) === "") { + closest_submit.disable(); + } + return field.on(event_name, function() { + if (that.rstrip($(this).val()) === "") { + return closest_submit.disable(); + } else { + return closest_submit.enable(); + } + }); +}; + +// automatically adjust scroll position for hash urls taking the height of the navbar into account +// https://github.com/twitter/bootstrap/issues/1768 +w.gl.utils.handleLocationHash = function() { + var hash = w.gl.utils.getLocationHash(); + if (!hash) return; + + // This is required to handle non-unicode characters in hash + hash = decodeURIComponent(hash); + + var fixedTabs = document.querySelector('.js-tabs-affix'); + var fixedNav = document.querySelector('.navbar-gitlab'); + + var adjustment = 0; + if (fixedNav) adjustment -= fixedNav.offsetHeight; + + // scroll to user-generated markdown anchor if we cannot find a match + if (document.getElementById(hash) === null) { + var target = document.getElementById('user-content-' + hash); + if (target && target.scrollIntoView) { + target.scrollIntoView(true); + window.scrollBy(0, adjustment); + } + } else { + // only adjust for fixedTabs when not targeting user-generated content + if (fixedTabs) { + adjustment -= fixedTabs.offsetHeight; + } + window.scrollBy(0, adjustment); + } +}; + +// Check if element scrolled into viewport from above or below +// Courtesy http://stackoverflow.com/a/7557433/414749 +w.gl.utils.isInViewport = function(el) { + var rect = el.getBoundingClientRect(); + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= window.innerHeight && + rect.right <= window.innerWidth + ); +}; + +gl.utils.getPagePath = function(index) { + index = index || 0; + return $('body').data('page').split(':')[index]; +}; + +gl.utils.parseUrl = function (url) { + var parser = document.createElement('a'); + parser.href = url; + return parser; +}; + +gl.utils.parseUrlPathname = function (url) { + var parsedUrl = gl.utils.parseUrl(url); + // parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11 + // We have to make sure we always have an absolute path. + return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : '/' + parsedUrl.pathname; +}; + +gl.utils.getUrlParamsArray = function () { + // We can trust that each param has one & since values containing & will be encoded + // Remove the first character of search as it is always ? + return window.location.search.slice(1).split('&').map((param) => { + const split = param.split('='); + return [decodeURI(split[0]), split[1]].join('='); + }); +}; + +gl.utils.isMetaKey = function(e) { + return e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; +}; + +gl.utils.isMetaClick = function(e) { + // Identify following special clicks + // 1) Cmd + Click on Mac (e.metaKey) + // 2) Ctrl + Click on PC (e.ctrlKey) + // 3) Middle-click or Mouse Wheel Click (e.which is 2) + return e.metaKey || e.ctrlKey || e.which === 2; +}; + +gl.utils.scrollToElement = function($el) { + var top = $el.offset().top; + gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height(); + + return $('body, html').animate({ + scrollTop: top - (gl.mrTabsHeight) + }, 200); +}; + +/** + this will take in the `name` of the param you want to parse in the url + if the name does not exist this function will return `null` + otherwise it will return the value of the param key provided +*/ +w.gl.utils.getParameterByName = (name, parseUrl) => { + const url = parseUrl || window.location.href; + name = name.replace(/[[\]]/g, '\\$&'); + const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`); + const results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ''; + return decodeURIComponent(results[2].replace(/\+/g, ' ')); +}; + +w.gl.utils.getSelectedFragment = () => { + const selection = window.getSelection(); + if (selection.rangeCount === 0) return null; + const documentFragment = document.createDocumentFragment(); + for (let i = 0; i < selection.rangeCount; i += 1) { + documentFragment.appendChild(selection.getRangeAt(i).cloneContents()); + } + if (documentFragment.textContent.length === 0) return null; + + return documentFragment; +}; + +w.gl.utils.insertText = (target, text) => { + // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas + + const selectionStart = target.selectionStart; + const selectionEnd = target.selectionEnd; + const value = target.value; + + const textBefore = value.substring(0, selectionStart); + const textAfter = value.substring(selectionEnd, value.length); + + const insertedText = text instanceof Function ? text(textBefore, textAfter) : text; + const newText = textBefore + insertedText + textAfter; + + target.value = newText; + target.selectionStart = target.selectionEnd = selectionStart + insertedText.length; + + // Trigger autosave + $(target).trigger('input'); + + // Trigger autosize + var event = document.createEvent('Event'); + event.initEvent('autosize:update', true, false); + target.dispatchEvent(event); +}; + +w.gl.utils.nodeMatchesSelector = (node, selector) => { + const matches = Element.prototype.matches || + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector; + + if (matches) { + return matches.call(node, selector); + } + + // IE11 doesn't support `node.matches(selector)` + + let parentNode = node.parentNode; + if (!parentNode) { + parentNode = document.createElement('div'); + node = node.cloneNode(true); + parentNode.appendChild(node); + } + + const matchingNodes = parentNode.querySelectorAll(selector); + return Array.prototype.indexOf.call(matchingNodes, node) !== -1; +}; + +/** + this will take in the headers from an API response and normalize them + this way we don't run into production issues when nginx gives us lowercased header keys +*/ +w.gl.utils.normalizeHeaders = (headers) => { + const upperCaseHeaders = {}; + + Object.keys(headers).forEach((e) => { + upperCaseHeaders[e.toUpperCase()] = headers[e]; + }); + + return upperCaseHeaders; +}; + +/** + this will take in the getAllResponseHeaders result and normalize them + this way we don't run into production issues when nginx gives us lowercased header keys +*/ +w.gl.utils.normalizeCRLFHeaders = (headers) => { + const headersObject = {}; + const headersArray = headers.split('\n'); + + headersArray.forEach((header) => { + const keyValue = header.split(': '); + headersObject[keyValue[0]] = keyValue[1]; + }); + + return w.gl.utils.normalizeHeaders(headersObject); +}; + +/** + * Parses pagination object string values into numbers. + * + * @param {Object} paginationInformation + * @returns {Object} + */ +w.gl.utils.parseIntPagination = paginationInformation => ({ + perPage: parseInt(paginationInformation['X-PER-PAGE'], 10), + page: parseInt(paginationInformation['X-PAGE'], 10), + total: parseInt(paginationInformation['X-TOTAL'], 10), + totalPages: parseInt(paginationInformation['X-TOTAL-PAGES'], 10), + nextPage: parseInt(paginationInformation['X-NEXT-PAGE'], 10), + previousPage: parseInt(paginationInformation['X-PREV-PAGE'], 10), +}); + +/** + * Updates the search parameter of a URL given the parameter and value provided. + * + * If no search params are present we'll add it. + * If param for page is already present, we'll update it + * If there are params but not for the given one, we'll add it at the end. + * Returns the new search parameters. + * + * @param {String} param + * @param {Number|String|Undefined|Null} value + * @return {String} + */ +w.gl.utils.setParamInURL = (param, value) => { + let search; + const locationSearch = window.location.search; + + if (locationSearch.length) { + const parameters = locationSearch.substring(1, locationSearch.length) + .split('&') + .reduce((acc, element) => { + const val = element.split('='); + acc[val[0]] = decodeURIComponent(val[1]); + return acc; + }, {}); + + parameters[param] = value; + + const toString = Object.keys(parameters) + .map(val => `${val}=${encodeURIComponent(parameters[val])}`) + .join('&'); + + search = `?${toString}`; + } else { + search = `?${param}=${value}`; + } + + return search; +}; + +/** + * Converts permission provided as strings to booleans. + * + * @param {String} string + * @returns {Boolean} + */ +w.gl.utils.convertPermissionToBoolean = permission => permission === 'true'; + +/** + * Back Off exponential algorithm + * backOff :: (Function<next, stop>, Number) -> Promise<Any, Error> + * + * @param {Function<next, stop>} fn function to be called + * @param {Number} timeout + * @return {Promise<Any, Error>} + * @example + * ``` + * backOff(function (next, stop) { + * // Let's perform this function repeatedly for 60s or for the timeout provided. + * + * ourFunction() + * .then(function (result) { + * // continue if result is not what we need + * next(); + * + * // when result is what we need let's stop with the repetions and jump out of the cycle + * stop(result); + * }) + * .catch(function (error) { + * // if there is an error, we need to stop this with an error. + * stop(error); + * }) + * }, 60000) + * .then(function (result) {}) + * .catch(function (error) { + * // deal with errors passed to stop() + * }) + * ``` + */ +w.gl.utils.backOff = (fn, timeout = 60000) => { + const maxInterval = 32000; + let nextInterval = 2000; + + const startTime = Date.now(); + + return new Promise((resolve, reject) => { + const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); + + const next = () => { + if (Date.now() - startTime < timeout) { + setTimeout(fn.bind(null, next, stop), nextInterval); + nextInterval = Math.min(nextInterval + nextInterval, maxInterval); } else { - return val; + reject(new Error('BACKOFF_TIMEOUT')); } }; - gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) { - return $tooltipEl.attr('title', newTitle).tooltip('fixTitle'); - }; - - w.gl.utils.disableButtonIfEmptyField = function(field_selector, button_selector, event_name) { - event_name = event_name || 'input'; - var closest_submit, field, that; - that = this; - field = $(field_selector); - closest_submit = field.closest('form').find(button_selector); - if (this.rstrip(field.val()) === "") { - closest_submit.disable(); - } - return field.on(event_name, function() { - if (that.rstrip($(this).val()) === "") { - return closest_submit.disable(); - } else { - return closest_submit.enable(); - } - }); - }; - - // automatically adjust scroll position for hash urls taking the height of the navbar into account - // https://github.com/twitter/bootstrap/issues/1768 - w.gl.utils.handleLocationHash = function() { - var hash = w.gl.utils.getLocationHash(); - if (!hash) return; - - // This is required to handle non-unicode characters in hash - hash = decodeURIComponent(hash); - - var fixedTabs = document.querySelector('.js-tabs-affix'); - var fixedNav = document.querySelector('.navbar-gitlab'); - - var adjustment = 0; - if (fixedNav) adjustment -= fixedNav.offsetHeight; - - // scroll to user-generated markdown anchor if we cannot find a match - if (document.getElementById(hash) === null) { - var target = document.getElementById('user-content-' + hash); - if (target && target.scrollIntoView) { - target.scrollIntoView(true); - window.scrollBy(0, adjustment); - } + fn(next, stop); + }); +}; + +w.gl.utils.setFavicon = (faviconPath) => { + if (faviconEl && faviconPath) { + faviconEl.setAttribute('href', faviconPath); + } +}; + +w.gl.utils.resetFavicon = () => { + if (faviconEl) { + faviconEl.setAttribute('href', originalFavicon); + } +}; + +w.gl.utils.setCiStatusFavicon = (pageUrl) => { + $.ajax({ + url: pageUrl, + dataType: 'json', + success: function(data) { + if (data && data.favicon) { + gl.utils.setFavicon(data.favicon); } else { - // only adjust for fixedTabs when not targeting user-generated content - if (fixedTabs) { - adjustment -= fixedTabs.offsetHeight; - } - window.scrollBy(0, adjustment); + gl.utils.resetFavicon(); } - }; - - // Check if element scrolled into viewport from above or below - // Courtesy http://stackoverflow.com/a/7557433/414749 - w.gl.utils.isInViewport = function(el) { - var rect = el.getBoundingClientRect(); - - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= window.innerHeight && - rect.right <= window.innerWidth - ); - }; - - gl.utils.getPagePath = function(index) { - index = index || 0; - return $('body').data('page').split(':')[index]; - }; - - gl.utils.parseUrl = function (url) { - var parser = document.createElement('a'); - parser.href = url; - return parser; - }; - - gl.utils.parseUrlPathname = function (url) { - var parsedUrl = gl.utils.parseUrl(url); - // parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11 - // We have to make sure we always have an absolute path. - return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : '/' + parsedUrl.pathname; - }; - - gl.utils.getUrlParamsArray = function () { - // We can trust that each param has one & since values containing & will be encoded - // Remove the first character of search as it is always ? - return window.location.search.slice(1).split('&').map((param) => { - const split = param.split('='); - return [decodeURI(split[0]), split[1]].join('='); - }); - }; - - gl.utils.isMetaKey = function(e) { - return e.metaKey || e.ctrlKey || e.altKey || e.shiftKey; - }; - - gl.utils.isMetaClick = function(e) { - // Identify following special clicks - // 1) Cmd + Click on Mac (e.metaKey) - // 2) Ctrl + Click on PC (e.ctrlKey) - // 3) Middle-click or Mouse Wheel Click (e.which is 2) - return e.metaKey || e.ctrlKey || e.which === 2; - }; - - gl.utils.scrollToElement = function($el) { - var top = $el.offset().top; - gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height(); - - return $('body, html').animate({ - scrollTop: top - (gl.mrTabsHeight) - }, 200); - }; - - /** - this will take in the `name` of the param you want to parse in the url - if the name does not exist this function will return `null` - otherwise it will return the value of the param key provided - */ - w.gl.utils.getParameterByName = (name, parseUrl) => { - const url = parseUrl || window.location.href; - name = name.replace(/[[\]]/g, '\\$&'); - const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`); - const results = regex.exec(url); - if (!results) return null; - if (!results[2]) return ''; - return decodeURIComponent(results[2].replace(/\+/g, ' ')); - }; - - w.gl.utils.getSelectedFragment = () => { - const selection = window.getSelection(); - if (selection.rangeCount === 0) return null; - const documentFragment = document.createDocumentFragment(); - for (let i = 0; i < selection.rangeCount; i += 1) { - documentFragment.appendChild(selection.getRangeAt(i).cloneContents()); - } - if (documentFragment.textContent.length === 0) return null; - - return documentFragment; - }; - - w.gl.utils.insertText = (target, text) => { - // Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas - - const selectionStart = target.selectionStart; - const selectionEnd = target.selectionEnd; - const value = target.value; - - const textBefore = value.substring(0, selectionStart); - const textAfter = value.substring(selectionEnd, value.length); - - const insertedText = text instanceof Function ? text(textBefore, textAfter) : text; - const newText = textBefore + insertedText + textAfter; - - target.value = newText; - target.selectionStart = target.selectionEnd = selectionStart + insertedText.length; - - // Trigger autosave - $(target).trigger('input'); - - // Trigger autosize - var event = document.createEvent('Event'); - event.initEvent('autosize:update', true, false); - target.dispatchEvent(event); - }; - - w.gl.utils.nodeMatchesSelector = (node, selector) => { - const matches = Element.prototype.matches || - Element.prototype.matchesSelector || - Element.prototype.mozMatchesSelector || - Element.prototype.msMatchesSelector || - Element.prototype.oMatchesSelector || - Element.prototype.webkitMatchesSelector; - - if (matches) { - return matches.call(node, selector); - } - - // IE11 doesn't support `node.matches(selector)` - - let parentNode = node.parentNode; - if (!parentNode) { - parentNode = document.createElement('div'); - node = node.cloneNode(true); - parentNode.appendChild(node); - } - - const matchingNodes = parentNode.querySelectorAll(selector); - return Array.prototype.indexOf.call(matchingNodes, node) !== -1; - }; - - /** - this will take in the headers from an API response and normalize them - this way we don't run into production issues when nginx gives us lowercased header keys - */ - w.gl.utils.normalizeHeaders = (headers) => { - const upperCaseHeaders = {}; - - Object.keys(headers).forEach((e) => { - upperCaseHeaders[e.toUpperCase()] = headers[e]; - }); - - return upperCaseHeaders; - }; - - /** - this will take in the getAllResponseHeaders result and normalize them - this way we don't run into production issues when nginx gives us lowercased header keys - */ - w.gl.utils.normalizeCRLFHeaders = (headers) => { - const headersObject = {}; - const headersArray = headers.split('\n'); - - headersArray.forEach((header) => { - const keyValue = header.split(': '); - headersObject[keyValue[0]] = keyValue[1]; - }); - - return w.gl.utils.normalizeHeaders(headersObject); - }; - - /** - * Parses pagination object string values into numbers. - * - * @param {Object} paginationInformation - * @returns {Object} - */ - w.gl.utils.parseIntPagination = paginationInformation => ({ - perPage: parseInt(paginationInformation['X-PER-PAGE'], 10), - page: parseInt(paginationInformation['X-PAGE'], 10), - total: parseInt(paginationInformation['X-TOTAL'], 10), - totalPages: parseInt(paginationInformation['X-TOTAL-PAGES'], 10), - nextPage: parseInt(paginationInformation['X-NEXT-PAGE'], 10), - previousPage: parseInt(paginationInformation['X-PREV-PAGE'], 10), - }); - - /** - * Updates the search parameter of a URL given the parameter and value provided. - * - * If no search params are present we'll add it. - * If param for page is already present, we'll update it - * If there are params but not for the given one, we'll add it at the end. - * Returns the new search parameters. - * - * @param {String} param - * @param {Number|String|Undefined|Null} value - * @return {String} - */ - w.gl.utils.setParamInURL = (param, value) => { - let search; - const locationSearch = window.location.search; - - if (locationSearch.length) { - const parameters = locationSearch.substring(1, locationSearch.length) - .split('&') - .reduce((acc, element) => { - const val = element.split('='); - acc[val[0]] = decodeURIComponent(val[1]); - return acc; - }, {}); - - parameters[param] = value; - - const toString = Object.keys(parameters) - .map(val => `${val}=${encodeURIComponent(parameters[val])}`) - .join('&'); - - search = `?${toString}`; - } else { - search = `?${param}=${value}`; - } - - return search; - }; - - /** - * Converts permission provided as strings to booleans. - * - * @param {String} string - * @returns {Boolean} - */ - w.gl.utils.convertPermissionToBoolean = permission => permission === 'true'; - - /** - * Back Off exponential algorithm - * backOff :: (Function<next, stop>, Number) -> Promise<Any, Error> - * - * @param {Function<next, stop>} fn function to be called - * @param {Number} timeout - * @return {Promise<Any, Error>} - * @example - * ``` - * backOff(function (next, stop) { - * // Let's perform this function repeatedly for 60s or for the timeout provided. - * - * ourFunction() - * .then(function (result) { - * // continue if result is not what we need - * next(); - * - * // when result is what we need let's stop with the repetions and jump out of the cycle - * stop(result); - * }) - * .catch(function (error) { - * // if there is an error, we need to stop this with an error. - * stop(error); - * }) - * }, 60000) - * .then(function (result) {}) - * .catch(function (error) { - * // deal with errors passed to stop() - * }) - * ``` - */ - w.gl.utils.backOff = (fn, timeout = 60000) => { - const maxInterval = 32000; - let nextInterval = 2000; - - const startTime = Date.now(); - - return new Promise((resolve, reject) => { - const stop = arg => ((arg instanceof Error) ? reject(arg) : resolve(arg)); - - const next = () => { - if (Date.now() - startTime < timeout) { - setTimeout(fn.bind(null, next, stop), nextInterval); - nextInterval = Math.min(nextInterval + nextInterval, maxInterval); - } else { - reject(new Error('BACKOFF_TIMEOUT')); - } - }; - - fn(next, stop); - }); - }; - - w.gl.utils.setFavicon = (faviconPath) => { - if (faviconEl && faviconPath) { - faviconEl.setAttribute('href', faviconPath); - } - }; - - w.gl.utils.resetFavicon = () => { - if (faviconEl) { - faviconEl.setAttribute('href', originalFavicon); - } - }; - - w.gl.utils.setCiStatusFavicon = (pageUrl) => { - $.ajax({ - url: pageUrl, - dataType: 'json', - success: function(data) { - if (data && data.favicon) { - gl.utils.setFavicon(data.favicon); - } else { - gl.utils.resetFavicon(); - } - }, - error: function() { - gl.utils.resetFavicon(); - } - }); - }; - })(window); -}).call(window); + }, + error: function() { + gl.utils.resetFavicon(); + } + }); +}; diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 1d1763c3963..ee7b6417c5b 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -1,4 +1,4 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, comma-dangle, no-unused-expressions, prefer-template, max-len */ +/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, comma-dangle, no-unused-expressions, prefer-template, max-len, vars-on-top */ import timeago from 'timeago.js'; import dateFormat from 'vendor/date.format'; @@ -11,123 +11,120 @@ import { window.timeago = timeago; window.dateFormat = dateFormat; -(function() { - (function(w) { - var base; - var timeagoInstance; +var w = window; +var base; +var timeagoInstance; - if (w.gl == null) { - w.gl = {}; - } - if ((base = w.gl).utils == null) { - base.utils = {}; - } - w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - - w.gl.utils.formatDate = function(datetime) { - return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); - }; +if (w.gl == null) { + w.gl = {}; +} +if ((base = w.gl).utils == null) { + base.utils = {}; +} +w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - w.gl.utils.getDayName = function(date) { - return this.days[date.getDay()]; - }; +w.gl.utils.formatDate = function(datetime) { + return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); +}; - w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) { - $timeagoEls.each((i, el) => { - el.setAttribute('title', el.getAttribute('title')); +w.gl.utils.getDayName = function(date) { + return this.days[date.getDay()]; +}; - if (setTimeago) { - // Recreate with custom template - $(el).tooltip({ - template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' - }); - } +w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago = true) { + $timeagoEls.each((i, el) => { + el.setAttribute('title', el.getAttribute('title')); - el.classList.add('js-timeago-render'); + if (setTimeago) { + // Recreate with custom template + $(el).tooltip({ + template: '<div class="tooltip local-timeago" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' }); + } - gl.utils.renderTimeago($timeagoEls); + el.classList.add('js-timeago-render'); + }); + + gl.utils.renderTimeago($timeagoEls); +}; + +w.gl.utils.getTimeago = function() { + var locale; + + if (!timeagoInstance) { + const localeRemaining = function(number, index) { + return [ + [s__('Timeago|less than a minute ago'), s__('Timeago|a while')], + [s__('Timeago|less than a minute ago'), s__('Timeago|%s seconds remaining')], + [s__('Timeago|about a minute ago'), s__('Timeago|1 minute remaining')], + [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')], + [s__('Timeago|about an hour ago'), s__('Timeago|1 hour remaining')], + [s__('Timeago|about %s hours ago'), s__('Timeago|%s hours remaining')], + [s__('Timeago|a day ago'), s__('Timeago|1 day remaining')], + [s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')], + [s__('Timeago|a week ago'), s__('Timeago|1 week remaining')], + [s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')], + [s__('Timeago|a month ago'), s__('Timeago|1 month remaining')], + [s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')], + [s__('Timeago|a year ago'), s__('Timeago|1 year remaining')], + [s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')] + ][index]; }; - - w.gl.utils.getTimeago = function() { - var locale; - - if (!timeagoInstance) { - const localeRemaining = function(number, index) { - return [ - [s__('Timeago|less than a minute ago'), s__('Timeago|a while')], - [s__('Timeago|less than a minute ago'), s__('Timeago|%s seconds remaining')], - [s__('Timeago|about a minute ago'), s__('Timeago|1 minute remaining')], - [s__('Timeago|%s minutes ago'), s__('Timeago|%s minutes remaining')], - [s__('Timeago|about an hour ago'), s__('Timeago|1 hour remaining')], - [s__('Timeago|about %s hours ago'), s__('Timeago|%s hours remaining')], - [s__('Timeago|a day ago'), s__('Timeago|1 day remaining')], - [s__('Timeago|%s days ago'), s__('Timeago|%s days remaining')], - [s__('Timeago|a week ago'), s__('Timeago|1 week remaining')], - [s__('Timeago|%s weeks ago'), s__('Timeago|%s weeks remaining')], - [s__('Timeago|a month ago'), s__('Timeago|1 month remaining')], - [s__('Timeago|%s months ago'), s__('Timeago|%s months remaining')], - [s__('Timeago|a year ago'), s__('Timeago|1 year remaining')], - [s__('Timeago|%s years ago'), s__('Timeago|%s years remaining')] - ][index]; - }; - locale = function(number, index) { - return [ - [s__('Timeago|less than a minute ago'), s__('Timeago|a while')], - [s__('Timeago|less than a minute ago'), s__('Timeago|in %s seconds')], - [s__('Timeago|about a minute ago'), s__('Timeago|in 1 minute')], - [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')], - [s__('Timeago|about an hour ago'), s__('Timeago|in 1 hour')], - [s__('Timeago|about %s hours ago'), s__('Timeago|in %s hours')], - [s__('Timeago|a day ago'), s__('Timeago|in 1 day')], - [s__('Timeago|%s days ago'), s__('Timeago|in %s days')], - [s__('Timeago|a week ago'), s__('Timeago|in 1 week')], - [s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')], - [s__('Timeago|a month ago'), s__('Timeago|in 1 month')], - [s__('Timeago|%s months ago'), s__('Timeago|in %s months')], - [s__('Timeago|a year ago'), s__('Timeago|in 1 year')], - [s__('Timeago|%s years ago'), s__('Timeago|in %s years')] - ][index]; - }; - - timeago.register(lang, locale); - timeago.register(`${lang}-remaining`, localeRemaining); - timeagoInstance = timeago(); - } - - return timeagoInstance; + locale = function(number, index) { + return [ + [s__('Timeago|less than a minute ago'), s__('Timeago|a while')], + [s__('Timeago|less than a minute ago'), s__('Timeago|in %s seconds')], + [s__('Timeago|about a minute ago'), s__('Timeago|in 1 minute')], + [s__('Timeago|%s minutes ago'), s__('Timeago|in %s minutes')], + [s__('Timeago|about an hour ago'), s__('Timeago|in 1 hour')], + [s__('Timeago|about %s hours ago'), s__('Timeago|in %s hours')], + [s__('Timeago|a day ago'), s__('Timeago|in 1 day')], + [s__('Timeago|%s days ago'), s__('Timeago|in %s days')], + [s__('Timeago|a week ago'), s__('Timeago|in 1 week')], + [s__('Timeago|%s weeks ago'), s__('Timeago|in %s weeks')], + [s__('Timeago|a month ago'), s__('Timeago|in 1 month')], + [s__('Timeago|%s months ago'), s__('Timeago|in %s months')], + [s__('Timeago|a year ago'), s__('Timeago|in 1 year')], + [s__('Timeago|%s years ago'), s__('Timeago|in %s years')] + ][index]; }; - w.gl.utils.timeFor = function(time, suffix, expiredLabel) { - var timefor; - if (!time) { - return ''; - } - if (new Date(time) < new Date()) { - expiredLabel || (expiredLabel = s__('Timeago|Past due')); - timefor = expiredLabel; - } else { - timefor = gl.utils.getTimeago().format(time, `${lang}-remaining`).trim(); - } - return timefor; - }; + timeago.register(lang, locale); + timeago.register(`${lang}-remaining`, localeRemaining); + timeagoInstance = timeago(); + } - w.gl.utils.renderTimeago = function($els) { - const timeagoEls = $els || document.querySelectorAll('.js-timeago-render'); + return timeagoInstance; +}; - // timeago.js sets timeouts internally for each timeago value to be updated in real time - gl.utils.getTimeago().render(timeagoEls, lang); - }; +w.gl.utils.timeFor = function(time, suffix, expiredLabel) { + var timefor; + if (!time) { + return ''; + } + if (new Date(time) < new Date()) { + expiredLabel || (expiredLabel = s__('Timeago|Past due')); + timefor = expiredLabel; + } else { + timefor = gl.utils.getTimeago().format(time, `${lang}-remaining`).trim(); + } + return timefor; +}; - w.gl.utils.getDayDifference = function(a, b) { - var millisecondsPerDay = 1000 * 60 * 60 * 24; - var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); - var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); +w.gl.utils.renderTimeago = function($els) { + const timeagoEls = $els || document.querySelectorAll('.js-timeago-render'); - return Math.floor((date2 - date1) / millisecondsPerDay); - }; - })(window); -}).call(window); + // timeago.js sets timeouts internally for each timeago value to be updated in real time + gl.utils.getTimeago().render(timeagoEls, lang); +}; + +w.gl.utils.getDayDifference = function(a, b) { + var millisecondsPerDay = 1000 * 60 * 60 * 24; + var date1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); + var date2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); + + return Math.floor((date2 - date1) / millisecondsPerDay); +}; /** * Port of ruby helper time_interval_in_words. diff --git a/app/assets/javascripts/lib/utils/pretty_time.js b/app/assets/javascripts/lib/utils/pretty_time.js index ae397212e55..a3d0b55afd3 100644 --- a/app/assets/javascripts/lib/utils/pretty_time.js +++ b/app/assets/javascripts/lib/utils/pretty_time.js @@ -1,65 +1,63 @@ -(() => { +/* + * TODO: Make these methods more configurable (e.g. parseSeconds timePeriodContstraints, + * stringifyTime condensed or non-condensed, abbreviateTimelengths) + * */ +const gl = window.gl || (window.gl = {}); +const utils = window.gl.utils = gl.utils || {}; +const prettyTime = utils.prettyTime = { /* - * TODO: Make these methods more configurable (e.g. parseSeconds timePeriodContstraints, - * stringifyTime condensed or non-condensed, abbreviateTimelengths) - * */ + * Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # } + * Seconds can be negative or positive, zero or non-zero. + */ + parseSeconds(seconds) { + const DAYS_PER_WEEK = 5; + const HOURS_PER_DAY = 8; + const MINUTES_PER_HOUR = 60; + const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR; + const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR; + + const timePeriodConstraints = { + weeks: MINUTES_PER_WEEK, + days: MINUTES_PER_DAY, + hours: MINUTES_PER_HOUR, + minutes: 1, + }; + + let unorderedMinutes = prettyTime.secondsToMinutes(seconds); + + return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => { + const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod); + + unorderedMinutes -= (periodCount * minutesPerPeriod); + + return periodCount; + }); + }, - const utils = window.gl.utils = gl.utils || {}; - const prettyTime = utils.prettyTime = { - /* - * Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # } - * Seconds can be negative or positive, zero or non-zero. - */ - parseSeconds(seconds) { - const DAYS_PER_WEEK = 5; - const HOURS_PER_DAY = 8; - const MINUTES_PER_HOUR = 60; - const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR; - const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR; - - const timePeriodConstraints = { - weeks: MINUTES_PER_WEEK, - days: MINUTES_PER_DAY, - hours: MINUTES_PER_HOUR, - minutes: 1, - }; - - let unorderedMinutes = prettyTime.secondsToMinutes(seconds); - - return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => { - const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod); - - unorderedMinutes -= (periodCount * minutesPerPeriod); - - return periodCount; - }); - }, - - /* - * Accepts a timeObject and returns a condensed string representation of it - * (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included. - */ - - stringifyTime(timeObject) { - const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => { - const isNonZero = !!unitValue; - return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; - }, '').trim(); - return reducedTime.length ? reducedTime : '0m'; - }, - - /* - * Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns - * the first non-zero unit/value pair. - */ - - abbreviateTime(timeStr) { - return timeStr.split(' ') - .filter(unitStr => unitStr.charAt(0) !== '0')[0]; - }, + /* + * Accepts a timeObject and returns a condensed string representation of it + * (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included. + */ + + stringifyTime(timeObject) { + const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => { + const isNonZero = !!unitValue; + return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo; + }, '').trim(); + return reducedTime.length ? reducedTime : '0m'; + }, - secondsToMinutes(seconds) { - return Math.abs(seconds / 60); - }, - }; -})(window.gl || (window.gl = {})); + /* + * Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns + * the first non-zero unit/value pair. + */ + + abbreviateTime(timeStr) { + return timeStr.split(' ') + .filter(unitStr => unitStr.charAt(0) !== '0')[0]; + }, + + secondsToMinutes(seconds) { + return Math.abs(seconds / 60); + }, +}; diff --git a/app/assets/javascripts/logo.js b/app/assets/javascripts/logo.js index 729baa2e1a7..5b96686a331 100644 --- a/app/assets/javascripts/logo.js +++ b/app/assets/javascripts/logo.js @@ -1,7 +1,5 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback */ -(function() { - window.addEventListener('beforeunload', function() { - $('.tanuki-logo').addClass('animate'); - }); -}).call(window); +window.addEventListener('beforeunload', function() { + $('.tanuki-logo').addClass('animate'); +}); diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js index e034729bd39..9b633485ff2 100644 --- a/app/assets/javascripts/member_expiration_date.js +++ b/app/assets/javascripts/member_expiration_date.js @@ -1,53 +1,51 @@ /* global Pikaday */ /* global dateFormat */ -(() => { - // Add datepickers to all `js-access-expiration-date` elements. If those elements are - // children of an element with the `clearable-input` class, and have a sibling - // `js-clear-input` element, then show that element when there is a value in the - // datepicker, and make clicking on that element clear the field. - // - window.gl = window.gl || {}; - gl.MemberExpirationDate = (selector = '.js-access-expiration-date') => { - function toggleClearInput() { - $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); - } - const inputs = $(selector); - - inputs.each((i, el) => { - const $input = $(el); - - const calendar = new Pikaday({ - field: $input.get(0), - theme: 'gitlab-theme animate-picker', - format: 'yyyy-mm-dd', - minDate: new Date(), - container: $input.parent().get(0), - onSelect(dateText) { - $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); - - $input.trigger('change'); - - toggleClearInput.call($input); - }, - }); - - calendar.setDate(new Date($input.val())); - $input.data('pikaday', calendar); +// Add datepickers to all `js-access-expiration-date` elements. If those elements are +// children of an element with the `clearable-input` class, and have a sibling +// `js-clear-input` element, then show that element when there is a value in the +// datepicker, and make clicking on that element clear the field. +// +window.gl = window.gl || {}; +gl.MemberExpirationDate = (selector = '.js-access-expiration-date') => { + function toggleClearInput() { + $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); + } + const inputs = $(selector); + + inputs.each((i, el) => { + const $input = $(el); + + const calendar = new Pikaday({ + field: $input.get(0), + theme: 'gitlab-theme animate-picker', + format: 'yyyy-mm-dd', + minDate: new Date(), + container: $input.parent().get(0), + onSelect(dateText) { + $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); + + $input.trigger('change'); + + toggleClearInput.call($input); + }, }); - inputs.next('.js-clear-input').on('click', function clicked(event) { - event.preventDefault(); + calendar.setDate(new Date($input.val())); + $input.data('pikaday', calendar); + }); - const input = $(this).closest('.clearable-input').find(selector); - const calendar = input.data('pikaday'); + inputs.next('.js-clear-input').on('click', function clicked(event) { + event.preventDefault(); - calendar.setDate(null); - input.trigger('change'); - toggleClearInput.call(input); - }); + const input = $(this).closest('.clearable-input').find(selector); + const calendar = input.data('pikaday'); + + calendar.setDate(null); + input.trigger('change'); + toggleClearInput.call(input); + }); - inputs.on('blur', toggleClearInput); + inputs.on('blur', toggleClearInput); - inputs.each(toggleClearInput); - }; -}).call(window); + inputs.each(toggleClearInput); +}; diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js index 8291b8c4a70..12a9abe281f 100644 --- a/app/assets/javascripts/members.js +++ b/app/assets/javascripts/members.js @@ -1,81 +1,79 @@ /* eslint-disable class-methods-use-this */ -(() => { - window.gl = window.gl || {}; +window.gl = window.gl || {}; - class Members { - constructor() { - this.addListeners(); - this.initGLDropdown(); - } +class Members { + constructor() { + this.addListeners(); + this.initGLDropdown(); + } - addListeners() { - $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); - $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this)); - $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this)); - gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); - } + addListeners() { + $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); + $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this)); + $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this)); + gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); + } - initGLDropdown() { - $('.js-member-permissions-dropdown').each((i, btn) => { - const $btn = $(btn); + initGLDropdown() { + $('.js-member-permissions-dropdown').each((i, btn) => { + const $btn = $(btn); - $btn.glDropdown({ - selectable: true, - isSelectable(selected, $el) { - return !$el.hasClass('is-active'); - }, - fieldName: $btn.data('field-name'), - id(selected, $el) { - return $el.data('id'); - }, - toggleLabel(selected, $el) { - return $el.text(); - }, - clicked: (options) => { - this.formSubmit(null, options.$el); - }, - }); + $btn.glDropdown({ + selectable: true, + isSelectable(selected, $el) { + return !$el.hasClass('is-active'); + }, + fieldName: $btn.data('field-name'), + id(selected, $el) { + return $el.data('id'); + }, + toggleLabel(selected, $el) { + return $el.text(); + }, + clicked: (options) => { + this.formSubmit(null, options.$el); + }, }); - } + }); + } - removeRow(e) { - const $target = $(e.target); + removeRow(e) { + const $target = $(e.target); - if ($target.hasClass('btn-remove')) { - $target.closest('.member') - .fadeOut(function fadeOutMemberRow() { - $(this).remove(); - }); - } + if ($target.hasClass('btn-remove')) { + $target.closest('.member') + .fadeOut(function fadeOutMemberRow() { + $(this).remove(); + }); } + } - formSubmit(e, $el = null) { - const $this = e ? $(e.currentTarget) : $el; - const { $toggle, $dateInput } = this.getMemberListItems($this); + formSubmit(e, $el = null) { + const $this = e ? $(e.currentTarget) : $el; + const { $toggle, $dateInput } = this.getMemberListItems($this); - $this.closest('form').trigger('submit.rails'); + $this.closest('form').trigger('submit.rails'); - $toggle.disable(); - $dateInput.disable(); - } + $toggle.disable(); + $dateInput.disable(); + } - formSuccess(e) { - const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member')); + formSuccess(e) { + const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member')); - $toggle.enable(); - $dateInput.enable(); - } + $toggle.enable(); + $dateInput.enable(); + } - getMemberListItems($el) { - const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('el-id')}`); + getMemberListItems($el) { + const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('el-id')}`); - return { - $memberListItem, - $toggle: $memberListItem.find('.dropdown-menu-toggle'), - $dateInput: $memberListItem.find('.js-access-expiration-date'), - }; - } + return { + $memberListItem, + $toggle: $memberListItem.find('.dropdown-menu-toggle'), + $dateInput: $memberListItem.find('.js-access-expiration-date'), + }; } +} - gl.Members = Members; -})(); +gl.Members = Members; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 0db2abe507d..5444457f651 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -6,127 +6,123 @@ import TaskList from './task_list'; import './merge_request_tabs'; import IssuablesHelper from './helpers/issuables_helper'; -(function() { - this.MergeRequest = (function() { - function MergeRequest(opts) { - // Initialize MergeRequest behavior - // - // Options: - // action - String, current controller action - // - this.opts = opts != null ? opts : {}; - this.submitNoteForm = this.submitNoteForm.bind(this); - this.$el = $('.merge-request'); - this.$('.show-all-commits').on('click', (function(_this) { - return function() { - return _this.showAllCommits(); - }; - })(this)); - - this.initTabs(); - this.initMRBtnListeners(); - this.initCommitMessageListeners(); - this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport(); - - if ($("a.btn-close").length) { - this.taskList = new TaskList({ - dataType: 'merge_request', - fieldName: 'description', - selector: '.detail-page-description', - onSuccess: (result) => { - document.querySelector('#task_status').innerText = result.task_status; - document.querySelector('#task_status_short').innerText = result.task_status_short; - } - }); - } - } - - // Local jQuery finder - MergeRequest.prototype.$ = function(selector) { - return this.$el.find(selector); - }; - - MergeRequest.prototype.initTabs = function() { - if (window.mrTabs) { - window.mrTabs.unbindEvents(); - } - window.mrTabs = new gl.MergeRequestTabs(this.opts); +function MergeRequest(opts) { + // Initialize MergeRequest behavior + // + // Options: + // action - String, current controller action + // + this.opts = opts != null ? opts : {}; + this.submitNoteForm = this.submitNoteForm.bind(this); + this.$el = $('.merge-request'); + this.$('.show-all-commits').on('click', (function(_this) { + return function() { + return _this.showAllCommits(); }; - - MergeRequest.prototype.showAllCommits = function() { - this.$('.first-commits').remove(); - return this.$('.all-commits').removeClass('hide'); - }; - - MergeRequest.prototype.initMRBtnListeners = function() { - var _this; - _this = this; - return $('a.btn-close, a.btn-reopen').on('click', function(e) { - var $this, shouldSubmit; - $this = $(this); - shouldSubmit = $this.hasClass('btn-comment'); - if (shouldSubmit && $this.data('submitted')) { - return; - } - - if (this.closeReopenReportToggle) this.closeReopenReportToggle.setDisable(); - - if (shouldSubmit) { - if ($this.hasClass('btn-comment-and-close') || $this.hasClass('btn-comment-and-reopen')) { - e.preventDefault(); - e.stopImmediatePropagation(); - - _this.submitNoteForm($this.closest('form'), $this); - } - } - }); - }; - - MergeRequest.prototype.submitNoteForm = function(form, $button) { - var noteText; - noteText = form.find("textarea.js-note-text").val(); - if (noteText.trim().length > 0) { - form.submit(); - $button.data('submitted', true); - return $button.trigger('click'); + })(this)); + + this.initTabs(); + this.initMRBtnListeners(); + this.initCommitMessageListeners(); + this.closeReopenReportToggle = IssuablesHelper.initCloseReopenReport(); + + if ($("a.btn-close").length) { + this.taskList = new TaskList({ + dataType: 'merge_request', + fieldName: 'description', + selector: '.detail-page-description', + onSuccess: (result) => { + document.querySelector('#task_status').innerText = result.task_status; + document.querySelector('#task_status_short').innerText = result.task_status_short; } - }; - - MergeRequest.prototype.initCommitMessageListeners = function() { - $(document).on('click', 'a.js-with-description-link', function(e) { - var textarea = $('textarea.js-commit-message'); - e.preventDefault(); + }); + } +} + +// Local jQuery finder +MergeRequest.prototype.$ = function(selector) { + return this.$el.find(selector); +}; + +MergeRequest.prototype.initTabs = function() { + if (window.mrTabs) { + window.mrTabs.unbindEvents(); + } + window.mrTabs = new gl.MergeRequestTabs(this.opts); +}; + +MergeRequest.prototype.showAllCommits = function() { + this.$('.first-commits').remove(); + return this.$('.all-commits').removeClass('hide'); +}; + +MergeRequest.prototype.initMRBtnListeners = function() { + var _this; + _this = this; + return $('a.btn-close, a.btn-reopen').on('click', function(e) { + var $this, shouldSubmit; + $this = $(this); + shouldSubmit = $this.hasClass('btn-comment'); + if (shouldSubmit && $this.data('submitted')) { + return; + } - textarea.val(textarea.data('messageWithDescription')); - $('.js-with-description-hint').hide(); - $('.js-without-description-hint').show(); - }); + if (this.closeReopenReportToggle) this.closeReopenReportToggle.setDisable(); - $(document).on('click', 'a.js-without-description-link', function(e) { - var textarea = $('textarea.js-commit-message'); + if (shouldSubmit) { + if ($this.hasClass('btn-comment-and-close') || $this.hasClass('btn-comment-and-reopen')) { e.preventDefault(); + e.stopImmediatePropagation(); - textarea.val(textarea.data('messageWithoutDescription')); - $('.js-with-description-hint').show(); - $('.js-without-description-hint').hide(); - }); - }; - - MergeRequest.prototype.updateStatusText = function(classToRemove, classToAdd, newStatusText) { - $('.detail-page-header .status-box') - .removeClass(classToRemove) - .addClass(classToAdd) - .find('span') - .text(newStatusText); - }; - - MergeRequest.prototype.decreaseCounter = function(by = 1) { - const $el = $('.nav-links .js-merge-counter'); - const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); - - $el.text(gl.text.addDelimiter(count)); - }; - - return MergeRequest; - })(); -}).call(window); + _this.submitNoteForm($this.closest('form'), $this); + } + } + }); +}; + +MergeRequest.prototype.submitNoteForm = function(form, $button) { + var noteText; + noteText = form.find("textarea.js-note-text").val(); + if (noteText.trim().length > 0) { + form.submit(); + $button.data('submitted', true); + return $button.trigger('click'); + } +}; + +MergeRequest.prototype.initCommitMessageListeners = function() { + $(document).on('click', 'a.js-with-description-link', function(e) { + var textarea = $('textarea.js-commit-message'); + e.preventDefault(); + + textarea.val(textarea.data('messageWithDescription')); + $('.js-with-description-hint').hide(); + $('.js-without-description-hint').show(); + }); + + $(document).on('click', 'a.js-without-description-link', function(e) { + var textarea = $('textarea.js-commit-message'); + e.preventDefault(); + + textarea.val(textarea.data('messageWithoutDescription')); + $('.js-with-description-hint').show(); + $('.js-without-description-hint').hide(); + }); +}; + +MergeRequest.prototype.updateStatusText = function(classToRemove, classToAdd, newStatusText) { + $('.detail-page-header .status-box') + .removeClass(classToRemove) + .addClass(classToAdd) + .find('span') + .text(newStatusText); +}; + +MergeRequest.prototype.decreaseCounter = function(by = 1) { + const $el = $('.nav-links .js-merge-counter'); + const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0); + + $el.text(gl.text.addDelimiter(count)); +}; + +window.MergeRequest = MergeRequest; diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 7840f05a8ae..d73ebdb1a22 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -54,370 +54,368 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; // /* eslint-enable max-len */ -(() => { - // Store the `location` object, allowing for easier stubbing in tests - let location = window.location; +// Store the `location` object, allowing for easier stubbing in tests +let location = window.location; - class MergeRequestTabs { +class MergeRequestTabs { - constructor({ action, setUrl, stubLocation } = {}) { - this.diffsLoaded = false; - this.pipelinesLoaded = false; - this.commitsLoaded = false; - this.fixedLayoutPref = null; + constructor({ action, setUrl, stubLocation } = {}) { + this.diffsLoaded = false; + this.pipelinesLoaded = false; + this.commitsLoaded = false; + this.fixedLayoutPref = null; - this.setUrl = setUrl !== undefined ? setUrl : true; - this.setCurrentAction = this.setCurrentAction.bind(this); - this.tabShown = this.tabShown.bind(this); - this.showTab = this.showTab.bind(this); + this.setUrl = setUrl !== undefined ? setUrl : true; + this.setCurrentAction = this.setCurrentAction.bind(this); + this.tabShown = this.tabShown.bind(this); + this.showTab = this.showTab.bind(this); - if (stubLocation) { - location = stubLocation; - } - - this.bindEvents(); - this.activateTab(action); - this.initAffix(); + if (stubLocation) { + location = stubLocation; } - bindEvents() { - $(document) - .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) - .on('click', '.js-show-tab', this.showTab); + this.bindEvents(); + this.activateTab(action); + this.initAffix(); + } - $('.merge-request-tabs a[data-toggle="tab"]') - .on('click', this.clickTab); - } + bindEvents() { + $(document) + .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) + .on('click', '.js-show-tab', this.showTab); + + $('.merge-request-tabs a[data-toggle="tab"]') + .on('click', this.clickTab); + } - // Used in tests - unbindEvents() { - $(document) - .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) - .off('click', '.js-show-tab', this.showTab); + // Used in tests + unbindEvents() { + $(document) + .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown) + .off('click', '.js-show-tab', this.showTab); - $('.merge-request-tabs a[data-toggle="tab"]') - .off('click', this.clickTab); - } + $('.merge-request-tabs a[data-toggle="tab"]') + .off('click', this.clickTab); + } - destroyPipelinesView() { - if (this.commitPipelinesTable) { - this.commitPipelinesTable.$destroy(); - this.commitPipelinesTable = null; + destroyPipelinesView() { + if (this.commitPipelinesTable) { + this.commitPipelinesTable.$destroy(); + this.commitPipelinesTable = null; - document.querySelector('#commit-pipeline-table-view').innerHTML = ''; - } + document.querySelector('#commit-pipeline-table-view').innerHTML = ''; } + } - showTab(e) { + showTab(e) { + e.preventDefault(); + this.activateTab($(e.target).data('action')); + } + + clickTab(e) { + if (e.currentTarget && gl.utils.isMetaClick(e)) { + const targetLink = e.currentTarget.getAttribute('href'); + e.stopImmediatePropagation(); e.preventDefault(); - this.activateTab($(e.target).data('action')); + window.open(targetLink, '_blank'); } + } - clickTab(e) { - if (e.currentTarget && gl.utils.isMetaClick(e)) { - const targetLink = e.currentTarget.getAttribute('href'); - e.stopImmediatePropagation(); - e.preventDefault(); - window.open(targetLink, '_blank'); + tabShown(e) { + const $target = $(e.target); + const action = $target.data('action'); + + if (action === 'commits') { + this.loadCommits($target.attr('href')); + this.expandView(); + this.resetViewContainer(); + this.destroyPipelinesView(); + } else if (this.isDiffAction(action)) { + this.loadDiff($target.attr('href')); + if (Breakpoints.get().getBreakpointSize() !== 'lg') { + this.shrinkView(); } - } - - tabShown(e) { - const $target = $(e.target); - const action = $target.data('action'); - - if (action === 'commits') { - this.loadCommits($target.attr('href')); - this.expandView(); - this.resetViewContainer(); - this.destroyPipelinesView(); - } else if (this.isDiffAction(action)) { - this.loadDiff($target.attr('href')); - if (Breakpoints.get().getBreakpointSize() !== 'lg') { - this.shrinkView(); - } - if (this.diffViewType() === 'parallel') { - this.expandViewContainer(); - } - this.destroyPipelinesView(); - } else if (action === 'pipelines') { - this.resetViewContainer(); - this.mountPipelinesView(); - } else { - if (Breakpoints.get().getBreakpointSize() !== 'xs') { - this.expandView(); - } - this.resetViewContainer(); - this.destroyPipelinesView(); + if (this.diffViewType() === 'parallel') { + this.expandViewContainer(); } - if (this.setUrl) { - this.setCurrentAction(action); + this.destroyPipelinesView(); + } else if (action === 'pipelines') { + this.resetViewContainer(); + this.mountPipelinesView(); + } else { + if (Breakpoints.get().getBreakpointSize() !== 'xs') { + this.expandView(); } + this.resetViewContainer(); + this.destroyPipelinesView(); } + if (this.setUrl) { + this.setCurrentAction(action); + } + } - scrollToElement(container) { - if (location.hash) { - const offset = 0 - ( - $('.navbar-gitlab').outerHeight() + - $('.js-tabs-affix').outerHeight() - ); - const $el = $(`${container} ${location.hash}:not(.match)`); - if ($el.length) { - $.scrollTo($el[0], { offset }); - } + scrollToElement(container) { + if (location.hash) { + const offset = 0 - ( + $('.navbar-gitlab').outerHeight() + + $('.js-tabs-affix').outerHeight() + ); + const $el = $(`${container} ${location.hash}:not(.match)`); + if ($el.length) { + $.scrollTo($el[0], { offset }); } } + } + + // Activate a tab based on the current action + activateTab(action) { + // important note: the .tab('show') method triggers 'shown.bs.tab' event itself + $(`.merge-request-tabs a[data-action='${action}']`).tab('show'); + } - // Activate a tab based on the current action - activateTab(action) { - // important note: the .tab('show') method triggers 'shown.bs.tab' event itself - $(`.merge-request-tabs a[data-action='${action}']`).tab('show'); + // Replaces the current Merge Request-specific action in the URL with a new one + // + // If the action is "notes", the URL is reset to the standard + // `MergeRequests#show` route. + // + // Examples: + // + // location.pathname # => "/namespace/project/merge_requests/1" + // setCurrentAction('diffs') + // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // + // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // setCurrentAction('show') + // location.pathname # => "/namespace/project/merge_requests/1" + // + // location.pathname # => "/namespace/project/merge_requests/1/diffs" + // setCurrentAction('commits') + // location.pathname # => "/namespace/project/merge_requests/1/commits" + // + // Returns the new URL String + setCurrentAction(action) { + this.currentAction = action; + + // Remove a trailing '/commits' '/diffs' '/pipelines' + let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, ''); + + // Append the new action if we're on a tab other than 'notes' + if (this.currentAction !== 'show' && this.currentAction !== 'new') { + newState += `/${this.currentAction}`; } - // Replaces the current Merge Request-specific action in the URL with a new one - // - // If the action is "notes", the URL is reset to the standard - // `MergeRequests#show` route. - // - // Examples: - // - // location.pathname # => "/namespace/project/merge_requests/1" - // setCurrentAction('diffs') - // location.pathname # => "/namespace/project/merge_requests/1/diffs" - // - // location.pathname # => "/namespace/project/merge_requests/1/diffs" - // setCurrentAction('show') - // location.pathname # => "/namespace/project/merge_requests/1" - // - // location.pathname # => "/namespace/project/merge_requests/1/diffs" - // setCurrentAction('commits') - // location.pathname # => "/namespace/project/merge_requests/1/commits" - // - // Returns the new URL String - setCurrentAction(action) { - this.currentAction = action; + // Ensure parameters and hash come along for the ride + newState += location.search + location.hash; - // Remove a trailing '/commits' '/diffs' '/pipelines' - let newState = location.pathname.replace(/\/(commits|diffs|pipelines)(\.html)?\/?$/, ''); + // TODO: Consider refactoring in light of turbolinks removal. - // Append the new action if we're on a tab other than 'notes' - if (this.currentAction !== 'show' && this.currentAction !== 'new') { - newState += `/${this.currentAction}`; - } + // Replace the current history state with the new one without breaking + // Turbolinks' history. + // + // See https://github.com/rails/turbolinks/issues/363 + window.history.replaceState({ + url: newState, + }, document.title, newState); - // Ensure parameters and hash come along for the ride - newState += location.search + location.hash; + return newState; + } - // TODO: Consider refactoring in light of turbolinks removal. + loadCommits(source) { + if (this.commitsLoaded) { + return; + } + this.ajaxGet({ + url: `${source}.json`, + success: (data) => { + document.querySelector('div#commits').innerHTML = data.html; + gl.utils.localTimeAgo($('.js-timeago', 'div#commits')); + this.commitsLoaded = true; + this.scrollToElement('#commits'); + }, + }); + } - // Replace the current history state with the new one without breaking - // Turbolinks' history. - // - // See https://github.com/rails/turbolinks/issues/363 - window.history.replaceState({ - url: newState, - }, document.title, newState); + mountPipelinesView() { + const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); + const CommitPipelinesTable = gl.CommitPipelinesTable; + this.commitPipelinesTable = new CommitPipelinesTable({ + propsData: { + endpoint: pipelineTableViewEl.dataset.endpoint, + helpPagePath: pipelineTableViewEl.dataset.helpPagePath, + }, + }).$mount(); + + // $mount(el) replaces the el with the new rendered component. We need it in order to mount + // it everytime this tab is clicked - https://vuejs.org/v2/api/#vm-mount + pipelineTableViewEl.appendChild(this.commitPipelinesTable.$el); + } - return newState; + loadDiff(source) { + if (this.diffsLoaded) { + return; } - loadCommits(source) { - if (this.commitsLoaded) { - return; - } - this.ajaxGet({ - url: `${source}.json`, - success: (data) => { - document.querySelector('div#commits').innerHTML = data.html; - gl.utils.localTimeAgo($('.js-timeago', 'div#commits')); - this.commitsLoaded = true; - this.scrollToElement('#commits'); - }, - }); - } + // We extract pathname for the current Changes tab anchor href + // some pages like MergeRequestsController#new has query parameters on that anchor + const urlPathname = gl.utils.parseUrlPathname(source); - mountPipelinesView() { - const pipelineTableViewEl = document.querySelector('#commit-pipeline-table-view'); - const CommitPipelinesTable = gl.CommitPipelinesTable; - this.commitPipelinesTable = new CommitPipelinesTable({ - propsData: { - endpoint: pipelineTableViewEl.dataset.endpoint, - helpPagePath: pipelineTableViewEl.dataset.helpPagePath, - }, - }).$mount(); + this.ajaxGet({ + url: `${urlPathname}.json${location.search}`, + success: (data) => { + const $container = $('#diffs'); + $container.html(data.html); - // $mount(el) replaces the el with the new rendered component. We need it in order to mount - // it everytime this tab is clicked - https://vuejs.org/v2/api/#vm-mount - pipelineTableViewEl.appendChild(this.commitPipelinesTable.$el); - } + if (typeof gl.diffNotesCompileComponents !== 'undefined') { + gl.diffNotesCompileComponents(); + } - loadDiff(source) { - if (this.diffsLoaded) { - return; - } + gl.utils.localTimeAgo($('.js-timeago', 'div#diffs')); + $('#diffs .js-syntax-highlight').syntaxHighlight(); - // We extract pathname for the current Changes tab anchor href - // some pages like MergeRequestsController#new has query parameters on that anchor - const urlPathname = gl.utils.parseUrlPathname(source); - - this.ajaxGet({ - url: `${urlPathname}.json${location.search}`, - success: (data) => { - const $container = $('#diffs'); - $container.html(data.html); - - if (typeof gl.diffNotesCompileComponents !== 'undefined') { - gl.diffNotesCompileComponents(); - } - - gl.utils.localTimeAgo($('.js-timeago', 'div#diffs')); - $('#diffs .js-syntax-highlight').syntaxHighlight(); - - if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) { - this.expandViewContainer(); - } - this.diffsLoaded = true; - - new gl.Diff(); - this.scrollToElement('#diffs'); - - $('.diff-file').each((i, el) => { - new BlobForkSuggestion({ - openButtons: $(el).find('.js-edit-blob-link-fork-toggler'), - forkButtons: $(el).find('.js-fork-suggestion-button'), - cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'), - suggestionSections: $(el).find('.js-file-fork-suggestion-section'), - actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'), - }) - .init(); + if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) { + this.expandViewContainer(); + } + this.diffsLoaded = true; + + new gl.Diff(); + this.scrollToElement('#diffs'); + + $('.diff-file').each((i, el) => { + new BlobForkSuggestion({ + openButtons: $(el).find('.js-edit-blob-link-fork-toggler'), + forkButtons: $(el).find('.js-fork-suggestion-button'), + cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'), + suggestionSections: $(el).find('.js-file-fork-suggestion-section'), + actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'), + }) + .init(); + }); + + // Scroll any linked note into view + // Similar to `toggler_behavior` in the discussion tab + const hash = window.gl.utils.getLocationHash(); + const anchor = hash && $container.find(`.note[id="${hash}"]`); + if (anchor && anchor.length > 0) { + const notesContent = anchor.closest('.notes_content'); + const lineType = notesContent.hasClass('new') ? 'new' : 'old'; + notes.toggleDiffNote({ + target: anchor, + lineType, + forceShow: true, }); + anchor[0].scrollIntoView(); + window.gl.utils.handleLocationHash(); + // We have multiple elements on the page with `#note_xxx` + // (discussion and diff tabs) and `:target` only applies to the first + anchor.addClass('target'); + } + }, + }); + } - // Scroll any linked note into view - // Similar to `toggler_behavior` in the discussion tab - const hash = window.gl.utils.getLocationHash(); - const anchor = hash && $container.find(`.note[id="${hash}"]`); - if (anchor && anchor.length > 0) { - const notesContent = anchor.closest('.notes_content'); - const lineType = notesContent.hasClass('new') ? 'new' : 'old'; - notes.toggleDiffNote({ - target: anchor, - lineType, - forceShow: true, - }); - anchor[0].scrollIntoView(); - window.gl.utils.handleLocationHash(); - // We have multiple elements on the page with `#note_xxx` - // (discussion and diff tabs) and `:target` only applies to the first - anchor.addClass('target'); - } - }, - }); - } + // Show or hide the loading spinner + // + // status - Boolean, true to show, false to hide + toggleLoading(status) { + $('.mr-loading-status .loading').toggle(status); + } - // Show or hide the loading spinner - // - // status - Boolean, true to show, false to hide - toggleLoading(status) { - $('.mr-loading-status .loading').toggle(status); - } + ajaxGet(options) { + const defaults = { + beforeSend: () => this.toggleLoading(true), + error: () => new Flash('An error occurred while fetching this tab.', 'alert'), + complete: () => this.toggleLoading(false), + dataType: 'json', + type: 'GET', + }; + $.ajax($.extend({}, defaults, options)); + } - ajaxGet(options) { - const defaults = { - beforeSend: () => this.toggleLoading(true), - error: () => new Flash('An error occurred while fetching this tab.', 'alert'), - complete: () => this.toggleLoading(false), - dataType: 'json', - type: 'GET', - }; - $.ajax($.extend({}, defaults, options)); - } + diffViewType() { + return $('.inline-parallel-buttons a.active').data('view-type'); + } - diffViewType() { - return $('.inline-parallel-buttons a.active').data('view-type'); - } + isDiffAction(action) { + return action === 'diffs' || action === 'new/diffs'; + } - isDiffAction(action) { - return action === 'diffs' || action === 'new/diffs'; + expandViewContainer() { + const $wrapper = $('.content-wrapper .container-fluid'); + if (this.fixedLayoutPref === null) { + this.fixedLayoutPref = $wrapper.hasClass('container-limited'); } + $wrapper.removeClass('container-limited'); + } - expandViewContainer() { - const $wrapper = $('.content-wrapper .container-fluid'); - if (this.fixedLayoutPref === null) { - this.fixedLayoutPref = $wrapper.hasClass('container-limited'); - } - $wrapper.removeClass('container-limited'); + resetViewContainer() { + if (this.fixedLayoutPref !== null) { + $('.content-wrapper .container-fluid') + .toggleClass('container-limited', this.fixedLayoutPref); } + } - resetViewContainer() { - if (this.fixedLayoutPref !== null) { - $('.content-wrapper .container-fluid') - .toggleClass('container-limited', this.fixedLayoutPref); - } - } + shrinkView() { + const $gutterIcon = $('.js-sidebar-toggle i:visible'); - shrinkView() { - const $gutterIcon = $('.js-sidebar-toggle i:visible'); + // Wait until listeners are set + setTimeout(() => { + // Only when sidebar is expanded + if ($gutterIcon.is('.fa-angle-double-right')) { + $gutterIcon.closest('a').trigger('click', [true]); + } + }, 0); + } - // Wait until listeners are set - setTimeout(() => { - // Only when sidebar is expanded - if ($gutterIcon.is('.fa-angle-double-right')) { - $gutterIcon.closest('a').trigger('click', [true]); - } - }, 0); + // Expand the issuable sidebar unless the user explicitly collapsed it + expandView() { + if (Cookies.get('collapsed_gutter') === 'true') { + return; } + const $gutterIcon = $('.js-sidebar-toggle i:visible'); - // Expand the issuable sidebar unless the user explicitly collapsed it - expandView() { - if (Cookies.get('collapsed_gutter') === 'true') { - return; + // Wait until listeners are set + setTimeout(() => { + // Only when sidebar is collapsed + if ($gutterIcon.is('.fa-angle-double-left')) { + $gutterIcon.closest('a').trigger('click', [true]); } - const $gutterIcon = $('.js-sidebar-toggle i:visible'); + }, 0); + } - // Wait until listeners are set - setTimeout(() => { - // Only when sidebar is collapsed - if ($gutterIcon.is('.fa-angle-double-left')) { - $gutterIcon.closest('a').trigger('click', [true]); - } - }, 0); - } + initAffix() { + const $tabs = $('.js-tabs-affix'); + const $fixedNav = $('.navbar-gitlab'); + + // Screen space on small screens is usually very sparse + // So we dont affix the tabs on these + if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return; + + /** + If the browser does not support position sticky, it returns the position as static. + If the browser does support sticky, then we allow the browser to handle it, if not + then we default back to Bootstraps affix + **/ + if ($tabs.css('position') !== 'static') return; + + const $diffTabs = $('#diff-notes-app'); + + $tabs.off('affix.bs.affix affix-top.bs.affix') + .affix({ + offset: { + top: () => ( + $diffTabs.offset().top - $tabs.height() - $fixedNav.height() + ), + }, + }) + .on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() })) + .on('affix-top.bs.affix', () => $diffTabs.css({ marginTop: '' })); - initAffix() { - const $tabs = $('.js-tabs-affix'); - const $fixedNav = $('.navbar-gitlab'); - - // Screen space on small screens is usually very sparse - // So we dont affix the tabs on these - if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return; - - /** - If the browser does not support position sticky, it returns the position as static. - If the browser does support sticky, then we allow the browser to handle it, if not - then we default back to Bootstraps affix - **/ - if ($tabs.css('position') !== 'static') return; - - const $diffTabs = $('#diff-notes-app'); - - $tabs.off('affix.bs.affix affix-top.bs.affix') - .affix({ - offset: { - top: () => ( - $diffTabs.offset().top - $tabs.height() - $fixedNav.height() - ), - }, - }) - .on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() })) - .on('affix-top.bs.affix', () => $diffTabs.css({ marginTop: '' })); - - // Fix bug when reloading the page already scrolling - if ($tabs.hasClass('affix')) { - $tabs.trigger('affix.bs.affix'); - } + // Fix bug when reloading the page already scrolling + if ($tabs.hasClass('affix')) { + $tabs.trigger('affix.bs.affix'); } } +} - window.gl = window.gl || {}; - window.gl.MergeRequestTabs = MergeRequestTabs; -})(); +window.gl = window.gl || {}; +window.gl.MergeRequestTabs = MergeRequestTabs; diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index 3e07ec4d0aa..6f503b7293a 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -2,52 +2,48 @@ /* global Flash */ /* global Sortable */ -(function() { - this.Milestone = (function() { - function Milestone() { - this.bindTabsSwitching(); - - // Load merge request tab if it is active - // merge request tab is active based on different conditions in the backend - this.loadTab($('.js-milestone-tabs .active a')); - - this.loadInitialTab(); - } - - Milestone.prototype.bindTabsSwitching = function() { - return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { - const $target = $(e.target); - - location.hash = $target.attr('href'); - this.loadTab($target); - }); - }; - - Milestone.prototype.loadInitialTab = function() { - const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); - - if ($target.length) { - $target.tab('show'); - } - }; - - Milestone.prototype.loadTab = function($target) { - const endpoint = $target.data('endpoint'); - const tabElId = $target.attr('href'); - - if (endpoint && !$target.hasClass('is-loaded')) { - $.ajax({ - url: endpoint, - dataType: 'JSON', - }) - .fail(() => new Flash('Error loading milestone tab')) - .done((data) => { - $(tabElId).html(data.html); - $target.addClass('is-loaded'); - }); - } - }; - - return Milestone; - })(); -}).call(window); +function Milestone() { + this.bindTabsSwitching(); + + // Load merge request tab if it is active + // merge request tab is active based on different conditions in the backend + this.loadTab($('.js-milestone-tabs .active a')); + + this.loadInitialTab(); +} + +Milestone.prototype.bindTabsSwitching = function() { + return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { + const $target = $(e.target); + + location.hash = $target.attr('href'); + this.loadTab($target); + }); +}; + +Milestone.prototype.loadInitialTab = function() { + const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); + + if ($target.length) { + $target.tab('show'); + } +}; + +Milestone.prototype.loadTab = function($target) { + const endpoint = $target.data('endpoint'); + const tabElId = $target.attr('href'); + + if (endpoint && !$target.hasClass('is-loaded')) { + $.ajax({ + url: endpoint, + dataType: 'JSON', + }) + .fail(() => new Flash('Error loading milestone tab')) + .done((data) => { + $(tabElId).html(data.html); + $target.addClass('is-loaded'); + }); + } +}; + +window.Milestone = Milestone; diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 9d481d7c003..bde4923fd2e 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -2,224 +2,220 @@ /* global Issuable */ /* global ListMilestone */ -(function() { - this.MilestoneSelect = (function() { - function MilestoneSelect(currentProject, els) { - var _this, $els; - if (currentProject != null) { - _this = this; - this.currentProject = JSON.parse(currentProject); - } +function MilestoneSelect(currentProject, els) { + var _this, $els; + if (currentProject != null) { + _this = this; + this.currentProject = JSON.parse(currentProject); + } - $els = $(els); + $els = $(els); - if (!els) { - $els = $('.js-milestone-select'); - } + if (!els) { + $els = $('.js-milestone-select'); + } - $els.each(function(i, dropdown) { - var $block, $dropdown, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, collapsedSidebarLabelTemplate, defaultLabel, defaultNo, issuableId, issueUpdateURL, milestoneLinkNoneTemplate, milestoneLinkTemplate, milestonesUrl, projectId, selectedMilestone, selectedMilestoneDefault, showAny, showNo, showUpcoming, showStarted, useId, showMenuAbove; - $dropdown = $(dropdown); - projectId = $dropdown.data('project-id'); - milestonesUrl = $dropdown.data('milestones'); - issueUpdateURL = $dropdown.data('issueUpdate'); - showNo = $dropdown.data('show-no'); - showAny = $dropdown.data('show-any'); - showMenuAbove = $dropdown.data('showMenuAbove'); - showUpcoming = $dropdown.data('show-upcoming'); - showStarted = $dropdown.data('show-started'); - useId = $dropdown.data('use-id'); - defaultLabel = $dropdown.data('default-label'); - defaultNo = $dropdown.data('default-no'); - issuableId = $dropdown.data('issuable-id'); - abilityName = $dropdown.data('ability-name'); - $selectbox = $dropdown.closest('.selectbox'); - $block = $selectbox.closest('.block'); - $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); - $value = $block.find('.value'); - $loading = $block.find('.block-loading').fadeOut(); - selectedMilestoneDefault = (showAny ? '' : null); - selectedMilestoneDefault = (showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault); - selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault; - if (issueUpdateURL) { - milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); - milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; - collapsedSidebarLabelTemplate = _.template('<span class="has-tooltip" data-container="body" title="<%- remaining %>" data-placement="left"> <%- title %> </span>'); - } - return $dropdown.glDropdown({ - showMenuAbove: showMenuAbove, - data: function(term, callback) { - return $.ajax({ - url: milestonesUrl - }).done(function(data) { - var extraOptions = []; - if (showAny) { - extraOptions.push({ - id: 0, - name: '', - title: 'Any Milestone' - }); - } - if (showNo) { - extraOptions.push({ - id: -1, - name: 'No Milestone', - title: 'No Milestone' - }); - } - if (showUpcoming) { - extraOptions.push({ - id: -2, - name: '#upcoming', - title: 'Upcoming' - }); - } - if (showStarted) { - extraOptions.push({ - id: -3, - name: '#started', - title: 'Started' - }); - } - if (extraOptions.length) { - extraOptions.push('divider'); - } - - callback(extraOptions.concat(data)); - if (showMenuAbove) { - $dropdown.data('glDropdown').positionMenuAbove(); - } - $(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active'); + $els.each(function(i, dropdown) { + var $block, $dropdown, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, collapsedSidebarLabelTemplate, defaultLabel, defaultNo, issuableId, issueUpdateURL, milestoneLinkNoneTemplate, milestoneLinkTemplate, milestonesUrl, projectId, selectedMilestone, selectedMilestoneDefault, showAny, showNo, showUpcoming, showStarted, useId, showMenuAbove; + $dropdown = $(dropdown); + projectId = $dropdown.data('project-id'); + milestonesUrl = $dropdown.data('milestones'); + issueUpdateURL = $dropdown.data('issueUpdate'); + showNo = $dropdown.data('show-no'); + showAny = $dropdown.data('show-any'); + showMenuAbove = $dropdown.data('showMenuAbove'); + showUpcoming = $dropdown.data('show-upcoming'); + showStarted = $dropdown.data('show-started'); + useId = $dropdown.data('use-id'); + defaultLabel = $dropdown.data('default-label'); + defaultNo = $dropdown.data('default-no'); + issuableId = $dropdown.data('issuable-id'); + abilityName = $dropdown.data('ability-name'); + $selectbox = $dropdown.closest('.selectbox'); + $block = $selectbox.closest('.block'); + $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); + $value = $block.find('.value'); + $loading = $block.find('.block-loading').fadeOut(); + selectedMilestoneDefault = (showAny ? '' : null); + selectedMilestoneDefault = (showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault); + selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault; + if (issueUpdateURL) { + milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); + milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; + collapsedSidebarLabelTemplate = _.template('<span class="has-tooltip" data-container="body" title="<%- remaining %>" data-placement="left"> <%- title %> </span>'); + } + return $dropdown.glDropdown({ + showMenuAbove: showMenuAbove, + data: function(term, callback) { + return $.ajax({ + url: milestonesUrl + }).done(function(data) { + var extraOptions = []; + if (showAny) { + extraOptions.push({ + id: 0, + name: '', + title: 'Any Milestone' }); - }, - renderRow: function(milestone) { - return ` - <li data-milestone-id="${milestone.name}"> - <a href='#' class='dropdown-menu-milestone-link'> - ${_.escape(milestone.title)} - </a> - </li> - `; - }, - filterable: true, - search: { - fields: ['title'] - }, - selectable: true, - toggleLabel: function(selected, el, e) { - if (selected && 'id' in selected && $(el).hasClass('is-active')) { - return selected.title; - } else { - return defaultLabel; - } - }, - defaultLabel: defaultLabel, - fieldName: $dropdown.data('field-name'), - text: function(milestone) { - return _.escape(milestone.title); - }, - id: function(milestone) { - if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) { - return milestone.name; - } else { - return milestone.id; - } - }, - isSelected: function(milestone) { - return milestone.name === selectedMilestone; - }, - hidden: function() { - $selectbox.hide(); - // display:block overrides the hide-collapse rule - return $value.css('display', ''); - }, - opened: function(e) { - const $el = $(e.currentTarget); - if ($dropdown.hasClass('js-issue-board-sidebar')) { - selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault; - } - $('a.is-active', $el).removeClass('is-active'); - $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active'); - }, - vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(options) { - const { $el, e } = options; - let selected = options.selectedObj; - var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore; - page = $('body').data('page'); - isIssueIndex = page === 'projects:issues:index'; - isMRIndex = (page === page && page === 'projects:merge_requests:index'); - isSelecting = (selected.name !== selectedMilestone); - selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault; - if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { - e.preventDefault(); - return; - } + } + if (showNo) { + extraOptions.push({ + id: -1, + name: 'No Milestone', + title: 'No Milestone' + }); + } + if (showUpcoming) { + extraOptions.push({ + id: -2, + name: '#upcoming', + title: 'Upcoming' + }); + } + if (showStarted) { + extraOptions.push({ + id: -3, + name: '#started', + title: 'Started' + }); + } + if (extraOptions.length) { + extraOptions.push('divider'); + } - if ($dropdown.closest('.add-issues-modal').length) { - boardsStore = gl.issueBoards.ModalStore.store.filter; - } + callback(extraOptions.concat(data)); + if (showMenuAbove) { + $dropdown.data('glDropdown').positionMenuAbove(); + } + $(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active'); + }); + }, + renderRow: function(milestone) { + return ` + <li data-milestone-id="${milestone.name}"> + <a href='#' class='dropdown-menu-milestone-link'> + ${_.escape(milestone.title)} + </a> + </li> + `; + }, + filterable: true, + search: { + fields: ['title'] + }, + selectable: true, + toggleLabel: function(selected, el, e) { + if (selected && 'id' in selected && $(el).hasClass('is-active')) { + return selected.title; + } else { + return defaultLabel; + } + }, + defaultLabel: defaultLabel, + fieldName: $dropdown.data('field-name'), + text: function(milestone) { + return _.escape(milestone.title); + }, + id: function(milestone) { + if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) { + return milestone.name; + } else { + return milestone.id; + } + }, + isSelected: function(milestone) { + return milestone.name === selectedMilestone; + }, + hidden: function() { + $selectbox.hide(); + // display:block overrides the hide-collapse rule + return $value.css('display', ''); + }, + opened: function(e) { + const $el = $(e.currentTarget); + if ($dropdown.hasClass('js-issue-board-sidebar')) { + selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault; + } + $('a.is-active', $el).removeClass('is-active'); + $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active'); + }, + vue: $dropdown.hasClass('js-issue-board-sidebar'), + clicked: function(options) { + const { $el, e } = options; + let selected = options.selectedObj; + var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore; + page = $('body').data('page'); + isIssueIndex = page === 'projects:issues:index'; + isMRIndex = (page === page && page === 'projects:merge_requests:index'); + isSelecting = (selected.name !== selectedMilestone); + selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault; + if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { + e.preventDefault(); + return; + } + + if ($dropdown.closest('.add-issues-modal').length) { + boardsStore = gl.issueBoards.ModalStore.store.filter; + } - if (boardsStore) { - boardsStore[$dropdown.data('field-name')] = selected.name; - e.preventDefault(); - } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { - return Issuable.filterResults($dropdown.closest('form')); - } else if ($dropdown.hasClass('js-filter-submit')) { - return $dropdown.closest('form').submit(); - } else if ($dropdown.hasClass('js-issue-board-sidebar')) { - if (selected.id !== -1 && isSelecting) { - gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({ - id: selected.id, - title: selected.name - })); - } else { - gl.issueBoards.boardStoreIssueDelete('milestone'); - } + if (boardsStore) { + boardsStore[$dropdown.data('field-name')] = selected.name; + e.preventDefault(); + } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { + return Issuable.filterResults($dropdown.closest('form')); + } else if ($dropdown.hasClass('js-filter-submit')) { + return $dropdown.closest('form').submit(); + } else if ($dropdown.hasClass('js-issue-board-sidebar')) { + if (selected.id !== -1 && isSelecting) { + gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({ + id: selected.id, + title: selected.name + })); + } else { + gl.issueBoards.boardStoreIssueDelete('milestone'); + } - $dropdown.trigger('loading.gl.dropdown'); - $loading.removeClass('hidden').fadeIn(); + $dropdown.trigger('loading.gl.dropdown'); + $loading.removeClass('hidden').fadeIn(); - gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) - .then(function () { - $dropdown.trigger('loaded.gl.dropdown'); - $loading.fadeOut(); - }) - .catch(() => { - $loading.fadeOut(); - }); + gl.issueBoards.BoardsStore.detail.issue.update($dropdown.attr('data-issue-update')) + .then(function () { + $dropdown.trigger('loaded.gl.dropdown'); + $loading.fadeOut(); + }) + .catch(() => { + $loading.fadeOut(); + }); + } else { + selected = $selectbox.find('input[type="hidden"]').val(); + data = {}; + data[abilityName] = {}; + data[abilityName].milestone_id = selected != null ? selected : null; + $loading.removeClass('hidden').fadeIn(); + $dropdown.trigger('loading.gl.dropdown'); + return $.ajax({ + type: 'PUT', + url: issueUpdateURL, + data: data + }).done(function(data) { + $dropdown.trigger('loaded.gl.dropdown'); + $loading.fadeOut(); + $selectbox.hide(); + $value.css('display', ''); + if (data.milestone != null) { + data.milestone.full_path = _this.currentProject.full_path; + data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date); + $value.html(milestoneLinkTemplate(data.milestone)); + return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone)); } else { - selected = $selectbox.find('input[type="hidden"]').val(); - data = {}; - data[abilityName] = {}; - data[abilityName].milestone_id = selected != null ? selected : null; - $loading.removeClass('hidden').fadeIn(); - $dropdown.trigger('loading.gl.dropdown'); - return $.ajax({ - type: 'PUT', - url: issueUpdateURL, - data: data - }).done(function(data) { - $dropdown.trigger('loaded.gl.dropdown'); - $loading.fadeOut(); - $selectbox.hide(); - $value.css('display', ''); - if (data.milestone != null) { - data.milestone.full_path = _this.currentProject.full_path; - data.milestone.remaining = gl.utils.timeFor(data.milestone.due_date); - $value.html(milestoneLinkTemplate(data.milestone)); - return $sidebarCollapsedValue.find('span').html(collapsedSidebarLabelTemplate(data.milestone)); - } else { - $value.html(milestoneLinkNoneTemplate); - return $sidebarCollapsedValue.find('span').text('No'); - } - }); + $value.html(milestoneLinkNoneTemplate); + return $sidebarCollapsedValue.find('span').text('No'); } - } - }); - }); - } + }); + } + } + }); + }); +} - return MilestoneSelect; - })(); -}).call(window); +window.MilestoneSelect = MilestoneSelect; diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index 5da2db063a4..6ecd54e67f6 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -1,85 +1,78 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, vars-on-top, one-var-declaration-per-line, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, no-param-reassign, no-cond-assign, max-len */ import Api from './api'; -(function() { - window.NamespaceSelect = (function() { - function NamespaceSelect(opts) { - this.onSelectItem = this.onSelectItem.bind(this); - var fieldName, showAny; - this.dropdown = opts.dropdown; - showAny = true; - fieldName = 'namespace_id'; - if (this.dropdown.attr('data-field-name')) { - fieldName = this.dropdown.data('fieldName'); +function NamespaceSelect(opts) { + this.onSelectItem = this.onSelectItem.bind(this); + var fieldName, showAny; + this.dropdown = opts.dropdown; + showAny = true; + fieldName = 'namespace_id'; + if (this.dropdown.attr('data-field-name')) { + fieldName = this.dropdown.data('fieldName'); + } + if (this.dropdown.attr('data-show-any')) { + showAny = this.dropdown.data('showAny'); + } + this.dropdown.glDropdown({ + filterable: true, + selectable: true, + filterRemote: true, + search: { + fields: ['path'] + }, + fieldName: fieldName, + toggleLabel: function(selected) { + if (selected.id == null) { + return selected.text; + } else { + return selected.kind + ": " + selected.full_path; } - if (this.dropdown.attr('data-show-any')) { - showAny = this.dropdown.data('showAny'); - } - this.dropdown.glDropdown({ - filterable: true, - selectable: true, - filterRemote: true, - search: { - fields: ['path'] - }, - fieldName: fieldName, - toggleLabel: function(selected) { - if (selected.id == null) { - return selected.text; - } else { - return selected.kind + ": " + selected.full_path; - } - }, - data: function(term, dataCallback) { - return Api.namespaces(term, function(namespaces) { - var anyNamespace; - if (showAny) { - anyNamespace = { - text: 'Any namespace', - id: null - }; - namespaces.unshift(anyNamespace); - namespaces.splice(1, 0, 'divider'); - } - return dataCallback(namespaces); - }); - }, - text: function(namespace) { - if (namespace.id == null) { - return namespace.text; - } else { - return namespace.kind + ": " + namespace.full_path; - } - }, - renderRow: this.renderRow, - clicked: this.onSelectItem + }, + data: function(term, dataCallback) { + return Api.namespaces(term, function(namespaces) { + var anyNamespace; + if (showAny) { + anyNamespace = { + text: 'Any namespace', + id: null + }; + namespaces.unshift(anyNamespace); + namespaces.splice(1, 0, 'divider'); + } + return dataCallback(namespaces); }); - } - - NamespaceSelect.prototype.onSelectItem = function(options) { - const { e } = options; - return e.preventDefault(); - }; + }, + text: function(namespace) { + if (namespace.id == null) { + return namespace.text; + } else { + return namespace.kind + ": " + namespace.full_path; + } + }, + renderRow: this.renderRow, + clicked: this.onSelectItem + }); +} - return NamespaceSelect; - })(); +NamespaceSelect.prototype.onSelectItem = function(options) { + const { e } = options; + return e.preventDefault(); +}; - window.NamespaceSelects = (function() { - function NamespaceSelects(opts) { - var ref; - if (opts == null) { - opts = {}; - } - this.$dropdowns = (ref = opts.$dropdowns) != null ? ref : $('.js-namespace-select'); - this.$dropdowns.each(function(i, dropdown) { - var $dropdown; - $dropdown = $(dropdown); - return new window.NamespaceSelect({ - dropdown: $dropdown - }); - }); - } +function NamespaceSelects(opts) { + var ref; + if (opts == null) { + opts = {}; + } + this.$dropdowns = (ref = opts.$dropdowns) != null ? ref : $('.js-namespace-select'); + this.$dropdowns.each(function(i, dropdown) { + var $dropdown; + $dropdown = $(dropdown); + return new window.NamespaceSelect({ + dropdown: $dropdown + }); + }); +} - return NamespaceSelects; - })(); -}).call(window); +window.NamespaceSelect = NamespaceSelect; +window.NamespaceSelects = NamespaceSelects; diff --git a/app/assets/javascripts/new_branch_form.js b/app/assets/javascripts/new_branch_form.js index 39fb302b644..ad11ec92e58 100644 --- a/app/assets/javascripts/new_branch_form.js +++ b/app/assets/javascripts/new_branch_form.js @@ -1,97 +1,93 @@ /* eslint-disable func-names, space-before-function-paren, no-var, one-var, prefer-rest-params, max-len, vars-on-top, wrap-iife, consistent-return, comma-dangle, one-var-declaration-per-line, quotes, no-return-assign, prefer-arrow-callback, prefer-template, no-shadow, no-else-return, max-len, object-shorthand */ import RefSelectDropdown from '~/ref_select_dropdown'; -(function() { - this.NewBranchForm = (function() { - function NewBranchForm(form, availableRefs) { - this.validate = this.validate.bind(this); - this.branchNameError = form.find('.js-branch-name-error'); - this.name = form.find('.js-branch-name'); - this.ref = form.find('#ref'); - new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new - this.setupRestrictions(); - this.addBinding(); - this.init(); - } +function NewBranchForm(form, availableRefs) { + this.validate = this.validate.bind(this); + this.branchNameError = form.find('.js-branch-name-error'); + this.name = form.find('.js-branch-name'); + this.ref = form.find('#ref'); + new RefSelectDropdown($('.js-branch-select'), availableRefs); // eslint-disable-line no-new + this.setupRestrictions(); + this.addBinding(); + this.init(); +} - NewBranchForm.prototype.addBinding = function() { - return this.name.on('blur', this.validate); - }; +NewBranchForm.prototype.addBinding = function() { + return this.name.on('blur', this.validate); +}; - NewBranchForm.prototype.init = function() { - if (this.name.length && this.name.val().length > 0) { - return this.name.trigger('blur'); - } - }; +NewBranchForm.prototype.init = function() { + if (this.name.length && this.name.val().length > 0) { + return this.name.trigger('blur'); + } +}; - NewBranchForm.prototype.setupRestrictions = function() { - var endsWith, invalid, single, startsWith; - startsWith = { - pattern: /^(\/|\.)/g, - prefix: "can't start with", - conjunction: "or" - }; - endsWith = { - pattern: /(\/|\.|\.lock)$/g, - prefix: "can't end in", - conjunction: "or" - }; - invalid = { - pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, - prefix: "can't contain", - conjunction: ", " - }; - single = { - pattern: /^@+$/g, - prefix: "can't be", - conjunction: "or" - }; - return this.restrictions = [startsWith, invalid, endsWith, single]; - }; +NewBranchForm.prototype.setupRestrictions = function() { + var endsWith, invalid, single, startsWith; + startsWith = { + pattern: /^(\/|\.)/g, + prefix: "can't start with", + conjunction: "or" + }; + endsWith = { + pattern: /(\/|\.|\.lock)$/g, + prefix: "can't end in", + conjunction: "or" + }; + invalid = { + pattern: /(\s|~|\^|:|\?|\*|\[|\\|\.\.|@\{|\/{2,}){1}/g, + prefix: "can't contain", + conjunction: ", " + }; + single = { + pattern: /^@+$/g, + prefix: "can't be", + conjunction: "or" + }; + return this.restrictions = [startsWith, invalid, endsWith, single]; +}; - NewBranchForm.prototype.validate = function() { - var errorMessage, errors, formatter, unique, validator; - const indexOf = [].indexOf; +NewBranchForm.prototype.validate = function() { + var errorMessage, errors, formatter, unique, validator; + const indexOf = [].indexOf; - this.branchNameError.empty(); - unique = function(values, value) { - if (indexOf.call(values, value) === -1) { - values.push(value); - } - return values; - }; - formatter = function(values, restriction) { - var formatted; - formatted = values.map(function(value) { - switch (false) { - case !/\s/.test(value): - return 'spaces'; - case !/\/{2,}/g.test(value): - return 'consecutive slashes'; - default: - return "'" + value + "'"; - } - }); - return restriction.prefix + " " + (formatted.join(restriction.conjunction)); - }; - validator = (function(_this) { - return function(errors, restriction) { - var matched; - matched = _this.name.val().match(restriction.pattern); - if (matched) { - return errors.concat(formatter(matched.reduce(unique, []), restriction)); - } else { - return errors; - } - }; - })(this); - errors = this.restrictions.reduce(validator, []); - if (errors.length > 0) { - errorMessage = $("<span/>").text(errors.join(', ')); - return this.branchNameError.append(errorMessage); + this.branchNameError.empty(); + unique = function(values, value) { + if (indexOf.call(values, value) === -1) { + values.push(value); + } + return values; + }; + formatter = function(values, restriction) { + var formatted; + formatted = values.map(function(value) { + switch (false) { + case !/\s/.test(value): + return 'spaces'; + case !/\/{2,}/g.test(value): + return 'consecutive slashes'; + default: + return "'" + value + "'"; + } + }); + return restriction.prefix + " " + (formatted.join(restriction.conjunction)); + }; + validator = (function(_this) { + return function(errors, restriction) { + var matched; + matched = _this.name.val().match(restriction.pattern); + if (matched) { + return errors.concat(formatter(matched.reduce(unique, []), restriction)); + } else { + return errors; } }; + })(this); + errors = this.restrictions.reduce(validator, []); + if (errors.length > 0) { + errorMessage = $("<span/>").text(errors.join(', ')); + return this.branchNameError.append(errorMessage); + } +}; - return NewBranchForm; - })(); -}).call(window); +window.NewBranchForm = NewBranchForm; diff --git a/app/assets/javascripts/new_commit_form.js b/app/assets/javascripts/new_commit_form.js index 04073ef7270..9f7820b05f8 100644 --- a/app/assets/javascripts/new_commit_form.js +++ b/app/assets/javascripts/new_commit_form.js @@ -1,32 +1,29 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-return-assign, max-len */ -(function() { - this.NewCommitForm = (function() { - function NewCommitForm(form) { - this.form = form; - this.renderDestination = this.renderDestination.bind(this); - this.branchName = form.find('.js-branch-name'); - this.originalBranch = form.find('.js-original-branch'); - this.createMergeRequest = form.find('.js-create-merge-request'); - this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); - this.branchName.keyup(this.renderDestination); - this.renderDestination(); - } - NewCommitForm.prototype.renderDestination = function() { - var different; - different = this.branchName.val() !== this.originalBranch.val(); - if (different) { - this.createMergeRequestContainer.show(); - if (!this.wasDifferent) { - this.createMergeRequest.prop('checked', true); - } - } else { - this.createMergeRequestContainer.hide(); - this.createMergeRequest.prop('checked', false); - } - return this.wasDifferent = different; - }; +function NewCommitForm(form) { + this.form = form; + this.renderDestination = this.renderDestination.bind(this); + this.branchName = form.find('.js-branch-name'); + this.originalBranch = form.find('.js-original-branch'); + this.createMergeRequest = form.find('.js-create-merge-request'); + this.createMergeRequestContainer = form.find('.js-create-merge-request-container'); + this.branchName.keyup(this.renderDestination); + this.renderDestination(); +} + +NewCommitForm.prototype.renderDestination = function() { + var different; + different = this.branchName.val() !== this.originalBranch.val(); + if (different) { + this.createMergeRequestContainer.show(); + if (!this.wasDifferent) { + this.createMergeRequest.prop('checked', true); + } + } else { + this.createMergeRequestContainer.hide(); + this.createMergeRequest.prop('checked', false); + } + return this.wasDifferent = different; +}; - return NewCommitForm; - })(); -}).call(window); +window.NewCommitForm = NewCommitForm; diff --git a/app/assets/javascripts/notifications_dropdown.js b/app/assets/javascripts/notifications_dropdown.js index 838356133cd..f9f486fb4d8 100644 --- a/app/assets/javascripts/notifications_dropdown.js +++ b/app/assets/javascripts/notifications_dropdown.js @@ -1,31 +1,27 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, consistent-return, prefer-arrow-callback, no-else-return, max-len */ /* global Flash */ -(function() { - this.NotificationsDropdown = (function() { - function NotificationsDropdown() { - $(document).off('click', '.update-notification').on('click', '.update-notification', function(e) { - var form, label, notificationLevel; - e.preventDefault(); - if ($(this).is('.is-active') && $(this).data('notification-level') === 'custom') { - return; - } - notificationLevel = $(this).data('notification-level'); - label = $(this).data('notification-title'); - form = $(this).parents('.notification-form:first'); - form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner'); - form.find('#notification_setting_level').val(notificationLevel); - return form.submit(); - }); - $(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) { - if (data.saved) { - return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html); - } else { - return new Flash('Failed to save new settings', 'alert'); - } - }); +function NotificationsDropdown() { + $(document).off('click', '.update-notification').on('click', '.update-notification', function(e) { + var form, label, notificationLevel; + e.preventDefault(); + if ($(this).is('.is-active') && $(this).data('notification-level') === 'custom') { + return; } + notificationLevel = $(this).data('notification-level'); + label = $(this).data('notification-title'); + form = $(this).parents('.notification-form:first'); + form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner'); + form.find('#notification_setting_level').val(notificationLevel); + return form.submit(); + }); + $(document).off('ajax:success', '.notification-form').on('ajax:success', '.notification-form', function(e, data) { + if (data.saved) { + return $(e.currentTarget).closest('.js-notification-dropdown').replaceWith(data.html); + } else { + return new Flash('Failed to save new settings', 'alert'); + } + }); +} - return NotificationsDropdown; - })(); -}).call(window); +window.NotificationsDropdown = NotificationsDropdown; diff --git a/app/assets/javascripts/notifications_form.js b/app/assets/javascripts/notifications_form.js index 2ab9c4fed2c..d8709a6fa5f 100644 --- a/app/assets/javascripts/notifications_form.js +++ b/app/assets/javascripts/notifications_form.js @@ -1,55 +1,51 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, one-var-declaration-per-line, newline-per-chained-call, comma-dangle, consistent-return, prefer-arrow-callback, max-len */ -(function() { - this.NotificationsForm = (function() { - function NotificationsForm() { - this.toggleCheckbox = this.toggleCheckbox.bind(this); - this.removeEventListeners(); - this.initEventListeners(); - } +function NotificationsForm() { + this.toggleCheckbox = this.toggleCheckbox.bind(this); + this.removeEventListeners(); + this.initEventListeners(); +} - NotificationsForm.prototype.removeEventListeners = function() { - return $(document).off('change', '.js-custom-notification-event'); - }; +NotificationsForm.prototype.removeEventListeners = function() { + return $(document).off('change', '.js-custom-notification-event'); +}; - NotificationsForm.prototype.initEventListeners = function() { - return $(document).on('change', '.js-custom-notification-event', this.toggleCheckbox); - }; +NotificationsForm.prototype.initEventListeners = function() { + return $(document).on('change', '.js-custom-notification-event', this.toggleCheckbox); +}; - NotificationsForm.prototype.toggleCheckbox = function(e) { - var $checkbox, $parent; - $checkbox = $(e.currentTarget); - $parent = $checkbox.closest('.checkbox'); - return this.saveEvent($checkbox, $parent); - }; +NotificationsForm.prototype.toggleCheckbox = function(e) { + var $checkbox, $parent; + $checkbox = $(e.currentTarget); + $parent = $checkbox.closest('.checkbox'); + return this.saveEvent($checkbox, $parent); +}; - NotificationsForm.prototype.showCheckboxLoadingSpinner = function($parent) { - return $parent.addClass('is-loading').find('.custom-notification-event-loading').removeClass('fa-check').addClass('fa-spin fa-spinner').removeClass('is-done'); - }; +NotificationsForm.prototype.showCheckboxLoadingSpinner = function($parent) { + return $parent.addClass('is-loading').find('.custom-notification-event-loading').removeClass('fa-check').addClass('fa-spin fa-spinner').removeClass('is-done'); +}; - NotificationsForm.prototype.saveEvent = function($checkbox, $parent) { - var form; - form = $parent.parents('form:first'); - return $.ajax({ - url: form.attr('action'), - method: form.attr('method'), - dataType: 'json', - data: form.serialize(), - beforeSend: (function(_this) { - return function() { - return _this.showCheckboxLoadingSpinner($parent); - }; - })(this) - }).done(function(data) { - $checkbox.enable(); - if (data.saved) { - $parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done'); - return setTimeout(function() { - return $parent.removeClass('is-loading').find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done'); - }, 2000); - } - }); - }; +NotificationsForm.prototype.saveEvent = function($checkbox, $parent) { + var form; + form = $parent.parents('form:first'); + return $.ajax({ + url: form.attr('action'), + method: form.attr('method'), + dataType: 'json', + data: form.serialize(), + beforeSend: (function(_this) { + return function() { + return _this.showCheckboxLoadingSpinner($parent); + }; + })(this) + }).done(function(data) { + $checkbox.enable(); + if (data.saved) { + $parent.find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done'); + return setTimeout(function() { + return $parent.removeClass('is-loading').find('.custom-notification-event-loading').toggleClass('fa-spin fa-spinner fa-check is-done'); + }, 2000); + } + }); +}; - return NotificationsForm; - })(); -}).call(window); +window.NotificationsForm = NotificationsForm; diff --git a/app/assets/javascripts/pager.js b/app/assets/javascripts/pager.js index 01110420cca..898bc40dacb 100644 --- a/app/assets/javascripts/pager.js +++ b/app/assets/javascripts/pager.js @@ -1,78 +1,76 @@ import '~/lib/utils/common_utils'; import '~/lib/utils/url_utility'; -(() => { - const ENDLESS_SCROLL_BOTTOM_PX = 400; - const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000; +const ENDLESS_SCROLL_BOTTOM_PX = 400; +const ENDLESS_SCROLL_FIRE_DELAY_MS = 1000; - const Pager = { - init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) { - this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']); - this.limit = limit; - this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit; - this.disable = disable; - this.prepareData = prepareData; - this.callback = callback; - this.loading = $('.loading').first(); - if (preload) { - this.offset = 0; - this.getOld(); - } - this.initLoadMore(); - }, +const Pager = { + init(limit = 0, preload = false, disable = false, prepareData = $.noop, callback = $.noop) { + this.url = $('.content_list').data('href') || gl.utils.removeParams(['limit', 'offset']); + this.limit = limit; + this.offset = parseInt(gl.utils.getParameterByName('offset'), 10) || this.limit; + this.disable = disable; + this.prepareData = prepareData; + this.callback = callback; + this.loading = $('.loading').first(); + if (preload) { + this.offset = 0; + this.getOld(); + } + this.initLoadMore(); + }, - getOld() { - this.loading.show(); - $.ajax({ - type: 'GET', - url: this.url, - data: `limit=${this.limit}&offset=${this.offset}`, - dataType: 'json', - error: () => this.loading.hide(), - success: (data) => { - this.append(data.count, this.prepareData(data.html)); - this.callback(); + getOld() { + this.loading.show(); + $.ajax({ + type: 'GET', + url: this.url, + data: `limit=${this.limit}&offset=${this.offset}`, + dataType: 'json', + error: () => this.loading.hide(), + success: (data) => { + this.append(data.count, this.prepareData(data.html)); + this.callback(); - // keep loading until we've filled the viewport height - if (!this.disable && !this.isScrollable()) { - this.getOld(); - } else { - this.loading.hide(); - } - }, - }); - }, + // keep loading until we've filled the viewport height + if (!this.disable && !this.isScrollable()) { + this.getOld(); + } else { + this.loading.hide(); + } + }, + }); + }, - append(count, html) { - $('.content_list').append(html); - if (count > 0) { - this.offset += count; - } else { - this.disable = true; - } - }, + append(count, html) { + $('.content_list').append(html); + if (count > 0) { + this.offset += count; + } else { + this.disable = true; + } + }, - isScrollable() { - const $w = $(window); - return $(document).height() > $w.height() + $w.scrollTop() + ENDLESS_SCROLL_BOTTOM_PX; - }, + isScrollable() { + const $w = $(window); + return $(document).height() > $w.height() + $w.scrollTop() + ENDLESS_SCROLL_BOTTOM_PX; + }, - initLoadMore() { - $(document).unbind('scroll'); - $(document).endlessScroll({ - bottomPixels: ENDLESS_SCROLL_BOTTOM_PX, - fireDelay: ENDLESS_SCROLL_FIRE_DELAY_MS, - fireOnce: true, - ceaseFire: () => this.disable === true, - callback: () => { - if (!this.loading.is(':visible')) { - this.loading.show(); - this.getOld(); - } - }, - }); - }, - }; + initLoadMore() { + $(document).unbind('scroll'); + $(document).endlessScroll({ + bottomPixels: ENDLESS_SCROLL_BOTTOM_PX, + fireDelay: ENDLESS_SCROLL_FIRE_DELAY_MS, + fireOnce: true, + ceaseFire: () => this.disable === true, + callback: () => { + if (!this.loading.is(':visible')) { + this.loading.show(); + this.getOld(); + } + }, + }); + }, +}; - window.Pager = Pager; -})(); +window.Pager = Pager; diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/preview_markdown.js index 141333b2b4d..fd1cbda10dd 100644 --- a/app/assets/javascripts/preview_markdown.js +++ b/app/assets/javascripts/preview_markdown.js @@ -6,195 +6,191 @@ // (including the explanation of quick actions), and showing a warning when // more than `x` users are referenced. // -(function () { - var lastTextareaPreviewed; - var lastTextareaHeight = null; - var markdownPreview; - var previewButtonSelector; - var writeButtonSelector; - - window.MarkdownPreview = (function () { - function MarkdownPreview() {} - - // Minimum number of users referenced before triggering a warning - MarkdownPreview.prototype.referenceThreshold = 10; - MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.'; - - MarkdownPreview.prototype.ajaxCache = {}; - - MarkdownPreview.prototype.showPreview = function ($form) { - var mdText; - var preview = $form.find('.js-md-preview'); - var url = preview.data('url'); - if (preview.hasClass('md-preview-loading')) { - return; - } - mdText = $form.find('textarea.markdown-area').val(); - - if (mdText.trim().length === 0) { - preview.text(this.emptyMessage); - this.hideReferencedUsers($form); +var lastTextareaPreviewed; +var lastTextareaHeight = null; +var markdownPreview; +var previewButtonSelector; +var writeButtonSelector; + +function MarkdownPreview() {} + +// Minimum number of users referenced before triggering a warning +MarkdownPreview.prototype.referenceThreshold = 10; +MarkdownPreview.prototype.emptyMessage = 'Nothing to preview.'; + +MarkdownPreview.prototype.ajaxCache = {}; + +MarkdownPreview.prototype.showPreview = function ($form) { + var mdText; + var preview = $form.find('.js-md-preview'); + var url = preview.data('url'); + if (preview.hasClass('md-preview-loading')) { + return; + } + mdText = $form.find('textarea.markdown-area').val(); + + if (mdText.trim().length === 0) { + preview.text(this.emptyMessage); + this.hideReferencedUsers($form); + } else { + preview.addClass('md-preview-loading').text('Loading...'); + this.fetchMarkdownPreview(mdText, url, (function (response) { + var body; + if (response.body.length > 0) { + body = response.body; } else { - preview.addClass('md-preview-loading').text('Loading...'); - this.fetchMarkdownPreview(mdText, url, (function (response) { - var body; - if (response.body.length > 0) { - body = response.body; - } else { - body = this.emptyMessage; - } - - preview.removeClass('md-preview-loading').html(body); - preview.renderGFM(); - this.renderReferencedUsers(response.references.users, $form); - - if (response.references.commands) { - this.renderReferencedCommands(response.references.commands, $form); - } - }).bind(this)); - } - }; - - MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) { - if (!url) { - return; + body = this.emptyMessage; } - if (text === this.ajaxCache.text) { - success(this.ajaxCache.response); - return; - } - $.ajax({ - type: 'POST', - url: url, - data: { - text: text - }, - dataType: 'json', - success: (function (response) { - this.ajaxCache = { - text: text, - response: response - }; - success(response); - }).bind(this) - }); - }; - - MarkdownPreview.prototype.hideReferencedUsers = function ($form) { - $form.find('.referenced-users').hide(); - }; - - MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) { - var referencedUsers; - referencedUsers = $form.find('.referenced-users'); - if (referencedUsers.length) { - if (users.length >= this.referenceThreshold) { - referencedUsers.show(); - referencedUsers.find('.js-referenced-users-count').text(users.length); - } else { - referencedUsers.hide(); - } - } - }; - - MarkdownPreview.prototype.hideReferencedCommands = function ($form) { - $form.find('.referenced-commands').hide(); - }; - - MarkdownPreview.prototype.renderReferencedCommands = function (commands, $form) { - var referencedCommands; - referencedCommands = $form.find('.referenced-commands'); - if (commands.length > 0) { - referencedCommands.html(commands); - referencedCommands.show(); - } else { - referencedCommands.html(''); - referencedCommands.hide(); - } - }; - - return MarkdownPreview; - }()); - - markdownPreview = new window.MarkdownPreview(); - - previewButtonSelector = '.js-md-preview-button'; - - writeButtonSelector = '.js-md-write-button'; - - lastTextareaPreviewed = null; - $.fn.setupMarkdownPreview = function () { - var $form = $(this); - $form.find('textarea.markdown-area').on('input', function () { - markdownPreview.hideReferencedUsers($form); - }); - }; + preview.removeClass('md-preview-loading').html(body); + preview.renderGFM(); + this.renderReferencedUsers(response.references.users, $form); - $(document).on('markdown-preview:show', function (e, $form) { - if (!$form) { - return; + if (response.references.commands) { + this.renderReferencedCommands(response.references.commands, $form); + } + }).bind(this)); + } +}; + +MarkdownPreview.prototype.fetchMarkdownPreview = function (text, url, success) { + if (!url) { + return; + } + if (text === this.ajaxCache.text) { + success(this.ajaxCache.response); + return; + } + $.ajax({ + type: 'POST', + url: url, + data: { + text: text + }, + dataType: 'json', + success: (function (response) { + this.ajaxCache = { + text: text, + response: response + }; + success(response); + }).bind(this) + }); +}; + +MarkdownPreview.prototype.hideReferencedUsers = function ($form) { + $form.find('.referenced-users').hide(); +}; + +MarkdownPreview.prototype.renderReferencedUsers = function (users, $form) { + var referencedUsers; + referencedUsers = $form.find('.referenced-users'); + if (referencedUsers.length) { + if (users.length >= this.referenceThreshold) { + referencedUsers.show(); + referencedUsers.find('.js-referenced-users-count').text(users.length); + } else { + referencedUsers.hide(); } + } +}; - lastTextareaPreviewed = $form.find('textarea.markdown-area'); - lastTextareaHeight = lastTextareaPreviewed.height(); +MarkdownPreview.prototype.hideReferencedCommands = function ($form) { + $form.find('.referenced-commands').hide(); +}; - // toggle tabs - $form.find(writeButtonSelector).parent().removeClass('active'); - $form.find(previewButtonSelector).parent().addClass('active'); +MarkdownPreview.prototype.renderReferencedCommands = function (commands, $form) { + var referencedCommands; + referencedCommands = $form.find('.referenced-commands'); + if (commands.length > 0) { + referencedCommands.html(commands); + referencedCommands.show(); + } else { + referencedCommands.html(''); + referencedCommands.hide(); + } +}; - // toggle content - $form.find('.md-write-holder').hide(); - $form.find('.md-preview-holder').show(); - markdownPreview.showPreview($form); - }); +window.MarkdownPreview = MarkdownPreview; - $(document).on('markdown-preview:hide', function (e, $form) { - if (!$form) { - return; - } - lastTextareaPreviewed = null; +markdownPreview = new window.MarkdownPreview(); - if (lastTextareaHeight) { - $form.find('textarea.markdown-area').height(lastTextareaHeight); - } +previewButtonSelector = '.js-md-preview-button'; - // toggle tabs - $form.find(writeButtonSelector).parent().addClass('active'); - $form.find(previewButtonSelector).parent().removeClass('active'); +writeButtonSelector = '.js-md-write-button'; - // toggle content - $form.find('.md-write-holder').show(); - $form.find('textarea.markdown-area').focus(); - $form.find('.md-preview-holder').hide(); +lastTextareaPreviewed = null; - markdownPreview.hideReferencedCommands($form); - }); - - $(document).on('markdown-preview:toggle', function (e, keyboardEvent) { - var $target; - $target = $(keyboardEvent.target); - if ($target.is('textarea.markdown-area')) { - $(document).triggerHandler('markdown-preview:show', [$target.closest('form')]); - keyboardEvent.preventDefault(); - } else if (lastTextareaPreviewed) { - $target = lastTextareaPreviewed; - $(document).triggerHandler('markdown-preview:hide', [$target.closest('form')]); - keyboardEvent.preventDefault(); - } - }); - - $(document).on('click', previewButtonSelector, function (e) { - var $form; - e.preventDefault(); - $form = $(this).closest('form'); - $(document).triggerHandler('markdown-preview:show', [$form]); +$.fn.setupMarkdownPreview = function () { + var $form = $(this); + $form.find('textarea.markdown-area').on('input', function () { + markdownPreview.hideReferencedUsers($form); }); +}; + +$(document).on('markdown-preview:show', function (e, $form) { + if (!$form) { + return; + } + + lastTextareaPreviewed = $form.find('textarea.markdown-area'); + lastTextareaHeight = lastTextareaPreviewed.height(); + + // toggle tabs + $form.find(writeButtonSelector).parent().removeClass('active'); + $form.find(previewButtonSelector).parent().addClass('active'); + + // toggle content + $form.find('.md-write-holder').hide(); + $form.find('.md-preview-holder').show(); + markdownPreview.showPreview($form); +}); + +$(document).on('markdown-preview:hide', function (e, $form) { + if (!$form) { + return; + } + lastTextareaPreviewed = null; - $(document).on('click', writeButtonSelector, function (e) { - var $form; - e.preventDefault(); - $form = $(this).closest('form'); - $(document).triggerHandler('markdown-preview:hide', [$form]); - }); -}()); + if (lastTextareaHeight) { + $form.find('textarea.markdown-area').height(lastTextareaHeight); + } + + // toggle tabs + $form.find(writeButtonSelector).parent().addClass('active'); + $form.find(previewButtonSelector).parent().removeClass('active'); + + // toggle content + $form.find('.md-write-holder').show(); + $form.find('textarea.markdown-area').focus(); + $form.find('.md-preview-holder').hide(); + + markdownPreview.hideReferencedCommands($form); +}); + +$(document).on('markdown-preview:toggle', function (e, keyboardEvent) { + var $target; + $target = $(keyboardEvent.target); + if ($target.is('textarea.markdown-area')) { + $(document).triggerHandler('markdown-preview:show', [$target.closest('form')]); + keyboardEvent.preventDefault(); + } else if (lastTextareaPreviewed) { + $target = lastTextareaPreviewed; + $(document).triggerHandler('markdown-preview:hide', [$target.closest('form')]); + keyboardEvent.preventDefault(); + } +}); + +$(document).on('click', previewButtonSelector, function (e) { + var $form; + e.preventDefault(); + $form = $(this).closest('form'); + $(document).triggerHandler('markdown-preview:show', [$form]); +}); + +$(document).on('click', writeButtonSelector, function (e) { + var $form; + e.preventDefault(); + $form = $(this).closest('form'); + $(document).triggerHandler('markdown-preview:hide', [$form]); +}); diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index 738e710deb9..e93ab0f06f2 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -3,129 +3,125 @@ import Cookies from 'js-cookie'; -(function() { - this.Project = (function() { - function Project() { - $('ul.clone-options-dropdown a').click(function() { - var url; - if ($(this).hasClass('active')) { - return; - } - $('.active').not($(this)).removeClass('active'); - $(this).toggleClass('active'); - url = $("#project_clone").val(); - $('#project_clone').val(url); - return $('.clone').text(url); - // Git protocol switcher - // Remove the active class for all buttons (ssh, http, kerberos if shown) - // Add the active class for the clicked button - // Update the input field - // Update the command line instructions - }); - // Ref switcher - this.initRefSwitcher(); - $('.project-refs-select').on('change', function() { - return $(this).parents('form').submit(); - }); - $('.hide-no-ssh-message').on('click', function(e) { - Cookies.set('hide_no_ssh_message', 'false'); - $(this).parents('.no-ssh-key-message').remove(); - return e.preventDefault(); - }); - $('.hide-no-password-message').on('click', function(e) { - Cookies.set('hide_no_password_message', 'false'); - $(this).parents('.no-password-message').remove(); - return e.preventDefault(); - }); - this.projectSelectDropdown(); +function Project() { + $('ul.clone-options-dropdown a').click(function() { + var url; + if ($(this).hasClass('active')) { + return; } + $('.active').not($(this)).removeClass('active'); + $(this).toggleClass('active'); + url = $("#project_clone").val(); + $('#project_clone').val(url); + return $('.clone').text(url); + // Git protocol switcher + // Remove the active class for all buttons (ssh, http, kerberos if shown) + // Add the active class for the clicked button + // Update the input field + // Update the command line instructions + }); + // Ref switcher + this.initRefSwitcher(); + $('.project-refs-select').on('change', function() { + return $(this).parents('form').submit(); + }); + $('.hide-no-ssh-message').on('click', function(e) { + Cookies.set('hide_no_ssh_message', 'false'); + $(this).parents('.no-ssh-key-message').remove(); + return e.preventDefault(); + }); + $('.hide-no-password-message').on('click', function(e) { + Cookies.set('hide_no_password_message', 'false'); + $(this).parents('.no-password-message').remove(); + return e.preventDefault(); + }); + this.projectSelectDropdown(); +} - Project.prototype.projectSelectDropdown = function() { - new ProjectSelect(); - $('.project-item-select').on('click', (function(_this) { - return function(e) { - return _this.changeProject($(e.currentTarget).val()); - }; - })(this)); - return $('.js-projects-dropdown-toggle').on('click', function(e) { - e.preventDefault(); - return $('.js-projects-dropdown').select2('open'); - }); +Project.prototype.projectSelectDropdown = function() { + new ProjectSelect(); + $('.project-item-select').on('click', (function(_this) { + return function(e) { + return _this.changeProject($(e.currentTarget).val()); }; + })(this)); + return $('.js-projects-dropdown-toggle').on('click', function(e) { + e.preventDefault(); + return $('.js-projects-dropdown').select2('open'); + }); +}; - Project.prototype.changeProject = function(url) { - return window.location = url; - }; +Project.prototype.changeProject = function(url) { + return window.location = url; +}; - Project.prototype.initRefSwitcher = function() { - var refListItem = document.createElement('li'); - var refLink = document.createElement('a'); +Project.prototype.initRefSwitcher = function() { + var refListItem = document.createElement('li'); + var refLink = document.createElement('a'); - refLink.href = '#'; + refLink.href = '#'; - return $('.js-project-refs-dropdown').each(function() { - var $dropdown, selected; - $dropdown = $(this); - selected = $dropdown.data('selected'); - return $dropdown.glDropdown({ - data: function(term, callback) { - return $.ajax({ - url: $dropdown.data('refs-url'), - data: { - ref: $dropdown.data('ref'), - search: term - }, - dataType: "json" - }).done(function(refs) { - return callback(refs); - }); + return $('.js-project-refs-dropdown').each(function() { + var $dropdown, selected; + $dropdown = $(this); + selected = $dropdown.data('selected'); + return $dropdown.glDropdown({ + data: function(term, callback) { + return $.ajax({ + url: $dropdown.data('refs-url'), + data: { + ref: $dropdown.data('ref'), + search: term }, - selectable: true, - filterable: true, - filterRemote: true, - filterByText: true, - fieldName: $dropdown.data('field-name'), - renderRow: function(ref) { - var li = refListItem.cloneNode(false); + dataType: "json" + }).done(function(refs) { + return callback(refs); + }); + }, + selectable: true, + filterable: true, + filterRemote: true, + filterByText: true, + fieldName: $dropdown.data('field-name'), + renderRow: function(ref) { + var li = refListItem.cloneNode(false); - if (ref.header != null) { - li.className = 'dropdown-header'; - li.textContent = ref.header; - } else { - var link = refLink.cloneNode(false); + if (ref.header != null) { + li.className = 'dropdown-header'; + li.textContent = ref.header; + } else { + var link = refLink.cloneNode(false); - if (ref === selected) { - link.className = 'is-active'; - } + if (ref === selected) { + link.className = 'is-active'; + } - link.textContent = ref; - link.dataset.ref = ref; + link.textContent = ref; + link.dataset.ref = ref; - li.appendChild(link); - } + li.appendChild(link); + } - return li; - }, - id: function(obj, $el) { - return $el.attr('data-ref'); - }, - toggleLabel: function(obj, $el) { - return $el.text().trim(); - }, - clicked: function(options) { - const { e } = options; - e.preventDefault(); - if ($('input[name="ref"]').length) { - var $form = $dropdown.closest('form'); - var action = $form.attr('action'); - var divider = action.indexOf('?') === -1 ? '?' : '&'; - gl.utils.visitUrl(action + '' + divider + '' + $form.serialize()); - } - } - }); - }); - }; + return li; + }, + id: function(obj, $el) { + return $el.attr('data-ref'); + }, + toggleLabel: function(obj, $el) { + return $el.text().trim(); + }, + clicked: function(options) { + const { e } = options; + e.preventDefault(); + if ($('input[name="ref"]').length) { + var $form = $dropdown.closest('form'); + var action = $form.attr('action'); + var divider = action.indexOf('?') === -1 ? '?' : '&'; + gl.utils.visitUrl(action + '' + divider + '' + $form.serialize()); + } + } + }); + }); +}; - return Project; - })(); -}).call(window); +window.Project = Project; diff --git a/app/assets/javascripts/project_avatar.js b/app/assets/javascripts/project_avatar.js index aabdfbf65e2..e412504de31 100644 --- a/app/assets/javascripts/project_avatar.js +++ b/app/assets/javascripts/project_avatar.js @@ -1,20 +1,16 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-useless-escape, max-len */ -(function() { - this.ProjectAvatar = (function() { - function ProjectAvatar() { - $('.js-choose-project-avatar-button').bind('click', function() { - var form; - form = $(this).closest('form'); - return form.find('.js-project-avatar-input').click(); - }); - $('.js-project-avatar-input').bind('change', function() { - var filename, form; - form = $(this).closest('form'); - filename = $(this).val().replace(/^.*[\\\/]/, ''); - return form.find('.js-avatar-filename').text(filename); - }); - } +function ProjectAvatar() { + $('.js-choose-project-avatar-button').bind('click', function() { + var form; + form = $(this).closest('form'); + return form.find('.js-project-avatar-input').click(); + }); + $('.js-project-avatar-input').bind('change', function() { + var filename, form; + form = $(this).closest('form'); + filename = $(this).val().replace(/^.*[\\\/]/, ''); + return form.find('.js-avatar-filename').text(filename); + }); +} - return ProjectAvatar; - })(); -}).call(window); +window.ProjectAvatar = ProjectAvatar; diff --git a/app/assets/javascripts/project_find_file.js b/app/assets/javascripts/project_find_file.js index 11f9754780d..e59901d5fc1 100644 --- a/app/assets/javascripts/project_find_file.js +++ b/app/assets/javascripts/project_find_file.js @@ -1,169 +1,161 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, consistent-return, one-var, one-var-declaration-per-line, no-cond-assign, max-len, object-shorthand, no-param-reassign, comma-dangle, prefer-template, no-unused-vars, no-return-assign */ /* global fuzzaldrinPlus */ -(function() { - this.ProjectFindFile = (function() { - var highlighter; +var highlighter; - function ProjectFindFile(element1, options) { - this.element = element1; - this.options = options; - this.goToBlob = this.goToBlob.bind(this); - this.goToTree = this.goToTree.bind(this); - this.selectRowDown = this.selectRowDown.bind(this); - this.selectRowUp = this.selectRowUp.bind(this); - this.filePaths = {}; - this.inputElement = this.element.find(".file-finder-input"); - // init event - this.initEvent(); - // focus text input box - this.inputElement.focus(); - // load file list - this.load(this.options.url); - } +function ProjectFindFile(element1, options) { + this.element = element1; + this.options = options; + this.goToBlob = this.goToBlob.bind(this); + this.goToTree = this.goToTree.bind(this); + this.selectRowDown = this.selectRowDown.bind(this); + this.selectRowUp = this.selectRowUp.bind(this); + this.filePaths = {}; + this.inputElement = this.element.find(".file-finder-input"); + // init event + this.initEvent(); + // focus text input box + this.inputElement.focus(); + // load file list + this.load(this.options.url); +} - ProjectFindFile.prototype.initEvent = function() { - this.inputElement.off("keyup"); - this.inputElement.on("keyup", (function(_this) { - return function(event) { - var oldValue, ref, target, value; - target = $(event.target); - value = target.val(); - oldValue = (ref = target.data("oldValue")) != null ? ref : ""; - if (value !== oldValue) { - target.data("oldValue", value); - _this.findFile(); - return _this.element.find("tr.tree-item").eq(0).addClass("selected").focus(); - } - }; - })(this)); - }; +ProjectFindFile.prototype.initEvent = function() { + this.inputElement.off("keyup"); + this.inputElement.on("keyup", (event) => { + var oldValue, ref, target, value; + target = $(event.target); + value = target.val(); + oldValue = (ref = target.data("oldValue")) != null ? ref : ""; + if (value !== oldValue) { + target.data("oldValue", value); + this.findFile(); + return this.element.find("tr.tree-item").eq(0).addClass("selected").focus(); + } + }); +}; - ProjectFindFile.prototype.findFile = function() { - var result, searchText; - searchText = this.inputElement.val(); - result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths; - return this.renderList(result, searchText); - // find file - }; +ProjectFindFile.prototype.findFile = function() { + var result, searchText; + searchText = this.inputElement.val(); + result = searchText.length > 0 ? fuzzaldrinPlus.filter(this.filePaths, searchText) : this.filePaths; + return this.renderList(result, searchText); +// find file +}; - // files pathes load - ProjectFindFile.prototype.load = function(url) { - return $.ajax({ - url: url, - method: "get", - dataType: "json", - success: (function(_this) { - return function(data) { - _this.element.find(".loading").hide(); - _this.filePaths = data; - _this.findFile(); - return _this.element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus(); - }; - })(this) - }); - }; +// files pathes load +ProjectFindFile.prototype.load = function(url) { + return $.ajax({ + url: url, + method: "get", + dataType: "json", + success: (data) => { + this.element.find(".loading").hide(); + this.filePaths = data; + this.findFile(); + return this.element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus(); + } + }); +}; - // render result - ProjectFindFile.prototype.renderList = function(filePaths, searchText) { - var blobItemUrl, filePath, html, i, j, len, matches, results; - this.element.find(".tree-table > tbody").empty(); - results = []; - for (i = j = 0, len = filePaths.length; j < len; i = (j += 1)) { - filePath = filePaths[i]; - if (i === 20) { - break; - } - if (searchText) { - matches = fuzzaldrinPlus.match(filePath, searchText); - } - blobItemUrl = this.options.blobUrlTemplate + "/" + filePath; - html = this.makeHtml(filePath, matches, blobItemUrl); - results.push(this.element.find(".tree-table > tbody").append(html)); - } - return results; - }; +// render result +ProjectFindFile.prototype.renderList = function(filePaths, searchText) { + var blobItemUrl, filePath, html, i, j, len, matches, results; + this.element.find(".tree-table > tbody").empty(); + results = []; + for (i = j = 0, len = filePaths.length; j < len; i = (j += 1)) { + filePath = filePaths[i]; + if (i === 20) { + break; + } + if (searchText) { + matches = fuzzaldrinPlus.match(filePath, searchText); + } + blobItemUrl = this.options.blobUrlTemplate + "/" + filePath; + html = this.makeHtml(filePath, matches, blobItemUrl); + results.push(this.element.find(".tree-table > tbody").append(html)); + } + return results; +}; - // highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> ) - highlighter = function(element, text, matches) { - var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched; - lastIndex = 0; - highlightText = ""; - matchedChars = []; - for (j = 0, len = matches.length; j < len; j += 1) { - matchIndex = matches[j]; - unmatched = text.substring(lastIndex, matchIndex); - if (unmatched) { - if (matchedChars.length) { - element.append(matchedChars.join("").bold()); - } - matchedChars = []; - element.append(document.createTextNode(unmatched)); - } - matchedChars.push(text[matchIndex]); - lastIndex = matchIndex + 1; - } +// highlight text(awefwbwgtc -> <b>a</b>wefw<b>b</b>wgt<b>c</b> ) +highlighter = function(element, text, matches) { + var highlightText, j, lastIndex, len, matchIndex, matchedChars, unmatched; + lastIndex = 0; + highlightText = ""; + matchedChars = []; + for (j = 0, len = matches.length; j < len; j += 1) { + matchIndex = matches[j]; + unmatched = text.substring(lastIndex, matchIndex); + if (unmatched) { if (matchedChars.length) { element.append(matchedChars.join("").bold()); } - return element.append(document.createTextNode(text.substring(lastIndex))); - }; + matchedChars = []; + element.append(document.createTextNode(unmatched)); + } + matchedChars.push(text[matchIndex]); + lastIndex = matchIndex + 1; + } + if (matchedChars.length) { + element.append(matchedChars.join("").bold()); + } + return element.append(document.createTextNode(text.substring(lastIndex))); +}; - // make tbody row html - ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) { - var $tr; - $tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>"); - if (matches) { - $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)); - } else { - $tr.find("a").attr("href", blobItemUrl); - $tr.find(".str-truncated").text(filePath); - } - return $tr; - }; +// make tbody row html +ProjectFindFile.prototype.makeHtml = function(filePath, matches, blobItemUrl) { + var $tr; + $tr = $("<tr class='tree-item'><td class='tree-item-file-name link-container'><a><i class='fa fa-file-text-o fa-fw'></i><span class='str-truncated'></span></a></td></tr>"); + if (matches) { + $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)); + } else { + $tr.find("a").attr("href", blobItemUrl); + $tr.find(".str-truncated").text(filePath); + } + return $tr; +}; - ProjectFindFile.prototype.selectRow = function(type) { - var next, rows, selectedRow; - rows = this.element.find(".files-slider tr.tree-item"); - selectedRow = this.element.find(".files-slider tr.tree-item.selected"); - if (rows && rows.length > 0) { - if (selectedRow && selectedRow.length > 0) { - if (type === "UP") { - next = selectedRow.prev(); - } else if (type === "DOWN") { - next = selectedRow.next(); - } - if (next.length > 0) { - selectedRow.removeClass("selected"); - selectedRow = next; - } - } else { - selectedRow = rows.eq(0); - } - return selectedRow.addClass("selected").focus(); +ProjectFindFile.prototype.selectRow = function(type) { + var next, rows, selectedRow; + rows = this.element.find(".files-slider tr.tree-item"); + selectedRow = this.element.find(".files-slider tr.tree-item.selected"); + if (rows && rows.length > 0) { + if (selectedRow && selectedRow.length > 0) { + if (type === "UP") { + next = selectedRow.prev(); + } else if (type === "DOWN") { + next = selectedRow.next(); } - }; + if (next.length > 0) { + selectedRow.removeClass("selected"); + selectedRow = next; + } + } else { + selectedRow = rows.eq(0); + } + return selectedRow.addClass("selected").focus(); + } +}; - ProjectFindFile.prototype.selectRowUp = function() { - return this.selectRow("UP"); - }; +ProjectFindFile.prototype.selectRowUp = function() { + return this.selectRow("UP"); +}; - ProjectFindFile.prototype.selectRowDown = function() { - return this.selectRow("DOWN"); - }; +ProjectFindFile.prototype.selectRowDown = function() { + return this.selectRow("DOWN"); +}; - ProjectFindFile.prototype.goToTree = function() { - return location.href = this.options.treeUrl; - }; +ProjectFindFile.prototype.goToTree = function() { + return location.href = this.options.treeUrl; +}; - ProjectFindFile.prototype.goToBlob = function() { - var $link = this.element.find(".tree-item.selected .tree-item-file-name a"); +ProjectFindFile.prototype.goToBlob = function() { + var $link = this.element.find(".tree-item.selected .tree-item-file-name a"); - if ($link.length) { - $link.get(0).click(); - } - }; + if ($link.length) { + $link.get(0).click(); + } +}; - return ProjectFindFile; - })(); -}).call(window); +window.ProjectFindFile = ProjectFindFile; diff --git a/app/assets/javascripts/project_fork.js b/app/assets/javascripts/project_fork.js index 47197db39d3..51b1a7db108 100644 --- a/app/assets/javascripts/project_fork.js +++ b/app/assets/javascripts/project_fork.js @@ -1,13 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */ -(function() { - this.ProjectFork = (function() { - function ProjectFork() { - $('.fork-thumbnail a').on('click', function() { - $('.fork-namespaces').hide(); - return $('.save-project-loader').show(); - }); - } +function ProjectFork() { + $('.fork-thumbnail a').on('click', function() { + $('.fork-namespaces').hide(); + return $('.save-project-loader').show(); + }); +} - return ProjectFork; - })(); -}).call(window); +window.ProjectFork = ProjectFork; diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js index 08334bf1ec5..f6d4d51d1c7 100644 --- a/app/assets/javascripts/project_import.js +++ b/app/assets/javascripts/project_import.js @@ -1,13 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */ -(function() { - this.ProjectImport = (function() { - function ProjectImport() { - setTimeout(function() { - return gl.utils.visitUrl(location.href); - }, 5000); - } +function ProjectImport() { + setTimeout(function() { + return gl.utils.visitUrl(location.href); + }, 5000); +} - return ProjectImport; - })(); -}).call(window); +window.ProjectImport = ProjectImport; diff --git a/app/assets/javascripts/project_label_subscription.js b/app/assets/javascripts/project_label_subscription.js index 0a811627600..d17a9bac82b 100644 --- a/app/assets/javascripts/project_label_subscription.js +++ b/app/assets/javascripts/project_label_subscription.js @@ -1,55 +1,54 @@ /* eslint-disable wrap-iife, func-names, space-before-function-paren, object-shorthand, comma-dangle, one-var, one-var-declaration-per-line, no-restricted-syntax, max-len, no-param-reassign */ +const global = window.gl || (window.gl = {}); -(function(global) { - class ProjectLabelSubscription { - constructor(container) { - this.$container = $(container); - this.$buttons = this.$container.find('.js-subscribe-button'); +class ProjectLabelSubscription { + constructor(container) { + this.$container = $(container); + this.$buttons = this.$container.find('.js-subscribe-button'); - this.$buttons.on('click', this.toggleSubscription.bind(this)); - } + this.$buttons.on('click', this.toggleSubscription.bind(this)); + } - toggleSubscription(event) { - event.preventDefault(); + toggleSubscription(event) { + event.preventDefault(); - const $btn = $(event.currentTarget); - const $span = $btn.find('span'); - const url = $btn.attr('data-url'); - const oldStatus = $btn.attr('data-status'); + const $btn = $(event.currentTarget); + const $span = $btn.find('span'); + const url = $btn.attr('data-url'); + const oldStatus = $btn.attr('data-status'); - $btn.addClass('disabled'); - $span.toggleClass('hidden'); + $btn.addClass('disabled'); + $span.toggleClass('hidden'); - $.ajax({ - type: 'POST', - url: url - }).done(() => { - let newStatus, newAction; + $.ajax({ + type: 'POST', + url: url + }).done(() => { + let newStatus, newAction; - if (oldStatus === 'unsubscribed') { - [newStatus, newAction] = ['subscribed', 'Unsubscribe']; - } else { - [newStatus, newAction] = ['unsubscribed', 'Subscribe']; - } + if (oldStatus === 'unsubscribed') { + [newStatus, newAction] = ['subscribed', 'Unsubscribe']; + } else { + [newStatus, newAction] = ['unsubscribed', 'Subscribe']; + } - $span.toggleClass('hidden'); - $btn.removeClass('disabled'); + $span.toggleClass('hidden'); + $btn.removeClass('disabled'); - this.$buttons.attr('data-status', newStatus); - this.$buttons.find('> span').text(newAction); + this.$buttons.attr('data-status', newStatus); + this.$buttons.find('> span').text(newAction); - this.$buttons.map((button) => { - const $button = $(button); + this.$buttons.map((button) => { + const $button = $(button); - if ($button.attr('data-original-title')) { - $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); - } + if ($button.attr('data-original-title')) { + $button.tooltip('hide').attr('data-original-title', newAction).tooltip('fixTitle'); + } - return button; - }); + return button; }); - } + }); } +} - global.ProjectLabelSubscription = ProjectLabelSubscription; -})(window.gl || (window.gl = {})); +global.ProjectLabelSubscription = ProjectLabelSubscription; diff --git a/app/assets/javascripts/project_new.js b/app/assets/javascripts/project_new.js index fd89a1a85c3..a015ff58411 100644 --- a/app/assets/javascripts/project_new.js +++ b/app/assets/javascripts/project_new.js @@ -7,153 +7,149 @@ function highlightChanges($elm) { setTimeout(() => $elm.removeClass('highlight-changes'), 10); } -(function() { - this.ProjectNew = (function() { - function ProjectNew() { - this.toggleSettings = this.toggleSettings.bind(this); - this.$selects = $('.features select'); - this.$repoSelects = this.$selects.filter('.js-repo-select'); - this.$projectSelects = this.$selects.not('.js-repo-select'); - - $('.project-edit-container').on('ajax:before', (function(_this) { - return function() { - $('.project-edit-container').hide(); - return $('.save-project-loader').show(); - }; - })(this)); - - this.initVisibilitySelect(); - - this.toggleSettings(); - this.toggleSettingsOnclick(); - this.toggleRepoVisibility(); - } +function ProjectNew() { + this.toggleSettings = this.toggleSettings.bind(this); + this.$selects = $('.features select'); + this.$repoSelects = this.$selects.filter('.js-repo-select'); + this.$projectSelects = this.$selects.not('.js-repo-select'); + + $('.project-edit-container').on('ajax:before', (function(_this) { + return function() { + $('.project-edit-container').hide(); + return $('.save-project-loader').show(); + }; + })(this)); + + this.initVisibilitySelect(); + + this.toggleSettings(); + this.toggleSettingsOnclick(); + this.toggleRepoVisibility(); +} + +ProjectNew.prototype.initVisibilitySelect = function() { + const visibilityContainer = document.querySelector('.js-visibility-select'); + if (!visibilityContainer) return; + const visibilitySelect = new VisibilitySelect(visibilityContainer); + visibilitySelect.init(); + + const $visibilitySelect = $(visibilityContainer).find('select'); + let projectVisibility = $visibilitySelect.val(); + const PROJECT_VISIBILITY_PRIVATE = '0'; + + $visibilitySelect.on('change', () => { + const newProjectVisibility = $visibilitySelect.val(); + + if (projectVisibility !== newProjectVisibility) { + this.$projectSelects.each((idx, select) => { + const $select = $(select); + const $options = $select.find('option'); + const values = $.map($options, e => e.value); + + // if switched to "private", limit visibility options + if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) { + if ($select.val() !== values[0] && $select.val() !== values[1]) { + $select.val(values[1]).trigger('change'); + highlightChanges($select); + } + $options.slice(2).disable(); + } - ProjectNew.prototype.initVisibilitySelect = function() { - const visibilityContainer = document.querySelector('.js-visibility-select'); - if (!visibilityContainer) return; - const visibilitySelect = new VisibilitySelect(visibilityContainer); - visibilitySelect.init(); - - const $visibilitySelect = $(visibilityContainer).find('select'); - let projectVisibility = $visibilitySelect.val(); - const PROJECT_VISIBILITY_PRIVATE = '0'; - - $visibilitySelect.on('change', () => { - const newProjectVisibility = $visibilitySelect.val(); - - if (projectVisibility !== newProjectVisibility) { - this.$projectSelects.each((idx, select) => { - const $select = $(select); - const $options = $select.find('option'); - const values = $.map($options, e => e.value); - - // if switched to "private", limit visibility options - if (newProjectVisibility === PROJECT_VISIBILITY_PRIVATE) { - if ($select.val() !== values[0] && $select.val() !== values[1]) { - $select.val(values[1]).trigger('change'); - highlightChanges($select); - } - $options.slice(2).disable(); - } - - // if switched from "private", increase visibility for non-disabled options - if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) { - $options.enable(); - if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) { - $select.val(values[values.length - 1]).trigger('change'); - highlightChanges($select); - } - } - }); - - projectVisibility = newProjectVisibility; + // if switched from "private", increase visibility for non-disabled options + if (projectVisibility === PROJECT_VISIBILITY_PRIVATE) { + $options.enable(); + if ($select.val() !== values[0] && $select.val() !== values[values.length - 1]) { + $select.val(values[values.length - 1]).trigger('change'); + highlightChanges($select); + } } }); - }; - ProjectNew.prototype.toggleSettings = function() { - var self = this; + projectVisibility = newProjectVisibility; + } + }); +}; + +ProjectNew.prototype.toggleSettings = function() { + var self = this; + + this.$selects.each(function () { + var $select = $(this); + var className = $select.data('field') + .replace(/_/g, '-') + .replace('access-level', 'feature'); + self._showOrHide($select, '.' + className); + }); +}; + +ProjectNew.prototype.toggleSettingsOnclick = function() { + this.$selects.on('change', this.toggleSettings); +}; + +ProjectNew.prototype._showOrHide = function(checkElement, container) { + var $container = $(container); + + if ($(checkElement).val() !== '0') { + return $container.show(); + } else { + return $container.hide(); + } +}; + +ProjectNew.prototype.toggleRepoVisibility = function () { + var $repoAccessLevel = $('.js-repo-access-level select'); + var $lfsEnabledOption = $('.js-lfs-enabled select'); + var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; + var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); + var prevSelectedVal = parseInt($repoAccessLevel.val(), 10); + + this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") + .nextAll() + .hide(); + + $repoAccessLevel.off('change') + .on('change', function () { + var selectedVal = parseInt($repoAccessLevel.val(), 10); + + this.$repoSelects.each(function () { + var $this = $(this); + var repoSelectVal = parseInt($this.val(), 10); + + $this.find('option').enable(); + + if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) { + $this.val(selectedVal).trigger('change'); + highlightChanges($this); + } - this.$selects.each(function () { - var $select = $(this); - var className = $select.data('field') - .replace(/_/g, '-') - .replace('access-level', 'feature'); - self._showOrHide($select, '.' + className); + $this.find("option[value='" + selectedVal + "']").nextAll().disable(); }); - }; - - ProjectNew.prototype.toggleSettingsOnclick = function() { - this.$selects.on('change', this.toggleSettings); - }; - ProjectNew.prototype._showOrHide = function(checkElement, container) { - var $container = $(container); + if (selectedVal) { + this.$repoSelects.removeClass('disabled'); - if ($(checkElement).val() !== '0') { - return $container.show(); + if ($lfsEnabledOption.length) { + $lfsEnabledOption.removeClass('disabled'); + highlightChanges($lfsEnabledOption); + } + if (containerRegistry) { + containerRegistry.style.display = ''; + } } else { - return $container.hide(); - } - }; + this.$repoSelects.addClass('disabled'); - ProjectNew.prototype.toggleRepoVisibility = function () { - var $repoAccessLevel = $('.js-repo-access-level select'); - var $lfsEnabledOption = $('.js-lfs-enabled select'); - var containerRegistry = document.querySelectorAll('.js-container-registry')[0]; - var containerRegistryCheckbox = document.getElementById('project_container_registry_enabled'); - var prevSelectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.find("option[value='" + $repoAccessLevel.val() + "']") - .nextAll() - .hide(); - - $repoAccessLevel.off('change') - .on('change', function () { - var selectedVal = parseInt($repoAccessLevel.val(), 10); - - this.$repoSelects.each(function () { - var $this = $(this); - var repoSelectVal = parseInt($this.val(), 10); - - $this.find('option').enable(); - - if (selectedVal < repoSelectVal || repoSelectVal === prevSelectedVal) { - $this.val(selectedVal).trigger('change'); - highlightChanges($this); - } - - $this.find("option[value='" + selectedVal + "']").nextAll().disable(); - }); - - if (selectedVal) { - this.$repoSelects.removeClass('disabled'); - - if ($lfsEnabledOption.length) { - $lfsEnabledOption.removeClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = ''; - } - } else { - this.$repoSelects.addClass('disabled'); - - if ($lfsEnabledOption.length) { - $lfsEnabledOption.val('false').addClass('disabled'); - highlightChanges($lfsEnabledOption); - } - if (containerRegistry) { - containerRegistry.style.display = 'none'; - containerRegistryCheckbox.checked = false; - } - } + if ($lfsEnabledOption.length) { + $lfsEnabledOption.val('false').addClass('disabled'); + highlightChanges($lfsEnabledOption); + } + if (containerRegistry) { + containerRegistry.style.display = 'none'; + containerRegistryCheckbox.checked = false; + } + } - prevSelectedVal = selectedVal; - }.bind(this)); - }; + prevSelectedVal = selectedVal; + }.bind(this)); +}; - return ProjectNew; - })(); -}).call(window); +window.ProjectNew = ProjectNew; diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index 9896b88d487..c46182126f9 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -1,111 +1,105 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-var, comma-dangle, object-shorthand, one-var, one-var-declaration-per-line, no-else-return, quotes, max-len */ import Api from './api'; -(function() { - this.ProjectSelect = (function() { - function ProjectSelect() { - $('.js-projects-dropdown-toggle').each(function(i, dropdown) { - var $dropdown; - $dropdown = $(dropdown); - return $dropdown.glDropdown({ - filterable: true, - filterRemote: true, - search: { - fields: ['name_with_namespace'] - }, - data: function(term, callback) { - var finalCallback, projectsCallback; - var orderBy = $dropdown.data('order-by'); - finalCallback = function(projects) { - return callback(projects); +function ProjectSelect() { + $('.js-projects-dropdown-toggle').each(function(i, dropdown) { + var $dropdown; + $dropdown = $(dropdown); + return $dropdown.glDropdown({ + filterable: true, + filterRemote: true, + search: { + fields: ['name_with_namespace'] + }, + data: function(term, callback) { + var finalCallback, projectsCallback; + var orderBy = $dropdown.data('order-by'); + finalCallback = function(projects) { + return callback(projects); + }; + if (this.includeGroups) { + projectsCallback = function(projects) { + var groupsCallback; + groupsCallback = function(groups) { + var data; + data = groups.concat(projects); + return finalCallback(data); }; - if (this.includeGroups) { - projectsCallback = function(projects) { - var groupsCallback; - groupsCallback = function(groups) { - var data; - data = groups.concat(projects); - return finalCallback(data); - }; - return Api.groups(term, {}, groupsCallback); - }; - } else { - projectsCallback = finalCallback; - } - if (this.groupId) { - return Api.groupProjects(this.groupId, term, projectsCallback); - } else { - return Api.projects(term, { order_by: orderBy }, projectsCallback); - } - }, - url: function(project) { - return project.web_url; - }, - text: function(project) { - return project.name_with_namespace; - } - }); - }); - $('.ajax-project-select').each(function(i, select) { - var placeholder; - this.groupId = $(select).data('group-id'); - this.includeGroups = $(select).data('include-groups'); - this.orderBy = $(select).data('order-by') || 'id'; - this.withIssuesEnabled = $(select).data('with-issues-enabled'); - this.withMergeRequestsEnabled = $(select).data('with-merge-requests-enabled'); + return Api.groups(term, {}, groupsCallback); + }; + } else { + projectsCallback = finalCallback; + } + if (this.groupId) { + return Api.groupProjects(this.groupId, term, projectsCallback); + } else { + return Api.projects(term, { order_by: orderBy }, projectsCallback); + } + }, + url: function(project) { + return project.web_url; + }, + text: function(project) { + return project.name_with_namespace; + } + }); + }); + $('.ajax-project-select').each(function(i, select) { + var placeholder; + this.groupId = $(select).data('group-id'); + this.includeGroups = $(select).data('include-groups'); + this.orderBy = $(select).data('order-by') || 'id'; + this.withIssuesEnabled = $(select).data('with-issues-enabled'); + this.withMergeRequestsEnabled = $(select).data('with-merge-requests-enabled'); - placeholder = "Search for project"; + placeholder = "Search for project"; + if (this.includeGroups) { + placeholder += " or group"; + } + return $(select).select2({ + placeholder: placeholder, + minimumInputLength: 0, + query: (query) => { + var finalCallback, projectsCallback; + finalCallback = function(projects) { + var data; + data = { + results: projects + }; + return query.callback(data); + }; if (this.includeGroups) { - placeholder += " or group"; - } - return $(select).select2({ - placeholder: placeholder, - minimumInputLength: 0, - query: (function(_this) { - return function(query) { - var finalCallback, projectsCallback; - finalCallback = function(projects) { - var data; - data = { - results: projects - }; - return query.callback(data); - }; - if (_this.includeGroups) { - projectsCallback = function(projects) { - var groupsCallback; - groupsCallback = function(groups) { - var data; - data = groups.concat(projects); - return finalCallback(data); - }; - return Api.groups(query.term, {}, groupsCallback); - }; - } else { - projectsCallback = finalCallback; - } - if (_this.groupId) { - return Api.groupProjects(_this.groupId, query.term, projectsCallback); - } else { - return Api.projects(query.term, { - order_by: _this.orderBy, - with_issues_enabled: _this.withIssuesEnabled, - with_merge_requests_enabled: _this.withMergeRequestsEnabled - }, projectsCallback); - } + projectsCallback = function(projects) { + var groupsCallback; + groupsCallback = function(groups) { + var data; + data = groups.concat(projects); + return finalCallback(data); }; - })(this), - id: function(project) { - return project.web_url; - }, - text: function(project) { - return project.name_with_namespace || project.name; - }, - dropdownCssClass: "ajax-project-dropdown" - }); - }); - } + return Api.groups(query.term, {}, groupsCallback); + }; + } else { + projectsCallback = finalCallback; + } + if (this.groupId) { + return Api.groupProjects(this.groupId, query.term, projectsCallback); + } else { + return Api.projects(query.term, { + order_by: this.orderBy, + with_issues_enabled: this.withIssuesEnabled, + with_merge_requests_enabled: this.withMergeRequestsEnabled + }, projectsCallback); + } + }, + id: function(project) { + return project.web_url; + }, + text: function(project) { + return project.name_with_namespace || project.name; + }, + dropdownCssClass: "ajax-project-dropdown" + }); + }); +} - return ProjectSelect; - })(); -}).call(window); +window.ProjectSelect = ProjectSelect; diff --git a/app/assets/javascripts/project_show.js b/app/assets/javascripts/project_show.js index 3a51c1f26ac..ff1a923a982 100644 --- a/app/assets/javascripts/project_show.js +++ b/app/assets/javascripts/project_show.js @@ -1,11 +1,6 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife */ -(function() { - this.ProjectShow = (function() { - function ProjectShow() {} - - return ProjectShow; - })(); -}).call(window); - // I kept class for future +function ProjectShow() {} + +window.ProjectShow = ProjectShow; diff --git a/app/assets/javascripts/project_variables.js b/app/assets/javascripts/project_variables.js index 4ee2e49306d..5688ed7ebb3 100644 --- a/app/assets/javascripts/project_variables.js +++ b/app/assets/javascripts/project_variables.js @@ -1,43 +1,41 @@ -(() => { - const HIDDEN_VALUE_TEXT = '******'; +const HIDDEN_VALUE_TEXT = '******'; - class ProjectVariables { - constructor() { - this.$revealBtn = $('.js-btn-toggle-reveal-values'); - this.$revealBtn.on('click', this.toggleRevealState.bind(this)); - } +class ProjectVariables { + constructor() { + this.$revealBtn = $('.js-btn-toggle-reveal-values'); + this.$revealBtn.on('click', this.toggleRevealState.bind(this)); + } - toggleRevealState(e) { - e.preventDefault(); + toggleRevealState(e) { + e.preventDefault(); - const oldStatus = this.$revealBtn.attr('data-status'); - let newStatus = 'hidden'; - let newAction = 'Reveal Values'; + const oldStatus = this.$revealBtn.attr('data-status'); + let newStatus = 'hidden'; + let newAction = 'Reveal Values'; - if (oldStatus === 'hidden') { - newStatus = 'revealed'; - newAction = 'Hide Values'; - } + if (oldStatus === 'hidden') { + newStatus = 'revealed'; + newAction = 'Hide Values'; + } - this.$revealBtn.attr('data-status', newStatus); + this.$revealBtn.attr('data-status', newStatus); - const $variables = $('.variable-value'); + const $variables = $('.variable-value'); - $variables.each((_, variable) => { - const $variable = $(variable); - let newText = HIDDEN_VALUE_TEXT; + $variables.each((_, variable) => { + const $variable = $(variable); + let newText = HIDDEN_VALUE_TEXT; - if (newStatus === 'revealed') { - newText = $variable.attr('data-value'); - } + if (newStatus === 'revealed') { + newText = $variable.attr('data-value'); + } - $variable.text(newText); - }); + $variable.text(newText); + }); - this.$revealBtn.text(newAction); - } + this.$revealBtn.text(newAction); } +} - window.gl = window.gl || {}; - window.gl.ProjectVariables = ProjectVariables; -})(); +window.gl = window.gl || {}; +window.gl.ProjectVariables = ProjectVariables; diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js index 2c3a9cacd38..d57486e2434 100644 --- a/app/assets/javascripts/render_gfm.js +++ b/app/assets/javascripts/render_gfm.js @@ -4,14 +4,12 @@ // // Delegates to syntax highlight and render math // -(function() { - $.fn.renderGFM = function() { - this.find('.js-syntax-highlight').syntaxHighlight(); - this.find('.js-render-math').renderMath(); - return this; - }; +$.fn.renderGFM = function() { + this.find('.js-syntax-highlight').syntaxHighlight(); + this.find('.js-render-math').renderMath(); + return this; +}; - $(document).on('ready load', function() { - return $('body').renderGFM(); - }); -}).call(window); +$(document).on('ready load', function() { + return $('body').renderGFM(); +}); diff --git a/app/assets/javascripts/render_math.js b/app/assets/javascripts/render_math.js index 8b3fee49cb9..1596cbe266f 100644 --- a/app/assets/javascripts/render_math.js +++ b/app/assets/javascripts/render_math.js @@ -8,49 +8,47 @@ // // <code class="js-render-math"></div> // -(function() { - // Only load once - var katexLoaded = false; +// Only load once +var katexLoaded = false; - // Loop over all math elements and render math - var renderWithKaTeX = function (elements) { - elements.each(function () { - var mathNode = $('<span></span>'); - var $this = $(this); +// Loop over all math elements and render math +var renderWithKaTeX = function (elements) { + elements.each(function () { + var mathNode = $('<span></span>'); + var $this = $(this); - var display = $this.attr('data-math-style') === 'display'; - try { - katex.render($this.text(), mathNode.get(0), { displayMode: display }); - mathNode.insertAfter($this); - $this.remove(); - } catch (err) { - // What can we do?? - console.log(err.message); - } - }); - }; - - $.fn.renderMath = function() { - var $this = this; - if ($this.length === 0) return; + var display = $this.attr('data-math-style') === 'display'; + try { + katex.render($this.text(), mathNode.get(0), { displayMode: display }); + mathNode.insertAfter($this); + $this.remove(); + } catch (err) { + // What can we do?? + console.log(err.message); + } + }); +}; - if (katexLoaded) renderWithKaTeX($this); - else { - // Request CSS file so it is in the cache - $.get(gon.katex_css_url, function() { - var css = $('<link>', - { rel: 'stylesheet', - type: 'text/css', - href: gon.katex_css_url, - }); - css.appendTo('head'); +$.fn.renderMath = function() { + var $this = this; + if ($this.length === 0) return; - // Load KaTeX js - $.getScript(gon.katex_js_url, function() { - katexLoaded = true; - renderWithKaTeX($this); // Run KaTeX + if (katexLoaded) renderWithKaTeX($this); + else { + // Request CSS file so it is in the cache + $.get(gon.katex_css_url, function() { + var css = $('<link>', + { rel: 'stylesheet', + type: 'text/css', + href: gon.katex_css_url, }); + css.appendTo('head'); + + // Load KaTeX js + $.getScript(gon.katex_js_url, function() { + katexLoaded = true; + renderWithKaTeX($this); // Run KaTeX }); - } - }; -}).call(window); + }); + } +}; diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index d8f1fe10b26..9b16e4cd613 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -3,218 +3,214 @@ import Cookies from 'js-cookie'; import SidebarHeightManager from './sidebar_height_manager'; -(function() { - this.Sidebar = (function() { - function Sidebar(currentUser) { - this.toggleTodo = this.toggleTodo.bind(this); - this.sidebar = $('aside'); - - this.removeListeners(); - this.addEventListeners(); +function Sidebar(currentUser) { + this.toggleTodo = this.toggleTodo.bind(this); + this.sidebar = $('aside'); + + this.removeListeners(); + this.addEventListeners(); +} + +Sidebar.prototype.removeListeners = function () { + this.sidebar.off('click', '.sidebar-collapsed-icon'); + $('.dropdown').off('hidden.gl.dropdown'); + $('.dropdown').off('loading.gl.dropdown'); + $('.dropdown').off('loaded.gl.dropdown'); + $(document).off('click', '.js-sidebar-toggle'); +}; + +Sidebar.prototype.addEventListeners = function() { + SidebarHeightManager.init(); + const $document = $(document); + + this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked); + $('.dropdown').on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden); + $('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading); + $('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded); + + $document.on('click', '.js-sidebar-toggle', function(e, triggered) { + var $allGutterToggleIcons, $this, $thisIcon; + e.preventDefault(); + $this = $(this); + $thisIcon = $this.find('i'); + $allGutterToggleIcons = $('.js-sidebar-toggle i'); + if ($thisIcon.hasClass('fa-angle-double-right')) { + $allGutterToggleIcons.removeClass('fa-angle-double-right').addClass('fa-angle-double-left'); + $('aside.right-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed'); + $('.page-with-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed'); + } else { + $allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right'); + $('aside.right-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded'); + $('.page-with-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded'); } - - Sidebar.prototype.removeListeners = function () { - this.sidebar.off('click', '.sidebar-collapsed-icon'); - $('.dropdown').off('hidden.gl.dropdown'); - $('.dropdown').off('loading.gl.dropdown'); - $('.dropdown').off('loaded.gl.dropdown'); - $(document).off('click', '.js-sidebar-toggle'); - }; - - Sidebar.prototype.addEventListeners = function() { - SidebarHeightManager.init(); - const $document = $(document); - - this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked); - $('.dropdown').on('hidden.gl.dropdown', this, this.onSidebarDropdownHidden); - $('.dropdown').on('loading.gl.dropdown', this.sidebarDropdownLoading); - $('.dropdown').on('loaded.gl.dropdown', this.sidebarDropdownLoaded); - - $document.on('click', '.js-sidebar-toggle', function(e, triggered) { - var $allGutterToggleIcons, $this, $thisIcon; - e.preventDefault(); - $this = $(this); - $thisIcon = $this.find('i'); - $allGutterToggleIcons = $('.js-sidebar-toggle i'); - if ($thisIcon.hasClass('fa-angle-double-right')) { - $allGutterToggleIcons.removeClass('fa-angle-double-right').addClass('fa-angle-double-left'); - $('aside.right-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed'); - $('.page-with-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed'); - } else { - $allGutterToggleIcons.removeClass('fa-angle-double-left').addClass('fa-angle-double-right'); - $('aside.right-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded'); - $('.page-with-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded'); - } - if (!triggered) { - return Cookies.set("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed')); - } - }); - return $(document).off('click', '.js-issuable-todo').on('click', '.js-issuable-todo', this.toggleTodo); - }; - - Sidebar.prototype.toggleTodo = function(e) { - var $btnText, $this, $todoLoading, ajaxType, url; - $this = $(e.currentTarget); - ajaxType = $this.attr('data-delete-path') ? 'DELETE' : 'POST'; - if ($this.attr('data-delete-path')) { - url = "" + ($this.attr('data-delete-path')); - } else { - url = "" + ($this.data('url')); - } - - $this.tooltip('hide'); - - return $.ajax({ - url: url, - type: ajaxType, - dataType: 'json', - data: { - issuable_id: $this.data('issuable-id'), - issuable_type: $this.data('issuable-type') - }, - beforeSend: (function(_this) { - return function() { - $('.js-issuable-todo').disable() - .addClass('is-loading'); - }; - })(this) - }).done((function(_this) { - return function(data) { - return _this.todoUpdateDone(data); - }; - })(this)); - }; - - Sidebar.prototype.todoUpdateDone = function(data) { - const deletePath = data.delete_path ? data.delete_path : null; - const attrPrefix = deletePath ? 'mark' : 'todo'; - const $todoBtns = $('.js-issuable-todo'); - - $(document).trigger('todo:toggle', data.count); - - $todoBtns.each((i, el) => { - const $el = $(el); - const $elText = $el.find('.js-issuable-todo-inner'); - - $el.removeClass('is-loading') - .enable() - .attr('aria-label', $el.data(`${attrPrefix}-text`)) - .attr('data-delete-path', deletePath) - .attr('title', $el.data(`${attrPrefix}-text`)); - - if ($el.hasClass('has-tooltip')) { - $el.tooltip('fixTitle'); - } - - if ($el.data(`${attrPrefix}-icon`)) { - $elText.html($el.data(`${attrPrefix}-icon`)); - } else { - $elText.text($el.data(`${attrPrefix}-text`)); - } - }); - }; - - Sidebar.prototype.sidebarDropdownLoading = function(e) { - var $loading, $sidebarCollapsedIcon, i, img; - $sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon'); - img = $sidebarCollapsedIcon.find('img'); - i = $sidebarCollapsedIcon.find('i'); - $loading = $('<i class="fa fa-spinner fa-spin"></i>'); - if (img.length) { - img.before($loading); - return img.hide(); - } else if (i.length) { - i.before($loading); - return i.hide(); - } - }; - - Sidebar.prototype.sidebarDropdownLoaded = function(e) { - var $sidebarCollapsedIcon, i, img; - $sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon'); - img = $sidebarCollapsedIcon.find('img'); - $sidebarCollapsedIcon.find('i.fa-spin').remove(); - i = $sidebarCollapsedIcon.find('i'); - if (img.length) { - return img.show(); - } else { - return i.show(); - } - }; - - Sidebar.prototype.sidebarCollapseClicked = function(e) { - var $block, sidebar; - if ($(e.currentTarget).hasClass('dont-change-state')) { - return; - } - sidebar = e.data; - e.preventDefault(); - $block = $(this).closest('.block'); - return sidebar.openDropdown($block); + if (!triggered) { + return Cookies.set("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed')); + } + }); + return $(document).off('click', '.js-issuable-todo').on('click', '.js-issuable-todo', this.toggleTodo); +}; + +Sidebar.prototype.toggleTodo = function(e) { + var $btnText, $this, $todoLoading, ajaxType, url; + $this = $(e.currentTarget); + ajaxType = $this.attr('data-delete-path') ? 'DELETE' : 'POST'; + if ($this.attr('data-delete-path')) { + url = "" + ($this.attr('data-delete-path')); + } else { + url = "" + ($this.data('url')); + } + + $this.tooltip('hide'); + + return $.ajax({ + url: url, + type: ajaxType, + dataType: 'json', + data: { + issuable_id: $this.data('issuable-id'), + issuable_type: $this.data('issuable-type') + }, + beforeSend: (function(_this) { + return function() { + $('.js-issuable-todo').disable() + .addClass('is-loading'); + }; + })(this) + }).done((function(_this) { + return function(data) { + return _this.todoUpdateDone(data); }; + })(this)); +}; - Sidebar.prototype.openDropdown = function(blockOrName) { - var $block; - $block = _.isString(blockOrName) ? this.getBlock(blockOrName) : blockOrName; - $block.find('.edit-link').trigger('click'); - if (!this.isOpen()) { - this.setCollapseAfterUpdate($block); - return this.toggleSidebar('open'); - } - }; +Sidebar.prototype.todoUpdateDone = function(data) { + const deletePath = data.delete_path ? data.delete_path : null; + const attrPrefix = deletePath ? 'mark' : 'todo'; + const $todoBtns = $('.js-issuable-todo'); - Sidebar.prototype.setCollapseAfterUpdate = function($block) { - $block.addClass('collapse-after-update'); - return $('.page-with-sidebar').addClass('with-overlay'); - }; + $(document).trigger('todo:toggle', data.count); - Sidebar.prototype.onSidebarDropdownHidden = function(e) { - var $block, sidebar; - sidebar = e.data; - e.preventDefault(); - $block = $(this).closest('.block'); - return sidebar.sidebarDropdownHidden($block); - }; + $todoBtns.each((i, el) => { + const $el = $(el); + const $elText = $el.find('.js-issuable-todo-inner'); - Sidebar.prototype.sidebarDropdownHidden = function($block) { - if ($block.hasClass('collapse-after-update')) { - $block.removeClass('collapse-after-update'); - $('.page-with-sidebar').removeClass('with-overlay'); - return this.toggleSidebar('hide'); - } - }; + $el.removeClass('is-loading') + .enable() + .attr('aria-label', $el.data(`${attrPrefix}-text`)) + .attr('data-delete-path', deletePath) + .attr('title', $el.data(`${attrPrefix}-text`)); - Sidebar.prototype.triggerOpenSidebar = function() { - return this.sidebar.find('.js-sidebar-toggle').trigger('click'); - }; + if ($el.hasClass('has-tooltip')) { + $el.tooltip('fixTitle'); + } - Sidebar.prototype.toggleSidebar = function(action) { - if (action == null) { - action = 'toggle'; - } - if (action === 'toggle') { - this.triggerOpenSidebar(); - } - if (action === 'open') { - if (!this.isOpen()) { - this.triggerOpenSidebar(); - } - } - if (action === 'hide') { - if (this.isOpen()) { - return this.triggerOpenSidebar(); - } - } - }; + if ($el.data(`${attrPrefix}-icon`)) { + $elText.html($el.data(`${attrPrefix}-icon`)); + } else { + $elText.text($el.data(`${attrPrefix}-text`)); + } + }); +}; + +Sidebar.prototype.sidebarDropdownLoading = function(e) { + var $loading, $sidebarCollapsedIcon, i, img; + $sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon'); + img = $sidebarCollapsedIcon.find('img'); + i = $sidebarCollapsedIcon.find('i'); + $loading = $('<i class="fa fa-spinner fa-spin"></i>'); + if (img.length) { + img.before($loading); + return img.hide(); + } else if (i.length) { + i.before($loading); + return i.hide(); + } +}; + +Sidebar.prototype.sidebarDropdownLoaded = function(e) { + var $sidebarCollapsedIcon, i, img; + $sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon'); + img = $sidebarCollapsedIcon.find('img'); + $sidebarCollapsedIcon.find('i.fa-spin').remove(); + i = $sidebarCollapsedIcon.find('i'); + if (img.length) { + return img.show(); + } else { + return i.show(); + } +}; + +Sidebar.prototype.sidebarCollapseClicked = function(e) { + var $block, sidebar; + if ($(e.currentTarget).hasClass('dont-change-state')) { + return; + } + sidebar = e.data; + e.preventDefault(); + $block = $(this).closest('.block'); + return sidebar.openDropdown($block); +}; + +Sidebar.prototype.openDropdown = function(blockOrName) { + var $block; + $block = _.isString(blockOrName) ? this.getBlock(blockOrName) : blockOrName; + $block.find('.edit-link').trigger('click'); + if (!this.isOpen()) { + this.setCollapseAfterUpdate($block); + return this.toggleSidebar('open'); + } +}; + +Sidebar.prototype.setCollapseAfterUpdate = function($block) { + $block.addClass('collapse-after-update'); + return $('.page-with-sidebar').addClass('with-overlay'); +}; + +Sidebar.prototype.onSidebarDropdownHidden = function(e) { + var $block, sidebar; + sidebar = e.data; + e.preventDefault(); + $block = $(this).closest('.block'); + return sidebar.sidebarDropdownHidden($block); +}; + +Sidebar.prototype.sidebarDropdownHidden = function($block) { + if ($block.hasClass('collapse-after-update')) { + $block.removeClass('collapse-after-update'); + $('.page-with-sidebar').removeClass('with-overlay'); + return this.toggleSidebar('hide'); + } +}; + +Sidebar.prototype.triggerOpenSidebar = function() { + return this.sidebar.find('.js-sidebar-toggle').trigger('click'); +}; + +Sidebar.prototype.toggleSidebar = function(action) { + if (action == null) { + action = 'toggle'; + } + if (action === 'toggle') { + this.triggerOpenSidebar(); + } + if (action === 'open') { + if (!this.isOpen()) { + this.triggerOpenSidebar(); + } + } + if (action === 'hide') { + if (this.isOpen()) { + return this.triggerOpenSidebar(); + } + } +}; - Sidebar.prototype.isOpen = function() { - return this.sidebar.is('.right-sidebar-expanded'); - }; +Sidebar.prototype.isOpen = function() { + return this.sidebar.is('.right-sidebar-expanded'); +}; - Sidebar.prototype.getBlock = function(name) { - return this.sidebar.find(".block." + name); - }; +Sidebar.prototype.getBlock = function(name) { + return this.sidebar.find(".block." + name); +}; - return Sidebar; - })(); -}).call(window); +window.Sidebar = Sidebar; diff --git a/app/assets/javascripts/search.js b/app/assets/javascripts/search.js index 05caf177aec..15b7add82c8 100644 --- a/app/assets/javascripts/search.js +++ b/app/assets/javascripts/search.js @@ -2,117 +2,113 @@ /* global Flash */ import Api from './api'; -(function() { - this.Search = (function() { - function Search() { - var $groupDropdown, $projectDropdown; - $groupDropdown = $('.js-search-group-dropdown'); - $projectDropdown = $('.js-search-project-dropdown'); - this.groupId = $groupDropdown.data('group-id'); - this.eventListeners(); - $groupDropdown.glDropdown({ - selectable: true, - filterable: true, - fieldName: 'group_id', - search: { - fields: ['full_name'] - }, - data: function(term, callback) { - return Api.groups(term, {}, function(data) { - data.unshift({ - full_name: 'Any' - }); - data.splice(1, 0, 'divider'); - return callback(data); - }); - }, - id: function(obj) { - return obj.id; - }, - text: function(obj) { - return obj.full_name; - }, - toggleLabel: function(obj) { - return ($groupDropdown.data('default-label')) + " " + obj.full_name; - }, - clicked: (function(_this) { - return function() { - return _this.submitSearch(); - }; - })(this) +function Search() { + var $groupDropdown, $projectDropdown; + $groupDropdown = $('.js-search-group-dropdown'); + $projectDropdown = $('.js-search-project-dropdown'); + this.groupId = $groupDropdown.data('group-id'); + this.eventListeners(); + $groupDropdown.glDropdown({ + selectable: true, + filterable: true, + fieldName: 'group_id', + search: { + fields: ['full_name'] + }, + data: function(term, callback) { + return Api.groups(term, {}, function(data) { + data.unshift({ + full_name: 'Any' + }); + data.splice(1, 0, 'divider'); + return callback(data); }); - $projectDropdown.glDropdown({ - selectable: true, - filterable: true, - fieldName: 'project_id', - search: { - fields: ['name'] - }, - data: (term, callback) => { - this.getProjectsData(term) - .then((data) => { - data.unshift({ - name_with_namespace: 'Any' - }); - data.splice(1, 0, 'divider'); + }, + id: function(obj) { + return obj.id; + }, + text: function(obj) { + return obj.full_name; + }, + toggleLabel: function(obj) { + return ($groupDropdown.data('default-label')) + " " + obj.full_name; + }, + clicked: (function(_this) { + return function() { + return _this.submitSearch(); + }; + })(this) + }); + $projectDropdown.glDropdown({ + selectable: true, + filterable: true, + fieldName: 'project_id', + search: { + fields: ['name'] + }, + data: (term, callback) => { + this.getProjectsData(term) + .then((data) => { + data.unshift({ + name_with_namespace: 'Any' + }); + data.splice(1, 0, 'divider'); - return data; - }) - .then(data => callback(data)) - .catch(() => new Flash('Error fetching projects')); - }, - id: function(obj) { - return obj.id; - }, - text: function(obj) { - return obj.name_with_namespace; - }, - toggleLabel: function(obj) { - return ($projectDropdown.data('default-label')) + " " + obj.name_with_namespace; - }, - clicked: (function(_this) { - return function() { - return _this.submitSearch(); - }; - })(this) - }); - } + return data; + }) + .then(data => callback(data)) + .catch(() => new Flash('Error fetching projects')); + }, + id: function(obj) { + return obj.id; + }, + text: function(obj) { + return obj.name_with_namespace; + }, + toggleLabel: function(obj) { + return ($projectDropdown.data('default-label')) + " " + obj.name_with_namespace; + }, + clicked: (function(_this) { + return function() { + return _this.submitSearch(); + }; + })(this) + }); +} - Search.prototype.eventListeners = function() { - $(document).off('keyup', '.js-search-input').on('keyup', '.js-search-input', this.searchKeyUp); - return $(document).off('click', '.js-search-clear').on('click', '.js-search-clear', this.clearSearchField); - }; +Search.prototype.eventListeners = function() { + $(document).off('keyup', '.js-search-input').on('keyup', '.js-search-input', this.searchKeyUp); + return $(document).off('click', '.js-search-clear').on('click', '.js-search-clear', this.clearSearchField); +}; - Search.prototype.submitSearch = function() { - return $('.js-search-form').submit(); - }; +Search.prototype.submitSearch = function() { + return $('.js-search-form').submit(); +}; - Search.prototype.searchKeyUp = function() { - var $input; - $input = $(this); - if ($input.val() === '') { - return $('.js-search-clear').addClass('hidden'); - } else { - return $('.js-search-clear').removeClass('hidden'); - } - }; +Search.prototype.searchKeyUp = function() { + var $input; + $input = $(this); + if ($input.val() === '') { + return $('.js-search-clear').addClass('hidden'); + } else { + return $('.js-search-clear').removeClass('hidden'); + } +}; - Search.prototype.clearSearchField = function() { - return $('.js-search-input').val('').trigger('keyup').focus(); - }; +Search.prototype.clearSearchField = function() { + return $('.js-search-input').val('').trigger('keyup').focus(); +}; - Search.prototype.getProjectsData = function(term) { - return new Promise((resolve) => { - if (this.groupId) { - Api.groupProjects(this.groupId, term, resolve); - } else { - Api.projects(term, { - order_by: 'id', - }, resolve); - } - }); - }; +Search.prototype.getProjectsData = function(term) { + return new Promise((resolve) => { + if (this.groupId) { + Api.groupProjects(this.groupId, term, resolve); + } else { + Api.projects(term, { + order_by: 'id', + }, resolve); + } + }); +}; - return Search; - })(); -}).call(window); +window.Search = Search; diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js index 6fd5345a0a6..68966c400b3 100644 --- a/app/assets/javascripts/search_autocomplete.js +++ b/app/assets/javascripts/search_autocomplete.js @@ -1,432 +1,427 @@ /* eslint-disable comma-dangle, no-return-assign, one-var, no-var, no-underscore-dangle, one-var-declaration-per-line, no-unused-vars, no-cond-assign, consistent-return, object-shorthand, prefer-arrow-callback, func-names, space-before-function-paren, prefer-template, quotes, class-methods-use-this, no-unused-expressions, no-sequences, wrap-iife, no-lonely-if, no-else-return, no-param-reassign, vars-on-top, max-len */ - -((global) => { - const KEYCODE = { - ESCAPE: 27, - BACKSPACE: 8, - ENTER: 13, - UP: 38, - DOWN: 40 - }; - - class SearchAutocomplete { - constructor({ wrap, optsEl, autocompletePath, projectId, projectRef } = {}) { - this.bindEventContext(); - this.wrap = wrap || $('.search'); - this.optsEl = optsEl || this.wrap.find('.search-autocomplete-opts'); - this.autocompletePath = autocompletePath || this.optsEl.data('autocomplete-path'); - this.projectId = projectId || (this.optsEl.data('autocomplete-project-id') || ''); - this.projectRef = projectRef || (this.optsEl.data('autocomplete-project-ref') || ''); - this.dropdown = this.wrap.find('.dropdown'); - this.dropdownContent = this.dropdown.find('.dropdown-content'); - this.locationBadgeEl = this.getElement('.location-badge'); - this.scopeInputEl = this.getElement('#scope'); - this.searchInput = this.getElement('.search-input'); - this.projectInputEl = this.getElement('#search_project_id'); - this.groupInputEl = this.getElement('#group_id'); - this.searchCodeInputEl = this.getElement('#search_code'); - this.repositoryInputEl = this.getElement('#repository_ref'); - this.clearInput = this.getElement('.js-clear-input'); - this.saveOriginalState(); - // Only when user is logged in - if (gon.current_user_id) { - this.createAutocomplete(); - } - this.searchInput.addClass('disabled'); - this.saveTextLength(); - this.bindEvents(); +const global = window.gl || (window.gl = {}); + +const KEYCODE = { + ESCAPE: 27, + BACKSPACE: 8, + ENTER: 13, + UP: 38, + DOWN: 40 +}; + +class SearchAutocomplete { + constructor({ wrap, optsEl, autocompletePath, projectId, projectRef } = {}) { + this.bindEventContext(); + this.wrap = wrap || $('.search'); + this.optsEl = optsEl || this.wrap.find('.search-autocomplete-opts'); + this.autocompletePath = autocompletePath || this.optsEl.data('autocomplete-path'); + this.projectId = projectId || (this.optsEl.data('autocomplete-project-id') || ''); + this.projectRef = projectRef || (this.optsEl.data('autocomplete-project-ref') || ''); + this.dropdown = this.wrap.find('.dropdown'); + this.dropdownContent = this.dropdown.find('.dropdown-content'); + this.locationBadgeEl = this.getElement('.location-badge'); + this.scopeInputEl = this.getElement('#scope'); + this.searchInput = this.getElement('.search-input'); + this.projectInputEl = this.getElement('#search_project_id'); + this.groupInputEl = this.getElement('#group_id'); + this.searchCodeInputEl = this.getElement('#search_code'); + this.repositoryInputEl = this.getElement('#repository_ref'); + this.clearInput = this.getElement('.js-clear-input'); + this.saveOriginalState(); + // Only when user is logged in + if (gon.current_user_id) { + this.createAutocomplete(); } + this.searchInput.addClass('disabled'); + this.saveTextLength(); + this.bindEvents(); + } - // Finds an element inside wrapper element - bindEventContext() { - this.onSearchInputBlur = this.onSearchInputBlur.bind(this); - this.onClearInputClick = this.onClearInputClick.bind(this); - this.onSearchInputFocus = this.onSearchInputFocus.bind(this); - this.onSearchInputClick = this.onSearchInputClick.bind(this); - this.onSearchInputKeyUp = this.onSearchInputKeyUp.bind(this); - this.onSearchInputKeyDown = this.onSearchInputKeyDown.bind(this); - } - getElement(selector) { - return this.wrap.find(selector); - } + // Finds an element inside wrapper element + bindEventContext() { + this.onSearchInputBlur = this.onSearchInputBlur.bind(this); + this.onClearInputClick = this.onClearInputClick.bind(this); + this.onSearchInputFocus = this.onSearchInputFocus.bind(this); + this.onSearchInputClick = this.onSearchInputClick.bind(this); + this.onSearchInputKeyUp = this.onSearchInputKeyUp.bind(this); + this.onSearchInputKeyDown = this.onSearchInputKeyDown.bind(this); + } + getElement(selector) { + return this.wrap.find(selector); + } - saveOriginalState() { - return this.originalState = this.serializeState(); - } + saveOriginalState() { + return this.originalState = this.serializeState(); + } - saveTextLength() { - return this.lastTextLength = this.searchInput.val().length; - } + saveTextLength() { + return this.lastTextLength = this.searchInput.val().length; + } - createAutocomplete() { - return this.searchInput.glDropdown({ - filterInputBlur: false, - filterable: true, - filterRemote: true, - highlight: true, - enterCallback: false, - filterInput: 'input#search', - search: { - fields: ['text'] - }, - id: this.getSearchText, - data: this.getData.bind(this), - selectable: true, - clicked: this.onClick.bind(this) - }); - } + createAutocomplete() { + return this.searchInput.glDropdown({ + filterInputBlur: false, + filterable: true, + filterRemote: true, + highlight: true, + enterCallback: false, + filterInput: 'input#search', + search: { + fields: ['text'] + }, + id: this.getSearchText, + data: this.getData.bind(this), + selectable: true, + clicked: this.onClick.bind(this) + }); + } - getSearchText(selectedObject, el) { - return selectedObject.id ? selectedObject.text : ''; - } + getSearchText(selectedObject, el) { + return selectedObject.id ? selectedObject.text : ''; + } - getData(term, callback) { - var _this, contents, jqXHR; - _this = this; - if (!term) { - if (contents = this.getCategoryContents()) { - this.searchInput.data('glDropdown').filter.options.callback(contents); - this.enableAutocomplete(); - } - return; + getData(term, callback) { + var _this, contents, jqXHR; + _this = this; + if (!term) { + if (contents = this.getCategoryContents()) { + this.searchInput.data('glDropdown').filter.options.callback(contents); + this.enableAutocomplete(); } - // Prevent multiple ajax calls - if (this.loadingSuggestions) { + return; + } + // Prevent multiple ajax calls + if (this.loadingSuggestions) { + return; + } + this.loadingSuggestions = true; + return jqXHR = $.get(this.autocompletePath, { + project_id: this.projectId, + project_ref: this.projectRef, + term: term + }, function(response) { + var data, firstCategory, i, lastCategory, len, suggestion; + // Hide dropdown menu if no suggestions returns + if (!response.length) { + _this.disableAutocomplete(); return; } - this.loadingSuggestions = true; - return jqXHR = $.get(this.autocompletePath, { - project_id: this.projectId, - project_ref: this.projectRef, - term: term - }, function(response) { - var data, firstCategory, i, lastCategory, len, suggestion; - // Hide dropdown menu if no suggestions returns - if (!response.length) { - _this.disableAutocomplete(); - return; - } - data = []; - // List results - firstCategory = true; - for (i = 0, len = response.length; i < len; i += 1) { - suggestion = response[i]; - // Add group header before list each group - if (lastCategory !== suggestion.category) { - if (!firstCategory) { - data.push('separator'); - } - if (firstCategory) { - firstCategory = false; - } - data.push({ - header: suggestion.category - }); - lastCategory = suggestion.category; + data = []; + // List results + firstCategory = true; + for (i = 0, len = response.length; i < len; i += 1) { + suggestion = response[i]; + // Add group header before list each group + if (lastCategory !== suggestion.category) { + if (!firstCategory) { + data.push('separator'); + } + if (firstCategory) { + firstCategory = false; } data.push({ - id: (suggestion.category.toLowerCase()) + "-" + suggestion.id, - category: suggestion.category, - text: suggestion.label, - url: suggestion.url - }); - } - // Add option to proceed with the search - if (data.length) { - data.push('separator'); - data.push({ - text: "Result name contains \"" + term + "\"", - url: "/search?search=" + term + "&project_id=" + (_this.projectInputEl.val()) + "&group_id=" + (_this.groupInputEl.val()) + header: suggestion.category }); + lastCategory = suggestion.category; } - return callback(data); - }).always(function() { - return _this.loadingSuggestions = false; - }); - } - - getCategoryContents() { - var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName, utils; - userId = gon.current_user_id; - userName = gon.current_username; - utils = gl.utils, projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions; - if (utils.isInGroupsPage() && groupOptions) { - options = groupOptions[utils.getGroupSlug()]; - } else if (utils.isInProjectPage() && projectOptions) { - options = projectOptions[utils.getProjectSlug()]; - } else if (dashboardOptions) { - options = dashboardOptions; + data.push({ + id: (suggestion.category.toLowerCase()) + "-" + suggestion.id, + category: suggestion.category, + text: suggestion.label, + url: suggestion.url + }); } - issuesPath = options.issuesPath, mrPath = options.mrPath, name = options.name; - items = [ - { - header: "" + name - }, { - text: 'Issues assigned to me', - url: issuesPath + "/?assignee_username=" + userName - }, { - text: "Issues I've created", - url: issuesPath + "/?author_username=" + userName - }, 'separator', { - text: 'Merge requests assigned to me', - url: mrPath + "/?assignee_username=" + userName - }, { - text: "Merge requests I've created", - url: mrPath + "/?author_username=" + userName - } - ]; - if (!name) { - items.splice(0, 1); + // Add option to proceed with the search + if (data.length) { + data.push('separator'); + data.push({ + text: "Result name contains \"" + term + "\"", + url: "/search?search=" + term + "&project_id=" + (_this.projectInputEl.val()) + "&group_id=" + (_this.groupInputEl.val()) + }); } - return items; - } - - serializeState() { - return { - // Search Criteria - search_project_id: this.projectInputEl.val(), - group_id: this.groupInputEl.val(), - search_code: this.searchCodeInputEl.val(), - repository_ref: this.repositoryInputEl.val(), - scope: this.scopeInputEl.val(), - // Location badge - _location: this.locationBadgeEl.text() - }; - } + return callback(data); + }).always(function() { + return _this.loadingSuggestions = false; + }); + } - bindEvents() { - this.searchInput.on('keydown', this.onSearchInputKeyDown); - this.searchInput.on('keyup', this.onSearchInputKeyUp); - this.searchInput.on('click', this.onSearchInputClick); - this.searchInput.on('focus', this.onSearchInputFocus); - this.searchInput.on('blur', this.onSearchInputBlur); - this.clearInput.on('click', this.onClearInputClick); - return this.locationBadgeEl.on('click', (function(_this) { - return function() { - return _this.searchInput.focus(); - }; - })(this)); + getCategoryContents() { + var dashboardOptions, groupOptions, issuesPath, items, mrPath, name, options, projectOptions, userId, userName, utils; + userId = gon.current_user_id; + userName = gon.current_username; + utils = gl.utils, projectOptions = gl.projectOptions, groupOptions = gl.groupOptions, dashboardOptions = gl.dashboardOptions; + if (utils.isInGroupsPage() && groupOptions) { + options = groupOptions[utils.getGroupSlug()]; + } else if (utils.isInProjectPage() && projectOptions) { + options = projectOptions[utils.getProjectSlug()]; + } else if (dashboardOptions) { + options = dashboardOptions; } - - enableAutocomplete() { - var _this; - // No need to enable anything if user is not logged in - if (!gon.current_user_id) { - return; - } - if (!this.dropdown.hasClass('open')) { - _this = this; - this.loadingSuggestions = false; - this.dropdown.addClass('open').trigger('shown.bs.dropdown'); - return this.searchInput.removeClass('disabled'); + issuesPath = options.issuesPath, mrPath = options.mrPath, name = options.name; + items = [ + { + header: "" + name + }, { + text: 'Issues assigned to me', + url: issuesPath + "/?assignee_username=" + userName + }, { + text: "Issues I've created", + url: issuesPath + "/?author_username=" + userName + }, 'separator', { + text: 'Merge requests assigned to me', + url: mrPath + "/?assignee_username=" + userName + }, { + text: "Merge requests I've created", + url: mrPath + "/?author_username=" + userName } + ]; + if (!name) { + items.splice(0, 1); } + return items; + } - // Saves last length of the entered text - onSearchInputKeyDown() { - return this.saveTextLength(); + serializeState() { + return { + // Search Criteria + search_project_id: this.projectInputEl.val(), + group_id: this.groupInputEl.val(), + search_code: this.searchCodeInputEl.val(), + repository_ref: this.repositoryInputEl.val(), + scope: this.scopeInputEl.val(), + // Location badge + _location: this.locationBadgeEl.text() + }; + } + + bindEvents() { + this.searchInput.on('keydown', this.onSearchInputKeyDown); + this.searchInput.on('keyup', this.onSearchInputKeyUp); + this.searchInput.on('click', this.onSearchInputClick); + this.searchInput.on('focus', this.onSearchInputFocus); + this.searchInput.on('blur', this.onSearchInputBlur); + this.clearInput.on('click', this.onClearInputClick); + return this.locationBadgeEl.on('click', () => this.searchInput.focus()); + } + + enableAutocomplete() { + var _this; + // No need to enable anything if user is not logged in + if (!gon.current_user_id) { + return; } + if (!this.dropdown.hasClass('open')) { + _this = this; + this.loadingSuggestions = false; + this.dropdown.addClass('open').trigger('shown.bs.dropdown'); + return this.searchInput.removeClass('disabled'); + } + } - onSearchInputKeyUp(e) { - switch (e.keyCode) { - case KEYCODE.BACKSPACE: - // when trying to remove the location badge - if (this.lastTextLength === 0 && this.badgePresent()) { - this.removeLocationBadge(); - } - // When removing the last character and no badge is present - if (this.lastTextLength === 1) { - this.disableAutocomplete(); - } - // When removing any character from existin value - if (this.lastTextLength > 1) { - this.enableAutocomplete(); - } - break; - case KEYCODE.ESCAPE: - this.restoreOriginalState(); - break; - case KEYCODE.ENTER: + // Saves last length of the entered text + onSearchInputKeyDown() { + return this.saveTextLength(); + } + + onSearchInputKeyUp(e) { + switch (e.keyCode) { + case KEYCODE.BACKSPACE: + // when trying to remove the location badge + if (this.lastTextLength === 0 && this.badgePresent()) { + this.removeLocationBadge(); + } + // When removing the last character and no badge is present + if (this.lastTextLength === 1) { this.disableAutocomplete(); - break; - case KEYCODE.UP: - case KEYCODE.DOWN: - return; - default: - // Handle the case when deleting the input value other than backspace - // e.g. Pressing ctrl + backspace or ctrl + x - if (this.searchInput.val() === '') { - this.disableAutocomplete(); - } else { - // We should display the menu only when input is not empty - if (e.keyCode !== KEYCODE.ENTER) { - this.enableAutocomplete(); - } + } + // When removing any character from existin value + if (this.lastTextLength > 1) { + this.enableAutocomplete(); + } + break; + case KEYCODE.ESCAPE: + this.restoreOriginalState(); + break; + case KEYCODE.ENTER: + this.disableAutocomplete(); + break; + case KEYCODE.UP: + case KEYCODE.DOWN: + return; + default: + // Handle the case when deleting the input value other than backspace + // e.g. Pressing ctrl + backspace or ctrl + x + if (this.searchInput.val() === '') { + this.disableAutocomplete(); + } else { + // We should display the menu only when input is not empty + if (e.keyCode !== KEYCODE.ENTER) { + this.enableAutocomplete(); } - } - this.wrap.toggleClass('has-value', !!e.target.value); + } } + this.wrap.toggleClass('has-value', !!e.target.value); + } - // Avoid falsy value to be returned - onSearchInputClick(e) { - return e.stopImmediatePropagation(); - } + // Avoid falsy value to be returned + onSearchInputClick(e) { + return e.stopImmediatePropagation(); + } - onSearchInputFocus() { - this.isFocused = true; - this.wrap.addClass('search-active'); - if (this.getValue() === '') { - return this.getData(); - } + onSearchInputFocus() { + this.isFocused = true; + this.wrap.addClass('search-active'); + if (this.getValue() === '') { + return this.getData(); } + } - getValue() { - return this.searchInput.val(); - } + getValue() { + return this.searchInput.val(); + } - onClearInputClick(e) { - e.preventDefault(); - return this.searchInput.val('').focus(); - } + onClearInputClick(e) { + e.preventDefault(); + return this.searchInput.val('').focus(); + } - onSearchInputBlur(e) { - this.isFocused = false; - this.wrap.removeClass('search-active'); - // If input is blank then restore state - if (this.searchInput.val() === '') { - return this.restoreOriginalState(); - } + onSearchInputBlur(e) { + this.isFocused = false; + this.wrap.removeClass('search-active'); + // If input is blank then restore state + if (this.searchInput.val() === '') { + return this.restoreOriginalState(); } + } - addLocationBadge(item) { - var badgeText, category, value; - category = item.category != null ? item.category + ": " : ''; - value = item.value != null ? item.value : ''; - badgeText = "" + category + value; - this.locationBadgeEl.text(badgeText).show(); - return this.wrap.addClass('has-location-badge'); - } + addLocationBadge(item) { + var badgeText, category, value; + category = item.category != null ? item.category + ": " : ''; + value = item.value != null ? item.value : ''; + badgeText = "" + category + value; + this.locationBadgeEl.text(badgeText).show(); + return this.wrap.addClass('has-location-badge'); + } - hasLocationBadge() { - return this.wrap.is('.has-location-badge'); - } + hasLocationBadge() { + return this.wrap.is('.has-location-badge'); + } - restoreOriginalState() { - var i, input, inputs, len; - inputs = Object.keys(this.originalState); - for (i = 0, len = inputs.length; i < len; i += 1) { - input = inputs[i]; - this.getElement("#" + input).val(this.originalState[input]); - } - if (this.originalState._location === '') { - return this.locationBadgeEl.hide(); - } else { - return this.addLocationBadge({ - value: this.originalState._location - }); - } + restoreOriginalState() { + var i, input, inputs, len; + inputs = Object.keys(this.originalState); + for (i = 0, len = inputs.length; i < len; i += 1) { + input = inputs[i]; + this.getElement("#" + input).val(this.originalState[input]); } - - badgePresent() { - return this.locationBadgeEl.length; + if (this.originalState._location === '') { + return this.locationBadgeEl.hide(); + } else { + return this.addLocationBadge({ + value: this.originalState._location + }); } + } - resetSearchState() { - var i, input, inputs, len, results; - inputs = Object.keys(this.originalState); - results = []; - for (i = 0, len = inputs.length; i < len; i += 1) { - input = inputs[i]; - // _location isnt a input - if (input === '_location') { - break; - } - results.push(this.getElement("#" + input).val('')); + badgePresent() { + return this.locationBadgeEl.length; + } + + resetSearchState() { + var i, input, inputs, len, results; + inputs = Object.keys(this.originalState); + results = []; + for (i = 0, len = inputs.length; i < len; i += 1) { + input = inputs[i]; + // _location isnt a input + if (input === '_location') { + break; } - return results; + results.push(this.getElement("#" + input).val('')); } + return results; + } - removeLocationBadge() { - this.locationBadgeEl.hide(); - this.resetSearchState(); - this.wrap.removeClass('has-location-badge'); - return this.disableAutocomplete(); - } + removeLocationBadge() { + this.locationBadgeEl.hide(); + this.resetSearchState(); + this.wrap.removeClass('has-location-badge'); + return this.disableAutocomplete(); + } - disableAutocomplete() { - if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('open')) { - this.searchInput.addClass('disabled'); - this.dropdown.removeClass('open').trigger('hidden.bs.dropdown'); - this.restoreMenu(); - } + disableAutocomplete() { + if (!this.searchInput.hasClass('disabled') && this.dropdown.hasClass('open')) { + this.searchInput.addClass('disabled'); + this.dropdown.removeClass('open').trigger('hidden.bs.dropdown'); + this.restoreMenu(); } + } - restoreMenu() { - var html; - html = "<ul> <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> </ul>"; - return this.dropdownContent.html(html); - } + restoreMenu() { + var html; + html = "<ul> <li><a class='dropdown-menu-empty-link is-focused'>Loading...</a></li> </ul>"; + return this.dropdownContent.html(html); + } - onClick(item, $el, e) { - if (location.pathname.indexOf(item.url) !== -1) { - if (!e.metaKey) e.preventDefault(); - if (!this.badgePresent) { - if (item.category === 'Projects') { - this.projectInputEl.val(item.id); - this.addLocationBadge({ - value: 'This project' - }); - } - if (item.category === 'Groups') { - this.groupInputEl.val(item.id); - this.addLocationBadge({ - value: 'This group' - }); - } + onClick(item, $el, e) { + if (location.pathname.indexOf(item.url) !== -1) { + if (!e.metaKey) e.preventDefault(); + if (!this.badgePresent) { + if (item.category === 'Projects') { + this.projectInputEl.val(item.id); + this.addLocationBadge({ + value: 'This project' + }); + } + if (item.category === 'Groups') { + this.groupInputEl.val(item.id); + this.addLocationBadge({ + value: 'This group' + }); } - $el.removeClass('is-active'); - this.disableAutocomplete(); - return this.searchInput.val('').focus(); } + $el.removeClass('is-active'); + this.disableAutocomplete(); + return this.searchInput.val('').focus(); } } +} - global.SearchAutocomplete = SearchAutocomplete; +global.SearchAutocomplete = SearchAutocomplete; - $(function() { - var $projectOptionsDataEl = $('.js-search-project-options'); - var $groupOptionsDataEl = $('.js-search-group-options'); - var $dashboardOptionsDataEl = $('.js-search-dashboard-options'); +$(function() { + var $projectOptionsDataEl = $('.js-search-project-options'); + var $groupOptionsDataEl = $('.js-search-group-options'); + var $dashboardOptionsDataEl = $('.js-search-dashboard-options'); - if ($projectOptionsDataEl.length) { - gl.projectOptions = gl.projectOptions || {}; + if ($projectOptionsDataEl.length) { + gl.projectOptions = gl.projectOptions || {}; - var projectPath = $projectOptionsDataEl.data('project-path'); + var projectPath = $projectOptionsDataEl.data('project-path'); - gl.projectOptions[projectPath] = { - name: $projectOptionsDataEl.data('name'), - issuesPath: $projectOptionsDataEl.data('issues-path'), - mrPath: $projectOptionsDataEl.data('mr-path') - }; - } + gl.projectOptions[projectPath] = { + name: $projectOptionsDataEl.data('name'), + issuesPath: $projectOptionsDataEl.data('issues-path'), + mrPath: $projectOptionsDataEl.data('mr-path') + }; + } - if ($groupOptionsDataEl.length) { - gl.groupOptions = gl.groupOptions || {}; + if ($groupOptionsDataEl.length) { + gl.groupOptions = gl.groupOptions || {}; - var groupPath = $groupOptionsDataEl.data('group-path'); + var groupPath = $groupOptionsDataEl.data('group-path'); - gl.groupOptions[groupPath] = { - name: $groupOptionsDataEl.data('name'), - issuesPath: $groupOptionsDataEl.data('issues-path'), - mrPath: $groupOptionsDataEl.data('mr-path') - }; - } + gl.groupOptions[groupPath] = { + name: $groupOptionsDataEl.data('name'), + issuesPath: $groupOptionsDataEl.data('issues-path'), + mrPath: $groupOptionsDataEl.data('mr-path') + }; + } - if ($dashboardOptionsDataEl.length) { - gl.dashboardOptions = { - issuesPath: $dashboardOptionsDataEl.data('issues-path'), - mrPath: $dashboardOptionsDataEl.data('mr-path') - }; - } - }); -})(window.gl || (window.gl = {})); + if ($dashboardOptionsDataEl.length) { + gl.dashboardOptions = { + issuesPath: $dashboardOptionsDataEl.data('issues-path'), + mrPath: $dashboardOptionsDataEl.data('mr-path') + }; + } +}); diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js index e3daa8cf949..e9575fda369 100644 --- a/app/assets/javascripts/shortcuts.js +++ b/app/assets/javascripts/shortcuts.js @@ -4,139 +4,135 @@ import Cookies from 'js-cookie'; import findAndFollowLink from './shortcuts_dashboard_navigation'; -(function() { - this.Shortcuts = (function() { - function Shortcuts(skipResetBindings) { - this.onToggleHelp = this.onToggleHelp.bind(this); - this.enabledHelp = []; - if (!skipResetBindings) { - Mousetrap.reset(); - } - Mousetrap.bind('?', this.onToggleHelp); - Mousetrap.bind('s', Shortcuts.focusSearch); - Mousetrap.bind('f', (e => this.focusFilter(e))); - Mousetrap.bind('p b', this.onTogglePerfBar); - - const $globalDropdownMenu = $('.global-dropdown-menu'); - const $globalDropdownToggle = $('.global-dropdown-toggle'); - const findFileURL = document.body.dataset.findFile; - - $('.global-dropdown').on('hide.bs.dropdown', () => { - $globalDropdownMenu.removeClass('shortcuts'); - }); +function Shortcuts(skipResetBindings) { + this.onToggleHelp = this.onToggleHelp.bind(this); + this.enabledHelp = []; + if (!skipResetBindings) { + Mousetrap.reset(); + } + Mousetrap.bind('?', this.onToggleHelp); + Mousetrap.bind('s', Shortcuts.focusSearch); + Mousetrap.bind('f', (e => this.focusFilter(e))); + Mousetrap.bind('p b', this.onTogglePerfBar); + + const $globalDropdownMenu = $('.global-dropdown-menu'); + const $globalDropdownToggle = $('.global-dropdown-toggle'); + const findFileURL = document.body.dataset.findFile; + + $('.global-dropdown').on('hide.bs.dropdown', () => { + $globalDropdownMenu.removeClass('shortcuts'); + }); - Mousetrap.bind('n', () => { - $globalDropdownMenu.toggleClass('shortcuts'); - $globalDropdownToggle.trigger('click'); + Mousetrap.bind('n', () => { + $globalDropdownMenu.toggleClass('shortcuts'); + $globalDropdownToggle.trigger('click'); - if (!$globalDropdownMenu.is(':visible')) { - $globalDropdownToggle.blur(); - } - }); - - Mousetrap.bind('shift+t', () => findAndFollowLink('.shortcuts-todos')); - Mousetrap.bind('shift+a', () => findAndFollowLink('.dashboard-shortcuts-activity')); - Mousetrap.bind('shift+i', () => findAndFollowLink('.dashboard-shortcuts-issues')); - Mousetrap.bind('shift+m', () => findAndFollowLink('.dashboard-shortcuts-merge_requests')); - Mousetrap.bind('shift+p', () => findAndFollowLink('.dashboard-shortcuts-projects')); - Mousetrap.bind('shift+g', () => findAndFollowLink('.dashboard-shortcuts-groups')); - Mousetrap.bind('shift+l', () => findAndFollowLink('.dashboard-shortcuts-milestones')); - Mousetrap.bind('shift+s', () => findAndFollowLink('.dashboard-shortcuts-snippets')); - - Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview); - if (typeof findFileURL !== "undefined" && findFileURL !== null) { - Mousetrap.bind('t', function() { - return gl.utils.visitUrl(findFileURL); - }); - } + if (!$globalDropdownMenu.is(':visible')) { + $globalDropdownToggle.blur(); } - - Shortcuts.prototype.onToggleHelp = function(e) { - e.preventDefault(); - return Shortcuts.toggleHelp(this.enabledHelp); - }; - - Shortcuts.prototype.onTogglePerfBar = function(e) { - e.preventDefault(); - const performanceBarCookieName = 'perf_bar_enabled'; - if (Cookies.get(performanceBarCookieName) === 'true') { - Cookies.remove(performanceBarCookieName, { path: '/' }); - } else { - Cookies.set(performanceBarCookieName, 'true', { path: '/' }); - } - gl.utils.refreshCurrentPage(); - }; - - Shortcuts.prototype.toggleMarkdownPreview = function(e) { - // Check if short-cut was triggered while in Write Mode - const $target = $(e.target); - const $form = $target.closest('form'); - - if ($target.hasClass('js-note-text')) { - $('.js-md-preview-button', $form).focus(); - } - return $(document).triggerHandler('markdown-preview:toggle', [e]); - }; - - Shortcuts.toggleHelp = function(location) { - var $modal; - $modal = $('#modal-shortcuts'); - if ($modal.length) { - $modal.modal('toggle'); - return; - } - return $.ajax({ - url: gon.shortcuts_path, - dataType: 'script', - success: function(e) { - var i, l, len, results; - if (location && location.length > 0) { - results = []; - for (i = 0, len = location.length; i < len; i += 1) { - l = location[i]; - results.push($(l).show()); - } - return results; - } else { - $('.hidden-shortcut').show(); - return $('.js-more-help-button').remove(); - } - } - }); - }; - - Shortcuts.prototype.focusFilter = function(e) { - if (this.filterInput == null) { - this.filterInput = $('input[type=search]', '.nav-controls'); - } - this.filterInput.focus(); - return e.preventDefault(); - }; - - Shortcuts.focusSearch = function(e) { - $('#search').focus(); - return e.preventDefault(); - }; - - return Shortcuts; - })(); - - $(document).on('click.more_help', '.js-more-help-button', function(e) { - $(this).remove(); - $('.hidden-shortcut').show(); - return e.preventDefault(); }); - Mousetrap.stopCallback = (function() { - var defaultStopCallback; - defaultStopCallback = Mousetrap.stopCallback; - return function(e, element, combo) { - // allowed shortcuts if textarea, input, contenteditable are focused - if (['ctrl+shift+p', 'command+shift+p'].indexOf(combo) !== -1) { - return false; + Mousetrap.bind('shift+t', () => findAndFollowLink('.shortcuts-todos')); + Mousetrap.bind('shift+a', () => findAndFollowLink('.dashboard-shortcuts-activity')); + Mousetrap.bind('shift+i', () => findAndFollowLink('.dashboard-shortcuts-issues')); + Mousetrap.bind('shift+m', () => findAndFollowLink('.dashboard-shortcuts-merge_requests')); + Mousetrap.bind('shift+p', () => findAndFollowLink('.dashboard-shortcuts-projects')); + Mousetrap.bind('shift+g', () => findAndFollowLink('.dashboard-shortcuts-groups')); + Mousetrap.bind('shift+l', () => findAndFollowLink('.dashboard-shortcuts-milestones')); + Mousetrap.bind('shift+s', () => findAndFollowLink('.dashboard-shortcuts-snippets')); + + Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview); + if (typeof findFileURL !== "undefined" && findFileURL !== null) { + Mousetrap.bind('t', function() { + return gl.utils.visitUrl(findFileURL); + }); + } +} + +Shortcuts.prototype.onToggleHelp = function(e) { + e.preventDefault(); + return Shortcuts.toggleHelp(this.enabledHelp); +}; + +Shortcuts.prototype.onTogglePerfBar = function(e) { + e.preventDefault(); + const performanceBarCookieName = 'perf_bar_enabled'; + if (Cookies.get(performanceBarCookieName) === 'true') { + Cookies.remove(performanceBarCookieName, { path: '/' }); + } else { + Cookies.set(performanceBarCookieName, 'true', { path: '/' }); + } + gl.utils.refreshCurrentPage(); +}; + +Shortcuts.prototype.toggleMarkdownPreview = function(e) { + // Check if short-cut was triggered while in Write Mode + const $target = $(e.target); + const $form = $target.closest('form'); + + if ($target.hasClass('js-note-text')) { + $('.js-md-preview-button', $form).focus(); + } + return $(document).triggerHandler('markdown-preview:toggle', [e]); +}; + +Shortcuts.toggleHelp = function(location) { + var $modal; + $modal = $('#modal-shortcuts'); + if ($modal.length) { + $modal.modal('toggle'); + return; + } + return $.ajax({ + url: gon.shortcuts_path, + dataType: 'script', + success: function(e) { + var i, l, len, results; + if (location && location.length > 0) { + results = []; + for (i = 0, len = location.length; i < len; i += 1) { + l = location[i]; + results.push($(l).show()); + } + return results; } else { - return defaultStopCallback.apply(this, arguments); + $('.hidden-shortcut').show(); + return $('.js-more-help-button').remove(); } - }; - })(); -}).call(window); + } + }); +}; + +Shortcuts.prototype.focusFilter = function(e) { + if (this.filterInput == null) { + this.filterInput = $('input[type=search]', '.nav-controls'); + } + this.filterInput.focus(); + return e.preventDefault(); +}; + +Shortcuts.focusSearch = function(e) { + $('#search').focus(); + return e.preventDefault(); +}; + +window.Shortcuts = Shortcuts; + +$(document).on('click.more_help', '.js-more-help-button', function(e) { + $(this).remove(); + $('.hidden-shortcut').show(); + return e.preventDefault(); +}); + +Mousetrap.stopCallback = (function() { + var defaultStopCallback; + defaultStopCallback = Mousetrap.stopCallback; + return function(e, element, combo) { + // allowed shortcuts if textarea, input, contenteditable are focused + if (['ctrl+shift+p', 'command+shift+p'].indexOf(combo) !== -1) { + return false; + } else { + return defaultStopCallback.apply(this, arguments); + } + }; +})(); diff --git a/app/assets/javascripts/shortcuts_find_file.js b/app/assets/javascripts/shortcuts_find_file.js index b18b6139b35..dd41c070c8d 100644 --- a/app/assets/javascripts/shortcuts_find_file.js +++ b/app/assets/javascripts/shortcuts_find_file.js @@ -4,35 +4,31 @@ import './shortcuts_navigation'; -(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; +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.ShortcutsFindFile = (function(superClass) { - extend(ShortcutsFindFile, superClass); +function ShortcutsFindFile(projectFindFile) { + var _oldStopCallback; + this.projectFindFile = projectFindFile; + ShortcutsFindFile.__super__.constructor.call(this); + _oldStopCallback = Mousetrap.stopCallback; - function ShortcutsFindFile(projectFindFile) { - var _oldStopCallback; - this.projectFindFile = projectFindFile; - ShortcutsFindFile.__super__.constructor.call(this); - _oldStopCallback = Mousetrap.stopCallback; - Mousetrap.stopCallback = (function(_this) { - // override to fire shortcuts action when focus in textbox - return function(event, element, combo) { - if (element === _this.projectFindFile.inputElement[0] && (combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')) { - // when press up/down key in textbox, cusor prevent to move to home/end - event.preventDefault(); - return false; - } - return _oldStopCallback(event, element, combo); - }; - })(this); - Mousetrap.bind('up', this.projectFindFile.selectRowUp); - Mousetrap.bind('down', this.projectFindFile.selectRowDown); - Mousetrap.bind('esc', this.projectFindFile.goToTree); - Mousetrap.bind('enter', this.projectFindFile.goToBlob); + // override to fire shortcuts action when focus in textbox + Mousetrap.stopCallback = function(event, element, combo) { + if (element === this.projectFindFile.inputElement[0] && (combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')) { + // when press up/down key in textbox, cusor prevent to move to home/end + event.preventDefault(); + return false; } + return _oldStopCallback(event, element, combo); + }.bind(this); - return ShortcutsFindFile; - })(ShortcutsNavigation); -}).call(window); + Mousetrap.bind('up', this.projectFindFile.selectRowUp); + Mousetrap.bind('down', this.projectFindFile.selectRowDown); + Mousetrap.bind('esc', this.projectFindFile.goToTree); + Mousetrap.bind('enter', this.projectFindFile.goToBlob); +} + +extend(ShortcutsFindFile, ShortcutsNavigation); + +window.ShortcutsFindFile = ShortcutsFindFile; diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index 51448252c0f..138b9768735 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -6,87 +6,81 @@ import 'mousetrap'; import './shortcuts_navigation'; -(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; +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.ShortcutsIssuable = (function(superClass) { - extend(ShortcutsIssuable, superClass); +var ShortcutsIssuable = {}; - function ShortcutsIssuable(isMergeRequest) { - ShortcutsIssuable.__super__.constructor.call(this); - Mousetrap.bind('a', this.openSidebarDropdown.bind(this, 'assignee')); - Mousetrap.bind('m', this.openSidebarDropdown.bind(this, 'milestone')); - Mousetrap.bind('r', (function(_this) { - return function() { - _this.replyWithSelectedText(); - return false; - }; - })(this)); - Mousetrap.bind('e', (function(_this) { - return function() { - _this.editIssue(); - return false; - }; - })(this)); - Mousetrap.bind('l', this.openSidebarDropdown.bind(this, 'labels')); - if (isMergeRequest) { - this.enabledHelp.push('.hidden-shortcut.merge_requests'); - } else { - this.enabledHelp.push('.hidden-shortcut.issues'); - } - } +extend(ShortcutsIssuable, ShortcutsNavigation); - ShortcutsIssuable.prototype.replyWithSelectedText = function() { - var quote, documentFragment, el, selected, separator; - var replyField = $('.js-main-target-form #note_note'); +ShortcutsIssuable = function(isMergeRequest) { + ShortcutsIssuable.__super__.constructor.call(this); + Mousetrap.bind('a', this.openSidebarDropdown.bind(this, 'assignee')); + Mousetrap.bind('m', this.openSidebarDropdown.bind(this, 'milestone')); + Mousetrap.bind('r', function() { + this.replyWithSelectedText(); + return false; + }.bind(this)); + Mousetrap.bind('e', function() { + this.editIssue(); + return false; + }.bind(this)); + Mousetrap.bind('l', this.openSidebarDropdown.bind(this, 'labels')); + if (isMergeRequest) { + this.enabledHelp.push('.hidden-shortcut.merge_requests'); + } else { + this.enabledHelp.push('.hidden-shortcut.issues'); + } +}; - documentFragment = window.gl.utils.getSelectedFragment(); - if (!documentFragment) { - replyField.focus(); - return; - } +ShortcutsIssuable.prototype.replyWithSelectedText = function() { + var quote, documentFragment, el, selected, separator; + var replyField = $('.js-main-target-form #note_note'); - el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true)); - selected = window.gl.CopyAsGFM.nodeToGFM(el); + documentFragment = window.gl.utils.getSelectedFragment(); + if (!documentFragment) { + replyField.focus(); + return; + } - if (selected.trim() === "") { - return; - } - quote = _.map(selected.split("\n"), function(val) { - return ("> " + val).trim() + "\n"; - }); - // If replyField already has some content, add a newline before our quote - separator = replyField.val().trim() !== "" && "\n\n" || ''; - replyField.val(function(_, current) { - return current + separator + quote.join('') + "\n"; - }); + el = window.gl.CopyAsGFM.transformGFMSelection(documentFragment.cloneNode(true)); + selected = window.gl.CopyAsGFM.nodeToGFM(el); - // Trigger autosave - replyField.trigger('input'); + if (selected.trim() === "") { + return; + } + quote = _.map(selected.split("\n"), function(val) { + return ("> " + val).trim() + "\n"; + }); + // If replyField already has some content, add a newline before our quote + separator = replyField.val().trim() !== "" && "\n\n" || ''; + replyField.val(function(_, current) { + return current + separator + quote.join('') + "\n"; + }); - // Trigger autosize - var event = document.createEvent('Event'); - event.initEvent('autosize:update', true, false); - replyField.get(0).dispatchEvent(event); + // Trigger autosave + replyField.trigger('input'); - // Focus the input field - return replyField.focus(); - }; + // Trigger autosize + var event = document.createEvent('Event'); + event.initEvent('autosize:update', true, false); + replyField.get(0).dispatchEvent(event); - ShortcutsIssuable.prototype.editIssue = function() { - var $editBtn; - $editBtn = $('.issuable-edit'); - // Need to click the element as on issues, editing is inline - // on merge request, editing is on a different page - $editBtn.get(0).click(); - }; + // Focus the input field + return replyField.focus(); +}; - ShortcutsIssuable.prototype.openSidebarDropdown = function(name) { - sidebar.openDropdown(name); - return false; - }; +ShortcutsIssuable.prototype.editIssue = function() { + var $editBtn; + $editBtn = $('.issuable-edit'); + // Need to click the element as on issues, editing is inline + // on merge request, editing is on a different page + $editBtn.get(0).click(); +}; - return ShortcutsIssuable; - })(ShortcutsNavigation); -}).call(window); +ShortcutsIssuable.prototype.openSidebarDropdown = function(name) { + sidebar.openDropdown(name); + return false; +}; + +window.ShortcutsIssuable = ShortcutsIssuable; diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index 55bae0c08a1..bba292cac2b 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -5,32 +5,30 @@ import findAndFollowLink from './shortcuts_dashboard_navigation'; import './shortcuts'; -(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; +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.ShortcutsNavigation = (function(superClass) { - extend(ShortcutsNavigation, superClass); +var ShortcutsNavigation = {}; - function ShortcutsNavigation() { - ShortcutsNavigation.__super__.constructor.call(this); - Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project')); - Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity')); - Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree')); - Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits')); - Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds')); - Mousetrap.bind('g n', () => findAndFollowLink('.shortcuts-network')); - Mousetrap.bind('g d', () => findAndFollowLink('.shortcuts-repository-charts')); - Mousetrap.bind('g i', () => findAndFollowLink('.shortcuts-issues')); - Mousetrap.bind('g b', () => findAndFollowLink('.shortcuts-issue-boards')); - Mousetrap.bind('g m', () => findAndFollowLink('.shortcuts-merge_requests')); - Mousetrap.bind('g t', () => findAndFollowLink('.shortcuts-todos')); - Mousetrap.bind('g w', () => findAndFollowLink('.shortcuts-wiki')); - Mousetrap.bind('g s', () => findAndFollowLink('.shortcuts-snippets')); - Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue')); - this.enabledHelp.push('.hidden-shortcut.project'); - } +extend(ShortcutsNavigation, Shortcuts); - return ShortcutsNavigation; - })(Shortcuts); -}).call(window); +ShortcutsNavigation = function() { + ShortcutsNavigation.__super__.constructor.call(this); + Mousetrap.bind('g p', () => findAndFollowLink('.shortcuts-project')); + Mousetrap.bind('g e', () => findAndFollowLink('.shortcuts-project-activity')); + Mousetrap.bind('g f', () => findAndFollowLink('.shortcuts-tree')); + Mousetrap.bind('g c', () => findAndFollowLink('.shortcuts-commits')); + Mousetrap.bind('g j', () => findAndFollowLink('.shortcuts-builds')); + Mousetrap.bind('g n', () => findAndFollowLink('.shortcuts-network')); + Mousetrap.bind('g d', () => findAndFollowLink('.shortcuts-repository-charts')); + Mousetrap.bind('g i', () => findAndFollowLink('.shortcuts-issues')); + Mousetrap.bind('g b', () => findAndFollowLink('.shortcuts-issue-boards')); + Mousetrap.bind('g m', () => findAndFollowLink('.shortcuts-merge_requests')); + Mousetrap.bind('g t', () => findAndFollowLink('.shortcuts-todos')); + Mousetrap.bind('g w', () => findAndFollowLink('.shortcuts-wiki')); + Mousetrap.bind('g s', () => findAndFollowLink('.shortcuts-snippets')); + Mousetrap.bind('i', () => findAndFollowLink('.shortcuts-new-issue')); + this.enabledHelp.push('.hidden-shortcut.project'); +}; + +window.ShortcutsNavigation = ShortcutsNavigation; diff --git a/app/assets/javascripts/shortcuts_network.js b/app/assets/javascripts/shortcuts_network.js index cc44082efa9..8ff5b86939a 100644 --- a/app/assets/javascripts/shortcuts_network.js +++ b/app/assets/javascripts/shortcuts_network.js @@ -4,25 +4,23 @@ import './shortcuts_navigation'; -(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; +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.ShortcutsNetwork = (function(superClass) { - extend(ShortcutsNetwork, superClass); +var ShortcutsNetwork = {}; - function ShortcutsNetwork(graph) { - this.graph = graph; - ShortcutsNetwork.__super__.constructor.call(this); - Mousetrap.bind(['left', 'h'], this.graph.scrollLeft); - Mousetrap.bind(['right', 'l'], this.graph.scrollRight); - Mousetrap.bind(['up', 'k'], this.graph.scrollUp); - Mousetrap.bind(['down', 'j'], this.graph.scrollDown); - Mousetrap.bind(['shift+up', 'shift+k'], this.graph.scrollTop); - Mousetrap.bind(['shift+down', 'shift+j'], this.graph.scrollBottom); - this.enabledHelp.push('.hidden-shortcut.network'); - } +extend(ShortcutsNetwork, ShortcutsNavigation); - return ShortcutsNetwork; - })(ShortcutsNavigation); -}).call(window); +ShortcutsNetwork = function(graph) { + this.graph = graph; + ShortcutsNetwork.__super__.constructor.call(this); + Mousetrap.bind(['left', 'h'], this.graph.scrollLeft); + Mousetrap.bind(['right', 'l'], this.graph.scrollRight); + Mousetrap.bind(['up', 'k'], this.graph.scrollUp); + Mousetrap.bind(['down', 'j'], this.graph.scrollDown); + Mousetrap.bind(['shift+up', 'shift+k'], this.graph.scrollTop); + Mousetrap.bind(['shift+down', 'shift+j'], this.graph.scrollBottom); + this.enabledHelp.push('.hidden-shortcut.network'); +}; + +window.ShortcutsNetwork = ShortcutsNetwork; diff --git a/app/assets/javascripts/templates/issuable_template_selector.js b/app/assets/javascripts/templates/issuable_template_selector.js index 9dd14488f22..4d81402d12c 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js +++ b/app/assets/javascripts/templates/issuable_template_selector.js @@ -3,58 +3,58 @@ 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'); - }); - } +const global = window.gl || (window.gl = {}); + +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 = {})); +global.IssuableTemplateSelector = IssuableTemplateSelector; diff --git a/app/assets/javascripts/templates/issuable_template_selectors.js b/app/assets/javascripts/templates/issuable_template_selectors.js index 97f6d37364d..5eb516c16f0 100644 --- a/app/assets/javascripts/templates/issuable_template_selectors.js +++ b/app/assets/javascripts/templates/issuable_template_selectors.js @@ -1,31 +1,31 @@ /* eslint-disable no-new, comma-dangle, class-methods-use-this, no-param-reassign */ -((global) => { - class IssuableTemplateSelectors { - constructor({ $dropdowns, editor } = {}) { - this.$dropdowns = $dropdowns || $('.js-issuable-selector'); - this.editor = editor || this.initEditor(); +const global = window.gl || (window.gl = {}); - 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 - }); +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 }); - } + }); + } - initEditor() { - const editor = $('.markdown-area'); - // Proxy ace-editor's .setValue to jQuery's .val - editor.setValue = editor.val; - editor.getValue = editor.val; - return 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 = {})); +global.IssuableTemplateSelectors = IssuableTemplateSelectors; diff --git a/app/assets/javascripts/u2f/authenticate.js b/app/assets/javascripts/u2f/authenticate.js index cd5280948fd..04e943ca581 100644 --- a/app/assets/javascripts/u2f/authenticate.js +++ b/app/assets/javascripts/u2f/authenticate.js @@ -7,110 +7,104 @@ // // State Flow #1: setup -> in_progress -> authenticated -> POST to server // State Flow #2: setup -> in_progress -> error -> setup -(function() { - const global = window.gl || (window.gl = {}); +const global = window.gl || (window.gl = {}); - global.U2FAuthenticate = (function() { - function U2FAuthenticate(container, form, u2fParams, fallbackButton, fallbackUI) { - this.container = container; - this.renderNotSupported = this.renderNotSupported.bind(this); - this.renderAuthenticated = this.renderAuthenticated.bind(this); - this.renderError = this.renderError.bind(this); - this.renderInProgress = this.renderInProgress.bind(this); - this.renderTemplate = this.renderTemplate.bind(this); - this.authenticate = this.authenticate.bind(this); - this.start = this.start.bind(this); - this.appId = u2fParams.app_id; - this.challenge = u2fParams.challenge; - this.form = form; - this.fallbackButton = fallbackButton; - this.fallbackUI = fallbackUI; - if (this.fallbackButton) this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this)); - this.signRequests = u2fParams.sign_requests.map(function(request) { - // The U2F Javascript API v1.1 requires a single challenge, with - // _no challenges per-request_. The U2F Javascript API v1.0 requires a - // challenge per-request, which is done by copying the single challenge - // into every request. - // - // In either case, we don't need the per-request challenges that the server - // has generated, so we can remove them. - // - // Note: The server library fixes this behaviour in (unreleased) version 1.0.0. - // This can be removed once we upgrade. - // https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4 - return _(request).omit('challenge'); - }); - } +function U2FAuthenticate(container, form, u2fParams, fallbackButton, fallbackUI) { + this.container = container; + this.renderNotSupported = this.renderNotSupported.bind(this); + this.renderAuthenticated = this.renderAuthenticated.bind(this); + this.renderError = this.renderError.bind(this); + this.renderInProgress = this.renderInProgress.bind(this); + this.renderTemplate = this.renderTemplate.bind(this); + this.authenticate = this.authenticate.bind(this); + this.start = this.start.bind(this); + this.appId = u2fParams.app_id; + this.challenge = u2fParams.challenge; + this.form = form; + this.fallbackButton = fallbackButton; + this.fallbackUI = fallbackUI; + if (this.fallbackButton) this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this)); + this.signRequests = u2fParams.sign_requests.map(function(request) { + // The U2F Javascript API v1.1 requires a single challenge, with + // _no challenges per-request_. The U2F Javascript API v1.0 requires a + // challenge per-request, which is done by copying the single challenge + // into every request. + // + // In either case, we don't need the per-request challenges that the server + // has generated, so we can remove them. + // + // Note: The server library fixes this behaviour in (unreleased) version 1.0.0. + // This can be removed once we upgrade. + // https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4 + return _(request).omit('challenge'); + }); +} - U2FAuthenticate.prototype.start = function() { - if (U2FUtil.isU2FSupported()) { - return this.renderInProgress(); - } else { - return this.renderNotSupported(); - } - }; +U2FAuthenticate.prototype.start = function() { + if (U2FUtil.isU2FSupported()) { + return this.renderInProgress(); + } else { + return this.renderNotSupported(); + } +}; - U2FAuthenticate.prototype.authenticate = function() { - return u2f.sign(this.appId, this.challenge, this.signRequests, (function(_this) { - return function(response) { - var error; - if (response.errorCode) { - error = new U2FError(response.errorCode, 'authenticate'); - return _this.renderError(error); - } else { - return _this.renderAuthenticated(JSON.stringify(response)); - } - }; - })(this), 10); - }; +U2FAuthenticate.prototype.authenticate = function() { + return u2f.sign(this.appId, this.challenge, this.signRequests, function(response) { + var error; + if (response.errorCode) { + error = new U2FError(response.errorCode, 'authenticate'); + return this.renderError(error); + } else { + return this.renderAuthenticated(JSON.stringify(response)); + } + }.bind(this), 10); +}; - // Rendering # - U2FAuthenticate.prototype.templates = { - "notSupported": "#js-authenticate-u2f-not-supported", - "setup": '#js-authenticate-u2f-setup', - "inProgress": '#js-authenticate-u2f-in-progress', - "error": '#js-authenticate-u2f-error', - "authenticated": '#js-authenticate-u2f-authenticated' - }; +// Rendering # +U2FAuthenticate.prototype.templates = { + "notSupported": "#js-authenticate-u2f-not-supported", + "setup": '#js-authenticate-u2f-setup', + "inProgress": '#js-authenticate-u2f-in-progress', + "error": '#js-authenticate-u2f-error', + "authenticated": '#js-authenticate-u2f-authenticated' +}; - U2FAuthenticate.prototype.renderTemplate = function(name, params) { - var template, templateString; - templateString = $(this.templates[name]).html(); - template = _.template(templateString); - return this.container.html(template(params)); - }; +U2FAuthenticate.prototype.renderTemplate = function(name, params) { + var template, templateString; + templateString = $(this.templates[name]).html(); + template = _.template(templateString); + return this.container.html(template(params)); +}; - U2FAuthenticate.prototype.renderInProgress = function() { - this.renderTemplate('inProgress'); - return this.authenticate(); - }; +U2FAuthenticate.prototype.renderInProgress = function() { + this.renderTemplate('inProgress'); + return this.authenticate(); +}; - U2FAuthenticate.prototype.renderError = function(error) { - this.renderTemplate('error', { - error_message: error.message(), - error_code: error.errorCode - }); - return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress); - }; +U2FAuthenticate.prototype.renderError = function(error) { + this.renderTemplate('error', { + error_message: error.message(), + error_code: error.errorCode + }); + return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress); +}; - U2FAuthenticate.prototype.renderAuthenticated = function(deviceResponse) { - this.renderTemplate('authenticated'); - const container = this.container[0]; - container.querySelector('#js-device-response').value = deviceResponse; - container.querySelector(this.form).submit(); - this.fallbackButton.classList.add('hidden'); - }; +U2FAuthenticate.prototype.renderAuthenticated = function(deviceResponse) { + this.renderTemplate('authenticated'); + const container = this.container[0]; + container.querySelector('#js-device-response').value = deviceResponse; + container.querySelector(this.form).submit(); + this.fallbackButton.classList.add('hidden'); +}; - U2FAuthenticate.prototype.renderNotSupported = function() { - return this.renderTemplate('notSupported'); - }; +U2FAuthenticate.prototype.renderNotSupported = function() { + return this.renderTemplate('notSupported'); +}; - U2FAuthenticate.prototype.switchToFallbackUI = function() { - this.fallbackButton.classList.add('hidden'); - this.container[0].classList.add('hidden'); - this.fallbackUI.classList.remove('hidden'); - }; +U2FAuthenticate.prototype.switchToFallbackUI = function() { + this.fallbackButton.classList.add('hidden'); + this.container[0].classList.add('hidden'); + this.fallbackUI.classList.remove('hidden'); +}; - return U2FAuthenticate; - })(); -})(); +global.U2FAuthenticate = U2FAuthenticate; diff --git a/app/assets/javascripts/u2f/error.js b/app/assets/javascripts/u2f/error.js index 3119b3480c3..f4a436c9f76 100644 --- a/app/assets/javascripts/u2f/error.js +++ b/app/assets/javascripts/u2f/error.js @@ -1,25 +1,21 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-console, quotes, prefer-template, max-len */ /* global u2f */ -(function() { - this.U2FError = (function() { - function U2FError(errorCode, u2fFlowType) { - this.errorCode = errorCode; - this.message = this.message.bind(this); - this.httpsDisabled = window.location.protocol !== 'https:'; - this.u2fFlowType = u2fFlowType; - } +function U2FError(errorCode, u2fFlowType) { + this.errorCode = errorCode; + this.message = this.message.bind(this); + this.httpsDisabled = window.location.protocol !== 'https:'; + this.u2fFlowType = u2fFlowType; +} - U2FError.prototype.message = function() { - if (this.errorCode === u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) { - return 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.'; - } else if (this.errorCode === u2f.ErrorCodes.DEVICE_INELIGIBLE) { - if (this.u2fFlowType === 'authenticate') return 'This device has not been registered with us.'; - if (this.u2fFlowType === 'register') return 'This device has already been registered with us.'; - } - return "There was a problem communicating with your device."; - }; +U2FError.prototype.message = function() { + if (this.errorCode === u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) { + return 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.'; + } else if (this.errorCode === u2f.ErrorCodes.DEVICE_INELIGIBLE) { + if (this.u2fFlowType === 'authenticate') return 'This device has not been registered with us.'; + if (this.u2fFlowType === 'register') return 'This device has already been registered with us.'; + } + return "There was a problem communicating with your device."; +}; - return U2FError; - })(); -}).call(window); +window.U2FError = U2FError; diff --git a/app/assets/javascripts/u2f/register.js b/app/assets/javascripts/u2f/register.js index 1234d17b8fd..38395710ad4 100644 --- a/app/assets/javascripts/u2f/register.js +++ b/app/assets/javascripts/u2f/register.js @@ -7,90 +7,84 @@ // // State Flow #1: setup -> in_progress -> registered -> POST to server // State Flow #2: setup -> in_progress -> error -> setup -(function() { - this.U2FRegister = (function() { - function U2FRegister(container, u2fParams) { - this.container = container; - this.renderNotSupported = this.renderNotSupported.bind(this); - this.renderRegistered = this.renderRegistered.bind(this); - this.renderError = this.renderError.bind(this); - this.renderInProgress = this.renderInProgress.bind(this); - this.renderSetup = this.renderSetup.bind(this); - this.renderTemplate = this.renderTemplate.bind(this); - this.register = this.register.bind(this); - this.start = this.start.bind(this); - this.appId = u2fParams.app_id; - this.registerRequests = u2fParams.register_requests; - this.signRequests = u2fParams.sign_requests; - } +function U2FRegister(container, u2fParams) { + this.container = container; + this.renderNotSupported = this.renderNotSupported.bind(this); + this.renderRegistered = this.renderRegistered.bind(this); + this.renderError = this.renderError.bind(this); + this.renderInProgress = this.renderInProgress.bind(this); + this.renderSetup = this.renderSetup.bind(this); + this.renderTemplate = this.renderTemplate.bind(this); + this.register = this.register.bind(this); + this.start = this.start.bind(this); + this.appId = u2fParams.app_id; + this.registerRequests = u2fParams.register_requests; + this.signRequests = u2fParams.sign_requests; +} - U2FRegister.prototype.start = function() { - if (U2FUtil.isU2FSupported()) { - return this.renderSetup(); - } else { - return this.renderNotSupported(); - } - }; +U2FRegister.prototype.start = function() { + if (U2FUtil.isU2FSupported()) { + return this.renderSetup(); + } else { + return this.renderNotSupported(); + } +}; - U2FRegister.prototype.register = function() { - return u2f.register(this.appId, this.registerRequests, this.signRequests, (function(_this) { - return function(response) { - var error; - if (response.errorCode) { - error = new U2FError(response.errorCode, 'register'); - return _this.renderError(error); - } else { - return _this.renderRegistered(JSON.stringify(response)); - } - }; - })(this), 10); - }; +U2FRegister.prototype.register = function() { + return u2f.register(this.appId, this.registerRequests, this.signRequests, (response) => { + var error; + if (response.errorCode) { + error = new U2FError(response.errorCode, 'register'); + return this.renderError(error); + } else { + return this.renderRegistered(JSON.stringify(response)); + } + }, 10); +}; - // Rendering # - U2FRegister.prototype.templates = { - "notSupported": "#js-register-u2f-not-supported", - "setup": '#js-register-u2f-setup', - "inProgress": '#js-register-u2f-in-progress', - "error": '#js-register-u2f-error', - "registered": '#js-register-u2f-registered' - }; +// Rendering # +U2FRegister.prototype.templates = { + "notSupported": "#js-register-u2f-not-supported", + "setup": '#js-register-u2f-setup', + "inProgress": '#js-register-u2f-in-progress', + "error": '#js-register-u2f-error', + "registered": '#js-register-u2f-registered' +}; - U2FRegister.prototype.renderTemplate = function(name, params) { - var template, templateString; - templateString = $(this.templates[name]).html(); - template = _.template(templateString); - return this.container.html(template(params)); - }; +U2FRegister.prototype.renderTemplate = function(name, params) { + var template, templateString; + templateString = $(this.templates[name]).html(); + template = _.template(templateString); + return this.container.html(template(params)); +}; - U2FRegister.prototype.renderSetup = function() { - this.renderTemplate('setup'); - return this.container.find('#js-setup-u2f-device').on('click', this.renderInProgress); - }; +U2FRegister.prototype.renderSetup = function() { + this.renderTemplate('setup'); + return this.container.find('#js-setup-u2f-device').on('click', this.renderInProgress); +}; - U2FRegister.prototype.renderInProgress = function() { - this.renderTemplate('inProgress'); - return this.register(); - }; +U2FRegister.prototype.renderInProgress = function() { + this.renderTemplate('inProgress'); + return this.register(); +}; - U2FRegister.prototype.renderError = function(error) { - this.renderTemplate('error', { - error_message: error.message(), - error_code: error.errorCode - }); - return this.container.find('#js-u2f-try-again').on('click', this.renderSetup); - }; +U2FRegister.prototype.renderError = function(error) { + this.renderTemplate('error', { + error_message: error.message(), + error_code: error.errorCode + }); + return this.container.find('#js-u2f-try-again').on('click', this.renderSetup); +}; - U2FRegister.prototype.renderRegistered = function(deviceResponse) { - this.renderTemplate('registered'); - // Prefer to do this instead of interpolating using Underscore templates - // because of JSON escaping issues. - return this.container.find("#js-device-response").val(deviceResponse); - }; +U2FRegister.prototype.renderRegistered = function(deviceResponse) { + this.renderTemplate('registered'); + // Prefer to do this instead of interpolating using Underscore templates + // because of JSON escaping issues. + return this.container.find("#js-device-response").val(deviceResponse); +}; - U2FRegister.prototype.renderNotSupported = function() { - return this.renderTemplate('notSupported'); - }; +U2FRegister.prototype.renderNotSupported = function() { + return this.renderTemplate('notSupported'); +}; - return U2FRegister; - })(); -}).call(window); +window.U2FRegister = U2FRegister; diff --git a/app/assets/javascripts/u2f/util.js b/app/assets/javascripts/u2f/util.js index 813d363db00..bcf62276ccf 100644 --- a/app/assets/javascripts/u2f/util.js +++ b/app/assets/javascripts/u2f/util.js @@ -1,12 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife */ -(function() { - this.U2FUtil = (function() { - function U2FUtil() {} +function U2FUtil() {} - U2FUtil.isU2FSupported = function() { - return window.u2f; - }; +U2FUtil.isU2FSupported = function() { + return window.u2f; +}; - return U2FUtil; - })(); -}).call(window); +window.U2FUtil = U2FUtil; |